如何使用ThreadStackSpoofer隐藏Shellcode的内存分配行为

安全 网站安全
ThreadStackSpoofer是一种先进的内存规避技术,它可以帮助广大研究人员或红/蓝队人员更好地隐藏已注入的Shellcode的内存分配行为,以避免被扫描程序或分析工具所检测到。

[[437138]]

关于ThreadStackSpoofer

ThreadStackSpoofer是一种先进的内存规避技术,它可以帮助广大研究人员或红/蓝队人员更好地隐藏已注入的Shellcode的内存分配行为,以避免被扫描程序或分析工具所检测到。

ThreadStackSpoofer是线程堆栈欺骗技术的一个示例实现,旨在规避恶意软件分析、反病毒产品和EDR在检查的线程调用堆栈中查找Shellcode帧的引用。其思想是隐藏对线程调用堆栈上针对Shellcode的引用,从而伪装包含了恶意代码的内存分配行为。

在该工具的帮助下,可以帮助现有的商业C2产品安全性有更好的提升,并协助红队研究人员开发出更好的安全产品/工具。

工具运行机制

ThreadStackSpoofer的大致运行机制和算法如下所示:

  • 从文件中读取Shellcode的内容;
  • 从dll获取所有必要的函数指针,然后调用SymInitialize;
  • 设置kernel32!Sleep狗子,并指向回我们的回调;
  • 通过VirtualAlloc + memcpy + CreateThread注入并启动Shellcode。线程应该通过我们的runShellcode函数启动,以避免线程的StartAddress节点进入某些意外或异常的地方(比如说ntdll!RtlUserThreadStart+0x21);
  • 当Beacon尝试休眠的时候,我们的MySleep回调便会被调用;
  • 接下来,我们将栈内存中最新返回的地址重写为0;
  • 最后,会发送一个针对::SleepEx的调用来让Beacon继续等待后续的连接;
  • 休眠结束之后,我们将恢复之前存储的原始函数返回地址并继续执行挂起的任务;

函数的返回地址会分散在线程的堆栈内存区域周围,由RBP/EBP寄存器存储其指向。为了在堆栈上找到它们,我们需要首先收集帧指针,然后取消对它们的引用以进行覆盖:

  1. *(PULONG_PTR)(frameAddr + sizeof(void*)) = Fake_Return_Address; 

工具下载

广大研究人员可以使用下列命令将该项目源码克隆至本地:

  1. git clone https://github.com/mgeeky/ThreadStackSpoofer.git 

工具使用

使用样例

  1. C:\> ThreadStackSpoofer.exe <shellcode> <spoof> 

其中:

  • <shellcode>:Shellcode的文件路径;
  • <spoof>:“1”或“true”代表启用线程栈内存欺骗,其他参数表示禁用该技术;

欺骗Beacon的线程调用栈示例:

  1. PS D:\dev2\ThreadStackSpoofer> .\x64\Release\ThreadStackSpoofer.exe .\tests\beacon64.bin 1 
  2. [.] Reading shellcode bytes... 
  3. [.] Hooking kernel32!Sleep... 
  4. [.] Injecting shellcode... 
  5. [+] Shellcode is now running. 
  6. [>] Original return address: 0x1926747bd51. Finishing call stack... 
  7. ===> MySleep(5000) 
  8. [<] Restoring original return address... 
  9. [>] Original return address: 0x1926747bd51. Finishing call stack... 
  10. ===> MySleep(5000) 
  11.  
  12.   
  13.  
  14. [<] Restoring original return address... 
  15.  
  16. [>] Original return address: 0x1926747bd51. Finishing call stack... 

工具使用演示

下面的例子中,演示了没有执行欺骗技术时的堆栈调用情况:

开启线程堆栈欺骗之后的堆栈调用情况如下图所示:

上述例子中,我们可以看到调用栈中最新的帧为MySleep回调。我们可以通过搜索规则查找调用堆栈未展开到系统库中的线程入口点:

  1. kernel32!BaseThreadInitThunk+0x14 
  2. ntdll!RtlUserThreadStart+0x21 

上图所示为未修改的Total Commander x64线程。正如我们所看到的,它的调用堆栈在初始调用堆栈帧方面与我们自己的调用堆栈非常相似。

项目地址

ThreadStackSpoofer:【GitHub传送门

 

责任编辑:赵宁宁 来源: FreeBuf
相关推荐

2013-11-07 09:42:42

对象对象池加速

2020-09-25 09:26:04

Speakeasy

2023-10-17 00:01:34

Linux操作系统

2021-02-28 13:22:54

Java内存代码

2010-09-25 15:40:52

配置JVM内存

2018-02-08 14:57:22

对象内存分配

2021-12-16 06:52:33

C语言内存分配

2019-02-28 14:04:28

内存固定分配存储

2013-12-10 10:53:47

shellcode

2021-07-14 10:00:32

Python内存测量

2018-04-08 08:45:53

对象内存策略

2015-11-16 11:22:05

Java对象内存分配

2009-06-03 15:52:34

堆内存栈内存Java内存分配

2010-09-25 14:12:50

Java内存分配

2010-08-11 13:28:46

Flex行为

2022-03-18 22:39:57

动态内存malloc

2023-06-08 09:44:13

WindowSpy目标用户监控

2022-03-16 08:39:19

StackHeap内存

2019-07-29 10:10:06

Java内存线程安全

2012-09-29 10:29:56

.Net内存分配继承
点赞
收藏

51CTO技术栈公众号