文章总结: 本文介绍了一种使用x64dbg调试器提取内存中Base64编码Shellcode的技术方法。文章首先解释了恶意软件常在运行时将编码的Shellcode解码到内存中执行的原理,然后通过一个模拟恶意程序实例,详细演示了如何定位解码后的Shellcode、设置断点、使用Scylla插件转储内存内容的完整流程。作者还提供了高级技巧,如设置内存访问断点和执行断点,以应对实际恶意软件分析场景。这些技术对安全研究人员和恶意软件分析师具有重要实用价值。
综合评分: 85
文章分类: 恶意软件,逆向分析,二进制安全,漏洞分析,安全工具
使用 x64dbg 解码并提取内存中的 Base64 Shellcode
原创
独特三明治
SOC安全分析之旅
2025年9月14日 09:38
上海
教程:使用 x64dbg 解码并提取内存中的 Base64 Shellcode
⚠️ 安全警告
本教程仅用于合法的安全研究、恶意软件分析和授权的渗透测试。所有操作应在隔离的虚拟实验室环境中进行。切勿将以下技术用于非法目的。
一、 核心原理
#
在恶意软件分析中,你经常会遇到程序在运行时才将加密或编码的 Shellcode 解码到内存中执行的情况。Base64 是最常见的编码方式之一。静态分析时,你只能在二进制文件中看到一串 Base64 字符串;动态分析的目标就是在其被解码为原始二进制机器码并准备执行时,从内存中将其捕获。
x64dbg 是完成此任务的理想工具,因为它允许我们:
- 在关键代码段设置断点,暂停执行。
- 检查和转储内存区域。
- 使用其内置的脚本和插件功能自动化任务。
二、 分析场景模拟
#
我们假设一个简单的恶意程序 malware.exe,它的行为如下:
- 它内部存储了一段经过 Base64 编码的 Shellcode(例如,弹出一个消息框)。
- 在运行时,它调用
CryptStringToBinaryA或自定义的 Base64 解码函数来解码这段字符串。 - 它将解码后的原始 Shellcode 写入一块新申请的内存(如
VirtualAlloc)。 - 最后,它跳转到这块内存执行 Shellcode。
我们的目标:在 Shellcode 被解码到内存后、但执行前,将其提取出来。
三、 必备工具与环境
#
- x64dbg: 强大的 Windows 开源调试器。确保已安装。
- Scylla: 通常内置于 x64dbg 的插件中,用于转储进程内存。
- 一个示例程序: 我们将使用下面提供的简单 C++ 程序来模拟恶意软件的行为。请先在 Visual Studio 中编译它。
示例程序代码 (simulated_malware.cpp):
#include <windows.h>#include <string.h>#include <stdio.h>
// 这是一段简单的弹窗Shellcode(MessageBoxA),使用Base64编码const char* encodedShellcode = "VYnlVlfky4XAdP9Ei8GDwQDBhMF16FNTiciDwQJmi8GDwgLBdQlEicyJ5VwBwYnlg+wC/3QEsA==";
int main() { printf("[+] Simulated Malware Started.\n"); printf("[+] Encoded Shellcode: %s\n", encodedShellcode);
// 1. 计算所需内存大小并申请内存 DWORD len = 0; CryptStringToBinaryA(encodedShellcode, 0, CRYPT_STRING_BASE64, NULL, &len, NULL, NULL); // 第一次调用获取长度 printf("[+] Decoded Shellcode Length: %d bytes\n", len);
LPVOID alloc_mem = VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!alloc_mem) { printf("[-] VirtualAlloc failed!\n"); return -1; } printf("[+] Memory allocated at: 0x%p\n", alloc_mem);
// 2. 解码Base64到申请的内存中 if (!CryptStringToBinaryA(encodedShellcode, 0, CRYPT_STRING_BASE64, (BYTE*)alloc_mem, &len, NULL, NULL)) { printf("[-] Decoding failed!\n"); return -1; } printf("[+] Shellcode decoded into memory.\n");
// 3. 打印解码后的字节(前10个)用于验证 printf("[+] First 10 bytes of decoded shellcode: "); for (int i = 0; i < 10 && i < len; i++) { printf("%02X ", ((BYTE*)alloc_mem)[i]); } printf("\n");
// 4. 创建一个断点,方便我们在x64dbg中拦截,防止直接执行 __debugbreak(); // 这是一个内置的断点指令,非常适合教学
// 5. 转换为函数指针并执行(在实际恶意软件中就是这样) printf("[+] Press any key to trigger the shellcode...\n"); getchar();
void (*func)() = (void (*)())alloc_mem; func();
printf("[+] Shellcode executed.\n"); getchar(); return 0;}
四、 分步详解:使用 x64dbg 提取
#
步骤 1: 加载并运行程序
- 打开 x64dbg,将编译好的
simulated_malware.exe拖入 x64dbg 窗口。 - 按
F9(运行)一次,让程序中断在系统断点(Entry Point)。 - 再按一次
F9,让程序运行起来。你会看到控制台窗口输出,程序暂停在__debugbreak()处,并自动被 x64dbg 捕获。
步骤 2: 定位解码后的 Shellcode
此时,Shellcode 已经被解码到内存中(由 VirtualAlloc 分配的内存块)。我们有几种方法找到它:
- 方法 A: 查看控制台输出:程序打印了内存地址
Memory allocated at: 0x0000000001230000(地址每次运行都不同,请以你的为准)。 - 方法 B: 在代码中查找:在 CPU 窗口,查看
__debugbreak()之前的代码。你会看到mov rcx, rax之类的指令,其中rax通常保存着VirtualAlloc返回的地址。查看寄存器窗口,找到这个地址。
步骤 3: 在内存转储中查看
- 在 x64dbg 左下角的 内存映射 (
Alt + M)窗口中,找到包含你刚刚记下的地址(例如0x0000000001230000)的内存区域。 - 右键该内存区域 -> 在转储中跟随。
- 现在主转储窗口会显示该内存地址的内容。你应该能看到原始的机器码字节(例如
FC 48 83 E4 F0 E8 C8 00 00 00),而不是之前的 Base64 文本。
步骤 4: 使用 Scylla 插件转储 Shellcode
这是最可靠的方法,可以将内存字节保存到文件中。
- 在 x64dbg 菜单栏,选择 插件 -> Scylla -> Dump Memory。
- 在弹出的窗口中:
- Address: 输入你找到的 Shellcode 起始地址(e.g.,
0x0000000001230000)。 - Size: 输入 Shellcode 的长度。我们的程序在控制台打印了
Decoded Shellcode Length: 80 bytes。 - Dump To File: 点击
...按钮,选择一个路径和文件名(如decoded_shellcode.bin)。
- 点击 Dump 按钮。
恭喜!你现在已经将内存中的原始 Shellcode 成功提取到了 decoded_shellcode.bin 文件中。
步骤 5 (验证): 分析转储的文件
你可以用任何工具分析这个 .bin 文件:
- 再次用 x64dbg 反汇编: 菜单栏 -> 文件 -> 修补文件 -> 将补丁加载到内存中,选择你刚保存的
.bin文件。x64dbg 会将其加载到一个新地址,你就可以在 CPU 窗口反汇编它了。 - 使用其他工具: 如
objdumpin Linux:objdump -D -b binary -m i386 decoded_shellcode.bin。
五、 高级技巧:设置执行断点
在实际分析中,程序不会友好地调用 __debugbreak()。更常见的方法是:
- 在
VirtualAlloc或类似的内存分配函数上设置断点,获取返回的内存地址。 - 在
CryptStringToBinaryA或自定义解码函数之后设置断点。 - 最好的方法:对存放解码后 Shellcode 的内存地址设置内存访问断点或执行断点。
- 在内存地址上右键 -> 断点 -> 硬件访问 -> 执行。
- 当程序尝试跳转到该地址执行 Shellcode 时,x64dbg 会中断。此时 Shellcode 已在内存中且未被执行,是转储的完美时机。
通过本教程,你已经掌握了在真实恶意软件分析中至关重要的一项技能。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:SOC安全分析之旅 独特三明治《使用 x64dbg 解码并提取内存中的 Base64 Shellcode》