Linux内存中加载二进制,如何在内存中执行二进制代码之linux平台

之前写了一篇关于win平台下,从内存执行二进制码的文章,所以此文主要修改自那篇。

大家可能会很好奇,我们的任意程序,不就是在内存中执行的二进制机器码吗?

不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它。

当然,这段代码也有其他用途,故而有了shell code的昵称,参考百度百科:

https://baike.baidu.com/item/shellcode/4051847?fr=aladdin

思考:

我们需要解决以下问题

二进制代码从哪里来?

c/c++中如何调用它?

这些问题,接下来,都会得到解决。

不过,我们先来看看效果。

一、执行二进制代码效果

main.c:

#include

#include

#include

typedef int(*AddFunc)(int, int);

int main()

{

// int add(int a, int b)函数64位系统下二进制码

unsigned char add_binaryCode[] = {

0x55,

0x48, 0x89, 0xe5,

0x89, 0x7d, 0xfc,

0x89, 0x75, 0xf8,

0x8b, 0x55, 0xfc,

0x8b, 0x45, 0xf8,

0x01, 0xd0,

0x5d,

0xc3

};

// 申请EXECUTE属性内存

void* execBuf = mmap(NULL, sizeof(add_binaryCode), PROT_WRITE | PROT_EXEC,MAP_ANON | MAP_PRIVATE, -1, 0);

// 拷贝二进制码

memcpy(execBuf, add_binaryCode, sizeof(add_binaryCode));

// 执行二进制码

AddFunc func = (AddFunc)execBuf;

int ret = func(1, 2);

printf("result:%d\n", ret);

// 释放内存

munmap(execBuf, sizeof(add_binaryCode));

return 0;

}

Ubuntu环境64位下编译执行

gcc main.c -o main.out

./main.out

add_binaryCode中装的是add函数二进制码,C函数形式如下:

int add(int a, int b)

{

return a + b;

}

我们不能在数组中执行二进制码,这样会报异常,故需要申请带可执行属性的内存,然后拷贝到其中,强转类型后,调用此函数。

运行结果:

c9fb714101d9068dff87d00aaa877618.png

运行结果正确,且没有报异常。

小结:

我们可以把逻辑代码封装为函数,并转换为二进制码,然后在c/c++中进行调用执行。

到此我们解决了,在c/c++中如何执行二进制码的问题。

接下来,我们来解决二进制码如何生成的问题。

二、二进制代码的生成

个人认为有2种方式生成二进制码

1.纯手写十六进制机器码

2.采用c/c++等高级语言编写程序,编译后,对其反汇编进而获得十六进制机器码

第一种,好比回到了纸带打孔编程的石器时代,需要了解x86指令集及其对应机器码,能力有限,直接放弃。

接下来,采用第二种方式,大概讲下,怎么通过自己写的函数,去提取生成的二进制码。

1. 编写add测试函数

add.c:

int add(int a, int b)

{

return a + b;

}

2. 编译,生成*.o文件

gcc -c add.c -o add.o

3. 提取add函数二进制码

objdump -j .text -d add.o

每行":"后面的十六进制数字就是机器码。如下:

290fb6c4ec440ab30dd54ce73c26f0ce.png

故,我们把这些机器码拷贝出来,放到数组中

unsigned char add_binaryCode[] = {

0x55,

0x48, 0x89, 0xe5,

0x89, 0x7d, 0xfc,

0x89, 0x75, 0xf8,

0x8b, 0x55, 0xfc,

0x8b, 0x45, 0xf8,

0x01, 0xd0,

0x5d,

0xc3

};

这些机器码就是我们add函数编译后生成的二进制码,即最终在内存中,cpu执行的机器码。我们让这个数组按照第一节中的方式,就可以在c/c++代码中进行调用执行了。

三、从文件中读取二进制码并执行

似乎本节的意义并不大,无非就是读取出来,放到buffer中,再执行罢了,主要的执行原理、二进制码生成都已经讲完了,这个就留给大家自行扩展吧。

四、总结

机器码的获取,比较关键的就是objdump这条命令。

另外执行时,比较关键的是,需要把机器码放到mmap指向的内存中去,不能在普通内存中执行。

代码地址:

https://gitee.com/bailiyang/cdemo/tree/master/C++/08ExecBinaryFromBuffer/ExecBinaryFromBuffer_linux

参考链接:

《执行机器码》

===================================================

===================================================

业余时间不定期更新一些想法、思考文章,欢迎关注,共同探讨,沉淀技术!

b1901bc27545efcaca2077a6b11480d0.png

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==            

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值