diff --git a/MemoryModule.c b/MemoryModule.cpp similarity index 77% rename from MemoryModule.c rename to MemoryModule.cpp index 0bd2ee1..6f5ce81 100644 --- a/MemoryModule.c +++ b/MemoryModule.cpp @@ -49,21 +49,16 @@ #include "MemoryModule.h" -typedef struct { - PIMAGE_NT_HEADERS headers; - unsigned char *codeBase; - HCUSTOMMODULE *modules; - int numModules; - int initialized; - CustomLoadLibraryFunc loadLibrary; - CustomGetProcAddressFunc getProcAddress; - CustomFreeLibraryFunc freeLibrary; - void *userdata; -} MEMORYMODULE, *PMEMORYMODULE; - typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); -#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] +typedef HANDLE (WINAPI * MyCreateActCtx)(PCACTCTXA); +typedef HANDLE (WINAPI * MyDeactivateActCtx)(DWORD,ULONG_PTR); +typedef BOOL (WINAPI * MyActivateActCtx)(HANDLE,ULONG_PTR*); +HMODULE libkernel32 = LoadLibrary(_T("kernel32.dll")); +MyCreateActCtx _CreateActCtxA = (MyCreateActCtx)GetProcAddress(libkernel32,"CreateActCtxA"); +MyDeactivateActCtx _DeactivateActCtx = (MyDeactivateActCtx)GetProcAddress(libkernel32,"DeactivateActCtx"); +MyActivateActCtx _ActivateActCtx = (MyActivateActCtx)GetProcAddress(libkernel32,"ActivateActCtx"); + #ifdef DEBUG_OUTPUT static void @@ -73,9 +68,9 @@ OutputLastError(const char *msg) char *tmpmsg; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL); - tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); + tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen((const char *) tmp) + 3); sprintf(tmpmsg, "%s: %s", msg, tmp); - OutputDebugString(tmpmsg); + OutputDebugStringA(tmpmsg); LocalFree(tmpmsg); LocalFree(tmp); } @@ -97,7 +92,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, size, MEM_COMMIT, - PAGE_READWRITE); + PAGE_EXECUTE_READWRITE); section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; memset(dest, 0, size); @@ -111,7 +106,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_COMMIT, - PAGE_READWRITE); + PAGE_EXECUTE_READWRITE); memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; } @@ -122,7 +117,7 @@ static int ProtectionFlags[2][2][2] = { { // not executable {PAGE_NOACCESS, PAGE_WRITECOPY}, - {PAGE_READONLY, PAGE_READWRITE}, + {PAGE_READONLY, PAGE_EXECUTE_READWRITE}, }, { // executable {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, @@ -172,11 +167,12 @@ FinalizeSections(PMEMORYMODULE module) if (size > 0) { // change memory access flags - if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) #ifdef DEBUG_OUTPUT - OutputLastError("Error protecting memory page") + if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) + OutputLastError("Error protecting memory page"); +#else + VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect); #endif - ; } } #ifndef _WIN64 @@ -263,23 +259,103 @@ BuildImportTable(PMEMORYMODULE module) int result=1; unsigned char *codeBase = module->codeBase; HCUSTOMMODULE *tmp; + ULONG_PTR lpCookie = NULL; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (directory->Size > 0) { + PIMAGE_DATA_DIRECTORY resource = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_RESOURCE); + if (directory->Size > 0) + { PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); - for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { + + // 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++) + { POINTER_TYPE *thunkRef; FARPROC *funcRef; - HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); - if (handle == NULL) { - SetLastError(ERROR_MOD_NOT_FOUND); - result = 0; - break; - } + HCUSTOMMODULE handle; + handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); + if (handle == NULL) + { + SetLastError(ERROR_MOD_NOT_FOUND); + result = 0; + break; + } tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); if (tmp == NULL) { - module->freeLibrary(handle, module->userdata); + module->freeLibrary(handle, module->userdata); SetLastError(ERROR_OUTOFMEMORY); result = 0; break; @@ -300,7 +376,7 @@ BuildImportTable(PMEMORYMODULE module) *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); + *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); } if (*funcRef == 0) { result = 0; @@ -315,7 +391,8 @@ BuildImportTable(PMEMORYMODULE module) } } } - + if (_DeactivateActCtx && lpCookie) + _DeactivateActCtx(NULL,lpCookie); return result; } @@ -376,14 +453,14 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), old_header->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); + PAGE_EXECUTE_READWRITE); if (code == NULL) { // try to allocate memory at arbitrary position code = (unsigned char *)VirtualAlloc(NULL, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); + PAGE_EXECUTE_READWRITE); if (code == NULL) { SetLastError(ERROR_OUTOFMEMORY); return NULL; @@ -410,7 +487,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, - PAGE_READWRITE); + PAGE_EXECUTE_READWRITE); // copy PE header to code memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); @@ -420,7 +497,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; // copy sections from DLL file block to new memory location - CopySections(data, old_header, result); + CopySections((const unsigned char*) data, old_header, result); // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); @@ -437,14 +514,14 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // sections that are marked as "discardable" FinalizeSections(result); - // TLS callbacks are executed BEFORE the main loading + // TLS callbacks are executed BEFORE the main loading ExecuteTLS(result); // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); // notify library about attaching to process - successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); + successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, result); if (!successfull) { SetLastError(ERROR_DLL_INIT_FAILED); goto error; @@ -576,9 +653,8 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( // a binary search to find faster... if (IS_INTRESOURCE(key)) { WORD check = (WORD) (POINTER_TYPE) key; - start = resources->NumberOfNamedEntries; - end = start + resources->NumberOfIdEntries; - + start = 0; //resources->NumberOfNamedEntries; + end = resources->NumberOfIdEntries; while (end > start) { WORD entryName; middle = (start + end) >> 1; @@ -593,19 +669,19 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } } else { -#if !defined(UNICODE) +#ifndef _UNICODE char *searchKey = NULL; int searchKeyLength = 0; #endif start = 0; - end = resources->NumberOfIdEntries; + end = resources->NumberOfNamedEntries; while (end > start) { // resource names are always stored using 16bit characters int cmp; - PIMAGE_RESOURCE_DIR_STRING_U resourceString; + PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); -#if !defined(UNICODE) +#ifndef _UNICODE if (searchKey == NULL || searchKeyLength < resourceString->Length) { void *tmp = realloc(searchKey, resourceString->Length); if (tmp == NULL) { @@ -628,7 +704,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( break; } } -#if !defined(UNICODE) +#ifndef _UNICODE free(searchKey); #endif } @@ -687,11 +763,10 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1); } - return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); } -DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) +DWORD MemorySizeOfResource(HMEMORYMODULE module, HMEMORYRSRC resource) { PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; @@ -706,19 +781,17 @@ LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) return codeBase + entry->OffsetToData; } -int -MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) +LPVOID MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) { return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE); } -int -MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) +LPVOID MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) { - HMEMORYRSRC resource; - PIMAGE_RESOURCE_DIR_STRING_U data; - DWORD size; - if (maxsize == 0) { + HMEMORYRSRC resource; + PIMAGE_RESOURCE_DIR_STRING_U data; + DWORD size; + if (buffer && maxsize == 0) { return 0; } @@ -728,7 +801,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO return 0; } - data = MemoryLoadResource(module, resource); + data = (PIMAGE_RESOURCE_DIR_STRING_U) MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); @@ -737,7 +810,8 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); buffer[0] = 0; return 0; - } + } else if (!buffer) + return data->NameString; size = data->Length; if (size >= (DWORD) maxsize) { @@ -750,5 +824,5 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO #else wcstombs(buffer, data->NameString, size); #endif - return size; + return (LPVOID)size; } diff --git a/MemoryModule.h b/MemoryModule.h index 7fbb22d..804716e 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -39,10 +39,24 @@ typedef void *HCUSTOMMODULE; extern "C" { #endif +#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] + typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *); typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); +typedef struct { + PIMAGE_NT_HEADERS headers; + unsigned char *codeBase; + HCUSTOMMODULE *modules; + int numModules; + int initialized; + CustomLoadLibraryFunc loadLibrary; + CustomGetProcAddressFunc getProcAddress; + CustomFreeLibraryFunc freeLibrary; + void *userdata; +} MEMORYMODULE, *PMEMORYMODULE; + /** * Load DLL from memory location. * @@ -85,7 +99,7 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); /** * Get the size of the resource in bytes. */ -DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); +DWORD MemorySizeOfResource(HMEMORYMODULE, HMEMORYRSRC); /** * Get a pointer to the contents of the resource. @@ -95,12 +109,12 @@ LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); /** * Load a string resource. */ -int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); +LPVOID MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); /** * Load a string resource with a given language. */ -int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); +LPVOID MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); #ifdef __cplusplus }