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

如何打印当前进程内存中实时的GLOBAL_OFFSET_TABLE(GOT)内容

如何获取当前进程实时的.got段内容(无需解析静态ELF)

核心思路

.got段在进程运行时会被映射到内存中,要拿到它的实时内容,关键是找到该段在当前进程内存中的起始地址和大小,然后直接读取对应内存区域即可,完全不需要解析静态ELF文件。

方法1:利用链接器导出的符号(C语言示例)

如果你的程序是C语言编写的,直接用链接器在编译时注入的边界符号就能定位.got段:

#include <stdio.h>

// 链接器自动导出的符号,标记.got段的起始与结束位置
extern char __got_start[];
extern char __got_end[];

int main() {
    size_t got_size = (size_t)(__got_end - __got_start);
    printf("GOT段起始地址: %p\n", __got_start);
    printf("GOT段大小: %zu 字节\n", got_size);
    
    // 以十六进制格式打印GOT段的每个条目
    printf("GOT段内容:\n");
    for (size_t i = 0; i < got_size; i += sizeof(void*)) {
        void** entry = (void**)(__got_start + i);
        printf("  偏移0x%zx: %p\n", i, *entry);
    }
    
    return 0;
}

编译命令:gcc -o read_got read_got.c

这种方式最直接,符号是编译时就确定的,运行时直接调用就能拿到实时的内存地址,完全跳过静态ELF解析步骤。

方法2:解析/proc/self/maps获取映射信息

如果没法用链接器符号(比如处理动态加载的模块),可以读取/proc/self/maps文件——这个文件实时记录当前进程的所有内存映射,从中筛选出.got段的条目:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    FILE* maps_file = fopen("/proc/self/maps", "r");
    if (!maps_file) {
        perror("打开/proc/self/maps失败");
        return 1;
    }

    char line_buf[256];
    void* got_start = NULL;
    size_t got_size = 0;

    // 遍历文件行,匹配包含[got]的条目
    while (fgets(line_buf, sizeof(line_buf), maps_file)) {
        if (strstr(line_buf, "[got]")) {
            // 解析地址范围:格式为"起始地址-结束地址 权限 ..."
            char* dash_pos = strchr(line_buf, '-');
            if (!dash_pos) continue;
            *dash_pos = '\0';
            got_start = (void*)strtoull(line_buf, NULL, 16);
            
            char* end_addr_str = dash_pos + 1;
            char* space_pos = strchr(end_addr_str, ' ');
            if (!space_pos) continue;
            *space_pos = '\0';
            void* got_end = (void*)strtoull(end_addr_str, NULL, 16);
            got_size = (size_t)(got_end - got_start);
            break;
        }
    }
    fclose(maps_file);

    if (!got_start) {
        fprintf(stderr, "未找到GOT段映射\n");
        return 1;
    }

    printf("GOT段起始地址: %p\n", got_start);
    printf("GOT段大小: %zu 字节\n", got_size);
    
    // 读取并打印GOT段内容
    printf("GOT段内容:\n");
    for (size_t i = 0; i < got_size; i += sizeof(void*)) {
        void** entry = (void**)((char*)got_start + i);
        printf("  偏移0x%zx: %p\n", i, *entry);
    }

    return 0;
}

编译命令:gcc -o read_got_proc read_got_proc.c && ./read_got_proc

/proc/self/maps是实时更新的,能拿到当前进程.got段的最新映射状态,适合动态场景。

注意事项

  • 部分环境中.got段可能被命名为.got.plt,需要根据实际情况调整筛选关键词。
  • .got段默认是可读权限,直接读取内存不会有问题;如果是修改操作则需要额外处理内存权限。
  • 32位程序指针大小为4字节,循环时要替换sizeof(void*)为4;64位程序保持原样即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 01:20:09