要想改变目标进程执行流程的办法有很多,最常见的就是hook。为了让目标进程执行特定的代码,可以注入shellcode或dll;shellcode的优点是体积小,不容易被检测到,但功能也相对单一;dll注入优点是可以包含的功能较多,但容易被检测到。本次拿xxxx软件举例做个dll注入;
要做注入,否先要再目标进程开辟一块内存空间,然后写入自己想要执行的代码,再想办法让eip跳转到这里。对于dll注入,大致的流程如下:
openprocess->VirtualAllocEx->WriteProcessMemory->GetProcAddress->CreateRemoteThread
核心思路:打开目标进程,分配内存空间,写入需要执行的dll地址,得到loadlibrary函数地址,最后调用createRemoteThread函数专门生成一个线程执行loadlibary函数。这种注入/HOOK方式多年前就烂大街了,这里不再赘述,感兴趣的小伙伴可google查阅相关资料;dll注入核心代码如下:
#include "windows.h" #include "tchar.h" BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath) { HANDLE hProcess = NULL, hThread = NULL; HMODULE hMod = NULL; LPVOID pRemoteBuf = NULL; DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR); LPTHREAD_START_ROUTINE pThreadProc; if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) ) { _tprintf(L"OpenProcess(%d) failed!!! [%d] ", dwPID, GetLastError()); return FALSE; } pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL); hMod = GetModuleHandle(L"kernel32.dll"); pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hProcess); return TRUE; } int _tmain(int argc, TCHAR *argv[]) { if( argc != 3) { _tprintf(L"USAGE : %s <pid> <dll_path> ", argv[0]); return 1; } // inject dll if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) ) _tprintf(L"InjectDll("%s") success!!! ", argv[2]); else _tprintf(L"InjectDll("%s") failed!!! ", argv[2]); return 0; }
这里需要输入两个参数:目标进程的PID和需要加载的dll全路径。这里为了突出重点(注入流程),省略了查找目标进程的代码(感兴趣的小伙伴可调用windows的API遍历进程,查找PID),这里手动在任务管理器里面查找;
为了测试dll是否加载成功,这里先不执行其他代码,只弹个窗试试:
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: MessageBoxW(NULL,L"dll加载成功",L"dll加载测试", MB_OK); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
测试效果,说明dll加载成功了!
下一步就是通过动态调试或静态分析找各种功能call了!有两种方式:
- 用ODCEX32DBGIDA等工具调试xxxx的PC端,通过各种方式找到各种功能(诸如发送/接受消息、二维码生成、发送/接受文件、红包等)的call
- 市面上有好些现成的外挂,可以“黑吃黑”:用IDA分析这些外挂的dll,看看hook了xxxx的哪些模块的哪些偏移地址,自己写代码直接hook这些地址即可,理论上比第一种方式快很多,不过只能追随别人的步伐,没有先发优势;