libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
delayed_imports_loader.cpp
Go to the documentation of this file.
3
4#include <iostream>
5
6IMAGE_DELAYLOAD_DESCRIPTOR* peconv::get_delayed_imps(IN const BYTE* modulePtr, IN const size_t moduleSize, OUT size_t &dir_size)
7{
8 dir_size = 0;
9 IMAGE_DATA_DIRECTORY *d_imps_dir = peconv::get_directory_entry(modulePtr, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
10 if (!d_imps_dir) {
11 return nullptr;
12 }
13 BYTE* dimps_table = (BYTE*)((ULONGLONG) modulePtr + d_imps_dir->VirtualAddress);
14 const size_t min_size = sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
15 if (d_imps_dir->Size < min_size) {
16 return nullptr;
17 }
18 if (!peconv::validate_ptr((LPVOID)modulePtr, moduleSize, dimps_table, min_size)) {
19 return nullptr;
20 }
21 dir_size = d_imps_dir->Size;
22 return reinterpret_cast<IMAGE_DELAYLOAD_DESCRIPTOR*> (dimps_table);
23}
24
25template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
26bool parse_delayed_desc(BYTE* modulePtr, const size_t moduleSize,
27 const ULONGLONG img_base,
28 LPSTR lib_name,
29 const T_FIELD ordinal_flag,
31 peconv::t_function_resolver* func_resolver
32)
33{
34 ULONGLONG iat_addr = desc->ImportAddressTableRVA;
35
36 if (iat_addr > img_base) iat_addr -= img_base; // it may be either RVA or VA
37
38 ULONGLONG thunk_addr = desc->ImportNameTableRVA;
39 if (thunk_addr > img_base) thunk_addr -= img_base; // it may be either RVA or VA
40
41 T_FIELD* record_va = (T_FIELD*)((ULONGLONG)modulePtr + iat_addr);
42 T_IMAGE_THUNK_DATA* thunk_va = (T_IMAGE_THUNK_DATA*)((ULONGLONG)modulePtr + thunk_addr);
43
44 for (; *record_va != NULL && thunk_va != NULL; record_va++, thunk_va++) {
45 if (!peconv::validate_ptr(modulePtr, moduleSize, record_va, sizeof(T_FIELD))) {
46 return false;
47 }
48 if (!peconv::validate_ptr(modulePtr, moduleSize, thunk_va, sizeof(T_FIELD))) {
49 return false;
50 }
51
52 T_FIELD iat_va = *record_va;
53 ULONGLONG iat_rva = (ULONGLONG)iat_va;
54 if (iat_va > img_base) iat_rva -= img_base; // it may be either RVA or VA
55#ifdef _DEBUG
56 std::cout << std::hex << iat_rva << " : ";
57#endif
58 T_FIELD* iat_record_ptr = (T_FIELD*)((ULONGLONG)modulePtr + iat_rva);
59 if (!peconv::validate_ptr(modulePtr, moduleSize, iat_record_ptr, sizeof(T_FIELD))) {
60 return false;
61 }
62 FARPROC hProc = nullptr;
63 if (thunk_va->u1.Ordinal & ordinal_flag) {
64 T_FIELD raw_ordinal = thunk_va->u1.Ordinal & (~ordinal_flag);
65#ifdef _DEBUG
66 std::cout << std::hex << "ord: " << raw_ordinal << " ";
67#endif
68 hProc = func_resolver->resolve_func(lib_name, MAKEINTRESOURCEA(raw_ordinal));
69 }
70 else {
71 ULONGLONG name_rva = thunk_va->u1.AddressOfData;
72 if (name_rva > img_base) {
73 name_rva -= img_base;
74 }
75 PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + name_rva);
76 LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
77 if (!peconv::is_valid_import_name(modulePtr, moduleSize, func_name)) {
78 continue;
79 }
80#ifdef _DEBUG
81 std::cout << func_name << " ";
82#endif
83 hProc = func_resolver->resolve_func(lib_name, func_name);
84 }
85 if (hProc) {
86 //rather than loading it via proxy function, we just overwrite the thunk like normal IAT:
87 *record_va = (T_FIELD) hProc;
88#ifdef _DEBUG
89 std::cout << "[OK]\n";
90#endif
91 }
92 else {
93#ifdef _DEBUG
94 std::cout << "[NOPE]\n";
95#endif
96 }
97 }
98 return true;
99}
100
101bool peconv::load_delayed_imports(BYTE* modulePtr, ULONGLONG moduleBase, t_function_resolver* func_resolver)
102{
103 if (!peconv::get_directory_entry(modulePtr, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)) {
104 return true; // nothing to resolve
105 }
106 const bool is_64bit = peconv::is64bit(modulePtr);
107 bool is_loader64 = false;
108#ifdef _WIN64
109 is_loader64 = true;
110#endif
111 if (is_64bit != is_loader64) {
112 std::cerr << "[ERROR] Loader/Payload bitness mismatch.\n";
113 return false;
114 }
115
116 const size_t module_size = peconv::get_image_size(modulePtr);
117 default_func_resolver default_res;
118 if (!func_resolver) {
119 func_resolver = (t_function_resolver*)&default_res;
120 }
121 size_t table_size = 0;
122 IMAGE_DELAYLOAD_DESCRIPTOR *first_desc = get_delayed_imps(modulePtr, module_size, table_size);
123 if (!first_desc) {
124 return false;
125 }
126#ifdef _DEBUG
127 std::cout << "OK, table_size = " << table_size << std::endl;
128#endif
129 bool is_ok = true;
130 size_t max_count = table_size / sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
131 for (size_t i = 0; i < max_count; i++) {
132 IMAGE_DELAYLOAD_DESCRIPTOR *desc = &first_desc[i];
133 if (!validate_ptr(modulePtr, module_size, desc, sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))) break;
134 if (desc->DllNameRVA == NULL) {
135 break;
136 }
137 ULONGLONG dll_name_rva = desc->DllNameRVA;
138 if (dll_name_rva > moduleBase) {
139 dll_name_rva -= moduleBase;
140 }
141 char* dll_name = (char*)((ULONGLONG) modulePtr + dll_name_rva);
142 if (!validate_ptr(modulePtr, module_size, dll_name, sizeof(char))) continue;
143#ifdef _DEBUG
144 std::cout << dll_name << std::endl;
145#endif
146 if (is_64bit) {
147#ifdef _WIN64
148 is_ok = parse_delayed_desc<ULONGLONG,IMAGE_THUNK_DATA64>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG64, desc, func_resolver);
149#else
150 return false;
151#endif
152 }
153 else {
154#ifndef _WIN64
155 is_ok = parse_delayed_desc<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG32, desc, func_resolver);
156#else
157 return false;
158#endif
159 }
160 }
161 return is_ok;
162}
virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name)=0
bool parse_delayed_desc(BYTE *modulePtr, const size_t moduleSize, const ULONGLONG img_base, LPSTR lib_name, const T_FIELD ordinal_flag, IMAGE_DELAYLOAD_DESCRIPTOR *desc, peconv::t_function_resolver *func_resolver)
Parsing and filling the Delayload Import Table.
struct _IMAGE_DELAYLOAD_DESCRIPTOR IMAGE_DELAYLOAD_DESCRIPTOR
Parsing and filling the Import Table.
bool load_delayed_imports(BYTE *modulePtr, const ULONGLONG moduleBase, t_function_resolver *func_resolver=nullptr)
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
DWORD get_image_size(IN const BYTE *payload)
bool is64bit(IN const BYTE *pe_buffer)
bool is_valid_import_name(const PBYTE modulePtr, const size_t moduleSize, LPSTR lib_name)
IMAGE_DATA_DIRECTORY * get_directory_entry(IN const BYTE *pe_buffer, IN DWORD dir_id, IN bool allow_empty=false)
IMAGE_DELAYLOAD_DESCRIPTOR * get_delayed_imps(IN const BYTE *modulePtr, IN const size_t moduleSize, OUT size_t &dir_size)