Well-known DEP-violating thunks
来源:互联网 发布:金融炼金术知乎 编辑:程序博客网 时间:2024/06/05 08:27
这几天调试发现一个奇怪的现象,一个在数据区段执行的指令,在开启了系统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
至于有什么用。。。
- Well-known DEP-violating thunks
- WKT (Well Known Text)
- WKT (Well Known Text)
- Well-known port assignment
- NAT64: well-Known Prefix
- WKT(well known text)
- Well known ports for servers
- WAP_WSP的Well-known header
- WKT (Well Known Text)坐标参照系统
- Review on 2 well-known Haskell textbooks
- Not-well-known but practical VIM tips
- List of Well-Known TCP Port Numbers
- WNDPROC Thunks
- Well-known security identifiers in Windows operating systems
- Codeforces Round #139 (Div. 2) B. Well-known Numbers
- CodeForces 225B Well-known Numbers(二分)
- ESRIs Well Known IDs (WKID) for Geographic Coordinate Systems
- DEP
- 从Slice_Header学习H.264(三.1)--相关细节之 POC的计算
- Java HIVE 使用Jdbc连接Hive
- These are broadcasts whose data is held by the system after being finished, so that clients can quic
- C++中的const
- jquery特效之图片轮播
- Well-known DEP-violating thunks
- OpenGL Window环境配置
- VGA,QVGA,CIF,QCIF
- hdu_1969_NWERC2006_Pie(二分)
- C++ 递归方式删除非空目录文件夹
- hibernate实现动态表名
- CIF,4CIF,QCIF,D1
- makefile实践例子
- 大数乘法