clsMemDump::clsMemDump( HANDLE hProc, PTCHAR FileBaseName, DWORD64 BaseOffset, DWORD Size, QWidget *pParent) { bool isProtectionChanged = false; DWORD OldProtection = NULL, NewProtection = PAGE_READWRITE, BytesWrote = NULL; SIZE_T BytesReaded = NULL; LPVOID pBuffer = malloc(Size); if(!ReadProcessMemory(hProc,(LPVOID)BaseOffset,pBuffer,Size,&BytesReaded)) { if(!VirtualProtectEx(hProc,(LPVOID)BaseOffset,Size,NewProtection,&OldProtection)) { QMessageBox::critical(pParent,"Nanomite","Failed to access Memory!",QMessageBox::Ok,QMessageBox::Ok); free(pBuffer); return; } isProtectionChanged = true; if(!ReadProcessMemory(hProc,(LPVOID)BaseOffset,pBuffer,Size,&BytesReaded)) { QMessageBox::critical(pParent,"Nanomite","Failed to read Memory!",QMessageBox::Ok,QMessageBox::Ok); free(pBuffer); return; } } PTCHAR FileName = (PTCHAR)malloc(MAX_PATH * sizeof(TCHAR)); if(wcslen(FileBaseName) <= 0) wsprintf(FileName,L"NANOMITEDUMP_%016I64X-%016I64X_%08X.bin",BaseOffset,BaseOffset + Size,Size); else wsprintf(FileName,L"%s_%016I64X-%016I64X_%08X.bin",FileBaseName,BaseOffset,BaseOffset + Size,Size); QString filePath = QFileDialog::getSaveFileName(pParent, "Please select a place to save the dump", QString("%1\\%2").arg(QDir::currentPath()).arg(QString::fromWCharArray(FileName)), "Dump files (*.dmp *.bin)", NULL, QFileDialog::DontUseNativeDialog); free(FileName); HANDLE hFile = CreateFile(filePath.toStdWString().c_str(), GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { QMessageBox::critical(pParent,"Nanomite","Failed to create File!",QMessageBox::Ok,QMessageBox::Ok); free(pBuffer); return; } if(!WriteFile(hFile,pBuffer,Size,&BytesWrote,NULL)) QMessageBox::critical(pParent,"Nanomite","Failed to write to File!",QMessageBox::Ok,QMessageBox::Ok); free(pBuffer); CloseHandle(hFile); if(isProtectionChanged && !VirtualProtectEx(hProc,(LPVOID)BaseOffset,Size,OldProtection,&NewProtection)) QMessageBox::critical(pParent,"Nanomite","Failed to reprotect the Memory!",QMessageBox::Ok,QMessageBox::Ok); QMessageBox::information(pParent,"Nanomite","Memory Dump finished!",QMessageBox::Ok,QMessageBox::Ok); }
HRESULT ExecData(PVOID &pvPEData) { HRESULT hr = S_OK; PROCESS_INFORMATION pi; STARTUPINFO si = { sizeof si }; LPTSTR cmdLine = _tcsdup(TEXT("cmd")); CreateProcess(NULL, cmdLine, 0, 0, FALSE, CREATE_SUSPENDED, 0, 0, &si, &pi); CONTEXT context = { CONTEXT_INTEGER }; #ifndef DEFER_INJECT GetThreadContext(pi.hThread, &context); PVOID x; /* Dynamic linking call: */ HMODULE hMod = GetModuleHandle(L"ntdll.dll"); pfnZwUnmapViewOfSection pZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)GetProcAddress(hMod, "ZwUnmapViewOfSection"); hr = ReadProcessMemory(pi.hProcess, PCHAR(context.Ebx) + 8, &x, sizeof x, 0); if (FAILED(hr)) { /* This is bad, abort! */ return hr; } pZwUnmapViewOfSection(pi.hProcess, x); PIMAGE_NT_HEADERS nt = PIMAGE_NT_HEADERS( PCHAR(pvPEData) + PIMAGE_DOS_HEADER(pvPEData)->e_lfanew); DWORD dwLastError = ::GetLastError(); PVOID q = VirtualAllocEx(pi.hProcess, PVOID(nt->OptionalHeader.ImageBase), nt->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_WRITECOPY); WriteProcessMemory(pi.hProcess, q, pvPEData, nt->OptionalHeader.SizeOfHeaders, 0); PIMAGE_SECTION_HEADER sect = IMAGE_FIRST_SECTION(nt); for (ULONG i = 0; i < nt->FileHeader.NumberOfSections; i++) { WriteProcessMemory(pi.hProcess, PCHAR(q) + sect[i].VirtualAddress, PCHAR(pvPEData) + sect[i].PointerToRawData, sect[i].SizeOfRawData, 0); ULONG x; VirtualProtectEx(pi.hProcess, PCHAR(q) + sect[i].VirtualAddress, sect[i].Misc.VirtualSize, protect(sect[i].Characteristics), &x ); } WriteProcessMemory(pi.hProcess, PCHAR(context.Ebx) + 8, &q, sizeof q, 0); context.Eax = ULONG(q) + nt->OptionalHeader.AddressOfEntryPoint; #endif SetThreadContext(pi.hThread, &context); ResumeThread(pi.hThread); return hr; }
VOID HookInlineChecks(BOOL Patch) { int i; DWORD NewData; #ifndef ISXEQ DWORD tmp; DWORD oldperm; #endif int cmps[] = { __AC1 + 6 }; int cmps2[] = { __AC2, __AC3, __AC4, __AC5, __AC6, __AC7 }; int len2[] = { 6, 6, 6, 6, 6, 6 }; char NewData2[20]; static char OldData2[sizeof(cmps2)/sizeof(cmps2[0])][20]; if (Patch) { NewData = 0x7fffffff; for (i=0;i<sizeof(cmps)/sizeof(cmps[0]);i++) { #ifdef ISXEQ EzModify(cmps[i],&NewData,4); #else AddDetour(cmps[i], NULL, NULL, 4); VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps[i], 4, PAGE_EXECUTE_READWRITE, &oldperm); WriteProcessMemory(GetCurrentProcess(), (LPVOID)cmps[i], (LPVOID)&NewData, 4, NULL); VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps[i], 4, oldperm, &tmp); #endif } memset(NewData2, 0x90, 20); for (i=0;i<sizeof(cmps2)/sizeof(cmps2[0]);i++) { #ifdef ISXEQ EzModify(cmps2[i],NewData2,len2[i]); #else AddDetour(cmps2[i], NULL, NULL, len2[i]); VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps2[i], len2[i], PAGE_EXECUTE_READWRITE, &oldperm); memcpy((void *)OldData2[i], (void *)cmps2[i], len2[i]); WriteProcessMemory(GetCurrentProcess(), (LPVOID)cmps2[i], (LPVOID)NewData2, len2[i], NULL); VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps2[i], len2[i], oldperm, &tmp); #endif } } else { NewData = __AC1_Data; for (i=0;i<sizeof(cmps)/sizeof(cmps[0]);i++) { #ifdef ISXEQ EzUnModify(cmps[i]); #else VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps[i], 4, PAGE_EXECUTE_READWRITE, &oldperm); WriteProcessMemory(GetCurrentProcess(), (LPVOID)cmps[i], (LPVOID)&NewData, 4, NULL); VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps[i], 4, oldperm, &tmp); RemoveDetour(cmps[i]); #endif } for (i=0;i<sizeof(cmps2)/sizeof(cmps2[0]);i++) { #ifdef ISXEQ EzUnModify(cmps2[i]); #else VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps2[i], len2[i], PAGE_EXECUTE_READWRITE, &oldperm); WriteProcessMemory(GetCurrentProcess(), (LPVOID)cmps2[i], (LPVOID)OldData2[i], len2[i], NULL); VirtualProtectEx(GetCurrentProcess(), (LPVOID)cmps2[i], len2[i], oldperm, &tmp); RemoveDetour(cmps2[i]); #endif } } }
int Inject(HANDLE hProcess, const char *dll_dir, const char *dll_fn, const char *func_name, const void *param, const size_t param_size) { // String constants const char *injectError1Format = "Could not inject %s.\n" "\n" "If you're running Windows Vista or 7, make sure that you have installed the KB2533623 update:\n" "\n" "\thttp://support.microsoft.com/kb/2533623/"; const char *injectError2Format = "Could not load the function: %s"; //------------------------------------------// // Function variables. // //------------------------------------------// // Main DLL we will need to load HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); // Main functions we will need to import. // If [dll_fn] is absolute, LoadLibraryEx() with the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR // flag is used to guarantee that the injected DLL and its dependencies really // are only loaded from the given directory. Otherwise, LoadLibrary() may load // a possible other DLL with the same name from the directory of [hProcess]. FARPROC getcurrentdirectory = GetProcAddress(kernel32, "GetCurrentDirectoryW"); FARPROC setcurrentdirectory = GetProcAddress(kernel32, "SetCurrentDirectoryW"); FARPROC loadlibrary = GetProcAddress(kernel32, "LoadLibraryW"); FARPROC loadlibraryex = GetProcAddress(kernel32, "LoadLibraryExW"); FARPROC getprocaddress = GetProcAddress(kernel32, "GetProcAddress"); FARPROC exitthread = GetProcAddress(kernel32, "ExitThread"); FARPROC freelibraryandexitthread = GetProcAddress(kernel32, "FreeLibraryAndExitThread"); int have_kb2269637 = GetProcAddress(kernel32, "SetDefaultDllDirectories") != 0; // The workspace we will build the codecave on locally. // workspaceSize gets incremented with the final length of the error strings. size_t workspaceSize = 2048; LPBYTE workspace = NULL; LPBYTE p = NULL; // The memory in the process we write to LPBYTE codecaveAddress = NULL; // Strings we have to write into the process size_t injectError1_len = _scprintf(injectError1Format, dll_fn) + 1; size_t injectError2_len = _scprintf(injectError2Format, func_name) + 1; char *injectError0 = "Error"; VLA(char, injectError1, injectError1_len); VLA(char, injectError2, injectError2_len); char *user32Name = "user32.dll"; char *msgboxName = "MessageBoxW"; // Placeholder addresses to use the strings LPBYTE user32NameAddr = 0; LPBYTE user32Addr = 0; LPBYTE msgboxNameAddr = 0; LPBYTE msgboxAddr = 0; LPBYTE dllAddr = 0; LPBYTE dllDirAddr = 0; LPBYTE dllNameAddr = 0; LPBYTE funcNameAddr = 0; LPBYTE funcParamAddr = 0; LPBYTE error0Addr = 0; LPBYTE error1Addr = 0; LPBYTE error2Addr = 0; // Where the codecave execution should begin at LPTHREAD_START_ROUTINE codecaveExecAddr = 0; // Handle to the thread we create in the process HANDLE hThread = NULL; // Old protection on page we are writing to in the process and the bytes written DWORD oldProtect = 0; DWORD byte_ret = 0; // Return code of injection function DWORD injRet; //------------------------------------------// // Variable initialization. // //------------------------------------------// // This section will cause compiler warnings on VS8, // you can upgrade the functions or ignore them // Build error messages sprintf(injectError1, injectError1Format, dll_fn); sprintf(injectError2, injectError2Format, func_name); workspaceSize += ( strlen(dll_dir) + 1 + strlen(dll_fn) + 1 + strlen(func_name) + 1 + param_size + strlen(injectError1) + 1 + strlen(injectError2) + 1 ) * sizeof(wchar_t); // Create the workspace workspace = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, workspaceSize); p = workspace; // Allocate space for the codecave in the process codecaveAddress = (LPBYTE)VirtualAllocEx(hProcess, 0, workspaceSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Note there is no error checking done above for any functions that return a pointer/handle. // I could have added them, but it'd just add more messiness to the code and not provide any real // benefit. It's up to you though in your final code if you want it there or not. //------------------------------------------// // Data and string writing. // //------------------------------------------// // Reserve space for the user32 dll address, the MessageBox address, // and the address of the injected DLL's module. user32Addr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); msgboxAddr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); dllAddr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); // User32 Dll Name user32NameAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, user32Name); // MessageBox name msgboxNameAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, msgboxName, strlen(msgboxName) + 1); // Directory name if(dll_dir) { dllDirAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, dll_dir); } // Dll Name dllNameAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, dll_fn); // Function Name funcNameAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, func_name, strlen(func_name) + 1); // Function Parameter funcParamAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, param, param_size); // Error Message 1 error0Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError0); // Error Message 2 error1Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError1); // Error Message 3 error2Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError2); // Pad a few INT3s after string data is written for seperation *p++ = 0xCC; *p++ = 0xCC; *p++ = 0xCC; // Store where the codecave execution should begin codecaveExecAddr = (LPTHREAD_START_ROUTINE)((p - workspace) + codecaveAddress); // For debugging - infinite loop, attach onto process and step over //*p++ = 0xEB; //*p++ = 0xFE; //------------------------------------------// // User32.dll loading. // //------------------------------------------// // User32 DLL Loading // PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibrary *p++ = 0x68; p = ptrcpy_advance_dst(p, user32NameAddr); // MOV EAX, ADDRESS - Move the address of LoadLibrary into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, loadlibrary); // CALL EAX - Call LoadLibrary *p++ = 0xFF; *p++ = 0xD0; // MessageBox Loading // PUSH 0x000000 - Push the address of the function name to load *p++ = 0x68; p = ptrcpy_advance_dst(p, msgboxNameAddr); // Push EAX, module to use in GetProcAddress *p++ = 0x50; // MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, getprocaddress); // CALL EAX - Call GetProcAddress *p++ = 0xFF; *p++ = 0xD0; // MOV [ADDRESS], EAX - Save the address to our variable *p++ = 0xA3; p = ptrcpy_advance_dst(p, msgboxAddr); //------------------------------------------// // Injected dll loading. // //------------------------------------------// /* // This is the way the following assembly code would look like in C/C++ // In case the injected DLL depends on other DLLs, // we need to change the current directory to the one given as parameter if(dll_dir) { size_t cur_dir_len = GetCurrentDirectory(0, NULL) + 1; VLA(wchar_t, cur_dir, cur_dir_len); GetCurrentDirectory(cur_dir, cur_dir_len); SetCurrentDirectory(dll_dir); } // Load the injected DLL into this process HMODULE h = LoadLibraryEx(dll_fn, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); if(!h) { MessageBox(0, injectError1, "Error", MB_ICONERROR); ExitThread(1); } if(dll_dir) { SetCurrentDirectory(cur_dir); } // Get the address of the export function FARPROC p = GetProcAddress(h, func_name); if(!p) { MessageBox(0, injectError2, "Error", MB_ICONERROR); FreeLibraryAndExitThread(h, 2); } // So we do not need a function pointer interface __asm call p // Exit the thread so the loader continues ExitThread(0); */ // DLL Loading if(dllDirAddr) { // Registers: // ebp: Base stack frame // esi: GetCurrentDirectory / SetCurrentDirectory // ebx: Current directory of process (on stack) // ecx: byte length of string at ebx // mov ebp, esp - Save stack frame *p++ = 0x89; *p++ = 0xe5; // Get length for current directory // push 0 // push 0 *p++ = 0x6a; *p++ = 0x00; *p++ = 0x6a; *p++ = 0x00; // mov esi, GetCurrentDirectory *p++ = 0xbe; p = ptrcpy_advance_dst(p, getcurrentdirectory); // call esi *p++ = 0xFF; *p++ = 0xD6; /// Calculate byte size of directory buffer. /// Also do some poor man's DWORD boundary alignment /// in order to not f**k up the stack // mov ecx, eax // shl ecx, 1 // and ecx, fffffff8 // add ecx, 4 *p++ = 0x89; *p++ = 0xc1; *p++ = 0xd1; *p++ = 0xe1; *p++ = 0x83; *p++ = 0xe1; *p++ = 0xf8; *p++ = 0x83; *p++ = 0xc1; *p++ = 0x04; /// "Allocate" ecx bytes on stack and store buffer pointer to ebx // sub esp, ecx // mov ebx, esp *p++ = 0x29; *p++ = 0xcc; *p++ = 0x89; *p++ = 0xe3; /// Call GetCurrentDirectory // push ebx // push eax // call esi *p++ = 0x53; *p++ = 0x50; *p++ = 0xff; *p++ = 0xd6; /// PUSH 0x00000000 - Push the address of our directory *p++ = 0x68; p = ptrcpy_advance_dst(p, dllDirAddr); // mov esi, SetCurrentDirectory *p++ = 0xbe; p = ptrcpy_advance_dst(p, setcurrentdirectory); // call esi *p++ = 0xFF; *p++ = 0xD6; } if(PathIsRelativeA(dll_fn) || !have_kb2269637) { // PUSH 0x00 (dwFlags = 0) *p++ = 0x6a; *p++ = 0x00; } else { // PUSH 0x00000900 (dwFlags = LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32) *p++ = 0x68; *p++ = 0x00; *p++ = 0x09; *p++ = 0x00; *p++ = 0x00; } // PUSH 0x00 (hFile = NULL) *p++ = 0x6a; *p++ = 0x00; // PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibraryEx *p++ = 0x68; p = ptrcpy_advance_dst(p, dllNameAddr); // MOV EAX, ADDRESS - Move the address of LoadLibraryEx into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, loadlibraryex); // CALL EAX - Call LoadLibraryEx *p++ = 0xFF; *p++ = 0xD0; // mov edi, eax - Save return value *p++ = 0x89; *p++ = 0xc7; if(dllDirAddr) { /// Reset directory to the original one of the process // push ebx // call esi *p++ = 0x53; *p++ = 0xFF; *p++ = 0xD6; /// Reset stack frame // mov esp, ebp *p++ = 0x89; *p++ = 0xec; } // Error Checking // CMP EDI, 0 *p++ = 0x83; *p++ = 0xFF; *p++ = 0x00; // JNZ EIP + 0x1E to skip over eror code *p++ = 0x75; *p++ = 0x1E; // Error Code 1 // MessageBox // PUSH 0x10 (MB_ICONHAND) *p++ = 0x6A; *p++ = 0x10; // PUSH 0x000000 - Push the address of the MessageBox title *p++ = 0x68; p = ptrcpy_advance_dst(p, error0Addr); // PUSH 0x000000 - Push the address of the MessageBox message *p++ = 0x68; p = ptrcpy_advance_dst(p, error1Addr); // Push 0 *p++ = 0x6A; *p++ = 0x00; // MOV EAX, [ADDRESS] - Move the address of MessageBox into EAX *p++ = 0xA1; p = ptrcpy_advance_dst(p, msgboxAddr); // CALL EAX - Call MessageBoxW *p++ = 0xFF; *p++ = 0xD0; // ExitThread // PUSH 1 *p++ = 0x6A; *p++ = 0x01; // MOV EAX, ADDRESS - Move the address of ExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, exitthread); // CALL EAX - Call ExitThread *p++ = 0xFF; *p++ = 0xD0; // Now we have the address of the injected DLL, so save the handle // MOV [ADDRESS], EAX - Save the address to our variable *p++ = 0x89; *p++ = 0x3D; p = ptrcpy_advance_dst(p, dllAddr); // Load the initilize function from it // PUSH 0x000000 - Push the address of the function name to load *p++ = 0x68; p = ptrcpy_advance_dst(p, funcNameAddr); // Push EDI - module to use in GetProcAddress *p++ = 0x57; // MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, getprocaddress); // CALL EAX - Call GetProcAddress *p++ = 0xFF; *p++ = 0xD0; // Error Checking // CMP EAX, 0 *p++ = 0x83; *p++ = 0xF8; *p++ = 0x00; // JNZ EIP + 0x23 to skip eror code *p++ = 0x75; *p++ = 0x23; // Error Code 2 // MessageBox // PUSH 0x10 (MB_ICONHAND) *p++ = 0x6A; *p++ = 0x10; // PUSH 0x000000 - Push the address of the MessageBox title *p++ = 0x68; p = ptrcpy_advance_dst(p, error0Addr); // PUSH 0x000000 - Push the address of the MessageBox message *p++ = 0x68; p = ptrcpy_advance_dst(p, error2Addr); // Push 0 *p++ = 0x6A; *p++ = 0x00; // MOV EAX, ADDRESS - Move the address of MessageBox into EAX *p++ = 0xA1; p = ptrcpy_advance_dst(p, msgboxAddr); // CALL EAX - Call MessageBoxA *p++ = 0xFF; *p++ = 0xD0; // FreeLibraryAndExitThread // PUSH 2 *p++ = 0x6A; *p++ = 0x02; // PUSH 0x000000 - Push the injected DLL's module handle *p++ = 0x68; p = ptrcpy_advance_dst(p, dllAddr); // MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, freelibraryandexitthread); // CALL EAX - Call ExitThread function *p++ = 0xFF; *p++ = 0xD0; // PUSH 0x000000 - Push the address of the function parameter *p++ = 0x68; p = ptrcpy_advance_dst(p, funcParamAddr); // CALL EAX - Call [func_name] *p++ = 0xFF; *p++ = 0xD0; // If we get here, [func_name] has been called, // so it's time to close this thread and optionally unload the DLL. //------------------------------------------// // Exiting from the injected dll. // //------------------------------------------// // Call ExitThread to leave the DLL loaded #if 1 // PUSH 0 (exit code) *p++ = 0x6A; *p++ = 0x00; // MOV EAX, ADDRESS - Move the address of ExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, exitthread); // CALL EAX - Call ExitThread *p++ = 0xFF; *p++ = 0xD0; #endif // Call FreeLibraryAndExitThread to unload DLL #if 0 // Push 0 (exit code) *p++ = 0x6A; *p++ = 0x00; // PUSH [0x000000] - Push the address of the DLL module to unload *p++ = 0xFF; *p++ = 0x35; p = ptrcpy_advance_dst(p, dllAddr); // MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, freelibraryandexitthread); // CALL EAX - Call FreeLibraryAndExitThread *p++ = 0xFF; *p++ = 0xD0; #endif //------------------------------------------// // Code injection and cleanup. // //------------------------------------------// // Change page protection so we can write executable code VirtualProtectEx(hProcess, codecaveAddress, p - workspace, PAGE_EXECUTE_READWRITE, &oldProtect); // Write out the patch WriteProcessMemory(hProcess, codecaveAddress, workspace, p - workspace, &byte_ret); // Restore page protection VirtualProtectEx(hProcess, codecaveAddress, p - workspace, oldProtect, &oldProtect); // Make sure our changes are written right away FlushInstructionCache(hProcess, codecaveAddress, p - workspace); // Free the workspace memory HeapFree(GetProcessHeap(), 0, workspace); // Execute the thread now and wait for it to exit, note we execute where the code starts, and not the codecave start // (since we wrote strings at the start of the codecave) hThread = CreateRemoteThread(hProcess, NULL, 0, codecaveExecAddr, 0, 0, NULL); WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &injRet); CloseHandle(hThread); // Free the memory in the process that we allocated VirtualFreeEx(hProcess, codecaveAddress, 0, MEM_RELEASE); VLA_FREE(injectError1); VLA_FREE(injectError2); return injRet; }