内容简介:版权声明:本文为博主原创,无版权,未经博主允许可以随意转载,无需注明出处,随意修改或保持可作为原创! 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。
大公司的 程序员 不会屑于写我这些淫巧,即便他们也不一定会,也不一定懂,他们只是太关注业务,也许是真的没时间,也许真的就是不屑,觉得这太简单。但是,我的意思就是,这些东西真的太简单,如果你不懂,那真的不是一个合格的程序员。
本文写一个 解释器 ,载入一个仅包含二进制指令的文件,然后执行,这非常简单。
有两种方法可以简单的改变程序的执行流:
- 通过替换函数调用的返回地址。
这是call指令提供的功能,call指令执行时,会将下一条指令压栈,我们只需要在栈里找到这个位置,将其替换为自己的指令即可。 - 直接通过内联汇编调用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了么。
非常简单!
请注意,埃里克.雷蒙德有枪!
皮鞋湿,不会胖!但是经理的皮鞋除外。埃里克.雷蒙德也不懂皮鞋,毕竟,第一次穿。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。