对象文件到二进制代码[英] Object file to binary code

本文是小编为大家收集整理的关于对象文件到二进制代码的处理方法,想解了对象文件到二进制代码的问题怎么解决?对象文件到二进制代码问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

让我们假设我有一个没有外部依赖关系的c文件,并且只有const数据部分.我想编译这个文件,然后获取二进制blob我可以在另一个程序中加载,其中函数将通过函数指针使用.

让我们举个例子,这是一个小说二进制模块,f1.c

static const unsigned char mylut[256] = {
    [0 ... 127] = 0,
    [128 ... 255] = 1,
};

void f1(unsigned char * src, unsigned char * dst, int len)
{
    while(len) {
        *dst++ = mylut[*src++];
        len--;
    }
}

我想编译它到f1.o,然后是f1.bin,并将它用这样 在prog.c

int somefunc() {
    unsigned char  * codedata;
    f1_type_ptr  f1_ptr;
    /* open f1.bin, and read it into codedata */

    /* set function pointer to beginning of loaded data */
    f1_ptr =(f1_type_ptr)codedata;

    /* call !*/
    f1_ptr(src, dst, len);
}

我假设从f1.c到f1.o涉及 - icpic来获得位置独立.我可以使用的标志或链接器脚本是什么? 从f1.o到f1.bin?

澄清:

我知道动态链接.在这种情况下,不可能动态链接.链接步骤必须是铸造func指针到加载数据,如果可以.

请假设没有操作系统支持.如果我能,我就会 用PC相关的地址写入F1.

推荐答案

首先,作为其他表示您应该考虑使用DLL左右.

表示,如果您真的想这样做,则需要替换链接器脚本.这样的东西(不是很好的测试,但我认为它有效):

ENTRY(_dummy_start)
SECTIONS
{
    _dummy_start = 0;
    _GLOBAL_OFFSET_TABLE_ = 0;
    .all : { 
        _all = .;
        LONG(f1 - _all);
        *( .text .text.* .data .data.* .rodata .rodata.* ) 
    }
}

然后编译:

$ gcc -c -fPIC test.c

链接:

$ ld -T script.ld test.o -o test.elf

并提取二进制BLOB:

$ objcopy -j .all -O binary test.elf test.bin

可能是脚本的一些解释是欢迎:

  • ENTRY(_dummy_start)只是避免了关于没有入口点的程序的警告.
  • _dummy_start = 0;定义前一行中使用的符号.该值未使用.
  • _GLOBAL_OFFSET_TABLE_ = 0;可防止另一个链接器误差.我不认为你真的需要这个符号,所以它可以定义为0.
  • .all这是将收集BLOB所有字节的部分的名称.在该样品中,它将全部将.text,.data和.rodata部分一起.如果您有一些复杂的函数,您可能需要更多,在这种情况下objdump -x test.o是您的朋友.
  • LONG(f1 - _all)不是真的需要的,但你想知道你的功能的偏移量进入斑点,不是吗?您不能假设它将在偏移0.使用这条行,BLOB中的前4个字节将是符号f1(您的函数)的偏移量.如果使用64位指针,请使用LONG更改LONG.

更新:现在是一个Quick'n'Dirty测试(它有效!):

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

typedef void (*f1_t)(char *a, char *b, int len);
f1_t f1;

int main()
{
    char *blob = (char*)valloc(4096);
    FILE *f = fopen("test.bin", "rb");
    fread(blob, 1, 4096, f);
    fclose(f);

    unsigned offs = *(unsigned*)blob;
    f1 = (f1_t)(blob + offs);
    mprotect(blob, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
    char txt[] = "¡hello world!";
    char txt2[sizeof(txt)] = "";
    f1(txt, txt2, sizeof(txt) - 1);
    printf("%s\n%s\n", txt, txt2);
    return 0;

}

其他推荐答案

您应该考虑构建一个共享库( .dll for windows,或 .so for linux).

构建如下所示:

gcc -c -fPIC test.c
gcc -shared test.o -o libtest.so

如果要从代码动态加载库,请查看功能 dlopen(3)和 dlsym(3).

或如果要在编译时间链接库,请使用

构建程序
gcc -c main.c
gcc main.o -o <binary name> -ltest

编辑:

我真的不确定在这里我会说什么,但这可能会给你一个关于你的研究进步的线索...

如果您不想使用 dlopen 和 dlsym ,您可以尝试从 .o 文件中读取符号表命令找到函数地址,然后, mmap 内存中的对象文件,具有读取和执行权限.然后,您应该能够在您找到的地址执行加载的代码.但要小心,你可以在这个代码中见到的其他依赖关系.

您可以检查man page elf(5)

其他推荐答案

使用铸造函数指针.

这是一个例子:

#include <stdio.h>

int main()
{
    unsigned char *dst, *src;
    int len;
    void (*f1)(unsigned char *, unsigned char *, int);
    *(void **)(&f1) = 0x..........;
    f1(src,dst,len);
    return 0;
}
要做任何事情,你真的需要一个链接器和动态加载器.

本文地址:https://www.itbaoku.cn/post/359389.html