在C++中动态执行用户Shellcode遇阻,求问题排查
分析你的Shellcode执行失败问题
我来帮你拆解代码里的几个关键问题,这些都是导致执行异常的核心原因:
1. Shellcode本身不完整,缺少返回指令
你定义的shellcode是"\xB8\x04\x00\x00\x00",对应的汇编指令是:
mov eax, 0x4
这段代码执行完毕后,CPU没有收到返回指令(ret),会继续执行后续的垃圾内存数据,必然触发访问异常。你需要在shellcode末尾加上\xC3(对应ret指令),让函数指针调用后能正确返回。
2. 自定义段的属性设置问题(MSVC特定)
你用#pragma section(".shell",read,execute)创建的段,存在两个潜在问题:
- MSVC的段属性设置中,只指定
read+execute的段可能会被链接器的默认规则调整,导致实际权限不符合预期; - 全局数组放到自定义段时,链接器可能会和其他段合并,破坏你设置的可执行属性。
更稳妥的写法是明确加上write属性(即使你不需要修改shellcode,也能避免链接器的特殊处理),或者直接用动态内存分配的方式控制权限,这比自定义段更可靠。
3. 函数指针转换的不规范写法(虽非直接崩溃原因,但需注意)
你把数组地址转换成函数指针的写法((int(*)())&code),这里&code是数组的指针(unsigned char (*)[...]类型),直接转换会触发类型转换警告。更规范的写法是取数组首元素地址,或者利用数组名退化为指针的特性:
// 两种等价的规范写法 shell = reinterpret_cast<int(*)()>(&code[0]); // 或者 shell = reinterpret_cast<int(*)()>(code);
修复后的示例代码
这里提供两种修复方案,按需选择:
方案1:修复自定义段写法
#pragma section(".shell", read, write, execute) __declspec(allocate(".shell")) unsigned char code[] = "\xB8\x04\x00\x00\x00\xC3"; // 新增ret指令\xC3 int(*shell)(); int main() { shell = reinterpret_cast<int(*)()>(code); int a = shell(); // a的值会是4,可正常返回 return 0; }
方案2:用VirtualAlloc动态分配可执行内存(更推荐,灵活性更高)
这种方式完全手动控制内存权限,不受编译器段设置的影响:
#include <windows.h> int main() { unsigned char code[] = "\xB8\x04\x00\x00\x00\xC3"; // 分配可读写执行的内存页 void* exec_mem = VirtualAlloc(nullptr, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!exec_mem) { // 处理内存分配失败的情况 return 1; } // 复制shellcode到可执行内存 memcpy(exec_mem, code, sizeof(code)); // 转换为函数指针并执行 int(*shell)() = reinterpret_cast<int(*)()>(exec_mem); int a = shell(); // 释放内存 VirtualFree(exec_mem, 0, MEM_RELEASE); return 0; }
额外注意事项
- 架构匹配:你的shellcode是32位x86指令,要确保项目编译为32位程序;如果是64位项目,需要编写对应的64位shellcode。
- DEP影响:上述两种方案都是在可执行内存中执行代码,不会被数据执行保护(DEP)拦截,无需额外关闭DEP。
- 编译器选项:如果启用了
/GS(缓冲区安全检查),不会影响上述代码的执行,但要注意其他内存操作的安全性。
内容的提问来源于stack exchange,提问作者Yedidya kfir
相关产品推荐
相关产品推荐

