C 将对象文件转换为二进制代码
假设我有一个没有外部依赖关系的C文件,只有const数据部分。我想编译这个文件,然后得到一个二进制blob,我可以加载到另一个程序中,通过函数指针使用函数 让我们举个例子,这是一个虚构的二进制模块f1.cC 将对象文件转换为二进制代码,c,gcc,ld,C,Gcc,Ld,假设我有一个没有外部依赖关系的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
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,然后像这样使用它
在程序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涉及到-fPIC以获得位置独立性。我可以使用哪些标志或链接器脚本
从f1.o转到f1.bin
澄清:
我知道动态链接。在这种情况下,不可能进行动态链接。如果可能的话,链接步骤必须转换为加载数据的func指针
请假定没有操作系统支持。如果可以的话,比如说,我会的
使用PC相关地址在程序集中写入f1 > P>您应该考虑构建一个共享的库(< Windows >强> > DLL<强> >或<强> .SO > 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
gcc-cmain.c
gcc main.o-o-ltest
编辑:
我真的不确定我将在这里说什么,但这可以给你一个线索,让你在你的研究进展
如果不想使用dlopen和dlsym,可以尝试从.o文件中读取符号表以查找函数地址,然后,mmap在内存中读取具有读取和执行权限的对象文件。然后,您应该能够在找到的地址执行加载的代码。但要小心处理在这段代码中可能遇到的其他依赖项
你可以检查man页面<代码>精灵(5)< /> > /p> < p>首先,正如其他人所说的,你应该考虑使用DLL等。 也就是说,如果您真的想这样做,您需要替换链接器脚本。类似这样的东西(没有经过很好的测试,但我认为它是有效的):
然后使用以下命令进行编译:$ 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(\u dummy\u start)
\u dummy\u start=0定义上一行中使用的符号的代码>。未使用该值
\u全局\u偏移量\u表\u0防止另一个链接器错误的代码>。我不认为你真的需要这个符号,所以它可以定义为0
这是将收集blob的所有字节的部分的名称。在本示例中,所有.all
、.text
和.data
部分将放在一起。如果您有复杂的函数,可能还需要一些,在本例中,.rodata
是您的朋友objdump-x test.o
实际上不需要,但是您想知道函数在blob中的偏移量,不是吗?不能假定它将位于偏移量0处。在这一行中,blob中的前4个字节将是符号LONG(f1-\u all)
(您的函数)的偏移量。如果使用64位指针,则使用f1
更改QUAD
LONG
#包括
#包括
#包括
typedef void(*f1_t)(字符*a,字符*b,整数长度);
f1_t f1;
int main()
{
char*blob=(char*)valloc(4096);
文件*f=fopen(“test.bin”、“rb”);
fread(blob,14096,f);
fclose(f);
无符号关闭=*(无符号*)blob;
f1=(f1_t)(水滴+关闭);
mprotect(blob,4096,PROT_READ | PROT_WRITE | PROT_EXEC);
char txt[]=“你好,世界!”;
char txt2[sizeof(txt)]=“”;
f1(txt,txt2,sizeof(txt)-1);
printf(“%s\n%s\n”,txt,txt2);
返回0;
}
使用强制转换函数指针
下面是一个例子:
#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;
}
#包括
int main()
{
无符号字符*dst,*src;
内伦;
void(*f1)(无符号字符*,无符号字符*,int);
*(void**)(&f1)=0x。。。。。。。。。。;
f1(src、dst、len);
返回0;
}
若要执行更多操作,您确实需要一个链接器和一个动态加载程序。您知道可以使用共享对象文件吗?将.c文件编译为.so,然后将其加载到程序中,并获取指向该函数的函数指针
dlsym()
。然后你可以调用它。让我们忘记libc和动态链接你想要动态加载f1.bin
thingie(即在运行时)?然后您必须构建一个共享库,并使用ldopen()+ldsym()或其他模块加载程序(如gmodule)。尝试其他方式很可能会很困难,并且会因为潜在的安全威胁(执行数据段等)而被拒绝。我确实不想使用动态链接,根据DLOPEN和dlsym编辑问题并不意味着动态链接(由于您的程序不会链接到库,因此二进制文件不会依赖于它,并且在编译过程中不需要库)。函数dlopen允许您加载库,dlsym将根据您提供的符号名称返回函数地址。dlsym意味着调用操作系统提供的动态链接器来分析库文件、执行映射等…\u GLOBAL\u OFFSET\u TABLE\如果引用其他符号(如标准库),则可能需要@APProgrammer:但OP明确表示没有外部依赖,因此可能不需要。如果他访问任何库,那么他必须静态链接blob中的所有库,或者自己进行动态链接……这将……非常复杂。
#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;
}
#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;
}