-
-
Win32汇编学习笔记04.重定位与汇编引擎
-
发表于: 2025-1-4 22:47 2027
-
重定位
**重定位:**也称为代码自重定位,代码自己去计算自己使用的各种资源再新进程中的地址,相应代码被称为被重新定位过后的代码。
示例
- 目标:向指定进程 扫雷 注入一段机器码,机器码的作用是弹出MessageBox。
与远程注入dll的区别:原是加载dll,本目标是注入一段机器码。
注机器码就是 把机器码写到对应进程里面去,写的地方不能覆盖它原本代码,否则会影响它原本的功能 ,可以去找一些空隙,但是这种方法不是很通用.最好的办法是 申请一块内存,把代码写进去,在调用线程去跑这个段代码
.asm
.586.model flat,stdcall option casemap:none include windows.inc include user32.inc include kernel32.inc includelib user32.lib includelib kernel32.lib WinMain proto .data g_szCap db "扫雷",0 ;窗口标题,用来获取窗口句柄 g_szTitle db "温情提示",0 ;弹窗窗口标题 g_szText db "你被注入了!!!",0 ;弹窗内容 .code CODE_BEGIN: invoke MessageBox,NULL,offset g_szText,offset g_szTitle,MB_OK ; ---------------------------------------------------------------------------WinMain proc LOCAL @hWndWinMine :HWND ;窗口句柄 LOCAL @dwPid :HWND ;进程id LOCAL @hProc :HINSTANCE ;进程句柄 LOCAL @pAddr :LPVOID ;申请的内存地址 LOCAL @dwBytesWirites :DWORD ;写入的字节数 invoke FindWindow,NULL ,offset g_szCap ;通过窗口标题获取窗口句柄 mov @hWndWinMine,eax invoke GetWindowThreadProcessId,@hWndWinMine,addr @dwPid ;获取进程id invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid ;获取进程句柄 mov @hProc,eax invoke VirtualAllocEx,@hProc, NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE ;自动申请内存空间 mov @pAddr,eax ;在内存中写入代码 invoke WriteProcessMemory,@hProc,@pAddr,\ ;\是换行 offset CODE_BEGIN, offset WinMain - offset CODE_BEGIN,\ addr @dwBytesWirites invoke CreateRemoteThread,@hProc ,NULL,0,@pAddr,NULL,0,NULL ;创建线程 mov eax,0 ret WinMain endpstart: invoke WinMain invoke ExitProcess,eaxend start
没重定向之前运行程序,发现我么的文件和扫雷都崩了,单独调试我们自己的代码是没问题,所以需要同时调试2个进程
Win32汇编学习笔记04.重定位与汇编引擎-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net
写入代码的地址是 05790000
可以看出,我们字符串的内存地址获取失败了,因为我们的字符串写在了我们的自己程序中,并不在扫雷程序中
把字符串移进来,调试发现地址还是我们自己的地址,字符串地址需要调整,最好让他自己算.我们只要原来代码所在的地址,与新地址所在的差值,就可以推算出新字符串所在的地址
.586.model flat,stdcall option casemap:none include windows.inc include user32.inc include kernel32.inc includelib user32.lib includelib kernel32.lib WinMain proto .data g_szCap db "扫雷",0 ;窗口标题,用来获取窗口句柄 .code CODE_BEGIN: jmp MSGBOX g_szTitle db "温情提示",0 ;弹窗窗口标题 g_szText db "你被注入了!!!",0 ;弹窗内容 MSGBOX: call LTEST ;会把 LIST 的地址入站 LTEST: pop ebx ;获取 LTEST 在新进程的地址 sub ebx ,offset LTEST ;可以得到LTEST 在 新进程地址和我们自己进程的地址差值 push MB_OK mov eax, offset g_szTitle ;获取字符串在原进程中的地址 add eax, ebx ;获取字符串在新进程中的地址 push eax ;入栈 mov eax, offset g_szText add eax, ebx push eax push NULL call MessageBox ;invoke MessageBox,NULL,offset g_szText,offset g_szTitle,MB_OK ret ; ---------------------------------------------------------------------------WinMain proc LOCAL @hWndWinMine :HWND ;窗口句柄 LOCAL @dwPid :HWND ;进程id LOCAL @hProc :HINSTANCE ;线程句柄 LOCAL @pAddr :LPVOID ;申请的内存地址 LOCAL @dwBytesWirites :DWORD ;写入的字节数 invoke FindWindow,NULL ,offset g_szCap ;通过窗口标题获取窗口句柄 mov @hWndWinMine,eax invoke GetWindowThreadProcessId,@hWndWinMine,addr @dwPid ;获取进程id invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid ;创建新线程 mov @hProc,eax invoke VirtualAllocEx,@hProc, NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE ;自动申请内存空间 mov @pAddr,eax ;在内存中写入代码 invoke WriteProcessMemory,@hProc,@pAddr,\ ;\是换行 offset CODE_BEGIN, offset WinMain - offset CODE_BEGIN,\ addr @dwBytesWirites invoke CreateRemoteThread,@hProc ,NULL,0,@pAddr,NULL,0,NULL mov eax,0 ret WinMain endpstart: invoke WinMain invoke ExitProcess,eaxend start
再继续调试,发现此数地址已经变了
有时候 CTRL + G 找地址会提示无效地址, 可以先到内存窗口,右键,在cpu数据窗口中查看,找到自己跳转的地址,在回到 代码页面 用 CTRL + G 跟随就可以了
user32 在 同一台电脑上的 不同进程的地址是一样的,因此可以利用这一点,还要注意,我们写的代码位于代码段,必须修改才能写入
重定位后的代码
.586.model flat,stdcall option casemap:none include windows.inc include user32.inc include kernel32.inc includelib user32.lib includelib kernel32.lib WinMain proto .data g_szCap db "扫雷",0 ;窗口标题,用来获取窗口句柄 g_szUser32 db "user32", 0 g_szMessageBox db "MessageBoxA", 0 .code CODE_BEGIN: jmp MSGBOX g_szTitle db "温情提示",0 ;弹窗窗口标题 g_szText db "你被注入了!!!",0 ;弹窗内容 g_dwMessageBox dd 0 ;MessageBox的地址 MSGBOX: ;下面四条就是重定位的核心代码 call NEXT ;会把 LIST 的地址入站 NEXT: pop ebx ;获取 NEXT 在新进程的地址 sub ebx ,offset NEXT ;可以得到NEXT 在 新进程地址和我们自己进程的地址差值 push MB_OK mov eax, offset g_szTitle ;获取字符串在原进程中的地址 add eax, ebx ;获取字符串在新进程中的地址 push eax ;入栈 mov eax, offset g_szText add eax, ebx push eax push NULL mov eax, offset g_dwMessageBox add eax, ebx mov eax, [eax] call eax ;call MessageBox ;invoke MessageBox,NULL,offset g_szText,offset g_szTitle,MB_OK ret ; ---------------------------------------------------------------------------WinMain proc LOCAL @hWndWinMine :HWND ;窗口句柄 LOCAL @dwPid :HWND ;进程id LOCAL @hProc :HINSTANCE ;线程句柄 LOCAL @pAddr :LPVOID ;申请的内存地址 LOCAL @dwBytesWirites :DWORD ;写入的字节数 LOCAL @dwOldProc:DWORD ;之前的内存属性 invoke FindWindow,NULL ,offset g_szCap ;通过窗口标题获取窗口句柄 mov @hWndWinMine,eax invoke GetWindowThreadProcessId,@hWndWinMine,addr @dwPid ;获取进程id invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid ;创建新线程 mov @hProc,eax invoke VirtualAllocEx,@hProc, NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE ;自动申请内存空间 mov @pAddr,eax ;修改代码区内存属性 invoke VirtualProtect, offset CODE_BEGIN, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc invoke GetModuleHandle, offset g_szUser32 invoke GetProcAddress, eax, offset g_szMessageBox mov g_dwMessageBox, eax ;还原内存属性 invoke VirtualProtect, offset CODE_BEGIN, 1, @dwOldProc, addr @dwOldProc ;在内存中写入代码 invoke WriteProcessMemory,@hProc,@pAddr,\ ;\是换行 offset CODE_BEGIN, offset WinMain - offset CODE_BEGIN,\ addr @dwBytesWirites invoke CreateRemoteThread,@hProc ,NULL,0,@pAddr,NULL,0,NULL mov eax,0 ret WinMain endpstart: invoke WinMain invoke ExitProcess,eaxend start
汇编引擎
使用 XDE
库: 如果装了x32DEBUG ,那么就有需要的库
用C来实现 汇编引擎
创建一个控制台程序
把头文件,dll,lib 拷贝到项目
成员:
1 32位还是64位,true 64位 flase 32位
2 汇编的地址 (跳转类指令必须)
3返回参数,汇编出来的机器码有几个字节
4回调,用不上,空就行
5传出的机器吗
6我们写进去的源码
7错误信息
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include <iostream>#include "XEDParse.h"#pragma comment (lib, "XEDParse_x86.lib")int main(){ XEDPARSE xde = {}; xde.x64 = false; xde.cip = 0x00401000; strcpy_s(xde.instr, sizeof(xde.instr), "mov eax, eax"); XEDPARSE_STATUS stus = XEDParseAssemble(&xde); std::cout << "Hello World!\n"; }
汇编实现汇编引擎
.586.model flat,stdcall option casemap:none include windows.inc include user32.inc include kernel32.inc include msvcrt.inc include AsmXde.inc includelib user32.lib includelib kernel32.lib includelib msvcrt.lib includelib XEDParse_x86.lib WinMain proto :DWORD,:DWORD,:DWORD,:DWORD.data xdep XEDPARSE <FALSE, 00401000h> g_szInstr db "mov ebp, esp", 0.codestart: invoke crt_strcpy, offset xdep._instr, offset g_szInstr invoke XEDParseAssemble, offset xdepend start
.inc
ifndef XDE_INC XDE_INC equ 1XEDPARSE_ERROR equ 0XEDPARSE_OK equ 1XEDPARSE_MAXBUFSIZE equ 256XEDPARSE_MAXASMSIZE equ 16;定义结构体 XEDPARSE struc x64 db 0 ALIGN 8 ;设置对齐值 cip dd 0 ;只用低32位 dd 0 dest_size dd 0 cbUnknown dd 0 dest db XEDPARSE_MAXASMSIZE dup(0) _instr db XEDPARSE_MAXBUFSIZE dup(0) error db XEDPARSE_MAXBUFSIZE dup(0)XEDPARSE endsXEDParseAssemble proto c :ptr XEDPARSE ;函数声明endif
比较强悍的工具是:Asmjit 但只能c使用
作业
周作业
1. 代码注入器
有bug, eip 每次要加它的长度
头文件xde.inc
ifndef XDE_INCXDE_INC equ 1 ;防止重复包含 ;这是原先出错或成功的枚举,换成equ XEDPARSE_ERROR equ 0 XEDPARSE_OK equ 1 ;原先的宏 XEDPARSE_MAXBUFSIZE equ 256 XEDPARSE_MAXASMSIZE equ 16 ;定义结构体 还需要设置对齐值,它的对齐值是8 XEDPARSE struc x64 db 0 ;x64 ALIGN 8 ;设置对齐值,只影响它下一条 cip dd 0 ;它是__int64类型的,但是我们只用低32位,所以就dd ,高32位就不用了 dd 0 ;它的高32位 dest_size dd 0;传出参数,机器码有几个字节 cbUnknown dd 0;回调 dest db XEDPARSE_MAXASMSIZE dup(0) ;机器码 _instr db XEDPARSE_MAXBUFSIZE dup(0);汇编指令 error db XEDPARSE_MAXBUFSIZE dup(0) XEDPARSE ends ;函数声明,C调用约定 ,参数为结构体指针 XEDParseAssemble proto C :ptr XEDPARSE endif
code.inc
include windows.inc include kernel32.inc include user32.inc include Comctl32.inc include shell32.inc include msvcrt.inc include Xde.inc includelib kernel32.lib includelib user32.lib includelib Comctl32.lib includelib shell32.lib includelib msvcrt.lib includelib XEDParse_x86.lib DlgProc PROTO :HWND,:UINT,:WPARAM,:LPARAM .const IDD_DIALOG1 equ 101BTN_SELECT equ 1001BTN_INJECTION equ 1002EDT_PROCESSID equ 1003EDT_CODE equ 1004DLG_PROCESS equ 1000LST_PROCESS equ 1005;#########################################################################.data? hInstance dd ? ;#########################################################################
code.asm
.386 .model flat, stdcall ;32 bit memory model option casemap :none ;case sensitiveinclude CodeIn.inc .data g_szHintProcessID db "进程ID" , 0 ;提示的中文 g_szHintProcessName db "进程名" , 0 ;提示的中文 g_szFmt db "%d",0 ;格式化字符串 g_szProcess db 255 dup(0) ; 进程ID字符串 g_hWnd dd 0 ;主窗口句柄 g_szCode db 255 dup(0) .code ;获取进程信息 GetProcess proc hWin:HWND LOCAL lvcol:LVCOLUMN ;lst的列结构体 LOCAL item:LVITEM ;项的结构体 local hlist LOCAL pe32:PROCESSENTRY32 ;pe32 LOCAL hProcessSnap:HANDLE LOCAL bRet:BOOL ; bool类型的返回值 LOCAL nRowCount:dword ;列数 LOCAL szTh32ProcessID[255]:byte LOCAL oldStyle :dword ;先初始化list控件 invoke GetDlgItem,hWin,LST_PROCESS ;获取控件句柄 mov hlist,eax ;向样式结构体里填数据 mov lvcol.imask,LVCF_FMT or LVCF_WIDTH or LVCF_TEXT or LVCF_SUBITEM mov lvcol.fmt,LVCFMT_CENTER mov lvcol.lx,275 mov lvcol.pszText,offset g_szHintProcessID ;发消息,增加一列 ;invoke SendMessage,hlist,LVM_INSERTCOLUMN,0,addr lvcol invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_INSERTCOLUMN,0,addr lvcol ;第二列 mov lvcol.pszText,offset g_szHintProcessName ;invoke SendMessage,hlist,LVM_INSERTCOLUMN,1,addr lvcol invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_INSERTCOLUMN,1,addr lvcol ;开始获取进程 ;hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); invoke CreateToolhelp32Snapshot,TH32CS_SNAPALL,0 mov hProcessSnap,eax ;Process32First(hProcessSnap, &pe32) mov pe32.dwSize,size PROCESSENTRY32 invoke Process32First,hProcessSnap,addr pe32 mov bRet,eax ;First成功后循环 .if bRet != 0 ;列数先置为0 mov nRowCount ,0 ;开始循环 .REPEAT ;插入第一列 mov eax,nRowCount mov item.iItem , eax; ;行号 从0开始 mov item.iSubItem,0 ;列号 mov item.imask,LVCF_FMT or LVCF_WIDTH or LVCF_TEXT mov eax,pe32.th32ProcessID ;格式化字符串进程ID invoke wsprintf,addr szTh32ProcessID,offset g_szFmt, pe32.th32ProcessID lea eax,szTh32ProcessID mov item.pszText,eax invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_INSERTITEM,0,addr item ;清除内存 invoke crt_memset,addr item,0,size item ;插入第二列 mov eax,nRowCount mov item.iItem , eax; ;行号 mov item.iSubItem,1;列号 mov item.imask , LVCF_FMT or LVCF_WIDTH or LVCF_TEXT; lea eax,pe32.szExeFile ;进程名称 mov item.pszText,eax ;插入其他列 invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_SETITEMTEXT,nRowCount,addr item ;行号++ mov eax,nRowCount inc eax mov nRowCount,eax ;清除内存 lea eax, pe32 invoke crt_memset,eax,0,128 ;重新赋值大小 mov pe32.dwSize,size PROCESSENTRY32 ;Next获取下一个 invoke Process32Next,hProcessSnap,addr pe32 mov bRet,eax .UNTIL bRet == 0 .endif ;获取旧样式 invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_GETEXTENDEDLISTVIEWSTYLE,0,0 ;拼接新样式 or eax,LVS_EX_FULLROWSELECT or eax,LVS_EX_GRIDLINES ;设置选中高亮一行和网格线样式 invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_SETEXTENDEDLISTVIEWSTYLE,0,eax retGetProcess endp OnProc proc hWin:HWND,wParam:WPARAM,lParam :LPARAM LOCAL item:LVITEM ;项的结构体 LOCAL dwSel:dword ;判断控件ID mov eax,wParam .if eax == LST_PROCESS mov esi,lParam assume esi:ptr NMHDR mov ebx,[esi].code assume esi:nothing .if ebx == NM_DBLCLK ;invoke MessageBox,hWin,offset g_szHintProcessID,offset g_szHintProcessID,MB_OK ;获取选中的ID invoke SendDlgItemMessage ,hWin,LST_PROCESS,LVM_GETSELECTIONMARK,0,0 ;选中ID赋值 mov dwSel,eax ;开始获取选中的文本 mov item.iItem , eax; ;行号 mov item.iSubItem,0;列号 mov item.imask , LVCF_FMT or LVCF_WIDTH or LVCF_TEXT; lea eax,g_szProcess mov item.pszText,eax mov item.cchTextMax,size g_szProcess invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_GETITEMTEXT,dwSel,addr item ;给外面的进程文本框赋值 invoke SetDlgItemText,g_hWnd,EDT_PROCESSID,offset g_szProcess ;关闭窗口 invoke EndDialog,hWin,0 .endif .endif retOnProc endp ;进程对话框过程函数 DlgProcessProc proc hWin:HWND,uMsg:UINT, wParam :WPARAM,lParam:LPARAM mov eax,uMsg .if eax==WM_INITDIALOG ;初始化 invoke GetProcess,hWin .elseif eax==WM_CLOSE invoke EndDialog,hWin,0 .elseif eax == WM_NOTIFY invoke OnProc,hWin,wParam,lParam .else mov eax,FALSE ret .endif mov eax,TRUE retDlgProcessProc endp Inject proc LOCAL @hProc:HINSTANCE ; 进程句柄 LOCAL @pAddr :LPVOID ;申请的内存地址 LOCAL @dwBytesWrited:dword ;写入的字节数,它是返回值 LOCAL @dwOldProc:dword ;旧的内存属性 LOCAL @xdep:XEDPARSE LOCAL @machineCode[255]:byte ;字符串 LOCAL @StrLen :dword LOCAL @idx:dword ;把进程ID字符串转成数字 invoke crt_atoi,offset g_szProcess ; 打开进程 invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,eax ;把进程句柄存储一下 mov @hProc,eax ;申请内存 invoke VirtualAllocEx,@hProc,NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE ;把申请的内存地址存一下 mov @pAddr,eax ;解析指令 ;代码注入 ;获取指令长度 invoke crt_strlen,offset g_szCode mov @StrLen,eax ;一个字节一个字节读取 lea esi,g_szCode lea edi,@machineCode .WHILE @StrLen > 0 mov eax,@idx .if byte ptr[esi] == 0dh inc esi .continue .endif .if byte ptr[esi] == 0ah inc esi ;开始注入代码 mov @xdep.x64,FALSE ;64位 mov eax,@pAddr mov @xdep.cip,eax ;内存地址 ;拷贝指令 invoke crt_strcpy ,addr @xdep._instr,addr @machineCode invoke XEDParseAssemble,addr @xdep ;要加上机器码的长度,也就是写入的字节数,确保下次正确写入 mov eax,@pAddr add eax,@dwBytesWrited mov @pAddr,eax ;写入机器码 invoke WriteProcessMemory,@hProc,@pAddr,addr @xdep.dest,@xdep.dest_size,addr @dwBytesWrited ;edi恢复 lea edi,@machineCode invoke crt_memset,addr @machineCode,0,255 ;invoke crt_memset, @xdep, 0,255 invoke crt_memset,addr @xdep._instr,0,255 invoke crt_memset,addr @xdep.dest,0,16 .continue .endif ;读取一个字节 movsb ;长度-- sub @StrLen,1 .ENDW ;创建远程线程 它的地址就是申请的内存地址,那块内存已经写入了自己的代码了 invoke CreateRemoteThread,@hProc,NULL,0,@pAddr,NULL,0,NULL retInject endp start: invoke GetModuleHandle,NULL mov hInstance,eax invoke InitCommonControls invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL invoke ExitProcess,0 ;######################################################################## ; 主对话框过程函数 DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM mov eax,hWin mov g_hWnd,eax mov eax,uMsg .if eax==WM_INITDIALOG ;初始化 .elseif eax==WM_COMMAND mov eax,wParam .if ax == BTN_SELECT ;打开对话框选择进程 invoke CreateDialogParam,hInstance,DLG_PROCESS,NULL,addr DlgProcessProc,NULL .elseif ax == BTN_INJECTION ;代码注入 ;获取输入的代码 invoke GetDlgItemText,hWin,EDT_CODE,offset g_szCode,255 invoke Inject ;解析输入的代码 .endif .elseif eax==WM_CLOSE invoke EndDialog,hWin,0 .else mov eax,FALSE ret .endif mov eax,TRUE
资源界面
2. 扫雷辅助
C++版
#include <Windows.h>#include <Windowsx.h>#define ARY_0 0x1005340#define MINE 0x8FHWND g_hWnd = 0; WNDPROC g_OldProc = 0; LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_MOUSEMOVE: { int x = LOWORD(lParam); int y = HIWORD(lParam); int ary_x = (x + 4) >> 4; int ary_y = ((y - 0x27) >> 4) << 5; if (*(PBYTE)((DWORD)ARY_0 + ary_x + ary_y) == MINE) { SetWindowText(hWnd, "扫雪"); } else { SetWindowText(hWnd, "扫雷"); } } default: break; } return CallWindowProc(g_OldProc, hWnd, Msg, wParam, lParam); }void Init() { g_hWnd = ::FindWindow(NULL, "扫雷"); g_OldProc = (WNDPROC)SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)WindowProc); }BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { Init(); break; } } return TRUE; }
win32asm版
.386 .model flat, stdcall option casemap :noneinclude WinMineDLL.Inc .data g_szBuffSnow db "扫雪", 0 g_szBuffMine db "扫雷", 0 g_szBuffError db "SetWindowLong success", 0 g_szBuffX db "X", 0 g_szBuffY db "Y", 0 g_OldProc dd 0 g_ddMine dd 0 g_hMine dd 0 .code MYWindowProc proc uses ecx esi edi, hwnd:HWND, uMsg:UINT , wParam:WPARAM, lParam:LPARAM .if uMsg == WM_MOUSEMOVE ; coordinate -> ary mov eax, dword ptr [lParam] shr eax, 010h sub eax, 027h sar eax, 04h mov edi, eax shl edi, 5 ; edi - Y movzx eax, word ptr [lParam] add eax, 4h sar eax, 4h mov esi, eax ; esi - X ; ary[0] = 01005340h xor eax, eax mov ebx, 01005340h add ebx, esi add ebx, edi mov al, byte ptr [ebx] ; is mine mov g_ddMine, eax .if g_ddMine == 08Fh invoke SetWindowText, hwnd, offset g_szBuffSnow .elseif invoke SetWindowText, hwnd, offset g_szBuffMine .endif .endif invoke CallWindowProc, g_OldProc, hwnd, uMsg, wParam, lParam retMYWindowProc endp InitDLL proc invoke FindWindow, NULL, offset g_szBuffMine mov g_hMine, eax invoke SetWindowLongW, g_hMine, GWL_WNDPROC, offset MYWindowProc mov g_OldProc, eax .if g_OldProc != NULL invoke MessageBox, NULL, offset g_szBuffError, NULL, MB_OK .endif InitDLL endp DllMain proc hinstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID .if fdwReason == DLL_PROCESS_ATTACH invoke InitDLL .endif mov eax, TRUE retDllMain endp end DllMain
.386.model flat, stdcalloption casemap:noneinclude windows.incinclude user32.incinclude kernel32.inc includelib user32.lib includelib kernel32.lib .data g_hwnd HWND 0 g_windowtitle db "扫雷", 0 g_dProcessId dd 0 g_dThreadId dd 0 g_hHook HHOOK 0 g_sz db "钩子", 0 .code GetMessageProc proc nCode:dword, wParam:WPARAM, lParam:LPARAM .if nCode < 0 invoke CallNextHookEx, g_hHook, nCode, wParam, lParam ret .endif mov eax, lParam assume eax:ptr MSG .if [eax].message == WM_COMMAND invoke MessageBox, NULL, offset g_sz, offset g_sz, MB_OK .endif invoke CallNextHookEx, g_hHook, nCode, wParam, lParam ret GetMessageProc endp DllMain proc hinstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID ;给扫雷安装消息钩子