基于断链的DLL隐藏

简介

在红队行动的时,我们往往需要往目标系统的某个进程内注入一个自定义的DLL,而这个自定的DLL往往是恶意,如何让这个模块不被蓝队或应急响应工作者更难检测到就是我们需要做的,断链这种技术非常古老,同时应用于非常多的场景,在内核层如果我们需要隐藏一个进程的内核结构体,也会使用这种技术。

在实战场景中,这种技术使用的比较少,如果需要跨进程隐藏的话需要频繁的读内存,或把代码打成shellcode注入目标进程,所以实际使用中往往不如直接使用shellcode来的方便,同时操作系统内核维护了一个vad二叉树,这个二叉树内管理着所有分配的内存和加载的模块,在三环我们往往无法直接操作内核,所以在windbg此类内核调试器中,此类模块隐藏往往没有意义。

手工实现

前面写commandline伪装的时候讲到过,操作系统会在ring3维护一个结构体PEB(进程环境块),段寄存器FS:[00](x86环境)在三环时始终指向TEB(线程环境块),TEB偏移0x30则指向该进程的PEB。

通常我们可以使用内联汇编的方式获取PEB位于内存的虚拟地址。

mov eax, fs: [0x30] ; 

通过windbg定位teb->peb。

0:007> dt _teb 02f60000
combase!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : (null) 
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : (null) 
   +0x02c ThreadLocalStoragePointer : (null) 
   +0x030 ProcessEnvironmentBlock : 0x02f48000 _PEB //PEB的位置
   +0x034 LastErrorValue   : 0
   +0x038 CountOfOwnedCriticalSections : 0
   +0x03c CsrClientThread  : (null) 
   +0x040 Win32ThreadInfo  : (null) 
   +0x044 User32Reserved   : [26] 0
   ···
   +0xfd8 LockCount        : 0
   +0xfdc WowTebOffset     : 0n-8192
   +0xfe0 ResourceRetValue : (null) 
   +0xfe4 ReservedForWdf   : (null) 
   +0xfe8 ReservedForCrt   : 0
   +0xff0 EffectiveContainerId : _GUID {00000000-0000-0000-0000-000000000000}

在PEB偏移0x0c位置存在着三条模块链表。

使用汇编获取。

根据链表含义分别是 模块加载顺序、模块初始化顺序、模块内存顺序。

这三条链表实际上是_LDR_DATA_TABLE_ENTRY结构体的头部。

到这里我们的思路应该已经很清晰了,在ring3操作系统维护着模块双向链表,我们只要修改我们想要隐藏的模块的前后两个_LDR_DATA_TABLE_ENTRY结构体的前后链表就能实现这个效果。

通俗点说,我们只要让 我的下一个模块的前一个模块指向我的前一个,我的前一个模块的下一个模块指向我的下一个。

思路

  1. 获取PEB地址

  2. 获取LDR地址

  3. 遍历链表

  4. 断链

代码实现

如果您是究极逻辑怪,还可以看看这个不使用结构体的指针版本。

最后更新于

这有帮助吗?