📄 lion-tut-c29.htm
字号:
ThreadId dd ? <br>
align dword <br>
context CONTEXT <> <br>
<br>
.code <br>
start: <br>
invoke FindWindow, addr ClassName, NULL <br>
.if eax!=NULL <br>
invoke GetWindowThreadProcessId, eax, addr ProcessId <br>
mov ThreadId, eax <br>
invoke DebugActiveProcess, ProcessId <br>
.while TRUE <br>
invoke WaitForDebugEvent, addr DBEvent,
INFINITE <br>
.break .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
<br>
.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
<br>
mov context.ContextFlags,
CONTEXT_CONTROL <br>
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread,
addr context <br>
invoke WriteProcessMemory,
DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr buffer, 2, NULL<br>
invoke MessageBox, 0,
addr TargetPatched, addr AppName, MB_OK+MB_ICONINFORMATION <br>
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
<br>
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
<br>
invoke
ContinueDebugEvent, DBEvent.dwProcessId,DBEvent.dwThreadId, DBG_CONTINUE <br>
.continue
<br>
.endif <br>
.endif <br>
invoke ContinueDebugEvent, DBEvent.dwProcessId,
DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED <br>
.endw <br>
.else <br>
invoke MessageBox, 0, addr SearchFail, addr AppName,MB_OK+MB_ICONERROR
.endif <br>
invoke ExitProcess, 0 <br>
end start </p>
<p>;--------------------------------------------------------------------<br>
; The partial source code of win.asm, our debuggee. It's actually<br>
; the simple window example in tutorial 2 with an infinite loop inserted<br>
; just before it enters the message loop.<br>
;----------------------------------------------------------------------</p>
<p>......<br>
mov wc.hIconSm,eax <br>
invoke LoadCursor,NULL,IDC_ARROW <br>
mov wc.hCursor,eax <br>
invoke RegisterClassEx, addr wc <br>
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ hInst,NULL <br>
mov hwnd,eax <br>
jmp $ <---- Here's our infinite loop. It assembles to EB FE<br>
invoke ShowWindow, hwnd,SW_SHOWNORMAL <br>
invoke UpdateWindow, hwnd <br>
.while TRUE <br>
invoke GetMessage, ADDR msg,NULL,0,0 <br>
.break .if (!eax) <br>
invoke TranslateMessage, ADDR msg <br>
invoke DispatchMessage, ADDR msg <br>
.endw <br>
mov eax,msg.wParam <br>
ret <br>
WinMain endp </p>
<h3>分析:</h3>
<p>invoke FindWindow, addr ClassName, NULL </p>
<p>我们的程序需要用<b>DebugActiveProcess</b>将自己绑定到被调试程序,这需要知道
被调试程序的进程Id。用<b>GetWindowThreadProcessId </b>可以得到该Id,该函数需要
窗口句柄作为参数,因此首先需要知道窗口句柄。<br>
用<b>FindWindow</b>, 我们先指定窗口类的名称,返回的是该类创建的窗口句柄。如
果返回<b>NULL</b>,则表明当前没有该类的窗口。</p>
<p> .if eax!=NULL <br>
invoke GetWindowThreadProcessId, eax, addr ProcessId <br>
mov ThreadId, eax <br>
invoke DebugActiveProcess, ProcessId </p>
<p>得到进程Id后,我们调用<b>DebugActiveProcess</b>。这样就进入等待调试事件的循
环中。</p>
<p> .if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
<br>
mov context.ContextFlags,
CONTEXT_CONTROL <br>
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread,
addr context </p>
<p>当得到<b> CREATE_PROCESS_DEBUG_INFO</b>, 这意味着被调试进程已经被暂停运行了。
我们就可以对该进程动手术了。本例中,我们将用NOPs ( 90h 90h)覆盖被调试进程中的无
限循环指令(0EBh 0FEh) 。
<br>
首先,需要得到该指令的地址。由于在我们的程序绑定到被调试程序时,被调试程序已经
处于循环语句中了,eip总是指向该指令。我们所要做的是得到eip的值。我们将使用
<b>GetThreadContext</b>来达到此目的。将上下文结构成员中<b>ContextFlags</b>设置
为<b>CONTEXT_CONTROL </b>,这样告诉<b>GetThreadContext</b>我们需要它去填充<b>上下
文</b>结构的成员中的"控制"寄存器。
</p>
<p> invoke WriteProcessMemory,
DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr buffer, 2, NULL</p>
<p>得到eip的值以后,可以调用<b>WriteProcessMemory</b>来用NOPs覆盖"jmp $"
指令,这样将使被调试程序退出无限循环。在向用户显示了信息之后,调用<b>ContinueDebugEvent</b>
来恢复被调试程序的运行。由于指令"jmp $"已被Nops覆盖,被调试程序将继续
显示窗口,并进入消息循环。证据是我们在屏幕上观察到了次窗口。
</p>
<p>另一个例子与此稍有不同,它是将被调试程序从无限循环中中断。
</p>
<p> .......<br>
.......<br>
.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT <br>
mov context.ContextFlags, CONTEXT_CONTROL <br>
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread,
addr context <br>
add context.regEip,2 <br>
invoke SetThreadContext,DBEvent.u.CreateProcessInfo.hThread,
addr context <br>
invoke MessageBox, 0, addr LoopSkipped, addr AppName, MB_OK+MB_ICONINFORMATION
<br>
.......<br>
....... </p>
<p>这里仍调用<b>GetThreadContext</b>来获取eip值,但没有去覆盖"jmp $"
指令,而是将<b> regEip</b>加2,从而"跳过"该指令。结果是当被调试程序
重新获得控制权时,将恢复执行在"jmp $"后的指令。</p>
<p>现在你可以体会到Get/SetThreadContext的威力了。你也可以修改其他寄存器映象,这
些值将直接反映到被调试程序中。甚至你可以把int 3h指令插入到被调试进程中。产生断点。
<strong> </strong></p>
<HR SIZE=1>
<DIV align=center> <font face="宋体">
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/textclick"></SCRIPT>
<BR>
</font></DIV>
<font face="宋体"><!-- 10:1 文本广告交换 --> </font>
<DIV align=center> <font face="宋体">
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/c21.htm"></SCRIPT>
<!-- 10:1 文本广告交换 --></font></DIV>
<HR SIZE=1>
<div align="center"> This article come from Iczelion's asm page, 翻译 xjg1124@163.net. Welcom to <a href="http://asm.yeah.net">http://asm.yeah.net</a></div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -