Well-known DEP-violating thunks
這幾天調試發現一個奇怪的現象,一個在數據區段執行的指令,在開啓了系統dep時
竟然還可以繼續執行,換成其他指令就不可以,而且執行時這個內存屬性仍舊是不可
執行屬性。同時按理指令是一條一條執行,但是這個指令的執行是跳躍了,瞬間差點毀了
多年的指令執行三觀。
debug
win7+system dep open
Breakpoint 0 hit
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=2e81e342 esp=0006dfbc ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MDIVWCTL!DllUnregisterServer+0x4399:
2e81e342 ffd6 call esi {001ff860} --------------〉問題點
0:000> db esi
000b1ec8 c7 44 24 04 84 ec 2d 00-e9 45 ad 76 2e ab ab ab .D$...-..E.v....
000b1ed8 ab ab ab ab ab fe ee fe-00 00 00 00 00 00 00 00 ................
000b1ee8 23 02 05 00 ee 14 ee 00-78 01 09 00 78 01 09 00 #.......x...x...
000b1ef8 ee fe ee fe ee fe ee fe-ee fe ee fe ee fe ee fe ................
000b1f08 ee fe ee fe ee fe ee fe-ee fe ee
*** ERROR: Module load completed but symbols could not be loaded for mspview.exe
0:000> u 001ff860
001ff860 c744240484609d04 mov dword ptr [esp+4],49D6084h --------------〉數據段2條要執行指令
001ff868 e9add3612e jmp MDIVWCTL!DllUnregisterServer+0x2c71 (2e81cc1a)
001ff86d ab stos dword ptr es:[edi]
001ff86e ab stos dword ptr es:[edi]
001ff86f ab stos dword ptr es:[edi]
001ff870 ab stos dword ptr es:[edi]
001ff871 ab stos dword ptr es:[edi]
001ff872 ab stos dword ptr es:[edi]
0:000> t
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff860 esp=0006dfb8 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
001ff860 c744240484609d04 mov dword ptr [esp+4],49D6084h ss:0023:0006dfbc=00030240
0:000> t -----------------〉單步了,但是直接跳到這裏了,毀三觀吧
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=2e81cc1b esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MDIVWCTL!DllUnregisterServer+0x2c72:
2e81cc1b 8bec mov ebp,esp
0:000> !address 001ff860
Failed to map Heaps (error 80004005)
Usage: <unclassified>
Allocation Base: 001d0000
Base Address: 001d0000
End Address: 00202000
Region Size: 00032000
Type: 00020000 MEM_PRIVATE
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE ----------->沒有可以執行屬性,但是竟然可以執行
0:000> r eip=001ff86d
0:000> r
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff86d esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
001ff86d ab stos dword ptr es:[edi] es:0023:00030240=????????
0:000> eb 001ff86d 90 90 90 90 ------------>更換成其他指令不可以執行
0:000> r
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff86d esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
001ff86d 90 nop
0:000> t
(9f0.9f4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff86d esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
001ff86d 90 nop
查閱資料發現這個是爲了兼容ATL實現的dep 兼容指令,叫做well-known DEP-violating thunks
如果PE header裏面沒有設置IMAGE_DLLCHARACTERISTICS_NX_COMPAT 標誌既可以保持這個兼容性。
(The application compatibility team found that there were so many programs written with application frameworks that were not DEP-compatible (ATL mostly, but a few others) that nobody would actually enable DEP because the odds were close to 100% that there would be some program on the system that was not DEP-ready. Even DEP-fan Leo Davidson runs a couple of programs that don't work with DEP enabled. And it takes only one program to foul an upgrade.
When the kernel encounters a DEP exception, it checks whether thunk emulation is enabled, and if so (which it usually is), it checks whether the code sequence is one of the "well-known DEP-violating thunks". If so, then it simulates the actions the thunks would have performed and resumes execution instead of raising the exception. For example, if thunk emulation is enabled and you just took a DEP exception on the code sequence
mov ecx, 12345678
jmp 43218765
the kernel thunk emulator will perform the moral equivalent of
pContext->Ecx = 0x12345678;
pContext->Eip = 0x43218765;
return EXCEPTION_CONTINUE_EXECUTION;)
查看內核代碼,發現可執行的三組序列指令 (不同版本會有所差別)
004442BC > C74424 04 54EC2D00 MOV DWORD PTR SS:[ESP+4],2DEC54
004442C4 - E9 45AD762E JMP 2EBAF00E
004442C9 B9 57FF15D0 MOV ECX,D015FF57
004442CE - E9 40006681 JMP 81AA4313
004442D3 BA 4D5A75E9 MOV EDX,E9755A4D
004442D8 - E9 483C03C8 JMP C8477F25
004442DD E1 FF LOOPDE SHORT MSPVIEW.004442DE
內核實現過程 ntkrnlpa.exe
KiDispatchException
.text:004274DA lea eax, [ebp-2E8h]
.text:004274E0 push eax
.text:004274E1 push ecx
.text:004274E2 push ebx
.text:004274E3 call _KeContextFromKframes@12 ; KeContextFromKframes(x,x,x)
.text:004274E8 mov eax, [esi]
.text:004274EA cmp eax, 80000003h
.text:004274EF jz short loc_42755F
.text:004274F1 cmp eax, 10000004h
.text:004274F6 jnz short loc_427565
.text:004274F8 mov dword ptr [esi], 0C0000005h
.text:004274FE cmp byte ptr [ebp+14h], 1
.text:00427502 jnz short loc_427565
.text:00427504 lea eax, [ebp-2E8h]
.text:0042750A push eax
.text:0042750B push esi
.text:0042750C call _KiCheckForAtlThunk@8 ; KiCheckForAtlThunk(x,x)
signed int __stdcall KiEmulateAtlThunk(int *opcode_buf, int *a2, int a3, int a4, int a5)
{
int v6; // edx@3
int v7; // esi@3
int v8; // eax@5
int v9; // eax@9
int v10; // edi@9
int v11; // eax@11
int v12; // eax@16
int v13; // [sp+18h] [bp-28h]@3
int v14; // [sp+20h] [bp-20h]@3
char v15; // [sp+27h] [bp-19h]@5
if ( *(_BYTE *)(*(_DWORD *)(*MK_FP(__FS__, 292) + 68) + 107) & 4 )
return 0;
v7 = *opcode_buf;
v6 = *a2;
v13 = *a2;
v14 = 0;
if ( *opcode_buf >= (unsigned int)MmUserProbeAddress )
*MmUserProbeAddress = 0;
v8 = *MK_FP(__FS__, 24) + 0xFB4;
v15 = *(_BYTE *)v8;
if ( *(_BYTE *)v8 )
*(_BYTE *)v8 = 0;
if ( *(_DWORD *)v7 != 0x42444C7 || *(_BYTE *)(v7 + 8) != 0xE9u ) ---------------〉三組指令類型
{
if ( *(_BYTE *)v7 != 0xB9u || *(_BYTE *)(v7 + 5) != 0xE9u )
{
if ( *(_BYTE *)v7 != 0xBAu
|| *(_BYTE *)(v7 + 5) != 0xB9u
|| *(_WORD *)(v7 + 0xA) != 0xE1FFu
|| (v10 = *(_DWORD *)(v7 + 6), !MmCheckForSafeExecution(v7, v6, *(_DWORD *)(v7 + 6), 0)) )
return v14;
*(_DWORD *)a5 = *(_DWORD *)(v7 + 1);
*(_DWORD *)a4 = v10;
}
else
{
v12 = *(_DWORD *)(v7 + 6);
v10 = v12 + v7 + 10;
if ( !MmCheckForSafeExecution(v7, v6, v12 + v7 + 10, 1) || !v15 )
return v14;
*(_DWORD *)a4 = *(_DWORD *)(v7 + 1);
}
}
else
{
v9 = *(_DWORD *)(v7 + 9);
v10 = v9 + v7 + 13;
if ( !MmCheckForSafeExecution(v7, v6, v9 + v7 + 13, 1) || !v15 )
return v14;
v11 = v13 + 4;
if ( v13 + 4 >= (unsigned int)MmUserProbeAddress )
*(_BYTE *)MmUserProbeAddress = 0;
*(_BYTE *)v11 = *(_BYTE *)v11;
*(_BYTE *)(v13 + 7) = *(_BYTE *)(v13 + 7); -----------〉模擬執行
*(_DWORD *)v11 = *(_DWORD *)(v7 + 4);
}
*opcode_buf = v10;
return 1;
}
debug過程
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=778a7094 esi=002cf600 edi=000401fe
eip=2e81e342 esp=0006dfbc ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MDIVWCTL!DllUnregisterServer+0x4399:
2e81e342 ffd6 call esi {002cf600}
0:000> dd 7ffdffca //查看這個SafeThunkCall 標誌是1
7ffdffca 00000421 00000000 00000000 00000000
7ffdffda 00000000 80300000 0000002a 00000000
7ffdffea 00000000 00000000 00000000 00000000
7ffdfffa 00000000 00000000 00000000 68ac0fa0
7ffe000a 00028b19 00020000 44df0000 34638cef
7ffe001a 346301ce c00001ce ffbcf1dc ffbcffff
7ffe002a 014cffff 0043014c 005c003a 00690057
7ffe003a 0064006e 0077006f 00000073 00000000
KiEmulateAtlThunk獲取SafeThunkCall 標誌代碼
83f017ad 64a118000000 mov eax,dword ptr fs:[00000018h]
83f017b3 05ca0f0000 add eax,0FCAh
83f017b8 8a08 mov cl,byte ptr [eax] ds:0023:7ffdffca=21
83f017ba 80e101 and cl,1
83f017bd 884d17 mov byte ptr [ebp+17h],cl
0:000> dt _TEB 7ffdf000
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x7ffdf02c Void
+0x030 ProcessEnvironmentBlock : 0x7ffd3000 _PEB
+0x034 LastErrorValue : 0
+0x038 CountOfOwnedCriticalSections : 0
+0x03c CsrClientThread : (null)
+0x040 Win32ThreadInfo : 0xfdb31168 Void
+0x044 User32Reserved : [26] 0
+0x0ac UserReserved : [5] 0
+0x0c0 WOW32Reserved : (null)
+0x0c4 CurrentLocale : 0x804
+0x0c8 FpSoftwareStatusRegister : 0
+0x0cc SystemReserved1 : [54] (null)
+0x1a4 ExceptionCode : 0n0
+0x1a8 ActivationContextStackPointer : 0x002107e0 _ACTIVATION_CONTEXT_STACK
+0x1ac SpareBytes : [36] ""
+0x1d0 TxFsContext : 0xfffe
+0x1d4 GdiTebBatch : _GDI_TEB_BATCH
+0x6b4 RealClientId : _CLIENT_ID
+0x6bc GdiCachedProcessHandle : (null)
+0x6c0 GdiClientPID : 0
+0x6c4 GdiClientTID : 0
+0x6c8 GdiThreadLocalInfo : (null)
+0x6cc Win32ClientInfo : [62] 0x20000008
+0x7c4 glDispatchTable : [233] (null)
+0xb68 glReserved1 : [29] 0
+0xbdc glReserved2 : (null)
+0xbe0 glSectionInfo : (null)
+0xbe4 glSection : (null)
+0xbe8 glTable : (null)
+0xbec glCurrentRC : (null)
+0xbf0 glContext : (null)
+0xbf4 LastStatusValue : 0xc0000034
+0xbf8 StaticUnicodeString : _UNICODE_STRING "ntdll.dll"
+0xc00 StaticUnicodeBuffer : [261] "ntdll.dll"
+0xe0c DeallocationStack : 0x00030000 Void
+0xe10 TlsSlots : [64] (null)
+0xf10 TlsLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0xf18 Vdm : (null)
+0xf1c ReservedForNtRpc : 0x0022d350 Void
+0xf20 DbgSsReserved : [2] (null)
+0xf28 HardErrorMode : 0
+0xf2c Instrumentation : [9] (null)
+0xf50 ActivityId : _GUID {00000000-0000-0000-0000-000000000000}
+0xf60 SubProcessTag : (null)
+0xf64 EtwLocalData : (null)
+0xf68 EtwTraceData : (null)
+0xf6c WinSockData : (null)
+0xf70 GdiBatchCount : 0
+0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
+0xf74 IdealProcessorValue : 0
+0xf74 ReservedPad0 : 0 ''
+0xf75 ReservedPad1 : 0 ''
+0xf76 ReservedPad2 : 0 ''
+0xf77 IdealProcessor : 0 ''
+0xf78 GuaranteedStackBytes : 0
+0xf7c ReservedForPerf : (null)
+0xf80 ReservedForOle : 0x002232b8 Void
+0xf84 WaitingOnLoaderLock : 0
+0xf88 SavedPriorityState : (null)
+0xf8c SoftPatchPtr1 : 0
+0xf90 ThreadPoolData : (null)
+0xf94 TlsExpansionSlots : (null)
+0xf98 MuiGeneration : 0
+0xf9c IsImpersonating : 0
+0xfa0 NlsCache : (null)
+0xfa4 pShimData : (null)
+0xfa8 HeapVirtualAffinity : 0
+0xfac CurrentTransactionHandle : (null)
+0xfb0 ActiveFrame : (null)
+0xfb4 FlsData : 0x002160a0 Void
+0xfb8 PreferredLanguages : (null)
+0xfbc UserPrefLanguages : 0x00217fb0 Void
+0xfc0 MergedPrefLanguages : 0x00218150 Void
+0xfc4 MuiImpersonation : 1
+0xfc8 CrossTebFlags : 0
+0xfc8 SpareCrossTebBits : 0y0000000000000000 (0)
+0xfca SameTebFlags : 0x421
+0xfca SafeThunkCall : 0y1 這個標誌爲1時,表示開啓dep 兼容
跟蹤下啥時候設置的
一開始是SafeThunkCall標誌爲0
(f08.bfc): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=0006fb08 edx=778a7094 esi=fffffffe edi=00000000
eip=7790054e esp=0006fb24 ebp=0006fb50 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!LdrpDoDebuggerBreak+0x2c:
7790054e cc int 3
0:000> dd 7ffdf000 +0xfca
7ffdffca 00000420 00000000 00000000 00000000
7ffdffda 00000000 00000000 00000000 00000000
7ffdffea 00000000 00000000 00000000 00000000
7ffdfffa 00000000 00000000 00000000 14200fa0
7ffe000a 00040123 00040000 c9200000 34652aaa
7ffe001a 346501ce c00001ce ffbcf1dc ffbcffff
7ffe002a 014cffff 0043014c 005c003a 00690057
7ffe003a 0064006e 0077006f 00000073 00000000
+0xfc0 MergedPrefLanguages : (null)
+0xfc4 MuiImpersonation : 0
+0xfc8 CrossTebFlags : 0
+0xfc8 SpareCrossTebBits : 0y0000000000000000 (0)
+0xfca SameTebFlags : 0
+0xfca SafeThunkCall : 0y0
+0xfca InDebugPrint : 0y0
+0xfca HasFiberData : 0y0
跟着何時設置的,ba w 1 7ffdffca
76f3c4c8 57 push edi
76f3c4c9 53 push ebx
76f3c4ca 68cdabbadc push 0DCBAABCDh
76f3c4cf 56 push esi
76f3c4d0 ff7518 push dword ptr [ebp+18h]
76f3c4d3 ff7514 push dword ptr [ebp+14h]
76f3c4d6 ff7510 push dword ptr [ebp+10h]
76f3c4d9 ff750c push dword ptr [ebp+0Ch]
76f3c4dc 64800dca0f000001 or byte ptr fs:[0FCAh],1
76f3c4e4 ff5508 call dword ptr [ebp+8] ss:0023:0006f89c={ole32!OleMainThreadWndProc (770d63e5)}
76f3c4e7 648025ca0f0000fe and byte ptr fs:[0FCAh],0FEh
這裏進行標誌位設置
eax=c0000000 ebx=00000000 ecx=40000000 edx=7471a970 esi=00000081 edi=0006f9d8
eip=76f3c4e4 esp=0006f870 ebp=0006f894 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
USER32!InternalCallWinProc+0x20:
76f3c4e4 ff5508 call dword ptr [ebp+8] ss:0023:0006f89c={ole32!OleMainThreadWndProc (770d63e5)}
函數執行完畢之後 又恢復標誌位
0:000> g
7ffdffca 00000420 00000000 00000000 00000000
7ffdffda 00000000 80300000 0000001d 00000000
7ffdffea 00000000 00000000 00000000 00000000
7ffdfffa 00000000 00000000 00000000 99e80fa0
7ffe000a 000517f9 00050000 4ee80000 34664181
7ffe001a 346601ce c00001ce ffbcf1dc ffbcffff
7ffe002a 014cffff 0043014c 005c003a 00690057
7ffe003a 0064006e 0077006f 00000073 00000000
eax=00000001 ebx=00000000 ecx=76f350e8 edx=778a7094 esi=00000081 edi=0006f9d8
eip=76f3c4ef esp=0006f880 ebp=0006f894 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
USER32!InternalCallWinProc+0x2b:
76f3c4ef 817c2404cdabbadc cmp dword ptr [esp+4],0DCBAABCDh ss:0023:0006f884=dcbaabcd
至於有什麼用。。。
竟然還可以繼續執行,換成其他指令就不可以,而且執行時這個內存屬性仍舊是不可
執行屬性。同時按理指令是一條一條執行,但是這個指令的執行是跳躍了,瞬間差點毀了
多年的指令執行三觀。
debug
win7+system dep open
Breakpoint 0 hit
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=2e81e342 esp=0006dfbc ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MDIVWCTL!DllUnregisterServer+0x4399:
2e81e342 ffd6 call esi {001ff860} --------------〉問題點
0:000> db esi
000b1ec8 c7 44 24 04 84 ec 2d 00-e9 45 ad 76 2e ab ab ab .D$...-..E.v....
000b1ed8 ab ab ab ab ab fe ee fe-00 00 00 00 00 00 00 00 ................
000b1ee8 23 02 05 00 ee 14 ee 00-78 01 09 00 78 01 09 00 #.......x...x...
000b1ef8 ee fe ee fe ee fe ee fe-ee fe ee fe ee fe ee fe ................
000b1f08 ee fe ee fe ee fe ee fe-ee fe ee
*** ERROR: Module load completed but symbols could not be loaded for mspview.exe
0:000> u 001ff860
001ff860 c744240484609d04 mov dword ptr [esp+4],49D6084h --------------〉數據段2條要執行指令
001ff868 e9add3612e jmp MDIVWCTL!DllUnregisterServer+0x2c71 (2e81cc1a)
001ff86d ab stos dword ptr es:[edi]
001ff86e ab stos dword ptr es:[edi]
001ff86f ab stos dword ptr es:[edi]
001ff870 ab stos dword ptr es:[edi]
001ff871 ab stos dword ptr es:[edi]
001ff872 ab stos dword ptr es:[edi]
0:000> t
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff860 esp=0006dfb8 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
001ff860 c744240484609d04 mov dword ptr [esp+4],49D6084h ss:0023:0006dfbc=00030240
0:000> t -----------------〉單步了,但是直接跳到這裏了,毀三觀吧
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=2e81cc1b esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MDIVWCTL!DllUnregisterServer+0x2c72:
2e81cc1b 8bec mov ebp,esp
0:000> !address 001ff860
Failed to map Heaps (error 80004005)
Usage: <unclassified>
Allocation Base: 001d0000
Base Address: 001d0000
End Address: 00202000
Region Size: 00032000
Type: 00020000 MEM_PRIVATE
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE ----------->沒有可以執行屬性,但是竟然可以執行
0:000> r eip=001ff86d
0:000> r
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff86d esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
001ff86d ab stos dword ptr es:[edi] es:0023:00030240=????????
0:000> eb 001ff86d 90 90 90 90 ------------>更換成其他指令不可以執行
0:000> r
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff86d esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
001ff86d 90 nop
0:000> t
(9f0.9f4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=77427094 esi=001ff860 edi=00030240
eip=001ff86d esp=0006dfb4 ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
001ff86d 90 nop
查閱資料發現這個是爲了兼容ATL實現的dep 兼容指令,叫做well-known DEP-violating thunks
如果PE header裏面沒有設置IMAGE_DLLCHARACTERISTICS_NX_COMPAT 標誌既可以保持這個兼容性。
(The application compatibility team found that there were so many programs written with application frameworks that were not DEP-compatible (ATL mostly, but a few others) that nobody would actually enable DEP because the odds were close to 100% that there would be some program on the system that was not DEP-ready. Even DEP-fan Leo Davidson runs a couple of programs that don't work with DEP enabled. And it takes only one program to foul an upgrade.
When the kernel encounters a DEP exception, it checks whether thunk emulation is enabled, and if so (which it usually is), it checks whether the code sequence is one of the "well-known DEP-violating thunks". If so, then it simulates the actions the thunks would have performed and resumes execution instead of raising the exception. For example, if thunk emulation is enabled and you just took a DEP exception on the code sequence
mov ecx, 12345678
jmp 43218765
the kernel thunk emulator will perform the moral equivalent of
pContext->Ecx = 0x12345678;
pContext->Eip = 0x43218765;
return EXCEPTION_CONTINUE_EXECUTION;)
查看內核代碼,發現可執行的三組序列指令 (不同版本會有所差別)
004442BC > C74424 04 54EC2D00 MOV DWORD PTR SS:[ESP+4],2DEC54
004442C4 - E9 45AD762E JMP 2EBAF00E
004442C9 B9 57FF15D0 MOV ECX,D015FF57
004442CE - E9 40006681 JMP 81AA4313
004442D3 BA 4D5A75E9 MOV EDX,E9755A4D
004442D8 - E9 483C03C8 JMP C8477F25
004442DD E1 FF LOOPDE SHORT MSPVIEW.004442DE
內核實現過程 ntkrnlpa.exe
KiDispatchException
.text:004274DA lea eax, [ebp-2E8h]
.text:004274E0 push eax
.text:004274E1 push ecx
.text:004274E2 push ebx
.text:004274E3 call _KeContextFromKframes@12 ; KeContextFromKframes(x,x,x)
.text:004274E8 mov eax, [esi]
.text:004274EA cmp eax, 80000003h
.text:004274EF jz short loc_42755F
.text:004274F1 cmp eax, 10000004h
.text:004274F6 jnz short loc_427565
.text:004274F8 mov dword ptr [esi], 0C0000005h
.text:004274FE cmp byte ptr [ebp+14h], 1
.text:00427502 jnz short loc_427565
.text:00427504 lea eax, [ebp-2E8h]
.text:0042750A push eax
.text:0042750B push esi
.text:0042750C call _KiCheckForAtlThunk@8 ; KiCheckForAtlThunk(x,x)
signed int __stdcall KiEmulateAtlThunk(int *opcode_buf, int *a2, int a3, int a4, int a5)
{
int v6; // edx@3
int v7; // esi@3
int v8; // eax@5
int v9; // eax@9
int v10; // edi@9
int v11; // eax@11
int v12; // eax@16
int v13; // [sp+18h] [bp-28h]@3
int v14; // [sp+20h] [bp-20h]@3
char v15; // [sp+27h] [bp-19h]@5
if ( *(_BYTE *)(*(_DWORD *)(*MK_FP(__FS__, 292) + 68) + 107) & 4 )
return 0;
v7 = *opcode_buf;
v6 = *a2;
v13 = *a2;
v14 = 0;
if ( *opcode_buf >= (unsigned int)MmUserProbeAddress )
*MmUserProbeAddress = 0;
v8 = *MK_FP(__FS__, 24) + 0xFB4;
v15 = *(_BYTE *)v8;
if ( *(_BYTE *)v8 )
*(_BYTE *)v8 = 0;
if ( *(_DWORD *)v7 != 0x42444C7 || *(_BYTE *)(v7 + 8) != 0xE9u ) ---------------〉三組指令類型
{
if ( *(_BYTE *)v7 != 0xB9u || *(_BYTE *)(v7 + 5) != 0xE9u )
{
if ( *(_BYTE *)v7 != 0xBAu
|| *(_BYTE *)(v7 + 5) != 0xB9u
|| *(_WORD *)(v7 + 0xA) != 0xE1FFu
|| (v10 = *(_DWORD *)(v7 + 6), !MmCheckForSafeExecution(v7, v6, *(_DWORD *)(v7 + 6), 0)) )
return v14;
*(_DWORD *)a5 = *(_DWORD *)(v7 + 1);
*(_DWORD *)a4 = v10;
}
else
{
v12 = *(_DWORD *)(v7 + 6);
v10 = v12 + v7 + 10;
if ( !MmCheckForSafeExecution(v7, v6, v12 + v7 + 10, 1) || !v15 )
return v14;
*(_DWORD *)a4 = *(_DWORD *)(v7 + 1);
}
}
else
{
v9 = *(_DWORD *)(v7 + 9);
v10 = v9 + v7 + 13;
if ( !MmCheckForSafeExecution(v7, v6, v9 + v7 + 13, 1) || !v15 )
return v14;
v11 = v13 + 4;
if ( v13 + 4 >= (unsigned int)MmUserProbeAddress )
*(_BYTE *)MmUserProbeAddress = 0;
*(_BYTE *)v11 = *(_BYTE *)v11;
*(_BYTE *)(v13 + 7) = *(_BYTE *)(v13 + 7); -----------〉模擬執行
*(_DWORD *)v11 = *(_DWORD *)(v7 + 4);
}
*opcode_buf = v10;
return 1;
}
debug過程
eax=2e81e301 ebx=00000000 ecx=0006df7c edx=778a7094 esi=002cf600 edi=000401fe
eip=2e81e342 esp=0006dfbc ebp=0006dffc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MDIVWCTL!DllUnregisterServer+0x4399:
2e81e342 ffd6 call esi {002cf600}
0:000> dd 7ffdffca //查看這個SafeThunkCall 標誌是1
7ffdffca 00000421 00000000 00000000 00000000
7ffdffda 00000000 80300000 0000002a 00000000
7ffdffea 00000000 00000000 00000000 00000000
7ffdfffa 00000000 00000000 00000000 68ac0fa0
7ffe000a 00028b19 00020000 44df0000 34638cef
7ffe001a 346301ce c00001ce ffbcf1dc ffbcffff
7ffe002a 014cffff 0043014c 005c003a 00690057
7ffe003a 0064006e 0077006f 00000073 00000000
KiEmulateAtlThunk獲取SafeThunkCall 標誌代碼
83f017ad 64a118000000 mov eax,dword ptr fs:[00000018h]
83f017b3 05ca0f0000 add eax,0FCAh
83f017b8 8a08 mov cl,byte ptr [eax] ds:0023:7ffdffca=21
83f017ba 80e101 and cl,1
83f017bd 884d17 mov byte ptr [ebp+17h],cl
0:000> dt _TEB 7ffdf000
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x7ffdf02c Void
+0x030 ProcessEnvironmentBlock : 0x7ffd3000 _PEB
+0x034 LastErrorValue : 0
+0x038 CountOfOwnedCriticalSections : 0
+0x03c CsrClientThread : (null)
+0x040 Win32ThreadInfo : 0xfdb31168 Void
+0x044 User32Reserved : [26] 0
+0x0ac UserReserved : [5] 0
+0x0c0 WOW32Reserved : (null)
+0x0c4 CurrentLocale : 0x804
+0x0c8 FpSoftwareStatusRegister : 0
+0x0cc SystemReserved1 : [54] (null)
+0x1a4 ExceptionCode : 0n0
+0x1a8 ActivationContextStackPointer : 0x002107e0 _ACTIVATION_CONTEXT_STACK
+0x1ac SpareBytes : [36] ""
+0x1d0 TxFsContext : 0xfffe
+0x1d4 GdiTebBatch : _GDI_TEB_BATCH
+0x6b4 RealClientId : _CLIENT_ID
+0x6bc GdiCachedProcessHandle : (null)
+0x6c0 GdiClientPID : 0
+0x6c4 GdiClientTID : 0
+0x6c8 GdiThreadLocalInfo : (null)
+0x6cc Win32ClientInfo : [62] 0x20000008
+0x7c4 glDispatchTable : [233] (null)
+0xb68 glReserved1 : [29] 0
+0xbdc glReserved2 : (null)
+0xbe0 glSectionInfo : (null)
+0xbe4 glSection : (null)
+0xbe8 glTable : (null)
+0xbec glCurrentRC : (null)
+0xbf0 glContext : (null)
+0xbf4 LastStatusValue : 0xc0000034
+0xbf8 StaticUnicodeString : _UNICODE_STRING "ntdll.dll"
+0xc00 StaticUnicodeBuffer : [261] "ntdll.dll"
+0xe0c DeallocationStack : 0x00030000 Void
+0xe10 TlsSlots : [64] (null)
+0xf10 TlsLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0xf18 Vdm : (null)
+0xf1c ReservedForNtRpc : 0x0022d350 Void
+0xf20 DbgSsReserved : [2] (null)
+0xf28 HardErrorMode : 0
+0xf2c Instrumentation : [9] (null)
+0xf50 ActivityId : _GUID {00000000-0000-0000-0000-000000000000}
+0xf60 SubProcessTag : (null)
+0xf64 EtwLocalData : (null)
+0xf68 EtwTraceData : (null)
+0xf6c WinSockData : (null)
+0xf70 GdiBatchCount : 0
+0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
+0xf74 IdealProcessorValue : 0
+0xf74 ReservedPad0 : 0 ''
+0xf75 ReservedPad1 : 0 ''
+0xf76 ReservedPad2 : 0 ''
+0xf77 IdealProcessor : 0 ''
+0xf78 GuaranteedStackBytes : 0
+0xf7c ReservedForPerf : (null)
+0xf80 ReservedForOle : 0x002232b8 Void
+0xf84 WaitingOnLoaderLock : 0
+0xf88 SavedPriorityState : (null)
+0xf8c SoftPatchPtr1 : 0
+0xf90 ThreadPoolData : (null)
+0xf94 TlsExpansionSlots : (null)
+0xf98 MuiGeneration : 0
+0xf9c IsImpersonating : 0
+0xfa0 NlsCache : (null)
+0xfa4 pShimData : (null)
+0xfa8 HeapVirtualAffinity : 0
+0xfac CurrentTransactionHandle : (null)
+0xfb0 ActiveFrame : (null)
+0xfb4 FlsData : 0x002160a0 Void
+0xfb8 PreferredLanguages : (null)
+0xfbc UserPrefLanguages : 0x00217fb0 Void
+0xfc0 MergedPrefLanguages : 0x00218150 Void
+0xfc4 MuiImpersonation : 1
+0xfc8 CrossTebFlags : 0
+0xfc8 SpareCrossTebBits : 0y0000000000000000 (0)
+0xfca SameTebFlags : 0x421
+0xfca SafeThunkCall : 0y1 這個標誌爲1時,表示開啓dep 兼容
跟蹤下啥時候設置的
一開始是SafeThunkCall標誌爲0
(f08.bfc): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=0006fb08 edx=778a7094 esi=fffffffe edi=00000000
eip=7790054e esp=0006fb24 ebp=0006fb50 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!LdrpDoDebuggerBreak+0x2c:
7790054e cc int 3
0:000> dd 7ffdf000 +0xfca
7ffdffca 00000420 00000000 00000000 00000000
7ffdffda 00000000 00000000 00000000 00000000
7ffdffea 00000000 00000000 00000000 00000000
7ffdfffa 00000000 00000000 00000000 14200fa0
7ffe000a 00040123 00040000 c9200000 34652aaa
7ffe001a 346501ce c00001ce ffbcf1dc ffbcffff
7ffe002a 014cffff 0043014c 005c003a 00690057
7ffe003a 0064006e 0077006f 00000073 00000000
+0xfc0 MergedPrefLanguages : (null)
+0xfc4 MuiImpersonation : 0
+0xfc8 CrossTebFlags : 0
+0xfc8 SpareCrossTebBits : 0y0000000000000000 (0)
+0xfca SameTebFlags : 0
+0xfca SafeThunkCall : 0y0
+0xfca InDebugPrint : 0y0
+0xfca HasFiberData : 0y0
跟着何時設置的,ba w 1 7ffdffca
76f3c4c8 57 push edi
76f3c4c9 53 push ebx
76f3c4ca 68cdabbadc push 0DCBAABCDh
76f3c4cf 56 push esi
76f3c4d0 ff7518 push dword ptr [ebp+18h]
76f3c4d3 ff7514 push dword ptr [ebp+14h]
76f3c4d6 ff7510 push dword ptr [ebp+10h]
76f3c4d9 ff750c push dword ptr [ebp+0Ch]
76f3c4dc 64800dca0f000001 or byte ptr fs:[0FCAh],1
76f3c4e4 ff5508 call dword ptr [ebp+8] ss:0023:0006f89c={ole32!OleMainThreadWndProc (770d63e5)}
76f3c4e7 648025ca0f0000fe and byte ptr fs:[0FCAh],0FEh
這裏進行標誌位設置
eax=c0000000 ebx=00000000 ecx=40000000 edx=7471a970 esi=00000081 edi=0006f9d8
eip=76f3c4e4 esp=0006f870 ebp=0006f894 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
USER32!InternalCallWinProc+0x20:
76f3c4e4 ff5508 call dword ptr [ebp+8] ss:0023:0006f89c={ole32!OleMainThreadWndProc (770d63e5)}
函數執行完畢之後 又恢復標誌位
0:000> g
7ffdffca 00000420 00000000 00000000 00000000
7ffdffda 00000000 80300000 0000001d 00000000
7ffdffea 00000000 00000000 00000000 00000000
7ffdfffa 00000000 00000000 00000000 99e80fa0
7ffe000a 000517f9 00050000 4ee80000 34664181
7ffe001a 346601ce c00001ce ffbcf1dc ffbcffff
7ffe002a 014cffff 0043014c 005c003a 00690057
7ffe003a 0064006e 0077006f 00000073 00000000
eax=00000001 ebx=00000000 ecx=76f350e8 edx=778a7094 esi=00000081 edi=0006f9d8
eip=76f3c4ef esp=0006f880 ebp=0006f894 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
USER32!InternalCallWinProc+0x2b:
76f3c4ef 817c2404cdabbadc cmp dword ptr [esp+4],0DCBAABCDh ss:0023:0006f884=dcbaabcd
至於有什麼用。。。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.