WEB开发网
开发学院软件开发汇编语言 汇编教程:Win32调试API(2) 阅读

汇编教程:Win32调试API(2)

 2008-10-14 09:35:25 来源:WEB开发网   
核心提示:例:第一个例子演示DebugActiveProcess的使用,首先,汇编教程:Win32调试API(2)(2),需要在Windows显示在屏幕上以前运行一个待调试程序win.exe,该程序将处于无限循环运行状态中,这些值将直接反映到被调试程序中,甚至你可以把int 3h指令插入到被调试进程中,然后你运行例子程序,它将把

例:

第一个例子演示DebugActiveProcess的使用。首先,需要在Windows显示在屏幕上以前运行一个待调试程序win.exe,该程序将处于无限循环运行状态中。然后你运行例子程序,它将把自己与win.exe连接起来,并且修改win.exe的代码,这样win.exe将退出无限循环状态而显示自己的窗口。


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\user32.lib
.data
AppName db "Win32 Debug Example no.2",0
ClassName db "SimpleWinClass",0
SearchFail db "Cannot find the target process",0
TargetPatched db "Target patched!",0
buffer dw 9090h
.data?
DBEvent DEBUG_EVENT <>
ProcessId dd ?
ThreadId dd ?
align dword
context CONTEXT <>
.code
start:
invoke FindWindow, addr ClassName, NULL
.if eax!=NULL
invoke GetWindowThreadProcessId, eax, addr ProcessId
mov ThreadId, eax
invoke DebugActiveProcess, ProcessId
.while TRUE
invoke WaitForDebugEvent, addr DBEvent, INFINITE
.break .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context
invoke WriteProcessMemory, DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr buffer, 2, NULL
invoke MessageBox, 0, addr TargetPatched, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId,DBEvent.dwThreadId, DBG_CONTINUE
.continue
.endif
.endif
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
.endw
.else
invoke MessageBox, 0, addr SearchFail, addr AppName,MB_OK+MB_ICONERROR .endif
invoke ExitProcess, 0
end start
;--------------------------------------------------------------------
; The partial source code of win.asm, our debuggee. It's actually
; the simple window example in tutorial 2 with an infinite loop inserted
; just before it enters the message loop.
;----------------------------------------------------------------------
......
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ hInst,NULL
mov hwnd,eax
jmp $ <---- Here's our infinite loop. It assembles to EB FE
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.break .if (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp
分析:


invoke FindWindow, addr ClassName, NULL

我们的程序需要用DebugActiveProcess将自己绑定到被调试程序,这需要知道被调试程序的进程Id。用GetWindowThreadProcessId 可以得到该Id,该函数需要窗口句柄作为参数,因此首先需要知道窗口句柄。本文来自编程入门网

用FindWindow, 我们先指定窗口类的名称,返回的是该类创建的窗口句柄。如 果返回NULL,则表明当前没有该类的窗口。


.if eax!=NULL
invoke GetWindowThreadProcessId, eax, addr ProcessId
mov ThreadId, eax
invoke DebugActiveProcess, ProcessId

得到进程Id后,我们调用DebugActiveProcess。这样就进入等待调试事件的循环中。


.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context

当得到 CREATE_PROCESS_DEBUG_INFO, 这意味着被调试进程已经被暂停运行了。 我们就可以对该进程动手术了。本例中,我们将用NOPs ( 90h 90h)覆盖被调试进程中的无 限循环指令(0EBh 0FEh) 。

首先,需要得到该指令的地址。由于在我们的程序绑定到被调试程序时,被调试程序已经 处于循环语句中了,eip总是指向该指令。我们所要做的是得到eip的值。我们将使用 GetThreadContext来达到此目的。将上下文结构成员中ContextFlags设置 为CONTEXT_CONTROL ,这样告诉GetThreadContext我们需要它去填充上下 文结构的成员中的"控制"寄存器。


invoke WriteProcessMemory, DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr buffer, 2, NULL


  得到eip的值以后,可以调用WriteProcessMemory来用NOPs覆盖"jmp $" 指令,这样将使被调试程序退出无限循环。在向用户显示了信息之后,调用ContinueDebugEvent 来恢复被调试程序的运行。由于指令"jmp $"已被Nops覆盖,被调试程序将继续 显示窗口,并进入消息循环。证据是我们在屏幕上观察到了次窗口。

另一个例子与此稍有不同,它是将被调试程序从无限循环中中断。


.......
.......
.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context
add context.regEip,2
invoke SetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context
invoke MessageBox, 0, addr LoopSkipped, addr AppName, MB_OK+MB_ICONINFORMATION
.......
.......

这里仍调用GetThreadContext来获取eip值,但没有去覆盖"jmp $" 指令,而是将 regEip加2,从而"跳过"该指令。结果是当被调试程序 重新获得控制权时,将恢复执行在"jmp $"后的指令。

现在你可以体会到Get/SetThreadContext的威力了。你也可以修改其他寄存器映象,这些值将直接反映到被调试程序中。甚至你可以把int 3h指令插入到被调试进程中。产生断点。

上一页  1 2 

Tags:汇编 教程 Win

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接