用户态直接执行仅包含二进制指令的文件

栏目: 编程语言 · 发布时间: 5年前

内容简介:版权声明:本文为博主原创,无版权,未经博主允许可以随意转载,无需注明出处,随意修改或保持可作为原创! https://blog.csdn.net/dog250/article/details/89599592

版权声明:本文为博主原创,无版权,未经博主允许可以随意转载,无需注明出处,随意修改或保持可作为原创! https://blog.csdn.net/dog250/article/details/89599592

经理的皮鞋湿了,但是却没有变胖,所以经理的皮鞋是人造革的。

刚刚写了一篇文章:

不依赖OS编译器,不依赖库,用汇编/机器码直接编程: https://blog.csdn.net/dog250/article/details/89500153

展示了一个直接执行二进制指令文件的基本方案,基于 Linux 内核来执行。

值得一提的是,这不是什么特别有技术含量的东西,这只是一个基本功,我在2006年的长春吉林大学边上租住的房子里就玩过此法。那时是用VC 6。

大公司的 程序员 不会屑于写我这些淫巧,即便他们也不一定会,也不一定懂,他们只是太关注业务,也许是真的没时间,也许真的就是不屑,觉得这太简单。但是,我的意思就是,这些东西真的太简单,如果你不懂,那真的不是一个合格的程序员。

本文写一个 解释器 ,载入一个仅包含二进制指令的文件,然后执行,这非常简单。

有两种方法可以简单的改变程序的执行流:

  1. 通过替换函数调用的返回地址。
    这是call指令提供的功能,call指令执行时,会将下一条指令压栈,我们只需要在栈里找到这个位置,将其替换为自己的指令即可。
  2. 直接通过内联汇编调用jmp指令执行自己的指令。
    这个非常直接,超级简单。

首先看第一个方法,代码如下:

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

// 我们想直接执行这段指令,当然,它保存于某个文件,可以从文件里读出到code内存空间。
// char nop[] = {0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x0f, 0x05};
unsigned char *code;
void exec()
{
	unsigned long a, *p;
	// 替换返回地址,使得exec返回的时候,跳转到我们的代码。
	p = (void*)((long)&a + 24);
	*p = (unsigned long)code;
}

int main(int argc, char **argv)
{
	FILE *fp = NULL;

	fp = fopen(argv[1], "r");
	// 映射地址空间
	code = (unsigned char*)mmap(0, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0);
	//memcpy(code, nop, sizeof(nop));
	// 将指令文件内容读取到code指示的地址空间。
	fread(code, 1024, 1, fp);
	// 执行之
	exec();
	printf("end\n");
}

接下来看看直接jmp的方式,依然是一个很简单的代码:

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

// 我们想直接执行这段指令,当然,它保存于某个文件,可以从文件里读出到code内存空间。
//char nop[] = {0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x0f, 0x05};
unsigned char *code;

int main(int argc, char **argv)
{
	FILE *fp = NULL;

	fp = fopen(argv[1], "r");
	code = (unsigned char*)mmap(0, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0);
	// memcpy(code, nop, sizeof(nop));
	fread(code, 1024, 1, fp);

	asm ( "jmp %0"
          :           
          :"r"(code)
          :);

	printf("end\n");
}

将上述的代码编译成一个比如a.out的程序,将一个二进制指令文件作为参数执行之,就会看到效果了。

我来准备一个二进制指令文件,以fork炸弹为例:

.global _start
_start:
	mov     $57, %rax               # fork 炸弹
	syscall
	jmp _start

照常编译:

[root@localhost ~]# as --64 -o forkbomb.o forkbomb.s
[root@localhost myflat]# ld -melf_x86_64 -o forkbomb forkbomb.o --oformat=binary

然后将这个forkbomb作为参数执行a.out,试试看。

有人会说这样做没有内核方案直接。确实是的,毕竟我们无法直接在bash的命令提示符里输入forkbomb那般执行,但是想达到这个效果,这也不难啊。

你在命令提示符里输入的任何程序都是通过bash来执行的,我们把上述的a.out整个儿给塞进bash中不就OK了吗?在bash开始fork/exec新进程的时候,自己完成mmap,memcpy的事情,然后要么通过替换函数返回地址后主动return,要么直接内联汇编里jmp,不就OK了么。

非常简单!

请注意,埃里克.雷蒙德有枪!

用户态直接执行仅包含二进制指令的文件

皮鞋湿,不会胖!但是经理的皮鞋除外。埃里克.雷蒙德也不懂皮鞋,毕竟,第一次穿。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

图解CSS3

图解CSS3

廖伟华 / 机械工业出版社 / 2014-7-1 / CNY 79.00

本书是CSS3领域的标准性著作,由资深Web前端工程师根据CSS3的最新技术标准撰写。内容极为全面、丰富和翔实,由浅入深地讲解了CSS3新特性的语法、功能和使用技巧,涵盖选择器、边框、背景、文本、颜色、UI、动画、新型盒模型、媒体查询、响应式设计等各种模块;写作方式创新,有趣且易懂,用图解的方式来描述CSS3的每一个特性甚至每一个步骤都配有实战效果图;包含大量案例,实战性强,每个特性都有作者从实践......一起来看看 《图解CSS3》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试