NTSTATUS kull_m_process_getImportedEntryInformations(PKULL_M_MEMORY_ADDRESS address, PKULL_M_IMPORTED_ENTRY_ENUM_CALLBACK callBack, PVOID pvArg) { KULL_M_MEMORY_HANDLE hBuffer = {KULL_M_MEMORY_TYPE_OWN, NULL}; PVOID pLocalBuffer; PIMAGE_IMPORT_DESCRIPTOR pImportDir; ULONG sizeThunk; ULONGLONG OriginalFirstThunk, FirstThunk, ordinalPattern; KULL_M_MEMORY_ADDRESS aOriginalFirstThunk = {&OriginalFirstThunk, &hBuffer}, aFirstThunk = {&FirstThunk, &hBuffer}; KULL_M_MEMORY_ADDRESS aProcOriginalFirstThunk = {NULL, address->hMemory}, aProcName = {NULL, address->hMemory}; KULL_M_PROCESS_IMPORTED_ENTRY importedEntry; BOOL continueCallback = TRUE; importedEntry.pFunction.hMemory = address->hMemory; importedEntry.function.hMemory = address->hMemory; if(kull_m_process_datadirectory(address, IMAGE_DIRECTORY_ENTRY_IMPORT, NULL, NULL, &importedEntry.machine, &pLocalBuffer)) { if(importedEntry.machine == IMAGE_FILE_MACHINE_I386) { sizeThunk = sizeof(IMAGE_THUNK_DATA32); ordinalPattern = IMAGE_ORDINAL_FLAG32; } else { sizeThunk = sizeof(IMAGE_THUNK_DATA64); ordinalPattern = IMAGE_ORDINAL_FLAG64; } for(pImportDir = (PIMAGE_IMPORT_DESCRIPTOR) pLocalBuffer ; pImportDir->Characteristics && continueCallback; pImportDir++) { aProcName.address = (PBYTE) address->address + pImportDir->Name; if(importedEntry.libname = kull_m_process_getImportNameWithoutEnd(&aProcName)) { for( aProcOriginalFirstThunk.address = ((PBYTE) address->address + pImportDir->OriginalFirstThunk), importedEntry.pFunction.address = ((PBYTE) address->address + pImportDir->FirstThunk); (kull_m_memory_copy(&aOriginalFirstThunk, &aProcOriginalFirstThunk, sizeThunk) && kull_m_memory_copy(&aFirstThunk, &importedEntry.pFunction, sizeThunk)) && (OriginalFirstThunk && FirstThunk) ; aProcOriginalFirstThunk.address = ((PBYTE) aProcOriginalFirstThunk.address + sizeThunk), ((PDWORD) &OriginalFirstThunk)[1] = 0, importedEntry.pFunction.address = ((PBYTE) importedEntry.pFunction.address + sizeThunk), ((PDWORD) &FirstThunk)[1] = 0 ) { importedEntry.function.address = (PVOID) FirstThunk; if(OriginalFirstThunk & ordinalPattern) { importedEntry.name = NULL; importedEntry.ordinal = IMAGE_ORDINAL(OriginalFirstThunk); } else { aProcName.address = ((PIMAGE_IMPORT_BY_NAME) ((PBYTE) address->address + OriginalFirstThunk))->Name; importedEntry.name = kull_m_process_getImportNameWithoutEnd(&aProcName); importedEntry.ordinal = 0; } continueCallback = callBack(&importedEntry, pvArg); if(importedEntry.name) LocalFree(importedEntry.name); } LocalFree(importedEntry.libname); } } LocalFree(pLocalBuffer); } return TRUE; }
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; }
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; }
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; } }
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; }
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 }
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; }
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID) #endif { // the functions we need LOADLIBRARYA pLoadLibraryA = NULL; GETPROCADDRESS pGetProcAddress = NULL; VIRTUALALLOC pVirtualAlloc = NULL; NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; USHORT usCounter; // the initial location of this image in memory ULONG_PTR uiLibraryAddress; // the kernels base address and later this images newly loaded base address ULONG_PTR uiBaseAddress; // variables for processing the kernels export table ULONG_PTR uiAddressArray; ULONG_PTR uiNameArray; ULONG_PTR uiExportDir; ULONG_PTR uiNameOrdinals; DWORD dwHashValue; // variables for loading this image ULONG_PTR uiHeaderValue; ULONG_PTR uiValueA; ULONG_PTR uiValueB; ULONG_PTR uiValueC; ULONG_PTR uiValueD; ULONG_PTR uiValueE; // STEP 0: calculate our images current base address // we will start searching backwards from our callers return address. uiLibraryAddress = caller(); // loop through memory backwards searching for our images base address // we dont need SEH style search as we shouldnt generate any access violations with this while (TRUE) { if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE) { uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024) { uiHeaderValue += uiLibraryAddress; // break if we have found a valid MZ/PE header if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE) break; } } uiLibraryAddress--; } // STEP 1: process the kernels exports for the functions our loader needs... // get the Process Enviroment Block #ifdef WIN_X64 uiBaseAddress = __readgsqword(0x60); #else #ifdef WIN_X86 uiBaseAddress = __readfsdword(0x30); #else WIN_ARM //uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); #endif #endif // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; // get the first entry of the InMemoryOrder module list uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; while (uiValueA) { // get pointer to current modules name (unicode string) uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; // set bCounter to the length for the loop usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; // clear uiValueC which will store the hash of the module name uiValueC = 0; // compute the hash of the module name... do { uiValueC = ror((DWORD)uiValueC); // normalize to uppercase if the madule name is in lowercase if (*((BYTE *)uiValueB) >= 'a') { uiValueC += *((BYTE *)uiValueB) - 0x20; } else { uiValueC += *((BYTE *)uiValueB); } uiValueB++; } while (--usCounter); // compare the hash with that of kernel32.dll if ((DWORD)uiValueC == KERNEL32DLL_HASH) { // get this modules base address uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of name pointers uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); usCounter = 3; // loop while we still have imports to find while (usCounter > 0) { // compute the hash values for this function name dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray))); // if we have found a function we want we get its virtual address if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH) { // get the VA for the array of addresses uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); // store this functions VA if (dwHashValue == LOADLIBRARYA_HASH) { pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray)); } else if (dwHashValue == GETPROCADDRESS_HASH) { pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray)); } else if (dwHashValue == VIRTUALALLOC_HASH) pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray)); // decrement our counter usCounter--; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } else if ((DWORD)uiValueC == NTDLLDLL_HASH) { // get this modules base address uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of name pointers uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); usCounter = 1; // loop while we still have imports to find while (usCounter > 0) { // compute the hash values for this function name dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray))); // if we have found a function we want we get its virtual address if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) { // get the VA for the array of addresses uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); // store this functions VA if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray)); // decrement our counter usCounter--; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } // we stop searching when we have found everything we need. if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache) break; // get the next entry uiValueA = DEREF(uiValueA); } // STEP 2: load our image into a new permanent location in memory... // get the VA of the NT Header for the PE to be loaded uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // allocate all the memory for the DLL to be loaded into. we can load at any address because we will // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); // we must now copy over the headers uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; uiValueB = uiLibraryAddress; uiValueC = uiBaseAddress; while (uiValueA--) *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; // STEP 3: load in all of our sections... // uiValueA = the VA of the first section uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); // itterate through all sections, loading them into memory. uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; while (uiValueE--) { // uiValueB is the VA for this section uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); // uiValueC if the VA for this sections data uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData); // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; while (uiValueD--) *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; // get the VA of the next section uiValueA += sizeof(IMAGE_SECTION_HEADER); } // STEP 4: process our images import table... // uiValueB = the address of the import directory uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; // we assume their is an import table to process // uiValueC is the first entry in the import table uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); // itterate through all imports while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name) { // use LoadLibraryA to load the imported module into memory uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); // uiValueD = VA of the OriginalFirstThunk uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk); // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk); // itterate through all imported functions, importing by ordinal if no name present while (DEREF(uiValueA)) { // sanity check uiValueD as some compilers only import by FirstThunk if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) { // get the VA of the modules NT Header uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of addresses uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); // patch in the address for this imported function DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); } else { // get the VA of this functions import by name struct uiValueB = (uiBaseAddress + DEREF(uiValueA)); // use GetProcAddress and patch in the address for this imported function DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); } // get the next imported function uiValueA += sizeof(ULONG_PTR); if (uiValueD) uiValueD += sizeof(ULONG_PTR); } // get the next import uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); } // STEP 5: process all of our images relocations... // calculate the base address delta and perform relocations (even if we load at desired image base) uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; // uiValueB = the address of the relocation directory uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; // check if their are any relocations present if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size) { // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); // and we itterate through all entries... while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock) { // uiValueA = the VA for this relocation block uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress); // uiValueB = number of entries in this relocation block uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); // uiValueD is now the first entry in the current relocation block uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); // we itterate through all the entries in the current block... while (uiValueB--) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we dont use a switch statement to avoid the compiler building a jump table // which would not be very position independent! if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64) { *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; } else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW) { *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; } #ifdef WIN_ARM // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T) { register DWORD dwInstruction; register DWORD dwAddress; register WORD wImm; // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)); // flip the words to get the instruction as expected dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); // sanity chack we are processing a MOV instruction... if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT) { // pull out the encoded 16bit value (the high portion of the address-to-relocate) wImm = (WORD)(dwInstruction & 0x000000FF); wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); // apply the relocation to the target address dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF; // now create a new instruction with the same opcode and register param. dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2); // patch in the relocated address... dwInstruction |= (DWORD)(dwAddress & 0x00FF); dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; // now flip the instructions words and patch back into the code... *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); } } #endif else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH) { *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); } else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW) { *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); } // get the next entry in the current relocation block uiValueD += sizeof(IMAGE_RELOC); }
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; }
BOOL ImportEnumerate(HINSTANCE hInst) { PBYTE pbBase = (PBYTE)hInst; PIMAGE_NT_HEADERS pNtHeader; // Read & Write PIMAGE_SECTION_HEADER pSectionHeaders; DWORD nPeOffset; DWORD nSectionsOffset; ////////////////////////////////////////////////////// Process DOS Header. // PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbBase; if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; } nPeOffset = pDosHeader->e_lfanew; /////////////////////////////////////////////////////// Process PE Header. // pNtHeader = (PIMAGE_NT_HEADERS)RvaToVa(pbBase, nPeOffset); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { return FALSE; } if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { return FALSE; } nSectionsOffset = nPeOffset + sizeof(pNtHeader->Signature) + sizeof(pNtHeader->FileHeader) + pNtHeader->FileHeader.SizeOfOptionalHeader; ///////////////////////////////////////////////// Process Section Headers. // pSectionHeaders = (PIMAGE_SECTION_HEADER)RvaToVa(pbBase, nSectionsOffset); //////////////////////////////////////////////////////// Get Import Table. // DWORD rvaImageDirectory = pNtHeader->OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; PIMAGE_IMPORT_DESCRIPTOR iidp = (PIMAGE_IMPORT_DESCRIPTOR)RvaToVa(pbBase, rvaImageDirectory); if (iidp == NULL) { return FALSE; } for (DWORD nFiles = 0; iidp[nFiles].Characteristics != 0; nFiles++) { // Count the files. } for (DWORD n = 0; n < nFiles; n++, iidp++) { DWORD rvaName = iidp->Name; PCHAR pszName = (PCHAR)RvaToVa(pbBase, rvaName); DWORD rvaThunk = (DWORD)iidp->OriginalFirstThunk; PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)RvaToVa(pbBase, rvaThunk); rvaThunk = (DWORD)iidp->FirstThunk; PIMAGE_THUNK_DATA pBoundThunk = (PIMAGE_THUNK_DATA)RvaToVa(pbBase, rvaThunk); Syelog(SYELOG_SEVERITY_INFORMATION, "%s [%08x %08x]\n", pszName, pThunk, pBoundThunk); DWORD nNames = 0; if (pThunk == NULL) { break; } for (; pThunk[nNames].u1.Ordinal; nNames++) { // Count the imports. } for (DWORD f = 0; f < nNames; f++) { DWORD nOrdinal = 0; PCHAR pszName = NULL; PDWORD pFunc = (PDWORD)pBoundThunk[f].u1.Function; DWORD rvaName = pThunk[f].u1.Ordinal; if (rvaName & IMAGE_ORDINAL_FLAG) { nOrdinal = IMAGE_ORDINAL(rvaName); } else { PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)RvaToVa(pbBase, rvaName); if (pName) { pszName = (PCHAR)pName->Name; } } Syelog(SYELOG_SEVERITY_INFORMATION, " %-32.32s %4d %08x\n", pszName, nOrdinal, pFunc); } } return TRUE; }
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; }
// This code is modified from Stephen Fewer's GetProcAddress implementation //===============================================================================================// // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// FARPROC WINAPI CustomGetProcAddressEx(HMODULE hModule, const PCHAR lpProcName, PWSTR wszOriginalModule) { UINT_PTR uiLibraryAddress = 0; UINT_PTR uiAddressArray = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiNameOrdinals = 0; UINT_PTR uiFuncVA = 0; PCHAR cpExportedFunctionName; PCHAR szFwdDesc; PCHAR szRedirFunc; PWSTR wszDllName; SIZE_T stDllName; PWCHAR wsRedir; PWSTR wszRedirName = NULL; SIZE_T stRedirName; HMODULE hFwdModule; PIMAGE_NT_HEADERS pNtHeaders = NULL; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; FARPROC fpResult = NULL; DWORD dwCounter; if (hModule == NULL) return NULL; // a module handle is really its base address uiLibraryAddress = (UINT_PTR)hModule; // get the VA of the modules NT Header pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(uiLibraryAddress + pDataDirectory->VirtualAddress); // get the VA for the array of addresses uiAddressArray = (uiLibraryAddress + pExportDirectory->AddressOfFunctions); // get the VA for the array of name pointers uiNameArray = (uiLibraryAddress + pExportDirectory->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals); // test if we are importing by name or by ordinal... #pragma warning(suppress: 4311) if (((DWORD)lpProcName & 0xFFFF0000) == 0x00000000) { // import by ordinal... // use the import ordinal (- export ordinal base) as an index into the array of addresses #pragma warning(suppress: 4311) uiAddressArray += ((IMAGE_ORDINAL((DWORD)lpProcName) - pExportDirectory->Base) * sizeof(DWORD)); // resolve the address for this imported function fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray)); } else { // import by name... dwCounter = pExportDirectory->NumberOfNames; while (dwCounter--) { cpExportedFunctionName = (PCHAR)(uiLibraryAddress + DEREF_32(uiNameArray)); // test if we have a match... if (strcmp(cpExportedFunctionName, lpProcName) == 0) { // use the functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); uiFuncVA = DEREF_32(uiAddressArray); // check for redirected exports if (pDataDirectory->VirtualAddress <= uiFuncVA && uiFuncVA < (pDataDirectory->VirtualAddress + pDataDirectory->Size)) { szFwdDesc = (PCHAR)(uiLibraryAddress + uiFuncVA); // Find the first character after "." szRedirFunc = strstr(szFwdDesc, ".") + 1; stDllName = (SIZE_T)(szRedirFunc - szFwdDesc); // Allocate enough space to append "dll" wszDllName = (PWSTR)calloc(stDllName + 3 + 1, sizeof(WCHAR)); if (wszDllName == NULL) break; mbstowcs_s(NULL, wszDllName, stDllName + 1, szFwdDesc, stDllName); memcpy(wszDllName + stDllName, L"dll", 3 * sizeof(WCHAR)); // check for a redirected module name if (_wcsnicmp(wszDllName, L"api-", 4) == 0 || _wcsnicmp(wszDllName, L"ext-", 4) == 0) { wsRedir = GetRedirectedName(wszOriginalModule, wszDllName, &stRedirName); if (wsRedir) { // Free the original buffer and allocate a new one for the redirected dll name free(wszDllName); wszDllName = (PWSTR)calloc(stRedirName + 1, sizeof(WCHAR)); if (wszDllName == NULL) break; memcpy(wszDllName, wsRedir, stRedirName * sizeof(WCHAR)); } } hFwdModule = GetModuleHandleW(wszDllName); fpResult = CustomGetProcAddressEx(hFwdModule, szRedirFunc, wszDllName); free(wszDllName); } else { // calculate the virtual address for the function fpResult = (FARPROC)(uiLibraryAddress + uiFuncVA); } // finish... break; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } return fpResult; }
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; }
//===============================================================================================// // We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which // wont be able to resolve exported addresses in reflectivly loaded librarys. FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) { UINT_PTR uiLibraryAddress = 0; FARPROC fpResult = NULL; if( hModule == NULL ) return NULL; // a module handle is really its base address uiLibraryAddress = (UINT_PTR)hModule; __try { UINT_PTR uiAddressArray = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiNameOrdinals = 0; PIMAGE_NT_HEADERS pNtHeaders = NULL; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; // get the VA of the modules NT Header pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress ); // get the VA for the array of addresses uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions ); // get the VA for the array of name pointers uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames ); // get the VA for the array of name ordinals uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals ); // test if we are importing by name or by ordinal... if( ((DWORD)lpProcName & 0xFFFF0000 ) == 0x00000000 ) { // import by ordinal... // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); // resolve the address for this imported function fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); } else { // import by name... DWORD dwCounter = pExportDirectory->NumberOfNames; while( dwCounter-- ) { char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray )); // test if we have a match... if( strcmp( cpExportedFunctionName, lpProcName ) == 0 ) { // use the functions name ordinal as an index into the array of name pointers uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); // calculate the virtual address for the function fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray )); // finish... break; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { fpResult = NULL; } return fpResult; }
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; }
FARPROC WINAPI _EXPFUNC __delayLoadHelper(ImgDelayDescr *pidd, FARPROC *ppfnIATEntry) { HMODULE hmod; unsigned iINT; FARPROC pfnRet; const IMAGE_THUNK_DATA * pitd; // Set up some data we use for the hook procs but also useful for // our own use // DelayLoadInfo dli; memset(&dli, 0, sizeof(dli)); dli.cb = sizeof (DelayLoadInfo); dli.pidd = pidd; dli.ppfn = ppfnIATEntry; dli.szDll = pidd->szName; hmod = pidd->hmod; // Calculate the index for the name in the import name table. // N.B. it is ordered the same as the IAT entries so the calculation // comes from the IAT side. // iINT = IndexFromPImgThunkData((const IMAGE_THUNK_DATA *)ppfnIATEntry, pidd->pIAT); pitd = &((pidd->pINT)[iINT]); if ((dli.dlp.fImportByName = ((pitd->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0)) != 0) { dli.dlp.szProcName = (LPCSTR)((IMAGE_IMPORT_BY_NAME*)pitd->u1.AddressOfData)->Name; } else { dli.dlp.dwOrdinal = 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. // pfnRet = NULL; if (__pfnDliNotifyHook) { if ((pfnRet = (*__pfnDliNotifyHook)(dliNoteStartProcessing, &dli)) != 0) { goto HookBypass; } } if (hmod == 0) { if (__pfnDliNotifyHook) { hmod = (HMODULE)(*__pfnDliNotifyHook)(dliNotePreLoadLibrary, &dli); } if (hmod == 0) { hmod = LoadLibrary(dli.szDll); } if (hmod == 0) { dli.dwLastError = GetLastError(); if (__pfnDliFailureHook) { // 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)(*__pfnDliFailureHook)(dliFailLoadLibrary, &dli); } if (hmod == 0) { DelayLoadInfo * pdli = &dli; RaiseException( BCPPException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND), 0, 1, (PDWORD)&pdli ); // 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 // EnterCriticalSection(&UnloadInfoCS); if (!pidd->hmod) { AddToUnloadList(pidd); pidd->hmod = hmod; } else { FreeLibrary(hmod); hmod = pidd->hmod; } LeaveCriticalSection(&UnloadInfoCS); } // Go for the procedure now. dli.hmodCur = hmod; if (__pfnDliNotifyHook) { pfnRet = (*__pfnDliNotifyHook)(dliNotePreGetProcAddress, &dli); } if (pfnRet == 0) { if (pidd->pBoundIAT && 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) == pidd->dwTimeStamp && FLoadedAtPreferredAddress(pinh, hmod)) { OverlayIAT(pidd->pIAT, pidd->pBoundIAT); pfnRet = (FARPROC)pidd->pIAT[iINT].u1.Function; goto HookBypass; } } pfnRet = GetProcAddress(hmod, dli.dlp.szProcName); } if (pfnRet == 0) { dli.dwLastError = GetLastError(); if (__pfnDliFailureHook) { // when the hook is called on GetProcAddress failure, it will // return 0 on failure and a valid proc address on success // pfnRet = (*__pfnDliFailureHook)(dliFailGetProcAddress, &dli); } if (pfnRet == 0) { DelayLoadInfo * pdli = &dli; RaiseException( BCPPException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND), 0, 1, (PDWORD)&pdli ); // 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; } } *ppfnIATEntry = pfnRet; HookBypass: if (__pfnDliNotifyHook) { dli.dwLastError = 0; dli.hmodCur = hmod; dli.pfnCur = pfnRet; (*__pfnDliNotifyHook)(dliNoteEndProcessing, &dli); } return pfnRet; }
DLLEXPORT UINT_PTR WINAPI ReflectiveLoader( VOID ) #endif { // the functions we need LOADLIBRARYA pLoadLibraryA; GETPROCADDRESS pGetProcAddress; VIRTUALALLOC pVirtualAlloc; VIRTUALLOCK pVirtualLock; OUTPUTDEBUG pOutputDebug; USHORT usCounter; // the initial location of this image in memory UINT_PTR uiLibraryAddress; // the kernels base address and later this images newly loaded base address UINT_PTR uiBaseAddress; // variables for processing the kernels export table UINT_PTR uiAddressArray; UINT_PTR uiNameArray; UINT_PTR uiExportDir; UINT_PTR uiNameOrdinals; DWORD dwHashValue; // variables for loading this image UINT_PTR uiHeaderValue; UINT_PTR uiValueA; UINT_PTR uiValueB; UINT_PTR uiValueC; UINT_PTR uiValueD; UINT_PTR uiValueE; register UINT_PTR inspect; // STEP 0: calculate our images current base address // we will start searching backwards from our current EIP #ifdef _WIN64 uiLibraryAddress = eip(); #else __asm { call geteip geteip: pop uiLibraryAddress } #endif // loop through memory backwards searching for our images base address // we dont need SEH style search as we shouldnt generate any access violations with this while( TRUE ) { if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) { uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) { uiHeaderValue += uiLibraryAddress; // break if we have found a valid MZ/PE header if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) break; } } uiLibraryAddress--; } // STEP 1: process the kernels exports for the functions our loader needs... // get the Process Enviroment Block #ifdef _WIN64 uiBaseAddress = __readgsqword( 0x60 ); #else uiBaseAddress = __readfsdword( 0x30 ); #endif // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx uiBaseAddress = (UINT_PTR)((_PPEB)uiBaseAddress)->pLdr; // get the first entry of the InMemoryOrder module list uiValueA = (UINT_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; while( uiValueA ) { // get pointer to current modules name (unicode string) uiValueB = (UINT_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; // set bCounter to the length for the loop usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; // clear uiValueC which will store the hash of the module name uiValueC = 0; // compute the hash of the module name... do { uiValueC = ror( (DWORD)uiValueC ); // normalize to uppercase if the module name is in lowercase if( *((BYTE *)uiValueB) >= 'a' ) uiValueC += *((BYTE *)uiValueB) - 0x20; else uiValueC += *((BYTE *)uiValueB); uiValueB++; } while( --usCounter ); // compare the hash with that of kernel32.dll if( (DWORD)uiValueC == KERNEL32DLL_HASH ) { // get this modules base address uiBaseAddress = (UINT_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; break; } // get the next entry uiValueA = DEREF( uiValueA ); } // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); // get the VA for the array of name pointers uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); // get the VA for the array of name ordinals uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); usCounter = 5; // loop while we still have imports to find while( usCounter > 0 ) { // compute the hash values for this function name dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); // if we have found a function we want we get its virtual address if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH || dwHashValue == VIRTUALLOCK_HASH || dwHashValue == OUTPUTDEBUG_HASH ) { // get the VA for the array of addresses uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); // store this functions VA if( dwHashValue == LOADLIBRARYA_HASH ) pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == GETPROCADDRESS_HASH ) pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == VIRTUALALLOC_HASH ) pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == VIRTUALLOCK_HASH ) pVirtualLock = (VIRTUALLOCK)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == OUTPUTDEBUG_HASH ) pOutputDebug = (OUTPUTDEBUG)( uiBaseAddress + DEREF_32( uiAddressArray ) ); // decrement our counter usCounter--; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } // STEP 2: load our image into a new permanent location in memory... // get the VA of the NT Header for the PE to be loaded uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // allocate all the memory for the DLL to be loaded into. we can load at any address because we will // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. uiBaseAddress = (UINT_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); // prevent our image from being swapped to the pagefile pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage); // we must now copy over the headers uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; uiValueB = uiLibraryAddress; uiValueC = uiBaseAddress; __movsb( (PBYTE)uiValueC, (PBYTE)uiValueB, uiValueA ); // STEP 3: load in all of our sections... // uiValueA = the VA of the first section uiValueA = ( (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; // iterate through all sections, loading them into memory. while( uiValueE-- ) { // uiValueB is the VA for this section uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); // uiValueC if the VA for this sections data uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; __movsb( (PBYTE)uiValueB, (PBYTE)uiValueC, uiValueD ); // get the VA of the next section uiValueA += sizeof( IMAGE_SECTION_HEADER ); } // STEP 4: process our images import table... // uiValueB = the address of the import directory uiValueB = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; uiValueC = ( uiBaseAddress + (UINT_PTR)((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); // iterate through all imports until a null RVA is found (Characteristics is mis-named) while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics ) { /* pOutputDebug("Loading library: "); pOutputDebug((LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name )); pOutputDebug("\n"); */ // use LoadLibraryA to load the imported module into memory uiLibraryAddress = (UINT_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); if (! uiLibraryAddress) { //pOutputDebug("Loading library FAILED\n"); // get the next import uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); continue; } // uiValueD = VA of the OriginalFirstThunk uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); // itterate through all imported functions, importing by ordinal if no name present while( DEREF(uiValueA) ) { // sanity check uiValueD as some compilers only import by FirstThunk if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) { // get the VA of the modules NT Header uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); // get the VA for the array of addresses uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); // patch in the address for this imported function DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); } else { // get the VA of this functions import by name struct uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); /* pOutputDebug("Resolving function: "); pOutputDebug((LPCSTR)( (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name )); pOutputDebug("\n"); */ // use GetProcAddress and patch in the address for this imported function DEREF(uiValueA) = (UINT_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); } // get the next imported function uiValueA += sizeof( UINT_PTR ); if( uiValueD ) uiValueD += sizeof( UINT_PTR ); } // get the next import uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); } // STEP 5: process all of our images relocations... // calculate the base address delta and perform relocations (even if we load at desired image base) uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; // uiValueB = the address of the relocation directory uiValueB = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; // check if there are any relocations present if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) { // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); // and we iterate through all entries... while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) { // uiValueA = the VA for this relocation block uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); // uiValueB = number of entries in this relocation block uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); // uiValueD is now the first entry in the current relocation block uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); // we itterate through all the entries in the current block... while( uiValueB-- ) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we dont use a switch statement to avoid the compiler building a jump table // which would not be very position independent! if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) *(UINT_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); // get the next entry in the current relocation block uiValueD += sizeof( IMAGE_RELOC ); } // get the next entry in the relocation directory uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; } } // STEP 6: process the images exception directory if it has one (PE32+ for x64) /* // uiValueB = the address of the relocation directory uiValueB = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION ]; // check if their are any exception etries present if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) { // get the number of entries uiValueA = ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); // uiValueC is now the first entry (IMAGE_RUNTIME_FUNCTION_ENTRY) uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); // itterate through all entries while( uiValueA-- ) { //((IMAGE_RUNTIME_FUNCTION_ENTRY)uiValueC).BeginAddress // get the next entry uiValueC += sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); } } */ // STEP 7: call our images entry point // uiValueA = the VA of our newly loaded DLL/EXE's entry point uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); // call our respective entry point, fudging our hInstance value #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); #else // if we are injecting an DLL via a stub we call DllMain with no parameter ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); #endif // STEP 8: return our new entry point address so whatever called us can call DLL_METASPLOIT_ATTACH/DLL_METASPLOIT_DETACH return uiValueA; }
// // 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); }