打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
编写shellcode的全过程

1、很简单的一段代码,功能就是打开Windows自带的计算器程序。而我要实现的shellcode的功能就是这个。

  1. #include <windows.h>  
  2.   
  3. int main()  
  4. {  
  5.     LoadLibraryA("kernel32.dll");  
  6.   
  7.     WinExec("calc.exe", SW_SHOW);  
  8.       
  9.     return 0;  
  10. }  
 

2、将WinExec("calc.exe", SW_SHOW);改成汇编后的样子。

  1. #include <windows.h>  
  2.   
  3. int main()  
  4. {  
  5.     char str[]="calc.exe";  
  6.     char* p = str;  
  7.   
  8.     LoadLibraryA("kernel32.dll");  
  9.   
  10.     __asm  
  11.     {  
  12.         push 0;  
  13.   
  14.         mov eax,p;  
  15.         push eax;  
  16.           
  17.         mov eax,0x7c86250d;  //WinExec的地址  
  18.         call eax;  
  19.     }  
  20.   
  21.     return 0;  
  22. }  

3、在堆栈中构造字符串,经典!这招是我在书上学来的,并非本人原创 -_-。

  1. /* 
  2.  *  Author: Leng_que 
  3.  *  Date: 2009年10月12日11:02:40 
  4.  *  E-mail: leng_que@yahoo.com.cn 
  5.  *  Description: 一段通过WinExec运行calc.exe的shellcode雏形I 
  6.  *  Comment: 在WindowsXP SP3 + VC6.0环境下调试通过 
  7.  */  
  8.   
  9. #include <windows.h>  
  10.   
  11. int main()  
  12. {  
  13.     //因为WinExec这个API函数在kernel32.dll这个动态链接库里,所以要先加载它  
  14.     LoadLibraryA("kernel32.dll");  
  15.       
  16.     __asm  
  17.     {  
  18.         push ebp;  
  19.         mov ebp,esp;  
  20.           
  21.         //在堆栈中构造字符串:calc.exe  
  22.         xor eax,eax;  
  23.         push eax;  
  24.           
  25.         sub esp,08h;  
  26.         mov byte ptr [ebp-0ch],63h;  
  27.         mov byte ptr [ebp-0bh],61h;  
  28.         mov byte ptr [ebp-0ah],6Ch;  
  29.         mov byte ptr [ebp-09h],63h;  
  30.           
  31.         mov byte ptr [ebp-08h],2Eh;  
  32.         mov byte ptr [ebp-07h],65h;  
  33.         mov byte ptr [ebp-06h],78h;  
  34.         mov byte ptr [ebp-05h],65h;  
  35.           
  36.         //执行WinExec,启动计算器程序  
  37.         push 0;  
  38.           
  39.         lea eax,[ebp-0ch];  
  40.         push eax;  
  41.           
  42.         mov eax,0x7c86250d;  //WinExec的地址  
  43.         call eax;  
  44.           
  45.         //平衡堆栈  
  46.         mov esp,ebp;  
  47.         pop ebp;  
  48.     }  
  49.       
  50.     return 0;  
  51. }  

 4、具有shellcode特点的汇编代码完成了!
值得一提:在这一步我这么也得不到LoadLibrary(在原来的代码中我是写这个的)的地址,于是只好先去吃饭,在来回饭堂的校道上,我突然想到了,原来自己一时忘记,于是犯了一个低级错误,其中在Kernel32.dll里是没有LoadLibrary这个函数的,只有LoadLibraryA和LoadLibraryW,它们的区别在于传入的参数是ANSI编码的还是Unicode编码的,但是为什么我们在平时的编程中写LoadLibrary又可以正常运行呢?那是因为其实这个LoadLibrary只是一个宏而已啦,在VC6.0下选中这个LoadLibrary函数(当然,应该叫宏更准确些),然后右键->"Go To Definition"一下就知道了。

  1. /* 
  2.  *  Author: Leng_que 
  3.  *  Date: 2009年10月12日15:15:32 
  4.  *  E-mail: leng_que@yahoo.com.cn 
  5.  *  Description: 一段通过WinExec运行calc.exe的完整shellcode雏形 
  6.  *  Comment: 在WindowsXP SP3 + VC6.0环境下调试通过 
  7.  */  
  8.   
  9. #include <windows.h>  
  10.   
  11. int main()  
  12. {  
  13.     //因为WinExec这个API函数在kernel32.dll这个动态链接库里,所以要先加载它  
  14.     __asm  
  15.     {  
  16.         push ebp;  
  17.         mov ebp,esp;  
  18.           
  19.         //在堆栈中构造字符串:kernel32.dll  
  20.         xor eax,eax;  
  21.         push eax;  
  22.           
  23.         sub esp,0Ch;  
  24.         mov byte ptr [ebp-10h],6Bh;  
  25.         mov byte ptr [ebp-0Fh],65h;  
  26.         mov byte ptr [ebp-0Eh],72h;  
  27.         mov byte ptr [ebp-0Dh],6Eh;  
  28.         mov byte ptr [ebp-0Ch],65h;  
  29.         mov byte ptr [ebp-0Bh],6Ch;  
  30.         mov byte ptr [ebp-0Ah],33h;  
  31.         mov byte ptr [ebp-09h],32h;  
  32.           
  33.         mov byte ptr [ebp-08h],2Eh;  
  34.         mov byte ptr [ebp-07h],64h;  
  35.         mov byte ptr [ebp-06h],6Ch;  
  36.         mov byte ptr [ebp-05h],6Ch;  
  37.           
  38.         lea eax,[ebp-10h];  
  39.         push eax;  
  40.           
  41.         mov eax,0x7c801d7b;  //LoadLibraryA的地址  
  42.         call eax;  //相当于执行LoadLibraryA("kernel32.dll");  
  43.           
  44.         //平衡堆栈  
  45.         mov esp,ebp;  
  46.           
  47.           
  48.         //在堆栈中构造字符串:calc.exe  
  49.         xor eax,eax;  
  50.         push eax;  
  51.           
  52.         sub esp,08h;  
  53.         mov byte ptr [ebp-0Ch],63h;  
  54.         mov byte ptr [ebp-0Bh],61h;  
  55.         mov byte ptr [ebp-0Ah],6Ch;  
  56.         mov byte ptr [ebp-09h],63h;  
  57.           
  58.         mov byte ptr [ebp-08h],2Eh;  
  59.         mov byte ptr [ebp-07h],65h;  
  60.         mov byte ptr [ebp-06h],78h;  
  61.         mov byte ptr [ebp-05h],65h;  
  62.           
  63.         push 05h;  
  64.           
  65.         lea eax,[ebp-0Ch];  
  66.         push eax;  
  67.           
  68.         mov eax,0x7c86250d;  //WinExec的地址  
  69.         call eax;  //相当于执行WinExec("calc.exe", SW_SHOW);  
  70.           
  71.         //平衡堆栈  
  72.         mov esp,ebp;  
  73.         pop ebp;  
  74.     }  
  75.       
  76.     return 0;  
  77. }  

5、然后就可以在VC6.0下用Debug功能提取出机器码:

  1. 55 8B EC 33 C0 50 83 EC 0C C6  
  2. 45 F0 6B C6 45 F1 65 C6 45 F2  
  3. 72 C6 45 F3 6E C6 45 F4 65 C6  
  4. 45 F5 6C C6 45 F6 33 C6 45 F7  
  5. 32 C6 45 F8 2E C6 45 F9 64 C6  
  6. 45 FA 6C C6 45 FB 6C 8D 45 F0  
  7. 50 B8 7B 1D 80 7C FF D0 8B E5  
  8. 33 C0 50 83 EC 08 C6 45 F4 63  
  9. C6 45 F5 61 C6 45 F6 6C C6 45  
  10. F7 63 C6 45 F8 2E C6 45 F9 65  
  11. C6 45 FA 78 C6 45 FB 65 6A 05  
  12. 8D 45 F4 50 B8 0D 25 86 7C FF  
  13. D0 8B E5 5D  

6、接着实际执行一下这段shellcode,看看效果,你会发现真的打开了Windows计算器程序。

  1. //作者:冷却  
  2. //在WindowsXP SP3 + VC6.0环境下运行成功  
  3. unsigned char shellcode[] =   
  4. "/x55/x8B/xEC/x33/xC0/x50/x83/xEC/x0C/xC6/x45/xF0/x6B/xC6/x45/xF1/x65/xC6/x45"  
  5. "/xF2/x72/xC6/x45/xF3/x6E/xC6/x45/xF4/x65/xC6/x45/xF5/x6C/xC6/x45/xF6/x33/xC6"  
  6. "/x45/xF7/x32/xC6/x45/xF8/x2E/xC6/x45/xF9/x64/xC6/x45/xFA/x6C/xC6/x45/xFB/x6C"  
  7. "/x8D/x45/xF0/x50/xB8/x7B/x1D/x80/x7C/xFF/xD0/x8B/xE5/x33/xC0/x50/x83/xEC/x08"  
  8. "/xC6/x45/xF4/x63/xC6/x45/xF5/x61/xC6/x45/xF6/x6C/xC6/x45/xF7/x63/xC6/x45/xF8"  
  9. "/x2E/xC6/x45/xF9/x65/xC6/x45/xFA/x78/xC6/x45/xFB/x65/x6A/x05/x8D/x45/xF4/x50"  
  10. "/xB8/x0D/x25/x86/x7C/xFF/xD0/x8B/xE5/x5D";  
  11.   
  12. void main()  
  13. {  
  14.     __asm  
  15.     {  
  16.         lea eax,shellcode;  
  17.         jmp eax;  
  18.     }  
  19. }  

7、最后,我写了个小程序,把那些十六进制的shellcode转换为纯二进制的机器码。大家看!这就是CPU老兄眼中的代码了。感觉很神奇吧,0和1在计算机中真的很有魔力。

  1. 01010101100010111110110000110011110000000101000010000011111011000000110011000110010001011111000001101011110001100100010111110001011001011100011001000101111100100111001011000110010001011111001101101110110001100100010111110100011001011100011001000101111101010110110011000110010001011111011000110011110001100100010111110111001100101100011001000101111110000010111011000110010001011111100101100100110001100100010111111010011011001100011001000101111110110110110010001101010001011111000001010000101110000111101100011101100000000111110011111111110100001000101111100101001100111100000001010000100000111110110000001000110001100100010111110100011000111100011001000101111101010110000111000110010001011111011001101100110001100100010111110111011000111100011001000101111110000010111011000110010001011111100101100101110001100100010111111010011110001100011001000101111110110110010101101010000001011000110101000101111101000101000010111000000011010010010110000110011111001111111111010000100010111110010101011101  

 

后记:

大家所看到的在计算机里的种种五彩缤纷的一切,在CPU看来不过是0和1……

 

 

 

更新补充:

针对评论中有位朋友指出运行时会弹出错误提示框的问题,我做了修正,解决了这个问题。

下面简单说说道理吧,是这样的:直接通过jmp指令跳到指定的函数去执行,这种做法是“有去无回”的,函数运行完后无法正确的返回原来的位置继续执行,所以修正的方式就是通过call指令来调用函数,然后在函数中通过ret指令(这条指令的机器码:C3)返回,这样就OK了。(详细的还是去看看汇编方面的东东吧)

  1. //作者:冷却  
  2. //在WindowsXP SP3 + VC6.0环境下运行成功  
  3. //修正:运行后弹出错误提示框 @ 2011-5-15 11:24:16  
  4. unsigned char shellcode[] =   
  5. "/x55/x8B/xEC/x33/xC0/x50/x83/xEC/x0C/xC6/x45/xF0/x6B/xC6/x45/xF1/x65/xC6/x45"  
  6. "/xF2/x72/xC6/x45/xF3/x6E/xC6/x45/xF4/x65/xC6/x45/xF5/x6C/xC6/x45/xF6/x33/xC6"  
  7. "/x45/xF7/x32/xC6/x45/xF8/x2E/xC6/x45/xF9/x64/xC6/x45/xFA/x6C/xC6/x45/xFB/x6C"  
  8. "/x8D/x45/xF0/x50/xB8/x7B/x1D/x80/x7C/xFF/xD0/x8B/xE5/x33/xC0/x50/x83/xEC/x08"  
  9. "/xC6/x45/xF4/x63/xC6/x45/xF5/x61/xC6/x45/xF6/x6C/xC6/x45/xF7/x63/xC6/x45/xF8"  
  10. "/x2E/xC6/x45/xF9/x65/xC6/x45/xFA/x78/xC6/x45/xFB/x65/x6A/x05/x8D/x45/xF4/x50"  
  11. "/xB8/x0D/x25/x86/x7C/xFF/xD0/x8B/xE5/x5D/xC3";  
  12.   
  13. void main()  
  14. {  
  15.     __asm  
  16.     {  
  17.         lea eax,shellcode;  
  18.         call eax;  
  19.     }  
  20. }  

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Ted's Blog
通达信修改技术:暴力初步(直接免费登录高级行情)
Position Independent Code (PIC) in shared libraries
外挂专用
qq反汇编日志
[C/C++] 对C/C++可变参数表的深层探索
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服