汇编学习实战修改win32扫雷

Posted 不会写代码的丝丽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编学习实战修改win32扫雷相关的知识,希望对你有一定的参考价值。

概述

概述下面的游戏我们都玩过

这个扫雷的程序点击右上角的关闭按钮会直接退出整个程序。我们利用od实现如下效果:
点击右上角弹出一个dialog,让用户确认是否是否关闭。

思路概念

win程序有消息机制,关闭的时候会触发WM_CLOSE消息.因此我们首先断点这个消息看看大致逻辑。

OD窗口点击查看->窗口(无数据请右键刷新)


选中对应的窗口选中消息断点。


接着点击扫雷关闭按钮触发关闭消息


这里利用断点分析后续流程


我首先记录下结论:

  1. 01001c23 如果是close消息会跳转到010021a2
  2. 010021a2 会将消息分发到系统默认处理。
  3. 010021bb 将会返回过程函数

于是我们利用如下思想完成需求:
01001c23跳转我们的额外我们内部插入新的代码。
内部代码如果是close消息那么弹出dialog,如果不是跳转回010021a2.
如果用户点击dialog确认关闭按钮,那么跳转回010021a2
如果用用户点击dialog取消按钮,那么跳转到010021bb 从而跳过关闭事件

于是我们在某处写入如下代码:


疑问点你怎么知道MessageBoxA函数位置?



od如何保存修改的代码到新的exe?


注入与重定位

假设我们需要单独写一个程序,对扫雷进行注入弹出一个dialog.其需要考虑重定位问题.


执行上面的按钮会执行注入一段代码到扫雷程序.

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include dlgdemo.inc


.data
	g_szWinimeName db "扫雷",0
	g_szUser32 db "user32",0
	g_szMessageBoxA db "MessageBoxA",0
.code


;被注入的代码
INJECT_CODE:
	;这里主要让其把字符串也拷贝过去
	jmp INJECT_MESGBOX
	g_szHello db "helloworld",0
	;存储messagbox函数的相对位置
	;messagbox是dll库地址,因此每个程序相对dll的位置是固定的
	g_pfnMessageBox dd 0
	
INJECT_MESGBOX:
	;重定向代码正确位置,因为注入后offset是原始程序的地址,而不是目标程序的地址
	call NEXT
NEXT:
   ;call后会存储当前返回地址到栈。此处弹出返回地址计算相对偏移
	pop ebx
	;减去之后得到两个程序之间的偏移差
	sub ebx,offset NEXT
	;得到字符串的地址
	lea eax,[offset g_szHello+ebx]
	;得到messagebox的相对位置
	lea ecx,[offset g_pfnMessageBox+ebx]
	
	push MB_OK
	push NULL
	push eax
	push NULL
	call dword ptr [ecx]
	ret
		
INJECT_END:
	g_dwCodeSize dd $ - offset INJECT_CODE

;InitInject 主要用于让其代码段可读可写	
;g_pfnMessageBox存储在代码段但是我们需要让其存储MessageBoxA函数地址
InitInject proc
	LOCAL @hUser32:HANDLE
	LOCAL @dwOldProc:DWORD
		
	invoke VirtualProtect,offset INJECT_CODE,g_dwCodeSize,PAGE_EXECUTE_READWRITE,addr @dwOldProc
	
	invoke GetModuleHandle,offset g_szUser32
	;存储模块句柄
	mov @hUser32,eax
	
	invoke GetProcAddress,@hUser32,offset g_szMessageBoxA
	
	mov g_pfnMessageBox,eax
	
	invoke VirtualProtect,offset INJECT_CODE,g_dwCodeSize,@dwOldProc,addr @dwOldProc
	 
	ret

InitInject endp



Inject proc
	LOCAL @hWnd:HWND
	LOCAL @dwPid:DWORD
	LOCAL @hProc:HWND
	LOCAL @lpAddr:LPVOID
	LOCAL @dwBytesWrited:DWORD
	LOCAL @hUser32:HANDLE
	
	
	int 3
	
	;得到窗口句柄
	invoke FindWindow,NULL,offset g_szWinimeName
	
	mov @hWnd,eax
	
	;得到进程的id
	invoke GetWindowThreadProcessId,@hWnd,addr @dwPid
	
	;得到进程句柄并获取所有权限
	invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid
	
	;保存进程句柄
	mov @hProc,eax
	
	;申请内存
	invoke VirtualAllocEx,@hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
	
	;保存内存引用
	mov @lpAddr,eax
	
	;int 3
	
	
	;内存写入
	invoke  WriteProcessMemory,@hProc,@lpAddr,offset INJECT_CODE,offset INJECT_END - offset INJECT_CODE,addr @dwBytesWrited
	
	;创建线程
	invoke CreateRemoteThread,@hProc,NULL,0,@lpAddr,NULL,0,NULL
		
	ret

Inject 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,uMsg
	.if eax==WM_INITDIALOG

	.elseif eax==WM_COMMAND
		mov edx,wParam
		.if dx==btn_xxx
	
			invoke InitInject
			;invoke MessageBox,hWin,offset g_szHello,NULL,MB_OK
			invoke Inject
		.endif
	.elseif eax==WM_CLOSE

		
		invoke EndDialog,hWin,0
	.else
		mov		eax,FALSE
		ret
	.endif
	mov		eax,TRUE
	ret

DlgProc endp

end start

以上是关于汇编学习实战修改win32扫雷的主要内容,如果未能解决你的问题,请参考以下文章

32位汇编第五讲,逆向实战干货,(OD)快速定位扫雷内存.

python实战教程之自动扫雷

如何修改汇编win32中 static控件的字体颜色

扫雷游戏 c语言

win32汇编中nmake用法

WIN32 汇编直接CALL 与间接CALL ?