免杀对抗—WinDbg查看Windows内存

前言

很久没有更新过了,今天抽空记录一下如何用WinDbg去查看Windows内存,这对于我们排查内存马是非常有帮助的。同时如果免杀想要精进,掌握查看、调试Windows内存或内核是必不可少的。

环境搭建

我们搭建一个WinDbg远程调试环境,也就是物理机运行 WinDbg 去调试虚拟机的内存,这样能确保 WinDbg 能在一个较为流程的环境运行,不会产生卡顿,同时又不会对物理机产生破坏,这被称为双机调试。

首先关闭虚拟机,然后编辑虚拟机设置 -> 添加 -> 串行端口 。

串行端口配置如下,管道名称填:\\.\pipe\com_1,这里有个地方要注意一下,如果你移除打印机,那么添加新的串行端口为2,此时管道名称填\\.\pipe\com_1是不行的。

现在启动虚拟机,管理员运行下面的命令,告诉虚拟机:"启用调试模式,并通过 COM1 口把数据发出去。"

复制代码
bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200

接着 WinDbg 点击 File -> Attach to Kernel,配置如下

选择 "COM" 选项卡:

  • Baud Rate: 115200

  • Port: \\.\pipe\com_1

  • Pipe: 勾选 "Pipe" 复选框(这一步非常重要,说明这不是物理串口,是虚拟管道)。

  • Reconnect: 建议勾选。

最后点击 OK 即可。

此时我们重启虚拟机,看到显示 Debuggee is running... 就代表成功了。

内存查看

为了方便,我运行了一个 project1.exe 加载一个shellcode上线,接下来我们就在内存中查找这个 shellcode,以此来了解Windows内存。

首先我们点击Break,让虚拟机处于冻结状态,否则我们是查看不了的。

输入下面命令,列出当前Windows中正在运行的所有进程,这里要注意 !process 0 0 数据**来自内核态的 EPROCESS 链表 (ActiveProcessLinks),而不是用户态的进程列表。**所以,有些 rootkit 即使在用户态隐藏了进程,我们还是可以在内核态找到。

复制代码
!process 0 0

这里简单解释一下各个信息

  • PROCESS ffffce0385906080: 这是最重要的地址! (我们称之为 EPROCESS),后续所有针对这个进程的操作都基于这个地址。
  • Cid (Client ID): 进程 ID (PID)

  • ParentCid: 父进程 ID。如果你发现 notepad.exe 的父亲是 word.exe,那就是 Process Hollowing 攻击。

  • Peb: 用户态环境块地址 (存放 DLL 加载信息等)。

  • HandleCount:进程句柄数量

  • Image:进程名称

  • DirBase :这是目录基址,它指向进程的页表目录。在 32 位和 64 位 Windows 操作系统中,页表用于虚拟内存到物理内存的映射。这个地址用于页面管理和内存保护。

  • ObjectTable: : 这是进程的对象表的地址。对象表包含了进程中打开的句柄(例如文件、线程、共享内存等),用于管理和访问对象。这个地址指向了包含句柄信息的数据结构。

我们直接查看 project1.exe 进程的相关信息。

复制代码
6: kd> !process 0 0 project1.exe

这里知道了 project1.exe 的 EPROCESS 地址,我们可以通过查看 EPROCESS 地址,去查看更详细的进程信息,其中 1 为简单输出,7 是最详细的输出。

复制代码
! process ffff8082a9288080 1

现在 windbg 默认查看的是Windows全局的内存,如果我们要查看指定进程地址的VAD,那么首先要切换到该进程的 VAD 才行。

复制代码
.process /i ffff8082a9288080
g

此时我们已近切换进去了,可以输入命令 lm 去查看加载了哪些DLL。

我们输入下面的命令,查看当前进程的 VAD 这也是排查shellcode最直接的手段。

复制代码
!vad

这里解释一下各个参数

VAD:虚拟地址

Star:起始地址

End:结束地址

Commit:1为页数,一页大小为4kb,Private 代表这是私有内存(程序自己申请的堆),而不是加载硬盘上的 DLL 文件

READWRITE :表示这块地址的权限,READWRITE 表示可读可写

那我们如何找到那个地址是被写入shellcode的呢,很简单,我们只需查找哪些地址的权限是可写可执行的,因为shellcode首先要写如地址,然后还要执行,所以要申请一块可写可执行的地址,

并且正常程序是极少申请可写可执行的地址的。

我们直接用瞪眼法,发现一块VAD是可写可执行的,并且页数只有1,也就是4kb大小,这非常符合shellcode的情形。

注意 Start 列的数值 26c9acb0,这通常是 虚拟页号 (VPN) 。要得到真实的内存地址,通常需要在后面加三个 0 (乘以 0x1000),所以地址大概率是:26c9acb0000。

这里我解释一下为什么是查看起始地址的数据,而不是VAD地址的数据,因为VAD 地址相当于索引卡片,记录着一本书,放在哪一层,哪一个架子。如果你直接 db 查看VAD地址的内容,只能看到一堆指针啥的。起始地址才是我们要查看的那本书,里面存放shellcode。

复制代码
db 26c9acb0000

此时我们对比一下CS生成的shellcode,可以发现一模一样。

现在我们再来看一下哪个线程执行了shellcode,输入下面的命令查看 project1.exe 进程最详细信息。

复制代码
!process  ffff8082a83ea080 7

我们看下面这两个线程,很明显第一次线程是执行shellcode的,因为第一个线程的开头是

复制代码
0x000001f2`636cce70

这显然与我们的shellcode地址是处于同一内存区域。

并且起始地址 (Start Address): Project1!mainCRTStartup,这说明这不是一个被外挂"注入"进来的新线程,这是程序自己的主线程。

第二张截图则是一个正常的线程,开头是 ntdll!RtlUserThreadStart+0x21

我们还可以查看一下进程的 PEB,以此来判断进程是否被伪造,输入下面命令查看指定进程的PEB。

复制代码
!peb 680f39b000

还可以通过查看EPROCESS信息去对比PEB是否被伪造,因为EPROCESS是内核级的,PEB伪造同时是在用户态。

在 Windows 内核中,EPROCESS 还有一个更隐秘的字段记录了进程创建时的原始全路径,这个通常黑客懒得改或者很难改。

复制代码
dt nt!_EPROCESS ffff8082a83ea080 SeAuditProcessCreationInfo.ImageFileName

然后输入下面命令,查看 _OBJECT_NAME_INFORMATION 结构体内容。

复制代码
dt nt!_OBJECT_NAME_INFORMATION 0xffff8082a1575340

总结

简单记录了一下如何查看进程内容是否写入了shellcode,以及如何判断exe是否伪造了PEB

相关推荐
无限进步_7 小时前
深入理解 C/C++ 内存管理:从内存布局到动态分配
c语言·c++·windows·git·算法·github·visual studio
克喵的水银蛇7 小时前
Flutter 通用标签选择组件:TagSelector 支持单选 / 多选
javascript·windows·flutter
txzz88887 小时前
网络应用netstart命令
网络·windows·计算机网络·microsoft
水饺编程9 小时前
第3章,[标签 Win32] :处理 WM_PRINT 消息
c语言·c++·windows·visual studio
求梦8209 小时前
Java:Windows家庭中文版的Docker下载安装
java·windows·docker
北极糊的狐10 小时前
报错java: 找不到符号符号: 类 XxxController位置: 程序包 com.ruoyi.xxx.xxx.service
开发语言·windows·python
这儿有一堆花10 小时前
Windows 环境下 Nmap 的实战逻辑
windows·网络安全
2gexmxy11 小时前
关于windows UTF-8 BOM的问题
windows
Logic10111 小时前
《Windows批处理(BAT)脚本实战大全:41个场景告别重复操作》含文件处理/查找/重命名/清理等)
windows·编程·文件管理·bat·效率工具·批处理·自动化脚本