static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll) { ULONG_PTR *lookup_tbl, *address_tbl; char *symname = NULL; int i; int ret = 0; void *adr; lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *); address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *); for (i = 0; lookup_tbl[i]; i++) { if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) { ERROR("ordinal import not supported: %Lu", (uint64_t)lookup_tbl[i]); return -1; } else { symname = RVA2VA(image, ((lookup_tbl[i] & ~IMAGE_ORDINAL_FLAG) + 2), char *); } adr = get_export(symname); if (adr == NULL) { ERROR("unknown symbol: %s:'%s'", dll, symname); ret = -1; } else { DBGLINKER("found symbol: %s:%s: addr: %p, rva = %Lu", dll, symname, adr, (uint64_t)address_tbl[i]); address_tbl[i] = (ULONG_PTR)adr; } } return ret; }
void __cdecl DefaultHook( PVOID dummy ) { __asm pushad // Save all general purpose registers // Get return address, then subtract 5 (size of a CALL X instruction) // The result points at a DLPD_IAT_STUB // pointer math! &dummy-1 really subtracts sizeof(PVOID) PDWORD pRetAddr = (PDWORD)(&dummy - 1); DLPD_IAT_STUB * pDLPDStub = (DLPD_IAT_STUB *)(*pRetAddr - 5); pDLPDStub->count++; #if 0 // Remove the above conditional to get a cheezy API trace from // the loader process. It's slow! if ( !IMAGE_SNAP_BY_ORDINAL( pDLPDStub->pszNameOrOrdinal) ) { OutputDebugString( "Called hooked function: " ); OutputDebugString( (PSTR)pDLPDStub->pszNameOrOrdinal ); OutputDebugString( "\n" ); } #endif __asm popad // Restore all general purpose registers }
//************************************************************ // 函数名称: RecIAT // 函数说明: 修复IAT操作 // 作 者: cyxvc // 时 间: 2015/12/28 // 返 回 值: void //************************************************************ void RecIAT() { //1.获取导入表结构体指针 PIMAGE_IMPORT_DESCRIPTOR pPEImport = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + g_stcShellData.stcPEImportDir.VirtualAddress); //2.修改内存属性为可写 DWORD dwOldProtect = 0; g_pfnVirtualProtect( (LPBYTE)(dwImageBase + g_stcShellData.dwIATSectionBase), g_stcShellData.dwIATSectionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect); //3.开始修复IAT while (pPEImport->Name) { //获取模块名 DWORD dwModNameRVA = pPEImport->Name; char* pModName = (char*)(dwImageBase + dwModNameRVA); HMODULE hMod = g_pfnLoadLibraryA(pModName); //获取IAT信息(有些文件INT是空的,最好用IAT解析,也可两个都解析作对比) PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(dwImageBase + pPEImport->FirstThunk); //获取INT信息(同IAT一样,可将INT看作是IAT的一个备份) //PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)(dwImageBase + pPEImport->OriginalFirstThunk); //通过IAT循环获取该模块下的所有函数信息(这里之获取了函数名) while (pIAT->u1.AddressOfData) { //判断是输出函数名还是序号 if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal)) { //输出序号 DWORD dwFunOrdinal = (pIAT->u1.Ordinal) & 0x7FFFFFFF; DWORD dwFunAddr = g_pfnGetProcAddress(hMod, (char*)dwFunOrdinal); *(DWORD*)pIAT = (DWORD)dwFunAddr; } else { //输出函数名 DWORD dwFunNameRVA = pIAT->u1.AddressOfData; PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(dwImageBase + dwFunNameRVA); DWORD dwFunAddr = g_pfnGetProcAddress(hMod, (LPCSTR)(pstcFunName->Name)); *(DWORD*)pIAT = (DWORD)dwFunAddr; } pIAT++; } //遍历下一个模块 pPEImport++; } //4.恢复内存属性 g_pfnVirtualProtect( (LPBYTE)(dwImageBase + g_stcShellData.dwIATSectionBase), g_stcShellData.dwIATSectionSize, dwOldProtect, &dwOldProtect); }
BOOL hook_getprocaddress() { HMODULE vim; PIMAGE_IMPORT_DESCRIPTOR impdesc; PIMAGE_IMPORT_DESCRIPTOR kernel32; PIMAGE_THUNK_DATA lookuptbl; PIMAGE_THUNK_DATA addrtbl; MEMORY_BASIC_INFORMATION bufinfo; BOOL succeeded; DWORD oldprotect; DWORD retsize; int i; vim = GetModuleHandle(NULL); impdesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData((HMODULE)vim, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &retsize); if (retsize == 0) return FALSE; OutputDebugString("dynfont: importdir found"); kernel32 = NULL; for (i = 0; impdesc[i].Characteristics != 0; ++i) { LPCSTR libname = (LPCSTR)((char*)vim + impdesc[i].Name); OutputDebugString(libname); if (lstrcmpi(libname, "KERNEL32.DLL") == 0) { kernel32 = &impdesc[i]; break; } } if (kernel32 == NULL) return FALSE; OutputDebugString("dynfont: kernel32 found."); lookuptbl = (PIMAGE_THUNK_DATA)((char*)vim + kernel32->OriginalFirstThunk); addrtbl = (PIMAGE_THUNK_DATA)((char*)vim + kernel32->FirstThunk); for (; lookuptbl->u1.Function != 0; ++lookuptbl, ++addrtbl) { if (!IMAGE_SNAP_BY_ORDINAL(lookuptbl->u1.Ordinal)) { PIMAGE_IMPORT_BY_NAME impfun = (PIMAGE_IMPORT_BY_NAME)((char*)vim + lookuptbl->u1.AddressOfData); if (strcmp((LPCSTR)impfun->Name, "GetProcAddress") == 0) { break; } } } if (lookuptbl->u1.Function == 0) return FALSE; OutputDebugString("dynfont: getprocaddr found."); orig_GetProcAddress = (GETPROCADDRESS_PROTO)addrtbl->u1.Function; retsize = VirtualQuery((LPCVOID)&addrtbl->u1.Function, &bufinfo, sizeof(bufinfo)); if (retsize == 0) return FALSE; succeeded = VirtualProtect(bufinfo.BaseAddress, bufinfo.RegionSize, PAGE_READWRITE, &oldprotect); if (succeeded == FALSE) return FALSE; addrtbl->u1.Function = (DWORD_PTR)oncall_GetProcAddress; VirtualProtect(bufinfo.BaseAddress, bufinfo.RegionSize, bufinfo.Protect, &oldprotect); OutputDebugString("dynfont: hooked."); return TRUE; }
// 函数说明: 抹去IAT(导入表)数据 void CPE::ClsImportTab() { if (m_PEImportDir.VirtualAddress == 0) { return; } //1.获取导入表结构体指针 PIMAGE_IMPORT_DESCRIPTOR pPEImport = (PIMAGE_IMPORT_DESCRIPTOR)(m_pFileBuf + m_PEImportDir.VirtualAddress); //2.开始循环抹去IAT(导入表)数据 //每循环一次抹去一个Dll的所有导入信息 while (pPEImport->Name) { //2.1.抹去模块名 DWORD dwModNameRVA = pPEImport->Name; char* pModName = (char*)(m_pFileBuf + dwModNameRVA); memset(pModName, 0, strlen(pModName)); PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->FirstThunk); PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->OriginalFirstThunk); //2.2.抹去IAT、INT和函数名函数序号 while (pIAT->u1.AddressOfData) { //判断是输出函数名还是序号 if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal)) { //抹去序号就是将pIAT清空 } else { //输出函数名 DWORD dwFunNameRVA = pIAT->u1.AddressOfData; PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(m_pFileBuf + dwFunNameRVA); //清除函数名和函数序号 memset(pstcFunName, 0, strlen(pstcFunName->Name) + sizeof(WORD)); } memset(pINT, 0, sizeof(IMAGE_THUNK_DATA)); memset(pIAT, 0, sizeof(IMAGE_THUNK_DATA)); pINT++; pIAT++; } //2.3.抹去导入表目录信息 memset(pPEImport, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR)); //遍历下一个模块 pPEImport++; } }
void * GetIATAddr(void * module, const char * searchDllName, const char * searchImportName) { UInt8 * base = (UInt8 *)module; IMAGE_DOS_HEADER * dosHeader = (IMAGE_DOS_HEADER *)base; IMAGE_NT_HEADERS * ntHeader = (IMAGE_NT_HEADERS *)(base + dosHeader->e_lfanew); IMAGE_IMPORT_DESCRIPTOR * importTable = (IMAGE_IMPORT_DESCRIPTOR *)(base + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); for(; importTable->Characteristics; ++importTable) { const char * dllName = (const char *)(base + importTable->Name); if(!_stricmp(dllName, searchDllName)) { // found the dll IMAGE_THUNK_DATA * thunkData = (IMAGE_THUNK_DATA *)(base + importTable->OriginalFirstThunk); uintptr_t * iat = (uintptr_t *)(base + importTable->FirstThunk); for(; thunkData->u1.Ordinal; ++thunkData, ++iat) { if(!IMAGE_SNAP_BY_ORDINAL(thunkData->u1.Ordinal)) { IMAGE_IMPORT_BY_NAME * importInfo = (IMAGE_IMPORT_BY_NAME *)(base + thunkData->u1.AddressOfData); if(!_stricmp((char *)importInfo->Name, searchImportName)) { // found the import return iat; } } } return NULL; } } return NULL; }
BOOL WINAPI DetourEnumerateImports(HMODULE hModule, PVOID pContext, PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; if (hModule == NULL) { pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); } __try { if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); return FALSE; } PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + pDosHeader->e_lfanew); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { SetLastError(ERROR_INVALID_EXE_SIGNATURE); return FALSE; } if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; } PIMAGE_IMPORT_DESCRIPTOR iidp = (PIMAGE_IMPORT_DESCRIPTOR) RvaAdjust(pDosHeader, pNtHeader->OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); if (iidp == NULL) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; } for (; iidp->OriginalFirstThunk != 0; iidp++) { PCSTR pszName = (PCHAR)RvaAdjust(pDosHeader, iidp->Name); if (pszName == NULL) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; } PIMAGE_THUNK_DATA pThunks = (PIMAGE_THUNK_DATA) RvaAdjust(pDosHeader, iidp->OriginalFirstThunk); PVOID * pAddrs = (PVOID *) RvaAdjust(pDosHeader, iidp->FirstThunk); HMODULE hFile = DetourGetContainingModule(pAddrs[0]); if (pfImportFile != NULL) { if (!pfImportFile(pContext, hFile, pszName)) { break; } } DWORD nNames = 0; if (pThunks) { for (; pThunks[nNames].u1.Ordinal; nNames++) { DWORD nOrdinal = 0; PCSTR pszFunc = NULL; if (IMAGE_SNAP_BY_ORDINAL(pThunks[nNames].u1.Ordinal)) { nOrdinal = (DWORD)IMAGE_ORDINAL(pThunks[nNames].u1.Ordinal); } else { pszFunc = (PCSTR)RvaAdjust(pDosHeader, (DWORD)pThunks[nNames].u1.AddressOfData + 2); } if (pfImportFunc != NULL) { if (!pfImportFunc(pContext, nOrdinal, pszFunc, pAddrs[nNames])) { break; } } } if (pfImportFunc != NULL) { pfImportFunc(pContext, 0, NULL, NULL); } } } if (pfImportFile != NULL) { pfImportFile(pContext, NULL, NULL); } SetLastError(NO_ERROR); return TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; } }
static DWORD fixup_imports( WINE_MODREF *wm ) { IMAGE_IMPORT_DESCRIPTOR *pe_imp; PE_MODREF *pem; unsigned int load_addr = wm->module; int i,characteristics_detection=1; char *modname; assert(wm->type==MODULE32_PE); pem = &(wm->binfmt.pe); if (pem->pe_export) modname = (char*) RVA(pem->pe_export->Name); else modname = "<unknown>"; TRACE("Dumping imports list\n"); pe_imp = pem->pe_import; if (!pe_imp) return 0; /* We assume that we have at least one import with !0 characteristics and * detect broken imports with all characteristsics 0 (notably Borland) and * switch the detection off for them. */ for (i = 0; pe_imp->Name ; pe_imp++) { if (!i && !pe_imp->u.Characteristics) characteristics_detection = 0; if (characteristics_detection && !pe_imp->u.Characteristics) break; i++; } if (!i) return 0; wm->nDeps = i; wm->deps = HeapAlloc( GetProcessHeap(), 0, i*sizeof(WINE_MODREF *) ); /* load the imported modules. They are automatically * added to the modref list of the process. */ for (i = 0, pe_imp = pem->pe_import; pe_imp->Name ; pe_imp++) { IMAGE_IMPORT_BY_NAME *pe_name; PIMAGE_THUNK_DATA import_list,thunk_list; char *name = (char *) RVA(pe_imp->Name); if (characteristics_detection && !pe_imp->u.Characteristics) break; /* FIXME: here we should fill imports */ TRACE("Loading imports for %s.dll\n", name); if (pe_imp->u.OriginalFirstThunk != 0) { TRACE("Microsoft style imports used\n"); import_list =(PIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk); thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk); while (import_list->u1.Ordinal) { if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) { int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal); // TRACE("--- Ordinal %s,%d\n", name, ordinal); thunk_list->u1.Function=LookupExternal(name, ordinal); } else { pe_name = (PIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData); // TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint); thunk_list->u1.Function=LookupExternalByName(name, pe_name->Name); } import_list++; thunk_list++; } } else { TRACE("Borland style imports used\n"); thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk); while (thunk_list->u1.Ordinal) { if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) { int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal); TRACE("--- Ordinal %s.%d\n",name,ordinal); thunk_list->u1.Function=LookupExternal( name, ordinal); } else { pe_name=(PIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData); TRACE("--- %s %s.%d\n", pe_name->Name,name,pe_name->Hint); thunk_list->u1.Function=LookupExternalByName( name, pe_name->Name); } thunk_list++; } } } return 0; }
static BOOL BuildImportTable(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; ULONG_PTR lpCookie = NULL; BOOL result = TRUE; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); if (directory->Size == 0) { return TRUE; } PIMAGE_DATA_DIRECTORY resource = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_RESOURCE); if (directory->Size == 0){ return TRUE; } PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); // Following will be used to resolve manifest in module if (resource->Size) { PIMAGE_RESOURCE_DIRECTORY resDir = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + resource->VirtualAddress); PIMAGE_RESOURCE_DIRECTORY resDirTemp; PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ((char*)resDir + sizeof(IMAGE_RESOURCE_DIRECTORY)); PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntryTemp; PIMAGE_RESOURCE_DATA_ENTRY resDataEntry; // ACTCTX Structure, not used members must be set to 0! ACTCTXA actctx ={0,0,0,0,0,0,0,0,0}; actctx.cbSize = sizeof(actctx); HANDLE hActCtx; // Path to temp directory + our temporary file name CHAR buf[MAX_PATH]; DWORD tempPathLength = GetTempPathA(MAX_PATH, buf); memcpy(buf + tempPathLength,"AutoHotkey.MemoryModule.temp.manifest",38); actctx.lpSource = buf; // Enumerate Resources int i = 0; if (_CreateActCtxA != NULL) for (;i < resDir->NumberOfIdEntries + resDir->NumberOfNamedEntries;i++) { // Resolve current entry resDirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((char*)resDir + sizeof(IMAGE_RESOURCE_DIRECTORY) + (i*sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))); // If entry is directory and Id is 24 = RT_MANIFEST if (resDirEntry->DataIsDirectory && resDirEntry->Id == 24) { //resDirTemp = (PIMAGE_RESOURCE_DIRECTORY)((char*)resDir + (resDirEntry->OffsetToDirectory)); resDirEntryTemp = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((char*)resDir + (resDirEntry->OffsetToDirectory) + sizeof(IMAGE_RESOURCE_DIRECTORY)); resDirTemp = (PIMAGE_RESOURCE_DIRECTORY) ((char*)resDir + (resDirEntryTemp->OffsetToDirectory)); resDirEntryTemp = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((char*)resDir + (resDirEntryTemp->OffsetToDirectory) + sizeof(IMAGE_RESOURCE_DIRECTORY)); resDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY) ((char*)resDir + (resDirEntryTemp->OffsetToData)); // Write manifest to temportary file // Using FILE_ATTRIBUTE_TEMPORARY will avoid writing it to disk // It will be deleted after CreateActCtx has been called. HANDLE hFile = CreateFileA(buf,GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY,NULL); if (hFile == INVALID_HANDLE_VALUE) { #if DEBUG_OUTPUT OutputDebugStringA("CreateFile failed.\n"); #endif break; //failed to create file, continue and try loading without CreateActCtx } DWORD byteswritten = 0; WriteFile(hFile,(codeBase + resDataEntry->OffsetToData),resDataEntry->Size,&byteswritten,NULL); CloseHandle(hFile); if (byteswritten == 0) { #if DEBUG_OUTPUT OutputDebugStringA("WriteFile failed.\n"); #endif break; //failed to write data, continue and try loading } hActCtx = _CreateActCtxA(&actctx); // Open file and automatically delete on CloseHandle (FILE_FLAG_DELETE_ON_CLOSE) hFile = CreateFileA(buf,GENERIC_WRITE,FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,NULL); CloseHandle(hFile); if (hActCtx == INVALID_HANDLE_VALUE) break; //failed to create context, continue and try loading _ActivateActCtx(hActCtx,&lpCookie); // Don't care if this fails since we would countinue anyway break; // Break since a dll can have only 1 manifest } } } for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { uintptr_t *thunkRef; FARPROC *funcRef; HCUSTOMMODULE *tmp; HCUSTOMMODULE handle = NULL; char *isMsvcr = NULL; if (g_hMSVCR != NULL && (isMsvcr = strstr((LPSTR)(codeBase + importDesc->Name), "MSVCR100.dll"))) { handle = g_hMSVCR; //GetModuleHandle(_T("MSVCRT.dll")); if (tmp == NULL) tmp = (HCUSTOMMODULE *)malloc((sizeof(HCUSTOMMODULE))); if (tmp == NULL) { SetLastError(ERROR_OUTOFMEMORY); result = 0; break; } module->modules = tmp; module->modules[0] = handle; } else handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); if (handle == NULL) { SetLastError(ERROR_MOD_NOT_FOUND); result = FALSE; break; } if (!isMsvcr) { tmp = (HCUSTOMMODULE *)realloc(module->modules, (module->numModules + 1)*(sizeof(HCUSTOMMODULE))); if (tmp == NULL) { module->freeLibrary(handle, module->userdata); SetLastError(ERROR_OUTOFMEMORY); result = 0; break; } module->modules = tmp; if (module->numModules == 1) module->modules[0] = NULL; module->modules[module->numModules++] = handle; } if (importDesc->OriginalFirstThunk) { thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } else { // no hint table thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } for (; *thunkRef; thunkRef++, funcRef++) { if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { if (!isMsvcr) *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); else *funcRef = MemoryGetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef)); } else { PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); if (!isMsvcr) *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); else *funcRef = MemoryGetProcAddress(handle, (LPCSTR)&thunkData->Name); } if (*funcRef == 0) { result = FALSE; break; } } if (!result) { module->freeLibrary(handle, module->userdata); SetLastError(ERROR_PROC_NOT_FOUND); break; } } if (_DeactivateActCtx && lpCookie) _DeactivateActCtx(NULL,lpCookie); return result; }
ARC_STATUS BlpBindImportName ( IN PVOID DllBase, IN PVOID ImageBase, IN PIMAGE_THUNK_DATA ThunkEntry, IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, IN ULONG ExportSize, IN BOOLEAN SnapForwarder ) /*++ Routine Description: This routine binds an import table reference with an exported entry point and fills in the thunk data. Arguments: DllBase - Supplies the base address of the DLL image that contains the export directory. On x86 systems, a NULL DllBase binds the import table reference to the OsLoader's exported entry points. ImageBase - Supplies the base address of the image that contains the import thunk table. ThunkEntry - Supplies a pointer to a thunk table entry. ExportDirectory - Supplies a pointer to the export directory of the DLL from which references are to be resolved. SnapForwarder - determine if the snap is for a forwarder, and therefore Address of Data is already setup. Return Value: ESUCCESS is returned if the specified thunk is bound. Otherwise, an return an unsuccessful status. --*/ { PULONG FunctionTable; LONG High; ULONG HintIndex; LONG Low; LONG Middle; PULONG NameTable; ULONG Ordinal; PUSHORT OrdinalTable; LONG Result; #if i386 if(DllBase == NULL) { DllBase = (PVOID)OsLoaderBase; } #endif // // If the reference is by ordinal, then compute the ordinal number. // Otherwise, lookup the import name in the export directory. // if (IMAGE_SNAP_BY_ORDINAL(ThunkEntry->u1.Ordinal) && !SnapForwarder) { // // Compute the ordinal. // Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkEntry->u1.Ordinal) - ExportDirectory->Base); } else { if (!SnapForwarder) { // // Change AddressOfData from an RVA to a VA. // ThunkEntry->u1.AddressOfData = (PIMAGE_IMPORT_BY_NAME)((ULONG)ImageBase + (ULONG)ThunkEntry->u1.AddressOfData); } // // Lookup the import name in the export table to determine the // ordinal. // NameTable = (PULONG)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfNames); OrdinalTable = (PUSHORT)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals); // // If the hint index is within the limits of the name table and the // import and export names match, then the ordinal number can be // obtained directly from the ordinal table. Otherwise, the name // table must be searched for the specified name. // HintIndex = ThunkEntry->u1.AddressOfData->Hint; if ((HintIndex < ExportDirectory->NumberOfNames) && (strcmp(&ThunkEntry->u1.AddressOfData->Name[0], (PCHAR)((ULONG)DllBase + NameTable[HintIndex])) == 0)) { // // Get the ordinal number from the ordinal table. // Ordinal = OrdinalTable[HintIndex]; } else { // // Lookup the import name in the name table using a binary search. // Low = 0; High = ExportDirectory->NumberOfNames - 1; while (High >= Low) { // // Compute the next probe index and compare the import name // with the export name entry. // Middle = (Low + High) >> 1; Result = strcmp(&ThunkEntry->u1.AddressOfData->Name[0], (PCHAR)((ULONG)DllBase + NameTable[Middle])); if (Result < 0) { High = Middle - 1; } else if (Result > 0) { Low = Middle + 1; } else { break; } } // // If the high index is less than the low index, then a matching // table entry was not found. Otherwise, get the ordinal number // from the ordinal table. // if (High < Low) { return EINVAL; } else { Ordinal = OrdinalTable[Middle]; } } } // // If the ordinal number is valid, then bind the import reference and // return success. Otherwise, return an unsuccessful status. // if (Ordinal >= ExportDirectory->NumberOfFunctions) { return EINVAL; } else { FunctionTable = (PULONG)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfFunctions); ThunkEntry->u1.Function = (PULONG)((ULONG)DllBase + FunctionTable[Ordinal]); // // Check for a forwarder. // if ( ((ULONG)ThunkEntry->u1.Function > (ULONG)ExportDirectory) && ((ULONG)ThunkEntry->u1.Function < ((ULONG)ExportDirectory + ExportSize)) ) { CHAR ForwardDllName[10]; PLDR_DATA_TABLE_ENTRY DataTableEntry; ULONG TargetExportSize; PIMAGE_EXPORT_DIRECTORY TargetExportDirectory; RtlCopyMemory(ForwardDllName, (PCHAR)ThunkEntry->u1.Function, sizeof(ForwardDllName)); *strchr(ForwardDllName,'.') = '\0'; if (!BlCheckForLoadedDll(ForwardDllName,&DataTableEntry)) { // // Should load the referenced DLL here, just return failure for now. // return(EINVAL); } TargetExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData(DataTableEntry->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &TargetExportSize); if (TargetExportDirectory) { IMAGE_THUNK_DATA thunkData; PIMAGE_IMPORT_BY_NAME addressOfData; UCHAR Buffer[128]; ULONG length; PCHAR ImportName; ARC_STATUS Status; ImportName = strchr((PCHAR)ThunkEntry->u1.Function, '.') + 1; addressOfData = (PIMAGE_IMPORT_BY_NAME)Buffer; RtlCopyMemory(&addressOfData->Name[0], ImportName, strlen(ImportName)+1); addressOfData->Hint = 0; thunkData.u1.AddressOfData = addressOfData; Status = BlpBindImportName(DataTableEntry->DllBase, ImageBase, &thunkData, TargetExportDirectory, TargetExportSize, TRUE); ThunkEntry->u1 = thunkData.u1; return(Status); } else { return(EINVAL); } } return ESUCCESS; } }
// 函数说明: 加壳的时候把 IAT(导入表) 保存出来 void CPE::SaveImportTab() { if (m_PEImportDir.VirtualAddress == 0) { return; } //0.获取导入表结构体指针 PIMAGE_IMPORT_DESCRIPTOR pPEImport = (PIMAGE_IMPORT_DESCRIPTOR)(m_pFileBuf + m_PEImportDir.VirtualAddress); //1.第一遍循环确定 m_pModNameBuf 和 m_pFunNameBuf 的大小 DWORD dwSizeOfModBuf = 0; DWORD dwSizeOfFunBuf = 0; m_dwNumOfIATFuns = 0; while (pPEImport->Name) { DWORD dwModNameRVA = pPEImport->Name; char* pModName = (char*)(m_pFileBuf + dwModNameRVA); dwSizeOfModBuf += (strlen(pModName) + 1); PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->FirstThunk); while (pIAT->u1.AddressOfData) { if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal)) { m_dwNumOfIATFuns++; } else { m_dwNumOfIATFuns++; DWORD dwFunNameRVA = pIAT->u1.AddressOfData; PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(m_pFileBuf + dwFunNameRVA); dwSizeOfFunBuf += (strlen(pstcFunName->Name) + 1); } pIAT++; } pPEImport++; } //2.第二遍循环保存信息到自己定义的数据结构里边 m_pModNameBuf = new CHAR[dwSizeOfModBuf]; m_pFunNameBuf = new CHAR[dwSizeOfFunBuf]; m_pMyImport = new MYIMPORT[m_dwNumOfIATFuns]; memset(m_pModNameBuf, 0, dwSizeOfModBuf); memset(m_pFunNameBuf, 0, dwSizeOfFunBuf); memset(m_pMyImport, 0, sizeof(MYIMPORT)*m_dwNumOfIATFuns); pPEImport = (PIMAGE_IMPORT_DESCRIPTOR)(m_pFileBuf + m_PEImportDir.VirtualAddress); DWORD TempNumOfFuns = 0; DWORD TempModRVA = 0; DWORD TempFunRVA = 0; while (pPEImport->Name) { DWORD dwModNameRVA = pPEImport->Name; char* pModName = (char*)(m_pFileBuf + dwModNameRVA); memcpy_s((PCHAR)m_pModNameBuf + TempModRVA, strlen(pModName) + 1, pModName, strlen(pModName) + 1); PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->FirstThunk); while (pIAT->u1.AddressOfData) { if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal)) { //保存以序号导入方式的函数信息 m_pMyImport[TempNumOfFuns].m_dwIATAddr = (DWORD)pIAT - (DWORD)m_pFileBuf; m_pMyImport[TempNumOfFuns].m_bIsOrdinal = TRUE; m_pMyImport[TempNumOfFuns].m_Ordinal = pIAT->u1.Ordinal & 0x7FFFFFFF; m_pMyImport[TempNumOfFuns].m_dwModNameRVA = TempModRVA; } else { //保存名称导入方式的函数信息 m_pMyImport[TempNumOfFuns].m_dwIATAddr = (DWORD)pIAT - (DWORD)m_pFileBuf; DWORD dwFunNameRVA = pIAT->u1.AddressOfData; PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(m_pFileBuf + dwFunNameRVA); memcpy_s((PCHAR)m_pFunNameBuf + TempFunRVA, strlen(pstcFunName->Name) + 1, pstcFunName->Name, strlen(pstcFunName->Name) + 1); m_pMyImport[TempNumOfFuns].m_dwFunNameRVA = TempFunRVA; m_pMyImport[TempNumOfFuns].m_dwModNameRVA = TempModRVA; TempFunRVA += (strlen(pstcFunName->Name) + 1); } TempNumOfFuns++; pIAT++; } TempModRVA += (strlen(pModName) + 1); pPEImport++; } //逆序排列 m_pMyImport MYIMPORT stcTemp = { 0 }; DWORD dwTempNum = m_dwNumOfIATFuns / 2; for (DWORD i = 0; i < dwTempNum; i++) { m_pMyImport[i]; m_pMyImport[m_dwNumOfIATFuns - i - 1]; memcpy_s(&stcTemp, sizeof(MYIMPORT), &m_pMyImport[i], sizeof(MYIMPORT)); memcpy_s(&m_pMyImport[i], sizeof(MYIMPORT), &m_pMyImport[m_dwNumOfIATFuns - i - 1], sizeof(MYIMPORT)); memcpy_s(&m_pMyImport[m_dwNumOfIATFuns - i - 1], sizeof(MYIMPORT), &stcTemp, sizeof(MYIMPORT)); } //保存信息 m_dwSizeOfModBuf = dwSizeOfModBuf; m_dwSizeOfFunBuf = dwSizeOfFunBuf; }
/** * Patches the import table of the given DLL. * * @returns true on success, false on failure. * @param hmod . */ __declspec(dllexport) /* kBuild workaround */ bool MsiHackPatchDll(HMODULE hmod) { uint8_t const * const pbImage = (uint8_t const *)hmod; /* * Locate the import descriptors. */ /* MZ header and PE headers. */ IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbImage; if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE) pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew]; else pNtHdrs = (IMAGE_NT_HEADERS const *)pbImage; /* Check PE header. */ MSIHACK_ASSERT_RETURN(pNtHdrs->Signature == IMAGE_NT_SIGNATURE, false); MSIHACK_ASSERT_RETURN(pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pNtHdrs->OptionalHeader), false); uint32_t const cbImage = pNtHdrs->OptionalHeader.SizeOfImage; /* Locate the import descriptor array. */ IMAGE_DATA_DIRECTORY const *pDirEnt; pDirEnt = (IMAGE_DATA_DIRECTORY const *)&pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; if ( pDirEnt->Size > 0 && pDirEnt->VirtualAddress != 0) { const IMAGE_IMPORT_DESCRIPTOR *pImpDesc = (const IMAGE_IMPORT_DESCRIPTOR *)&pbImage[pDirEnt->VirtualAddress]; uint32_t cLeft = pDirEnt->Size / sizeof(*pImpDesc); MEMORY_BASIC_INFORMATION ProtInfo = { NULL, NULL, 0, 0, 0, 0, 0 }; uint8_t *pbProtRange = NULL; SIZE_T cbProtRange = 0; DWORD fOldProt = 0; uint32_t const cbPage = 0x1000; BOOL fRc; MSIHACK_ASSERT_RETURN(pDirEnt->VirtualAddress < cbImage, false); MSIHACK_ASSERT_RETURN(pDirEnt->Size < cbImage, false); MSIHACK_ASSERT_RETURN(pDirEnt->VirtualAddress + pDirEnt->Size <= cbImage, false); /* * Walk the import descriptor array. * Note! This only works if there's a backup thunk array, otherwise we cannot get at the name. */ while ( cLeft-- > 0 && pImpDesc->Name > 0 && pImpDesc->FirstThunk > 0) { uint32_t iThunk; const char * const pszImport = (const char *)&pbImage[pImpDesc->Name]; PIMAGE_THUNK_DATA paThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk]; PIMAGE_THUNK_DATA paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk]; MSIHACK_ASSERT_RETURN(pImpDesc->Name < cbImage, false); MSIHACK_ASSERT_RETURN(pImpDesc->FirstThunk < cbImage, false); MSIHACK_ASSERT_RETURN(pImpDesc->OriginalFirstThunk < cbImage, false); MSIHACK_ASSERT_RETURN(pImpDesc->OriginalFirstThunk != pImpDesc->FirstThunk, false); MSIHACK_ASSERT_RETURN(pImpDesc->OriginalFirstThunk, false); /* Iterate the thunks. */ for (iThunk = 0; paOrgThunks[iThunk].u1.Ordinal != 0; iThunk++) { uintptr_t const off = paOrgThunks[iThunk].u1.Function; MSIHACK_ASSERT_RETURN(off < cbImage, false); if (!IMAGE_SNAP_BY_ORDINAL(off)) { IMAGE_IMPORT_BY_NAME const *pName = (IMAGE_IMPORT_BY_NAME const *)&pbImage[off]; size_t const cchSymbol = strlen((const char *)&pName->Name[0]); uint32_t i = RT_ELEMENTS(g_aReplaceFunctions); while (i-- > 0) if ( g_aReplaceFunctions[i].cchFunction == cchSymbol && memcmp(g_aReplaceFunctions[i].pszFunction, pName->Name, cchSymbol) == 0) { if ( !g_aReplaceFunctions[i].pszModule || stricmp(g_aReplaceFunctions[i].pszModule, pszImport) == 0) { MsiHackDebugF("Replacing %s!%s\n", pszImport, pName->Name); /* The .rdata section is normally read-only, so we need to make it writable first. */ if ((uintptr_t)&paThunks[iThunk] - (uintptr_t)pbProtRange >= cbPage) { /* Restore previous .rdata page. */ if (fOldProt) { fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, NULL /*pfOldProt*/); MSIHACK_ASSERT(fRc); fOldProt = 0; } /* Query attributes for the current .rdata page. */ pbProtRange = (uint8_t *)((uintptr_t)&paThunks[iThunk] & ~(uintptr_t)(cbPage - 1)); cbProtRange = VirtualQuery(pbProtRange, &ProtInfo, sizeof(ProtInfo)); MSIHACK_ASSERT(cbProtRange); if (cbProtRange) { switch (ProtInfo.Protect) { case PAGE_READWRITE: case PAGE_WRITECOPY: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: /* Already writable, nothing to do. */ fRc = TRUE; break; default: MSIHACK_ASSERT_MSG(false, ("%#x\n", ProtInfo.Protect)); case PAGE_READONLY: cbProtRange = cbPage; fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_READWRITE, &fOldProt); break; case PAGE_EXECUTE: case PAGE_EXECUTE_READ: cbProtRange = cbPage; fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_EXECUTE_READWRITE, &fOldProt); break; } MSIHACK_ASSERT_STMT(fRc, fOldProt = 0); } } paThunks[iThunk].u1.AddressOfData = g_aReplaceFunctions[i].pfnReplacement; break; } } } } /* Next import descriptor. */ pImpDesc++; } if (fOldProt) { DWORD fIgnore = 0; fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, &fIgnore); MSIHACK_ASSERT_MSG(fRc, ("%u\n", GetLastError())); NOREF(fRc); } return true; } MsiHackErrorF("No imports in target DLL!\n"); return false; }
HMODULE CustomLoadLibrary(const PWCHAR wszFullDllName, const PWCHAR wszBaseDllName, ULONG_PTR pDllBase) { // File handles HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hMap = NULL; PCHAR pFile = NULL; // PE headers PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; PIMAGE_SECTION_HEADER pSectionHeader; // Library PCHAR pLibraryAddr = NULL; DWORD dwIdx; // Relocation PIMAGE_DATA_DIRECTORY pDataDir; PIMAGE_BASE_RELOCATION pBaseReloc; ULONG_PTR pReloc; DWORD dwNumRelocs; ULONG_PTR pInitialImageBase; PIMAGE_RELOC pImageReloc; // Import PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PCHAR szDllName; SIZE_T stDllName; PWSTR wszDllName = NULL; PWCHAR wsRedir = NULL; PWSTR wszRedirName = NULL; SIZE_T stRedirName; SIZE_T stSize; HMODULE hModule; PIMAGE_THUNK_DATA pThunkData; FARPROC* pIatEntry; // clr.dll hotpatches itself at runtime for performance reasons, so skip it if (wcscmp(L"clr.dll", wszBaseDllName) == 0) goto cleanup; dprintf("[REFRESH] Opening file: %S", wszFullDllName); // ---- // Step 1: Map the file into memory // ---- hFile = CreateFileW(wszFullDllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) goto cleanup; hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMap == NULL) goto cleanup; pFile = (PCHAR)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (pFile == NULL) goto cleanup; // ---- // Step 2: Parse the file headers and load it into memory // ---- pDosHeader = (PIMAGE_DOS_HEADER)pFile; pNtHeader = (PIMAGE_NT_HEADERS)(pFile + pDosHeader->e_lfanew); // allocate memory to copy DLL into dprintf("[REFRESH] Allocating memory for library"); pLibraryAddr = (PCHAR)VirtualAlloc(NULL, pNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // copy header dprintf("[REFRESH] Copying PE header into memory"); memcpy(pLibraryAddr, pFile, pNtHeader->OptionalHeader.SizeOfHeaders); // copy sections dprintf("[REFRESH] Copying PE sections into memory"); pSectionHeader = (PIMAGE_SECTION_HEADER)(pFile + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)); for (dwIdx = 0; dwIdx < pNtHeader->FileHeader.NumberOfSections; dwIdx++) { memcpy(pLibraryAddr + pSectionHeader[dwIdx].VirtualAddress, pFile + pSectionHeader[dwIdx].PointerToRawData, pSectionHeader[dwIdx].SizeOfRawData); } // update our pointers to the loaded image pDosHeader = (PIMAGE_DOS_HEADER)pLibraryAddr; pNtHeader = (PIMAGE_NT_HEADERS)(pLibraryAddr + pDosHeader->e_lfanew); // ---- // Step 3: Calculate relocations // ---- dprintf("[REFRESH] Calculating file relocations"); pDataDir = &pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; pInitialImageBase = pNtHeader->OptionalHeader.ImageBase; // set the ImageBase to the already loaded module's base pNtHeader->OptionalHeader.ImageBase = pDllBase; // check if their are any relocations present if (pDataDir->Size) { // calculate the address of the first IMAGE_BASE_RELOCATION entry pBaseReloc = (PIMAGE_BASE_RELOCATION)(pLibraryAddr + pDataDir->VirtualAddress); // iterate through each relocation entry while ((PCHAR)pBaseReloc < (pLibraryAddr + pDataDir->VirtualAddress + pDataDir->Size) && pBaseReloc->SizeOfBlock) { // the VA for this relocation block pReloc = (ULONG_PTR)(pLibraryAddr + pBaseReloc->VirtualAddress); // number of entries in this relocation block dwNumRelocs = (pBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); // first entry in the current relocation block pImageReloc = (PIMAGE_RELOC)((PCHAR)pBaseReloc + sizeof(IMAGE_BASE_RELOCATION)); // iterate through each entry in the relocation block while (dwNumRelocs--) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we subtract the initial ImageBase and add in the original dll base if (pImageReloc->type == IMAGE_REL_BASED_DIR64) { *(ULONG_PTR *)(pReloc + pImageReloc->offset) -= pInitialImageBase; *(ULONG_PTR *)(pReloc + pImageReloc->offset) += pDllBase; } else if (pImageReloc->type == IMAGE_REL_BASED_HIGHLOW) { *(DWORD *)(pReloc + pImageReloc->offset) -= (DWORD)pInitialImageBase; *(DWORD *)(pReloc + pImageReloc->offset) += (DWORD)pDllBase; } else if (pImageReloc->type == IMAGE_REL_BASED_HIGH) { *(WORD *)(pReloc + pImageReloc->offset) -= HIWORD(pInitialImageBase); *(WORD *)(pReloc + pImageReloc->offset) += HIWORD(pDllBase); } else if (pImageReloc->type == IMAGE_REL_BASED_LOW) { *(WORD *)(pReloc + pImageReloc->offset) -= LOWORD(pInitialImageBase); *(WORD *)(pReloc + pImageReloc->offset) += LOWORD(pDllBase); } // get the next entry in the current relocation block pImageReloc = (PIMAGE_RELOC)((PCHAR)pImageReloc + sizeof(IMAGE_RELOC)); } // get the next entry in the relocation directory pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBaseReloc + pBaseReloc->SizeOfBlock); } } // ---- // Step 4: Update import table // ---- dprintf("[REFRESH] Resolving Import Address Table (IAT) "); pDataDir = &pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; if (pDataDir->Size) { pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pLibraryAddr + pDataDir->VirtualAddress); while (pImportDesc->Characteristics) { hModule = NULL; wszDllName = NULL; szDllName = (PCHAR)(pLibraryAddr + pImportDesc->Name); stDllName = strnlen(szDllName, MAX_PATH); wszDllName = (PWSTR)calloc(stDllName + 1, sizeof(WCHAR)); if (wszDllName == NULL) goto next_import; mbstowcs_s(&stSize, wszDllName, stDllName + 1, szDllName, stDllName); dprintf("[REFRESH] Loading library: %S", wszDllName); // If the DLL starts with api- or ext-, resolve the redirected name and load it if (_wcsnicmp(wszDllName, L"api-", 4) == 0 || _wcsnicmp(wszDllName, L"ext-", 4) == 0) { // wsRedir is not null terminated wsRedir = GetRedirectedName(wszBaseDllName, wszDllName, &stRedirName); if (wsRedir) { // Free the original wszDllName and allocate a new buffer for the redirected dll name free(wszDllName); wszDllName = (PWSTR)calloc(stRedirName + 1, sizeof(WCHAR)); if (wszDllName == NULL) goto next_import; memcpy(wszDllName, wsRedir, stRedirName * sizeof(WCHAR)); dprintf("[REFRESH] Redirected library: %S", wszDllName); } } // Load the module hModule = CustomGetModuleHandleW(wszDllName); // Ignore libraries that fail to load if (hModule == NULL) goto next_import; if (pImportDesc->OriginalFirstThunk) pThunkData = (PIMAGE_THUNK_DATA)(pLibraryAddr + pImportDesc->OriginalFirstThunk); else pThunkData = (PIMAGE_THUNK_DATA)(pLibraryAddr + pImportDesc->FirstThunk); pIatEntry = (FARPROC*)(pLibraryAddr + pImportDesc->FirstThunk); // loop through each thunk and resolve the import for(; DEREF(pThunkData); pThunkData++, pIatEntry++) { if (IMAGE_SNAP_BY_ORDINAL(pThunkData->u1.Ordinal)) *pIatEntry = CustomGetProcAddressEx(hModule, (PCHAR)IMAGE_ORDINAL(pThunkData->u1.Ordinal), wszDllName); else *pIatEntry = CustomGetProcAddressEx(hModule, ((PIMAGE_IMPORT_BY_NAME)(pLibraryAddr + DEREF(pThunkData)))->Name, wszDllName); } next_import: if (wszDllName != NULL) { free(wszDllName); wszDllName = NULL; } pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((PCHAR)pImportDesc + sizeof(IMAGE_IMPORT_DESCRIPTOR)); } } cleanup: if (pFile != NULL) UnmapViewOfFile(pFile); if (hMap != NULL) CloseHandle(hMap); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return (HMODULE) pLibraryAddr; }
static void dump_import_directory(const void *const section_base, const DWORD section_base_virtual, const IMAGE_IMPORT_DESCRIPTOR * imp) /* dump of import directory. * quite a challenge because of broken linkers, unbound/old-bound and new-bound directories */ { #define indent " " #define adr(rva) ((const void*)((char*)section_base+((DWORD)(rva))-section_base_virtual)) for (; !IsBadReadPtr(imp, sizeof(*imp)) && imp->Name; imp++) { const IMAGE_THUNK_DATA *import_entry, *mapped_entry; enum { bound_none, bound_old, bound_new } bound; printf("\n" indent "from \"%s\":\n", (char *)adr(imp->Name)); if (imp->TimeDateStamp == ~0UL) { puts(indent "bound, new style"); bound = bound_new; } else if (imp->TimeDateStamp) { printf(indent "bound (old style) to %s", asctime(gmtime((const time_t *)&imp->TimeDateStamp))); bound = bound_old; } else { puts(indent "not bound"); bound = bound_none; } printf(indent "name table at %#lx, address table at %#lx\n", imp->OriginalFirstThunk, imp->FirstThunk); if (imp->OriginalFirstThunk) { import_entry = adr(imp->OriginalFirstThunk); mapped_entry = adr(imp->FirstThunk); } else { puts(indent "(hint table missing, probably Borland bug)"); import_entry = adr(imp->FirstThunk); mapped_entry = 0; bound = bound_none; } printf(indent "%6s %s\n", "hint", "name"); printf(indent "%6s %s\n", "----", "----"); { int count, nextforwarder = bound==bound_old ? imp->ForwarderChain : -1; for (count = 0; import_entry->u1.Ordinal; count++, import_entry++, bound ? mapped_entry++ : 0) { if (IMAGE_SNAP_BY_ORDINAL(import_entry->u1.Ordinal)) printf(indent "%6lu %-20s", IMAGE_ORDINAL(import_entry->u1.Ordinal),"<ordinal>"); else { const IMAGE_IMPORT_BY_NAME *name_import = adr(import_entry->u1.AddressOfData); printf(indent "%6u %-20.50s", name_import->Hint, name_import->Name); } if (bound) if (count != nextforwarder) printf("%#12lx\n", (unsigned long)mapped_entry->u1.Function); else { printf("%12s\n", " --> forward"); nextforwarder = (int)mapped_entry->u1.ForwarderString; } else puts(""); } } } if (IsBadReadPtr(imp, sizeof(*imp))) puts(indent "!! data inaccessible!!"); #undef adr #undef indent }
/*********************************************************************** * BindImageEx (IMAGEHLP.@) * * Compute the virtual address of each function imported by a PE image * * PARAMS * * Flags [in] Bind options * ImageName [in] File name of the image to be bound * DllPath [in] Root of the fallback search path in case the ImageName file cannot be opened * SymbolPath [in] Symbol file root search path * StatusRoutine [in] Pointer to a status routine which will be called during the binding process * * RETURNS * Success: TRUE * Failure: FALSE * * NOTES * Binding is not implemented yet, so far this function only enumerates * all imported dlls/functions and returns TRUE. */ BOOL WINAPI BindImageEx( DWORD Flags, PCSTR ImageName, PCSTR DllPath, PCSTR SymbolPath, PIMAGEHLP_STATUS_ROUTINE StatusRoutine) { LOADED_IMAGE loaded_image; const IMAGE_IMPORT_DESCRIPTOR *import_desc; ULONG size; FIXME("(%d, %s, %s, %s, %p): semi-stub\n", Flags, debugstr_a(ImageName), debugstr_a(DllPath), debugstr_a(SymbolPath), StatusRoutine ); if (!(MapAndLoad(ImageName, DllPath, &loaded_image, TRUE, TRUE))) return FALSE; if (!(import_desc = RtlImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size))) { UnMapAndLoad(&loaded_image); return TRUE; /* No imported modules means nothing to bind, so we're done. */ } /* FIXME: Does native imagehlp support both 32-bit and 64-bit PE executables? */ #ifdef _WIN64 if (loaded_image.FileHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) #else if (loaded_image.FileHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) #endif { FIXME("Wrong architecture in PE header, unable to enumerate imports\n"); UnMapAndLoad(&loaded_image); return TRUE; } for (; import_desc->Name && import_desc->FirstThunk; ++import_desc) { IMAGE_THUNK_DATA *thunk; char dll_fullname[MAX_PATH]; const char *dll_name; if (!(dll_name = ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, 0))) { UnMapAndLoad(&loaded_image); SetLastError(ERROR_INVALID_ACCESS); /* FIXME */ return FALSE; } if (StatusRoutine) StatusRoutine(BindImportModule, ImageName, dll_name, 0, 0); if (!SearchPathA(DllPath, dll_name, 0, sizeof(dll_fullname), dll_fullname, 0)) { UnMapAndLoad(&loaded_image); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } if (!(thunk = ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->OriginalFirstThunk ? import_desc->OriginalFirstThunk : import_desc->FirstThunk, 0))) { ERR("Can't grab thunk data of %s, going to next imported DLL\n", dll_name); continue; } for (; thunk->u1.Ordinal; ++thunk) { /* Ignoring ordinal imports for now */ if(!IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) { IMAGE_IMPORT_BY_NAME *iibn; if (!(iibn = ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, thunk->u1.AddressOfData, 0))) { ERR("Can't grab import by name info, skipping to next ordinal\n"); continue; } if (StatusRoutine) StatusRoutine(BindImportProcedure, ImageName, dll_fullname, 0, (ULONG_PTR)iibn->Name); } } } UnMapAndLoad(&loaded_image); return TRUE; }
BOOL HookIAT( HMODULE TargetModule, LPCSTR TargetImport, LPCSTR TargetFunction, LPVOID Hook, PHOOKED_IAT_ENTRY Hooked) { LPBYTE TargetModuleBaseAddress = (LPBYTE)TargetModule; PIMAGE_DOS_HEADER DOSHeader; PIMAGE_NT_HEADERS NTHeader; PIMAGE_OPTIONAL_HEADER OptionalHeader; PIMAGE_IMPORT_DESCRIPTOR ImportsDescriptor, ImportDescriptor; DWORD Index, OldProtection; PDWORD_PTR ImportFunctionsName; LPVOID *ImportFunctionsAddress, *TargetEntry; // Get Target Headers DOSHeader = (PIMAGE_DOS_HEADER)TargetModuleBaseAddress; NTHeader = (PIMAGE_NT_HEADERS)(TargetModuleBaseAddress + DOSHeader->e_lfanew); OptionalHeader = &NTHeader->OptionalHeader; // Get Imports Descriptor if (OptionalHeader->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_IMPORT) return FALSE; ImportsDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(TargetModuleBaseAddress + OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); // Search Target Import ImportDescriptor = NULL; for (Index = 0; memcmp(&ImportsDescriptor[Index], &NULLImportDescriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR)) != 0; Index++) { LPCSTR ImportName = TargetModuleBaseAddress + ImportsDescriptor[Index].Name; if (_strcmpi(ImportName, TargetImport) == 0) { ImportDescriptor = &ImportsDescriptor[Index]; break; } } if (!ImportDescriptor) return FALSE; ImportFunctionsName = (PDWORD_PTR)(TargetModuleBaseAddress + ImportDescriptor->OriginalFirstThunk); ImportFunctionsAddress = (LPVOID *)(TargetModuleBaseAddress + ImportDescriptor->FirstThunk); // Search Target Function TargetEntry = NULL; for (Index = 0; ImportFunctionsName[Index] != 0; Index++) { if (IMAGE_SNAP_BY_ORDINAL(ImportFunctionsName[Index])) { if (IMAGE_ORDINAL(ImportFunctionsName[Index]) == ((DWORD_PTR)(TargetFunction))) { TargetEntry = &ImportFunctionsAddress[Index]; break; } } else { PIMAGE_IMPORT_BY_NAME Name; if (((DWORD_PTR)TargetFunction) <= MAXWORD) continue; Name = (PIMAGE_IMPORT_BY_NAME)(TargetModuleBaseAddress + ImportFunctionsName[Index]); if (strcmp(Name->Name, TargetFunction) == 0) { TargetEntry = &ImportFunctionsAddress[Index]; break; } } } if (!TargetEntry) return FALSE; // Install Hook if (!VirtualProtect(TargetEntry, sizeof(*TargetEntry), PAGE_EXECUTE_READWRITE, &OldProtection)) return FALSE; __try { Hooked->Entry = TargetEntry; Hooked->OriginalFunction = InterlockedExchangePointer(TargetEntry, Hook); } __finally { VirtualProtect(TargetEntry, sizeof(*TargetEntry), OldProtection, &OldProtection); } return TRUE; }
BOOL CRemoteLoader::ProcessImportTable( PVOID BaseAddress, PVOID RemoteAddress, PCHAR OptionalPath ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].Size ) { IMAGE_IMPORT_DESCRIPTOR* ImageImportDescriptor = ( IMAGE_IMPORT_DESCRIPTOR* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress, BaseAddress ); if( ImageImportDescriptor ) { for( ; ImageImportDescriptor->Name; ImageImportDescriptor++ ) { PCHAR ModuleName = ( PCHAR ) RvaToPointer( ImageImportDescriptor->Name, BaseAddress ); if( ModuleName == NULL ) { DebugShout( "[ProcessImportTable] Module name for entry NULL" ); continue; } DebugShout( "[ProcessImportTable] Module Name [%s]", ModuleName ); HMODULE ModuleBase = GetRemoteModuleHandleA( ModuleName ); if( ModuleBase == NULL ) { ModuleBase = LoadLibraryByPathA( ModuleName ); } if( ModuleBase == NULL ) { DebugShout( "[ProcessImportTable] Failed to obtain module handle [%s]", ModuleName ); continue; } IMAGE_THUNK_DATA *ImageThunkData = NULL; IMAGE_THUNK_DATA *ImageFuncData = NULL; if( ImageImportDescriptor->OriginalFirstThunk ) { ImageThunkData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->OriginalFirstThunk, BaseAddress ); ImageFuncData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); } else { ImageThunkData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); ImageFuncData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); } if( ImageThunkData == NULL ) { DebugShout( "[ProcessImportTable] Image Thunk Data is NULL" ); } if( ImageFuncData == NULL ) { DebugShout( "[ProcessImportTable] Image Func Data is NULL" ); } for( ; ImageThunkData->u1.AddressOfData; ImageThunkData++, ImageFuncData++ ) { FARPROC FunctionAddress = NULL; if( IMAGE_SNAP_BY_ORDINAL( ImageThunkData->u1.Ordinal ) ) { SHORT Ordinal = ( SHORT ) IMAGE_ORDINAL( ImageThunkData->u1.Ordinal ); FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, Ordinal ); DebugShout( "[ProcessImportTable] Processed (%s -> %i) -> (0x%X)", ModuleName, Ordinal, FunctionAddress ); if( this->GetProcess() == INVALID_HANDLE_VALUE ) { DebugShout( "[ProcessImportTable] Normal Value (0x%X)", GetProcAddress( GetModuleHandleA( ModuleName ), ( LPCSTR ) Ordinal ) ); } } else { IMAGE_IMPORT_BY_NAME* ImageImportByName = ( IMAGE_IMPORT_BY_NAME* ) RvaToPointer( *( DWORD* ) ImageThunkData, BaseAddress ); PCHAR NameOfImport = ( PCHAR ) ImageImportByName->Name; FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, NameOfImport ); DebugShout( "[ProcessImportTable] Processed (%s -> %s) -> (0x%X)", ModuleName, NameOfImport, FunctionAddress ); if( this->GetProcess() == INVALID_HANDLE_VALUE ) { DebugShout( "[ProcessImportTable] Normal Value (0x%X)", GetProcAddress( GetModuleHandleA( ModuleName ), NameOfImport ) ); } } ImageFuncData->u1.Function = ( DWORD ) FunctionAddress; } } return TRUE; } else { DebugShout( "[ProcessImportTable] Size of table confirmed but pointer to data invalid!" ); return FALSE; } } else { DebugShout( "[ProcessImportTable] No Imports" ); return TRUE; } return FALSE; }
static BOOL BuildImportTable(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; PIMAGE_IMPORT_DESCRIPTOR importDesc; BOOL result = TRUE; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); if (directory->Size == 0) { return TRUE; } importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { uintptr_t *thunkRef; FARPROC *funcRef; HCUSTOMMODULE *tmp; HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); if (handle == NULL) { SetLastError(ERROR_MOD_NOT_FOUND); result = FALSE; break; } tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); if (tmp == NULL) { module->freeLibrary(handle, module->userdata); SetLastError(ERROR_OUTOFMEMORY); result = FALSE; break; } module->modules = tmp; module->modules[module->numModules++] = handle; if (importDesc->OriginalFirstThunk) { thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } else { // no hint table thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } for (; *thunkRef; thunkRef++, funcRef++) { if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); } else { PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); } if (*funcRef == 0) { result = FALSE; break; } } if (!result) { module->freeLibrary(handle, module->userdata); SetLastError(ERROR_PROC_NOT_FOUND); break; } } return result; }
static NTSTATUS ImportScanLoop( PCHAR ModuleBase, ULONG SizeOfImage, PVOID ImportedModuleBase, ULONG rvaINT, ULONG rvaIAT ) { NTSTATUS ntStatus = STATUS_SUCCESS; PIAT_ENTRY pIatEntry = NULL; PIMAGE_IMPORT_BY_NAME pOrdinalName; PIMAGE_THUNK_DATA pINT; PIMAGE_THUNK_DATA pIAT; IAT_ENTRY IatEntry; if ( rvaINT == 0 ) // No Characteristics field? { // Yes! Gotta have a non-zero FirstThunk field then. rvaINT = rvaIAT; if ( rvaINT == 0 ) // No FirstThunk field? Ooops!!! return(STATUS_INVALID_IMAGE_FORMAT); } // Adjust the pointer to point where the tables are in the // mem mapped file. pINT = (PIMAGE_THUNK_DATA)PeSupRvaToVa(rvaINT, ModuleBase); if (!pINT ) return(STATUS_INVALID_IMAGE_FORMAT); pIAT = (PIMAGE_THUNK_DATA)PeSupRvaToVa(rvaIAT, ModuleBase); while (TRUE) // Loop forever (or until we break out) { if ( pINT->u1.AddressOfData == 0 ) break; if ( IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal) == FALSE) { pOrdinalName = (PIMAGE_IMPORT_BY_NAME)PeSupRvaToVa((ULONG)pINT->u1.AddressOfData, ModuleBase); } else if( pINT->u1.Ordinal >= (ULONG_PTR)ModuleBase && pINT->u1.Ordinal < ((ULONG_PTR)ModuleBase + SizeOfImage)) { pOrdinalName = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)pINT->u1.AddressOfData); } else pOrdinalName = NULL; if (pOrdinalName) { if (IatEntry = (IAT_ENTRY)PeSupGetFunctionAddress(ImportedModuleBase, (PCHAR)&pOrdinalName->Name)) { pIatEntry = &pIAT->u1.Function; *pIatEntry = IatEntry; } else { ntStatus = STATUS_PROCEDURE_NOT_FOUND; break; } } // if (pOrdinalName) pINT++; // advance to next thunk pIAT++; // advance to next thunk } // while (TRUE) return(ntStatus); }
static PIAT_ENTRY ImportScanLoop( PCHAR ModuleBase, ULONG SizeOfImage, PCHAR pFunctionName, ULONG rvaINT, ULONG rvaIAT, BOOL bDelayImport, PCHAR* ppName ) { PIAT_ENTRY pIatEntry = NULL; PIMAGE_IMPORT_BY_NAME pOrdinalName; PIMAGE_THUNK_DATA pINT; PIMAGE_THUNK_DATA pIAT; if (!rvaINT && !(rvaINT = rvaIAT)) // No Characteristics and no FirstThunk field return(NULL); // RVA to VA pINT = (PIMAGE_THUNK_DATA)PeSupRvaToVa(rvaINT, ModuleBase); pIAT = (PIMAGE_THUNK_DATA)PeSupRvaToVa(rvaIAT, ModuleBase); while (TRUE) // Loop forever (or until we break out) { if ( pINT->u1.AddressOfData == 0 ) break; if (IMAGE_SNAP_BY_ORDINAL((ULONG_PTR)pFunctionName)) { // There's on ordinal number instead of a name specified if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal) && pINT->u1.Ordinal == (ULONG_PTR)pFunctionName) { pIatEntry = &pIAT->u1.Function; if (ppName) *(PVOID*)ppName = &pINT->u1.Ordinal; break; // Found, leaving } } else { // Import by a function name if (!IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal)) { #ifndef _WIN64 if (bDelayImport && (ULONG_PTR)pINT->u1.AddressOfData >= (ULONG_PTR)ModuleBase && (ULONG_PTR)pINT->u1.AddressOfData < (ULONG_PTR)(ModuleBase + SizeOfImage)) pOrdinalName = (PIMAGE_IMPORT_BY_NAME)(ULONG_PTR)pINT->u1.AddressOfData; else #endif pOrdinalName = (PIMAGE_IMPORT_BY_NAME)PeSupRvaToVa((ULONG)pINT->u1.AddressOfData, ModuleBase); if (!_stricmp((PCHAR)&pOrdinalName->Name, pFunctionName)) { pIatEntry = &pIAT->u1.Function; if (ppName) *ppName = (PCHAR)&pOrdinalName->Name; break; // Found, leaving } } else if( pINT->u1.Ordinal >= (ULONG_PTR)ModuleBase && pINT->u1.Ordinal < ((ULONG_PTR)ModuleBase + SizeOfImage)) { pOrdinalName = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)pINT->u1.AddressOfData); if ( pOrdinalName ) { if (!_stricmp((PCHAR)&pOrdinalName->Name, pFunctionName)) { pIatEntry = &pIAT->u1.Function; if (ppName) *ppName = (PCHAR)&pOrdinalName->Name; break; // Found, leaving } } } } pINT++; // advance to next thunk pIAT++; // advance to next thunk } // while (TRUE) return(pIatEntry); }
bool PLH::IATHook::FindIATFunc(const char* LibraryName,const char* FuncName, PIMAGE_THUNK_DATA* pFuncThunkOut,const char* Module) { bool UseModuleName = true; if (Module == NULL || Module[0] == '\0') UseModuleName = false; HINSTANCE hInst = GetModuleHandleA(UseModuleName ? Module:NULL); if (!hInst) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook IATHook:Failed to find Module")); return false; } ULONG Sz; PIMAGE_IMPORT_DESCRIPTOR pImports = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToDataEx(hInst, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Sz, nullptr); for (int i = 0; pImports[i].Characteristics != 0; i++) { char* _ModuleName = (char*)ResolveRVA(hInst, pImports[i].Name); if (_stricmp(_ModuleName, LibraryName) != 0) continue; //Original holds the API Names PIMAGE_THUNK_DATA pOriginalThunk = (PIMAGE_THUNK_DATA) ResolveRVA(hInst, pImports->OriginalFirstThunk); //FirstThunk is overwritten by loader with API addresses, we change this PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ResolveRVA(hInst, pImports->FirstThunk); if (!pOriginalThunk) { PostError(RuntimeError(RuntimeError::Severity::Critical, "PolyHook IATHook:PE Files without OriginalFirstThunk are unsupported")); return false; } //Table is null terminated, increment both tables for (; pOriginalThunk->u1.Function != NULL; pOriginalThunk++,pThunk++) { if (IMAGE_SNAP_BY_ORDINAL(pOriginalThunk->u1.Ordinal)) { XTrace("Import By Ordinal:[Ordinal:%d]\n",IMAGE_ORDINAL(pOriginalThunk->u1.Ordinal)); continue; } PIMAGE_IMPORT_BY_NAME pImport = (PIMAGE_IMPORT_BY_NAME) ResolveRVA(hInst, pOriginalThunk->u1.AddressOfData); XTrace("Import By Name: [Ordinal:%d] [Name:%s]\n", IMAGE_ORDINAL(pOriginalThunk->u1.Ordinal),pImport->Name); //Check the name of API given by OriginalFirthThunk if (_stricmp(FuncName, pImport->Name) != 0) continue; /*Name matched in OriginalFirstThunk, return FirstThunk so we can changed it's address*/ *pFuncThunkOut = pThunk; return true; } } PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook IATHook:Failed to find import")); return false; }
bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr ) { PIMAGE_THUNK_DATA pIAT; // Ptr to import address table PIMAGE_THUNK_DATA pINT; // Ptr to import names table PIMAGE_THUNK_DATA pIteratingIAT; // Figure out which OS platform we're on OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx( &osvi ); // If no import names table, we can't redirect this, so bail if ( pImportDesc->OriginalFirstThunk == 0 ) return false; pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk ); pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk ); // Count how many entries there are in this IAT. Array is 0 terminated pIteratingIAT = pIAT; unsigned cFuncs = 0; while ( pIteratingIAT->u1.Function ) { cFuncs++; pIteratingIAT++; } if ( cFuncs == 0 ) // If no imported functions, we're done! return false; // These next few lines ensure that we'll be able to modify the IAT, // which is often in a read-only section in the EXE. DWORD flOldProtect, flNewProtect, flDontCare; MEMORY_BASIC_INFORMATION mbi; // Get the current protection attributes VirtualQuery( pIAT, &mbi, sizeof(mbi) ); // remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag flNewProtect = mbi.Protect; flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ); flNewProtect |= (PAGE_READWRITE); if ( !VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flNewProtect, &flOldProtect) ) { return false; } // If the Default hook is enabled, build an array of redirection stubs in the processes memory. DLPD_IAT_STUB * pStubs = 0; if ( DLLHook->UseDefault ) { // Allocate memory for the redirection stubs. Make one extra stub at the // end to be a sentinel pStubs = new DLPD_IAT_STUB[ cFuncs + 1]; if ( !pStubs ) return false; } // Scan through the IAT, completing the stubs and redirecting the IAT // entries to point to the stubs pIteratingIAT = pIAT; while ( pIteratingIAT->u1.Function ) { void* HookFn = 0; // Set to either the SFunctionHook or pStubs. if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) ) // import by name { PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData ); // Iterate through the hook functions, searching for this import. SFunctionHook* FHook = DLLHook->Functions; while ( FHook->Name ) { if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 ) { OutputDebugString( "Hooked function: " ); OutputDebugString( (char*)pImportName->Name ); OutputDebugString( "\n" ); // Save the old function in the SFunctionHook structure and get the new one. FHook->OrigFn = (void*)pIteratingIAT->u1.Function; // cyber / cast as void* HookFn = FHook->HookFn; break; } FHook++; } // If the default function is enabled, store the name for the user. if ( DLLHook->UseDefault ) pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name; } else { // If the default function is enabled, store the ordinal for the user. if ( DLLHook->UseDefault ) pStubs->pszNameOrOrdinal = pINT->u1.Ordinal; } // If the default function is enabled, fill in the fields to the stub code. if ( DLLHook->UseDefault ) { pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn - (DWORD)(PDWORD)&pStubs->instr_JMP; pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count; // If it wasn't manually hooked, use the Stub function. if ( !HookFn ) HookFn = (void*)pStubs; } // Replace the IAT function pointer if we have a hook. if ( HookFn ) { // Cheez-o hack to see if what we're importing is code or data. // If it's code, we shouldn't be able to write to it if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) ) { pIteratingIAT->u1.Function = (DWORD)HookFn; // cyber / made PDWORD into DWORD } else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { // Special hack for Win9X, which builds stubs for imported // functions in system DLLs (Loaded above 2GB). These stubs are // writeable, so we have to explicitly check for this case if ( pIteratingIAT->u1.Function > (DWORD)0x80000000 ) // cyber / made PDWORD into DWORD pIteratingIAT->u1.Function = (DWORD)HookFn; // cyber / made PDWORD into DWORD } } if ( DLLHook->UseDefault ) pStubs++; // Advance to next stub pIteratingIAT++; // Advance to next IAT entry pINT++; // Advance to next INT entry } if ( DLLHook->UseDefault ) pStubs->pszNameOrOrdinal = 0; // Final stub is a sentinel // Put the page attributes back the way they were. VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare); return true; }
int renderspuIatPatcherGetImportAddress(HMODULE hModule, LPCSTR pszLib, LPCSTR pszName, void** ppAdr) { PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hModule; PIMAGE_NT_HEADERS pNtHdr; PIMAGE_IMPORT_DESCRIPTOR pImportDr; DWORD rvaImport; crDebug("searching entry %s from %s", pszName, pszLib); *ppAdr = 0; if (pDosHdr->e_magic != IMAGE_DOS_SIGNATURE) { crWarning("invalid dos signature"); return VERR_INVALID_HANDLE; } pNtHdr = RVA2PTR(IMAGE_NT_HEADERS, pDosHdr, pDosHdr->e_lfanew); if (pNtHdr->Signature != IMAGE_NT_SIGNATURE) { crWarning("invalid nt signature"); return VERR_INVALID_HANDLE; } rvaImport = pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if (!rvaImport) { crWarning("no imports found"); return VERR_NOT_FOUND; } pImportDr = RVA2PTR(IMAGE_IMPORT_DESCRIPTOR, pDosHdr, rvaImport); for ( ;pImportDr->TimeDateStamp != 0 || pImportDr->Name != 0; ++pImportDr) { DWORD rvaINT, rvaIAT; PIMAGE_THUNK_DATA pINT, pIAT; LPCSTR pszLibCur = RVA2PTR(char, pDosHdr, pImportDr->Name); if (stricmp(pszLibCur, pszLib)) continue; /* got the necessary lib! */ crDebug("got info for lib"); rvaINT = pImportDr->OriginalFirstThunk; rvaIAT = pImportDr->FirstThunk; if (!rvaINT || !rvaIAT) { crWarning("either rvaINT(0x%x) or rvaIAT(0x%x) are NULL, nothing found!", rvaINT, rvaIAT); return VERR_NOT_FOUND; } pINT = RVA2PTR(IMAGE_THUNK_DATA, pDosHdr, rvaINT); pIAT = RVA2PTR(IMAGE_THUNK_DATA, pDosHdr, rvaIAT); for ( ; pINT->u1.AddressOfData; ++pINT, ++pIAT) { PIMAGE_IMPORT_BY_NAME pIbn; if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal)) continue; pIbn = RVA2PTR(IMAGE_IMPORT_BY_NAME, pDosHdr, pINT->u1.AddressOfData); if (stricmp(pszName, (char*)pIbn->Name)) continue; *ppAdr = &pIAT->u1.Function; crDebug("search succeeded!"); return VINF_SUCCESS; } } crDebug("not found"); return VERR_NOT_FOUND; }
FARPROC WINAPI __delayLoadHelper2( PCImgDelayDescr pidd, FARPROC * ppfnIATEntry ) { // Set up some data we use for the hook procs but also useful for // our own use // InternalImgDelayDescr idd = { pidd->grAttrs, PFromRva<LPCSTR>(pidd->rvaDLLName), PFromRva<HMODULE*>(pidd->rvaHmod), PFromRva<PImgThunkData>(pidd->rvaIAT), PFromRva<PCImgThunkData>(pidd->rvaINT), PFromRva<PCImgThunkData>(pidd->rvaBoundIAT), PFromRva<PCImgThunkData>(pidd->rvaUnloadIAT), pidd->dwTimeStamp }; DelayLoadInfo dli = { sizeof DelayLoadInfo, pidd, ppfnIATEntry, idd.szName, { 0 }, 0, 0, 0 }; if (0 == (idd.grAttrs & dlattrRva)) { PDelayLoadInfo rgpdli[1] = { &dli }; RaiseException( VcppException(ERROR_SEVERITY_ERROR, ERROR_INVALID_PARAMETER), 0, 1, PULONG_PTR(rgpdli) ); return 0; } HMODULE hmod = *idd.phmod; // Calculate the index for the IAT entry in the import address table // N.B. The INT entries are ordered the same as the IAT entries so // the calculation can be done on the IAT side. // const unsigned iIAT = IndexFromPImgThunkData(PCImgThunkData(ppfnIATEntry), idd.pIAT); const unsigned iINT = iIAT; PCImgThunkData pitd = &(idd.pINT[iINT]); dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal); if (dli.dlp.fImportByName) { dli.dlp.szProcName = LPCSTR(PFromRva<PIMAGE_IMPORT_BY_NAME>(RVA(UINT_PTR(pitd->u1.AddressOfData)))->Name); } else { dli.dlp.dwOrdinal = DWORD(IMAGE_ORDINAL(pitd->u1.Ordinal)); } // Call the initial hook. If it exists and returns a function pointer, // abort the rest of the processing and just return it for the call. // FARPROC pfnRet = NULL; if (__pfnDliNotifyHook2) { pfnRet = ((*__pfnDliNotifyHook2)(dliStartProcessing, &dli)); if (pfnRet != NULL) { goto HookBypass; } } // Check to see if we need to try to load the library. // if (hmod == 0) { if (__pfnDliNotifyHook2) { hmod = HMODULE(((*__pfnDliNotifyHook2)(dliNotePreLoadLibrary, &dli))); } if (hmod == 0) { hmod = ::LoadLibraryEx(dli.szDll, NULL, 0); } if (hmod == 0) { dli.dwLastError = ::GetLastError(); if (__pfnDliFailureHook2) { // when the hook is called on LoadLibrary failure, it will // return 0 for failure and an hmod for the lib if it fixed // the problem. // hmod = HMODULE((*__pfnDliFailureHook2)(dliFailLoadLib, &dli)); } if (hmod == 0) { PDelayLoadInfo rgpdli[1] = { &dli }; RaiseException( VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND), 0, 1, PULONG_PTR(rgpdli) ); // If we get to here, we blindly assume that the handler of the exception // has magically fixed everything up and left the function pointer in // dli.pfnCur. // return dli.pfnCur; } } // Store the library handle. If it is already there, we infer // that another thread got there first, and we need to do a // FreeLibrary() to reduce the refcount // HMODULE hmodT = HMODULE(InterlockedExchangePointer((PVOID *) idd.phmod, PVOID(hmod))); if (hmodT == hmod) { ::FreeLibrary(hmod); } } // Go for the procedure now. // dli.hmodCur = hmod; if (__pfnDliNotifyHook2) { pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress, &dli); } if (pfnRet == 0) { if (pidd->rvaBoundIAT && pidd->dwTimeStamp) { // bound imports exist...check the timestamp from the target image // PIMAGE_NT_HEADERS pinh(PinhFromImageBase(hmod)); if (pinh->Signature == IMAGE_NT_SIGNATURE && TimeStampOfImage(pinh) == idd.dwTimeStamp && FLoadedAtPreferredAddress(pinh, hmod)) { // Everything is good to go, if we have a decent address // in the bound IAT! // pfnRet = FARPROC(UINT_PTR(idd.pBoundIAT[iIAT].u1.Function)); if (pfnRet != 0) { goto SetEntryHookBypass; } } } pfnRet = ::GetProcAddress(hmod, dli.dlp.szProcName); } if (pfnRet == 0) { dli.dwLastError = ::GetLastError(); if (__pfnDliFailureHook2) { // when the hook is called on GetProcAddress failure, it will // return 0 on failure and a valid proc address on success // pfnRet = (*__pfnDliFailureHook2)(dliFailGetProc, &dli); } if (pfnRet == 0) { PDelayLoadInfo rgpdli[1] = { &dli }; RaiseException( VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND), 0, 1, PULONG_PTR(rgpdli) ); // If we get to here, we blindly assume that the handler of the exception // has magically fixed everything up and left the function pointer in // dli.pfnCur. // pfnRet = dli.pfnCur; } } SetEntryHookBypass: *ppfnIATEntry = pfnRet; HookBypass: if (__pfnDliNotifyHook2) { dli.dwLastError = 0; dli.hmodCur = hmod; dli.pfnCur = pfnRet; (*__pfnDliNotifyHook2)(dliNoteEndProcessing, &dli); } return pfnRet; }
HRESULT ApiHijackImports( HMODULE hModule, //хэндл на эту программу (метод импорта), в ней замещающая процедура LPSTR szVictim, LPSTR szEntry, LPVOID pHijacker, //замещающая процедура LPVOID *ppOrig ) { FILE* pf = fopen("importlog.txt","a+"); // Check args if (::IsBadStringPtrA(szVictim, -1) || (!IS_INTRESOURCE(szEntry) && ::IsBadStringPtrA(szEntry, -1)) || ::IsBadCodePtr(FARPROC(pHijacker))) { fclose(pf); return E_INVALIDARG; } PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER(hModule); //DOS заголовок PE файла (этой программы) if (::IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) || IMAGE_DOS_SIGNATURE != pDosHeader->e_magic) { fclose(pf); return E_INVALIDARG; } PIMAGE_NT_HEADERS pNTHeaders = MakePtr(PIMAGE_NT_HEADERS, hModule, pDosHeader->e_lfanew); //PE заголовок (этой программы) if (::IsBadReadPtr(pNTHeaders, sizeof(IMAGE_NT_HEADERS)) || IMAGE_NT_SIGNATURE != pNTHeaders->Signature) { fclose(pf); return E_INVALIDARG; } HRESULT hr = E_UNEXPECTED; // Locate the victim IMAGE_DATA_DIRECTORY& impDir = pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; //элемент директории данных опционального заголовка (структура): символы импорта PIMAGE_IMPORT_DESCRIPTOR pImpDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, hModule, impDir.VirtualAddress), //адрес начала таблицы импорта (массив структур IMAGE_IMPORT_DESCRIPTOR) pEnd = pImpDesc + impDir.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; //адрес конца таблицы while(pImpDesc < pEnd) { char *p; //debug p=MakePtr(char*,hModule,pImpDesc->Name); if (0 == ::lstrcmpiA(MakePtr(LPSTR, hModule, pImpDesc->Name), szVictim)) //в таблице импорта szVictim { if (0 == pImpDesc->OriginalFirstThunk) { // no import names table fclose(pf); return E_UNEXPECTED; } // Locate the entry PIMAGE_THUNK_DATA pNamesTable = MakePtr(PIMAGE_THUNK_DATA, hModule, pImpDesc->OriginalFirstThunk); if (IS_INTRESOURCE(szEntry)) { // By ordinal while(pNamesTable->u1.AddressOfData) { if (IMAGE_SNAP_BY_ORDINAL(pNamesTable->u1.Ordinal) && WORD(szEntry) == IMAGE_ORDINAL(pNamesTable->u1.Ordinal)) { hr = S_OK; break; } pNamesTable++; } } else { // By name while(pNamesTable->u1.AddressOfData) { if (!IMAGE_SNAP_BY_ORDINAL(pNamesTable->u1.Ordinal)) { PIMAGE_IMPORT_BY_NAME pName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule, pNamesTable->u1.AddressOfData); if (0 == ::lstrcmpiA(LPSTR(pName->Name), szEntry)) { hr = S_OK; break; } } pNamesTable++; } } if (SUCCEEDED(hr)) { // Get address LPVOID *pProc = MakePtr(LPVOID *, pNamesTable, pImpDesc->FirstThunk - pImpDesc->OriginalFirstThunk); //pImpDesc->FirstThunk - выводится как Address в проге pe_class - import_descriptor_array->FirstThunk // Save original handler if (ppOrig) *ppOrig = *pProc; // write to write-protected memory fprintf(pf, "0x%X 0x%X 0x%X 0x%X\n", pProc, pNamesTable, pImpDesc->FirstThunk, pImpDesc->OriginalFirstThunk); fclose(pf); return WriteProtectedMemory(pProc, &pHijacker, sizeof(LPVOID)); } break; } pImpDesc++; } fclose(pf); return hr; }
static BOOLEAN WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead, IN PVOID DllBase, IN PVOID ImageBase, IN PIMAGE_THUNK_DATA ThunkData, IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, IN ULONG ExportSize, IN BOOLEAN ProcessForwards, IN PCSTR DirectoryPath) { ULONG Ordinal; PULONG NameTable, FunctionTable; PUSHORT OrdinalTable; LONG High, Low, Middle, Result; ULONG Hint; PIMAGE_IMPORT_BY_NAME ImportData; PCHAR ExportName, ForwarderName; BOOLEAN Success; //TRACE("WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n", // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards); /* Check passed DllBase param */ if(DllBase == NULL) { WARN("DllBase == NULL!\n"); return FALSE; } /* Convert all non-critical pointers to PA from VA */ ThunkData = VaToPa(ThunkData); /* Is the reference by ordinal? */ if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards) { /* Yes, calculate the ordinal */ Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base); //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal); } else { /* It's reference by name, we have to look it up in the export directory */ if (!ProcessForwards) { /* AddressOfData in thunk entry will become a virtual address (from relative) */ //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData); ThunkData->u1.AddressOfData = (ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData); //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData); } /* Get the import name */ ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData); /* Get pointers to Name and Ordinal tables (RVA -> VA) */ NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames)); OrdinalTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals)); //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n", // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals); /* Get the hint, convert it to a physical pointer */ Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint; //TRACE("HintIndex %d\n", Hint); /* Get the export name from the hint */ ExportName = VaToPa(RVA(DllBase, NameTable[Hint])); /* If Hint is less than total number of entries in the export directory, and import name == export name, then we can just get it from the OrdinalTable */ if ((Hint < ExportDirectory->NumberOfNames) && (strcmp(ExportName, (PCHAR)ImportData->Name) == 0)) { Ordinal = OrdinalTable[Hint]; //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal); } else { /* It's not the easy way, we have to lookup import name in the name table. Let's use a binary search for this task. */ //TRACE("WinLdrpBindImportName() looking up the import name using binary search...\n"); /* Low boundary is set to 0, and high boundary to the maximum index */ Low = 0; High = ExportDirectory->NumberOfNames - 1; /* Perform a binary-search loop */ while (High >= Low) { /* Divide by 2 by shifting to the right once */ Middle = (Low + High) / 2; /* Get the name from the name table */ ExportName = VaToPa(RVA(DllBase, NameTable[Middle])); /* Compare the names */ Result = strcmp(ExportName, (PCHAR)ImportData->Name); /*TRACE("Binary search: comparing Import '__', Export '%s'\n",*/ /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/ /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/ /*TRACE("TE->u1.AOD %p, fulladdr %p\n", ThunkData->u1.AddressOfData, ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/ /* Depending on result of strcmp, perform different actions */ if (Result > 0) { /* Adjust top boundary */ High = Middle - 1; } else if (Result < 0) { /* Adjust bottom boundary */ Low = Middle + 1; } else { /* Yay, found it! */ break; } } /* If high boundary is less than low boundary, then no result found */ if (High < Low) { //Print(L"Error in binary search\n"); ERR("Did not find export '%s'!\n", (PCHAR)ImportData->Name); return FALSE; } /* Everything alright, get the ordinal */ Ordinal = OrdinalTable[Middle]; //TRACE("WinLdrpBindImportName() found Ordinal %d\n", Ordinal); } } /* Check ordinal number for validity! */ if (Ordinal >= ExportDirectory->NumberOfFunctions) { ERR("Ordinal number is invalid!\n"); return FALSE; } /* Get a pointer to the function table */ FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions)); /* Save a pointer to the function */ ThunkData->u1.Function = (ULONG_PTR)RVA(DllBase, FunctionTable[Ordinal]); /* Is it a forwarder? (function pointer is within the export directory) */ ForwarderName = (PCHAR)VaToPa((PVOID)ThunkData->u1.Function); if (((ULONG_PTR)ForwarderName > (ULONG_PTR)ExportDirectory) && ((ULONG_PTR)ForwarderName < ((ULONG_PTR)ExportDirectory + ExportSize))) { PLDR_DATA_TABLE_ENTRY DataTableEntry; CHAR ForwardDllName[255]; PIMAGE_EXPORT_DIRECTORY RefExportDirectory; ULONG RefExportSize; TRACE("WinLdrpBindImportName(): ForwarderName %s\n", ForwarderName); /* Save the name of the forward dll */ RtlCopyMemory(ForwardDllName, ForwarderName, sizeof(ForwardDllName)); /* Strip out the symbol name */ *strrchr(ForwardDllName,'.') = '\0'; /* Check if the target image is already loaded */ if (!WinLdrCheckForLoadedDll(ModuleListHead, ForwardDllName, &DataTableEntry)) { /* Check if the forward dll name has an extension */ if (strchr(ForwardDllName, '.') == NULL) { /* Name does not have an extension, append '.dll' */ strcat(ForwardDllName, ".dll"); } /* Now let's try to load it! */ Success = WinLdrpLoadAndScanReferencedDll(ModuleListHead, DirectoryPath, ForwardDllName, &DataTableEntry); if (!Success) { ERR("WinLdrpLoadAndScanReferencedDll() failed to load forwarder dll.\n"); return Success; } } /* Get pointer to the export directory of loaded DLL */ RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase), TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &RefExportSize); /* Fail if it's NULL */ if (RefExportDirectory) { UCHAR Buffer[128]; IMAGE_THUNK_DATA RefThunkData; PIMAGE_IMPORT_BY_NAME ImportByName; PCHAR ImportName; /* Get pointer to the import name */ ImportName = strrchr(ForwarderName, '.') + 1; /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */ ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer; /* Fill the name with the import name */ RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1); /* Set Hint to 0 */ ImportByName->Hint = 0; /* And finally point ThunkData's AddressOfData to that structure */ RefThunkData.u1.AddressOfData = (ULONG_PTR)ImportByName; /* And recursively call ourselves */ Success = WinLdrpBindImportName(ModuleListHead, DataTableEntry->DllBase, ImageBase, &RefThunkData, RefExportDirectory, RefExportSize, TRUE, DirectoryPath); /* Fill out the ThunkData with data from RefThunkData */ ThunkData->u1 = RefThunkData.u1; /* Return what we got from the recursive call */ return Success; } else { /* Fail if ExportDirectory is NULL */ return FALSE; } } /* Success! */ return TRUE; }
// // APC function. Initializes mapped image of a DLL: processes import, restores section protection. Executes image entry. // VOID _stdcall LoadDllApcStub( PLOADER_CONTEXT LdrCtx, PVOID SystemArgument1, PVOID SystemArgument2 ) { HANDLE hModule; PCHAR ImageBase; BOOL Result; if (ImageBase = (PCHAR)LdrCtx->ImageBase) { NTSTATUS ntStatus = STATUS_SUCCESS; FUNC_DLL_MAIN pDllMain; FUNC_APP_ENTRY AppEntryPoint; // Initializing DLL image PIMAGE_NT_HEADERS Pe = (PIMAGE_NT_HEADERS)(ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew); PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(Pe); ULONG i, OldProtect, NumberSections = Pe->FileHeader.NumberOfSections; // Resolving module import ULONG ImportStartRVA; PCHAR ModuleName; PVOID ImportedModuleBase = NULL; PIAT_ENTRY pIatEntry = NULL; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; // Get the import table RVA from the data dir if (ImportStartRVA = Pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) { pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + ImportStartRVA); // Find the import descriptor containing references to callee's functions for (; pImportDesc->Name; pImportDesc++) { ULONG NameLen = 0; ModuleName = ImageBase + pImportDesc->Name; while(ModuleName[NameLen]) { LdrCtx->wDllPath[NameLen] = (WCHAR)ModuleName[NameLen]; NameLen += 1; } LdrCtx->uDllPath.Length = (USHORT)(NameLen*sizeof(WCHAR)); LdrCtx->uDllPath.MaximumLength = (USHORT)((NameLen+1)*sizeof(WCHAR)); LdrCtx->uDllPath.Buffer = (PWSTR)&LdrCtx->wDllPath; ntStatus = ((FUNC_LOAD_LIBRARY)LdrCtx->Import.pLdrLoadDll)(NULL, 0, &LdrCtx->uDllPath, &ImportedModuleBase); if (NT_SUCCESS(ntStatus)) { ULONG rvaINT = pImportDesc->OriginalFirstThunk; ULONG rvaIAT = pImportDesc->FirstThunk; PIAT_ENTRY pIatEntry = NULL; PIMAGE_IMPORT_BY_NAME pOrdinalName; PIMAGE_THUNK_DATA pINT; PIMAGE_THUNK_DATA pIAT; IAT_ENTRY IatEntry; USHORT Ordinal = 0; if ( rvaINT == 0 ) // No Characteristics field? rvaINT = rvaIAT; if ( rvaINT != 0 ) // No FirstThunk field? Ooops!!! { // Adjust the pointer to point where the tables are in the mem mapped file. pINT = (PIMAGE_THUNK_DATA)(ImageBase + rvaINT); pIAT = (PIMAGE_THUNK_DATA)(ImageBase + rvaIAT); while (TRUE) // Loop forever (or until we break out) { if (pINT->u1.AddressOfData == 0) break; if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal) == FALSE) pOrdinalName = (PIMAGE_IMPORT_BY_NAME)(ImageBase + (ULONG)pINT->u1.AddressOfData); else if (pINT->u1.Ordinal >= (ULONG_PTR)ImageBase && pINT->u1.Ordinal < ((ULONG_PTR)ImageBase + Pe->OptionalHeader.SizeOfImage)) pOrdinalName = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)pINT->u1.AddressOfData); else { pOrdinalName = NULL; Ordinal = (USHORT)IMAGE_ORDINAL(pINT->u1.Ordinal); } if (pOrdinalName) { NameLen = 0; while(pOrdinalName->Name[NameLen]) NameLen += 1; LdrCtx->uDllPath.Length = (USHORT)NameLen; LdrCtx->uDllPath.MaximumLength = (USHORT)(NameLen + 1); LdrCtx->uDllPath.Buffer = (PWSTR)&pOrdinalName->Name; pOrdinalName = (PIMAGE_IMPORT_BY_NAME)&LdrCtx->uDllPath; } ntStatus = ((FUNC_PROC_ADDRESS)LdrCtx->Import.pLdrGetProcedureAddress)(ImportedModuleBase, (PANSI_STRING)pOrdinalName, Ordinal, (PVOID*)&IatEntry); if (NT_SUCCESS(ntStatus)) { pIatEntry = &pIAT->u1.Function; *pIatEntry = IatEntry; } else { ntStatus = STATUS_PROCEDURE_NOT_FOUND; break; } pINT++; // advance to next thunk pIAT++; // advance to next thunk } // while (TRUE) } // if ( rvaINT != 0 ) } // if (NT_SUCCESS(ntStatus)) else { ntStatus = STATUS_INVALID_IMPORT_OF_NON_DLL; break; } } // for (; pImportDesc->Name; pImportDesc++) } // if (ImportStartRVA = Pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) if (NT_SUCCESS(ntStatus)) { ULONG_PTR tSize = (ULONG_PTR)Pe->OptionalHeader.SizeOfHeaders; // Restoring sections' protection ntStatus = ((FUNC_PROTECT_MEM)LdrCtx->Import.pNtProtectVirtualMemory)((HANDLE)-1, (PVOID*)&ImageBase, &tSize, PAGE_READWRITE, &OldProtect); for (i=0; (i<NumberSections && NT_SUCCESS(ntStatus)); i++) { ULONG NewProtect = 0; PVOID BaseAddress; if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) { if (Section->Characteristics & IMAGE_SCN_MEM_WRITE) NewProtect = PAGE_EXECUTE_READWRITE; else NewProtect = PAGE_EXECUTE_READ; } else if (Section->Characteristics & IMAGE_SCN_MEM_READ) { if (Section->Characteristics & IMAGE_SCN_MEM_WRITE) NewProtect = PAGE_READWRITE; else NewProtect = PAGE_READONLY; } else NewProtect = PAGE_READWRITE; tSize = (ULONG_PTR)Section->Misc.VirtualSize; BaseAddress = (PVOID)(ImageBase + Section->VirtualAddress); ntStatus = ((FUNC_PROTECT_MEM)LdrCtx->Import.pNtProtectVirtualMemory)(NtCurrentProcess(), &BaseAddress, &tSize, NewProtect, &OldProtect); Section += 1; } // for (i=0; i<NumberSections; i++) if (NT_SUCCESS(ntStatus)) { // Calling DLL entry point pDllMain = (FUNC_DLL_MAIN)(ImageBase + Pe->OptionalHeader.AddressOfEntryPoint); Result = (pDllMain)(ImageBase, DLL_PROCESS_ATTACH, NULL); } // if (NT_SUCCESS(ntStatus)) } // if (NT_SUCCESS(ntStatus)) } // if (ImageBase = LdrCtx->ImageBase) else { // Loading DLL by name if (NT_SUCCESS(((FUNC_LOAD_LIBRARY)LdrCtx->Import.pLdrLoadDll)(NULL, 0, &LdrCtx->uDllPath, &hModule))) Result = TRUE; } UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2); }