//注入DLL //lpFilePath:DLL文件路径 //ulPID:进程ID //返回:true:注入成功,false:注入失败 bool process_injectDll(LPTSTR lpFilePath,ULONG ulPID) { //获得进程权限 HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION, FALSE, ulPID); //如果打开进程成功 if(hProcess) { DWORD dwSize,dwWritten; //进程路径大小 dwSize = sizeof(WCHAR)*lstrlenW(lpFilePath)+1; //在目标进程空间内,分配空间用于存放DLL文件路径 LPVOID lpBuffer=VirtualAllocEx(hProcess,NULL,dwSize,MEM_COMMIT,PAGE_READWRITE); //如果分配空间失败 if(lpBuffer==NULL) { CloseHandle(hProcess); return false; } //往刚分配的空间写入DLL文件路径 if(WriteProcessMemory(hProcess,lpBuffer,lpFilePath,dwSize,&dwWritten)) { //如果实际写入的数据不等于DLL路径大小 if(dwWritten!=dwSize) { //释放刚才分配的空间 VirtualFreeEx(hProcess,lpBuffer,dwSize,MEM_DECOMMIT); CloseHandle(hProcess); return false; } //获得kernel动态链接库句柄 HMODULE hModule=GetModuleHandle(L"Kernel32.dll"); //如果获得失败 if(hModule==NULL) { //释放刚才分配的空间 VirtualFreeEx(hProcess,lpBuffer,dwSize,MEM_DECOMMIT); CloseHandle(hProcess); return false; } //获得模块中函数的地址 LPTHREAD_START_ROUTINE pFunc=(LPTHREAD_START_ROUTINE)GetProcAddress(hModule,"LoadLibraryW"); //获取函数地址失败 if(pFunc==NULL) { //释放刚才分配的空间 VirtualFreeEx(hProcess,lpBuffer,dwSize,MEM_DECOMMIT); CloseHandle(hProcess); return false; } //在目标进程空间内创建线程 HANDLE hThread=CreateRemoteThread(hProcess,NULL,0,pFunc,lpBuffer,0,NULL); //无限等待目标线程的结束 WaitForSingleObject(hThread,INFINITE); //释放线程句柄 CloseHandle(hThread); //释放刚才分配的空间 VirtualFreeEx(hProcess,lpBuffer,dwSize,MEM_DECOMMIT); CloseHandle(hProcess); return true; } return false; } return false; }
ShellServiceWindow::ShellServiceWindow(HINSTANCE pInstance, bool pTopmost) { hInstance = pInstance; TaskbarCreated = RegisterWindowMessage(TEXT("TaskbarCreated")); hUser32 = LoadLibrary(TEXT("user32.dll")); if (hUser32) { ChangeWindowMessageFilter = (BOOL (WINAPI *)(UINT, DWORD))GetProcAddress(hUser32, "ChangeWindowMessageFilter"); if (ChangeWindowMessageFilter) { ChangeWindowMessageFilter(TaskbarCreated, MSGFLT_ADD); } } else ChangeWindowMessageFilter = NULL; HMODULE trayForward = LoadLibrary(TEXT("TrayForwarder.dll")); WCHAR trayForwardName[MAX_PATH]; bool trayInjected = false; DWORD trayProcessId = 0; LPVOID injectName = NULL; LPVOID loadLibraryWAddr = NULL; HANDLE proc = NULL; if (trayForward) { GetModuleFileNameW(trayForward, trayForwardName, MAX_PATH); FreeLibrary(trayForward); OutputDebugStringW(trayForwardName); GetWindowThreadProcessId(FindWindow(TEXT("Shell_TrayWnd"), NULL), &trayProcessId); if (trayProcessId) { proc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, trayProcessId); if (proc) { loadLibraryWAddr = reinterpret_cast<LPVOID>(GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), TEXT("LoadLibraryW"))); injectName = VirtualAllocEx(proc, NULL, (wcslen(trayForwardName)+1)*sizeof(WCHAR), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(proc, injectName, reinterpret_cast<LPVOID>(trayForwardName), (wcslen(trayForwardName)+1)*sizeof(WCHAR), NULL); trayInjected = true; } } } WNDCLASSEX wndClass; ZeroMemory(&wndClass, sizeof(wndClass)); wndClass.cbSize = sizeof(wndClass); wndClass.hInstance = hInstance; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = sizeof(this); if (trayInjected) { wndClass.lpszClassName = TEXT("HandlerShell_TrayWnd"); } else { wndClass.lpszClassName = TEXT("Shell_TrayWnd"); } RegisterClassEx(&wndClass); hTrayWnd = CreateWindowEx( WS_EX_TOOLWINDOW | (pTopmost ? WS_EX_TOPMOST : 0), wndClass.lpszClassName, NULL, WS_POPUP | WS_DISABLED | WS_OVERLAPPED | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); if (!trayInjected) { HWND tempParent = createChild(hTrayWnd, TEXT("TrayNotifyWnd")); createChild(tempParent, TEXT("TrayClockWClass")); createChild(createChild(tempParent, TEXT("SysPager")), TEXT("ToolbarWindow32"), TEXT("Notification Area")); createChild(createChild(tempParent, TEXT("SysPager")), TEXT("ToolbarWindow32"), TEXT("System Control Area")); } SetClassLongPtr(hTrayWnd, 0, (LONG_PTR)this); if (trayInjected) { m_forwarderModuleMsg = RegisterWindowMessage(TEXT("TRAYFORWARDER_MODULE")); WaitForSingleObject(CreateRemoteThread(proc, NULL, NULL, (LPTHREAD_START_ROUTINE)loadLibraryWAddr, injectName, NULL, NULL), INFINITE); } CloseHandle(proc); announceWindow(); }
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { // find the actual BO executable we should load char exePath[MAX_PATH]; GetModuleFileName(NULL, exePath, MAX_PATH); char* dirPointer = strrchr(exePath, '\\'); dirPointer[1] = '\0'; strcat(exePath, EXE_NAME); // check file existence if (GetFileAttributes(exePath) == INVALID_FILE_ATTRIBUTES) { MessageBox(NULL, "Could not find " EXE_NAME " in the directory this executable is located. Make sure it actually exists, and try again.", "secretSchemes", MB_ICONERROR | MB_OK); return 1; } // get DLL path char dllPath[MAX_PATH]; GetModuleFileName(NULL, dllPath, MAX_PATH); dirPointer = strrchr(dllPath, '\\'); dirPointer[1] = '\0'; strcat(dllPath, DLL_NAME); // check file existence if (GetFileAttributes(dllPath) == INVALID_FILE_ATTRIBUTES) { MessageBox(NULL, "Could not find " DLL_NAME " in the directory this executable is located. Make sure it actually exists, and try again.", "secretSchemes", MB_ICONERROR | MB_OK); return 1; } // hm, start the process (in a suspended state, obviously) STARTUPINFO startupInfo; memset(&startupInfo, 0, sizeof(startupInfo)); startupInfo.cb = sizeof(startupInfo); PROCESS_INFORMATION processInfo; memset(&processInfo, 0, sizeof(processInfo)); if (FAILED(CreateProcess(exePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo))) { MessageBox(NULL, "Could not start the process.", "secretSchemes", MB_ICONERROR | MB_OK); return 2; } // allocate room for DLL name in the process void* memory = VirtualAllocEx(processInfo.hProcess, NULL, sizeof(dllPath), MEM_COMMIT, PAGE_READWRITE); if (!memory) { MessageBox(NULL, "Could not allocate memory in the process.", "secretSchemes", MB_ICONERROR | MB_OK); return 3; } DWORD written; WriteProcessMemory(processInfo.hProcess, memory, dllPath, sizeof(dllPath), &written); // create a remote thread for LoadLibrary HMODULE kernel32 = GetModuleHandle("kernel32"); HANDLE thread = CreateRemoteThread(processInfo.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(kernel32, "LoadLibraryA"), memory, 0, NULL); if (!thread) { MessageBox(NULL, "Could not start remote thread.", "secretSchemes", MB_ICONERROR | MB_OK); return 3; } // wait for the thread to finish executing WaitForSingleObject(thread, INFINITE); // free remote memory VirtualFreeEx(processInfo.hProcess, memory, sizeof(dllPath), MEM_RELEASE); // clean up the handle CloseHandle(thread); // resume base process thread ResumeThread(processInfo.hThread); // and finally, clean everything else up CloseHandle(processInfo.hThread); CloseHandle(processInfo.hProcess); return 0; }
//////////////////////////////////////////////////////////////////////////////////////////// // MapRemoteModuleW //////////////////////////////////////////////////////////////////////////////////////////// BOOL MapRemoteModuleW( DWORD dwProcessId, LPCWSTR lpModulePath ) { BOOL bRet = FALSE; HANDLE hFile = 0; DWORD fileSize = 0; BYTE *dllBin = 0; PIMAGE_NT_HEADERS nt_header = 0; PIMAGE_DOS_HEADER dos_header = 0; HANDLE hProcess = 0; LPVOID lpModuleBase = 0; PIMAGE_IMPORT_DESCRIPTOR pImgImpDesc = 0; PIMAGE_BASE_RELOCATION pImgBaseReloc = 0; PIMAGE_TLS_DIRECTORY pImgTlsDir = 0; __try { // Get a handle for the target process. hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | // Required by Alpha PROCESS_CREATE_THREAD | // For CreateRemoteThread PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx PROCESS_VM_WRITE | // For WriteProcessMemory PROCESS_VM_READ, FALSE, dwProcessId); if(!hProcess) { PRINT_ERROR_MSGA("Could not get handle to process (PID: 0x%X).", dwProcessId); __leave; } hFile = CreateFileW( lpModulePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { PRINT_ERROR_MSGA("CreateFileW failed."); __leave; } if(GetFileAttributesW(lpModulePath) & FILE_ATTRIBUTE_COMPRESSED) { fileSize = GetCompressedFileSizeW(lpModulePath, NULL); } else { fileSize = GetFileSize(hFile, NULL); } if(fileSize == INVALID_FILE_SIZE) { PRINT_ERROR_MSGA("Could not get size of file."); __leave; } dllBin = (BYTE*)malloc(fileSize); { DWORD NumBytesRead = 0; if(!ReadFile(hFile, dllBin, fileSize, &NumBytesRead, FALSE)) { PRINT_ERROR_MSGA("ReadFile failed."); } } dos_header = (PIMAGE_DOS_HEADER)dllBin; // Make sure we got a valid DOS header if(dos_header->e_magic != IMAGE_DOS_SIGNATURE) { PRINT_ERROR_MSGA("Invalid DOS header."); __leave; } // Get the real PE header from the DOS stub header nt_header = (PIMAGE_NT_HEADERS)( (DWORD_PTR)dllBin + dos_header->e_lfanew); // Verify the PE header if(nt_header->Signature != IMAGE_NT_SIGNATURE) { PRINT_ERROR_MSGA("Invalid PE header."); __leave; } // Allocate space for the module in the remote process lpModuleBase = VirtualAllocEx( hProcess, NULL, nt_header->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!lpModuleBase) { PRINT_ERROR_MSGA("Could not allocate memory in remote process."); __leave; } // fix imports pImgImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA( nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, nt_header, (PBYTE)dllBin); if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) { if(!FixIAT(dwProcessId, hProcess, (PBYTE)dllBin, nt_header, pImgImpDesc)) { PRINT_ERROR_MSGA("@Fixing imports."); __leave; } } // fix relocs pImgBaseReloc = (PIMAGE_BASE_RELOCATION)GetPtrFromRVA( (DWORD)(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress), nt_header, (PBYTE)dllBin); if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { if(!FixRelocations(dllBin, lpModuleBase, nt_header, pImgBaseReloc)) { PRINT_ERROR_MSGA("@Fixing relocations."); __leave; } } // Write the PE header into the remote process's memory space { SIZE_T NumBytesWritten = 0; SIZE_T nSize = nt_header->FileHeader.SizeOfOptionalHeader + sizeof(nt_header->FileHeader) + sizeof(nt_header->Signature); if(!WriteProcessMemory(hProcess, lpModuleBase, dllBin, nSize, &NumBytesWritten) || NumBytesWritten != nSize) { PRINT_ERROR_MSGA("Could not write to memory in remote process."); __leave; } } // Map the sections into the remote process(they need to be aligned // along their virtual addresses) if(!MapSections(hProcess, lpModuleBase, dllBin, nt_header)) { PRINT_ERROR_MSGA("@Map sections."); __leave; } // call all tls callbacks // pImgTlsDir = (PIMAGE_TLS_DIRECTORY)GetPtrFromRVA( nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress, nt_header, (PBYTE)dllBin); if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) { if(!CallTlsInitializers(dllBin, nt_header, hProcess, (HMODULE)lpModuleBase, DLL_PROCESS_ATTACH, pImgTlsDir)) { PRINT_ERROR_MSGA("@Call TLS initializers."); __leave; } } // call entry point if(!RemoteDllMainCall( hProcess, (LPVOID)( (DWORD_PTR)lpModuleBase + nt_header->OptionalHeader.AddressOfEntryPoint), (HMODULE)lpModuleBase, 1, 0)) { PRINT_ERROR_MSGA("@Call DllMain."); __leave; } bRet = TRUE; wprintf(L"Successfully injected (%s | PID: %x):\n\n" L" AllocationBase:\t0x%p\n" L" EntryPoint:\t\t0x%p\n" L" SizeOfImage:\t\t0x%p\n" L" CheckSum:\t\t0x%p\n", lpModulePath, dwProcessId, lpModuleBase, (DWORD_PTR)lpModuleBase + nt_header->OptionalHeader.AddressOfEntryPoint, nt_header->OptionalHeader.SizeOfImage, nt_header->OptionalHeader.CheckSum); } __finally { if(hFile) { CloseHandle(hFile); } if(dllBin) { free(dllBin); } if(hProcess) { CloseHandle(hProcess); } } return bRet; }
int main(int argc, char *argv[]) { char *DRpath; HANDLE dll; int_func_t init_func; void_func_t take_over_func; int res = 0; BOOL debugbreak = FALSE; BOOL infinite = FALSE; BOOL keypress = FALSE; BOOL initialize_dr = TRUE; BOOL use_dont_resolve = FALSE; int arg_offs = 1; void *force_base = NULL; void *preferred_base = NULL; int call_offset = -1; BOOL find_safe_offset = FALSE; char *imagelist = NULL; /* Link user32.dll for easier running under dr */ do { if (argc > 1000) MessageBeep(0); } while (0); if (argc < 2) return usage(argv[0]); while (arg_offs < argc && argv[arg_offs][0] == '-') { if (strcmp(argv[arg_offs], "-help") == 0) { return help(argv[0]); } else if (strcmp(argv[arg_offs], "-debugbreak") == 0) { debugbreak = TRUE; arg_offs += 1; } else if (strcmp(argv[arg_offs], "-loop") == 0) { infinite = TRUE; arg_offs += 1; } else if (strcmp(argv[arg_offs], "-key") == 0) { keypress = TRUE; arg_offs += 1; } else if (strcmp(argv[arg_offs], "-no_init") == 0) { initialize_dr = FALSE; arg_offs += 1; } else if (strcmp(argv[arg_offs], "-call_to_offset") == 0) { int len; arg_offs += 1; if (argc - (arg_offs) < 1) return usage(argv[0]); len = sscanf(argv[arg_offs], "%08x", &call_offset); if (len != 1 || call_offset == -1) return usage(argv[0]); arg_offs += 1; } else if (strcmp(argv[arg_offs], "-find_safe_offset") == 0) { find_safe_offset = TRUE; arg_offs += 1; } else if (strcmp(argv[arg_offs], "-no_resolve") == 0) { use_dont_resolve = TRUE; arg_offs += 1; } else if (strcmp(argv[arg_offs], "-map") == 0) { void *addr = NULL; int len; arg_offs += 1; if (argc - (arg_offs+1) < 1) return usage(argv[0]); len = sscanf(argv[arg_offs+1], "%08x", &addr); if (len != 1 || addr == NULL) return usage(argv[0]); map_file(argv[arg_offs], addr, 0 /* mapped */); arg_offs += 2; } else if (strcmp(argv[arg_offs], "-base") == 0) { int len; arg_offs += 1; if (argc - (arg_offs) < 1) return usage(argv[0]); len = sscanf(argv[arg_offs], "%08x", &force_base); if (len != 1 || force_base == NULL) return usage(argv[0]); arg_offs += 1; } else if (strcmp(argv[arg_offs], "-preferred") == 0) { int len; arg_offs += 1; if (argc - (arg_offs) < 1) return usage(argv[0]); len = sscanf(argv[arg_offs], "%08x", &preferred_base); if (len != 1 || preferred_base == NULL) return usage(argv[0]); arg_offs += 1; } else if (strcmp(argv[arg_offs], "-imagelist") == 0) { arg_offs += 1; if (argc - (arg_offs) < 1) return usage(argv[0]); imagelist = argv[arg_offs]; arg_offs += 1; } else return usage(argv[0]); if (argc - arg_offs < (imagelist == NULL ? 1 : 0)) return usage(argv[0]); } if (imagelist != NULL) { FILE *f; int count = 0; char line[MAX_PATH]; if (_access(imagelist, 4/*read*/) == -1) { fprintf(stderr, "Cannot read %s\n", imagelist); return 1; } f = fopen(imagelist, "r"); if (f == NULL) { fprintf(stderr, "Failed to open %s\n", imagelist); return 1; } while (fgets(line, BUFFER_SIZE_ELEMENTS(line), f) != NULL) { size_t len = strlen(line) - 1; while (len > 0 && (line[len] == '\n' || line[len] == '\r')) { line[len] = '\0'; len--; } fprintf(stderr, "loading %s\n", line); if (map_file(line, NULL, 1/*image*/)) count++; else fprintf(stderr, " => FAILED\n", line); } fprintf(stderr, "loaded %d images successfully\n", count); fflush(stderr); } else { DRpath = argv[arg_offs]; if (force_base != NULL) { /* add load blocks at the expected base addresses */ void *base; if (preferred_base != NULL) base = preferred_base; else /* assume DR dll */ base = (void *)0x71000000; VirtualAllocEx(GetCurrentProcess(), base, 0x1000, MEM_RESERVE, PAGE_NOACCESS); if (preferred_base == NULL) { /* also do debug build base */ base = (void*)0x15000000; VirtualAllocEx(GetCurrentProcess(), base, 0x1000, MEM_RESERVE, PAGE_NOACCESS); } base = force_base; /* to ensure we fill all cavities we loop through */ while (base > (void*)0x10000) { base = (void*)((int)base - 0x10000); VirtualAllocEx(GetCurrentProcess(), base, 0x1000, MEM_RESERVE, PAGE_NOACCESS); } #if 0 map_file(DRpath, force_base, 1 /* image */); /* FIXME: note that the DLL will not be relocated! */ /* we can't really initialize */ #endif } if (use_dont_resolve) { dll = LoadLibraryExA(DRpath, NULL, DONT_RESOLVE_DLL_REFERENCES); } else { dll = LoadLibraryA(DRpath); } if (dll == NULL) { int err = GetLastError(); fprintf(stderr, "Error %d loading %s\n", err, DRpath); return 1; } if (initialize_dr) { init_func = (int_func_t) GetProcAddress(dll, "dynamorio_app_init"); take_over_func = (void_func_t) GetProcAddress(dll, "dynamorio_app_take_over"); if (init_func == NULL || take_over_func == NULL) { fprintf(stderr, "Error finding DR init routines\n"); res = 1; goto done; } res = (*init_func)(); /* FIXME: ASSERT(res) */ (*take_over_func)(); res = 0; } if (call_offset != -1) { unsigned char *call_location = (char *)dll+call_offset; if (find_safe_offset) { MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery(call_location, &mbi, sizeof(mbi)) != sizeof(mbi) || mbi.State == MEM_FREE || mbi.State == MEM_RESERVE) { fprintf(stderr, "Call offset invalid, leaving as is\n"); } else { /* find safe place to call, we just look for 0xc3 though could in theory * use other types of rets too */ unsigned char *test; for (test = call_location; test < (char *)mbi.BaseAddress+mbi.RegionSize; test++) { if (*test == 0xc3 /* plain ret */) { fprintf(stderr, "Found safe call target at offset 0x%tx\n", test - (char *)dll); call_location = test; break; } } if (call_location != test) { fprintf(stderr, "Unable to find safe call target\n"); } } } fprintf(stderr, "Calling base(%p) + offset(0x%tx) = %p\n", dll, call_location-(char *)dll, call_location); (*(int (*) ())(call_location))(); } } done: if (keypress) { fprintf(stderr, "press any key or attach a debugger...\n"); fflush(stderr); getchar(); } if (debugbreak) { __debugbreak(); } if (infinite) { while (1) Sleep(1); } return res; }
/*********************************************************************** * VirtualAlloc (KERNEL32.@) * * Reserves or commits a region of pages in virtual address space. * * PARAMS * addr [I] Address of region to reserve or commit. * size [I] Size of region. * type [I] Type of allocation. * protect [I] Type of access protection. * * RETURNS * Success: Base address of allocated region of pages. * Failure: NULL. */ LPVOID WINAPI VirtualAlloc( LPVOID addr, SIZE_T size, DWORD type, DWORD protect ) { return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect ); }
BOOL MapNewExecutableRegionInProcess( IN HANDLE TargetProcessHandle, IN HANDLE TargetThreadHandle, IN LPVOID NewExecutableRawImage) { PROCESS_INFORMATION BasicInformation; PIMAGE_SECTION_HEADER SectionHeader; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeader64; DWORD_PTR dwImageBase; NtUnmapViewOfSection pNtUnmapViewOfSection; LPVOID pImageBase; SIZE_T dwBytesWritten; SIZE_T dwBytesRead; int Count; PCONTEXT ThreadContext; BOOL Success = FALSE; DosHeader = (PIMAGE_DOS_HEADER)NewExecutableRawImage; if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE) { NtHeader64 = (PIMAGE_NT_HEADERS64)((UINTPTR)NewExecutableRawImage + DosHeader->e_lfanew); if (NtHeader64->Signature == IMAGE_NT_SIGNATURE) { RtlZeroMemory(&BasicInformation, sizeof(PROCESS_INFORMATION)); ThreadContext = (PCONTEXT)VirtualAlloc(NULL, sizeof(ThreadContext) + 4, MEM_COMMIT, PAGE_READWRITE); ThreadContext = (PCONTEXT)Align((UINTPTR)ThreadContext, 4); ThreadContext->ContextFlags = CONTEXT_FULL; if (GetThreadContext(TargetThreadHandle, ThreadContext)) //used to be LPCONTEXT(ThreadContext) { ReadProcessMemory(TargetProcessHandle, (LPCVOID)(ThreadContext->Rdx + 16), &dwImageBase, sizeof(DWORD_PTR), &dwBytesRead); pNtUnmapViewOfSection = (NtUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection"); if (pNtUnmapViewOfSection) pNtUnmapViewOfSection(TargetProcessHandle, (PVOID)dwImageBase); pImageBase = VirtualAllocEx(TargetProcessHandle, (LPVOID)NtHeader64->OptionalHeader.ImageBase, NtHeader64->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE); if (pImageBase) { WriteProcessMemory(TargetProcessHandle, pImageBase, (LPCVOID)NewExecutableRawImage, NtHeader64->OptionalHeader.SizeOfHeaders, &dwBytesWritten); SectionHeader = IMAGE_FIRST_SECTION(NtHeader64); for (Count = 0; Count < NtHeader64->FileHeader.NumberOfSections; Count++) { WriteProcessMemory(TargetProcessHandle, (LPVOID)((DWORD_PTR)pImageBase + SectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)NewExecutableRawImage + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, &dwBytesWritten); SectionHeader++; } WriteProcessMemory(TargetProcessHandle, (LPVOID)(ThreadContext->Rdx + 16), (LPVOID)&NtHeader64->OptionalHeader.ImageBase, sizeof(DWORD_PTR), &dwBytesWritten); ThreadContext->Rcx = (DWORD_PTR)pImageBase + NtHeader64->OptionalHeader.AddressOfEntryPoint; SetThreadContext(TargetThreadHandle, (LPCONTEXT)ThreadContext); ResumeThread(TargetThreadHandle); Success = TRUE; } else TerminateProcess(TargetProcessHandle, 0); //VirtualFree(ThreadContext, 0, MEM_RELEASE); } } } return Success; }
void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) { CONTEXT context; DWORD len; LPVOID mem; DWORD mem32; #define CODESIZE 20 BYTE code[CODESIZE+TSIZE(MAX_PATH)]; union { PBYTE pB; PDWORD pL; } ip; #ifdef IMPORT_WOW64 if (Wow64GetThreadContext == 0) { #define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc ) HMODULE hKernel = GetModuleHandle( L"kernel32.dll" ); GETPROC( Wow64GetThreadContext ); GETPROC( Wow64SetThreadContext ); // Assume if one is defined, so is the other. if (Wow64GetThreadContext == 0) { DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext." ); return; } } #endif len = TSIZE(lstrlen( dll ) + 1); if (len > TSIZE(MAX_PATH)) return; if (LLW32 == 0) { #ifdef _WIN64 STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); // ...ANSI32.dll\0 CopyMemory( code, dll, len - TSIZE(7) ); // ...ANSI-LLW.exe\0 CopyMemory( code + len - TSIZE(7), L"-LLW.exe", TSIZE(9) ); if (!CreateProcess( (LPCTSTR)code, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi )) { DEBUGSTR( 1, L"Failed to execute \"%s\".", (LPCTSTR)code ); return; } WaitForSingleObject( pi.hProcess, INFINITE ); GetExitCodeProcess( pi.hProcess, &LLW32 ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); #else LLW32 = (DWORD)GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "LoadLibraryW" ); #endif } CopyMemory( code + CODESIZE, dll, len ); len += CODESIZE; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext( ppi->hThread, &context ); mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); mem32 = (DWORD)(DWORD_PTR)mem; ip.pB = code; *ip.pB++ = 0x68; // push eip *ip.pL++ = context.Eip; *ip.pB++ = 0x9c; // pushf *ip.pB++ = 0x60; // pusha *ip.pB++ = 0x68; // push L"path\to\ANSI32.dll" *ip.pL++ = mem32 + CODESIZE; *ip.pB++ = 0xe8; // call LoadLibraryW *ip.pL++ = LLW32 - (mem32 + (DWORD)(ip.pB+4 - code)); *ip.pB++ = 0x61; // popa *ip.pB++ = 0x9d; // popf *ip.pB++ = 0xc3; // ret WriteProcessMemory( ppi->hProcess, mem, code, len, NULL ); FlushInstructionCache( ppi->hProcess, mem, len ); context.Eip = mem32; SetThreadContext( ppi->hThread, &context ); }
//#define LocalTest //#define ServerTest //#define Final void LaunchRose( char* ip, int port ) { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi; unsigned char myBuffer[ 0x200 ]; #if defined(ServerTest) sprintf( (char*)myBuffer, "TRose.exe @TRIGGER_SOFT@ _server 127.0.0.1 _port 29000"); #elif defined(LocalTest) sprintf( (char*)myBuffer, "TRose.exe @TRIGGER_SOFT@ _server 127.0.0.1 _port 29000"); #else sprintf( (char*)myBuffer, "TRose.exe @TRIGGER_SOFT@ _server %s _port %i", ip, port ); #endif if( CreateProcessA( 0, (char*)myBuffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ) ) { // Loaded OK char myDLLName[] = "AdventureRose.dll"; DWORD dwWritten = 0; LPVOID myDLLSpace = VirtualAllocEx( pi.hProcess, 0, sizeof( myDLLName ), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); WriteProcessMemory( pi.hProcess, myDLLSpace, myDLLName, sizeof( myDLLName ), &dwWritten ); if( dwWritten != sizeof( myDLLName ) ) { MessageBox( 0, "Failed to inject new game code", "WARNING", MB_ICONERROR | MB_OK ); TerminateProcess( pi.hProcess, 0 ); } else { { int tid = 0; HANDLE thread; CreateRemoteThread( pi.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)GetProcAddress( GetModuleHandleA("kernel32.dll"), "LoadLibraryA"), myDLLSpace, 0, (LPDWORD)&tid ); thread = OpenThread( THREAD_ALL_ACCESS, 0, tid ); WaitForSingleObject( thread, 5000 ); CloseHandle( thread ); } #if defined(ServerTest) || defined(Final) char myDLLName2[] = "RoseProtect.dll"; dwWritten =0; myDLLSpace = VirtualAllocEx( pi.hProcess, 0, sizeof( myDLLName2 ), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); WriteProcessMemory( pi.hProcess, myDLLSpace, myDLLName2, sizeof( myDLLName2 ), &dwWritten ); if( dwWritten != sizeof( myDLLName2 ) ) { MessageBox( 0, "Failed to inject protection code", "WARNING", MB_ICONERROR | MB_OK ); TerminateProcess( pi.hProcess, 0 ); } else { { int tid = 0; HANDLE thread; CreateRemoteThread( pi.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)GetProcAddress( GetModuleHandleA("kernel32.dll"), "LoadLibraryA"), myDLLSpace, 0, (LPDWORD)&tid ); thread = OpenThread( THREAD_ALL_ACCESS, 0, tid ); WaitForSingleObject( thread, 5000 ); CloseHandle( thread ); } #endif ResumeThread( pi.hThread ); #if defined(ServerTest) || defined(Final) } #endif } } else { MessageBox( 0, "Could not find/load TRose.exe", "WARNING", MB_ICONERROR | MB_OK ); } }
BOOL MapNewExecutableRegionInProcess( IN HANDLE TargetProcessHandle, IN HANDLE TargetThreadHandle, IN LPVOID NewExecutableRawImage) { PROCESS_BASIC_INFORMATION BasicInformation; PIMAGE_SECTION_HEADER SectionHeader; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeader; PMINI_PEB ProcessPeb; NTSTATUS (NTAPI *NtUnmapViewOfSection)(HANDLE, LPVOID) = NULL; NTSTATUS (NTAPI *NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG) = NULL; NTSTATUS Status; CONTEXT ThreadContext; LPVOID OldEntryPoint = NULL; LPVOID TargetImageBase = NULL; ULONG SectionIndex = 0; ULONG SizeOfBasicInformation; BOOL Success = FALSE; // // Error checking? Bah. // DosHeader = (PIMAGE_DOS_HEADER)NewExecutableRawImage; NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)NewExecutableRawImage + DosHeader->e_lfanew); do { // // Get the old entry point address by inspecting eax of the current // thread (which should be BaseProcessStart). Eax holds the address // of the entry point for the executable when the process is created // suspended. // ZeroMemory( &ThreadContext, sizeof(ThreadContext)); ThreadContext.ContextFlags = CONTEXT_INTEGER; if (!GetThreadContext( TargetThreadHandle, &ThreadContext)) { break; } OldEntryPoint = (LPVOID) NtHeader->OptionalHeader.ImageBase; // // Unmap the old executable region in the child process to avoid // conflicts // NtUnmapViewOfSection = (NTSTATUS (NTAPI *)(HANDLE, LPVOID))GetProcAddress( GetModuleHandle( TEXT("NTDLL")), "NtUnmapViewOfSection"); NtUnmapViewOfSection(TargetProcessHandle, OldEntryPoint); // // Change the entry point address to the new executable's entry point // ThreadContext.Eax = NtHeader->OptionalHeader.AddressOfEntryPoint + NtHeader->OptionalHeader.ImageBase; if (!SetThreadContext( TargetThreadHandle, &ThreadContext)) break; // // Allocate storage for the new executable in the child process // if (!(TargetImageBase = VirtualAllocEx( TargetProcessHandle, (LPVOID)NtHeader->OptionalHeader.ImageBase, NtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE))) break; // // Update the executable's image base address in the PEB... // NtQueryInformationProcess = (NTSTATUS (NTAPI *)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG))GetProcAddress( GetModuleHandle( TEXT("NTDLL")), "NtQueryInformationProcess"); if (NtQueryInformationProcess( TargetProcessHandle, ProcessBasicInformation, &BasicInformation, sizeof(BasicInformation), &SizeOfBasicInformation) != ERROR_SUCCESS) break; ProcessPeb = BasicInformation.PebBaseAddress; if (!WriteProcessMemory( TargetProcessHandle, (LPVOID)&ProcessPeb->ImageBaseAddress, (LPVOID)&NtHeader->OptionalHeader.ImageBase, sizeof(LPVOID), NULL)) break; // // Copy the image headers and all of the section contents // if (!WriteProcessMemory( TargetProcessHandle, TargetImageBase, NewExecutableRawImage, NtHeader->OptionalHeader.SizeOfHeaders, NULL)) break; Success = TRUE; for (SectionIndex = 0, SectionHeader = IMAGE_FIRST_SECTION(NtHeader); SectionIndex < NtHeader->FileHeader.NumberOfSections; SectionIndex++) { // // Skip uninitialized data // if ((!SectionHeader[SectionIndex].SizeOfRawData) || (SectionHeader[SectionIndex].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) continue; if (!WriteProcessMemory( TargetProcessHandle, (LPVOID)((PCHAR)TargetImageBase + SectionHeader[SectionIndex].VirtualAddress), (LPVOID)((PCHAR)NewExecutableRawImage + SectionHeader[SectionIndex].PointerToRawData), SectionHeader[SectionIndex].SizeOfRawData, NULL)) { Success = FALSE; break; } } } while (0); return Success; }
int APIENTRY WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { // data HANDLE hProc; DWORD dwPID; HANDLE hThread; PBYTE pData; PBYTE pCode; InjData injData; // prepare data to be injected injData.fnCreateProcess = &CreateProcessA; injData.fnGetAsyncKeyState = &GetAsyncKeyState; injData.fnSleep = &Sleep; injData.fnMessageBox = &MessageBoxA; strcpy( injData.szCmd, PROCESS_COMMAND ); memset( &injData.si, 0, sizeof( injData.si ) ); injData.si.cb = sizeof( injData.si ); memset( &injData.pi, 0, sizeof( injData.pi ) ); // Step 1: Find and gain access to process DWORD nProcesses; DWORD processIDs[MAX_PROCESS_IDS]; EnumProcesses( processIDs, sizeof( processIDs ), &nProcesses ); nProcesses /= sizeof( DWORD ); for ( DWORD i = 0; i < nProcesses; ++i ) { hProc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, processIDs[i] ); if ( hProc ) { char szProcName[MAX_PATH]; GetProcessImageFileNameA( hProc, szProcName, sizeof( szProcName ) ); if ( std::string( szProcName ).find( PROCESS_NAME ) != std::string::npos ) { dwPID = i; break; } } } // Step 2: Allocate block of memory for data in remote process pData = (PBYTE)VirtualAllocEx( hProc, NULL, DATA_CHUNK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); ASSERT( pData != NULL, "allocating memory for data failed =(" ); // Step 3: Copy data to remote process ASSERT( WriteProcessMemory( hProc, pData, &injData, sizeof( InjData ), NULL ), "copying data to memory failed =(" ); // Step 4: Allocate block of memory for code in remote process pCode = (PBYTE)VirtualAllocEx( hProc, NULL, CODE_CHUNK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); ASSERT( pCode != NULL, "allocating memory for code failed =(" ); // Step 5: Copy function to remote process #pragma warning( disable : 4311 ) ASSERT( WriteProcessMemory( hProc, pCode, &ThreadFunc, (SIZE_T)&DummyFunc - (SIZE_T)&ThreadFunc, NULL ), "copying function to memory failed =(" ); #pragma warning( default : 4311 ) // Step 6: Create remote thread! hThread = CreateRemoteThread( hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, NULL ); ASSERT( hThread != NULL, "creating thread failed =(" ) return 0; }
void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) { CONTEXT context; DWORD len; LPVOID mem; DWORD64 LLW; union { PBYTE pB; PDWORD64 pL; } ip; #define CODESIZE 92 static BYTE code[CODESIZE+MAX_PATH*sizeof(TCHAR)] = { 0,0,0,0,0,0,0,0, // original rip 0,0,0,0,0,0,0,0, // LoadLibraryW 0x9C, // pushfq 0x50, // push rax 0x51, // push rcx 0x52, // push rdx 0x53, // push rbx 0x55, // push rbp 0x56, // push rsi 0x57, // push rdi 0x41,0x50, // push r8 0x41,0x51, // push r9 0x41,0x52, // push r10 0x41,0x53, // push r11 0x41,0x54, // push r12 0x41,0x55, // push r13 0x41,0x56, // push r14 0x41,0x57, // push r15 0x48,0x83,0xEC,0x28, // sub rsp, 40 0x48,0x8D,0x0D,41,0,0,0, // lea ecx, L"path\to\ANSI64.dll" 0xFF,0x15,-49,-1,-1,-1, // call LoadLibraryW 0x48,0x83,0xC4,0x28, // add rsp, 40 0x41,0x5F, // pop r15 0x41,0x5E, // pop r14 0x41,0x5D, // pop r13 0x41,0x5C, // pop r12 0x41,0x5B, // pop r11 0x41,0x5A, // pop r10 0x41,0x59, // pop r9 0x41,0x58, // pop r8 0x5F, // pop rdi 0x5E, // pop rsi 0x5D, // pop rbp 0x5B, // pop rbx 0x5A, // pop rdx 0x59, // pop rcx 0x58, // pop rax 0x9D, // popfq 0xFF,0x25,-91,-1,-1,-1, // jmp original Rip 0, // dword alignment for LLW, fwiw }; len = lstrlen( dll ) + 1; if (len > MAX_PATH) return; len *= sizeof(TCHAR); CopyMemory( code + CODESIZE, dll, len ); len += CODESIZE; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext( ppi->hThread, &context ); mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); LLW = (DWORD64)LoadLibraryW; ip.pB = code; *ip.pL++ = context.Rip; *ip.pL++ = LLW; WriteProcessMemory( ppi->hProcess, mem, code, len, NULL ); FlushInstructionCache( ppi->hProcess, mem, len ); context.Rip = (DWORD64)mem + 16; SetThreadContext( ppi->hThread, &context ); }
EASYHOOK_NT_EXPORT RhInjectLibrary( ULONG InTargetPID, ULONG InWakeUpTID, ULONG InInjectionOptions, WCHAR* InLibraryPath_x86, WCHAR* InLibraryPath_x64, PVOID InPassThruBuffer, ULONG InPassThruSize) { /* Description: Injects a library into the target process. This is a very stable operation. The problem so far is, that only the NET layer will support injection through WOW64 boundaries and into other terminal sessions. It is quite complex to realize with unmanaged code and that's why it is not supported! If you really need this feature I highly recommend to at least look at C++.NET because using the managed injection can speed up your development progress about orders of magnitudes. I know by experience that writing the required multi-process injection code in any unmanaged language is a rather daunting task! Parameters: - InTargetPID The process in which the library should be injected. - InWakeUpTID If the target process was created suspended (RhCreateAndInject), then this parameter should be set to the main thread ID of the target. You may later resume the process from within the injected library by calling RhWakeUpProcess(). If the process is already running, you should specify zero. - InInjectionOptions All flags can be combined. EASYHOOK_INJECT_DEFAULT: No special behavior. The given libraries are expected to be unmanaged DLLs. Further they should export an entry point named "NativeInjectionEntryPoint" (in case of 64-bit) and "_NativeInjectionEntryPoint@4" (in case of 32-bit). The expected entry point signature is REMOTE_ENTRY_POINT. EASYHOOK_INJECT_MANAGED: The given user library is a NET assembly. Further they should export a class named "EasyHook.InjectionLoader" with a static method named "Main". The signature of this method is expected to be "int (String)". Please refer to the managed injection loader of EasyHook for more information about writing such managed entry points. EASYHOOK_INJECT_STEALTH: Uses the experimental stealth thread creation. If it fails you may try it with default settings. EASYHOOK_INJECT_HEART_BEAT: Is only used internally to workaround the managed process creation bug. For curiosity, NET seems to hijack our remote thread if a managed process is created suspended. It doesn't do anything with the suspended main thread, - InLibraryPath_x86 A relative or absolute path to the 32-bit version of the user library being injected. If you don't want to inject into 32-Bit processes, you may set this parameter to NULL. - InLibraryPath_x64 A relative or absolute path to the 64-bit version of the user library being injected. If you don't want to inject into 64-Bit processes, you may set this parameter to NULL. - InPassThruBuffer An optional buffer containg data to be passed to the injection entry point. Such data is available in both, the managed and unmanaged user library entry points. Set to NULL if no used. - InPassThruSize Specifies the size in bytes of the pass thru data. If "InPassThruBuffer" is NULL, this parameter shall also be zero. Returns: */ HANDLE hProc = NULL; HANDLE hRemoteThread = NULL; HANDLE hSignal = NULL; UCHAR* RemoteInjectCode = NULL; LPREMOTE_INFO Info = NULL; LPREMOTE_INFO RemoteInfo = NULL; ULONG RemoteInfoSize = 0; BYTE* Offset = 0; ULONG CodeSize; BOOL Is64BitTarget; NTSTATUS NtStatus; LONGLONG Diff; HANDLE Handles[2]; ULONG UserLibrarySize; ULONG PATHSize; ULONG EasyHookPathSize; ULONG EasyHookEntrySize; ULONG Code; SIZE_T BytesWritten; WCHAR UserLibrary[MAX_PATH+1]; WCHAR PATH[MAX_PATH + 1]; WCHAR EasyHookPath[MAX_PATH + 1]; #ifdef _M_X64 CHAR* EasyHookEntry = "HookCompleteInjection"; #else CHAR* EasyHookEntry = "_HookCompleteInjection@4"; #endif // validate parameters if(InPassThruSize > MAX_PASSTHRU_SIZE) THROW(STATUS_INVALID_PARAMETER_7, L"The given pass thru buffer is too large."); if(InPassThruBuffer != NULL) { if(!IsValidPointer(InPassThruBuffer, InPassThruSize)) THROW(STATUS_INVALID_PARAMETER_6, L"The given pass thru buffer is invalid."); } else if(InPassThruSize != 0) THROW(STATUS_INVALID_PARAMETER_7, L"If no pass thru buffer is specified, the pass thru length also has to be zero."); if(InTargetPID == GetCurrentProcessId()) THROW(STATUS_NOT_SUPPORTED, L"For stability reasons it is not supported to inject into the calling process."); // open target process if((hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, InTargetPID)) == NULL) { if(GetLastError() == ERROR_ACCESS_DENIED) THROW(STATUS_ACCESS_DENIED, L"Unable to open target process. Consider using a system service.") else THROW(STATUS_NOT_FOUND, L"The given target process does not exist!"); } /* Check bitness... After this we can assume hooking a target that is running in the same WOW64 level. */ #ifdef _M_X64 FORCE(RhIsX64Process(InTargetPID, &Is64BitTarget)); if(!Is64BitTarget) THROW(STATUS_WOW_ASSERTION, L"It is not supported to directly hook through the WOW64 barrier."); if(!GetFullPathNameW(InLibraryPath_x64, MAX_PATH, UserLibrary, NULL)) THROW(STATUS_INVALID_PARAMETER_5, L"Unable to get full path to the given 64-bit library."); #else FORCE(RhIsX64Process(InTargetPID, &Is64BitTarget)); if(Is64BitTarget) THROW(STATUS_WOW_ASSERTION, L"It is not supported to directly hook through the WOW64 barrier."); if(!GetFullPathNameW(InLibraryPath_x86, MAX_PATH, UserLibrary, NULL)) THROW(STATUS_INVALID_PARAMETER_4, L"Unable to get full path to the given 32-bit library."); #endif /* Validate library path... */ if(!RtlFileExists(UserLibrary)) { #ifdef _M_X64 THROW(STATUS_INVALID_PARAMETER_5, L"The given 64-Bit library does not exist!"); #else THROW(STATUS_INVALID_PARAMETER_4, L"The given 32-Bit library does not exist!"); #endif } // import strings... RtlGetWorkingDirectory(PATH, MAX_PATH - 1); RtlGetCurrentModulePath(EasyHookPath, MAX_PATH); // allocate remote information block EasyHookPathSize = (RtlUnicodeLength(EasyHookPath) + 1) * 2; EasyHookEntrySize = (RtlAnsiLength(EasyHookEntry) + 1); PATHSize = (RtlUnicodeLength(PATH) + 1 + 1) * 2; UserLibrarySize = (RtlUnicodeLength(UserLibrary) + 1 + 1) * 2; PATH[PATHSize / 2 - 2] = ';'; PATH[PATHSize / 2 - 1] = 0; RemoteInfoSize = EasyHookPathSize + EasyHookEntrySize + PATHSize + InPassThruSize + UserLibrarySize; RemoteInfoSize += sizeof(REMOTE_INFO); if((Info = (LPREMOTE_INFO)RtlAllocateMemory(TRUE, RemoteInfoSize)) == NULL) THROW(STATUS_NO_MEMORY, L"Unable to allocate memory in current process."); Info->LoadLibraryW = (PVOID)GetProcAddress(hKernel32, "LoadLibraryW"); Info->FreeLibrary = (PVOID)GetProcAddress(hKernel32, "FreeLibrary"); Info->GetProcAddress = (PVOID)GetProcAddress(hKernel32, "GetProcAddress"); Info->VirtualFree = (PVOID)GetProcAddress(hKernel32, "VirtualFree"); Info->VirtualProtect = (PVOID)GetProcAddress(hKernel32, "VirtualProtect"); Info->ExitThread = (PVOID)GetProcAddress(hKernel32, "ExitThread"); Info->GetLastError = (PVOID)GetProcAddress(hKernel32, "GetLastError"); Info->WakeUpThreadID = InWakeUpTID; Info->IsManaged = InInjectionOptions & EASYHOOK_INJECT_MANAGED; // allocate memory in target process CodeSize = GetInjectionSize(); if((RemoteInjectCode = (BYTE*)VirtualAllocEx(hProc, NULL, CodeSize + RemoteInfoSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL) THROW(STATUS_NO_MEMORY, L"Unable to allocate memory in target process."); // save strings Offset = (BYTE*)(Info + 1); Info->EasyHookEntry = (char*)Offset; Info->EasyHookPath = (wchar_t*)(Offset += EasyHookEntrySize); Info->PATH = (wchar_t*)(Offset += EasyHookPathSize); Info->UserData = (BYTE*)(Offset += PATHSize); Info->UserLibrary = (WCHAR*)(Offset += InPassThruSize); Info->Size = RemoteInfoSize; Info->HostProcess = GetCurrentProcessId(); Info->UserDataSize = 0; Offset += UserLibrarySize; if((ULONG)(Offset - ((BYTE*)Info)) > Info->Size) THROW(STATUS_BUFFER_OVERFLOW, L"A buffer overflow in internal memory was detected."); RtlCopyMemory(Info->EasyHookPath, EasyHookPath, EasyHookPathSize); RtlCopyMemory(Info->PATH, PATH, PATHSize); RtlCopyMemory(Info->EasyHookEntry, EasyHookEntry, EasyHookEntrySize); RtlCopyMemory(Info->UserLibrary, UserLibrary, UserLibrarySize); if(InPassThruBuffer != NULL) { RtlCopyMemory(Info->UserData, InPassThruBuffer, InPassThruSize); Info->UserDataSize = InPassThruSize; } // copy code into target process if(!WriteProcessMemory(hProc, RemoteInjectCode, GetInjectionPtr(), CodeSize, &BytesWritten) || (BytesWritten != CodeSize)) THROW(STATUS_INTERNAL_ERROR, L"Unable to write into target process memory."); // create and export signal event> if((hSignal = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) THROW(STATUS_INSUFFICIENT_RESOURCES, L"Unable to create event."); // Possible resource leck: the remote handles cannt be closed here if an error occurs if(!DuplicateHandle(GetCurrentProcess(), hSignal, hProc, &Info->hRemoteSignal, EVENT_ALL_ACCESS, FALSE, 0)) THROW(STATUS_INTERNAL_ERROR, L"Failed to duplicate remote event."); // relocate remote information RemoteInfo = (LPREMOTE_INFO)(RemoteInjectCode + CodeSize); Diff = ((BYTE*)RemoteInfo - (BYTE*)Info); Info->EasyHookEntry = (char*)(((BYTE*)Info->EasyHookEntry) + Diff); Info->EasyHookPath = (wchar_t*)(((BYTE*)Info->EasyHookPath) + Diff); Info->PATH = (wchar_t*)(((BYTE*)Info->PATH) + Diff); Info->UserLibrary = (wchar_t*)(((BYTE*)Info->UserLibrary) + Diff); if(Info->UserData != NULL) Info->UserData = (BYTE*)(((BYTE*)Info->UserData) + Diff); Info->RemoteEntryPoint = RemoteInjectCode; if(!WriteProcessMemory(hProc, RemoteInfo, Info, RemoteInfoSize, &BytesWritten) || (BytesWritten != RemoteInfoSize)) THROW(STATUS_INTERNAL_ERROR, L"Unable to write into target process memory."); if((InInjectionOptions & EASYHOOK_INJECT_STEALTH) != 0) { FORCE(RhCreateStealthRemoteThread(InTargetPID, (LPTHREAD_START_ROUTINE)RemoteInjectCode, RemoteInfo, &hRemoteThread)); } else { if(!RTL_SUCCESS(NtCreateThreadEx(hProc, (LPTHREAD_START_ROUTINE)RemoteInjectCode, RemoteInfo, FALSE, &hRemoteThread))) { // create remote thread and wait for injection completion if((hRemoteThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)RemoteInjectCode, RemoteInfo, 0, NULL)) == NULL) THROW(STATUS_ACCESS_DENIED, L"Unable to create remote thread."); } } /* * The assembler codes are designed to let us derive extensive error information... */ Handles[1] = hSignal; Handles[0] = hRemoteThread; Code = WaitForMultipleObjects(2, Handles, FALSE, INFINITE); if(Code == WAIT_OBJECT_0) { // parse error code GetExitCodeThread(hRemoteThread, &Code); SetLastError(Code & 0x0FFFFFFF); switch(Code & 0xF0000000) { case 0x10000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to find internal entry point."); case 0x20000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to make stack executable."); case 0x30000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to release injected library."); case 0x40000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to find EasyHook library in target process context."); case 0xF0000000: // error in C++ injection completion { switch(Code & 0xFF) { #ifdef _M_X64 case 20: THROW(STATUS_INVALID_PARAMETER_5, L"Unable to load the given 64-bit library into target process."); case 21: THROW(STATUS_INVALID_PARAMETER_5, L"Unable to find the required native entry point in the given 64-bit library."); case 12: THROW(STATUS_INVALID_PARAMETER_5, L"Unable to find the required managed entry point in the given 64-bit library."); #else case 20: THROW(STATUS_INVALID_PARAMETER_4, L"Unable to load the given 32-bit library into target process."); case 21: THROW(STATUS_INVALID_PARAMETER_4, L"Unable to find the required native entry point in the given 32-bit library."); case 12: THROW(STATUS_INVALID_PARAMETER_4, L"Unable to find the required managed entry point in the given 32-bit library."); #endif case 13: THROW(STATUS_DLL_INIT_FAILED, L"The user defined managed entry point failed in the target process. Make sure that EasyHook is registered in the GAC. Refer to event logs for more information."); case 1: THROW(STATUS_INTERNAL_ERROR, L"Unable to allocate memory in target process."); case 2: THROW(STATUS_INTERNAL_ERROR, L"Unable to adjust target's PATH variable."); case 10: THROW(STATUS_INTERNAL_ERROR, L"Unable to load 'mscoree.dll' into target process."); case 11: THROW(STATUS_INTERNAL_ERROR, L"Unable to bind NET Runtime to target process."); case 22: THROW(STATUS_INTERNAL_ERROR, L"Unable to signal remote event."); default: THROW(STATUS_INTERNAL_ERROR, L"Unknown error in injected C++ completion routine."); } }break; case 0: THROW(STATUS_INTERNAL_ERROR, L"C++ completion routine has returned success but didn't raise the remote event."); default: THROW(STATUS_INTERNAL_ERROR, L"Unknown error in injected assembler code."); } } else if(Code != WAIT_OBJECT_0 + 1) THROW(STATUS_INTERNAL_ERROR, L"Unable to wait for injection completion due to timeout. "); RETURN; THROW_OUTRO: FINALLY_OUTRO: { // release resources if(hProc != NULL) CloseHandle(hProc); if(Info != NULL) RtlFreeMemory(Info); if(hRemoteThread != NULL) CloseHandle(hRemoteThread); if(hSignal != NULL) CloseHandle(hSignal); return NtStatus; } }
bool InjectDLL(DWORD processID, const char* dllLocation) { // gets a module handler which loaded by the process which // should be injected HMODULE hModule = GetModuleHandle("kernel32.dll"); if (!hModule) { printf("ERROR: Can't get 'kernel32.dll' handle, "); printf("ErrorCode: %u\n", GetLastError()); return false; } // gets the address of an exported function which can load DLLs FARPROC loadLibraryAddress = GetProcAddress(hModule, "LoadLibraryA"); if (!loadLibraryAddress) { printf("ERROR: Can't get function 'LoadLibraryA' address, "); printf("ErrorCode: %u\n", GetLastError()); return false; } // opens the process which should be injected HANDLE hProcess = OpenClientProcess(processID); if (!hProcess) { printf("Process [%u] '%s' open is failed.\n", processID, lookingProcessName); return false; } printf("\nProcess [%u] '%s' is opened.\n", processID, lookingProcessName); // gets the build number WORD buildNumber = GetBuildNumberFromProcess(hProcess); // error occured if (!buildNumber) { printf("Can't determine build number.\n"); CloseHandle(hProcess); return false; } printf("Detected build number: %hu\n", buildNumber); // checks this build is supported or not HookEntry hookEntry; if (!GetOffsets(NULL, buildNumber, &hookEntry)) { printf("ERROR: This build number is not supported.\n"); CloseHandle(hProcess); return false; } // allocates memory for the DLL location string LPVOID allocatedMemoryAddress = VirtualAllocEx(hProcess, NULL, strlen(dllLocation), MEM_COMMIT, PAGE_READWRITE); if (!allocatedMemoryAddress) { printf("ERROR: Virtual memory allocation is failed, "); printf("ErrorCode: %u.\n", GetLastError()); CloseHandle(hProcess); return false; } // writes the DLL location string to the process // so this is the parameter which will be passed to LoadLibraryA if (!WriteProcessMemory(hProcess, allocatedMemoryAddress, dllLocation, strlen(dllLocation), NULL)) { printf("ERROR: Process memory writing is failed, "); printf("ErrorCode: %u\n", GetLastError()); VirtualFreeEx(hProcess, allocatedMemoryAddress, 0, MEM_RELEASE); CloseHandle(hProcess); return false; } // creates a thread that runs in the virtual address space of // the process which should be injected and gives the // parameter (allocatedMemoryAddress) to LoadLibraryA(loadLibraryAddress) HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddress, allocatedMemoryAddress, 0, NULL); if (!hRemoteThread) { printf("ERROR: Remote thread creation is failed, "); printf("ErrorCode: %u\n", GetLastError()); VirtualFreeEx(hProcess, allocatedMemoryAddress, 0, MEM_RELEASE); CloseHandle(hProcess); return false; } // waits until the DLL's main function returns WaitForSingleObject(hRemoteThread, INFINITE); // frees resources VirtualFreeEx(hProcess, allocatedMemoryAddress, 0, MEM_RELEASE); CloseHandle(hRemoteThread); CloseHandle(hProcess); return true; }
// runs position independent code in remote process BOOL inject (DWORD dwId, LPVOID pPIC, SIZE_T dwCode, LPVOID lpParam, SIZE_T dwParam, DWORD dbg) { HANDLE hProc, hThread; BOOL bStatus=FALSE, bRemoteWow64, bLocalWow64; LPVOID pCode=NULL, pData=NULL; SIZE_T written; DWORD old, idx, ec; pCreateRemoteThread64 CreateRemoteThread64=NULL; // try open the process printf(" [ opening process id %lu\n", dwId); hProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, dwId); if (hProc != NULL) { // allocate memory there printf(" [ allocating %lu bytes of RW memory in process for code\n", dwCode); pCode=VirtualAllocEx (hProc, 0, dwCode, MEM_COMMIT, PAGE_READWRITE); if (pCode != NULL) { // write the code printf(" [ writing %lu bytes of code to 0x%p\n", dwCode, pCode); bStatus=WriteProcessMemory (hProc, pCode, pPIC, dwCode, &written); if (bStatus) { printf(" [ changing memory attributes to RX\n"); // change the protection to read/execute only VirtualProtectEx (hProc, pCode, dwCode, PAGE_EXECUTE_READ, &old); // is there a parameter required for PIC? if (lpParam != NULL) { printf(" [ allocating %lu bytes of RW memory in process for parameter\n", dwParam); pData=VirtualAllocEx (hProc, 0, dwParam+1, MEM_COMMIT, PAGE_READWRITE); if (pData != NULL) { printf(" [ writing %lu bytes of data to 0x%p\n", dwParam, pData); bStatus=WriteProcessMemory (hProc, pData, lpParam, dwParam, &written); if (!bStatus) { printf (" [ warning: unable to allocate write parameters to process..."); } } } IsWow64Process (GetCurrentProcess(), &bLocalWow64); IsWow64Process (hProc, &bRemoteWow64); printf(" [ remote process is %s-bit\n", bRemoteWow64 ? "32" : "64"); if (dbg) { printf(" [ attach debugger now or set breakpoint on %p\n", pCode); printf(" [ press any key to continue . . .\n"); fgetc (stdin); } printf(" [ creating thread\n"); // if remote process is not wow64 but I am, // make switch to 64-bit for thread creation. if (!bRemoteWow64 && bLocalWow64) { hThread=NULL; //DebugBreak (); CreateRemoteThread64=(pCreateRemoteThread64) init_func(CreateThreadPIC, CreateThreadPIC_SIZE); CreateRemoteThread64 (hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, 0, &hThread); } else { hThread=CreateRemoteThread (hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, 0); } if (hThread != NULL) { printf (" [ waiting for thread %lx to terminate\n", (DWORD)hThread); idx=WaitForSingleObject (hThread, INFINITE); if (idx!=0) { xstrerror ("WaitForSingleObject"); } ec=0; if (GetExitCodeThread(hThread, &ec)) { printf (" [ exit code was %lu (%08lX)", ec, ec); } CloseHandle (hThread); } else { xstrerror ("CreateRemoteThread"); } } if (idx==0) { VirtualFreeEx (hProc, pCode, 0, MEM_RELEASE); if (pData!=NULL) { VirtualFreeEx (hProc, pData, 0, MEM_RELEASE); } } } else { xstrerror ("VirtualFreeEx()"); } CloseHandle (hProc); } else { xstrerror ("OpenProcess (%lu)", dwId); } if (CreateRemoteThread64!=NULL) free_func(CreateRemoteThread64); return bStatus; }
void LaunchGame(LPCSTR lpCmdLine) { //Get FF8.exe path _TCHAR exe_path[MAX_PATH]; memset(&exe_path, 0, sizeof(_TCHAR)*MAX_PATH); _TCHAR dir_path[MAX_PATH]; DWORD dir_path_size = MAX_PATH*sizeof(_TCHAR); memset(&dir_path, 0, dir_path_size); int lpCmdLineF_size = (int)strlen(lpCmdLine)+1; _TCHAR *lpCmdLineF = new _TCHAR[lpCmdLineF_size]; #ifdef _UNICODE MultiByteToWideChar(CP_UTF8, 0, lpCmdLine, -1, lpCmdLineF, lpCmdLineF_size); #else _sntprintf_s(lpCmdLineF, lpCmdLineF_size, lpCmdLineF_size, _T("%s"), lpCmdLine); #endif FILE *fs; if(lpCmdLineF_size > 1 && ((fs = _wfsopen(lpCmdLineF, _T("r"), _SH_DENYNO)) != NULL)) { //From file fclose(fs); _sntprintf_s((_TCHAR *)&dir_path, MAX_PATH, MAX_PATH, _T("%s"), lpCmdLineF); for(int i = MAX_PATH-1; i >= 0; i--) { if(dir_path[i] == _T('\\')) { dir_path[i] = _T('\0'); break; } } _sntprintf_s((_TCHAR *)&exe_path, MAX_PATH, MAX_PATH, _T("%s"), lpCmdLineF); } else { //From registry HKEY hFF8_key = NULL; if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Square Soft, Inc\\FINAL FANTASY VIII\\1.00"), 0, KEY_QUERY_VALUE, &hFF8_key)) { if(ERROR_SUCCESS == RegQueryValueEx(hFF8_key, _T("AppPath"), NULL, NULL, (LPBYTE)&dir_path, &dir_path_size)) { _sntprintf_s((_TCHAR *)&exe_path, MAX_PATH, MAX_PATH, _T("%s\\FF8.exe"), dir_path); } } } if(_tcslen((_TCHAR *)&exe_path) <= 0) { MessageBox(NULL, _T("FF8.exe path missing from both command line and registry.\n\nCorrect Usage:\nc:\\games\\ff8_loader.exe c:\\games\\ff8.exe"), _T("Final Fantasy VIII Launcher"), MB_OK | MB_ICONERROR); } else { //Inject our library into the target process //installCOMHook(); STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); //Launch ff8.exe if(!CreateProcess(NULL, (LPWSTR)&exe_path, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL /*(LPCWSTR)&dir_path*/, &si, &pi)) { _TCHAR mbuffer[255]; _sntprintf_s((_TCHAR *)&mbuffer, 150, 150, _T("CreateProcess(FF8.exe) returned an error...\n\nERROR CODE: %d\n"), GetLastError()); MessageBox(NULL, (_TCHAR *)&mbuffer, _T("Final Fantasy VIII Launcher"), MB_OK | MB_ICONERROR); } HANDLE hThread; _TCHAR currdirPath[MAX_PATH], libPath[MAX_PATH]; void* pLibRemote; DWORD hLibModule; HMODULE hKernel32 = GetModuleHandle(_T("Kernel32")); if(GetCurrentDirectory(MAX_PATH, currdirPath)) { //Error } _sntprintf_s(libPath, MAX_PATH, MAX_PATH, _T("%s\\dx_hook.dll"), currdirPath); pLibRemote = VirtualAllocEx(pi.hProcess, NULL, sizeof(libPath), MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(pi.hProcess, pLibRemote, (void*)libPath, sizeof(libPath), NULL ); hThread = ::CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) GetProcAddress(hKernel32, "LoadLibraryW"), pLibRemote, 0, NULL); WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &hLibModule); CloseHandle(hThread); VirtualFreeEx(pi.hProcess, pLibRemote, sizeof(libPath), MEM_RELEASE); // now start running the application ResumeThread(pi.hThread); //Destroy the application window and wait for the FF8.exe process to return before therminating the launcher process DestroyWindow(g_hwndMain); WaitForSingleObject(pi.hProcess, INFINITE); //Unload DLL hThread = ::CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) GetProcAddress(hKernel32, "FreeLibraryW"), (LPVOID)hLibModule, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); //Release COM-hook and cleanup //removeCOMHook(); } delete lpCmdLineF; lpCmdLineF = NULL; }
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath) { HANDLE hProcess = NULL; HANDLE hThread = NULL; LPVOID pRemoteBuf = NULL; DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR); LPTHREAD_START_ROUTINE pThreadProc = NULL; BOOL bRet = FALSE; HMODULE hMod = NULL; DWORD dwDesiredAccess = 0; TCHAR szProcName[MAX_PATH] = { 0, }; dwDesiredAccess = PROCESS_ALL_ACCESS; //dwDesiredAccess = MAXIMUM_ALLOWED; if (!(hProcess = OpenProcess(dwDesiredAccess, FALSE, dwPID))) { wsprintf(buf, L"InjectDll() : OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError()); MessageBox(NULL, buf, L"error", MB_OK); goto INJECTDLL_EXIT; } pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); if (pRemoteBuf == NULL) { wsprintf(buf, L"InjectDll() : VirtualAllocEx() failed!!! [%d]\n", GetLastError()); MessageBox(NULL, buf, L"error", MB_OK); goto INJECTDLL_EXIT; } if (!WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL)) { wsprintf(buf, L"InjectDll() : WriteProcessMemory() failed!!! [%d]\n", GetLastError()); MessageBox(NULL, buf, L"error", MB_OK); goto INJECTDLL_EXIT; } hMod = GetModuleHandle(L"kernel32.dll"); if (hMod == NULL) { wsprintf(buf, L"InjectDll() : GetModuleHandle(\"kernel32.dll\") failed!!! [%d]\n", GetLastError()); MessageBox(NULL, buf, L"error", MB_OK); goto INJECTDLL_EXIT; } pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); if (pThreadProc == NULL) { wsprintf(buf, L"InjectDll() : GetProcAddress(\"LoadLibraryW\") failed!!! [%d]\n", GetLastError()); MessageBox(NULL, buf, L"error", MB_OK); goto INJECTDLL_EXIT; } if (!MyCreateRemoteThread(hProcess, pThreadProc, pRemoteBuf)) { wsprintf(buf, L"InjectDll() : MyCreateRemoteThread() failed!!!\n"); MessageBox(NULL, buf, L"error", MB_OK); goto INJECTDLL_EXIT; } bRet = TRUE; // bRet = CheckDllInProcess(dwPID, szDllPath); INJECTDLL_EXIT: wsprintf(szProcName, L"%s", GetProcName(dwPID)); if (szProcName[0] == '\0') _tcscpy_s(szProcName, L"(no_process)"); wsprintf(buf, L"%s(%d) %s!!!\n", szProcName, dwPID); OutputDebugStringW(buf); if (pRemoteBuf) VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE); if (hThread) CloseHandle(hThread); if (hProcess) CloseHandle(hProcess); return bRet; }
bool ServerBrowser::InjectLibraryIntoProcess(DWORD dwProcessId, char * szLibraryPath) { bool bReturn = true; // Open our target process HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId); if(!hProcess) { // Failed to open the process MessageBoxA(NULL, "Failed to open the remote process.", NULL, NULL); return false; } // Get the length of the library path size_t sLibraryPathLen = (strlen(szLibraryPath) + 1); // Allocate the a block of memory in our target process for the library name void * pRemoteLibraryPath = VirtualAllocEx(hProcess, NULL, sLibraryPathLen, MEM_COMMIT, PAGE_READWRITE); // Write our library name to the allocated block of memory SIZE_T sBytesWritten = 0; WriteProcessMemory(hProcess, pRemoteLibraryPath, (void *)szLibraryPath, sLibraryPathLen, &sBytesWritten); if(sBytesWritten != sLibraryPathLen) { MessageBoxA(NULL, "Failed to write library path into remote process.", NULL, NULL); bReturn = false; } else { // Get the handle of Kernel32.dll HMODULE hKernel32 = GetModuleHandle(L"Kernel32"); // Get the address of the LoadLibraryA function from Kernel32.dll FARPROC pfnLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA"); // Create a thread inside the target process to load our library HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnLoadLibraryA, pRemoteLibraryPath, 0, NULL); if(hThread) { // Wait for the created thread to end WaitForSingleObject(hThread, INFINITE); // Get the remote thread exit code /*DWORD dwExitCode; GetExitCodeThread(hThread, &dwExitCode); if(dwExitCode != 0) { IVMessageBox("Failed to inject library into remote process. Cannot launch IV:MP."); bReturn = false; }*/ // Close our thread handle CloseHandle(hThread); } else { // Thread creation failed MessageBoxA(NULL, "Failed to create remote thread in remote process.", NULL, NULL); bReturn = false; } } // Free the allocated block of memory inside the target process VirtualFreeEx(hProcess, pRemoteLibraryPath, sizeof(pRemoteLibraryPath), MEM_RELEASE); // If the injection failed terminate the target process if(!bReturn) TerminateProcess(hProcess, 0); // Close our target process CloseHandle(hProcess); return bReturn; }
static void _DoDLLInjection() { DWORD cbDLLPath; HANDLE hProcess; HANDLE hSnapshot; HANDLE hThread; PROCESSENTRY32W pe; PVOID pLoadLibraryAddress; PVOID pLoadLibraryArgument; PWSTR p; WCHAR wszFilePath[MAX_PATH]; // Get the full path to our EXE file. if (!GetModuleFileNameW(NULL, wszFilePath, _countof(wszFilePath))) { DPRINT("GetModuleFileNameW failed with error %lu!\n", GetLastError()); return; } // Replace the extension. p = wcsrchr(wszFilePath, L'.'); if (!p) { DPRINT("File path has no file extension: %S\n", wszFilePath); return; } wcscpy(p, L".dll"); cbDLLPath = (wcslen(wszFilePath) + 1) * sizeof(WCHAR); // Create a snapshot of the currently running processes. hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { DPRINT("CreateToolhelp32Snapshot failed with error %lu!\n", GetLastError()); return; } // Enumerate through all running processes. pe.dwSize = sizeof(pe); if (!Process32FirstW(hSnapshot, &pe)) { DPRINT("Process32FirstW failed with error %lu!\n", GetLastError()); return; } do { // Check if this is the spooler server process. if (wcsicmp(pe.szExeFile, L"spoolsv.exe") != 0) continue; // Open a handle to the process. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); if (!hProcess) { DPRINT("OpenProcess failed with error %lu!\n", GetLastError()); return; } // Get the address of LoadLibraryW. pLoadLibraryAddress = (PVOID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW"); if (!pLoadLibraryAddress) { DPRINT("GetProcAddress failed with error %lu!\n", GetLastError()); return; } // Allocate memory for the DLL path in the spooler process. pLoadLibraryArgument = VirtualAllocEx(hProcess, NULL, cbDLLPath, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!pLoadLibraryArgument) { DPRINT("VirtualAllocEx failed with error %lu!\n", GetLastError()); return; } // Write the DLL path to the process memory. if (!WriteProcessMemory(hProcess, pLoadLibraryArgument, wszFilePath, cbDLLPath, NULL)) { DPRINT("WriteProcessMemory failed with error %lu!\n", GetLastError()); return; } // Create a new thread in the spooler process that calls LoadLibraryW as the start routine with our DLL as the argument. // This effectively injects our DLL into the spooler process and we can inspect localspl.dll there just like the spooler. hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryAddress, pLoadLibraryArgument, 0, NULL); if (!hThread) { DPRINT("CreateRemoteThread failed with error %lu!\n", GetLastError()); return; } CloseHandle(hThread); break; } while (Process32NextW(hSnapshot, &pe)); }
static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib) { #ifdef _M_AMD64 # define InstructionPointer Rip # define StackPointer Rsp # define LoaderRegister Rcx # define LoadLibraryAOffset 0x15 /* This payload allows us to load arbitrary module located * at the end of this buffer */ static uint8_t const loader[] = { "\x55" /* push rbp */ "\x48\x89\xE5" /* mov rbp,rsp */ "\x48\x83\xEC\x20" /* sub rsp,byte +0x20 */ "\x48\x83\xE4\xF0" /* and rsp,byte -0x10 */ "\x48\x8D\x0D\x14\x00\x00\x00" /* lea rcx,[rel 0x27] */ "\x48\xB8________" /* mov rax, LoadLibraryA */ "\xFF\xD0" /* call rax */ "\x48\x85\xC0" /* test rax,rax */ "\x75\x01" /* jnz 0x25 */ "\xCC" /* int3 */ "\xC9" /* leave */ "\xC3" /* ret */ }; #elif defined (_M_IX86) # define InstructionPointer Eip # define StackPointer Esp # define LoaderRegister Eax /* It seems the Windows loader store the oep as the first param * but by a side effect it's also contained in eax register */ # define loader loader32 # define LoadLibraryAOffset 0x04 /* This payload allows us to load arbitrary module located * at the end of this buffer */ static uint8_t const loader[] = { "\x60" /* pushad */ "\xEB\x0E" /* jmp short 0x11 */ "\xB8____" /* mov eax,LoadLibraryA */ "\xFF\xD0" /* call eax */ "\x85\xC0" /* test eax,eax */ "\x75\x01" /* jnz 0xf */ "\xCC" /* int3 */ "\x61" /* popad */ "\xC3" /* ret */ "\xE8\xED\xFF\xFF\xFF" /* call dword 0x3 */ }; #else # error Unimplemented architecture ! #endif /* We use this code to make the targeted process wait for us */ static uint8_t const wait[] = "\xeb\xfe"; /* jmp $-1 */ size_t wait_len = sizeof(wait) - 1; void *process = pinfo->hProcess; void *thread = pinfo->hThread; SIZE_T written = 0; BOOL tmp; /* Payload */ size_t payload_len = sizeof(loader) - 1 + strlen(lib) + 1; uint8_t *payload = malloc(payload_len); if (payload == NULL) goto error; /* Use the main thread to inject our library */ CONTEXT ctxt; ctxt.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(thread, &ctxt)) goto error; /* Make the target program wait when it reaches the original entry * point, because we can't do many thing from the Windows loader */ DWORD_PTR oep = ctxt.LoaderRegister; /* Original Entry Point */ uint8_t orig_data[2]; tmp = ReadProcessMemory(process, (LPVOID)oep, orig_data, sizeof(orig_data), &written); if (!tmp || written != sizeof(orig_data)) goto error; /* save original opcode */ tmp = WriteProcessMemory(process, (LPVOID)oep, wait, wait_len, &written); if (!tmp || written != wait_len) goto error; /* write jmp short $-1 */ if (!FlushInstructionCache(process, (LPVOID)oep, wait_len)) goto error; if (ResumeThread(thread) == (DWORD)-1) goto error; /* Stop when the program reachse the oep */ while (oep != ctxt.InstructionPointer) { if (!GetThreadContext(thread, &ctxt)) goto error; Sleep(10); } if (SuspendThread(thread) == (DWORD)-1) goto error; /* Resolve LoadLibraryA from the target process memory context */ DWORD pid = pinfo->dwProcessId; void *rldlib = get_proc_address(process, pid, "LoadLibraryA"); if (rldlib == NULL) goto error; void *rpl = VirtualAllocEx(process, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (rpl == NULL) goto error; /* Emulate a call to the loader code, thus the ret instruction from * loader will get (e|r)ip back to the original entry point */ ctxt.StackPointer -= sizeof(oep); tmp = WriteProcessMemory(process, (LPVOID)ctxt.StackPointer, &oep, sizeof(oep), &written); if (!tmp || written != sizeof(oep)) goto error; ctxt.InstructionPointer = (DWORD_PTR)rpl; if (!SetThreadContext(thread, &ctxt)) goto error; /* Forge the payload */ memcpy(payload, loader, sizeof(loader) - 1); /* Write the address of LoadLibraryA */ memcpy(payload + LoadLibraryAOffset, &rldlib, sizeof(rldlib)); /* Write the first parameter of LoadLibraryA */ strcpy((char *)(payload + sizeof(loader) - 1), lib); tmp = WriteProcessMemory(process, rpl, payload, payload_len, &written); if (!tmp || written != payload_len) goto error; /* Restore original opcode */ tmp = WriteProcessMemory(process, (LPVOID)oep, orig_data, sizeof(orig_data), &written); if (!tmp || written != sizeof(orig_data)) goto error; if (!FlushInstructionCache(process, rpl, payload_len)) goto error; if (!FlushInstructionCache(process, (LPVOID)oep, sizeof(orig_data))) goto error; /* We must not free remote allocated memory since they will be used * after the process will be resumed */ free(payload); return 0; error: free(payload); return -1; }
/* DWORD MemRead::ReadPointer(DWORD base, DWORD* offset, int count) { for (int i = 0; i < count - 1; i++) { base = ReadMem(base + offset[i], 4).toUINT16; // читаем по 4 байта так как адреса занимают 32 битные 4 байта, и приводим к UINT32 } return base + offset[count - 1]; count - 1 - для того что бы возвращать адрес, а не значение } */ DWORD MemRead::Alloc(DWORD memProtect) { return (DWORD)VirtualAllocEx(m_hProc, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, memProtect);}
BOOL GetSetThreadContext_Injection() { TCHAR lpApplicationName[] = _T("C:\\Windows\\System32\\svchost.exe"); TCHAR lpApplicationName2[] = _T("C:\\masm32\\examples\\dialogs_later\\basic\\basicdlg.exe"); BOOL bResult; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; SecureZeroMemory(&StartupInfo, sizeof(STARTUPINFO)); SecureZeroMemory(&ProcessInfo, sizeof(PPROCESS_INFORMATION)); // Create the hollowed process in suspended mode bResult = CreateProcess(lpApplicationName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &StartupInfo, &ProcessInfo); if (bResult == NULL){ print_last_error(_T("CreateProcess")); return FALSE; } // Allocate space for context structure PCONTEXT pContext; LPVOID pTargetImageBase = NULL; pContext = PCONTEXT(VirtualAlloc(NULL, sizeof(LPVOID), MEM_COMMIT, PAGE_READWRITE)); if (pContext == NULL) { print_last_error(_T("VirtualAlloc")); return FALSE; } // Get the thread context of target pContext->ContextFlags = CONTEXT_FULL; bResult = GetThreadContext(ProcessInfo.hThread, pContext); if (bResult == NULL) { print_last_error(_T("GetThreadContext")); return FALSE; } // Read the image base address of target ReadProcessMemory(ProcessInfo.hProcess, LPCVOID(pContext->Ebx + 8), pTargetImageBase, 4, NULL); // Opening source image HANDLE hFile = CreateFile(lpApplicationName2, GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { print_last_error(_T("CreateFile")); return FALSE; } // Reading the file DWORD dwSize = GetFileSize(hFile, 0); DWORD dwBytesRead; PBYTE pBuffer = new BYTE[dwSize]; ReadFile(hFile, pBuffer, dwSize, &dwBytesRead, 0); PIMAGE_SECTION_HEADER pImageSectionHeader; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuffer; if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) { PIMAGE_NT_HEADERS32 pNTHeaders = PIMAGE_NT_HEADERS(DWORD(pBuffer) + pDosHeader->e_lfanew); if (pNTHeaders->Signature == IMAGE_NT_SIGNATURE) { if (DWORD(pTargetImageBase) == pNTHeaders->OptionalHeader.ImageBase) { pNtUnmapViewOfSection NtUnmapViewOfSection; NtUnmapViewOfSection = (pNtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection")); NtUnmapViewOfSection(ProcessInfo.hProcess, pTargetImageBase); } LPVOID pImageBase; pImageBase = VirtualAllocEx(ProcessInfo.hProcess, LPVOID(pNTHeaders->OptionalHeader.ImageBase), pNTHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pImageBase == NULL) { print_last_error(_T("VirtualAllocEx")); return FALSE; } WriteProcessMemory(ProcessInfo.hProcess, pImageBase, pBuffer, pNTHeaders->OptionalHeader.SizeOfHeaders, NULL); for (int Count = 0; Count < pNTHeaders->FileHeader.NumberOfSections; Count++) { pImageSectionHeader = PIMAGE_SECTION_HEADER(DWORD(pBuffer) + pDosHeader->e_lfanew + 248 + (Count * 40)); WriteProcessMemory(ProcessInfo.hProcess, LPVOID(DWORD(pImageBase) + pImageSectionHeader->VirtualAddress), LPVOID(DWORD(pBuffer) + pImageSectionHeader->PointerToRawData), pImageSectionHeader->SizeOfRawData, NULL); } WriteProcessMemory(ProcessInfo.hProcess, LPVOID(pContext->Ebx + 8), LPVOID(&pNTHeaders->OptionalHeader.ImageBase), 4, NULL); pContext->Eax = DWORD(pImageBase) + pNTHeaders->OptionalHeader.AddressOfEntryPoint; SetThreadContext(ProcessInfo.hThread, LPCONTEXT(pContext)); ResumeThread(ProcessInfo.hThread); } } return TRUE; }
int main(int argc, char* argv[]) { DWORD dwProcessId = GetCurrentProcessId(); char szProcessName[256] = {0}; char szModuleName[MAX_PATH] = {0}; for (int i = 1; i < argc; i++) { if (_stricmp(argv[i], "-pid") == 0 && i < (argc - 1)) { dwProcessId = atoi(argv[i + 1]); } if (_stricmp(argv[i], "-name") == 0 && i < (argc - 1)) { strcpy_s(szProcessName, argv[i + 1]); } if (_stricmp(argv[i], "-dll") == 0 && i < (argc - 1)) { strcpy_s(szModuleName, argv[i + 1]); } } if (strlen(szModuleName) == 0) { printf("Module name is required...\n"); return 0; } if (strlen(szProcessName) == 0 && dwProcessId == GetCurrentProcessId()) { printf("Invalid parameters!\n"); return 0; } if (strlen(szProcessName) > 0) { if (dwProcessId == GetCurrentProcessId()) { // Only change the processid if it's not already set dwProcessId = GetProcessIdFromProcessName(szProcessName); if (dwProcessId == GetCurrentProcessId()) { printf("Failed to obtain process \"%s\"...\n", szProcessName); return 0; } } } HMODULE hKernel = LoadLibraryA("kernel32.dll"); DWORD64 dwLoadLibraryA = (DWORD64) GetProcAddress(hKernel, "LoadLibraryA") - (DWORD64) hKernel; printf("kernel32.dll: %016llX\n", hKernel); printf("LoadLibraryA: %016llX\n", dwLoadLibraryA); printf("Module Name: %s\n", szModuleName); char szCurrentModulePath[MAX_PATH] = {0}; GetModuleFileNameA(GetModuleHandle(NULL), szCurrentModulePath, MAX_PATH); for (size_t i = strlen(szCurrentModulePath); i > 0; i--) { if (szCurrentModulePath[ i ] == '\\') { szCurrentModulePath[ i + 1 ] = 0; break; } } strcat_s(szCurrentModulePath, szModuleName); printf("Full Path: %s\n", szCurrentModulePath); DWORD dwFileAttributes = GetFileAttributesA(szCurrentModulePath); if (dwFileAttributes == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) { printf("File not found...\n"); return 0; } printf("Injecting: %s\n", szCurrentModulePath); HMODULE hRemoteKernel = GetRemoteModuleHandleA(dwProcessId, "kernel32.dll"); if (hRemoteKernel == NULL) { printf("Failed to locate kernel32 in remote process...\n"); return 0; } printf("kernel32 (remote): 0x%016llX\n", hRemoteKernel); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (hProcess == INVALID_HANDLE_VALUE) { printf("Failed to locate remote process...\n"); return 0; } LPVOID lpModuleName = VirtualAllocEx(hProcess, NULL, strlen(szCurrentModulePath) + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (lpModuleName == NULL) { printf("Failed to allocate module name in remote process...\n"); return 0; } if (WriteProcessMemory(hProcess, lpModuleName, szCurrentModulePath, strlen(szCurrentModulePath), NULL) == FALSE) { printf("Failed to write module name in remote process...\n"); return 0; } DWORD64 dwRemoteLoadLibraryAddress = ((DWORD64)hRemoteKernel + dwLoadLibraryA); printf("LoadLibraryA (remote): %016llX\n", dwRemoteLoadLibraryAddress); HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE) dwRemoteLoadLibraryAddress, lpModuleName, 0, 0); printf("Injecting... "); WaitForSingleObject(hThread, INFINITE); printf("Injected!\n"); return 0; }
/*********************************************************************** * VirtualAllocExNuma (KERNEL32.@) */ LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocExNuma(HANDLE process, void *addr, SIZE_T size, DWORD type, DWORD protect, DWORD numa_node) { FIXME_(virtual)("Ignoring preferred numa_node\n"); return VirtualAllocEx(process, addr, size, type, protect); }
/*********************************************************************** * VirtualAlloc (KERNEL32.@) * * Reserves or commits a region of pages in virtual address space. * * PARAMS * addr [I] Address of region to reserve or commit. * size [I] Size of region. * type [I] Type of allocation. * protect [I] Type of access protection. * * RETURNS * Success: Base address of allocated region of pages. * Failure: NULL. */ LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc( void *addr, SIZE_T size, DWORD type, DWORD protect ) { return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect ); }
DWORD demoSuspendInjectResume(PCWSTR pszLibFile, DWORD dwProcessId) { void *stub; unsigned long threadID, oldIP, oldprot; HANDLE hThread; CONTEXT ctx; DWORD stubLen = sizeof(sc); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (hProcess == NULL) { wprintf(L"[-] Error: Could not open process for PID (%d).\n", dwProcessId); return(1); } DWORD LoadLibraryAddress = (DWORD)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); if (LoadLibraryAddress == NULL) { wprintf(L"[-] Error: Could not find LoadLibraryA function inside kernel32.dll library.\n"); exit(1); } SIZE_T dwSize = (wcslen(pszLibFile) + 1) * sizeof(wchar_t); LPVOID lpDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (lpDllAddr == NULL) { wprintf(L"[-] Error: Could not allocate memory inside PID (%d).\n", dwProcessId); exit(1); } stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (stub == NULL) { wprintf(L"[-] Error: Could not allocate memory for stub.\n"); exit(1); } BOOL bStatus = WriteProcessMemory(hProcess, lpDllAddr, pszLibFile, dwSize, NULL); if (bStatus == 0) { wprintf(L"[-] Error: Could not write any bytes into the PID (%d) address space.\n", dwProcessId); return(1); } threadID = getThreadID(dwProcessId); hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID); if (hThread != NULL) { SuspendThread(hThread); } else printf("could not open thread\n"); ctx.ContextFlags = CONTEXT_CONTROL; GetThreadContext(hThread, &ctx); oldIP = ctx.Eip; ctx.Eip = (DWORD)stub; ctx.ContextFlags = CONTEXT_CONTROL; VirtualProtect(sc, stubLen, PAGE_EXECUTE_READWRITE, &oldprot); memcpy((void *)((unsigned long)sc + 1), &oldIP, 4); memcpy((void *)((unsigned long)sc + 8), &lpDllAddr, 4); memcpy((void *)((unsigned long)sc + 13), &LoadLibraryAddress, 4); WriteProcessMemory(hProcess, stub, sc, stubLen, NULL); SetThreadContext(hThread, &ctx); ResumeThread(hThread); Sleep(8000); VirtualFreeEx(hProcess, lpDllAddr, dwSize, MEM_DECOMMIT); VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT); CloseHandle(hProcess); CloseHandle(hThread); return(0); }
DWORD demoSuspendInjectResume64(PCWSTR pszLibFile, DWORD dwProcessId) { void *stub; unsigned long threadID, oldprot; HANDLE hThread; CONTEXT ctx; DWORD64 stubLen = sizeof(sc); wprintf(TEXT("[+] Shellcode Length is: %d\n"), stubLen); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (hProcess == NULL) { wprintf(L"[-] Error: Could not open process for PID (%d).\n", dwProcessId); return(1); } DWORD64 LoadLibraryAddress = (DWORD64)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); if (LoadLibraryAddress == NULL) { wprintf(L"[-] Error: Could not find LoadLibraryA function inside kernel32.dll library.\n"); exit(1); } SIZE_T dwSize = (wcslen(pszLibFile) + 1) * sizeof(wchar_t); LPVOID lpDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (lpDllAddr == NULL) { wprintf(L"[-] Error: Could not allocate memory inside PID (%d).\n", dwProcessId); exit(1); } stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (stub == NULL) { wprintf(L"[-] Error: Could not allocate memory for stub.\n"); exit(1); } SIZE_T nBytesWritten = 0; BOOL bStatus = WriteProcessMemory(hProcess, lpDllAddr, pszLibFile, dwSize, &nBytesWritten); if (bStatus == 0) { wprintf(L"[-] Error: Could not write any bytes into the PID (%d) address space.\n", dwProcessId); return(1); } if (nBytesWritten != dwSize) wprintf(TEXT("[-] Something is wrong!\n")); threadID = getThreadID(dwProcessId); hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID); if (hThread != NULL) { SuspendThread(hThread); } else wprintf(L"[-] Could not open thread\n"); ctx.ContextFlags = CONTEXT_CONTROL; GetThreadContext(hThread, &ctx); DWORD64 oldIP = ctx.Rip; ctx.Rip = (DWORD64)stub; ctx.ContextFlags = CONTEXT_CONTROL; memcpy(sc + 3, &oldIP, sizeof(oldIP)); memcpy(sc + 41, &lpDllAddr, sizeof(lpDllAddr)); memcpy(sc + 51, &LoadLibraryAddress, sizeof(LoadLibraryAddress)); #ifdef _DEBUG wprintf(TEXT("[+] Shellcode Launcher Code:\n\t")); for (int i = 0; i < stubLen; i++) wprintf(TEXT("%02x "), sc[i]); wprintf(TEXT("\n")); #endif WriteProcessMemory(hProcess, (void *)stub, &sc, stubLen, NULL); SetThreadContext(hThread, &ctx); ResumeThread(hThread); Sleep(8000); VirtualFreeEx(hProcess, lpDllAddr, dwSize, MEM_DECOMMIT); VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT); CloseHandle(hProcess); CloseHandle(hThread); return(0); }
void CodeInjectionPlayer::InjectCode() { if (!opts.enable_code_injection) return; else if (next_request_time > GetTickCount()) return; // Window is opened? HWND hwnd = FindWindow(); if (hwnd == nullptr) return; // Msg Window is registered? (aka plugin is running?) HWND msgHwnd = ::FindWindow(message_window_class, nullptr); if (msgHwnd != nullptr) return; next_request_time = GetTickCount() + 30000; // Get the dll path char dll_path[1024] = { 0 }; if (!GetModuleFileNameA(g_plugin.getInst(), dll_path, _countof(dll_path))) return; char *p = strrchr(dll_path, '\\'); if (p == nullptr) return; p++; *p = '\0'; size_t len = p - dll_path; mir_snprintf(p, 1024 - len, "listeningto\\%s.dll", dll_name); len = strlen(dll_path); // File exists? DWORD attribs = GetFileAttributesA(dll_path); if (attribs == 0xFFFFFFFF || !(attribs & FILE_ATTRIBUTE_ARCHIVE)) return; // Do the code injection unsigned long pid; GetWindowThreadProcessId(hwnd, &pid); HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid); if (hProcess == nullptr) return; char *_dll = (char *)VirtualAllocEx(hProcess, nullptr, len + 1, MEM_COMMIT, PAGE_READWRITE); if (_dll == nullptr) { CloseHandle(hProcess); return; } WriteProcessMemory(hProcess, _dll, dll_path, len + 1, nullptr); HMODULE hKernel32 = GetModuleHandleA("kernel32"); HANDLE hLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA"); DWORD threadId; HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)hLoadLibraryA, _dll, 0, &threadId); if (hThread == nullptr) { VirtualFreeEx(hProcess, _dll, len + 1, MEM_RELEASE); CloseHandle(hProcess); return; } WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); VirtualFreeEx(hProcess, _dll, len + 1, MEM_RELEASE); CloseHandle(hProcess); }
int change_sleep_button(PROCESS_INFORMATION *pi, DWORD ImageBase) { SIZE_T written = 0; DWORD oldprot; DWORD Addr_img; char new_img[0xD02]; DWORD Addr; char buf_jmp[] = "\xE9"; char buf_code[] = "\x60" // PUSHAD "\x81\xFB\x50\xF2\x65\x00" // CMP EBX,HEROES3.0065F250 "\x75\x0D" // JNZ SHORT HEROES3.0047C37D "\x90" "\xBE\x42\x42\x42\x42" // MOV ESI, XXXX // EDI POINTS ACTUALLY TO BUF WHERE FILE IS DECOMPRESSED "\xB9\x02\x0D\x00\x00" // MOV ECX, D02 "\xF3\xA4" // REP MOVS BYTE PTR ES:[EDI],DWORD PTR DS:[ESI] "\x61" // POPAD "\x8B\xE5" // MOV ESP,EBP "\x5D" // POP EBP "\xC2\x08\x00"; // RET 8 FILE *fp; char buf_nop[9]; memset(buf_nop, 0x90, 9); fp = fopen("iam_dig.def", "rb"); if (fp == NULL) { MessageBoxA(NULL, "iam_dig.def", "Error", MB_ICONERROR); exit(EXIT_FAILURE); } fread(new_img, 0xD02, 1, fp); fclose(fp); /* NOP function wich redraw sleep/walk button */ VirtualProtect((LPVOID)0x00417F2F, 9, PAGE_EXECUTE_READWRITE, &oldprot); if (!WriteProcessMemory(pi->hProcess, (LPVOID)(0x00417F2F), buf_nop, 9, &written) || written != 9) error("WriteProcessMemory"); VirtualProtect((LPVOID)(0x00417F2F), 9, oldprot, &oldprot); /* Writting new .def file into memory */ Addr_img = (DWORD)VirtualAllocEx(pi->hProcess, 0, 0xD02, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!Addr_img) error("VirtualAllocEx"); if (!WriteProcessMemory(pi->hProcess, (LPVOID)Addr_img, new_img, 0xD02, &written) || written != 0xD02) error("WriteProcessMemory"); /* ESI points to new .def file */ memcpy(buf_code + 11, &Addr_img, 4); Addr = (DWORD)VirtualAllocEx(pi->hProcess, 0, 46, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!Addr) error("VirtualAllocEx"); if (!WriteProcessMemory(pi->hProcess, (LPVOID)(Addr), buf_code, 46, &written) || written != 46) error("WriteProcessMemory"); /* 004FAC0E |. 8BE5 MOV ESP,EBP */ /* 004FAC10 |. 5D POP EBP */ /* 004FAC11 |. C2 0800 RET 8 */ /* SETUP HOOK */ VirtualProtect((LPVOID)0x004FAC0E, 5, PAGE_EXECUTE_READWRITE, &oldprot); if (!WriteProcessMemory(pi->hProcess, (LPVOID)(0x004FAC0E), buf_jmp, 1, &written) || written != 1) error("WriteProcessMemory"); Addr = Addr - 0x004FAC0E - 5; if (!WriteProcessMemory(pi->hProcess, (LPVOID)(0x004FAC0E + 1), &Addr, 4, &written) || written != 4) error("WriteProcessMemory"); VirtualProtect((LPVOID)(0x004FAC0E), 5, oldprot, &oldprot); return (0); }
// 0 - OK, иначе - ошибка // Здесь вызывается CreateRemoteThread int InfiltrateDll(HANDLE hProcess, LPCWSTR asConEmuHk) { int iRc = -150; //if (iRc != -150) //{ // InfiltrateProc(NULL); InfiltrateEnd(); //} //const size_t cb = ((size_t)InfiltrateEnd) - ((size_t)InfiltrateProc); InfiltrateArg dat = {}; HMODULE hKernel = NULL; HANDLE hThread = NULL; DWORD id = 0; LPTHREAD_START_ROUTINE pRemoteProc = NULL; PVOID pRemoteDat = NULL; CreateRemoteThread_t _CreateRemoteThread = NULL; char FuncName[20]; void* ptrCode; size_t cbCode; //_ASSERTE("InfiltrateDll"==(void*)TRUE); cbCode = GetInfiltrateProc(&ptrCode); // Примерно, проверка размера кода созданного компилятором if (cbCode != WIN3264TEST(68,79)) { _ASSERTE(cbCode == WIN3264TEST(68,79)); iRc = -100; goto wrap; } if (lstrlen(asConEmuHk) >= (int)countof(dat.szConEmuHk)) { iRc = -101; goto wrap; } // Исполняемый код загрузки библиотеки pRemoteProc = (LPTHREAD_START_ROUTINE) VirtualAllocEx( hProcess, // Target process NULL, // Let the VMM decide where cbCode, // Size MEM_COMMIT, // Commit the memory PAGE_EXECUTE_READWRITE); // Protections if (!pRemoteProc) { iRc = -102; goto wrap; } if (!WriteProcessMemory( hProcess, // Target process (void*)pRemoteProc, // Source for code ptrCode, // The code cbCode, // Code length NULL)) // We don't care { iRc = -103; goto wrap; } // Путь к нашей библиотеке lstrcpyn(dat.szConEmuHk, asConEmuHk, countof(dat.szConEmuHk)); // Kernel-процедуры hKernel = LoadLibrary(L"Kernel32.dll"); if (!hKernel) { iRc = -104; goto wrap; } // Избежать статической линковки и строки "CreateRemoteThread" в бинарнике FuncName[ 0] = 'C'; FuncName[ 2] = 'e'; FuncName[ 4] = 't'; FuncName[ 6] = 'R'; FuncName[ 8] = 'm'; FuncName[ 1] = 'r'; FuncName[ 3] = 'a'; FuncName[ 5] = 'e'; FuncName[ 7] = 'e'; FuncName[ 9] = 'o'; FuncName[10] = 't'; FuncName[12] = 'T'; FuncName[14] = 'r'; FuncName[16] = 'a'; FuncName[11] = 'e'; FuncName[13] = 'h'; FuncName[15] = 'e'; FuncName[17] = 'd'; FuncName[18] = 0; _CreateRemoteThread = (CreateRemoteThread_t)GetProcAddress(hKernel, FuncName); // Functions for external process. MUST BE SAME ADDRESSES AS CURRENT PROCESS. // kernel32.dll компонуется таким образом, что всегда загружается по одному определенному адресу в памяти // Поэтому адреса процедур для приложений одинаковой битности совпадают (в разных процессах) dat._GetLastError = (GetLastError_t)GetProcAddress(hKernel, "GetLastError"); dat._SetLastError = (SetLastError_t)GetProcAddress(hKernel, "SetLastError"); dat._LoadLibraryW = (LoadLibraryW_t)GetLoadLibraryAddress(); // GetProcAddress(hKernel, "LoadLibraryW"); if (!_CreateRemoteThread || !dat._LoadLibraryW || !dat._SetLastError || !dat._GetLastError) { iRc = -105; goto wrap; } else { // Проверим, что адреса этих функций действительно лежат в модуле Kernel32.dll // и не были кем-то перехвачены до нас. FARPROC proc[] = {(FARPROC)dat._GetLastError, (FARPROC)dat._SetLastError, (FARPROC)dat._LoadLibraryW}; if (!CheckCallbackPtr(hKernel, countof(proc), proc, TRUE, TRUE)) { // Если функции перехвачены - попытка выполнить код по этим адресам // скорее всего приведет к ошибке доступа, что не есть гут. iRc = -111; goto wrap; } } // Копируем параметры в процесс pRemoteDat = VirtualAllocEx(hProcess, NULL, sizeof(InfiltrateArg), MEM_COMMIT, PAGE_READWRITE); if(!pRemoteDat) { iRc = -106; goto wrap; } if (!WriteProcessMemory(hProcess, pRemoteDat, &dat, sizeof(InfiltrateArg), NULL)) { iRc = -107; goto wrap; } // Запускаем поток в процессе hProcess // В принципе, на эту функцию могут ругаться антивирусы hThread = _CreateRemoteThread( hProcess, // Target process NULL, // No security 4096 * 16, // 16 pages of stack pRemoteProc, // Thread routine address pRemoteDat, // Data 0, // Run NOW &id); if (!hThread) { iRc = -108; goto wrap; } // Дождаться пока поток завершится WaitForSingleObject(hThread, INFINITE); // И считать результат if (!ReadProcessMemory( hProcess, // Target process pRemoteDat, // Their data &dat, // Our data sizeof(InfiltrateArg), // Size NULL)) // We don't care { iRc = -109; goto wrap; } // Вернуть результат загрузки SetLastError((dat.hInst != NULL) ? 0 : (DWORD)dat.ErrCode); iRc = (dat.hInst != NULL) ? 0 : -110; wrap: if (hKernel) FreeLibrary(hKernel); if (hThread) CloseHandle(hThread); if(pRemoteProc) VirtualFreeEx(hProcess, (void*)pRemoteProc, cbCode, MEM_RELEASE); if(pRemoteDat) VirtualFreeEx(hProcess, pRemoteDat, sizeof(InfiltrateArg), MEM_RELEASE); return iRc; }