📄 内存补丁的编写与运用(三).txt
字号:
前俩篇我们讲了一些内存补丁的基本应用,第一篇我们的例子非常简陋,跟文件补丁差不多,没多大用处,第二篇我们尝试用到了一些调试API函数,但效率不高,如果我们要补丁的程序能检测INT3断点(这种检测不难实现)的话,我们的补丁就用不成了,这一篇文章,我们讨论一种更高级的补丁方法,调试寄存器的使用。
如果以用过OD调试程序,你可能会知道OD里能设置四个硬件断点,为什么不能设多于四个的硬件断点呢?这跟硬件有关,INTER的调试寄存器中的DR0~DR4就是之四个硬件断点。我们今天的例子就是对调试寄存器DR0~DR4的应用。
;loader3,硬件断点的应用,Code bY eLaNce
.386
.model flat, stdcall
option casemap:none
INCLUDE \masm32\include\windows.inc
INCLUDE \masm32\include\kernel32.inc
INCLUDE \masm32\include\user32.inc
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDELIB \masm32\lib\user32.lib
OEP EQU 00401000H
PATCH_POINT1 EQU 00401002H
PATCH_POINT2 EQU 00401002H
.CONST
szProcErr DB "此程序必须与被补丁文件在同一目录下",0
szExe DB "loader1.exe",0;被补丁程序
szNTDll DB "ntdll",0
szNtCont DB "NtContinue",0
dbPatched1 db 84h
dbPatched2 db 85h
;------ DATA ------
.DATA
PI_ PROCESS_INFORMATION <>
SI_ STARTUPINFO <SIZEOF STARTUPINFO>
Regs CONTEXT <CONTEXT_FULL OR CONTEXT_DEBUG_REGISTERS>
DB_ DEBUG_EVENT <>
SP_ PROCESSENTRY32<>
dwBPCnt DD 0
dwContStat DD 0
cBuff DB 50 DUP (0)
dwBytesRead DD 0
dwBytesWritten DD 0
dwBuff DD 0
dwSSCnt DD 0
.data?
hSnapShot dd ?
.CODE
start:
invoke RtlZeroMemory,addr SP_,sizeof SP_
mov SP_.dwSize,sizeof SP_
invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
mov hSnapShot,eax
invoke Process32First,hSnapShot,addr SP_
.while eax
invoke CompareString,LOCALE_USER_DEFAULT,NORM_IGNORECASE,addr szExe,sizeof szExe,\
addr SP_.szExeFile,sizeof szExe
.if eax==2
invoke OpenProcess,PROCESS_TERMINATE,FALSE,SP_.th32ProcessID
.if eax
mov ebx,eax
invoke TerminateProcess,ebx,-1
invoke CloseHandle,ebx
.endif
.break
.endif
invoke Process32Next,hSnapShot,addr SP_
.endw
INVOKE CreateProcess,offset szExe,NULL,NULL,NULL,FALSE,DEBUG_PROCESS OR DEBUG_ONLY_THIS_PROCESS,NULL,NULL,\
offset SI_,offset PI_
OR EAX, EAX
JZ ProcErr
SUB EAX, EAX
MOV dwBPCnt, EAX
MOV dwSSCnt, EAX
.WHILE TRUE
INVOKE WaitForDebugEvent,offset DB_,INFINITE
MOV dwContStat, DBG_EXCEPTION_NOT_HANDLED
.IF DB_.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
.IF DB_.u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT
MOV dwContStat, DBG_CONTINUE
INC dwBPCnt
.IF dwBPCnt == 1
;在"NtContinue"处设硬件断点,NT下必须通过此跳板才能停在OEP处
INVOKE GetThreadContext, PI_.hThread, OFFSET Regs
MOV Regs.iDr7, 257
INVOKE GetModuleHandle, OFFSET szNTDll
INVOKE GetProcAddress, EAX, OFFSET szNtCont
MOV Regs.iDr0, EAX
INVOKE SetThreadContext, PI_.hThread, OFFSET Regs
JMP @@Continue
.ENDIF
.ELSEIF DB_.u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP
INC dwSSCnt
MOV dwContStat, DBG_CONTINUE
.IF dwSSCnt == 1
; NtContinue reached
INVOKE GetThreadContext, PI_.hThread, OFFSET Regs
MOV Regs.iDr0, 0
MOV Regs.iDr7, 0
INVOKE SetThreadContext, PI_.hThread, OFFSET Regs
;下面的几句必须有,必须通过ESP来写Regs
MOV EBX, Regs.regEsp
ADD EBX, 4 ; EBX -> first parameter to NtContinue
; read pointer to real context
INVOKE ReadProcessMemory, PI_.hProcess, EBX, OFFSET dwBuff, 4, \
OFFSET dwBytesRead
; read real context
INVOKE ReadProcessMemory, PI_.hProcess, dwBuff, OFFSET Regs, SIZEOF CONTEXT, \
OFFSET dwBytesRead
MOV Regs.iDr0, OEP ; EntryPoint处硬件断点
MOV Regs.iDr7, 257
; rewrite modifed context
INVOKE WriteProcessMemory, PI_.hProcess, dwBuff, OFFSET Regs, SIZEOF CONTEXT, \
OFFSET dwBytesWritten
.ELSEIF dwSSCnt == 2
; BPM on Entry reached
;-> wipe BPM out of the thread context
INVOKE GetThreadContext, PI_.hThread, OFFSET Regs
MOV Regs.iDr0, PATCH_POINT1;在00401002h处下硬件断点
;iDr0,iDr1,iDr2,iDr3这四个调试寄存器可设置四个硬件断点,这也是OD里只能设四个硬件断点的原因
MOV Regs.iDr7, 257
INVOKE SetThreadContext, PI_.hThread, OFFSET Regs
.ELSEIF dwSSCnt == 3
;删除硬件断点
INVOKE GetThreadContext, PI_.hThread, OFFSET Regs
MOV Regs.iDr0, 0
MOV Regs.iDr7, 0
INVOKE SetThreadContext, PI_.hThread, OFFSET Regs
;写入补丁数据
invoke WriteProcessMemory,PI_.hProcess,PATCH_POINT1+1,addr dbPatched1,\
sizeof dbPatched1,addr dwBytesWritten
;invoke WriteProcessMemory,PI_.hProcess,PATCH_POINT2+1,addr dbPatched2,\
;sizeof dbPatched2,addr dwBytesWritten
.ENDIF
JMP @@Continue
.ENDIF
.ELSEIF DB_.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT
.BREAK
.ENDIF
@@Continue:
INVOKE ContinueDebugEvent,DB_.dwProcessId,DB_.dwThreadId,DBG_CONTINUE
.ENDW
;-> clean up
INVOKE CloseHandle, PI_.hThread
INVOKE CloseHandle, PI_.hProcess
@@Quit:
RET
ProcErr:
INVOKE MessageBox,NULL,OFFSET szProcErr,NULL,0
end start
有些软件可以检测OEP处的CC(例如ExeCrypt加壳的程序),也就是说我们的loader2是不能在OEP处设INT3断点的,而我们的loader3却可以,呵呵,爽吧。到此我们的内存补丁的编写与应用系列到此结束,希望对大家有所帮助!!!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -