如何在内存中执行二进制代码之win平台

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

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

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

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

思考:
我们需要解决以下问题

  • 二进制代码从哪里来?
  • c/c++中如何调用它?

这些问题,接下来,都会得到解决。
不过,我们先来看看效果。

一、执行二进制代码效果

VS2017环境,x86模式下编译执行,如下代码:

#include <iostream>
#include <windows.h>

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

int main()
{
	// int add(int a, int b)函数二进制码
	unsigned char add_binaryCode_x86[] = { 0x55, 0x8b, 0xec, 0x8b, 0x45, 0x08, 0x03, 0x45, 0x0c, 0x5d, 0xc3 };

	// 申请EXECUTE属性内存
	void* execBuf = VirtualAlloc(0, sizeof(add_binaryCode_x86), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	// 拷贝二进制码
	memcpy(execBuf, add_binaryCode_x86, sizeof(add_binaryCode_x86));

	// 执行二进制码
	AddFunc func = (AddFunc)execBuf;
	int ret = func(1, 2);
	std::cout << "result:" << ret;

	// 释放内存
	VirtualFree(execBuf, 0, MEM_RELEASE);
	return 0;
}

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

int add(int a, int b)
{
	return a + b;
}

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

运行结果:
在这里插入图片描述

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

小结:

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

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

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

二、二进制代码的生成

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

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

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

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

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

1. 编写一个测试程序

#include <iostream>

int add(int a, int b)
{
	return a + b;
}

int main()
{
	int ret = add(1 ,8);
	std::cout << "result:" << ret;
	return 0;
}

2. 进入Release模式调试,对它进行反汇编

注意:编译前对VS做如下配置

1、使用Release模式。近来编译器的Debug模式可能产生逆序的函数,并且会插入许多与位置相关的调用。

2、禁用优化。编译器会默认优化那些没有使用的函数,而那可能正是我们所需要的。

3、禁用栈缓冲区安全检查(/Gs)。在函数头尾所调用的栈检查函数,存在于二进制文件的某个特定位置,导致输出的函数不能重定位,这对shellcode是无意义的

设置步骤:

禁用优化:项目属性->配置属性->C/C+±>优化->优化,选择"已禁用 (/Od)"。
禁用栈缓冲区安全检查:项目属性->配置属性->C/C+±>所有选项->安全检查,选择"禁用安全检查 (/GS-)"。

开始调试,代码断在调用add()处

在这里插入图片描述

VS中,调试->窗口->反汇编,打开反汇编窗口。即可看到代码的反汇编结果:

在这里插入图片描述

图中call add (0B41080h)指令,表示调用add函数,0B41080h为add函数地址。另外前面2个push将实参1,8进行压栈。

我们继续F11,一步一步,进入add函数,如下:

在这里插入图片描述

可以看到00B41080为add函数二进制码开始地址;00B4108A为add函数二进制码结束地址,后面的2句汇编pop ebp和ret表示计算结果出栈和返回,虽然不在{}内,但是依然属于add函数的二进制码。

3. 提取add函数二进制码

VS中,调试->窗口->内存->内存1,打开内存窗口。并输入add函数二进制码开始地址00B41080,回车跳转到此地址,如下:

在这里插入图片描述

结合add函数结束地址00B4108A,得出00B41080至00B4108A=11个字节,如下:

在这里插入图片描述

故,我们把这11个字节拷贝出来,放到数组中

unsigned char xx[] = { 0x55, 0x8b, 0xec, 0x8b, 0x45, 0x08, 0x03, 0x45, 0x0c, 0x5d, 0xc3 };

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

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

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

四、总结与思考

上述步骤讲解的是,x86 32位程序二进制码的提取,那么x64 64位下程序二进制码,如何提取,原理与此类似,依葫芦画瓢,就不再赘述了。add函数x64二进制码如下:

unsigned char add_binaryCode_x64[] = 
	{ 0x89, 0x54, 0x24, 0x10, 0x89, 0x4c, 0x24, 0x08, 0x8b, 0x44, 0x24, 0x10, 0x8b, 0x4c, 0x24, 0x08, 0x03, 0xc8, 0x8b, 0xc1, 0xc3 };

参考链接:

《Windows Shellcode学习笔记——通过VisualStudio生成shellcode》

《c执行机器码》



若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!

同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。

本文涉及工程代码,公众号回复:08ExecBinaryFromBuffer_win,即可下载。

在这里插入图片描述

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要将字符串作为程序二进制代码执行,需要使用一些底层的编程技术,具体取决于所使用的编程语言和平台。以下是一般的步骤: 1. 将字符串转换为对应的二进制数据:首先,你需要将字符串转换为其对应的二进制表示。这可以通过编码和解码技术来实现,例如使用Base64编码或自定义的编码方案。 2. 分配内存空间:在执行二进制代码之前,你需要在内存分配足够大的空间来存储二进制数据。这可以通过调用特定的内存分配函数来实现,例如malloc()。 3. 将二进制数据复制到分配的内存空间:将转换后的二进制数据复制到先前分配的内存空间。这可以使用内存拷贝函数(例如memcpy())来完成。 4. 设置内存区域可执行权限:默认情况下,分配的内存区域可能被设置为不可执行。因此,你需要使用特定的系统调用或API来设置内存区域的可执行权限。具体的方法取决于所使用的操作系统和编程语言。 5. 转换为函数指针并执行:将分配的内存区域视为函数指针,并通过调用该指针来执行二进制代码。这可以通过将内存区域的地址转换为函数指针类型,并调用该指针来实现。 请注意,这种技术涉及到底层的编程概念和操作系统相关的功能。因此,确保你对所使用的编程语言和平台有足够的了解,并小心操作,以避免安全问题和意外的行为。此外,这种技术在大多数情况下是不推荐的,应该谨慎使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值