刚写完了一个全局的inline hook 库, 易用性感觉还不是很好。 但是"全局"2字是亮点。
先说一下全局的思路。
首先遍历当前所有的进程。当然我们想到的大多数方法是用一些枚举进程的api来做,我想到了另一种方法。暴力穷举,这样可以把隐藏进程也给揪出来。
//暴力穷举进程(进程ID都是4的整数倍,而且小于0x0000ffff)
代码:
HANDLE hProcess = 0; for (DWORD dwProcessID = 0; dwProcessID<=0x0000FFFF; dwProcessID+=4) { 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 , // For CreateRemoteThread FALSE, dwProcessID); if (hProcess == 0) { continue; } //有进程句柄了。。远程线程注入啥的。。。 }
我想到了hook CreateProcess 于是就想了想创建进程的方法 WinExec ShellExcute 等等 用OD简单的跟踪了一下 发现最终都会调用Kernel32!CreateProcessInternalW函数 好了 就勾他吧。
在 我们的 MyCreateProcessInternalW中如何处理才能让新建立的线程也能Load我们的dll呢
方法有很多 我挑了一种最简单的 先用CREATE_SUSPENDED属性挂起进程 然后修改入口点 然后构造shellcode 完成load我们的dll的任务 最后在返回入口点之前把入口点修改过的代码恢复过去。
具体代码如下(shellcode代码写的太挫了 - -!):
代码:
BOOL __stdcall MyCreateProcessInternalW( HANDLE hToken, LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation , PHANDLE hNewToken) { //以CREATE_SUSPENDED属性先挂起进程 BOOL bRet = (BOOL)g_ApiInfo[Index_CreateProcessInternalW].InvokeApi( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags|CREATE_SUSPENDED, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken); if (bRet == FALSE) { return bRet; } //得到入口点。 DWORD dwEntry = GetProcessEntryPoint(lpProcessInformation->hProcess); if (dwEntry == 0) { ResumeThread(lpProcessInformation->hThread); return TRUE; } DWORD dwLoadLibrary = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); DWORD dwVirtualProtect = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualProtect"); //保存前5个字节 以后好恢复 BYTE bSave[5] = {0}; DWORD dwRead = 0; bRet = ReadProcessMemory(lpProcessInformation->hProcess, (LPVOID)dwEntry, bSave, 5, &dwRead); //编写shellcode /*cc 9c pushfd 0040101D 50 push eax ; 保存eax寄存器 ;;data offset + 0 0040101E 834424 08 FB add dword ptr ss:[esp+8],-5 ; 修改跳回去的地址为原入口点(在ret之前修正入口点) 00401023 E8 0C000000 call 00401034 ; 将后面的字符串push进去 00401028 6D 79 68 6F 6F 6B 2E 64 6C 6C 00 00 "myhook.dll" 00401034 E8 3E0D407C call kernel32.LoadLibraryA ; 加载dll ;;data offset + 24 00401039 6A 00 push 0 ; 修改入口点页属性 这里是申请一个空间 0040103B 54 push esp ; old 属性地址 即0的地址 0040103C 6A 40 push 40 ; PAGE_EXECUTE_READWRITE 0040103E 6A 05 push 5 00401040 68 99999999 push 99999999 ; 入口点地址 ;;data offset + 36 00401045 E8 860A407C call kernel32.VirtualProtect ; 修改入口点前5字节属性为可写 否则崩 ;;data offset + 41 0040104A 58 pop eax ; 平衡堆栈 0040104B B8 99999999 mov eax,99999999 ;;data offset 47 00401050 C600 11 mov byte ptr ds:[eax],11 ;恢复入口点的5字节 ;;data offset 53 00401053 40 inc eax 00401054 C700 88888808 mov dword ptr ds:[eax],8888888 ;;data offset 57 0040105A 58 pop eax 9d popfd 0040105B C3 retn */ //第一个字节是为了用WinDbg调试而添加的,调试完成了就置为0x90了 BYTE shellcode[66] = { 0x90, 0x9c, 0x50, 0x83, 0x44, 0x24, 0x08, 0xfb, 0xe8, 0x0c, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x64, 0x6c, 0x6c, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x54, 0x6a, 0x40, 0x6a, 0x05, 0x68, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x40, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x9d, 0xc3}; //申请空间 LPVOID lpRomateAddress = VirtualAllocEx(lpProcessInformation->hProcess, 0, 66, MEM_COMMIT, PAGE_EXECUTE_READWRITE); //修改call library地址 PBYTE pOffset = (PBYTE)shellcode + 2; *(DWORD*)(pOffset+24) = dwLoadLibrary - ((DWORD)lpRomateAddress + 2 + 23) - 5; *(DWORD*)(pOffset+36) = dwEntry; *(DWORD*)(pOffset+41) = dwVirtualProtect -((DWORD)lpRomateAddress + 2 + 40) -5; *(DWORD*)(pOffset+47) = dwEntry; *(BYTE*)(pOffset+53) = bSave[0]; *(DWORD*)(pOffset+57) = *(DWORD*)(bSave+1); //写入进程空间 bRet = WriteProcessMemory(lpProcessInformation->hProcess, lpRomateAddress, shellcode, 66, 0); //修改前5字节 //call xxx BYTE bSet[5] = {0}; bSet[0] = 0xe8; *(DWORD*)(bSet+1) = (DWORD)lpRomateAddress - dwEntry - 5; bRet = WriteProcessMemory(lpProcessInformation->hProcess, LPVOID(dwEntry), bSet, 5, 0); ResumeThread(lpProcessInformation->hThread); return TRUE; }
在.h文件中用到 了一个 GetOpcodeSize函数 貌似是海风大侠的 谢谢了 否则就得用反汇编引擎。
ps 一般来说这样的需求要用WinDbg来调试子进程。 OllyDbg不太好用。