大家可能会很好奇,我们的任意exe程序,不就是在内存中执行的二进制机器码吗?
不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它。
当然,这段代码也有其他用途,故而有了shell code的昵称,参考百度百科:
https://baike.baidu.com/item/shellcode/4051847?fr=aladdin
思考:
我们需要解决以下问题
这些问题,接下来,都会得到解决。
不过,我们先来看看效果。
VS2017环境,x86模式下编译执行,如下代码:
#include <iostream>
#include <windows.h>
typedef int(*AddFunc)(int, int);
int main()
unsigned char add_binaryCode_x86[] = { 0x55, 0x8b, 0xec, 0x8b, 0x45, 0x08, 0x03, 0x45, 0x0c, 0x5d, 0xc3 };
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;
我们不能在数组中执行二进制码,这样会报异常,故需要申请带可执行属性的内存,然后拷贝到其中,强转类型后,调用此函数。
运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200607173751555.png)
运行结果正确,且没有报异常。
我们可以把逻辑代码封装为函数,并转换为二进制码,然后在c/c++中进行调用执行。
到此我们解决了,在c/c++中如何执行二进制码的问题。
接下来,我们来解决二进制码如何生成的问题。
个人认为有2种方式生成二进制码
1.纯手写十六进制机器码
2.采用c/c++等高级语言编写程序,编译后,对其反汇编进而获得十六进制机器码
第一种,好比回到了纸带打孔编程的石器时代,需要了解x86指令集及其对应机器码,能力有限,直接放弃。
接下来,采用第二种方式,大概讲下,怎么通过自己写的函数,去提取生成的二进制码。
#include <iostream>
int add(int a, int b)
return a + b;
int main()
int ret = add(1 ,8);
std::cout << "result:" << ret;
return 0;
注意:编译前对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函数的二进制码。
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,即可下载。
大家可能会很好奇,我们的任意exe程序,不就是在内存中执行的二进制机器码吗?不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它。当然,这段代码也有其他用途,故而有了shell code的昵称,参考百度百科:https://baike.baidu.com/item/shellcode/4051847?fr=aladdin思考:我们需要解决以下问题二进制代码从哪里来?c/c++中如何调用它?这些问题,接下来,都会得到解决。不过,我们
原文:https://blog.csdn.net/woailincon/article/details/9415935
在Linux等系统的环境中,C语言库及其头文件都是系统的一部分,只要安装了编译工具即可以完成C语言程序的开发。这点与Windows中程序的开发有所不同,Windows中一般需要安装开发包才能进行程序开发。
C语言程序经过编译-汇编-连接,最终生成可执行程序格式。可执行程序中包含两个部分的内容:
程序主体(二进制机器代码)
在程序头中包含了供操作系统加载的信息,操作系统根据
在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。
转自:http://www.cppblog.com/returnnull/archive/2006/12/30/17021.html
typedef IMAGE_SECTION_HEADER ( * PIMAGE_SECTION_HEADERS)[ 1 ];
// 计算对齐后的大小
unsigned long
之前写了一篇关于win平台下,从内存执行二进制码的文章,所以此文主要修改自那篇。
大家可能会很好奇,我们的任意程序,不就是在内存中执行的二进制机器码吗?
不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它。
当然,这段代码也有其他用途,故而有了shell code的昵称,参考百度百科:
https://baike.baidu.com/item/shellcode/4051847?fr=aladdin
我们需要解决以下问题
二进制代码从哪里来
学习前端这门手艺,栈底到栈顶依次是:浏览器架构、Web 网络、事件循环机制、JavaScript 核心、V8 的内存管理、浏览器的渲染流程、Web 安全、CSS、React、Vue、Node、构建工具链等
06-16
图解 Google V8 学习笔记在执行代码时,V8 需要先将 JavaScript 编译成字节码,然后再解释执行字节码,或者将需要优化的字节码编译成二进制,并直接执行二进制代码。CPU执行二进制代码:下面是一段 C 代码
先通过 GCC 编译器将这段 C 代码编译成二进制文件,编译出来的机器码每一行都是一个指令,该指令可以让 CPU 执行指定的任务。助记符(mnemonic)计算机系统的硬件组织结构:
首先,在程序执行之前,需要被装进内存。内存还是一个临时存储数据的设备,之所以是临时的存储器,是因为断电之
汇编-》.o/obj 目标程序(二进制文件)
链接-》.exe可执行程序 (二进制文件)
(1) 为什么要生成汇编,而不是直接从源文件编译成机器指令(二进制代码)?
首先,汇编语言作为机器指令的助记符,调试以及优化起来都会比较方便;
其次,汇编到机器指令的过程是由硬件完成的,是一个自动过程,让硬件...
Java二进制指令代码解析
小注:去年在看《深入解析JVM》书的时候做的一些记录,同时参考了《Java虚拟机规范》。只是对指令的一些列举,加入了一些自己的理解。可以用来查询。
Java二进制指令代码解析
Java源码在运行之前都要编译成为字节码格式(如.class文件),然后由ClassLoader将字节码载入运行。在字节码文件中,指令代码只是其中的一部分,里面还记...
一个c++程序从代码到可执行文件,有四个过程,预编译,编译,汇编,链接。
预编译:展开所有头文件,宏置换,去掉注释,条件编译(对#ifend #endif判断)
编译:将代码转换为汇编代码
汇编:把汇编语言翻译成机器指令(代码段:主要包含的是程序的指令,不可写,可读,可执行。数据段:存放程序中用到的各种全局变量或者静态数据。可读可写可执行)
合并各个.obj文件,合并符号表,解析符号表是否重定义
符号地址重定位
生成.exe文件