@@ -73,8 +73,51 @@ static uint32_t get_dll_count(pe_ctx_t *ctx) {
7373 return count ;
7474}
7575
76- static uint32_t get_functions_count (pe_ctx_t * ctx , uint64_t offset ) {
77- uint64_t ofs = offset ;
76+ static uint32_t get_delay_dll_count (pe_ctx_t * ctx ) {
77+ uint32_t count = 0 ;
78+
79+ const IMAGE_DATA_DIRECTORY * dir = pe_directory_by_entry (ctx , IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT );
80+ if (dir == NULL )
81+ return count ;
82+
83+ const uint64_t va = dir -> VirtualAddress ;
84+ if (va == 0 ) {
85+ // TODO: report error?
86+ return count ;
87+ }
88+
89+ uint64_t ofs = pe_rva2ofs (ctx , va );
90+
91+ while (1 ) {
92+ IMAGE_DELAYLOAD_DESCRIPTOR * dd = LIBPE_PTR_ADD (ctx -> map_addr , ofs );
93+ if (!pe_can_read (ctx , dd , sizeof (IMAGE_DELAYLOAD_DESCRIPTOR ))) {
94+ // TODO: Should we report something?
95+ return count ;
96+ }
97+
98+ if (!dd -> ImportNameTableRVA )
99+ break ;
100+
101+ ofs += sizeof (IMAGE_DELAYLOAD_DESCRIPTOR );
102+
103+ const uint64_t aux = ofs ; // Store current ofs
104+ ofs = pe_rva2ofs (ctx , dd -> DllNameRVA );
105+ if (ofs == 0 )
106+ break ;
107+
108+ ofs = pe_rva2ofs (ctx , dd -> ImportNameTableRVA );
109+ if (ofs == 0 )
110+ break ;
111+
112+ count ++ ;
113+ ofs = aux ; // Restore previous ofs
114+ }
115+
116+ return count ;
117+ }
118+
119+ static uint32_t get_functions_count (pe_ctx_t * ctx , uint64_t offset , bool rva_based ) {
120+ uint64_t ofs = offset - (rva_based ? 0 : ctx -> pe .imagebase );
78121 uint32_t count = 0 ;
79122
80123 while (1 ) {
@@ -94,7 +137,8 @@ static uint32_t get_functions_count(pe_ctx_t *ctx, uint64_t offset) {
94137 bool is_ordinal = (thunk_type & (IMAGE_ORDINAL_MASK (ctx ))) != 0 ;
95138
96139 if (!is_ordinal ) {
97- const uint64_t imp_ofs = pe_rva2ofs (ctx , thunk -> u1 .AddressOfData );
140+ const uint32_t rva = thunk -> u1 .AddressOfData - (rva_based ? 0 : ctx -> pe .imagebase );
141+ const uint64_t imp_ofs = pe_rva2ofs (ctx , rva );
98142 const IMAGE_IMPORT_BY_NAME * imp_name = LIBPE_PTR_ADD (ctx -> map_addr , imp_ofs );
99143 if (!pe_can_read (ctx , imp_name , sizeof (IMAGE_IMPORT_BY_NAME )))
100144 return count ;
@@ -116,7 +160,8 @@ static uint32_t get_functions_count(pe_ctx_t *ctx, uint64_t offset) {
116160 bool is_ordinal = (thunk_type & (IMAGE_ORDINAL_MASK (ctx ))) != 0 ;
117161
118162 if (!is_ordinal ) {
119- uint64_t imp_ofs = pe_rva2ofs (ctx , thunk -> u1 .AddressOfData );
163+ uint64_t rva = thunk -> u1 .AddressOfData - (rva_based ? 0 : ctx -> pe .imagebase );
164+ uint64_t imp_ofs = pe_rva2ofs (ctx , rva );
120165 const IMAGE_IMPORT_BY_NAME * imp_name = LIBPE_PTR_ADD (ctx -> map_addr , imp_ofs );
121166 if (!pe_can_read (ctx , imp_name , sizeof (IMAGE_IMPORT_BY_NAME )))
122167 return count ;
@@ -133,9 +178,9 @@ static uint32_t get_functions_count(pe_ctx_t *ctx, uint64_t offset) {
133178 return count ;
134179}
135180
136- static pe_err_e parse_imported_functions (pe_ctx_t * ctx , pe_imported_dll_t * imported_dll , uint64_t offset ) {
181+ static pe_err_e parse_imported_functions (pe_ctx_t * ctx , pe_imported_dll_t * imported_dll , uint64_t offset , bool rva_based ) {
137182 imported_dll -> err = LIBPE_E_OK ;
138- imported_dll -> functions_count = get_functions_count (ctx , offset );
183+ imported_dll -> functions_count = get_functions_count (ctx , offset , rva_based );
139184
140185 imported_dll -> functions = calloc (imported_dll -> functions_count , sizeof (pe_imported_function_t ));
141186 if (imported_dll -> functions == NULL ) {
@@ -150,7 +195,7 @@ static pe_err_e parse_imported_functions(pe_ctx_t *ctx, pe_imported_dll_t *impor
150195 bool is_ordinal = false;
151196 uint16_t ordinal = 0 ;
152197 uint16_t hint = 0 ;
153- uint64_t ofs = offset ;
198+ uint64_t ofs = offset - ( rva_based ? 0 : ctx -> pe . imagebase ) ;
154199
155200 for (uint32_t i = 0 ; i < imported_dll -> functions_count ; i ++ ) {
156201 switch (ctx -> pe .optional_hdr .type ) {
@@ -177,7 +222,8 @@ static pe_err_e parse_imported_functions(pe_ctx_t *ctx, pe_imported_dll_t *impor
177222 hint = 0 ;
178223 ordinal = (thunk -> u1 .Ordinal & ~(IMAGE_ORDINAL_MASK (ctx ))) & 0xffff ;
179224 } else {
180- const uint64_t imp_ofs = pe_rva2ofs (ctx , thunk -> u1 .AddressOfData );
225+ const uint32_t rva = thunk -> u1 .AddressOfData - (rva_based ? 0 : ctx -> pe .imagebase );
226+ const uint64_t imp_ofs = pe_rva2ofs (ctx , rva );
181227 const IMAGE_IMPORT_BY_NAME * imp_name = LIBPE_PTR_ADD (ctx -> map_addr , imp_ofs );
182228 if (!pe_can_read (ctx , imp_name , sizeof (IMAGE_IMPORT_BY_NAME ))) {
183229 imported_dll -> err = LIBPE_E_ALLOCATION_FAILURE ;
@@ -217,7 +263,8 @@ static pe_err_e parse_imported_functions(pe_ctx_t *ctx, pe_imported_dll_t *impor
217263 hint = 0 ; // No hint
218264 ordinal = (thunk -> u1 .Ordinal & ~(IMAGE_ORDINAL_MASK (ctx ))) & 0xffff ;
219265 } else {
220- uint64_t imp_ofs = pe_rva2ofs (ctx , thunk -> u1 .AddressOfData );
266+ const uint64_t rva = thunk -> u1 .AddressOfData - (rva_based ? 0 : ctx -> pe .imagebase );
267+ const uint64_t imp_ofs = pe_rva2ofs (ctx , rva );
221268 const IMAGE_IMPORT_BY_NAME * imp_name = LIBPE_PTR_ADD (ctx -> map_addr , imp_ofs );
222269 if (!pe_can_read (ctx , imp_name , sizeof (IMAGE_IMPORT_BY_NAME ))) {
223270 imported_dll -> err = LIBPE_E_ALLOCATION_FAILURE ;
@@ -265,28 +312,44 @@ pe_imports_t *pe_imports(pe_ctx_t *ctx) {
265312 imports -> err = LIBPE_E_OK ;
266313
267314 imports -> dll_count = get_dll_count (ctx );
268- if (imports -> dll_count == 0 )
315+ imports -> delay_dll_count = get_delay_dll_count (ctx );
316+ if (imports -> dll_count == 0 && imports -> delay_dll_count == 0 )
269317 return imports ;
270318
271319 // Allocate array to store DLLs
272- imports -> dlls = calloc (imports -> dll_count , sizeof (pe_imported_dll_t ));
273- if (imports -> dlls == NULL ) {
274- imports -> err = LIBPE_E_ALLOCATION_FAILURE ;
275- return imports ;
320+ if (imports -> dll_count != 0 ) {
321+ imports -> dlls = calloc (imports -> dll_count , sizeof (pe_imported_dll_t ));
322+ if (imports -> dlls == NULL ) {
323+ imports -> err = LIBPE_E_ALLOCATION_FAILURE ;
324+ return imports ;
325+ }
276326 }
277327
278- const IMAGE_DATA_DIRECTORY * dir = pe_directory_by_entry (ctx , IMAGE_DIRECTORY_ENTRY_IMPORT );
279- if (dir == NULL ) {
280- return imports ;
328+ // Allocate array to store delay loaded DLLs
329+ if (imports -> delay_dll_count != 0 ) {
330+ imports -> delay_dlls = calloc (imports -> delay_dll_count , sizeof (pe_imported_dll_t ));
331+ if (imports -> delay_dlls == NULL ) {
332+ imports -> err = LIBPE_E_ALLOCATION_FAILURE ;
333+ return imports ;
334+ }
281335 }
282336
283- const uint64_t va = dir -> VirtualAddress ;
284- if (va == 0 ) {
285- // TODO: report error?
286- return imports ;
287- }
337+ uint64_t ofs = 0 ;
288338
289- uint64_t ofs = pe_rva2ofs (ctx , va );
339+ if (imports -> dll_count != 0 ) {
340+ const IMAGE_DATA_DIRECTORY * dir = pe_directory_by_entry (ctx , IMAGE_DIRECTORY_ENTRY_IMPORT );
341+ if (dir == NULL ) {
342+ return imports ;
343+ }
344+
345+ const uint64_t va = dir -> VirtualAddress ;
346+ if (va == 0 ) {
347+ // TODO: report error?
348+ return imports ;
349+ }
350+
351+ ofs = pe_rva2ofs (ctx , va );
352+ }
290353
291354 for (uint32_t i = 0 ; i < imports -> dll_count ; i ++ ) {
292355 IMAGE_IMPORT_DESCRIPTOR * id = LIBPE_PTR_ADD (ctx -> map_addr , ofs );
@@ -333,7 +396,78 @@ pe_imports_t *pe_imports(pe_ctx_t *ctx) {
333396 break ;
334397 }
335398
336- pe_err_e parse_err = parse_imported_functions (ctx , dll , ofs );
399+ // IMAGE_IMPORT_DESCRIPTOR is always RVA based.
400+ pe_err_e parse_err = parse_imported_functions (ctx , dll , ofs , true);
401+ if (parse_err != LIBPE_E_OK ) {
402+ imports -> err = parse_err ;
403+ return imports ;
404+ }
405+
406+ ofs = aux ; // Restore previous ofs
407+ }
408+
409+ if (imports -> delay_dll_count != 0 ) {
410+ const IMAGE_DATA_DIRECTORY * dir = pe_directory_by_entry (ctx , IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT );
411+ if (dir == NULL ) {
412+ return imports ;
413+ }
414+
415+ const uint64_t va = dir -> VirtualAddress ;
416+ if (va == 0 ) {
417+ // TODO: report error?
418+ return imports ;
419+ }
420+
421+ ofs = pe_rva2ofs (ctx , va );
422+ }
423+
424+ for (uint32_t i = 0 ; i < imports -> delay_dll_count ; i ++ ) {
425+ IMAGE_DELAYLOAD_DESCRIPTOR * dd = LIBPE_PTR_ADD (ctx -> map_addr , ofs );
426+ if (!pe_can_read (ctx , dd , sizeof (IMAGE_DELAYLOAD_DESCRIPTOR ))) {
427+ break ;
428+ }
429+
430+ if (!dd -> ImportNameTableRVA )
431+ break ;
432+
433+ ofs += sizeof (IMAGE_DELAYLOAD_DESCRIPTOR );
434+ const uint64_t aux = ofs ; // Store current ofs
435+
436+ ofs = pe_rva2ofs (ctx , dd -> DllNameRVA - (dd -> Attributes .u1 .RvaBased ? 0 : ctx -> pe .imagebase ));
437+ if (ofs == 0 )
438+ break ;
439+
440+ const char * dll_name_ptr = LIBPE_PTR_ADD (ctx -> map_addr , ofs );
441+ if (!pe_can_read (ctx , dll_name_ptr , 1 )) {
442+ // TODO: Should we report something?
443+ break ;
444+ }
445+
446+ pe_imported_dll_t * const dll = & imports -> delay_dlls [i ];
447+
448+ // Allocate string to store DLL name
449+ const size_t dll_name_size = MAX_DLL_NAME ;
450+ dll -> name = calloc (1 , dll_name_size );
451+ if (dll -> name == NULL ) {
452+ imports -> err = LIBPE_E_ALLOCATION_FAILURE ;
453+ return imports ;
454+ }
455+
456+ // Validate whether it's ok to access at least 1 byte after dll_name_ptr.
457+ // It might be '\0', for example.
458+ strncpy (dll -> name , dll_name_ptr , dll_name_size - 1 );
459+ // Because `strncpy` does not guarantee to NUL terminate the string itself, this must be done explicitly.
460+ dll -> name [dll_name_size - 1 ] = '\0' ;
461+
462+ ofs = pe_rva2ofs (ctx , dd -> ImportNameTableRVA );
463+ if (ofs == 0 ) {
464+ break ;
465+ }
466+
467+ // IMAGE_DELAYLOAD_DESCRIPTOR v1 is absolute address based and v2 is RVA based.
468+ // LINK.EXE from Visual C++ 6.0 generates IMAGE_DELAYLOAD_DESCRIPTOR v1.
469+ // LINK.EXE from Visual C++ 7.0/2002 and new generates IMAGE_DELAYLOAD_DESCRIPTOR v2.
470+ pe_err_e parse_err = parse_imported_functions (ctx , dll , ofs , dd -> Attributes .u1 .RvaBased );
337471 if (parse_err != LIBPE_E_OK ) {
338472 imports -> err = parse_err ;
339473 return imports ;
@@ -358,6 +492,16 @@ void pe_imports_dealloc(pe_imports_t *obj) {
358492 free (dll -> name );
359493 free (dll -> functions );
360494 }
495+ for (uint32_t i = 0 ; i < obj -> delay_dll_count ; i ++ ) {
496+ const pe_imported_dll_t * dll = & obj -> delay_dlls [i ];
497+ for (uint32_t j = 0 ; j < dll -> functions_count ; j ++ ) {
498+ const pe_imported_function_t * function = & dll -> functions [j ];
499+ free (function -> name );
500+ }
501+ free (dll -> name );
502+ free (dll -> functions );
503+ }
361504 free (obj -> dlls );
505+ free (obj -> delay_dlls );
362506 free (obj );
363507}
0 commit comments