上一篇文章讨论了远程线程注入的相关知识,我们通过LoadLibraryA函数在目标进程加重了我们自己编写的dll并成功运行,但是这种方法显然很容易被发现,我们只要比较PE文件中的导入表和运行时加载的dll文件就能知道该进程是否被注入了,因此我们需要隐藏我们加载的dll
1 断链
TEB(Thread Environment Block),它记录的相关线程的信息,每一个线程都有自己的TEB,FS:[0]即是当前线程的TEB
PEB(Process Environment Block),进程环境块存放进程信息,每个进程都有自己的PEB信息,TEB偏移0x30即当前进程的PEB
我们借助windbg查看TEB和PEB的结构如下
在peb中有一个结构体为_PEB_LDR_DATA如下:
红框中的部分为三个双向链表,InLoadOrderModuleList为加载时的模块列表,InMemoryOrderModuleList为在内存中的模块列表,InInitializationOrderModuleList为初始化时的模块列表,链表里面的值为以下结构体
因此我们需要在这三个双向链表中把远程加载的dll文件删掉就能到达隐藏的目的
2 实验
我们编写断链隐藏dll的代码如下:
#include <iostream>
#include <windows.h>
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _PEB_LDR_DATA {
ULONG length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
UCHAR ShutdownInProgress;
PVOID ShutdownThreadId;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks; //代表按加载顺序构成的模块链表
LIST_ENTRY InMemoryOrderLinks; //代表按内存顺序构成的链表
LIST_ENTRY InInitializationOrderLinks; //代表按初始化顺序构成的链表
PVOID BaseAddress; //该模块基地址
PVOID EntryPoint; //该模块的入口
ULONG SizeOfImage; //该模块的影像大小
UNICODE_STRING FullDllName; //包含路径的模块名
UNICODE_STRING BaseDllName; //不包含路径的模块名
ULONG Flags;
USHORT LoadCount; //该模块的引用次数
} LDR_MODULE, * PLDR_MODULE;
void Hide(char* moduleName) {
HMODULE hMod = GetModuleHandle(moduleName);
PLIST_ENTRY Head, Cur;
PPEB_LDR_DATA ldr;
PLDR_MODULE ldm;
__asm
{
mov eax , fs:[0x30]
mov ecx , [eax + 0x0c]
mov ldr , ecx
}
Head = &(ldr->InLoadOrderModuleList);
Cur = Head->Flink;
do
{
//宏CONTAINING_RECORD根据结构体中的某成员的地址来推算结构体的地址
ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderLinks);
if (hMod == ldm->BaseAddress)
{
ldm->InLoadOrderLinks.Blink->Flink = ldm->InLoadOrderLinks.Flink;
ldm->InLoadOrderLinks.Flink->Blink = ldm->InLoadOrderLinks.Blink;
ldm->InMemoryOrderLinks.Blink->Flink = ldm->InMemoryOrderLinks.Flink;
ldm->InMemoryOrderLinks.Flink->Blink = ldm->InMemoryOrderLinks.Blink;
ldm->InInitializationOrderLinks.Blink->Flink = ldm->InInitializationOrderLinks.Flink;
ldm->InInitializationOrderLinks.Flink->Blink = ldm->InInitializationOrderLinks.Blink;
break;
}
Cur = Cur->Flink;
} while (Cur != Head);
}
int main() {
printf("---------按任意键断链---------\n");
getchar();
Hide("kernel32.dll");
printf("---------断链成功---------\n");
getchar();
return 0;
}
编写完代码后编译运行,借助DTDebug来查看进程加载的模块
启动模块隐藏后,发现kernel32.dll被隐藏了
断链之后虽然隐藏了kernel32.dll,但仍然可以通过遍历进程vad树的方式发现该模块