生物科技公司珠海贝斯昂科获近亿元天使轮融资
06-18
断链是一项非常古老的技术,在很多场景中都有使用。在内核层,如果我们需要隐藏某个进程的内核结构,也会用到这种技术。
本文分别在用户层和内核层实现PEB断链。在用户层实现的效果主要是dll模块的隐藏,在内核层实现的效果主要是进程的隐藏。
3环PEB断链 每个线程都有一个TEB结构来存储线程的一些属性结构。 TEB的地址通过fs:[0]获得。
在地址0x30处,有一个指针指向PEB结构image-9.png,然后定位到PEB。 PEB是进程用来记录自身信息的结构体。
PEB 的 0x00c 偏移处有一个 Ldr _PEB_LDR_DATA 结构。按照 image-9.png 进行操作。
_PEB_LDR_DATA中有3个双向链表。 InLoadOrderModuleList:模块加载的顺序。
InMemoryOrderModuleList:模块。内存中的顺序 InInitializationOrderModuleList:模块初始化的顺序 image-0.png 以 InLoadOrderModuleList 为例,双向链表的含义是最后一个指针会指向自己 image-7.png 那么了解了基本原理后,我们可以通过断开链接来实现模块的隐藏,我们知道如果我们要枚举模块,一般都是使用CreateToolhelp32Snapshot来进行快照,找到之后再遍历模块列表。
事实上,API也是通过查找_PEB_LDR_DATA结构来获取程序有哪些模块。那么如果我们想要隐藏某个dll就可以通过修改这两个双向链表来隐藏。
_DRIVER_OBJECT结构中的0x偏移处有一个成员DriverSection,它可以遍历内核模块。DriverSection是一个指针,它实际上对应了一个结构体: _LDR_DATA_TABLE_ENTRYimage-2.png 在_LDR_DATA_TABLE_ENTRY的0x偏移处有一个DllBase,里面存放的是dll image-0.png的地址,所以如果我们想在这里隐藏它的话对于指定的dll,可以通过DllBase通过GetModuleHandleA获取该dll的句柄进行比较。
然后我们首先定义_PEB_LDR_DATA和_LDR_DATA_TABLE_ENTRY结构。代码语言:c++ copy // LDR链表头 typedef struct _PEB_LDR_DATA{DWORD Length;bool Initialized;PVOID SsHandle;LIST_ENTRY InLoadOrderModuleList; // 指向 InLoadOrderModuleList 列表的第一项 LIST_ENTRY InMemoryOrderModuleList;LIST_ENTRY InInitializationOrderModuleList;} PEB_LDR_DATA,*PPEB_LDR_DATA;typedef struct _LDR_DATA_TABLE_ENTRY{LIST_ ENTRY InLoadOrderModuleList;LIST_ENTRY InMemoryOrderModuleList;LIST_ENTRY InInitializationOr derModuleList;void* 基址;无效*入口点; ULONG SizeOfImage;UNICODE_STRINGFullDllName;UNICODE_STRING BaseDllName;ULONG Flags;SHORT LoadCount;SHORT TlsIndex;HANDLE SectionHandle;ULONG CheckSum;ULONG TimeDateStamp;} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;然后通过汇编定位到LDR代码语言: c++ copy__asm{mov eax,fs:[0x30] // PEB mov ecx,[eax + 0x0c] // LDRmov ldr,因为这里的三个双向链表的结构是相同的,所以这里使用InLoadOrderModuleList来演示断链。
这里要实现断链,最简单的办法就是让Head的Flink和Blink指向自己。首先,获取获取到的ldr结构体指向InLoadOrderModuleList。
代码语言:c++ copy Head = &(ldr->InLoadOrderModuleList);然后通过CONTAINING_RECORD宏返回结构体的基地址。代码语言:c++ copy Cur = Head->Flink;ldte = CONTAINING_RECORD( Cur, LDR_DATA_TABLE_ENTRY , InInitializationOrderModuleList); image-4.png 代码语言:c++ copy void CONTAINING_RECORD(address, type, field);执行断链操作 代码语言:txt copy ldte->InInitializationOrderModuleList.Blink->Flink = ldte->InInitializationOrderModuleList.Flink;代码语言:txt复制ldte->InInitializationOrderModuleList.Flink->Blink = ldte->InInitializationOrderModuleList.Blink;然后将指针指向下一个结构体代码语言:c++ copy Cur = Cur->Flink;因为它需要遍历链表来断开链接并指向自己进行操作,所以需要编写一个循环来断开链接。
完整代码如下。代码语言:c++ copy //killPEB.cpp :D定义控制台应用程序的入口点。
//#include "stdafx.h"#include
代码语言:c++ copy void HideModule_All(){PPEB_LDR_DATA ldr; PLDR_DATA_TABLE_ENTRY ldte;//获取LDR__asm{mov eax,fs:[0x30] mov ecx,[eax + 0x0c]mov ldr,ecx }PLIST_ENTRY 头; Head = &(ldr->InLoadOrderModuleList);Head->Flink = Head->Blink = Head;Head = &(ldr->InMemoryOrderModuleList);Head->Flink = Head->Blink = Head;Head = &(ldr- >InInitializationOrderModuleList);Head->Flink = Head->Blink = Head;}??效果如下 image-5.png 练习后,所有模块不再可见 image-8.png0 Ring PEB Break 在操作系统层面,一个过程本质上是一个结构。当操作系统要创建一个进程时,它会分配一块内存,填充一个结构体,并为结构体中的每一项填充一些特定的值。
该结构 EPROCESSimage-6.png 在 x 偏移处有一个指针 ActiveProcessLinks,指向 _LIST_ENTRY。它是一个双向链表,所有活动进程连接在一起形成一个链表image-0.png。
那么链表总是有一个头,全局变量PsActiveProcessHead(8个字节)指向全局链表头。这个链表与进程隐藏有关。
只要我们打断我们想要隐藏的进程对应的EPROCESS链接,就可以达到隐藏ring 0进程的目的。我们看一下PsActiveProcessHead代码语言:c++ copy kd> dd PsActiveProcessHeadimage-4.png 。
前四个字节指向下一个EPROCESS结构,但它不是指向EPROCESS的首地址,而是指向每个进程的_EPROCESS + 0x88。 image-7.png的位置,所以当我们要查询下一个进程结构时,我们需要-0x88。
例如,PsActiveProcessHead 当前指向的下一个地址是 0xb58b8 代码语言: c++ copy kd> dt _EPROCESS b58b8-0x88 将进程名称存储在 0x 偏移处。我们可以看到第一个EPROCESS结构体对应的是System进程,这里 0x88 的偏移量存储的是下一个EPROCESS结构体的地址,但是这里要注意,因为这个结构体的地址指向下一个链表的地址,所以如果你想要获取EPROCESS的第一个结构体,需要-0x88image-3.png,我们通过偏移量得到下一个EPROCESS结构体,可以发现其实现为smss.exe进程image-2.png。
所以我们的想法在这里很明确。通过EPROCESS找到我们想要隐藏的进程的ActiveProcessLinks,修改双向链表的值,我们就可以将这个进程的ActiveProcessLinks从双向链表中删除掉,达到隐藏的效果,这样比较方便直接使用windbg中的ed进行修改,但是如果想使用代码修改的话,需要先在ETHREAD中定位EPROCESS的0x偏移量,通过ThreadsProcess获取,它指向_EPROCESS结构体image-7.png。
然后就可以用汇编实现来查找EPROCESS结构体代码语言: c++ copy __asm{mov eax, fs: [0x] ;mov eax, [ eax + 0x];mov pEprocess, eax;} ??首先定义一个指向EPROCESS的指针构造并初始化指向ActiveProcessLinks的指针 代码语言:c++ copy pCurProcess = pEprocess; curNode = (PLIST_ENTRY)((ULONG)pCurProcess + 0x88);然后判断使用EPROCESS中0x处的ImageFileName判断该进程名是否是我们要隐藏的进程 image-6.png 代码语言:c++ copy ImageFileName = (PCHAR)pCurProcess + 0x;if (strcmp(ImageFileName, "notepad .exe") == 0) 如果是我们要隐藏的进程,执行链接破坏操作代码语言:c++ copy curNode = (PLIST_ENTRY)((ULONG)pCurProcess + 0x88);nextNode = curNode->Flink;preNode = curNode->Blink;preNode->Flink = curNode->Flink;nextNode->Blink = curNode->Blink;如果不是我们想要的进程,继续往下走,获取ActiveProcessLinks的值。代码语言:c++ copy pCurProcess = (PEPROCESS)(*(PULONG)((ULONG)pCurProcess + 0x88) - 0x88);完整代码如下。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-18
06-17
06-08
06-06
06-17
06-18
06-18
06-17
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用