顾名思义我们今天讨论的是应用层软件的调试,且是64位的软件,当一个软件发生错误或者异常时(不管是无意的还是刻意的)首先这个错误信息会先在内核中处理,如果是驱动程序产生的异常或者错误,能处理就处理不能处理就直接蓝屏,如果是应用程序的话,在内核中分配一些诸如ExceptionRecord、ContextRecord的结构体后就返回到用户层面继续处理了。
内核函数 KiExceptionDispatch在检测到异常或错误来自用户空间时,就会调用用户层的KiUserExceptionDispatcher,这个函数是用户层面的异常错误总入口,位于NTDLL.DLL中,我们编写软件时用到的SEH异常处理,都是由这个函数来实现的。
上图是win10的目前最新的版本
我们看下它的导出函数KiUserExceptionDispatcher,其中RtlDispatchException就是核心的异常处理过程,RtlGuardRestoreContext 函数是调用我们提供给SEH的安全返回地址。
现在市面上的商业软件不管32位还是64位,都有防跟踪、防逆向的指令在保护自身代码,很多调试器也有相应的插件提供过保护,32位系统下,基本上OD可以过所有保护。但64位系统下就不行了,其中win64对内核有更加严格的保护,不像32位下你可以随时接管中断接口、异常接口、SSDT 等,64位系统下你这样做分分钟蓝屏,PatchGuard了解一下。
基于这个原因,其实我们可以从ntdll的RtlDispatchException函数入手,我们挂钩RtlDispatchException,接管用户层面的所有异常,然后过滤出我们感兴趣的程序即可。
我们增加一个新的节区(fix)调整节区属性为可读、可写、可执行、可共享(应用程序加载NTDLL时不会为这个节区额外分配空间,直接映射我们分配的空间)
手动修改call的跳转地址。然后自己编写过滤代码,将编好的代码用ue写入我们新建的节区就可以了。假如我们要跟踪一个license 授权文件的解密流程,那就需要挂钩ZwCreateFile函数,获取到文件句柄后,挂钩ZwReadFile函数。方法和RtlDispatchException一样,直接把指令call到我们提前定义的空间地址上。整个过程就是在真实的环境中运行,软件自身的反调试功能统统失效,因为我们就没用市面上的任何调试器,我们直接通过和NTDLL的自定义节区(fix)交换数据来获取调试数据。
很多软件喜欢用VMP来加壳,我们就针对VMP来简单说下调试过程吧。VMP壳软件在启动过程中自身会调用一些函数来检测电脑的运行环境,如果电脑处在调试模式,或者检测到调试端口、事件之类,就会异常退出,我们没用调试器所以就不用关心这些事情,唯一要做的是VMP对自陷指令的处理,比如:int1 、int 3。我们不是接管了RtlDispatchException嘛,所以VMP 产生的异常指令,都会被我们过滤到,把这些过滤到的异常指令全部保存下来,将来在动态跟踪时,遇到这些指令就放行。
pushfq
or byte ptr [rsp 1],1 ;单步
popfq
持续产生int1 中断,就可以把整个代码流程给抓取出来。用正确的授权走一遍,再用错误的走一遍,比对一下不同点很快就可以找到关键 jz jnz 指令点。
align 16
org 300h
dq 0cccccccccccccccch
dq 0cccccccccccccccch
_DispatchException proc
LOCAL @OBJECT_ATTRIBUTES :OBJECT_ATTRIBUTES ;30h
LOCAL @seh_64_exe_UNICODE_STRING :UNICODE_STRING ;<?>;10h
LOCAL ip:qword
LOCAL @SectionHandle:qword
LOCAL @LARGE_INTEGER:qword
LOCAL @SectionOffset:qword
LOCAL @ViewSize:qword
LOCAL @viewBaseAddress:qword
LOCAL @PEB_LDR_DATA :qword
LOCAL @NEXT_PEB_LDR_DATA:qword ;要调试的程序的文件名
LOCAL @NEXT__for_all_PEB_LDR_DATA:qword ;要调试的程序所包含的全部DLL信息
LOCAL @flags_debug_or_nodebug:qword
LOCAL @hevent_read_for_seh_64 :qword
LOCAL @hevent_write_for_ntdll :qword ;NTDLL可以写数据了
LOCAL @DllBase :qword
LOCAL _rcx:qword; ExceptionRecord
LOCAL _rdx:qword;ContextRecord
LOCAL _rsi:qword
LOCAL _rdi:qword
LOCAL _r8:qword
LOCAL _r9:qword
LOCAL _r10:qword
LOCAL _r11:qword
LOCAL _r12:qword, _r13:qword, _r14:qword, _r15:qword
LOCAL @ObjectDirectory:qword
LOCAL @count:qword
mov _rcx,rcx
mov _rdx,rdx
mov _rsi,rsi
mov _rdi,rdi
mov _r8,r8
mov _r9,r9
mov _r10,r10
mov _r11,r11
push rcx
push rdx
push rbx
push rbp
push rsi
push rdi
push r12
push r13
push r14
push r15
sub rsp, 80h
call @f
@@:
pop rax
lea rbx,@b
sub rax,rbx
mov ip,rax
mov rsi,[rdx _CONTEXT._Rip]
lea rdi, track_point
add rdi,rax
lea rbx, track_point_end
add rbx,rax
.if << cmp rsi,rdi>>, ABOVE?||EQUAL? ;可能产生异常的地方,处理方法
.if <<cmp rsi,rbx>> , BELOW?||EQUAL? ;如果是我们自己的RtlDispatchException 产生的异常,那就跳过这个异常的记录, mov rsi,[rsi _CONTEXT._Rip]
;.if <<test rsi,rsi>>, NOZERO?
;REP MOVSB 这个很容易产生异常
;.else
;mov qword ptr [rdi],0
;.endif
lea rbx,track_point_end
mov [rdx _CONTEXT._Rip],rbx
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行
; ret ;不能直接返回:RtlRestoreContext 已经被我们HOOK,会生成单步中断
mov rax,ip
lea rax,[rax 78e9b39fh] ; RtlRestoreContext
;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改为E8 3afb1500 call near ptr qword_78FFb800
mov rcx,_rcx
mov rdx,_rdx
mov rcx,rdx ;context
xor rdx,rdx
leave
;jmp qword ptr _r11
jmp rax
.endif
.endif
mov rsi,[rdx _CONTEXT._Rip]
lea rdi, copy_rip
add rdi,rax
lea rbx, copy_rip_end
add rbx,rax
.if << cmp rsi,rdi>>, ABOVE?||EQUAL? ;可能产生异常的地方,处理方法
.if <<cmp rsi,rbx>> , BELOW?||EQUAL? ;如果是我们自己的RtlDispatchException 产生的异常,那就跳过这个异常的记录, mov rsi,[rsi _CONTEXT._Rip]
;.if <<test rsi,rsi>>, NOZERO?
;REP MOVSB 这个很容易产生异常
;.else
;mov qword ptr [rdi],0
;.endif
lea rbx,copy_rip_end
mov [rdx _CONTEXT._Rip],rbx
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行
; ret ;不能直接返回:RtlRestoreContext 已经被我们HOOK,会生成单步中断
mov rax,ip
lea rax,[rax 78e9b39fh] ; RtlRestoreContext
;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改为E8 3afb1500 call near ptr qword_78FFb800
mov rcx,_rcx
mov rdx,_rdx
mov rcx,rdx ;context
xor rdx,rdx
leave
;jmp qword ptr _r11
jmp rax
.endif
.endif
lea rdi,copy_in_data_rbp
add rdi,rax
lea rbx,copy_in_rbp_end
add rbx,rax
.if << cmp rsi,rdi>>, ABOVE?||EQUAL? ;可能产生异常的地方,处理方法
.if <<cmp rsi,rbx>> ,BELOW?||EQUAL?
mov rax,ip
lea rbx,copy_in_rbp_end
mov [rdx _CONTEXT._Rip],rbx
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行
; ret ;不能直接返回:RtlRestoreContext 已经被我们HOOK,会生成单步中断
mov rax,ip
lea rax,[rax 78e9b39fh] ; RtlRestoreContext
;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改为E8 3afb1500 call near ptr qword_78FFb800
mov rcx,_rcx
mov rdx,_rdx
mov rcx,rdx ;context
xor rdx,rdx
leave
;jmp qword ptr _r11
jmp rax
.endif
.endif
lea rdi,[rax 78ffa060h]
lea rbx,[rax 78ffa0e0h]
.if << cmp rsi,rdi>>, ABOVE?||EQUAL?
.if <<cmp rsi,rbx>> ,BELOW?||EQUAL?
mov rax,ip
lea rbx,[rax 78ffa0e0h] ;这里存放的是ret指令(POP RCX POP RDI POP RSI RET
mov [rdx _CONTEXT._Rip],rbx
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行
; ret ;不能直接返回:RtlRestoreContext 已经被我们HOOK,会生成单步中断
mov rax,ip
lea rax,[rax 78e9b39fh] ; RtlRestoreContext
;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改为E8 3afb1500 call near ptr qword_78FFb800
mov rcx,_rcx
mov rdx,_rdx
mov rcx,rdx ;context
xor rdx,rdx
leave
;jmp qword ptr _r11
jmp rax
.endif
.endif
.if <<cmp [rdx _CONTEXT._Rax],12121212h>>,ZERO?
.if <<cmp [rdx _CONTEXT._Rbx],23232323h>>,ZERO?
.if <<cmp [rdx _CONTEXT._Rcx],34343434h>>,ZERO?
.if <<cmp [rdx _CONTEXT._Rdx],45454545h>>,ZERO?
;确认是我们的调试器发出的指令
mov rax,[rdx _CONTEXT._R12]
mov @flags_debug_or_nodebug,rax
mov rax,[rdx _CONTEXT._R13] ;sizeof_file
mov @hevent_read_for_seh_64,0
mov rax,[rdx _CONTEXT._R14]
mov @hevent_write_for_ntdll,0
mov rax,ip
lea rax, [rax 78efb2f0h];
call rax ;ntdll!RtlGetCurrentPeb
.if <<test rax,rax>>,NOZERO?
mov rax,[rax 18h] ;_PEB_LDR_DATA
.if <<test rax,rax>>,NOZERO?
lea rcx, [rax 10h]
mov @PEB_LDR_DATA,rcx
mov rax,[rax 10h];_PEB_LDR_DATA.InLoadOrderModuleList;InLoadOrderModuleList : _LIST_ENTRY
.if <<test rax,rax>>,NOZERO?
.while <<cmp rax,@PEB_LDR_DATA>>,NOZERO?
lea rax,[rax LIST_ENTRY.Flink]
mov @NEXT_PEB_LDR_DATA,rax
mov rbx,[rax 30h];_LDR_DATA_TABLE_ENTRY.DllBase
mov @DllBase,rbx
lea rax,[rax 58h]; _LDR_DATA_TABLE_ENTRY.BaseDllName : _UNICODE_STRING
; mov rsi,[rax _UNICODE_STRING.Buffer]
; invoke MessageBoxW,0,rsi,addr ldrtest,MB_OK
movzx rcx,[rax _UNICODE_STRING._Length]
mov rsi,[rax _UNICODE_STRING.Buffer]
mov rax,ip
lea rdi ,[rax 78ffa010h] ;szMMFName db "seh_64.exe64---",0
cld
repz cmpsb
.if ZERO? ;是seh_64发出的异常指令
mov rdx,_rdx
lea rsi , [rdx _CONTEXT._Rsi];_rsi--_r11 总共30H 存放有要调试的程序
mov ecx,30h
mov rax,ip
lea rdi ,[rax 78ffa030h 8]
cld
rep movsb
mov rcx,[rdx _CONTEXT._R15]
mov qword ptr [rax 78ffa030h],rcx
lea rsi , [rdx _CONTEXT.___u38.data.__s1._Xmm0]
lea rdi ,[rax 78ffa200h]
mov rcx,20h
cld
rep movsq
mov rcx,@flags_debug_or_nodebug
mov [rax 78ffa100h],rcx ;1自动跟踪MT5 或 0只是检测它的异常断点 -1,动态调试
mov rdx,_rdx
mov rcx,8989898989898989h
mov [rdx _CONTEXT._Rax],rcx
mov rcx,9a9a9a9a9a9a9a9ah
mov [rdx _CONTEXT._Rbx],rcx
mov rcx,0ababababababababh
mov [rdx _CONTEXT._Rcx],rcx
mov rcx,0bcbcbcbcbcbcbcbch
mov [rdx _CONTEXT._Rdx],rcx
mov rax,ip
mov rcx,78ffc000h
add rcx,rax
mov [rdx _CONTEXT._Rsi],rcx ;@viewBaseAddress
mov rcx,78ffa0f8h
add rcx,rax
mov [rdx _CONTEXT._Rdi],rcx ;@hevent_write_for_ntdll;NTDLL可以写数据了
mov rcx,78ffa0f0h
add rcx,rax
mov [rdx _CONTEXT._R9],rcx ;;hevent_read_for_seh_64
mov rcx,78ffc000h
add rcx,rax
mov @viewBaseAddress,rcx
lock and qword ptr [rax 78ffa008h],0;@viewBaseAddress
lock or [rax 78ffa008h],rcx
lock and qword ptr [rax 78ffa000h],0;第一次运行需要获取程序需要的DLL信息
lock and qword ptr [rax 78ffa110h],0;进程ID
lock and qword ptr [rax 78ffa120h],0;78ffa120h license.lic 文件句柄
mov rcx,[rdx _CONTEXT._R13] ;sizeof_file
mov qword ptr [rax 78ffa118h],rcx;被调试程序大小
mov rcx,[rdx _CONTEXT._R14];
lock and qword ptr [rax 78ffa108h],0
lock or qword ptr [rax 78ffa108h],rcx;总开关,系统在初始化时,不需要任何检测的,我们的调试器还没有启动呢!
add qword ptr [rdx _CONTEXT._Rip],8 ; C6 04 25 00 00 00 00 00 mov byte ptr ds:0, 0
mov rax,ip
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行
ret
.endif
mov rax, @NEXT_PEB_LDR_DATA
mov rax,[rax]
.endw
.endif
.endif
.endif
.endif
.endif
.endif
.endif
;是否MT5产生的异常
mov rax,ip
mov rcx,[rax 78ffa108h] ;总开关,系统在初始化时,不需要任何检测了
.if <<test rcx,rcx>>, ZERO?
jmp exit
.endif
mov rax,ip
mov rcx,[rax 78ffa110h]
mov rax,qword ptr gs:[30h] ;_TEB. _NT_TIB.self
mov eax,dword ptr [rax 40h];GetCurrentProcessId ;ClientId._CLIENT_ID.UniqueProcess
.if <<test rcx,rcx>>, NOZERO? ;进程ID
.if <<cmp rcx,rax>>, NOZERO?
jmp exit ;不是我们要处理的程序
.endif
.else ;如果进程ID为空说明之前还没有捕获到MT5的异常 这里继续在本次异常里尝试
mov rax,ip
lea rax, [rax 78efb2f0h];
call rax ;ntdll!RtlGetCurrentPeb
.if <<test rax,rax>>,NOZERO?
mov rax,[rax 18h] ;_PEB_LDR_DATA
.if <<test rax,rax>>,NOZERO?
lea rcx, [rax 10h]
mov @PEB_LDR_DATA,rcx
mov rax,[rax 10h];_PEB_LDR_DATA.InLoadOrderModuleList;InLoadOrderModuleList : _LIST_ENTRY
.if <<test rax,rax>>,NOZERO?
.while <<cmp rax,@PEB_LDR_DATA>>,NOZERO?
; lea rax,[rax LIST_ENTRY.Flink];;其实这里还是== lea rax,[rax] ;LIST_ENTRY.Flink == 0
mov @NEXT_PEB_LDR_DATA,rax
mov rbx,[rax 30h];_LDR_DATA_TABLE_ENTRY.DllBase
mov @DllBase,rbx
lea rax,[rax 58h]; _LDR_DATA_TABLE_ENTRY.BaseDllName : _UNICODE_STRING
movzx rcx,[rax _UNICODE_STRING._Length]
mov rbx,ip
.if <<cmp rcx,[rbx 78ffa030h]>>,zero? ; 要调试的程序名长度
mov rsi,[rax _UNICODE_STRING.Buffer]
mov rax,ip
lea rdi ,[rax 78ffa030h 8]
cld
repz cmpsb
.if ZERO? ;MT5的异常;这里找到MT5了
;保存加载的DLL信息和进程ID
mov rax,ip
mov rcx,@DllBase
mov [rax 78ffa0e8h],rcx
mov rcx,[rax 78ffa000h]
.if <<test rcx,rcx>>,ZERO? ;第一次运行需要获取程序需要的DLL信息
comment ~
lea rcx,@seh_64_exe_UNICODE_STRING
lea rdx, [rax 78ffa010h 8]
lea rax,[rax 78e9f5d0h]
call rax ;RtlInitUnicodeString
lea rcx,@ObjectDirectory
mov rax,ip
lea rax, [rax 78EF7FA0h];
call rax;BaseGetNamedObjectDirectory
mov rax,ip
lea rdx,@seh_64_exe_UNICODE_STRING
lea rcx,@OBJECT_ATTRIBUTES
mov rax,@ObjectDirectory
InitializeObjectAttributes rcx, rdx, OBJ_OPENIF, rax, NULL;OBJ_OPENIF equ 80h
lea r8,@OBJECT_ATTRIBUTES
mov rdx,EVENT_ALL_ACCESS
lea rcx,@hevent_read_for_seh_64
mov rax,ip
lea rax, [rax 78e9c130h]
call rax ;ZwOpenEvent returns STATUS_SUCCESS on success
.if <<test rax,rax>>, NOZERO?
jmp exit
.endif
mov rax,ip
mov rcx,@hevent_read_for_seh_64;
mov [rax 78ffa0f0h],rcx
lea rcx,@seh_64_exe_UNICODE_STRING
lea rdx, [rax 78ffa010h 10H]
lea rax,[rax 78e9f5d0h]
call rax ;RtlInitUnicodeString
lea rcx,@ObjectDirectory
mov rax,ip
lea rax, [rax 78EF7FA0h];
call rax;BaseGetNamedObjectDirectory
mov rax,ip
lea rdx,@seh_64_exe_UNICODE_STRING
lea rcx,@OBJECT_ATTRIBUTES
mov rax,@ObjectDirectory
InitializeObjectAttributes rcx, rdx, OBJ_OPENIF, rax, NULL;OBJ_OPENIF equ 80h
lea r8,@OBJECT_ATTRIBUTES
mov rdx,EVENT_ALL_ACCESS
lea rcx,@hevent_write_for_ntdll
mov rax,ip
lea rax, [rax 78e9c130h]
call rax ;ZwOpenEvent returns STATUS_SUCCESS on success
.if <<test rax,rax>>, NOZERO?
jmp exit
.endif
mov rax,ip
mov rcx,@hevent_write_for_ntdll;NTDLL可以写数据了
mov [rax 78ffa0f8h],rcx
lea rcx,@seh_64_exe_UNICODE_STRING
lea rdx, [rax 78ffa010h]
lea rax,[rax 78e9f5d0h]
call rax ;RtlInitUnicodeString
lea rcx,@ObjectDirectory
mov rax,ip
lea rax, [rax 78EF7FA0h];
call rax;BaseGetNamedObjectDirectory
mov rax,ip
lea rdx,@seh_64_exe_UNICODE_STRING
lea rcx,@OBJECT_ATTRIBUTES
mov rax,@ObjectDirectory
InitializeObjectAttributes rcx, rdx, OBJ_OPENIF, rax, NULL;OBJ_OPENIF equ 80h
lea r8,@OBJECT_ATTRIBUTES
mov rdx,SECTION_MAP_WRITE or SECTION_MAP_READ ;SECTION_MAP_WRITE equ 2h SECTION_MAP_READ equ 4h
lea rcx,@SectionHandle
mov rax,ip
lea rax, [rax 78e9c0a0h]
call rax ;ZwOpenSection returns STATUS_SUCCESS on success
.if <<test rax,rax>>,ZERO?
mov rcx,@SectionHandle
mov rdx,-1;ProcessHandle
lea r8,@viewBaseAddress
mov @viewBaseAddress,0
mov r9,0;ZeroBits,
mov qword ptr [rsp 20h],0;CommitSize
lea rax,@SectionOffset
mov @SectionOffset,0
mov qword ptr [rsp 28h],rax;SectionOffset
lea rax,@ViewSize
mov @ViewSize,0
mov qword ptr [rsp 30h],rax;ViewSize 分配的尺寸
mov qword ptr [rsp 38h],1;ViewShare equ 1
mov qword ptr [rsp 40h],0
mov qword ptr [rsp 48h],PAGE_READWRITE ; equ 4
mov dword ptr [rsp 4ch],-1
mov rax,ip
lea rax, [rax 78e9bfb0h]
call rax ;ntdll!ZwMapViewOfSection PROTO64 external,ZwMapViewOfSection,
; :QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD
.if <<test rax,rax>>,ZERO?
comment ~
mov rax,ip
mov rcx,1
mov @SectionHandle,rcx
; lock and qword ptr [rax 78ffa000h],0;第一次运行需要获取程序需要的DLL信息
; lock or [rax 78ffa000h],rcx
lock xchg [rax 78ffa000h],rcx
mov rax,ip
lea rax, [rax 78efb2f0h];
call rax ;ntdll!RtlGetCurrentPeb
.if <<test rax,rax>>,NOZERO?
mov rax,[rax 18h] ;_PEB_LDR_DATA
.if <<test rax,rax>>,NOZERO?
lea rcx, [rax 10h]
mov @PEB_LDR_DATA,rcx
mov rax,[rax 10h];_PEB_LDR_DATA.InLoadOrderModuleList;InLoadOrderModuleList : _LIST_ENTRY
.if <<test rax,rax>>,NOZERO?
;把找到的dll信息发给调试器
mov @NEXT_PEB_LDR_DATA,rax
; mov rax,ip
; mov rcx,[rax 78ffa0f8h];;NTDLL可以写数据了
; mov rdx,0
; mov r8,0
; lea rax, [rax 78e9bd70h];
; call rax ;ntdll!ZwWaitForSingleObject
mov rax,ip
@@:
lock bts qword ptr [rax 78ffa0f8h], 0 ; BTS就是根据位偏移值从位串中取出一位放入CF中,然后将位串中的该位置成1
jnc @f
_wait:
pause
wait
fwait
test qword ptr [rax 78ffa0f8h], 1
jnz _wait
jmp @b
@@:
mov rax, @NEXT_PEB_LDR_DATA
mov rbx,0
.while <<cmp rax,@PEB_LDR_DATA>>,NOZERO?
; lea rax,[rax LIST_ENTRY.Flink]
mov @NEXT_PEB_LDR_DATA,rax
mov rdx,[rax 30h];_LDR_DATA_TABLE_ENTRY.DllBase
lea rax,[rax 58h]; _LDR_DATA_TABLE_ENTRY.BaseDllName : _UNICODE_STRING
movzx rcx,[rax _UNICODE_STRING._Length];我们设置的长度是40h unicode模式 是ASCII码长度的2倍
.if <<cmp rcx,40h>>, BELOW?||EQUAL?
mov rsi,[rax _UNICODE_STRING.Buffer]
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
mov [rdi][rbx][dllinformation.flags],2
mov [rdi][rbx][dllinformation.dllbase],rdx
mov [rdi][rbx][dllinformation.dllnamelength],rcx
lea rdi,[rdi][rbx][dllinformation.dllname]
cld
rep movsb
add rbx,sizeof dllinformation
.if <<cmp rbx,40*sizeof dllinformation>>, ABOVE?
.break
.endif
.endif
mov rax,@NEXT_PEB_LDR_DATA
mov rax,[rax LIST_ENTRY.Flink]
.endw
mov rcx,qword ptr gs:[30h]
mov ecx,dword ptr [rcx 40h];GetCurrentProcessId
mov rax,ip
lock xchg [rax 78ffa110h],rcx;把进程id保存起来,下次直接通过ID比较
; mov rcx,[rax 78ffa0f0h];hevent_read_for_seh_64
; mov rdx,0
; mov rax,ip
; lea rax, [rax 78e9be10h];ZwSetEvent
; call rax
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock hevent_read_for_seh_64 客户端可以读数据了
.break ;跳出上一层循环
.else
jmp error
.endif
.else
jmp error
.endif
.else
jmp error
.endif
.else
.break ;如果已经设置好了,就不需要重复设置了
.endif
.endif
.endif
mov rax,@NEXT_PEB_LDR_DATA
mov rax,[rax LIST_ENTRY.Flink]
.endw
mov rax,ip
mov rcx,[rax 78ffa110h];进程ID
.if <<test rcx,rcx>>, ZERO?
;没有填充进程ID
jmp exit
.endif
.else
jmp exit
.endif
.else
jmp exit
.endif
.else
jmp exit
.endif
.endif
;这里确定是MT5后继续执行
mov rax,ip
mov rdi,[rax 78ffa0e8h] ;mt5DllBase
mov @DllBase,rdi
@@:
lock bts qword ptr [rax 78ffa0f8h], 0 ; BTS就是根据位偏移值从位串中取出一位放入CF中,然后将位串中的该位置成1 ;;;;NTDLL可以写数据事件
jnc @f
_wait1:
pause
wait
fwait
test qword ptr [rax 78ffa0f8h], 1
jnz _wait1
jmp @b
@@:
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
mov rax,qword ptr gs:[30h]
mov eax,dword ptr [rax 40h];GetCurrentProcessId
mov qword ptr [rdi][recvfromntddd.flage_CONTEXT_EFlags],0
mov qword ptr [rdi][recvfromntddd.flags],1
mov qword ptr [rdi][recvfromntddd.from_processid],rax
mov rax,qword ptr gs:[30h]
mov eax,dword ptr [rax 48h];GetCurrentThreadId;_CLIENT_ID.UniqueThread
mov qword ptr [rdi][recvfromntddd.from_threadid],rax
mov rax,@DllBase
mov qword ptr [rdi][recvfromntddd.dllbase],rax
lea rdi, [rdi recvfromntddd.from_EXCEPTION_RECORD]
mov rsi,_rcx
mov rcx,sizeof EXCEPTION_RECORD
.if <<test rsi,rsi>>, NOZERO?
cld
REP MOVSB
.else
mov rax,0cccccccccccccccch
cld
rep stosb
;mov qword ptr [rdi],rax
.endif
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
lea rdi, [rdi recvfromntddd.from__CONTEXT]
mov rcx,sizeof _CONTEXT
mov rsi,_rdx
.if <<test rsi,rsi>>, NOZERO?
cld
REP MOVSB
.else
mov al,90h
cld
rep stosb
; mov qword ptr [rdi],rax
;mov qword ptr [rdi],0
.endif
; mov rcx,sizeof DISPATCHER_CONTEXT
; mov rsi,_r9
; .if <<test rsi,rsi>>, NOZERO?
; REP MOVSB
; .endif
; mov rsi,_r8
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
lea rdi, [rdi recvfromntddd.from__Rip]
mov rcx,11h
mov rsi,_rdx
mov rsi,[rsi _CONTEXT._Rip]
copy_rip::
.if <<test rsi,rsi>>, NOZERO?
REP MOVSB
.else
copy_rip_end::
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
lea rdi, [rdi recvfromntddd.from__Rip]
mov rax,9090909090909090h
mov qword ptr [rdi],rax
mov word ptr [rdi],0cd04h;int 4
mov qword ptr [rdi 8],rax
mov byte ptr [rdi 10h],90h
.endif
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
lea rdi, [rdi recvfromntddd.RBP_0]
mov rcx,2h
mov rsi,_rdx
mov rsi,[rsi _CONTEXT._Rbp]
copy_in_data_rbp::
.if <<test rsi,rsi>>, NOZERO?
REP MOVSQ ;这里有可能RBP的地址会产生异常
.else
copy_in_rbp_end::
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
lea rdi, [rdi recvfromntddd.RBP_0]
mov rax,9090909090909090h
mov qword ptr [rdi],rax
mov qword ptr [rdi 8], rax
.endif
comment ~
;mov qword ptr[rsp 30],0
;mov qword ptr[rsp 28],SEC_COMMIT
;mov qword ptr [rsp 20],PAGE_READWRITE
;lea r9,@LARGE_INTEGER
;mov qword ptr [r9],1000h
;lea r8,@OBJECT_ATTRIBUTES
;mov rdx,0f0007h
;lea rcx,@SectionHandle
;mov rax,ip
;lea rax, [rax 78e9c1d0h]
;call rax ;ZwCreateSection PROTO64 external,ZwCreateSection, :QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD
;test eax,eax
;lea rax,[rax 78e78120h] ; RtlpExecuteHandlerForException 文件地址 1795a :E8 C1 FB 00 00 被替换为:text:0000000078E6855A E8 A1 1D 19 00 call near ptr qword_78FFA300
; lea rax,[rax 78e68150h] ;
;RtlpCallVectoredHandlers ;0000000078E681ED E8 5E FF FF FF 文件地址: 175ED 更改为E8 0e211900 call near ptr qword_78FFA300 call RtlpCallVectoredHandlers 已经替换了78E681ED的地址
; mov _r11,rax
;pop rax
;要对VEH作个检测
; mov r13d,2 ;VEH: 向量化异常处理程序(进程相关) mov r13d,3 对VCH检测
; mov rax, qword ptr gs:[30h] ;teb
; mov r12, [rax 60h] ;peb
; mov eax, [r12 50h] ;ProcessUsingVEH
; bt eax, r13d ; ;BT 把 eax 的第3位(或者 第2位根据 r8 2决定)复制到 CF 从0 开始排列
; 0x050 ProcessUsingVEH : Pos 2, 1 Bit
; 0x050 ProcessUsingVCH : Pos 3, 1 Bit
; VEH: 向量化异常处理程序(进程相关)
; VCH: 同上,也是向量化异常处理程序,
; 不过它总是在最后被调用(进程相关)
;VEH,VCH:保存在ntdll.dll模块的_LdrpVectorHandlerList全局变量里
; .if CARRY?
; .endif
;0F 82 FD 16 00 00 jb loc_78E6988D
comment ~
mov rax,ip
mov rcx,[rax 78ffa100h] ;1自动跟踪MT5 或 0只是检测它的异常断点 -1,动态调试
.if <<test rcx,rcx>>, GREATER?
;自动跟踪MT5
mov rax,ip
mov rsi,[rax 78ffa008h];@viewBaseAddress
lea rsi,[rsi 4096 80h] ;这里存入的是官方的异常断点,这个值应该是个偏移量,因为程序每次装入的地址应该不一样。
;前4 个字节是异常总共占用的大小
mov ecx,[rsi orgbreak.count_except]
mov rbx,0
mov rdi,_rdx
mov rdi,[rdi _CONTEXT._Rip]
.while <<test rcx,rcx>>,NOZERO?
mov rax,[rsi orgbreak.except_point][rbx]
add rax, @DllBase
.if <<cmp rdi,rax>>, ZERO? ;官方的断点需要原程序自己去处理
mov r8d,[rsi orgbreak.except_flags][rbx]
;官方的断点要在 RtlpCallVectoredHandlers 里标记 还要在RtlRestoreContext里标记
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock,通知seh_64 接收数据
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
mov rax,ip
lea rax,[rax 78e681d0h] ; RtlDispatchException
leave
pushfq
; or byte ptr [rsp 1],1 ;单步
popfq
jmp rax
;这里不会返回了
.endif
add rbx,sizeof orgbreak
dec rcx
.endw
mov rsi,_rdx
mov rax,[rsi _CONTEXT._Rip]
track_point::
.if <<cmp byte ptr [rax],09ch>>, ZERO?;;9c pushfq 如果当前INT1中断的地址内容是 pushf
sub qword ptr [rsi _CONTEXT._Rsp],8 ;模拟pushfq 的执行
mov eax,[rsi _CONTEXT.EFlags]
and rax,0fffffffffffffeffh ;把tf 置0 if(中断标志) 用sti cli 修改,用户模式没有权限
mov rbx,[rsi _CONTEXT._Rsp]
mov [rbx],rax
inc [rsi _CONTEXT._Rip];模拟pushf 之后 跳过pushf 的执行
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
mov qword ptr [rdi][recvfromntddd.flage_CONTEXT_EFlags],1;我们模拟pufhf 的执行 所以加个标志通知 seh_64。exe 处理这个情况
track_point_end::
and [rsi _CONTEXT.EFlags],0fffffeffh ;把tf和IF 置0
OR [rsi _CONTEXT.EFlags],100H
mov rax,ip
mov rdi,[rax 78ffa008h];@viewBaseAddress
mov rax,[rsi _CONTEXT._Rip]
jmp track_point ;或许有多个pushfq
;ID VIP VIF AC VM RF NT IOPL OF DF IF TF SF ZF AF PF CF
;21 20 19 18 17 16 14 13–12 11 10 9 8 7 6 4 2 0
.elseif <<cmp word ptr [rax],09cf3h>>, ZERO?;;9c
inc [rsi _CONTEXT._Rip];模拟pushf 之后 跳过pushf 的执行
mov rax,[rsi _CONTEXT._Rip]
jmp track_point
.elseif <<cmp word ptr [rax],09c2eh>>, ZERO?;;9c
inc [rsi _CONTEXT._Rip];模拟pushf 之后 跳过pushf 的执行
mov rax,[rsi _CONTEXT._Rip]
jmp track_point
.elseif <<cmp word ptr [rax],09c40h>>, ZERO?;;9c
inc [rsi _CONTEXT._Rip];模拟pushf 之后 跳过pushf 的执行
mov rax,[rsi _CONTEXT._Rip]
jmp track_point
.else
OR [rsi _CONTEXT.EFlags],100H
.endif
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行 我们HOOK的 RtlRestoreContext 会设置单步
ret ;返回后继续调用RtlRestoreContext 这个RtlRestoreContext 调用不会再产生 异常,(我们没有设置 单步标志)下一次的异常是在返回用户地址后产生的
.elseif <<test rcx,rcx>>, zero? ;1要调试MT5 或 0只是检测它的异常断点 -1,动态调试
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock,通知seh_64 接收数据
.else
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据
_80h_instruct:
mov rax,ip
@@:
lock bts qword ptr [rax 78ffa0f8h], 0 ; BTS就是根据位偏移值从位串中取出一位放入CF中,然后将位串中的该位置成1
jnc @f
_wait2:
pause
wait
fwait
test qword ptr [rax 78ffa0f8h], 1
jnz _wait2
jmp @b
@@:
mov rax,ip
mov rsi,[rax 78ffa008h];@viewBaseAddress 78ffc000
mov qword ptr [rsi][recvfromntddd.flags],0
lea rsi,[rsi 4096] ;78ffd000h单步调试指令区 sizeof == 80h
.if <<cmp byte ptr [rsi],0>>,NOZERO? ;这里是指令区
lea rdi,[rax 78ffa060h]
mov rcx,10h
rep movsq ;读80h个指令
mov rcx,_rcx
mov rdx,_rdx
lea rbx,[rax 78ffa060h]
call rbx;qword ptr [rax 78ffa060h] ;80H字节的指令区
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据
jmp _80h_instruct
nop
.else
mov rax,ip
lock and qword ptr [rax 78ffa0f0h], 0 ; release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据 release spin lock,通知seh_64 接收数据
.endif
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 继续执行
; ret ;不能直接返回:RtlRestoreContext 已经被我们HOOK,会生成单步中断
mov rax,ip
lea rax,[rax 78e9b39fh] ; RtlRestoreContext
;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改为E8 3afb1500 call near ptr qword_78FFb800
mov rcx,_rcx
mov rdx,_rdx
mov rcx,rdx ;context
xor rdx,rdx
leave
;jmp qword ptr _r11
jmp rax
.endif
error_DispatchException::
error:
exit: ;不是我们需要的
add rsp,80h
pop r15
pop r14
pop r13
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
mov r8,_r8
mov r9,_r9
mov r10,_r10
mov r11,_r11
mov rax,ip
;lea rax,[rax 78e78120h] ; RtlpExecuteHandlerForException 文件地址 1795a :E8 C1 FB 00 00 被替换为:text:0000000078E6855A E8 A1 1D 19 00 call near ptr qword_78FFA300
;lea rax,[rax 78e68150h] ;
;RtlpCallVectoredHandlers ;0000000078E681ED E8 5E FF FF FF 文件地址: 175ED 更改为E8 0e211900 call near ptr qword_78FFA300 call RtlpCallVectoredHandlers 已经替换了78E681ED的地址
lea rax,[rax 78e681d0h] ; RtlDispatchException
;.text:0000000078E9BCB3 E8 18 C5 FC FF call RtlDispatchException ;文件地址: 4b0b4 更改为E8 48e61500 call near ptr qword_78FFA300
; mov _r11,rax
;pop rax
;jmp qword ptr _r11
leave
jmp rax
;call rax 这里不能用CALL 会破坏堆栈平衡
ret
_DispatchException endp
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved