模块隐藏(LDR_MODULE链 与 PE特征)
比較常見的模塊隱藏方法有抹去模塊的PE頭,斷開進程的LDR_MODULE鏈,Hook模塊枚舉函數(shù)等。后面?zhèn)渥AD隱藏。
//測試EXE,加載WaiGua.dll,再隱藏。 #include <Windows.h> #include <stdio.h> #include <TLHELP32.H> typedef struct _LSA_UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR Buffer; } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;typedef struct _LDR_MODULE{LIST_ENTRY InLoadOrderModuleList;LIST_ENTRY InMemoryOrderModuleList;LIST_ENTRY InInitializationOrderModuleList;PVOID BaseAddress;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;LIST_ENTRY HashTableEntry;ULONG TimeDateStamp;} LDR_MODULE, *PLDR_MODULE, *PLML;// typedef struct _LE{ // DWORD Flink; // DWORD Blink; // }LE, LIST_ENTRY;BOOL BreakLdrModuleLink(DWORD dwBaseAddr) {PLDR_MODULE pLMFNode = NULL, pLNode = NULL ;PLDR_MODULE pLMHNode = NULL, pLMPNode = NULL;PLDR_MODULE pLMTNode = NULL;BOOL bSuccess = FALSE;//獲取LDR_MODULE鏈的頭指針__asm{pushadpushfdxor edx, edxmov ebx, fs:[edx + 0x30] mov ecx, [ebx + 0x0C] lea edx, [ecx + 0x0C]mov ecx, [ecx + 0x0C] mov pLMHNode, edx mov pLMFNode, ecxpopfdpopad}//查找目標PLDR_MODULE pLMNode = pLMFNode;pLMPNode = pLMHNode;do{//比較是否是目標模塊if( (DWORD)pLMNode->BaseAddress == dwBaseAddr){bSuccess = TRUE;break;}pLMPNode = pLMNode;pLMNode = (PLDR_MODULE)pLMNode->InLoadOrderModuleList.Flink;}while(pLMNode != pLMHNode);if( !bSuccess ){OutputDebugString("cannot find the dest module!");return bSuccess; //未找到目標模塊}//斷開InLoadOrderModuleList鏈//重建FlinkpLMTNode = (PLDR_MODULE)pLMNode->InLoadOrderModuleList.Flink;pLMPNode->InLoadOrderModuleList.Flink = (PLIST_ENTRY)pLMTNode;//重建Blink((PLDR_MODULE)(pLMNode->InLoadOrderModuleList.Flink))->InLoadOrderModuleList.Blink = pLMNode->InLoadOrderModuleList.Blink;//斷開InMemoryOrderModuleList鏈//重建FlinkpLMPNode->InMemoryOrderModuleList.Flink = pLMNode->InMemoryOrderModuleList.Flink;//重建BlinkpLMTNode = (PLML)(pLMNode->InMemoryOrderModuleList.Flink - sizeof(LIST_ENTRY));pLMTNode->InMemoryOrderModuleList.Blink = pLMNode->InMemoryOrderModuleList.Blink;//斷開InInitializationOrderModuleList鏈//重建FlinkpLMPNode->InInitializationOrderModuleList.Flink = pLMNode->InInitializationOrderModuleList.Flink;//重建BlinkpLMTNode = (PLML)(pLMNode->InInitializationOrderModuleList.Flink - 2*sizeof(LIST_ENTRY));pLMTNode->InInitializationOrderModuleList.Blink = pLMNode->InInitializationOrderModuleList.Blink; }void ModuleHide(HMODULE hInjectDll) {DWORD dwOldProtect;VirtualProtect((LPVOID)hInjectDll,1024,PAGE_READWRITE, &dwOldProtect);PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) hInjectDll;//抹去MZ標志pDosHeader->e_magic = 0;//DOS頭后面就是PE頭//PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader+1);PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((CHAR*)hInjectDll + pDosHeader->e_lfanew);//抹去PE標志pNtHeader->Signature = 0;VirtualProtect((LPVOID)hInjectDll,1024,dwOldProtect, &dwOldProtect);//斷開LDR_MODULEBreakLdrModuleLink((DWORD)hInjectDll); }void EnumModule(void) {// TODO: Add your control notification handler code herechar szBuffer[256*100] = "";char szModuFile[240] = "";char szTmpBuffer[256] = "";MODULEENTRY32 moudle;HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);if (handle == INVALID_HANDLE_VALUE){printf("枚舉模塊失敗!");return;}int i = 1;if ( Module32First(handle,&moudle)){ do{sprintf(szModuFile,"[%d]Address: 0x%x, Name: %s \r\n", i, moudle.modBaseAddr, moudle.szModule);strcat(szBuffer,szModuFile);i++;}while(Module32Next(handle,&moudle));}CloseHandle(handle);printf(szBuffer);} void main() {HMODULE hDll = LoadLibrary("WaiGua.dll");printf("this waigua.dll load at:0x%x\n",hDll);ModuleHide(hDll);EnumModule();getchar(); }
?
?
備注:
摘要(轉(zhuǎn)自網(wǎng)絡):
一、從PEB的Ldr鏈中消失
????????????????????????????? 引用內(nèi)容
lkd> dt _PEB 7ffdc000 //當前PEB的地址
nt!_PEB
????...
????+0x00cLdr??????????????: 0x001a1e90 _PEB_LDR_DATA?? //這里指向Ldr結(jié)構(gòu)
lkd> dt _PEB_LDR_DATA 0x001a1e90 //這個結(jié)構(gòu)里有三個鏈表的表頭
nt!_PEB_LDR_DATA
????+0x000Length????????????:0x28
????+0x004 Initialized??????: 0x1 ''
????+0x008SsHandle??????????: (null)
????+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x1a1ec0 -0x1a34f8 ]
????+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x1a1ec8- 0x1a3500 ]
????+0x01c InInitializationOrderModuleList : _LIST_ENTRY [0x1a1f28 - 0x1a3508 ]
????+0x024 EntryInProgress?? : (null)
這里看到有三個鏈表,其實三個鏈表的內(nèi)容是一樣的,但是鏈表的順序不一樣,分別按加載順序、內(nèi)存順序、初始化順序排列。
每一個DLL由一個LDR_DATA_TABLE_ENTRY結(jié)構(gòu)描述,但是第一個結(jié)構(gòu)被鏈入了三個鏈表。取一個來看看:
引用內(nèi)容
lkd> dt _LDR_DATA_TABLE_ENTRY 0x1a34f8
nt!_LDR_DATA_TABLE_ENTRY
????+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x1a1e9c -0x1a3450 ]
????+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x1a1ea4 -0x1a3458 ]
????+0x010 InInitializationOrderLinks : _LIST_ENTRY [0x1a1eac - 0x1a3460 ]
????+0x018DllBase?????????? :0x20000000
????+0x01cEntryPoint????????: (null)
????+0x020 SizeOfImage??????: 0x549000
????+0x024 FullDllName??????: _UNICODE_STRING "C:\WINDOWS\system32\xpsp2res.dll"
????+0x02c BaseDllName??????: _UNICODE_STRING "xpsp2res.dll"
?? ......//省略部分內(nèi)容
隨便取一個鏈表進行遍歷,根據(jù)DllBase找到自己的DLL之后,從三個鏈中RemoveEntryList就可以了,這樣所有使用PEB->Ldr結(jié)構(gòu)來枚舉DLL鏈表的就無法找到了。
由于大部分ARK對隱藏DLL的查找并不是很重視(比如RKU,Gmer,XueTr,Atool,NIAP),因此該方法就可以bypass很多ARK了,還是有一定市場的~
但對IceSword是個例外
二、從VAD樹中消失
IceSword 在枚舉進程模塊時使用的是ZwQueryVirtualMemory,查詢的InfoClass是MemorySectionName(或者叫 MemoryMappedFilenameInformation,值為2)。NtQueryVirtualMemory首先判斷Vad->ControlArea->FilePointer是否有效,若有效則調(diào)用ObQueryNameString查詢此文件對象的名 稱,最終由文件系統(tǒng)完成此次查詢工作。
關于VAD的詳細知識,可以參考《JIURL玩玩Win2k內(nèi)存篇 VAD》,這里不作為重點,知道是平衡二叉樹就可以了,樹的根結(jié)點在EPROCESS中。
引用內(nèi)容
lkd> dt _EPROCESS 83f915b8??
nt!_EPROCESS
????...
????+0x11cVadRoot?????????? :0x84079c08
該成員是一個MMVAD類型的結(jié)構(gòu),而成員LeftChild和RightChild分別是該結(jié)點的左子結(jié)點和右子結(jié)點。
引用內(nèi)容
lkd> dt _MMVAD 0x84079c08
nt!_MMVAD
????+0x000 StartingVpn??????: 0x8e0
????+0x004EndingVpn???????? : 0x8e0
????+0x008Parent????????????:(null)
????+0x00cLeftChild???????? : 0x843b1128 _MMVAD//左孩子
????+0x010RightChild????????: 0x840bf4a0 _MMVAD//右孩子
????+0x014u????????????????: __unnamed //標志位
????+0x018 ControlArea??????: (null)
????+0x01c FirstPrototypePte : (null)
????+0x020 LastContiguousPte : (null)
????+0x024u2????????????????:__unnamed
要 對目標DLL實施隱藏時,先獲取該DLL基址,然后遍歷VAD樹,根據(jù)MMVAD->StartingVpn做匹配(StartingVpn實際上 是內(nèi)存地址的高20位,比如0x7c800000在這里將只顯示為0x7c800)找到目標DLL的VAD結(jié)構(gòu)(這里以kernel32.dll為例,其 加載地址正為0x7c800000):
引用內(nèi)容
lkd> dt _MMVAD 84174a18
nt!_MMVAD
????+0x000 StartingVpn??????: 0x7c800
????+0x004EndingVpn???????? : 0x7c91b
????+0x008Parent????????????:0x841223a0 _MMVAD
????+0x00cLeftChild???????? : 0x84120470 _MMVAD
????+0x010RightChild????????: 0x841a4790 _MMVAD
????+0x014u????????????????: __unnamed
????+0x018 ControlArea??????: 0x876d0b88 _CONTROL_AREA //關鍵域
????+0x01c FirstPrototypePte : 0xe177d6f0 _MMPTE
????+0x020 LastContiguousPte : 0xfffffffc _MMPTE
????+0x024u2????????????????:__unnamed
lkd> dt _CONTROL_AREA 0x876d0b88
nt!_CONTROL_AREA
????...
????+0x024 FilePointer??????: 0x876d0b10 _FILE_OBJECT外//目標在這里
好 了,看到FILE_OBJECT了,這時你應該會想到系統(tǒng)是從這里取到的文件名吧,沒錯,這兒就是我們要動手腳的地方。根據(jù)小偉、Sysnap等人的測 試,只要把ControlArea->FilePointer->FileName.Buffer填0就可以實現(xiàn)該DLL的隱藏(根據(jù)字符串 的特性,實際上只需要把第一個字符填0就可以了),此時ZwQueryVirtualMemory將返回0xC0000039錯誤,即“指定的路徑無 效”,自然也就枚舉不到了。而且對于那些共享的dll,如系統(tǒng)的ntdll.dll,kernel32.dll或在不同進程中被加載2次或以上的dll, 雖然是在不同進程中,但是使用的是同一個共享的ControlArea結(jié)構(gòu),因此只需要改一個,那么在所有進程中都將實現(xiàn)隱藏,這對于隱藏全局鉤子類型的dll顯然是非常方便的。
IS是在ZwQueryVirtualMemory查完全無法枚舉到DLL時才采用枚舉PEB的方法,因此結(jié)合前面的Ldr斷鏈法,足以搞定N多ARK了。
我所說的“從VAD樹中消失”只是使該VAD的信息從IS的查詢結(jié)果中消失,而并不是真的摘掉該VAD~~
值得一說的是,Sysnap的Yas Kit在檢測隱藏DLL方面也是比較強的,但是對于動了VAD的,似乎也無能為力~
三、抹掉PE特征
有的工具可以直接枚舉所有有效內(nèi)存并檢查PE標記來確定是否有隱藏DLL,因此需要把PE特征抹掉來對抗之,方法很簡單,把PE頭整個填零就可以了。
這種方法主要是作為前兩種方法的補充,單獨搞是沒有意義的。
再來說說非正規(guī)方式加載的DLL,怎么個非正規(guī)呢?其實就是不用LoadLibrary,自已實現(xiàn)Loader的功能.
實 現(xiàn)Loader功能之后,不管你是Load別的DLL,或者DLL自已Load自己(老V的ReloadAndRun同樣適用于DLL),在Load完成 后,不會出現(xiàn)在PEB->Ldr鏈中,它的VAD也不會與FILE_OBJECT發(fā)生任何關系,然后再抹掉PE特征,隱藏效果與上面的正規(guī)隱藏法相 當,甚至要更隱蔽一些~~
再極端一點,DLL也可以完全不要,注入具有相同功能的shellcode然后開線程執(zhí)行就可以了,只是shellcode寫起來麻煩一點而已,寫Loader也麻煩啊~~
?
?
http://bbs.pediy.com/archive/index.php?t-125571.html
http://lwglucky.blog.51cto.com/1228348/282331
?
總結(jié)
以上是生活随笔為你收集整理的模块隐藏(LDR_MODULE链 与 PE特征)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 注入(二):修改导入表(c++)
- 下一篇: 安全的交互通道 及 栈回塑检查与伪造