網上有很多關于pos機開機異常,NTDLL 異常處理在調試中的應用的知識,也有很多人為大家解答關于pos機開機異常的問題,今天pos機之家(www.www690aa.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
1、pos機開機異常
pos機開機異常
顧名思義我們今天討論的是應用層軟件的調試,且是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 16org 300hdq 0cccccccccccccccchdq 0cccccccccccccccch_DispatchException procLOCAL @OBJECT_ATTRIBUTES :OBJECT_ATTRIBUTES ;30hLOCAL @seh_64_exe_UNICODE_STRING :UNICODE_STRING ;<?>;10hLOCAL ip:qwordLOCAL @SectionHandle:qwordLOCAL @LARGE_INTEGER:qwordLOCAL @SectionOffset:qwordLOCAL @ViewSize:qwordLOCAL @viewBaseAddress:qwordLOCAL @PEB_LDR_DATA :qwordLOCAL @NEXT_PEB_LDR_DATA:qword ;要調試的程序的文件名LOCAL @NEXT__for_all_PEB_LDR_DATA:qword ;要調試的程序所包含的全部DLL信息LOCAL @flags_debug_or_nodebug:qwordLOCAL @hevent_read_for_seh_64 :qwordLOCAL @hevent_write_for_ntdll :qword ;NTDLL可以寫數據了LOCAL @DllBase :qwordLOCAL _rcx:qword; ExceptionRecordLOCAL _rdx:qword;ContextRecordLOCAL _rsi:qwordLOCAL _rdi:qwordLOCAL _r8:qwordLOCAL _r9:qwordLOCAL _r10:qwordLOCAL _r11:qwordLOCAL _r12:qword, _r13:qword, _r14:qword, _r15:qwordLOCAL @ObjectDirectory:qwordLOCAL @count:qwordmov _rcx,rcxmov _rdx,rdxmov _rsi,rsimov _rdi,rdimov _r8,r8mov _r9,r9mov _r10,r10mov _r11,r11push rcxpush rdxpush rbxpush rbppush rsipush rdipush r12push r13push r14push r15sub rsp, 80hcall @f@@:pop raxlea rbx,@bsub rax,rbxmov ip,raxmov rsi,[rdx+_CONTEXT._Rip]lea rdi, track_pointadd rdi,raxlea rbx, track_point_endadd 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;.endiflea rbx,track_point_endmov [rdx+_CONTEXT._Rip],rbxadd rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行; ret ;不能直接返回:RtlRestoreContext 已經被我們HOOK,會生成單步中斷mov rax,iplea rax,[rax+78e9b39fh] ; RtlRestoreContext;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改為E8 3afb1500 call near ptr qword_78FFb800mov rcx,_rcxmov rdx,_rdxmov rcx,rdx ;contextxor rdx,rdxleave;jmp qword ptr _r11jmp rax.endif.endifmov rsi,[rdx+_CONTEXT._Rip]lea rdi, copy_ripadd rdi,raxlea rbx, copy_rip_endadd 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;.endiflea rbx,copy_rip_endmov [rdx+_CONTEXT._Rip],rbxadd rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行; ret ;不能直接返回:RtlRestoreContext 已經被我們HOOK,會生成單步中斷mov rax,iplea rax,[rax+78e9b39fh] ; RtlRestoreContext;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改為E8 3afb1500 call near ptr qword_78FFb800mov rcx,_rcxmov rdx,_rdxmov rcx,rdx ;contextxor rdx,rdxleave;jmp qword ptr _r11jmp rax.endif.endiflea rdi,copy_in_data_rbpadd rdi,raxlea rbx,copy_in_rbp_endadd rbx,rax.if << cmp rsi,rdi>>, ABOVE?||EQUAL? ;可能產生異常的地方,處理方法.if <<cmp rsi,rbx>> ,BELOW?||EQUAL?mov rax,iplea rbx,copy_in_rbp_endmov [rdx+_CONTEXT._Rip],rbxadd rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行; ret ;不能直接返回:RtlRestoreContext 已經被我們HOOK,會生成單步中斷mov rax,iplea rax,[rax+78e9b39fh] ; RtlRestoreContext;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改為E8 3afb1500 call near ptr qword_78FFb800mov rcx,_rcxmov rdx,_rdxmov rcx,rdx ;contextxor rdx,rdxleave;jmp qword ptr _r11jmp rax.endif.endiflea rdi,[rax+78ffa060h]lea rbx,[rax+78ffa0e0h].if << cmp rsi,rdi>>, ABOVE?||EQUAL?.if <<cmp rsi,rbx>> ,BELOW?||EQUAL?mov rax,iplea rbx,[rax+78ffa0e0h] ;這里存放的是ret指令(POP RCX POP RDI POP RSI RETmov [rdx+_CONTEXT._Rip],rbxadd rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行; ret ;不能直接返回:RtlRestoreContext 已經被我們HOOK,會生成單步中斷mov rax,iplea rax,[rax+78e9b39fh] ; RtlRestoreContext;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改為E8 3afb1500 call near ptr qword_78FFb800mov rcx,_rcxmov rdx,_rdxmov rcx,rdx ;contextxor rdx,rdxleave;jmp qword ptr _r11jmp 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,raxmov rax,[rdx+_CONTEXT._R13] ;sizeof_filemov @hevent_read_for_seh_64,0mov rax,[rdx+_CONTEXT._R14]mov @hevent_write_for_ntdll,0mov rax,iplea 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,rcxmov 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,raxmov rbx,[rax+30h];_LDR_DATA_TABLE_ENTRY.DllBasemov @DllBase,rbxlea rax,[rax+58h]; _LDR_DATA_TABLE_ENTRY.BaseDllName : _UNICODE_STRING; mov rsi,[rax+_UNICODE_STRING.Buffer]; invoke MessageBoxW,0,rsi,addr ldrtest,MB_OKmovzx rcx,[rax+_UNICODE_STRING._Length]mov rsi,[rax+_UNICODE_STRING.Buffer]mov rax,iplea rdi ,[rax+78ffa010h] ;szMMFName db "seh_64.exe64---",0cldrepz cmpsb.if ZERO? ;是seh_64發出的異常指令mov rdx,_rdxlea rsi , [rdx+_CONTEXT._Rsi];_rsi--_r11 總共30H 存放有要調試的程序mov ecx,30hmov rax,iplea rdi ,[rax+78ffa030h+8]cldrep movsbmov rcx,[rdx+_CONTEXT._R15]mov qword ptr [rax+78ffa030h],rcxlea rsi , [rdx+_CONTEXT.___u38.data.__s1._Xmm0]lea rdi ,[rax+78ffa200h]mov rcx,20hcldrep movsqmov rcx,@flags_debug_or_nodebugmov [rax+78ffa100h],rcx ;1自動跟蹤MT5 或 0只是檢測它的異常斷點 -1,動態調試mov rdx,_rdxmov rcx,8989898989898989hmov [rdx+_CONTEXT._Rax],rcxmov rcx,9a9a9a9a9a9a9a9ahmov [rdx+_CONTEXT._Rbx],rcxmov rcx,0ababababababababhmov [rdx+_CONTEXT._Rcx],rcxmov rcx,0bcbcbcbcbcbcbcbchmov [rdx+_CONTEXT._Rdx],rcxmov rax,ipmov rcx,78ffc000hadd rcx,raxmov [rdx+_CONTEXT._Rsi],rcx ;@viewBaseAddressmov rcx,78ffa0f8hadd rcx,raxmov [rdx+_CONTEXT._Rdi],rcx ;@hevent_write_for_ntdll;NTDLL可以寫數據了mov rcx,78ffa0f0hadd rcx,raxmov [rdx+_CONTEXT._R9],rcx ;;hevent_read_for_seh_64mov rcx,78ffc000hadd rcx,raxmov @viewBaseAddress,rcxlock and qword ptr [rax+78ffa008h],0;@viewBaseAddresslock or [rax+78ffa008h],rcxlock and qword ptr [rax+78ffa000h],0;第一次運行需要獲取程序需要的DLL信息lock and qword ptr [rax+78ffa110h],0;進程IDlock and qword ptr [rax+78ffa120h],0;78ffa120h license.lic 文件句柄mov rcx,[rdx+_CONTEXT._R13] ;sizeof_filemov qword ptr [rax+78ffa118h],rcx;被調試程序大小mov rcx,[rdx+_CONTEXT._R14];lock and qword ptr [rax+78ffa108h],0lock 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, 0mov rax,ipadd rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行ret.endifmov rax, @NEXT_PEB_LDR_DATAmov rax,[rax].endw.endif.endif.endif.endif.endif.endif.endif;是否MT5產生的異常mov rax,ipmov rcx,[rax+78ffa108h] ;總開關,系統在初始化時,不需要任何檢測了.if <<test rcx,rcx>>, ZERO?jmp exit.endifmov rax,ipmov rcx,[rax+78ffa110h]mov rax,qword ptr gs:[30h] ;_TEB. _NT_TIB.selfmov 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,iplea 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,rcxmov 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 == 0mov @NEXT_PEB_LDR_DATA,raxmov rbx,[rax+30h];_LDR_DATA_TABLE_ENTRY.DllBasemov @DllBase,rbxlea rax,[rax+58h]; _LDR_DATA_TABLE_ENTRY.BaseDllName : _UNICODE_STRINGmovzx rcx,[rax+_UNICODE_STRING._Length]mov rbx,ip.if <<cmp rcx,[rbx+78ffa030h]>>,zero? ; 要調試的程序名長度mov rsi,[rax+_UNICODE_STRING.Buffer]mov rax,iplea rdi ,[rax+78ffa030h+8]cldrepz cmpsb.if ZERO? ;MT5的異常;這里找到MT5了;保存加載的DLL信息和進程IDmov rax,ipmov rcx,@DllBasemov [rax+78ffa0e8h],rcxmov rcx,[rax+78ffa000h].if <<test rcx,rcx>>,ZERO? ;第一次運行需要獲取程序需要的DLL信息comment ~lea rcx,@seh_64_exe_UNICODE_STRINGlea rdx, [rax+78ffa010h+8]lea rax,[rax+78e9f5d0h]call rax ;RtlInitUnicodeStringlea rcx,@ObjectDirectorymov rax,iplea rax, [rax+78EF7FA0h];call rax;BaseGetNamedObjectDirectorymov rax,iplea rdx,@seh_64_exe_UNICODE_STRINGlea rcx,@OBJECT_ATTRIBUTESmov rax,@ObjectDirectoryInitializeObjectAttributes rcx, rdx, OBJ_OPENIF, rax, NULL;OBJ_OPENIF equ 80hlea r8,@OBJECT_ATTRIBUTESmov rdx,EVENT_ALL_ACCESSlea rcx,@hevent_read_for_seh_64mov rax,iplea rax, [rax+78e9c130h]call rax ;ZwOpenEvent returns STATUS_SUCCESS on success.if <<test rax,rax>>, NOZERO?jmp exit.endifmov rax,ipmov rcx,@hevent_read_for_seh_64;mov [rax+78ffa0f0h],rcxlea rcx,@seh_64_exe_UNICODE_STRINGlea rdx, [rax+78ffa010h+10H]lea rax,[rax+78e9f5d0h]call rax ;RtlInitUnicodeStringlea rcx,@ObjectDirectorymov rax,iplea rax, [rax+78EF7FA0h];call rax;BaseGetNamedObjectDirectorymov rax,iplea rdx,@seh_64_exe_UNICODE_STRINGlea rcx,@OBJECT_ATTRIBUTESmov rax,@ObjectDirectoryInitializeObjectAttributes rcx, rdx, OBJ_OPENIF, rax, NULL;OBJ_OPENIF equ 80hlea r8,@OBJECT_ATTRIBUTESmov rdx,EVENT_ALL_ACCESSlea rcx,@hevent_write_for_ntdllmov rax,iplea rax, [rax+78e9c130h]call rax ;ZwOpenEvent returns STATUS_SUCCESS on success.if <<test rax,rax>>, NOZERO?jmp exit.endifmov rax,ipmov rcx,@hevent_write_for_ntdll;NTDLL可以寫數據了mov [rax+78ffa0f8h],rcxlea rcx,@seh_64_exe_UNICODE_STRINGlea rdx, [rax+78ffa010h]lea rax,[rax+78e9f5d0h]call rax ;RtlInitUnicodeStringlea rcx,@ObjectDirectorymov rax,iplea rax, [rax+78EF7FA0h];call rax;BaseGetNamedObjectDirectorymov rax,iplea rdx,@seh_64_exe_UNICODE_STRINGlea rcx,@OBJECT_ATTRIBUTESmov rax,@ObjectDirectoryInitializeObjectAttributes rcx, rdx, OBJ_OPENIF, rax, NULL;OBJ_OPENIF equ 80hlea r8,@OBJECT_ATTRIBUTESmov rdx,SECTION_MAP_WRITE or SECTION_MAP_READ ;SECTION_MAP_WRITE equ 2h SECTION_MAP_READ equ 4hlea rcx,@SectionHandlemov rax,iplea rax, [rax+78e9c0a0h]call rax ;ZwOpenSection returns STATUS_SUCCESS on success.if <<test rax,rax>>,ZERO?mov rcx,@SectionHandlemov rdx,-1;ProcessHandlelea r8,@viewBaseAddressmov @viewBaseAddress,0mov r9,0;ZeroBits,mov qword ptr [rsp+20h],0;CommitSizelea rax,@SectionOffsetmov @SectionOffset,0mov qword ptr [rsp+28h],rax;SectionOffsetlea rax,@ViewSizemov @ViewSize,0mov qword ptr [rsp+30h],rax;ViewSize 分配的尺寸mov qword ptr [rsp+38h],1;ViewShare equ 1mov qword ptr [rsp+40h],0mov qword ptr [rsp+48h],PAGE_READWRITE ; equ 4mov dword ptr [rsp+4ch],-1mov rax,iplea 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,ipmov rcx,1mov @SectionHandle,rcx; lock and qword ptr [rax+78ffa000h],0;第一次運行需要獲取程序需要的DLL信息; lock or [rax+78ffa000h],rcxlock xchg [rax+78ffa000h],rcxmov rax,iplea 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,rcxmov 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!ZwWaitForSingleObjectmov rax,ip@@:lock bts qword ptr [rax+78ffa0f8h], 0 ; BTS就是根據位偏移值從位串中取出一位放入CF中,然后將位串中的該位置成1jnc @f_wait:pausewaitfwaittest qword ptr [rax+78ffa0f8h], 1jnz _waitjmp @b@@:mov rax, @NEXT_PEB_LDR_DATAmov rbx,0.while <<cmp rax,@PEB_LDR_DATA>>,NOZERO?; lea rax,[rax+LIST_ENTRY.Flink]mov @NEXT_PEB_LDR_DATA,raxmov rdx,[rax+30h];_LDR_DATA_TABLE_ENTRY.DllBaselea rax,[rax+58h]; _LDR_DATA_TABLE_ENTRY.BaseDllName : _UNICODE_STRINGmovzx rcx,[rax+_UNICODE_STRING._Length];我們設置的長度是40h unicode模式 是ASCII碼長度的2倍.if <<cmp rcx,40h>>, BELOW?||EQUAL?mov rsi,[rax+_UNICODE_STRING.Buffer]mov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddressmov [rdi][rbx][dllinformation.flags],2mov [rdi][rbx][dllinformation.dllbase],rdxmov [rdi][rbx][dllinformation.dllnamelength],rcxlea rdi,[rdi][rbx][dllinformation.dllname]cldrep movsbadd rbx,sizeof dllinformation.if <<cmp rbx,40*sizeof dllinformation>>, ABOVE?.break.endif.endifmov rax,@NEXT_PEB_LDR_DATAmov rax,[rax+LIST_ENTRY.Flink].endwmov rcx,qword ptr gs:[30h]mov ecx,dword ptr [rcx+40h];GetCurrentProcessIdmov rax,iplock 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 raxmov rax,iplock and qword ptr [rax+78ffa0f0h], 0 ; release spin lock hevent_read_for_seh_64 客戶端可以讀數據了.break ;跳出上一層循環.elsejmp error.endif.elsejmp error.endif.elsejmp error.endif.else.break ;如果已經設置好了,就不需要重復設置了.endif.endif.endifmov rax,@NEXT_PEB_LDR_DATAmov rax,[rax+LIST_ENTRY.Flink].endwmov rax,ipmov rcx,[rax+78ffa110h];進程ID.if <<test rcx,rcx>>, ZERO?;沒有填充進程IDjmp exit.endif.elsejmp exit.endif.elsejmp exit.endif.elsejmp exit.endif.endif;這里確定是MT5后繼續執行mov rax,ipmov rdi,[rax+78ffa0e8h] ;mt5DllBasemov @DllBase,rdi@@:lock bts qword ptr [rax+78ffa0f8h], 0 ; BTS就是根據位偏移值從位串中取出一位放入CF中,然后將位串中的該位置成1 ;;;;NTDLL可以寫數據事件jnc @f_wait1:pausewaitfwaittest qword ptr [rax+78ffa0f8h], 1jnz _wait1jmp @b@@:mov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddressmov rax,qword ptr gs:[30h]mov eax,dword ptr [rax+40h];GetCurrentProcessIdmov qword ptr [rdi][recvfromntddd.flage_CONTEXT_EFlags],0mov qword ptr [rdi][recvfromntddd.flags],1mov qword ptr [rdi][recvfromntddd.from_processid],raxmov rax,qword ptr gs:[30h]mov eax,dword ptr [rax+48h];GetCurrentThreadId;_CLIENT_ID.UniqueThreadmov qword ptr [rdi][recvfromntddd.from_threadid],raxmov rax,@DllBasemov qword ptr [rdi][recvfromntddd.dllbase],raxlea rdi, [rdi+recvfromntddd.from_EXCEPTION_RECORD]mov rsi,_rcxmov rcx,sizeof EXCEPTION_RECORD.if <<test rsi,rsi>>, NOZERO?cldREP MOVSB.elsemov rax,0cccccccccccccccchcldrep stosb;mov qword ptr [rdi],rax.endifmov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddresslea rdi, [rdi+recvfromntddd.from__CONTEXT]mov rcx,sizeof _CONTEXTmov rsi,_rdx.if <<test rsi,rsi>>, NOZERO?cldREP MOVSB.elsemov al,90hcldrep 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,_r8mov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddresslea rdi, [rdi+recvfromntddd.from__Rip]mov rcx,11hmov rsi,_rdxmov rsi,[rsi+ _CONTEXT._Rip]copy_rip::.if <<test rsi,rsi>>, NOZERO?REP MOVSB.elsecopy_rip_end::mov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddresslea rdi, [rdi+recvfromntddd.from__Rip]mov rax,9090909090909090hmov qword ptr [rdi],raxmov word ptr [rdi],0cd04h;int 4mov qword ptr [rdi+8],raxmov byte ptr [rdi+10h],90h.endifmov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddresslea rdi, [rdi+recvfromntddd.RBP_0]mov rcx,2hmov rsi,_rdxmov rsi,[rsi+ _CONTEXT._Rbp]copy_in_data_rbp::.if <<test rsi,rsi>>, NOZERO?REP MOVSQ ;這里有可能RBP的地址會產生異常.elsecopy_in_rbp_end::mov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddresslea rdi, [rdi+recvfromntddd.RBP_0]mov rax,9090909090909090hmov qword ptr [rdi],raxmov qword ptr [rdi+8], rax.endifcomment ~;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_78E6988Dcomment ~mov rax,ipmov rcx,[rax+78ffa100h] ;1自動跟蹤MT5 或 0只是檢測它的異常斷點 -1,動態調試.if <<test rcx,rcx>>, GREATER?;自動跟蹤MT5mov rax,ipmov rsi,[rax+78ffa008h];@viewBaseAddresslea rsi,[rsi+4096+80h] ;這里存入的是官方的異常斷點,這個值應該是個偏移量,因為程序每次裝入的地址應該不一樣。;前4 個字節是異常總共占用的大小mov ecx,[rsi+orgbreak.count_except]mov rbx,0mov rdi,_rdxmov 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,iplock and qword ptr [rax+78ffa0f0h], 0 ; release spin lock,通知seh_64 接收數據add rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11mov rax,iplea rax,[rax+78e681d0h] ; RtlDispatchExceptionleavepushfq; or byte ptr [rsp+1],1 ;單步popfqjmp rax;這里不會返回了.endifadd rbx,sizeof orgbreakdec rcx.endwmov rsi,_rdxmov rax,[rsi+ _CONTEXT._Rip]track_point::.if <<cmp byte ptr [rax],09ch>>, ZERO?;;9c pushfq 如果當前INT1中斷的地址內容是 pushfsub 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],raxinc [rsi+ _CONTEXT._Rip];模擬pushf 之后 跳過pushf 的執行mov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddressmov qword ptr [rdi][recvfromntddd.flage_CONTEXT_EFlags],1;我們模擬pufhf 的執行 所以加個標志通知 seh_64。exe 處理這個情況track_point_end::and [rsi+ _CONTEXT.EFlags],0fffffeffh ;把tf和IF 置0OR [rsi+ _CONTEXT.EFlags],100Hmov rax,ipmov rdi,[rax+78ffa008h];@viewBaseAddressmov 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?;;9cinc [rsi+ _CONTEXT._Rip];模擬pushf 之后 跳過pushf 的執行mov rax,[rsi+ _CONTEXT._Rip]jmp track_point.elseif <<cmp word ptr [rax],09c2eh>>, ZERO?;;9cinc [rsi+ _CONTEXT._Rip];模擬pushf 之后 跳過pushf 的執行mov rax,[rsi+ _CONTEXT._Rip]jmp track_point.elseif <<cmp word ptr [rax],09c40h>>, ZERO?;;9cinc [rsi+ _CONTEXT._Rip];模擬pushf 之后 跳過pushf 的執行mov rax,[rsi+ _CONTEXT._Rip]jmp track_point.elseOR [rsi+ _CONTEXT.EFlags],100H.endifmov rax,iplock and qword ptr [rax+78ffa0f0h], 0 ; release spin lock,通知seh_64 接收數據 release spin lock,通知seh_64 接收數據 release spin lock,通知seh_64 接收數據add rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行 我們HOOK的 RtlRestoreContext 會設置單步ret ;返回后繼續調用RtlRestoreContext 這個RtlRestoreContext 調用不會再產生 異常,(我們沒有設置 單步標志)下一次的異常是在返回用戶地址后產生的.elseif <<test rcx,rcx>>, zero? ;1要調試MT5 或 0只是檢測它的異常斷點 -1,動態調試mov rax,iplock and qword ptr [rax+78ffa0f0h], 0 ; release spin lock,通知seh_64 接收數據.elsemov rax,iplock 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中,然后將位串中的該位置成1jnc @f_wait2:pausewaitfwaittest qword ptr [rax+78ffa0f8h], 1jnz _wait2jmp @b@@:mov rax,ipmov rsi,[rax+78ffa008h];@viewBaseAddress 78ffc000mov qword ptr [rsi][recvfromntddd.flags],0lea rsi,[rsi+4096] ;78ffd000h單步調試指令區 sizeof == 80h.if <<cmp byte ptr [rsi],0>>,NOZERO? ;這里是指令區lea rdi,[rax+78ffa060h]mov rcx,10hrep movsq ;讀80h個指令mov rcx,_rcxmov rdx,_rdxlea rbx,[rax+78ffa060h]call rbx;qword ptr [rax+78ffa060h] ;80H字節的指令區mov rax,iplock and qword ptr [rax+78ffa0f0h], 0 ; release spin lock,通知seh_64 接收數據 release spin lock,通知seh_64 接收數據 release spin lock,通知seh_64 接收數據jmp _80h_instructnop.elsemov rax,iplock and qword ptr [rax+78ffa0f0h], 0 ; release spin lock,通知seh_64 接收數據 release spin lock,通知seh_64 接收數據 release spin lock,通知seh_64 接收數據.endifadd rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11; mov rax,1 ;RtlDispatchException 返回1 之后RtlRestoreContext 繼續執行; ret ;不能直接返回:RtlRestoreContext 已經被我們HOOK,會生成單步中斷mov rax,iplea rax,[rax+78e9b39fh] ; RtlRestoreContext;text:0000000078E9BCC1 E8 D9 F6 FF FF call RtlRestoreContext ; VOID WINAPI RtlRestoreContext( ;文件地址: 4b0c1 更改為E8 3afb1500 call near ptr qword_78FFb800mov rcx,_rcxmov rdx,_rdxmov rcx,rdx ;contextxor rdx,rdxleave;jmp qword ptr _r11jmp rax.endiferror_DispatchException::error:exit: ;不是我們需要的add rsp,80hpop r15pop r14pop r13pop r12pop rdipop rsipop rbppop rbxpop rdxpop rcxmov r8,_r8mov r9,_r9mov r10,_r10mov r11,_r11mov 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 _r11leavejmp rax;call rax 這里不能用CALL 會破壞堆棧平衡ret_DispatchException endp
以上就是關于pos機開機異常,NTDLL 異常處理在調試中的應用的知識,后面我們會繼續為大家整理關于pos機開機異常的知識,希望能夠幫助到大家!









