NTDLL 异常处理在调试中的应用

NTDLL 异常处理在调试中的应用

首页休闲益智堆栈平衡更新时间:2024-05-09

顾名思义我们今天讨论的是应用层软件的调试,且是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