https://m.toutiaocdn.com/group/6605149381450531332/?iid=44506179400&app=news_article×tamp=1537931264&group_id=6605149381450531332
这是2008年写的文章, 没有正式发表过,里面使用的环境不记得是i386Linux还是AMD64的Linux了。
其实,叫 bincode 合适一点,一些搞入侵的人会称之为shellcode,本文的目的是探索与学习,不是为了搞入侵,实用性也不强。
先实现一个简单的装载的代码,通常叫做 launcher。
#include #include #include #include #include #include static int file_size ( int fd ) { struct stat buf; if ( fd<0 )="" return="" -1;="" fstat="" (fd,&buf);="" if="" (=""><0 )="" return="" -2;="" return="" buf.st_size;="" }="" static="" int="" read_file(="" const="" char="" *filename,="" void="" *buf="" )="" {="" int="" rfd;="" size_t="" buflen="0;" rfd="open(filename,O_RDONLY,S_IRUSR|S_IWUSR);" if="" (="" -1="=rfd" )="" return="" -3;="" buflen="file_size" (="" rfd="" );="" if="" (=""><=0 )="" return="" -4;="" read(rfd,buf,buflen);="" close(rfd);="" return="" 0;="" }="" int="" (*myfunc)(char="" *str);="" 定义一个函数指针*/="" int="" main(int="" argc,char="" *argv[]="" )="" {="" myfunc="malloc(" 1024="" *="" sizeof(char*)="" );="" 申请一小段内存,把指针指向这段内存,作为缓冲区用*/="" read_file(="" './myfunc.bin',="" myfunc="" );="" 把myfunc.bin读进来*/="" int="" i="0;" i="myfunc('AABBCC');" 执行*/="" printf('i="%d\n',i);" }="">
gcc -g -o binloader binloader.c;
然后,实现 myfunc.bin
#include #include #include #include int bin_printf ( char *instr ) { char *word = 'hello '; write( 1,word, strlen(word) ); write( 1,instr, strlen(instr) ); write( 1,'\n', 1 ); return 0x0; }
代码很简单了,关键之处,在于怎么编译:
gcc -fpic -c myfunc.c;ld myfunc.o -static -o myfunc -e bin_printf -lc objcopy -R .note -R .comment -S -O binary myfunc myfunc.bin
然后执行
./binloader %./binloader hello AABBCCi=0
可见,这是很完整的一个函数调用的过程,解释下编译的几个步骤:
gcc -fpic -c myfunc.c;
-fpic 是让 gcc 生产的汇编代码是位置无关的,否则,
调用
write( 1,word, strlen(word) );
的时候,对 word 的寻址就通常无法正确。
ld myfunc.o -static -o myfunc -e bin_printf -lc
-e bin_printf
链接时,入口指定是 bin_printf
因为用到一个系统调用wrie,所以 -lc
最后就是用
objcopy -R .note -R .comment -S -O binary myfunc myfunc.bin
产生一个bin格式的文件