撰寫本系列文章目的在於提升資訊安全之實務能力,
並透過實作體悟到資訊安全領域的重要性,
本系列所有文章之內容皆有一定技術水平,
不得從事非法行為、惡意攻擊等非法活動,
「一切不合法規之行為皆受法律所約束」,
為了避免造成公司、廠商或玩家之間困擾,
所有實作不會拿已上市產品、Online Game 等等來作範例學習,
且部分具有深度、價值之內容,將會提升一定閱讀門檻(不對該技術做分析、解說),
請勿透過本系列文章所學,從事任何非法活動,請不要以身試法!!!
在昨日的文章中:
【Day 10】- 藏起來的 Process 真的看不見摸不著?(講解找出斷鏈後的 Process 方法)
已經有說到如何找出修改 ActiveProcessLinks 隱藏的 Process,
到文末時,
有稍微提到 PsLookupProcessByProcessId 會透過 PspCidTable 拿對應 PID 的 Object,
透過這樣的方式拿到 EProcess Address,
那今天就要來說說 PspCidTable 是什麼東西。
上一篇與上上篇還沒看得可以先去看看哦~
首先開始前要先說一下,
小弟我目前還屬於菜鳥階段,正不斷努力學習中,
若有發現錯誤或不妥之處還請不吝賜教。
歡迎大家多多留言,互相交流交流。
那就開始今天的主題吧~~
什麼是 PspCidTable ?
A Process's、A Thread's Kernel Object Handle Table
每個 Process 都有自己的 Handle Table,
Index 就是 Process 的 PID、TID,
要操作 Process 時(應該說要拿 EProcess Address 時),
通過 Index(PID、TID)存取 Handle Table,然後返回 object pointer。
那 PspCidTable 長什麼樣子?
在 WinDbg 中輸入 dt _HANDLE_TABLE
lkd> dt _HANDLE_TABLE
nt!_HANDLE_TABLE
+0x000 NextHandleNeedingPool : Uint4B
+0x004 ExtraInfoPages : Int4B
+0x008 TableCode : Uint8B
+0x010 QuotaProcess : Ptr64 _EPROCESS
+0x018 HandleTableList : _LIST_ENTRY
+0x028 UniqueProcessId : Uint4B
+0x02c Flags : Uint4B
+0x02c StrictFIFO : Pos 0, 1 Bit
+0x02c EnableHandleExceptions : Pos 1, 1 Bit
+0x02c Rundown : Pos 2, 1 Bit
+0x02c Duplicated : Pos 3, 1 Bit
+0x02c RaiseUMExceptionOnInvalidHandleClose : Pos 4, 1 Bit
+0x030 HandleContentionEvent : _EX_PUSH_LOCK
+0x038 HandleTableLock : _EX_PUSH_LOCK
+0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST
+0x040 ActualEntry : [32] UChar
+0x060 DebugInfo : Ptr64 _HANDLE_TRACE_DEBUG_INFO
首先,先來逆向 PsLookupProcessByProcessId:
uf PsLookupProcessByProcessId
lkd> uf PsLookupProcessByProcessId
nt!PsLookupProcessByProcessId:
fffff800`09de0ad0 48895c2408 mov qword ptr [rsp+8],rbx
fffff800`09de0ad5 4889742410 mov qword ptr [rsp+10h],rsi
fffff800`09de0ada 48897c2418 mov qword ptr [rsp+18h],rdi
fffff800`09de0adf 4156 push r14
fffff800`09de0ae1 4883ec20 sub rsp,20h
fffff800`09de0ae5 65488b342588010000 mov rsi,qword ptr gs:[188h]
fffff800`09de0aee 4c8bf2 mov r14,rdx
fffff800`09de0af1 66ff8ee6010000 dec word ptr [rsi+1E6h]
fffff800`09de0af8 b203 mov dl,3
fffff800`09de0afa e8412afcff call nt!PspReferenceCidTableEntry (fffff800`09da3540)
因為時間、文章長度的關係,我就直接講重點,
這邊看到 call 了一個 PspReferenceCidTableEntry,直接跟進去看,
uf fffff800`09da3540
lkd> uf fffff800`09da3540
nt!PspReferenceCidTableEntry:
fffff800`09da3540 48896c2420 mov qword ptr [rsp+20h],rbp
fffff800`09da3545 56 push rsi
fffff800`09da3546 4883ec20 sub rsp,20h
fffff800`09da354a 488b05afbcedff mov rax,qword ptr [nt!PspCidTable (fffff800`09c7f200)]
不遠處就可以看到拿了 PspCidTable Address,
所以可以直接透過這個 API 來定位 PspCidTable,
PspCidTable 是沒有導出的,無法直接呼叫使用,
需要手動透過特徵定位。
定位方式:
一、取得 PsLookupProcessByProcessId Address
二、找到 call PspReferenceCidTableEntry
(特徵直接抓 0xe8 即可)
三、進入 PspReferenceCidTableEntry 這個 call
四、找到 rax,qword ptr [nt!PspCidTable (xxx)]
(特徵直接抓 0x48、0x8b 0x05 即可)
五、取得 PspCidTable Address
dp PspCidTable
fffff800`09c7f200
lkd> dp PspCidTable
fffff800`09c7f200 ffffcf01`82216cc0 fffff800`09c7f208
fffff800`09c7f210 fffff800`09c7f208 ffffe307`15ec0480
fffff800`09c7f220 00000000`00000000 00000000`00000000
fffff800`09c7f230 00001000`00010000 ffffe307`15ec7800
fffff800`09c7f240 00000000`00000000 00000002`00005e03
fffff800`09c7f250 00000000`00000000 00000000`00000000
fffff800`09c7f260 00000000`00000000 fffff800`0a158000
fffff800`09c7f270 fffff800`09886000 00000000`00000000
dt _HANDLE_TABLE ffffcf01`82216cc0
lkd> dt _HANDLE_TABLE ffffcf01`82216cc0
nt!_HANDLE_TABLE
+0x000 NextHandleNeedingPool : 0x1800
+0x004 ExtraInfoPages : 0n0
+0x008 TableCode : 0xffffcf01`87f59001
+0x010 QuotaProcess : (null)
+0x018 HandleTableList : _LIST_ENTRY [ 0x?? - 0x?? ]
+0x028 UniqueProcessId : 0
+0x02c Flags : 1
+0x02c StrictFIFO : 0y1
+0x02c EnableHandleExceptions : 0y0
+0x02c Rundown : 0y0
+0x02c Duplicated : 0y0
+0x02c RaiseUMExceptionOnInvalidHandleClose : 0y0
+0x030 HandleContentionEvent : _EX_PUSH_LOCK
+0x038 HandleTableLock : _EX_PUSH_LOCK
+0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST
+0x040 ActualEntry : [32] ""
+0x060 DebugInfo : (null)
再來就是 Table 是有分 Level 的:
判斷 Table 的 Level:
這裡的 TableCode:0xffffcf01`87f59001
結尾是 01
代表這張表是 Level2
dp 0xffffcf01`87f59000
lkd> dp 0xffffcf01`87f59000
ffffcf01`87f59000 ffffcf01`8221a000 ffffcf01`87f5a000
ffffcf01`87f59010 ffffcf01`88585000 ffffcf01`88b50000
ffffcf01`87f59020 ffffcf01`88fe9000 ffffcf01`89d39000
ffffcf01`87f59030 00000000`00000000 00000000`00000000
ffffcf01`87f59040 00000000`00000000 00000000`00000000
ffffcf01`87f59050 00000000`00000000 00000000`00000000
ffffcf01`87f59060 00000000`00000000 00000000`00000000
ffffcf01`87f59070 00000000`00000000 00000000`00000000
dp ffffcf01`8221a000
lkd> dp ffffcf01`8221a000
ffffcf01`8221a000 00000000`00000000 00000000`00000000
ffffcf01`8221a010 e30715ed`8040ff57 00000000`00000000
ffffcf01`8221a020 e30718f8`5080fe9b 00000000`00000000
ffffcf01`8221a030 e30715ec`8700fff7 00000000`00000000
ffffcf01`8221a040 e30715ec`e040fff7 00000000`00000000
ffffcf01`8221a050 e30715ed`3700fff7 00000000`00000000
ffffcf01`8221a060 e30715eb`9040fff7 00000000`00000000
ffffcf01`8221a070 e30715e4`e040fff7 00000000`00000000
e30715ed`8040ff57
dt _eprocess 0xFFFFE30715ED8040
lkd> dt _eprocess 0xFFFFE30715ED8040
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x2d8 ProcessLock : _EX_PUSH_LOCK
--- --- ---
--- --- ---
--- --- ---
+0x450 ImageFileName : [15] "System"
--- --- ---
--- --- ---
--- --- ---
看到了吧,列舉到了系統 Process:System
補充:
每張 Table 在 x64 的大小是 0x1000(4096),
Level2 和 Level3 放的是 Pointer,大小是 8,
所以 Level2 和 Level3 都要列舉 4096 / 8 = 516 次,
Level1 是 _handle_table_entry 結構,所以大小是 16,
所以 Level1 要列舉 4096 / 16 = 256 次。
列舉結果:
所以說了這麼多要怎麼隱藏ㄋ?
請看 hidden Project 的 PsMonitor.c
我放一份在這裡:
VOID UnlinkProcessFromCidTable(PProcessTableEntry Entry)
{
PVOID PspCidTable = GetPspCidTablePointer();
if (!PspCidTable)
{
LogWarning("Can't unlink process %Iu from PspCidTable(NULL)", Entry->processId);
return;
}
CidTableContext context;
context.ProcessId = Entry->processId;
context.Found = FALSE;
EX_ENUMERATE_HANDLE_ROUTINE routine = (IsWin8OrAbove() ? (EX_ENUMERATE_HANDLE_ROUTINE)&RemoveHandleCallbackWin8 : &RemoveHandleCallback);
if (!ExEnumHandleTable(PspCidTable, routine, &context, NULL))
{
LogWarning("Can't unlink process %Iu from PspCidTable", Entry->processId);
return;
}
if (!context.Found)
{
LogWarning("Can't find process %Iu in PspCidTable", Entry->processId);
return;
}
// Hack for Windows Vista, 7, to avoid lock bit leak
if (!IsWin8OrAbove())
{
context.Entry->u1.Object = NULL;
context.Entry->u2.GrantedAccess = 0;
}
Entry->cidEntryBackup = context.EntryBackup;
Entry->cidEntry = context.Entry;
}
BOOLEAN RemoveHandleCallback(PHANDLE_TABLE_ENTRY HandleTableEntry, HANDLE Handle, PVOID EnumParameter)
{
PCidTableContext context = (PCidTableContext)EnumParameter;
if (context->ProcessId != Handle)
return FALSE;
context->Found = TRUE;
context->Entry = HandleTableEntry;
context->EntryBackup = *HandleTableEntry;
LogInfo(
"PID %Iu has been removed from PspCidTable, entry:%p, object:%p, access:%08x",
Handle,
HandleTableEntry,
context->EntryBackup.u1.Object,
context->EntryBackup.u2.GrantedAccess
);
return TRUE;
}
notepad.exe 隱藏前:
在 R0 下,暴力列舉 PID,然後 CALL PsLookupProcessByProcessId:
在 R3 下,暴力列舉 PID,然後 CALL OpenProcess:
隱藏 notepad.exe:
隱藏後在 R0 下,暴力列舉 PID,然後 CALL PsLookupProcessByProcessId:
隱藏後在 R3 下,暴力列舉 PID,然後 CALL OpenProcess:
隱藏後在 R0 下,列舉 PspCidTable:
沒人找的到我了吧!哈哈哈哈哈~
好啦,明天開大絕,
教你/妳把 Windows 裡所有藏起來的 Process(Rookit)找出來 :D
好了,今天就講到這結束了,
大家若有發現哪裡寫得不好或錯誤的地方,都留個言討論一下吧 XD
那我們下期見 o( ̄▽ ̄)ブ