最近跟隊友更新monitor版本,發現新版本將Zwxxx的hook位置移到了ntxxx的位置,其實作的是同一件事,爲何要如此?帶着疑問我用OD進行了追蹤。api
WriteFile asm source code from OD(kernel32.dll)code
7C810E17 > $ 6A 18 push 0x18 ; WriteFileorm
7C810E19 . 68 B00E817C push kernel32.7C810EB0it
7C810E1E . E8 B316FFFF call kernel32.7C8024D6asm
7C810E23 . 8B5D 14 mov ebx,dword ptr ss:[ebp+0x14]table
7C810E26 . 33C9 xor ecx,ecxast
7C810E28 . 3BD9 cmp ebx,ecxtest
7C810E2A . 74 02 je short kernel32.7C810E2E監控
7C810E2C . 890B mov dword ptr ds:[ebx],ecxfile
7C810E2E > 64:A1 1800000>mov eax,dword ptr fs:[0x18]
7C810E34 . 8B40 30 mov eax,dword ptr ds:[eax+0x30]
7C810E37 . 8B7D 08 mov edi,dword ptr ss:[ebp+0x8]
7C810E3A . 83FF F4 cmp edi,-0xC ; Switch (cases FFFFFFF4..FFFFFFF6)
7C810E3D . 0F84 C3D00100 je kernel32.7C82DF06
7C810E43 . 83FF F5 cmp edi,-0xB
7C810E46 . 0F84 AFD00100 je kernel32.7C82DEFB
7C810E4C . 83FF F6 cmp edi,-0xA
7C810E4F . 0F84 ADBC0200 je kernel32.7C83CB02
7C810E55 > 8BC7 mov eax,edi ; Default case of switch 7C810E3A
7C810E57 . 25 03000010 and eax,0x10000003
7C810E5C . 83F8 03 cmp eax,0x3
7C810E5F . 0F84 FCBD0000 je kernel32.7C81CC61
7C810E65 . 8B75 18 mov esi,dword ptr ss:[ebp+0x18]
7C810E68 . 51 push ecx
7C810E69 . 3BF1 cmp esi,ecx
7C810E6B . 0F85 ABD90100 jnz kernel32.7C82E81C
7C810E71 . 51 push ecx
7C810E72 . FF75 10 push dword ptr ss:[ebp+0x10]
7C810E75 . FF75 0C push dword ptr ss:[ebp+0xC]
7C810E78 . 8D45 E0 lea eax,dword ptr ss:[ebp-0x20]
7C810E7B . 50 push eax
7C810E7C . 51 push ecx
7C810E7D . 51 push ecx
7C810E7E . 51 push ecx
7C810E7F . 57 push edi
7C810E80 . FF15 BC11807C call dword ptr ds:[<&ntdll.NtWriteFile>] ; ntdll.ZwWriteFile //here is static address, it's a fn table in kernel32.dll
7C810E86 . 3D 03010000 cmp eax,0x103
7C810E8B . 0F84 A7BC0200 je kernel32.7C83CB38
7C810E91 > 85C0 test eax,eax
7C810E93 . 0F8C 49D00100 jl kernel32.7C82DEE2
7C810E99 . 8B45 E4 mov eax,dword ptr ss:[ebp-0x1C]
7C810E9C . 8903 mov dword ptr ds:[ebx],eax
7C810E9E > 33C0 xor eax,eax
7C810EA0 . 40 inc eax
7C810EA1 > E8 6B16FFFF call kernel32.7C802511
7C810EA6 . C2 1400 retn 0x14
ZwWriteFile source code(ntdll.dll):
7C92DF60 > B8 12010000 mov eax,0x112 ; ZwWriteFile
7C92DF65 BA 0003FE7F mov edx,0x7FFE0300
7C92DF6A FF12 call dword ptr ds:[edx] ; ntdll.KiFastSystemCall
7C92DF6C C2 2400 retn 0x24
fn table(kernel32.dll):
7C80119C > . B0D9927C dd ntdll.ZwReadFile
7C8011A0 > . 50CF927C dd ntdll.ZwAllocateVirtualMemory
7C8011A4 > . D0DE927C dd ntdll.ZwUnlockFile
7C8011A8 > . 80D4927C dd ntdll.ZwLockFile
7C8011AC > . 8F4F937C dd ntdll.RtlAppendUnicodeStringToString
7C8011B0 > . 1A4F937C dd ntdll.RtlAppendUnicodeToString
7C8011B4 > . B94E937C dd ntdll.RtlCopyUnicodeString
7C8011B8 > . 70D3927C dd ntdll.ZwFreeVirtualMemory
7C8011BC > . 60DF927C dd ntdll.ZwWriteFile ; NtWriteFile
7C8011C0 > . 1234937C dd ntdll.RtlCreateUnicodeString
7C8011C4 > . F94F937C dd ntdll.RtlFormatCurrentUserKeyPath
7C8011C8 > . B949937C dd ntdll.RtlGetLongestNtPathLength
7C8011CC > . 80D2927C dd ntdll.ZwDuplicateObject
7C8011D0 > . 40D8927C dd ntdll.ZwQueryKey
7C8011D4 > . 50D2927C dd ntdll.ZwDeleteValueKey
7C8011D8 > . B635937C dd ntdll.RtlEqualString
7C8011DC > . FFEA937C dd ntdll.CsrFreeCaptureBuffer
7C8011E0 > . EE06947C dd ntdll.CsrCaptureMessageString
7C8011E4 > . 58EB937C dd ntdll.CsrAllocateCaptureBuffer
7C8011E8 > . 1D28927C dd ntdll.strncpy
7C8011EC > . 903B957C dd ntdll.RtlCharToInteger
7C8011F0 > . C003937C dd ntdll.RtlUpcaseUnicodeChar
前後順序是,api->NtApi->ZwApi。
能夠看到ZwWritefile是沒有好的inlinehook的位置的,直接就進了ntdll.KiFastSystemCall 經過中斷跳入ring0,真要hook則,必須在跳回的時候作修復,可能會所以致使hook後程序不穩定。
因此改fntable即方便又穩定,old fn ptr跳回便可調用原來的。壞處是,若是惡意代碼直接調用zwxxx,可能會漏掉。hook時必須根據狀況單獨處理。
固然經過掛起,注入,繼續執行的方式也不能保證都能監控,之後還要在ring0作進一步的保護措施。