void MemoryFreeLibrary(HMEMORYMODULE mod) { PMEMORYMODULE module = (PMEMORYMODULE)mod; if (module == NULL) { return; } if (module->initialized) { // notify library about detaching from process DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); } if (module->modules != NULL) { // free previously opened libraries int i; for (i=0; i<module->numModules; i++) { if (module->modules[i] != NULL) { module->freeLibrary(module->modules[i], module->userdata); } } free(module->modules); } if (module->codeBase != NULL) { // release memory of library VirtualFree(module->codeBase, 0, MEM_RELEASE); } HeapFree(GetProcessHeap(), 0, module); }
static BOOL CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { int i, section_size; unsigned char *codeBase = module->codeBase; unsigned char *dest; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) { if (section->SizeOfRawData == 0) { // section doesn't contain data in the dll itself, but may define // uninitialized data section_size = old_headers->OptionalHeader.SectionAlignment; if (section_size > 0) { dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress, section_size, MEM_COMMIT, PAGE_READWRITE, module->userdata); if (dest == NULL) { return FALSE; } // Always use position from file to support alignments smaller // than page size (allocation above will align to page size). dest = codeBase + section->VirtualAddress; // NOTE: On 64bit systems we truncate to 32bit here but expand // again later when "PhysicalAddress" is used. section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); memset(dest, 0, section_size); } // section is empty continue; } if (!CheckSize(size, section->PointerToRawData + section->SizeOfRawData)) { return FALSE; } // commit memory block and copy data from dll dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE, module->userdata); if (dest == NULL) { return FALSE; } // Always use position from file to support alignments smaller // than page size (allocation above will align to page size). dest = codeBase + section->VirtualAddress; memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); // NOTE: On 64bit systems we truncate to 32bit here but expand // again later when "PhysicalAddress" is used. section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); } return TRUE; }
int MemoryCallEntryPoint(HMEMORYMODULE mod) { PMEMORYMODULE module = (PMEMORYMODULE)mod; if (module == NULL || module->isDLL || module->exeEntry == NULL || !module->isRelocated) { return -1; } return module->exeEntry(); }
static BOOL FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { DWORD protect, oldProtect; BOOL executable; BOOL readable; BOOL writeable; if (sectionData->size == 0) { return TRUE; } if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) { // section is not needed any more and can safely be freed if (sectionData->address == sectionData->alignedAddress && (sectionData->last || module->headers->OptionalHeader.SectionAlignment == module->pageSize || (sectionData->size % module->pageSize) == 0) ) { // Only allowed to decommit whole pages module->free(sectionData->address, sectionData->size, MEM_DECOMMIT, module->userdata); } return TRUE; } // determine protection flags based on characteristics executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0; writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0; protect = ProtectionFlags[executable][readable][writeable]; if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) { protect |= PAGE_NOCACHE; } // change memory access flags if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { OutputLastError("Error protecting memory page"); return FALSE; } 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; }