0 0 0

科锐学习笔记-第三阶段-调试器 03 单步

admin
173 0

本文共计21080个字,预计阅读时长84.3分钟。

目录

单步 

TF - 置位(置1  复位就是置0) 

单步步入 -- 遇到call便入 

img 

单步步过  -- 遇到call不入 

img 

区分一条指令是不是call指令:    通过反汇编引擎,反汇编出来是个 call 说明 就是 call指令 

代码实现


.586 
.model flat,stdcall 
option casemap:none 

  include windows.inc 
  include user32.inc 
  include kernel32.inc 
  include msvcrt.inc 
  include udis86.inc 

  includelib user32.lib 
  includelib kernel32.lib 
  includelib msvcrt.lib 
  includelib libudis86.lib 

.data 
   g_szExe db "winmine.exe", 0     ;打开的进程 
   g_hExe  dd 0 
   g_szEXCEPTION_DEBUG_EVENT         db "EXCEPTION_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szCREATE_THREAD_DEBUG_EVENT     db "CREATE_THREAD_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szCREATE_PROCESS_DEBUG_EVENT    db "CREATE_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szEXIT_THREAD_DEBUG_EVENT       db "EXIT_THREAD_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szEXIT_PROCESS_DEBUG_EVENT      db "EXIT_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szLOAD_DLL_DEBUG_EVENT          db "LOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szUNLOAD_DLL_DEBUG_EVENT        db "UNLOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szOUTPUT_DEBUG_STRING_EVENT     db "OUTPUT_DEBUG_STRING_EVENT", 0dh, 0ah, 0 

   g_szLoadDllFmt   db "%08X %s", 0dh, 0ah, 0 
   g_szwLoadDllFmt   dw '%', '0', '8', 'X', ' ', '%', 's', 0dh, 0ah, 0 
   g_szBpFmt  db "CC异常 %08X", 0dh, 0ah, 0 
   g_szSsFmt  db "单步异常 %08X", 0dh, 0ah, 0 

   g_szInputCmd db "选择命令:", 0dh, 0ah 
               db "是:单步步入", 0dh, 0ah 
               db "否:单步步过", 0dh, 0ah 
               db "取消:直接运行", 0dh, 0ah,0 

   g_btOldCode db 0               ;下断点之前的指令 
   g_dwBpAddr  dd   010021a9h     ;下断点的地址 
   g_byteCC   db 0CCh             ;CC指令 

   g_szOutPutAsm db 64 dup(0)    ;要进行反汇编的指令 

   g_szOutPutAsmFmt db "%08x %-20s %-20s", 0dh, 0ah, 0     ;指令反汇编输出格式  

   g_ud_obj db 1000h dup(0) 

   g_bIsCCStep dd FALSE          ;是否是CC单步 

   g_bIsStepStep dd FALSE        ;是否是T命令单步 

.code   

;判断是否是 call 指令 
IsCallMn  proc uses esi edi pDE:ptr DEBUG_EVENT, pdwCodeLen:DWORD 
   LOCAL @dwBytesOut:DWORD 
   LOCAL @dwOff:DWORD 
   LOCAL @pHex:LPSTR 
   LOCAL @pAsm:LPSTR 

   mov esi, pDE 
   assume esi:ptr DEBUG_EVENT 

     ;显示下一条即将执行的指令   从内存读取要反汇编指令 (20个字节)到  g_szOutPutAsm 
   invoke ReadProcessMemory, g_hExe, [esi].u.Exception.pExceptionRecord.ExceptionAddress, \ 
       offset g_szOutPutAsm, 20, addr @dwBytesOut 

   ;初始化结构体   
   invoke ud_init, offset g_ud_obj 
   invoke ud_set_input_buffer, offset g_ud_obj, offset g_szOutPutAsm, 20 
   invoke ud_set_mode, offset g_ud_obj, 32 
   invoke ud_set_syntax, offset g_ud_obj, offset ud_translate_intel 
   invoke ud_set_pc, offset g_ud_obj, [esi].u.Exception.pExceptionRecord.ExceptionAddress 

   invoke ud_disassemble, offset g_ud_obj 

   ;获取EIP  当前指令地址 
   invoke ud_insn_off, offset g_ud_obj 
   mov @dwOff, eax 

   ;获取机器码 
   invoke ud_insn_hex, offset g_ud_obj 
   mov @pHex, eax 

   ;获取反汇编结果 
   invoke ud_insn_asm, offset g_ud_obj 
   mov @pAsm, eax 

   ;获取指令长度  
   invoke ud_insn_len, offset g_ud_obj 
   mov edi, pdwCodeLen 

   mov [edi], eax 

   ;输出反汇编结果 
   invoke crt_printf, offset g_szOutPutAsmFmt, @dwOff, @pHex, @pAsm 

   mov eax, @pAsm                 ;将反汇编字符数组的首地址给eax 
   .if dword ptr [eax] == 'llac'  ;call在内存里面是 小尾方式存储 
       mov eax, TRUE 
       ret         
   .endif 

   mov eax, FALSE 
   ret 

IsCallMn endp 

;将TF置位(置1) 
SetTF proc dwTID:DWORD 
   LOCAL @hThread:HANDLE  
   LOCAL @ctx:CONTEXT 

   invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID 
   mov @hThread, eax 

   mov @ctx.ContextFlags, CONTEXT_FULL 
   invoke GetThreadContext, @hThread, addr @ctx 

   ;将TF置1 
   or @ctx.regFlag, 100h 

   invoke SetThreadContext, @hThread, addr @ctx 
   invoke CloseHandle, @hThread 

   ret 

SetTF endp 

;回退EIP 
DecEIP proc dwTID:DWORD 
   LOCAL @hThread:HANDLE  
   LOCAL @ctx:CONTEXT 

   invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID 
   mov @hThread, eax 

   mov @ctx.ContextFlags, CONTEXT_FULL 
   invoke GetThreadContext, @hThread, addr @ctx 

   dec @ctx.regEip 

   invoke SetThreadContext, @hThread, addr @ctx 
   invoke CloseHandle, @hThread 
   ret 

DecEIP endp 

;设置断点 
SetBp proc   
   LOCAL @dwBytesOut:DWORD   
   LOCAL @dwOldProc:DWORD   ;修改之前的内存属性 

   ;修改内存属性 
   invoke VirtualProtect, g_dwBpAddr, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc 

   ;保存指定地址的指令, 
   invoke ReadProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut 

   ;在指定地址 写入cc 
   invoke WriteProcessMemory, g_hExe,  g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut 

   ;还原内存属性 
   invoke VirtualProtect, g_dwBpAddr, 1, @dwOldProc, addr @dwOldProc 
   ret 

SetBp endp 

;选择指令 
InputCmd proc uses esi pDE:ptr DEBUG_EVENT  
   LOCAL @bIsCall:BOOL        ;是否call指令 
   LOCAL @dwCodeLen:DWORD     ;指令长度 

   mov esi, pDE 
   assume esi:ptr DEBUG_EVENT 

   ;判断是否是call指定以及获取指令长度 
   invoke IsCallMn, pDE, addr @dwCodeLen 
   mov @bIsCall, eax    ;保存判断结果 

   invoke MessageBox, NULL, offset g_szInputCmd, NULL, MB_YESNOCANCEL 

   .if eax == IDYES 
       ;单步步入,直接TF置1 
       invoke SetTF, [esi].dwThreadId 

       ;单步中需要处理T命令 
       mov g_bIsStepStep, TRUE 
   .elseif eax == IDNO 
       ;单步步过,判断是否是call 
       .if @bIsCall 
           ;call指令,在下一条指令设置断点 
           mov eax, [esi].u.Exception.pExceptionRecord.ExceptionAddress      ;获取call指令地址 
           add eax, @dwCodeLen     ;获取call下条指令地址  call指令地址 +  指令长度  
           mov g_dwBpAddr, eax     
           invoke SetBp            ;设置断点 

       .else   
           ;单步步入,直接TF置1 
           invoke SetTF, [esi].dwThreadId 

           ;单步中需要处理T命令 
           mov g_bIsStepStep, TRUE    

       .endif 

   .else 
       ;直接运行 

   .endif 
   ret 

InputCmd endp 

OnException proc uses esi pDE:ptr DEBUG_EVENT  
   LOCAL @dwOldProc:DWORD   ;修改之前的内存属性 
   LOCAL @dwBytesOut:DWORD   
   mov esi, pDE 
   assume esi:ptr DEBUG_EVENT 

   .if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT 
       ;判断是否是自己的CC 
       mov eax, [esi].u.Exception.pExceptionRecord.ExceptionAddress 
       .if eax != g_dwBpAddr 
           ;不是自己的CC异常,不处理 
           mov eax, DBG_EXCEPTION_NOT_HANDLED  
           ret 
       .endif 

       ;处理自己的CC异常 
       invoke crt_printf, offset g_szBpFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress 

       ;修改内存属性 
       invoke VirtualProtect, g_dwBpAddr, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc 

       ;恢复之前指令 
       invoke WriteProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut  

       ;还原内存属性 
       invoke VirtualProtect, g_dwBpAddr, 1, @dwOldProc, addr @dwOldProc 

       ;设置单步 
       invoke SetTF, [esi].dwThreadId 
       invoke DecEIP, [esi].dwThreadId 

       ;单步中需要处理CC的单步 
       mov g_bIsCCStep,  TRUE 

       ;输入命令 
       invoke InputCmd, pDE 

       mov eax, DBG_CONTINUE 
       ret 
   .endif 

   ;单步来了 
   .if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP 

       ;处理自己的单步 
       invoke crt_printf, offset g_szSsFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress 

       ;处理CC的单步 
       .if g_bIsCCStep == TRUE 
           mov g_bIsCCStep, FALSE 

           ;重设断点, 重新写入CC 
           ;invoke WriteProcessMemory, g_hExe,  g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut 
       .endif 

       ;处理T命令的单步 
       .if g_bIsStepStep == TRUE 
           mov g_bIsStepStep, FALSE 

           invoke InputCmd, pDE 
       .endif 

       mov eax, DBG_CONTINUE 
       ret 
   .endif 

   assume esi:nothing 

   mov eax, DBG_EXCEPTION_NOT_HANDLED  
   ret 

OnException endp 

OnCreateProcess proc  

   ;设置断点 
   invoke SetBp 

   ret 

OnCreateProcess endp 

main proc 
   LOCAL @si:STARTUPINFO 
   LOCAL @pi:PROCESS_INFORMATION 
   LOCAL @de:DEBUG_EVENT  
   LOCAL @dwStatus:DWORD 

   invoke RtlZeroMemory, addr @si, size @si 
   invoke RtlZeroMemory, addr @pi, size @pi 
   invoke RtlZeroMemory, addr @de, size @de 

   mov @dwStatus, DBG_CONTINUE 
   ;建立调试会话 
   invoke CreateProcess, NULL, offset g_szExe, NULL, NULL, FALSE, \ 
       DEBUG_ONLY_THIS_PROCESS,\ 
       NULL, NULL,\ 
       addr @si,\ 
       addr @pi 
   .if !eax 
       ret 
   .endif  
   mov eax, @pi.hProcess 
   mov g_hExe, eax 

   ;循环接受调试事件 
   .while TRUE 
       invoke WaitForDebugEvent, addr @de, INFINITE 

       ;处理调试事件 
       .if @de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT 
           ;invoke crt_printf, offset g_szEXCEPTION_DEBUG_EVENT 
           invoke OnException, addr @de 
           mov @dwStatus, eax 
       .elseif @de.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT 
           invoke crt_printf, offset g_szCREATE_THREAD_DEBUG_EVENT

反汇编头文件 

udis86.inc


ifndef UDIS86_H 

UDIS86_H equ 

ud_init proto c ud:ptr 
ud_set_input_buffer proto c ud:ptr, pBuf:ptr, nSize:dword 
ud_set_mode proto c ud:ptr, nBit:dword 
ud_set_syntax proto c ud:ptr, translate:ptr 
ud_translate_intel proto c ud:ptr 
ud_set_pc proto c ud:ptr, eip:dword 
ud_disassemble proto c ud:ptr 
ud_insn_asm proto c ud:ptr 
ud_insn_len proto c ud:ptr 
ud_insn_off proto c ud:ptr 
ud_insn_hex proto c ud:ptr 

endif 
``` 

## 反单步 

单步主要是通过 TF 置位 来实现的,所以检查单步的一般思路是  检查TF 位 

获取TF位的方法是  获取 标志寄存器 

;pushfd 

;and dword ptr [esp], 100h 

;jz CONTIUE 

;invoke MessageBox, NULL, NULL, NULL, MB_OK 

​  

但是通过调试发现并不能实现,应该  代码执行完 TF 已经被还原为0 了此时在入栈,它的值就是0 ,所以没办法检查判断是否为1,因此要反其道行之 ,自己置个单步, 正常情况下自己可以收到一个单步异常,但处于调试状况时就无法收到,因为被调试器收了,调试器收到之后就继续往后执行 

``` 
.586 
.model flat,stdcall 
option casemap:none 

  include windows.inc 
  include user32.inc 
  include kernel32.inc 

  includelib user32.lib 
  includelib kernel32.lib 

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD 

.data 
  ClassName db "MainWinClass",0 
  AppName  db "Main Window",0 

.data? 
  hInstance HINSTANCE ? 
  CommandLine LPSTR ? 

.code 

; --------------------------------------------------------------------------- 

start: 
invoke GetModuleHandle, NULL 
mov    hInstance,eax 

invoke GetCommandLine 
mov    CommandLine,eax 

invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT 
invoke ExitProcess,eax 

;SEH异常回调函数 
F0Handler proc uses esi edi pER:ptr EXCEPTION_RECORD, pFrame:dword, pContext:ptr CONTEXT, pDC:dword 

   assume esi:ptr EXCEPTION_RECORD 
   mov esi, pER 

   mov edi, pContext 
   assume edi:ptr CONTEXT 

   ;跳过下条指令 
   add [edi].regEip, 5 

   assume edi:nothing 
   assume esi:nothing 

   ret 
F0Handler endp 

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD 
LOCAL wc:WNDCLASSEX 
LOCAL msg:MSG 
LOCAL hwnd:HWND 

assume fs:nothing 
   push offset F0Handler ;handler    ;注册SEH异常 
   push fs:[0] ;next 
   mov fs:[0], esp 

pushfd 
or dword ptr [esp], 100h 
popfd 

   ;异常被调试器收了,会继续执行下面的代码,自己异常无法收到,无法进SEH异常函数,所以无法跳过下条指令 

invoke ExitProcess, 0   ;退出进程 非单步调试情况下执行当前指令进异常,指令长度为5 

;获取TF 
;pushfd 
;and dword ptr [esp], 100h 
;jz CONTIUE 
;invoke MessageBox, NULL, NULL, NULL, MB_OK 

;CONTIUE: 
   ;正常流程,TF没有置1 

mov   wc.cbSize,SIZEOF WNDCLASSEX 
mov   wc.style, CS_HREDRAW or CS_VREDRAW 
mov   wc.lpfnWndProc, OFFSET WndProc 
mov   wc.cbClsExtra,NULL 
mov   wc.cbWndExtra,NULL 
push  hInstance 
pop   wc.hInstance 
mov   wc.hbrBackground,COLOR_BTNFACE+1 
mov   wc.lpszMenuName,NULL 
mov   wc.lpszClassName,OFFSET ClassName 

invoke LoadIcon,NULL,IDI_APPLICATION 
mov   wc.hIcon,eax 
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 

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 

       ;卸载SEH 
       pop fs:[0] 
       add esp, 4 

mov     eax,msg.wParam 
ret 
WinMain endp 

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 

.IF uMsg==WM_DESTROY 
 invoke PostQuitMessage,NULL 
.ELSEIF uMsg==WM_CREATE 
 ; 
.ELSE 
 invoke DefWindowProc,hWnd,uMsg,wParam,lParam   
 ret 
.ENDIF 

xor eax,eax 
ret 
WndProc endp 

end start

应对方法,在调试器里把上面代码 nop 调,调试器本身没办法处理,因为没办法判断单步是调试器自己的还是程序的 

TRACE  追踪 

OD的追踪功能 

img 

也可以设置条件 

img 

img 

查看 

img 

img 

开启trace 就在 指定范围地址直接运行 p 命令,不用提示输入指令 

代码实现 

点击否执行trace功能


.586 
.model flat,stdcall 
option casemap:none 

  include windows.inc 
  include user32.inc 
  include kernel32.inc 
  include msvcrt.inc 
  include udis86.inc 

  includelib user32.lib 
  includelib kernel32.lib 
  includelib msvcrt.lib 
  includelib libudis86.lib 

.data 
   g_szExe db "winmine.exe", 0 
   g_hExe  dd 0 
   g_szEXCEPTION_DEBUG_EVENT         db "EXCEPTION_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szCREATE_THREAD_DEBUG_EVENT     db "CREATE_THREAD_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szCREATE_PROCESS_DEBUG_EVENT    db "CREATE_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szEXIT_THREAD_DEBUG_EVENT       db "EXIT_THREAD_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szEXIT_PROCESS_DEBUG_EVENT      db "EXIT_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szLOAD_DLL_DEBUG_EVENT          db "LOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szUNLOAD_DLL_DEBUG_EVENT        db "UNLOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0 
   g_szOUTPUT_DEBUG_STRING_EVENT     db "OUTPUT_DEBUG_STRING_EVENT", 0dh, 0ah, 0 

   g_szLoadDllFmt   db "%08X %s", 0dh, 0ah, 0 
   g_szwLoadDllFmt   dw '%', '0', '8', 'X', ' ', '%', 's', 0dh, 0ah, 0 
   g_szBpFmt  db "CC异常 %08X", 0dh, 0ah, 0 
   g_szSsFmt  db "单步异常 %08X", 0dh, 0ah, 0 
   g_szOutPutAsmFmt db "%08x %-20s %-20s", 0dh, 0ah, 0 
   g_szInputCmd db "选择命令:", 0dh, 0ah 
               db "是:单步步入", 0dh, 0ah 
               db "否:单步步过", 0dh, 0ah 
               db "取消:直接运行", 0dh, 0ah,0 

   g_btOldCode db 0 
   g_dwBpAddr  dd   01003e21h  
   g_byteCC   db 0CCh 
   g_szOutPutAsm db 64 dup(0) 
   g_ud_obj db 1000h dup(0) 
   g_bIsCCStep dd FALSE 
   g_bIsStepStep dd FALSE 
   g_bIsAutoStep dd FALSE   ;是否trace追踪  

.code   

IsCallMn  proc uses esi edi pDE:ptr DEBUG_EVENT, pdwCodeLen:DWORD 
   LOCAL @dwBytesOut:DWORD 
   LOCAL @dwOff:DWORD 
   LOCAL @pHex:LPSTR 
   LOCAL @pAsm:LPSTR 

   mov esi, pDE 
   assume esi:ptr DEBUG_EVENT 

       ;显示下一条即将执行的指令 
   invoke ReadProcessMemory, g_hExe, [esi].u.Exception.pExceptionRecord.ExceptionAddress, \ 
       offset g_szOutPutAsm, 20, addr @dwBytesOut 
   invoke ud_init, offset g_ud_obj 
   invoke ud_set_input_buffer, offset g_ud_obj, offset g_szOutPutAsm, 20 
   invoke ud_set_mode, offset g_ud_obj, 32 
   invoke ud_set_syntax, offset g_ud_obj, offset ud_translate_intel 
   invoke ud_set_pc, offset g_ud_obj, [esi].u.Exception.pExceptionRecord.ExceptionAddress 

   invoke ud_disassemble, offset g_ud_obj 
   invoke ud_insn_off, offset g_ud_obj 
   mov @dwOff, eax 
   invoke ud_insn_hex, offset g_ud_obj 
   mov @pHex, eax 
   invoke ud_insn_asm, offset g_ud_obj 
   mov @pAsm, eax 
   invoke ud_insn_len, offset g_ud_obj 
   mov edi, pdwCodeLen 
   mov [edi], eax 

   invoke crt_printf, offset g_szOutPutAsmFmt, @dwOff, @pHex, @pAsm 

   mov eax, @pAsm 
   .if dword ptr [eax] == 'llac' 
       mov eax, TRUE 
       ret         
   .endif 

   mov eax, FALSE 
   ret 

IsCallMn endp 

SetTF proc dwTID:DWORD 
   LOCAL @hThread:HANDLE  
   LOCAL @ctx:CONTEXT 

   invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID 
   mov @hThread, eax 

   mov @ctx.ContextFlags, CONTEXT_FULL 
   invoke GetThreadContext, @hThread, addr @ctx 

   or @ctx.regFlag, 100h 

   invoke SetThreadContext, @hThread, addr @ctx 
   invoke CloseHandle, @hThread 

   ret 

SetTF endp 

DecEIP proc dwTID:DWORD 
   LOCAL @hThread:HANDLE  
   LOCAL @ctx:CONTEXT 

   invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID 
   mov @hThread, eax 

   mov @ctx.ContextFlags, CONTEXT_FULL 
   invoke GetThreadContext, @hThread, addr @ctx 

   dec @ctx.regEip 

   invoke SetThreadContext, @hThread, addr @ctx 
   invoke CloseHandle, @hThread 
   ret 

DecEIP endp 

SetBp proc   
   LOCAL @dwBytesOut:DWORD   

   ;保存原来的指令, 在 01001BCF写入CC 
   invoke ReadProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut 
   invoke WriteProcessMemory, g_hExe,  g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut 

   ret 

SetBp endp 

InputCmd proc uses esi pDE:ptr DEBUG_EVENT  
   LOCAL @bIsCall:BOOL 
   LOCAL @dwCodeLen:DWORD 

   mov esi, pDE 
   assume esi:ptr DEBUG_EVENT 

   .if [esi].u.Exception.pExceptionRecord.ExceptionAddress == 01003ebeh 
       mov g_bIsAutoStep, FALSE 
   .endif 

   invoke IsCallMn, pDE, addr @dwCodeLen 
   mov @bIsCall, eax 

   ;如果开启了trace 直接执行p命令,否则提示输入指令 
   .if g_bIsAutoStep != TRUE 
       invoke MessageBox, NULL, offset g_szInputCmd, NULL, MB_YESNOCANCEL 
    .else  
        mov eax, IDNO 
   .endif 

   .if eax == IDYES 
       ;单步步入,直接TF置1 
       invoke SetTF, [esi].dwThreadId 

       ;单步中需要处理T命令 
       mov g_bIsStepStep, TRUE 
   .elseif eax == IDNO 

       ;开启trace追踪 
       mov g_bIsAutoStep, TRUE 
       ;单步步过,判断是否是call 
       .if @bIsCall 
           ;call指令,在下一条指令设置断点 
           mov eax, [esi].u.Exception.pExceptionRecord.ExceptionAddress 
           add eax, @dwCodeLen 
           mov g_dwBpAddr, eax 
           invoke SetBp 
       .else   
           ;单步步入,直接TF置1 
           invoke SetTF, [esi].dwThreadId 

           ;单步中需要处理T命令 
           mov g_bIsStepStep, TRUE    

       .endif 

   .else 
       ;直接运行 

   .endif 
   ret 

InputCmd endp 

OnException proc uses esi pDE:ptr DEBUG_EVENT  
   LOCAL @dwBytesOut:DWORD   
   mov esi, pDE 
   assume esi:ptr DEBUG_EVENT 

   .if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT 
       ;判断是否是自己的CC 
       mov eax, [esi].u.Exception.pExceptionRecord.ExceptionAddress 
       .if eax != g_dwBpAddr 
           ;不是自己的CC异常,不处理 
           mov eax, DBG_EXCEPTION_NOT_HANDLED  
           ret 
       .endif 

       ;处理自己的CC异常 
       invoke crt_printf, offset g_szBpFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress 

       ;恢复指令 
       invoke WriteProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut  

       ;设置单步 
       invoke SetTF, [esi].dwThreadId 
       invoke DecEIP, [esi].dwThreadId 

       ;单步中需要处理CC的单步 
       mov g_bIsCCStep,  TRUE 

       ;输入命令 
       invoke InputCmd, pDE 

       mov eax, DBG_CONTINUE 
       ret 
   .endif 

   ;单步来了 
   .if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP 

       ;处理自己的单步 
       invoke crt_printf, offset g_szSsFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress 

       ;处理CC的单步 
       .if g_bIsCCStep == TRUE 
           mov g_bIsCCStep, FALSE 

           ;重设断点, 重新写入CC 
           ;invoke WriteProcessMemory, g_hExe,  g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut 
       .endif 

       ;处理T命令的单步 
       .if g_bIsStepStep == TRUE 
           mov g_bIsStepStep, FALSE 

           invoke InputCmd, pDE 
       .endif 

       mov eax, DBG_CONTINUE 
       ret 
   .endif 

   assume esi:nothing 

   mov eax, DBG_EXCEPTION_NOT_HANDLED  
   ret 

OnException endp 

OnCreateProcess proc  

   ;保存原来的指令, 在 01001BCF写入CC 
   invoke SetBp 

   ret 

OnCreateProcess endp 

main proc 
   LOCAL @si:STARTUPINFO 
   LOCAL @pi:PROCESS_INFORMATION 
   LOCAL @de:DEBUG_EVENT  
   LOCAL @dwStatus:DWORD 

   invoke RtlZeroMemory, addr @si, size @si 
   invoke RtlZeroMemory, addr @pi, size @pi 
   invoke RtlZeroMemory, addr @de, size @de 

   mov @dwStatus, DBG_CONTINUE 
   ;建立调试会话 
   invoke CreateProcess, NULL, offset g_szExe, NULL, NULL, FALSE, \ 
       DEBUG_ONLY_THIS_PROCESS,\ 
       NULL, NULL,\ 
       addr @si,\ 
       addr @pi 
   .if !eax 
       ret 
   .endif  
   mov eax, @pi.hProcess 
   mov g_hExe, eax 

   ;循环接受调试事件 
   .while TRUE 
       invoke WaitForDebugEvent, addr @de, INFINITE 

       ;处理调试事件 
       .if @de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT 
           ;invoke crt_printf, offset g_szEXCEPTION_DEBUG_EVENT 
           invoke OnException, addr @de 
           mov @dwStatus, eax 
       .elseif @de.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT 
           invoke crt_printf, offset g_szCREATE_THREAD_DEBUG_EVENT 
       .elseif @de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT 
           ;invoke crt_printf, offset g_szCREATE_PROCESS_DEBUG_EVENT 
           invoke OnCreateProcess 
       .elseif @de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT 
           invoke crt_printf, offset g_szEXIT_THREAD_DEBUG_EVENT 
       .elseif @de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT 
           invoke crt_printf, offset g_szEXIT_PROCESS_DEBUG_EVENT 
       .elseif @de.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT 
           ;invoke OnLoadDll, addr @de 
       .elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT 
           invoke crt_printf, offset g_szUNLOAD_DLL_DEBUG_EVENT 
       .elseif @de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT 
           invoke crt_printf, offset g_szOUTPUT_DEBUG_STRING_EVENT 
       .endif 

       ;提交事件处理结果 
       invoke ContinueDebugEvent, @de.dwProcessId, @de.dwThreadId, @dwStatus 
       invoke RtlZeroMemory, addr @de, size @de 
   .endw 

   ret 

main endp 

start: 
   invoke main 

最新回复 ( 0 )
全部楼主