⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 内存补丁的编写与运用(三).txt

📁 这是最简单的内存补丁方法,又很多的不足,因为程序的好多代码都是在壳中才解密出来的,我将在文章中给出改进方案.
💻 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 + -