masm32汇编实现扫雷进程注入
一、什么是进程注入?
进程注入是将代码或者dll插入另一个目标进程的地址空间中,并强制该进程执行注入的代码。与dll注入不同,直接代码注入相对隐蔽,不需要额外的DLL文件。该技术通常会有如下应用场景:
- 游戏外挂开发
- 安全软件检测
- 进程监控
- 恶意软件分析
二、实现注入程序
注入程序实现思路如下:
- 通过窗口标题找到扫雷程序
- 获取目标进程ID
- 打开目标进程获取句柄
- 在目标进程中分配可执行内存
- 获取MessageBoxA函数地址
- 创建远程线程执行注入代码
实现代码如下;
.586
.model flat,stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.libInjectCode proto .datagameWindowCaption db "扫雷",0injectionSuccessTitle db "注入成功",0 injectionMessage db "扫雷进程被注入!",0
.codeInjectedCodeStart:
invoke MessageBox, NULL, offset injectionMessage, offset injectionSuccessTitle, MB_OK; ---------------------------------------------------------------------------
InjectCode proc LOCAL @hwndMinesweeper :HWNDLOCAL @dwTargetProcessId :DWORDLOCAL @hTargetProcess :HANDLELOCAL @lpRemoteCode :LPVOIDLOCAL @dwBytesWritten :DWORDinvoke FindWindow, NULL, offset gameWindowCaptionmov @hwndMinesweeper, eaxinvoke GetWindowThreadProcessId, @hwndMinesweeper, addr @dwTargetProcessIdinvoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, @dwTargetProcessIdmov @hTargetProcess, eaxinvoke VirtualAllocEx, @hTargetProcess, NULL, 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE mov @lpRemoteCode, eaxinvoke WriteProcessMemory, @hTargetProcess, @lpRemoteCode, offset InjectedCodeStart, offset InjectCode - offset InjectedCodeStart,addr @dwBytesWritteninvoke CreateRemoteThread, @hTargetProcess, NULL, 0, @lpRemoteCode, NULL, 0, NULLmov eax, 0 ret
InjectCode endpstart:invoke InjectCodeinvoke ExitProcess, eaxend start
经过编译执行上述代码后,我们发现扫雷进程会自动退出。通过使用OD进行调试,可以确认WriteProcessMemory操作执行成功。因此,现在使用OD附加到扫雷进程,并对扫雷进程中写入地址出设设置断点(也可以直接在注入的代码中增加int 3指令),写入到进程中的代码如下:
这里明显有问题,地址0x403005和0x40300E是注入进程中的地址。在数据窗口中搜索,发现不存在:
这引出一个核心问题:如何正确处理注入到目标进程的代码重定位。解决方案是通过计算注入进程与目标进程的地址差值,然后为注入代码中的字符串地址和函数地址加上这个差值即可实现重定位。与此同时,我们的注入程序中的funcMessageBox是在代码段,当前只有可读和执行权限,因此需要修改内存属性。重定位原理示意图如下所示:
修正后的代码如下:
.586
.model flat,stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.libInjectCode proto .datagameWindowCaption db "扫雷",0szUser32 db "user32.dll", 0 szMessageBox db "MessageBoxA", 0.codeInjectedCodeStart:jmp MsgBoxinjectionSuccessTitle db "Injection successful",0 injectionMessage db "The winmine process was injected!",0 funcMessageBox dd 0
MsgBox:pushadcall Next
Next:pop ebxsub ebx ,offset Nextpush MB_OKmov eax, offset injectionSuccessTitleadd eax, ebxpush eaxmov eax, offset injectionMessageadd eax, ebxpush eaxpush NULLmov eax, offset funcMessageBox add eax, ebx call dword ptr [eax]popadret
InjectedCodeStart_End:dwCodeSize dd offset InjectedCodeStart_End - offset InjectedCodeStart; ---------------------------------------------------------------------------
InjectCode proc LOCAL @hwndMinesweeper :HWNDLOCAL @dwTargetProcessId :DWORDLOCAL @hTargetProcess :HANDLELOCAL @lpRemoteCode :LPVOIDLOCAL @dwBytesWritten :DWORDLOCAL @dwOldProc:DWORDLOCAL @hUser32:DWORDinvoke LoadLibrary, offset szUser32mov @hUser32, eax;修改内存属性invoke VirtualProtect, offset funcMessageBox, size funcMessageBox, PAGE_EXECUTE_READWRITE, addr @dwOldProcinvoke GetProcAddress, @hUser32, offset szMessageBoxmov funcMessageBox, eax;还原内存属性invoke VirtualProtect, offset funcMessageBox, size funcMessageBox, @dwOldProc, addr @dwOldProcinvoke FindWindow, NULL, offset gameWindowCaptionmov @hwndMinesweeper, eaxinvoke GetWindowThreadProcessId, @hwndMinesweeper, addr @dwTargetProcessIdinvoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, @dwTargetProcessIdmov @hTargetProcess, eaxinvoke VirtualAllocEx, @hTargetProcess, NULL, 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE mov @lpRemoteCode, eaxinvoke WriteProcessMemory, @hTargetProcess, @lpRemoteCode, offset InjectedCodeStart, dwCodeSize,addr @dwBytesWritteninvoke CreateRemoteThread, @hTargetProcess, NULL, 0, @lpRemoteCode, NULL, 0, NULLmov eax, 0 ret
InjectCode endpstart:invoke InjectCodeinvoke ExitProcess, eaxend start
执行结果如下所示: