有时候我们在对目标进程注入后,并不像让对方发现我们的DLL,也就是为了避免被检查出来,所以我们需要将DLL信息抹去,也就是从PEB中的三根链表中断开存储DLL信息的节点即可。
介绍:
先看一下PEB结构
kd> dt nt!_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
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
在PEB的+0c处,有一个叫Ldr的字段,为什么叫Ldr,其实它是"Loader"的缩写,说到这里,那也就知道了这个字段是和DLL加载有关系的。下来看一下结构体Ptr32 _PEB_LDR_DATA
0: kd> dt nt!_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
在其中最重要的就是标红的三根链表了,
InLoadOrderModuleList; 模块加载顺序
InMemoryOrderModuleList; 模块在内存中的顺序
InInitializationOrderModuleList; 模块初始化装载顺序
LIST_ENTRY 结构是一个双向链表
0: kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
这个双链表指向进程装载的模块,结构中的每个指针,指向了一个LDR_DATA_TABLE_ENTRY
的结构:
0: kd> dt nt!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : Ptr32 Void
+0x01c EntryPoint : Ptr32 Void
+0x020 SizeOfImage : Uint4B
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 _ACTIVATION_CONTEXT
+0x04c PatchInformation : Ptr32 Void
+0x050 ForwarderLinks : _LIST_ENTRY
+0x058 ServiceTagLinks : _LIST_ENTRY
+0x060 StaticLinks : _LIST_ENTRY
+0x068 ContextInformation : Ptr32 Void
+0x06c OriginalBase : Uint4B
+0x070 LoadTime : _LARGE_INTEGER
在LDR_DATA_TABLE_ENTRY结构中有标红的两个字段比较重要,可以根据DLLName来判断是否为目标进程,如果是则把当前LIST_ENTRY节点处断开即可。
代码:
void HideModule(char *szModule)
{
DWORD *PEB = NULL;
DWORD *Ldr = NULL;
DWORD *Flink = NULL;
DWORD *p = NULL;
DWORD *BaseAddress = NULL;
DWORD *FullDllName = NULL;
//定位PEB
__asm
{
//fs位置保存着teb
//fs:[0x30]位置保存着peb
mov eax, fs:[0x30]
mov PEB, eax
}
HMODULE hMod = GetModuleHandleA(szModule);
//得到LDR
Ldr = *((DWORD **)((unsigned char *)PEB + 0x0c));
//第一条链表
Flink = *((DWORD **)((unsigned char *)Ldr + 0x0c));
p = Flink;
do
{
BaseAddress = *((DWORD **)((unsigned char *)p + 0x18));
FullDllName = *((DWORD **)((unsigned char *)p + 0x28));
if ((DWORD*)hMod == BaseAddress)
{
**((DWORD **)(p + 1)) = (DWORD)*((DWORD **)p);
*(*((DWORD **)p) + 1) = (DWORD)*((DWORD **)(p + 1));
break;
}
p = *((DWORD **)p);
} while (Flink != p);
Flink = *((DWORD **)((unsigned char *)Ldr + 0x14));
p = Flink;
do
{
BaseAddress = *((DWORD **)((unsigned char *)p + 0x10));
FullDllName = *((DWORD **)((unsigned char *)p + 0x20));
if (BaseAddress == (DWORD *)hMod)
{
**((DWORD **)(p + 1)) = (DWORD)*((DWORD **)p);
*(*((DWORD **)p) + 1) = (DWORD)*((DWORD **)(p + 1));
break;
}
p = *((DWORD **)p);
} while (Flink != p);
Flink = *((DWORD **)((unsigned char *)Ldr + 0x1c));
p = Flink;
do
{
BaseAddress = *((DWORD **)((unsigned char *)p + 0x8));
FullDllName = *((DWORD **)((unsigned char *)p + 0x18));
if (BaseAddress == (DWORD *)hMod)
{
**((DWORD **)(p + 1)) = (DWORD)*((DWORD **)p);
*(*((DWORD **)p) + 1) = (DWORD)*((DWORD **)(p + 1));
break;
}
p = *((DWORD **)p);
} while (Flink != p);
}