2026/1/26 10:15:53
网站建设
项目流程
怎么做购物车网站,电子商务网站建设投资预算,机关网站建设工程总结,网站制作建设是做什么我们继续Win32调试API的话题。在本章中#xff0c;我们将要学习如何修改被调试程序。下载 the example 理论:在前面一章中#xff0c;我们学会了如何装载被调试的进程以及如何处理进程中发生的事件。为了有实际用途#xff0c;我们的程序应具有修改被调试程序的能力。有好几…我们继续Win32调试API的话题。在本章中我们将要学习如何修改被调试程序。下载 the example理论:在前面一章中我们学会了如何装载被调试的进程以及如何处理进程中发生的事件。为了有实际用途我们的程序应具有修改被调试程序的能力。有好几个API函数用于这一目的。ReadProcessMemory该函数允许你去读指定的进程的内存。函数原型如下:ReadProcessMemory proto hProcess:DWORD, lpBaseAddress:DWORD, lpBuffer:DWORD, nSize:DWORD, lpNumberOfBytesRead:DWORDhProcess 待读进程的句柄.lpBaseAddress 目标进程中待读内存起始地址。例如如果你想要读目标 进程中从地址401000h开始的4个字节该参数值应置为401000h。lpBuffer 接收缓冲区地址nSize 想要读的字节数。lpNumberOfBytesRead 记录实际读取的字节数的变量地址。如果对这个值 不关心填入NULL即可。WriteProcessMemory 是对应于ReadProcessMemory的函数通过它 可以写目标进程的内存。其参数和ReadProcessMemory 相同。理解接下去的两个函数需要一些进程上下文的有关背景知识。在象Windows这样的 多任务操作系统中同一时间里可能运行着几个程序。Windows分配给每个线程一个 时间片当时间片结束后Windows将冻结当前线程并切换到下一具有最高优先级的 线程。在切换之前Windows将保存当前进程的寄存器的 内容这样当在该线程再 次恢复运行时Windows可以恢复最近一次线程运行的*环境*。保存的寄存器内容总 称为进程上下文。现在回到我们的主题。当一个调试事件发生时Windows暂停被调试进程并保存其 进程上下文。由于进程被暂停运行我们可以确信其进程上下文内容将保持不变。 可以用GetThreadContext来获取进程上下文内容并且也可以用GetThreadContext 来修改进程上下文内容。这两个函数威力非凡。有了他们对被调试进程你就具有象VxD的能力: 如改变其寄 存器内容而在被调试程序恢复运行前这些值将会写回寄存器中。在进程上下文中 所做的任何改动将都会反映到被调试程序中。想象一下: 甚至可以改变eip寄存器 的内容这样你可以让程序运行到你想要的任何地方! 在正常情况下是不可能做到这 一点的。GetThreadContext proto hThread:DWORD, lpContext:DWORDhThread 你想要获得上下文的线程句柄lpContext 函数成功返回时用来保存上下文内容的结构指针。SetThreadContext 参数相同。让我们来看看上下文的结构:CONTEXT STRUCTContextFlags dd ?;----------------------------------------------------------------------------------------------------------;当ContextFlags包含CONTEXT_DEBUG_REGISTERS返回本部分;-----------------------------------------------------------------------------------------------------------iDr0 dd ?iDr1 dd ?iDr2 dd ?iDr3 dd ?iDr6 dd ?iDr7 dd ?;----------------------------------------------------------------------------------------------------------;当ContextFlags包含CONTEXT_FLOATING_POINT返回本部分;-----------------------------------------------------------------------------------------------------------FloatSave FLOATING_SAVE_AREA ;----------------------------------------------------------------------------------------------------------;当ContextFlags包含CONTEXT_SEGMENTS返回本部分;-----------------------------------------------------------------------------------------------------------regGs dd ?regFs dd ?regEs dd ?regDs dd ?;----------------------------------------------------------------------------------------------------------;当ContextFlags包含CONTEXT_INTEGER返回本部分;-----------------------------------------------------------------------------------------------------------regEdi dd ?regEsi dd ?regEbx dd ?regEdx dd ?regEcx dd ?regEax dd ?;----------------------------------------------------------------------------------------------------------;当ContextFlags包含CONTEXT_CONTROL返回本部分;-----------------------------------------------------------------------------------------------------------regEbp dd ?regEip dd ?regCs dd ?regFlag dd ?regEsp dd ?regSs dd ?;----------------------------------------------------------------------------------------------------------;当ContextFlags包含CONTEXT_EXTENDED_REGISTERS返回本部分;-----------------------------------------------------------------------------------------------------------ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?) CONTEXT ENDS可以看出该结构中的成员是对实际处理器的寄存器的模仿。在使用该结构之前 要在ContextFlags 中指定哪些寄存器组用来读写。如要访问所有的寄存器 你可以置ContextFlags 为CONTEXT_FULL 。或者只访问regEbp, regEip, regCs, regFlag, regEsp 或 regSs, 应置ContextFlags 为 CONTEXT_CONTROL 。在使用结构CONTEXT 时还应记住: 它必须是双字对齐的否则在NT下将得 到奇怪的结果。可以在定义前加上align dword。例如:align dwordMyContext CONTEXT 例:第一个例子演示DebugActiveProcess的使用。首先需要在Windows显示在屏幕上以前运行一个待调试程序win.exe该程序将处于无限循环运行状态中。然后你运行例子程序它将把自己与win.exe连接起来并且修改win.exe的代码这样win.exe将退出无限循环状态而显示自己的窗口。.386.model flat,stdcalloption casemap:noneinclude \masm32\include\windows.incinclude \masm32\include\kernel32.incinclude \masm32\include\comdlg32.incinclude \masm32\include\user32.incincludelib \masm32\lib\kernel32.libincludelib \masm32\lib\comdlg32.libincludelib \masm32\lib\user32.lib.dataAppName db Win32 Debug Example no.2,0ClassName db SimpleWinClass,0SearchFail db Cannot find the target process,0TargetPatched db Target patched!,0buffer dw 9090h.data?DBEvent DEBUG_EVENT ProcessId dd ?ThreadId dd ?align dwordcontext CONTEXT .codestart:invoke FindWindow, addr ClassName, NULL.if eax!NULLinvoke GetWindowThreadProcessId, eax, addr ProcessIdmov ThreadId, eaxinvoke DebugActiveProcess, ProcessId.while TRUEinvoke WaitForDebugEvent, addr DBEvent, INFINITE.break .if DBEvent.dwDebugEventCodeEXIT_PROCESS_DEBUG_EVENT.if DBEvent.dwDebugEventCodeCREATE_PROCESS_DEBUG_EVENTmov context.ContextFlags, CONTEXT_CONTROLinvoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr contextinvoke WriteProcessMemory, DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr buffer, 2, NULLinvoke MessageBox, 0, addr TargetPatched, addr AppName, MB_OKMB_ICONINFORMATION.elseif DBEvent.dwDebugEventCodeEXCEPTION_DEBUG_EVENT.if DBEvent.u.Exception.pExceptionRecord.ExceptionCodeEXCEPTION_BREAKPOINTinvoke ContinueDebugEvent, DBEvent.dwProcessId,DBEvent.dwThreadId, DBG_CONTINUE.continue.endif.endifinvoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED.endw.elseinvoke MessageBox, 0, addr SearchFail, addr AppName,MB_OKMB_ICONERROR .endifinvoke ExitProcess, 0end start;--------------------------------------------------------------------; The partial source code of win.asm, our debuggee. Its actually; the simple window example in tutorial 2 with an infinite loop inserted; just before it enters the message loop.;----------------------------------------------------------------------......mov wc.hIconSm,eaxinvoke LoadCursor,NULL,IDC_ARROWmov wc.hCursor,eaxinvoke RegisterClassEx, addr wcINVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ hInst,NULLmov hwnd,eaxjmp $ ---- Heres our infinite loop. It assembles to EB FEinvoke ShowWindow, hwnd,SW_SHOWNORMALinvoke UpdateWindow, hwnd.while TRUEinvoke GetMessage, ADDR msg,NULL,0,0.break .if (!eax)invoke TranslateMessage, ADDR msginvoke DispatchMessage, ADDR msg.endwmov eax,msg.wParamretWinMain endp分析:invoke FindWindow, addr ClassName, NULL我们的程序需要用DebugActiveProcess将自己绑定到被调试程序这需要知道被调试程序的进程Id。用GetWindowThreadProcessId 可以得到该Id该函数需要窗口句柄作为参数因此首先需要知道窗口句柄。用FindWindow, 我们先指定窗口类的名称返回的是该类创建的窗口句柄。如 果返回NULL则表明当前没有该类的窗口。.if eax!NULLinvoke GetWindowThreadProcessId, eax, addr ProcessIdmov ThreadId, eaxinvoke DebugActiveProcess, ProcessId得到进程Id后我们调用DebugActiveProcess。这样就进入等待调试事件的循环中。.if DBEvent.dwDebugEventCodeCREATE_PROCESS_DEBUG_EVENTmov context.ContextFlags, CO