16 virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
20 IMAGE_THUNK_DATA64* desc =
reinterpret_cast<IMAGE_THUNK_DATA64*
>(origFirstThunkPtr);
21 ULONGLONG* call_via =
reinterpret_cast<ULONGLONG*
>(firstThunkPtr);
22 return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
24 LOG_ERROR(
"Cannot fill imports into 64-bit PE via 32-bit loader.");
30 IMAGE_THUNK_DATA32* desc =
reinterpret_cast<IMAGE_THUNK_DATA32*
>(origFirstThunkPtr);
31 DWORD* call_via =
reinterpret_cast<DWORD*
>(firstThunkPtr);
32 return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
34 LOG_ERROR(
"Cannot fill imports into 32-bit PE via 64-bit loader.");
41 template <
typename T_FIELD,
typename T_IMAGE_THUNK_DATA>
42 bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc, T_FIELD* call_via, T_FIELD ordinal_flag)
44 static_assert(
sizeof(T_FIELD) >=
sizeof(ULONG_PTR),
"T_FIELD must be wide enough to hold a function pointer");
50 const bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
52 FARPROC hProc =
nullptr;
54 T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
55 LOG_DEBUG(
"raw ordinal: 0x%llx.", (
unsigned long long)raw_ordinal);
60 PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)
modulePtr + desc->u1.AddressOfData);
62 LOG_ERROR(
"Invalid pointer to IMAGE_IMPORT_BY_NAME.");
65 const LPSTR func_name =
reinterpret_cast<LPSTR
>(by_name->Name);
67 LOG_ERROR(
"Invalid pointer to function name.");
74 LOG_ERROR(
"Could not resolve the function.");
78 (*call_via) =
reinterpret_cast<T_FIELD
>(hProc);
100 virtual bool processThunks(LPSTR libName, ULONG_PTR origFirstThunkPtr, ULONG_PTR va)
105 const ULONGLONG module_base =
reinterpret_cast<ULONGLONG
>(this->
vBuf);
106 if (va < module_base) {
109 if (va >= module_base + this->
vBufSize) {
132 virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
135 IMAGE_THUNK_DATA64* desc =
reinterpret_cast<IMAGE_THUNK_DATA64*
>(origFirstThunkPtr);
136 ULONGLONG* call_via =
reinterpret_cast<ULONGLONG*
>(firstThunkPtr);
137 return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
142 IMAGE_THUNK_DATA32* desc =
reinterpret_cast<IMAGE_THUNK_DATA32*
>(origFirstThunkPtr);
143 DWORD* call_via =
reinterpret_cast<DWORD*
>(firstThunkPtr);
144 return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
149 template <
typename T_FIELD,
typename T_IMAGE_THUNK_DATA>
150 bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc, T_FIELD* call_via, T_FIELD ordinal_flag)
157 const bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
161 T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
162 func =
new ExportedFunc(short_name, IMAGE_ORDINAL64(raw_ordinal));
165 PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)
modulePtr + desc->u1.AddressOfData);
167 LOG_ERROR(
"Invalid pointer to IMAGE_IMPORT_BY_NAME.");
170 const LPSTR func_name =
reinterpret_cast<LPSTR
>(by_name->Name);
172 LOG_ERROR(
"Invalid pointer to function name.");
175 const WORD ordinal = by_name->Hint;
176 func =
new ExportedFunc(short_name, func_name, ordinal);
192template <
typename T_FIELD,
typename T_IMAGE_THUNK_DATA>
195 static_assert(
sizeof(T_FIELD) ==
sizeof(T_IMAGE_THUNK_DATA),
"T_FIELD and T_IMAGE_THUNK_DATA must have the same size");
199 T_FIELD *thunks = (T_FIELD*)((ULONGLONG)modulePtr + thunk_addr);
200 T_FIELD *callers = (T_FIELD*)((ULONGLONG)modulePtr + call_via);
202 for (
size_t index = 0;
true; index++) {
203 T_IMAGE_THUNK_DATA* desc =
reinterpret_cast<T_IMAGE_THUNK_DATA*
>((LPVOID) &thunks[index]);
204 if (!
validate_ptr(modulePtr, module_size, desc,
sizeof(T_IMAGE_THUNK_DATA))) {
208 if (desc->u1.Function == 0) {
209 LOG_DEBUG(
"Desc[%d], RVA = 0x%llx is empty. Finishing.", (
int)index, (
unsigned long long)((ULONG_PTR)&desc->u1.Function - (ULONG_PTR)modulePtr) );
213 if (!
validate_ptr(modulePtr, module_size, &callers[index],
sizeof(T_FIELD))) {
217 T_FIELD ordinal_flag = (
sizeof(T_FIELD) ==
sizeof(ULONGLONG)) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32;
218 bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
220 PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
221 if (!
validate_ptr(modulePtr, module_size, by_name,
sizeof(IMAGE_IMPORT_BY_NAME))) {
228 if (callback && !callback->processThunks(lib_name, (ULONG_PTR)&thunks[index], (ULONG_PTR)&callers[index])) {
238 bool isAllFilled =
true;
240 const bool is64 =
is64bit((BYTE*)modulePtr);
241 IMAGE_IMPORT_DESCRIPTOR* lib_desc =
nullptr;
243 for (
size_t i = 0;
true; i++) {
244 lib_desc = &first_desc[i];
245 if (!
validate_ptr(modulePtr, module_size, lib_desc,
sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
248 if (!lib_desc->OriginalFirstThunk && !lib_desc->FirstThunk) {
251 LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name);
256 DWORD call_via = lib_desc->FirstThunk;
257 DWORD thunk_addr = lib_desc->OriginalFirstThunk;
259 thunk_addr = lib_desc->FirstThunk;
261 LOG_DEBUG(
"Imported Lib: 0x%lx : 0x%lx : 0x%lx", lib_desc->FirstThunk, lib_desc->OriginalFirstThunk, lib_desc->Name);
262 bool all_solved =
false;
264 all_solved = process_imp_functions_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(modulePtr, module_size, lib_name, call_via, thunk_addr, callback);
267 all_solved = process_imp_functions_tpl<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, lib_name, call_via, thunk_addr, callback);
279 if (moduleSize == 0) {
282 if (moduleSize == 0)
return false;
284 IMAGE_DATA_DIRECTORY *importsDir =
get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
288 const DWORD impAddr = importsDir->VirtualAddress;
289 IMAGE_IMPORT_DESCRIPTOR *first_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + (ULONG_PTR)modulePtr);
290 if (!
peconv::validate_ptr(modulePtr, moduleSize, first_desc,
sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
293 return process_dlls(modulePtr, moduleSize, first_desc, callback);
299 if (moduleSize == 0)
return false;
301 bool is64 =
is64bit((BYTE*)modulePtr);
302 bool is_loader64 =
false;
306 if (is64 != is_loader64) {
307 LOG_ERROR(
"Loader/Payload bitness mismatch.");
312 if (!func_resolver) {
313 func_resolver = &default_res;
323 bool is_terminated =
false;
324 for (
size_t i = 0; i < MAX_PATH; i++) {
328 char next_char = *lib_name;
329 if (next_char ==
'\0') {
330 is_terminated =
true;
333 if (next_char < 0x20 || next_char >= 0x7E) {
338 return is_terminated;
342 template <
typename FIELD_T>
343 bool _has_valid_import_table(
const PBYTE modulePtr,
size_t moduleSize,
size_t maxCount = 0)
345 IMAGE_DATA_DIRECTORY* importsDir =
get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
346 if (!importsDir)
return false;
348 const DWORD impAddr = importsDir->VirtualAddress;
349 if (impAddr == 0 || impAddr >= moduleSize) {
352 IMAGE_IMPORT_DESCRIPTOR* lib_desc =
nullptr;
353 size_t parsedSize = 0;
354 size_t valid_records = 0;
356 bool is_terminated =
false;
357 while (parsedSize < moduleSize) {
359 if (maxCount != 0 && valid_records >= maxCount) {
362 lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)((ULONG_PTR)impAddr + parsedSize + (ULONG_PTR)modulePtr);
366 parsedSize +=
sizeof(IMAGE_IMPORT_DESCRIPTOR);
368 if (!lib_desc->OriginalFirstThunk && !lib_desc->FirstThunk) {
369 is_terminated =
true;
372 LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name);
375 DWORD call_via = lib_desc->FirstThunk;
376 DWORD thunk_addr = lib_desc->OriginalFirstThunk;
377 if (!thunk_addr) thunk_addr = lib_desc->FirstThunk;
379 FIELD_T* thunks = (FIELD_T*)((ULONGLONG)modulePtr + thunk_addr);
382 FIELD_T* callers = (FIELD_T*)((ULONGLONG)modulePtr + call_via);
387 return is_terminated && (valid_records > 0);
394 return _has_valid_import_table<ULONGLONG>(modulePtr, moduleSize, maxCount);
396 return _has_valid_import_table<DWORD>(modulePtr, moduleSize, maxCount);
#define MASK_TO_DWORD(val)
CollectImportsCallback(BYTE *_modulePtr, size_t _moduleSize, std::map< DWORD, ExportedFunc * > &_thunkToFunc)
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA *desc, T_FIELD *call_via, T_FIELD ordinal_flag)
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
std::map< DWORD, ExportedFunc * > & thunkToFunc
virtual bool processThunks(LPSTR libName, ULONG_PTR origFirstThunkPtr, ULONG_PTR va)
CollectThunksCallback(BYTE *_vBuf, size_t _vBufSize, std::set< DWORD > &_fields)
std::set< DWORD > & fields
FillImportThunks(BYTE *_modulePtr, size_t _moduleSize, t_function_resolver *func_resolver)
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA *desc, T_FIELD *call_via, T_FIELD ordinal_flag)
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
t_function_resolver * funcResolver
virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name)=0
bool process_dlls(BYTE *modulePtr, size_t module_size, IMAGE_IMPORT_DESCRIPTOR *first_desc, IN ImportThunksCallback *callback)
bool process_imp_functions_tpl(BYTE *modulePtr, size_t module_size, LPSTR lib_name, DWORD call_via, DWORD thunk_addr, IN ImportThunksCallback *callback)
Parsing and filling the Import Table.
Compile-time configurable logging macros for peconv.
#define LOG_DEBUG(fmt,...)
#define LOG_ERROR(fmt,...)
bool has_valid_import_table(const PBYTE modulePtr, size_t moduleSize, size_t max_count=0)
bool is_valid_string(LPVOID modulePtr, const size_t moduleSize, const CHAR_T *name_ptr, const size_t max_len=260)
bool process_import_table(IN BYTE *modulePtr, IN SIZE_T moduleSize, IN ImportThunksCallback *callback)
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 collect_thunks(IN BYTE *modulePtr, IN SIZE_T moduleSize, OUT std::set< DWORD > &thunk_rvas)
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)
bool collect_imports(IN BYTE *modulePtr, IN SIZE_T moduleSize, OUT ImportsCollection &collection)
std::string get_dll_shortname(const std::string &str)
bool load_imports(BYTE *modulePtr, t_function_resolver *func_resolver=nullptr)
Miscellaneous utility functions.