1、模塊隱藏的實現原理html
普通API查找模塊實現思路:其經過查詢在R3中的PEB(Process Environment Block 進程環境塊)與TEB(Thread Environment Block 進程環境塊)來找到一個雙向鏈表,經過遍歷雙向鏈表中某一成員(字符串)來查找所有模塊。ios
模塊隱藏實現思路:在R3層的模塊隱藏,咱們須要作的就是將其該鏈表斷鏈,將某一模塊從這個雙向鏈表中摘除,這樣再調用傳統的API時就會搜索不到。windows
2、結構體成員詳細介紹ide
<1> TEB結構體 -- 內存地址爲 fs:[0] 處。
函數
使用Windbg的 "dt _TEB"命令來查看TEB結構體spa
kd> dt _TEB
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
.net
1. 屬性介紹
線程
1.1)_NT_TIB:重點兩個屬性,棧頂與棧大小。指針
http://www.nirsoft.net/kernel_struct/vista/NT_TIB.htmlcode
1.2) _CLIENT_ID: 存儲該進程ID與當前主線程ID。
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsts/a11e7129-685b-4535-8d37-21d4596ac057?redirectedfrom=MSDN
1.3) _PEB:進程環境塊 ,記住其在 TEB 偏移 0x30處便可。
2. 經過olldbg查看該結構體
2.1) 打開任意進程,在寄存器窗口找到 fs:[0],查看其內存地址。
2.2) 在內存窗口使用命令 "db 5E7000" 跳轉到該內存,使用地址格式(長型-地址)顯示。
<2> PEB結構體 -- fs:[0x30]
使用 Windbg 指令 dt _PEB 查看 PEB結構體,重點關注最後一個 進程加載信息表。
kd> dt _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 BitField : UChar
+0x003 ImageUsesLargePages : Pos 0, 1 Bit
+0x003 IsProtectedProcess : Pos 1, 1 Bit
+0x003 IsLegacyProcess : Pos 2, 1 Bit
+0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
+0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
+0x003 SpareBits : Pos 5, 3 Bits
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA // PEB_LOADER_DATA 進程加載信息表
1. 查看 _PEB_LDR_DATA 進程加載信息表 的結構體
1.1)重點關注 0x00c處的指針,其指向 _PEB_LDR_DATA 這個結構體,在這個結構體中 0x00c、0x01四、0x01c 分別表示 模塊加載順序 / 加載後在內存中的順序 / 模塊初始化的順序。
kd > dt _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+ 0x000 Length : Uint4B
+ 0x004 Initialized : UChar
+ 0x008 SsHandle : Ptr32 Void
+ 0x00c InLoadOrderModuleList : _LIST_ENTRY // 模塊加載順序
+ 0x014 InMemoryOrderModuleList : _LIST_ENTRY // 加載後在內存中的順序
+ 0x01c InInitializationOrderModuleList : _LIST_ENTRY // 模塊初始化的順序
+ 0x024 EntryInProgress : Ptr32 Void
+ 0x028 ShutdownInProgress : UChar
+ 0x02c ShutdownThreadId : Ptr32 Void
2.2)理解其三個成員的順序,其指向_LDR_DATA_TABLE_ENTRY元素中開始的三個成員,而 _LDR_DATA_TABLE_ENTRY 中存儲着就是關於有關模塊信息的元素(好比模塊名等)
kd > dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+ 0x000 InLoadOrderLinks : _LIST_ENTRY
+ 0x008 InMemoryOrderLinks : _LIST_ENTRY
+ 0x010 InInitializationOrderLinks : _LIST_ENTRY
+ 0x018 DllBase : Ptr32 Void // 模塊基地址
+ 0x01c EntryPoint : Ptr32 Void // 入口函數(對於 exe 模塊有效)
+ 0x020 SizeOfImage : Uint4B // 模塊大小
+ 0x024 FullDllName : _UNICODE_STRING // 完成模塊名稱(帶路徑)
+ 0x02c BaseDllName : _UNICODE_STRING // 模塊名稱
+ 0x034 Flags : Uint4B
2. 使用olldbg來查看查找首先加載模塊的模塊名稱(TEB->PEB-> InLoadOrderModuleList -> BaseDllName)
2.1)接以前TEB內容查找到PEB的所在位置 fs:[0x30]。
2.2) 在其0x00c處發現InLoadOrderModuleList成員,其指向的是一個_LDR_DATA_TABLE_ENTRY 結構體。
2.3) 跳轉到 _LDR_DATA_TABLE_ENTRY 結構體,從0x0c開始依次是三個 _LIST_ENTRY 結構體,該結構體雙向鏈表存儲着兩個地址。
2.4)選中第一個進入,在其偏移0x02c處(UNICODE結構體佔四字),能夠查看字符串名稱。
2.5)經過開頭 _LIST_ENTRY結構體能夠遍歷前一個模塊的內容和下一個模塊的內容。
3、利用C++斷鏈來實現模塊隱藏
若是你看懂上面分析,則源代碼很是好理解。
1 // 隱藏模塊.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。 2 // 3 4 #include "pch.h" 5 #include <iostream> 6 #include <Windows.h> 7 8 9 /* 所須要的結構體 10 1. _LDR_DATA_TABLE_ENTRY 鏈表指向數據 11 2. _PEB_LDR_DATA 表示其 PEB0x處指向的數據表 12 3. _LIST_ENTRY 指針指向的鏈表 13 */ 14 15 typedef struct _LSA_UNICODE_STRING { 16 USHORT Length; 17 USHORT MaximumLength; 18 PWSTR Buffer; 19 } 20 UNICODE_STRING, *PUNICODE_STRING; 21 22 typedef struct _PEB_LDR_DATA 23 { 24 DWORD Length; // +0x00 25 bool Initialized; // +0x04 26 PVOID SsHandle; // +0x08 27 LIST_ENTRY InLoadOrderModuleList; // +0x0c 28 LIST_ENTRY InMemoryOrderModuleList; // +0x14 29 LIST_ENTRY InInitializationOrderModuleList;// +0x1c 30 } PEB_LDR_DATA, *PPEB_LDR_DATA; // +0x24 31 32 typedef struct _LDR_MODULE 33 { 34 LIST_ENTRY InLoadOrderModuleList; 35 LIST_ENTRY InMemoryOrderModuleList; 36 LIST_ENTRY InInitializationOrderModuleList; 37 void* BaseAddress; 38 void* EntryPoint; 39 ULONG SizeOfImage; 40 UNICODE_STRING FullDllName; 41 UNICODE_STRING BaseDllName; 42 ULONG Flags; 43 SHORT LoadCount; 44 SHORT TlsIndex; 45 HANDLE SectionHandle; 46 ULONG CheckSum; 47 ULONG TimeDateStamp; 48 } LDR_MODULE, *PLDR_MODULE; 49 50 //所謂模塊句柄,即該模塊的入口地址 51 void hide_module(char* szDllName) 52 { 53 HMODULE hMod = GetModuleHandleA(szDllName); 54 PLIST_ENTRY Head, Cur; 55 PPEB_LDR_DATA ldr; 56 PLDR_MODULE ldm; 57 __asm 58 { 59 mov eax, fs:[0x30] 60 mov ecx, [eax + 0x0c] //Ldr 61 mov ldr, ecx 62 } 63 Head = &(ldr->InLoadOrderModuleList); 64 Cur = Head->Flink; 65 do 66 { 67 ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList); 68 if (hMod == ldm->BaseAddress) 69 { 70 // 三個鏈表同時給斷掉 71 ldm->InLoadOrderModuleList.Blink->Flink = 72 ldm->InLoadOrderModuleList.Flink; 73 ldm->InLoadOrderModuleList.Flink->Blink = 74 ldm->InLoadOrderModuleList.Blink; 75 76 // 77 ldm->InInitializationOrderModuleList.Blink->Flink = 78 ldm->InInitializationOrderModuleList.Flink; 79 ldm->InInitializationOrderModuleList.Flink->Blink = 80 ldm->InInitializationOrderModuleList.Blink; 81 82 // 83 ldm->InMemoryOrderModuleList.Blink->Flink = 84 ldm->InMemoryOrderModuleList.Flink; 85 ldm->InMemoryOrderModuleList.Flink->Blink = 86 ldm->InMemoryOrderModuleList.Blink; 87 break; 88 } 89 Cur = Cur->Flink; 90 } while (Head != Cur); 91 } 92 93 94 95 int main() 96 { 97 // 經過模塊名,來獲取模塊句柄 98 printf("****按任意鍵隱藏模塊*****"); 99 getchar(); 100 hide_module((char*)"kernel32.dll"); 101 printf("****隱藏模塊完成*****"); 102 getchar(); 103 getchar(); 104 105 }