You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

64位Linux下如何将执行流程重定向至堆上代码?

解决64位Linux下堆代码执行重定向问题

嘿,我来帮你搞定这个把执行流跳转到堆代码的问题!你的代码有几个关键问题导致编译失败或者运行出错,我来逐个拆解并修正:

原代码的核心问题

  • 64位寄存器指令错误:你用了movl(32位移动指令)操作64位的rip寄存器,这在64位编译环境下会报错,应该用movq来处理64位数据。
  • 操作方向完全搞反:你的汇编指令是把rip的值写入t指向的内存,而我们需要的是让rip跳转到t指向的堆内存,也就是要把t的地址加载到rip。
  • 堆内存默认无执行权限:Linux下malloc分配的堆内存默认是RW(可读可写)但不可执行的,直接跳转过去会触发段错误,需要用mprotect修改内存权限为RWX。
  • 输入类型不匹配:用int接收十六进制字节再赋值给char可能会有符号扩展问题,建议改用unsigned char。

修正后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

int main() {
    size_t len = 0;
    unsigned char *t;
    unsigned int chr; // 用unsigned int避免符号问题

    printf("Input code length: ");
    scanf("%zu", &len);

    // 分配堆内存,注意要对齐到页边界(mprotect要求页对齐)
    t = malloc(len + getpagesize());
    if (!t) {
        perror("malloc failed");
        exit(1);
    }
    // 计算页对齐的起始地址
    unsigned char *aligned_t = (unsigned char*)((unsigned long)t & ~(getpagesize() - 1));

    // 修改内存权限为可读、可写、可执行
    if (mprotect(aligned_t, len + getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {
        perror("mprotect failed");
        free(t);
        exit(1);
    }

    printf("Input hex bytes (space-separated): ");
    for (size_t i = 0; i < len; ++i) {
        scanf("%x", &chr);
        t[i] = (unsigned char)chr;
    }

    // 跳转到堆上的代码:用call或者jmp指令修改rip
    asm volatile(
        "jmp *%0" // 间接跳转,把%0的值(t的地址)加载到rip
        :
        : "r"(t)
        : "memory"
    );

    // 下面的代码不会被执行到
    free(t);
    return 0;
}

关键修改点说明

  1. 内存权限修改:

    • 用mprotect修改堆内存权限,它要求操作的内存区域必须是页对齐的,所以我们先分配了额外的页大小空间,再计算对齐后的起始地址。
    • PROT_READ | PROT_WRITE | PROT_EXEC让内存同时拥有读写执行权限。
  2. 内联汇编修正:

    • 用jmp *%0实现间接跳转,把t的地址加载到rip,这是64位下修改指令指针的正确方式。
    • asm volatile确保编译器不会优化掉这段汇编代码,"memory"约束告诉编译器这段代码会修改内存,避免乱序优化。
  3. 输入与内存分配优化:

    • 用size_t存储长度,匹配malloc和mprotect的参数类型。
    • 用unsigned char存储代码字节,避免符号扩展导致的错误。

编译与运行注意事项

编译时需要关闭栈保护和PIE(位置无关执行),否则可能会影响执行:

gcc -fno-stack-protector -no-pie your_code.c -o heap_exec

然后运行程序,输入代码长度和对应的十六进制机器码(比如输入2和c3,这是x86_64的返回指令),就能看到执行流跳转到堆上的代码了。

内容的提问来源于stack exchange,提问作者enedil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:22:41