|
Posted on 2009-04-05 17:31 besterChen 閱讀(942) 評論(0) 編輯 收藏 引用 所屬分類: 軟件安全中的JJXX
本人收集與網絡,不知原作者是誰…… 一:序言 下列情況不在討論之中(沒進程) 1 通過CreateRemoteThread Inject代碼到另一個進程(有種病毒就用這種方法,實現內存感染的;其實還有更多應用) 2 通過CreateRemoteThread LoadLibray一dll到另一個進程(屏蔽Ctrl+Alt+Del,就是通過這種方法和SetWindowLog實現)
二:進程隱藏 1 Hook/InlineHook Api NtQuerySystemInformation(taskmgr.exe就是用這個函數得到Process list) 2 Hook/InlineHook Api Process32Next 3 把要隱藏的進程的EPROCESS從LIST_ENTRY中摘除 a)ring0下驅動實現,注意:Nt/2000/xp/2003中PID和FLINK在EPROCESS中的offset不盡相同 b)ring3下利用call gate結合\Device\PhysicalMemory內核對象實現
三:檢測進程隱藏 我們重要討論一下殺毒軟件Kaspersky和rootkit檢測工具Icesword的兩種方法: 1 kaspersky的方法:kaspersky從6.0中加入了主動防御功能,它detour了SwapContext.
lkd> u KiSwapThread L20 nt!KiSwapThread: 804dd66e 8bff mov edi,edi 804dd670 56 push esi 804dd671 57 push edi 804dd672 3ea120f0dfff mov eax,ds:[ffdff020] 804dd678 8bf0 mov esi,eax 804dd67a 8b4608 mov eax,[esi+0x8] 804dd67d 85c0 test eax,eax 804dd67f 8b7e04 mov edi,[esi+0x4] 804dd682 0f8557ba0000 jne nt!KiSwapThread+0x16 (804e90df) 804dd688 53 push ebx 804dd689 0fbe5e10 movsx ebx,byte ptr [esi+0x10] 804dd68d 33d2 xor edx,edx 804dd68f 8bcb mov ecx,ebx 804dd691 e86bffffff call nt!KiFindReadyThread (804dd601) 804dd696 85c0 test eax,eax 804dd698 0f843e990000 je nt!KiSwapThread+0x2e (804e6fdc) 804dd69e 5b pop ebx 804dd69f 8bc8 mov ecx,eax 804dd6a1 e80cf7ffff call nt!KiSwapContext (804dcdb2) 804dd6a6 84c0 test al,al 804dd6a8 8a4f58 mov cl,[edi+0x58] 804dd6ab 8b7f54 mov edi,[edi+0x54] 804dd6ae 8b3570864d80 mov esi,[nt!_imp_KfLowerIrql (804d8670)] 804dd6b4 0f85d10a0100 jne nt!KiSwapThread+0x56 (804ee18b) 804dd6ba ffd6 call esi 804dd6bc 8bc7 mov eax,edi 804dd6be 5f pop edi 804dd6bf 5e pop esi 804dd6c0 c3 ret
lkd> u KiSwapContext L20 nt!KiSwapContext: 804dcdb2 83ec10 sub esp,0x10 804dcdb5 895c240c mov [esp+0xc],ebx 804dcdb9 89742408 mov [esp+0x8],esi 804dcdbd 897c2404 mov [esp+0x4],edi 804dcdc1 892c24 mov [esp],ebp 804dcdc4 8b1d1cf0dfff mov ebx,[ffdff01c] 804dcdca 8bf1 mov esi,ecx 804dcdcc 8bbb24010000 mov edi,[ebx+0x124] 804dcdd2 89b324010000 mov [ebx+0x124],esi 804dcdd8 8a4f58 mov cl,[edi+0x58] 804dcddb e8d9000000 call nt!SwapContext (804dceb9) 804dcde0 8b2c24 mov ebp,[esp] 804dcde3 8b7c2404 mov edi,[esp+0x4] 804dcde7 8b742408 mov esi,[esp+0x8] 804dcdeb 8b5c240c mov ebx,[esp+0xc] 804dcdef 83c410 add esp,0x10 804dcdf2 c3 ret
lkd> u SwapContext L10 nt!SwapContext: 804dceb9 0ac9 or cl,cl 804dcebb 26c6462d02 mov byte ptr es:[esi+0x2d],0x2 804dcec0 9c pushfd 804dcec1 8b0b mov ecx,[ebx] 804dcec3 e948cfa077 jmp f7ee9e10(注意:這個地址不在NTOSKRNL.EXE范圍中,落在klif.sys范圍中,<它用了相對轉跳,這樣可以節約兩個字節,cs:08>) 804dcec8 90 nop 804dcec9 90 nop 804dceca 51 push ecx 804dcecb 0f8534010000 jne nt!SwapContext+0x14d (804dd005) 804dced1 833d8c29568000 cmp dword ptr [nt!PPerfGlobalGroupMask (8056298c)],0x0 804dced8 0f85fe000000 jne nt!SwapContext+0x124 (804dcfdc) 804dcede 0f20c5 mov ebp,cr0 804dcee1 8bd5 mov edx,ebp 804dcee3 8a4e2c mov cl,[esi+0x2c] 804dcee6 884b50 mov [ebx+0x50],cl 804dcee9 fa cli
考慮到機器的效率,SwapContext是用匯編代碼實現的,看看它具體功能(實現自己看代碼吧:)): ;++ ; ; Routine Description: ; ; This routine is called to swap context from one thread to the next. ; It swaps context, flushes the data, instruction, and translation ; buffer caches, restores nonvolatile integer registers, and returns ; to its caller. ; ; N.B. It is assumed that the caller (only caller's are within this ; module) saved the nonvolatile registers, ebx, esi, edi, and ; ebp. This enables the caller to have more registers available. ; ; Arguments: ; ; cl - APC interrupt bypass disable (zero enable, nonzero disable). ; edi - Address of previous thread. ; esi - Address of next thread. ; ebx - Address of PCR. ; ; Return value: ; ; al - Kernel APC pending. ; ebx - Address of PCR. ; esi - Address of current thread object. ; ;--
(雖然懸掛或等待的線程,不會獲得cpu時間,但在SwapContext的時候仍然要檢測,知道Thread了,得到對應Process也就容易了) 注:這個方法最初是J. Butler提出的,參見:http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=1232409 2 IceSword的方法:以前的方法是檢測EPRCOESS,后來改成了PspCidTable a)全局變量PspCidTable是一個HANDLE_TABLE的指針,這個變量并沒有被NTOSKRNL導出,這個HANDLE_TABLE的表保存著所有進程和線程對象的指針.
b)PID(進程ID)和 ThreadID(線程ID)就是在這個句柄表中的索引,這個HANDLE_TABLE不屬于任何進程,也沒有鏈在HANDLE_TABLE鏈上.
c)PspCidTable在PsLookupProcessByProcessId中被用到,所以可以在此函數中搜索PspCidTalbe變量以定位其地址.
d)得到PspCidTable這個句柄表地址后,IceSword調用ExEnumHandleTable.
這個函數的函數原形是: BOOLEAN ExEnumHandleTable( IN PHANDLE_TABLE HandleTable, IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure, IN PVOID EnumParameter, OUT PHANDLE Handle OPTIONAL)
參數說明: HandleTable : 句柄表,可以用PspCidTable做參數. EnumHandleProcedure: 類型為BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(HANDLE_TALBE_ENTRY*,DWORD PID,PVOID Param)函數指針. EnumParameter : 傳送給EnumHandleProcedure函數的參數. Handle : 此函數返回True時此參數才有效,為停止枚舉前所枚舉的句柄(可選).
功能說明: 調用ExEnumHandleTable函數的時,在每次枚舉到表中的一個句柄時都會調用一次回調函數; 回調函數返回值為FALSE時繼續枚舉句柄表,返回TRUE時則停止枚舉.
我們來看看他的具體實現吧!
BOOLEAN ExEnumHandleTable( IN PHANDLE_TABLE HandleTable, IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure, IN PVOID EnumParameter, OUT PHANDLE Handle OPTIONAL ) /*++
Routine Description:
This function enumerates all the valid handles in a handle table. For each valid handle in the handle table, the specified eumeration function is called. If the enumeration function returns TRUE, then the enumeration is stopped, the current handle is returned to the caller via the optional Handle parameter, and this function returns TRUE to indicated that the enumeration stopped at a specific handle.
Arguments:
HandleTable - Supplies a pointer to a handle table.
EnumHandleProcedure - Supplies a pointer to a fucntion to call for each valid handle in the enumerated handle table.
EnumParameter - Supplies an uninterpreted 32-bit value that is passed to the EnumHandleProcedure each time it is called.
Handle - Supplies an optional pointer a variable that receives the Handle value that the enumeration stopped at. Contents of the variable only valid if this function returns TRUE.
Return Value:
If the enumeration stopped at a specific handle, then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
--*/
{
PHANDLE_ENTRY HandleEntry; BOOLEAN ResultValue; PHANDLE_ENTRY TableEntries; PHANDLE_ENTRY TableBound; ULONG TableIndex;
PAGED_CODE();
ASSERT(HandleTable != NULL);
// // Lock the handle table exclusive and enumerate the handle entries. //
ResultValue = FALSE; ExLockHandleTableShared(HandleTable); TableBound = HandleTable->TableBound; TableEntries = HandleTable->TableEntries; HandleEntry = &TableEntries[1]; while (HandleEntry < TableBound) { if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) { TableIndex = HandleEntry - TableEntries; if ((*EnumHandleProcedure)(HandleEntry, INDEX_TO_HANDLE(TableIndex), EnumParameter)) {
if (ARGUMENT_PRESENT(Handle)) { *Handle = INDEX_TO_HANDLE(TableIndex); }
ResultValue = TRUE; break; } }
HandleEntry += 1; }
ExUnlockHandleTableShared(HandleTable); return ResultValue; }
(PS:IceSword的檢測方法部分參見匿名用戶的文章,非常感謝!)
|