1、很简单的一段代码,功能就是打开Windows自带的计算器程序。而我要实现的shellcode的功能就是这个。
- #include <windows.h>
-
- int main()
- {
- LoadLibraryA("kernel32.dll");
-
- WinExec("calc.exe", SW_SHOW);
-
- return 0;
- }
2、将WinExec("calc.exe", SW_SHOW);改成汇编后的样子。
- #include <windows.h>
-
- int main()
- {
- char str[]="calc.exe";
- char* p = str;
-
- LoadLibraryA("kernel32.dll");
-
- __asm
- {
- push 0;
-
- mov eax,p;
- push eax;
-
- mov eax,0x7c86250d; //WinExec的地址
- call eax;
- }
-
- return 0;
- }
3、在堆栈中构造字符串,经典!这招是我在书上学来的,并非本人原创 -_-。
- /*
- * Author: Leng_que
- * Date: 2009年10月12日11:02:40
- * E-mail: leng_que@yahoo.com.cn
- * Description: 一段通过WinExec运行calc.exe的shellcode雏形I
- * Comment: 在WindowsXP SP3 + VC6.0环境下调试通过
- */
-
- #include <windows.h>
-
- int main()
- {
- //因为WinExec这个API函数在kernel32.dll这个动态链接库里,所以要先加载它
- LoadLibraryA("kernel32.dll");
-
- __asm
- {
- push ebp;
- mov ebp,esp;
-
- //在堆栈中构造字符串:calc.exe
- xor eax,eax;
- push eax;
-
- sub esp,08h;
- mov byte ptr [ebp-0ch],63h;
- mov byte ptr [ebp-0bh],61h;
- mov byte ptr [ebp-0ah],6Ch;
- mov byte ptr [ebp-09h],63h;
-
- mov byte ptr [ebp-08h],2Eh;
- mov byte ptr [ebp-07h],65h;
- mov byte ptr [ebp-06h],78h;
- mov byte ptr [ebp-05h],65h;
-
- //执行WinExec,启动计算器程序
- push 0;
-
- lea eax,[ebp-0ch];
- push eax;
-
- mov eax,0x7c86250d; //WinExec的地址
- call eax;
-
- //平衡堆栈
- mov esp,ebp;
- pop ebp;
- }
-
- return 0;
- }
4、具有shellcode特点的汇编代码完成了!
值得一提:在这一步我这么也得不到LoadLibrary(在原来的代码中我是写这个的)的地址,于是只好先去吃饭,在来回饭堂的校道上,我突然想到了,原来自己一时忘记,于是犯了一个低级错误,其中在Kernel32.dll里是没有LoadLibrary这个函数的,只有LoadLibraryA和LoadLibraryW,它们的区别在于传入的参数是ANSI编码的还是Unicode编码的,但是为什么我们在平时的编程中写LoadLibrary又可以正常运行呢?那是因为其实这个LoadLibrary只是一个宏而已啦,在VC6.0下选中这个LoadLibrary函数(当然,应该叫宏更准确些),然后右键->"Go To Definition"一下就知道了。
- /*
- * Author: Leng_que
- * Date: 2009年10月12日15:15:32
- * E-mail: leng_que@yahoo.com.cn
- * Description: 一段通过WinExec运行calc.exe的完整shellcode雏形
- * Comment: 在WindowsXP SP3 + VC6.0环境下调试通过
- */
-
- #include <windows.h>
-
- int main()
- {
- //因为WinExec这个API函数在kernel32.dll这个动态链接库里,所以要先加载它
- __asm
- {
- push ebp;
- mov ebp,esp;
-
- //在堆栈中构造字符串:kernel32.dll
- xor eax,eax;
- push eax;
-
- sub esp,0Ch;
- mov byte ptr [ebp-10h],6Bh;
- mov byte ptr [ebp-0Fh],65h;
- mov byte ptr [ebp-0Eh],72h;
- mov byte ptr [ebp-0Dh],6Eh;
- mov byte ptr [ebp-0Ch],65h;
- mov byte ptr [ebp-0Bh],6Ch;
- mov byte ptr [ebp-0Ah],33h;
- mov byte ptr [ebp-09h],32h;
-
- mov byte ptr [ebp-08h],2Eh;
- mov byte ptr [ebp-07h],64h;
- mov byte ptr [ebp-06h],6Ch;
- mov byte ptr [ebp-05h],6Ch;
-
- lea eax,[ebp-10h];
- push eax;
-
- mov eax,0x7c801d7b; //LoadLibraryA的地址
- call eax; //相当于执行LoadLibraryA("kernel32.dll");
-
- //平衡堆栈
- mov esp,ebp;
-
-
- //在堆栈中构造字符串:calc.exe
- xor eax,eax;
- push eax;
-
- sub esp,08h;
- mov byte ptr [ebp-0Ch],63h;
- mov byte ptr [ebp-0Bh],61h;
- mov byte ptr [ebp-0Ah],6Ch;
- mov byte ptr [ebp-09h],63h;
-
- mov byte ptr [ebp-08h],2Eh;
- mov byte ptr [ebp-07h],65h;
- mov byte ptr [ebp-06h],78h;
- mov byte ptr [ebp-05h],65h;
-
- push 05h;
-
- lea eax,[ebp-0Ch];
- push eax;
-
- mov eax,0x7c86250d; //WinExec的地址
- call eax; //相当于执行WinExec("calc.exe", SW_SHOW);
-
- //平衡堆栈
- mov esp,ebp;
- pop ebp;
- }
-
- return 0;
- }
5、然后就可以在VC6.0下用Debug功能提取出机器码:
- 55 8B EC 33 C0 50 83 EC 0C C6
- 45 F0 6B C6 45 F1 65 C6 45 F2
- 72 C6 45 F3 6E C6 45 F4 65 C6
- 45 F5 6C C6 45 F6 33 C6 45 F7
- 32 C6 45 F8 2E C6 45 F9 64 C6
- 45 FA 6C C6 45 FB 6C 8D 45 F0
- 50 B8 7B 1D 80 7C FF D0 8B E5
- 33 C0 50 83 EC 08 C6 45 F4 63
- C6 45 F5 61 C6 45 F6 6C C6 45
- F7 63 C6 45 F8 2E C6 45 F9 65
- C6 45 FA 78 C6 45 FB 65 6A 05
- 8D 45 F4 50 B8 0D 25 86 7C FF
- D0 8B E5 5D
6、接着实际执行一下这段shellcode,看看效果,你会发现真的打开了Windows计算器程序。
- //作者:冷却
- //在WindowsXP SP3 + VC6.0环境下运行成功
- unsigned char shellcode[] =
- "/x55/x8B/xEC/x33/xC0/x50/x83/xEC/x0C/xC6/x45/xF0/x6B/xC6/x45/xF1/x65/xC6/x45"
- "/xF2/x72/xC6/x45/xF3/x6E/xC6/x45/xF4/x65/xC6/x45/xF5/x6C/xC6/x45/xF6/x33/xC6"
- "/x45/xF7/x32/xC6/x45/xF8/x2E/xC6/x45/xF9/x64/xC6/x45/xFA/x6C/xC6/x45/xFB/x6C"
- "/x8D/x45/xF0/x50/xB8/x7B/x1D/x80/x7C/xFF/xD0/x8B/xE5/x33/xC0/x50/x83/xEC/x08"
- "/xC6/x45/xF4/x63/xC6/x45/xF5/x61/xC6/x45/xF6/x6C/xC6/x45/xF7/x63/xC6/x45/xF8"
- "/x2E/xC6/x45/xF9/x65/xC6/x45/xFA/x78/xC6/x45/xFB/x65/x6A/x05/x8D/x45/xF4/x50"
- "/xB8/x0D/x25/x86/x7C/xFF/xD0/x8B/xE5/x5D";
-
- void main()
- {
- __asm
- {
- lea eax,shellcode;
- jmp eax;
- }
- }
7、最后,我写了个小程序,把那些十六进制的shellcode转换为纯二进制的机器码。大家看!这就是CPU老兄眼中的代码了。感觉很神奇吧,0和1在计算机中真的很有魔力。
- 01010101100010111110110000110011110000000101000010000011111011000000110011000110010001011111000001101011110001100100010111110001011001011100011001000101111100100111001011000110010001011111001101101110110001100100010111110100011001011100011001000101111101010110110011000110010001011111011000110011110001100100010111110111001100101100011001000101111110000010111011000110010001011111100101100100110001100100010111111010011011001100011001000101111110110110110010001101010001011111000001010000101110000111101100011101100000000111110011111111110100001000101111100101001100111100000001010000100000111110110000001000110001100100010111110100011000111100011001000101111101010110000111000110010001011111011001101100110001100100010111110111011000111100011001000101111110000010111011000110010001011111100101100101110001100100010111111010011110001100011001000101111110110110010101101010000001011000110101000101111101000101000010111000000011010010010110000110011111001111111111010000100010111110010101011101
后记:
大家所看到的在计算机里的种种五彩缤纷的一切,在CPU看来不过是0和1……
更新补充:
针对评论中有位朋友指出运行时会弹出错误提示框的问题,我做了修正,解决了这个问题。
下面简单说说道理吧,是这样的:直接通过jmp指令跳到指定的函数去执行,这种做法是“有去无回”的,函数运行完后无法正确的返回原来的位置继续执行,所以修正的方式就是通过call指令来调用函数,然后在函数中通过ret指令(这条指令的机器码:C3)返回,这样就OK了。(详细的还是去看看汇编方面的东东吧)
- //作者:冷却
- //在WindowsXP SP3 + VC6.0环境下运行成功
- //修正:运行后弹出错误提示框 @ 2011-5-15 11:24:16
- unsigned char shellcode[] =
- "/x55/x8B/xEC/x33/xC0/x50/x83/xEC/x0C/xC6/x45/xF0/x6B/xC6/x45/xF1/x65/xC6/x45"
- "/xF2/x72/xC6/x45/xF3/x6E/xC6/x45/xF4/x65/xC6/x45/xF5/x6C/xC6/x45/xF6/x33/xC6"
- "/x45/xF7/x32/xC6/x45/xF8/x2E/xC6/x45/xF9/x64/xC6/x45/xFA/x6C/xC6/x45/xFB/x6C"
- "/x8D/x45/xF0/x50/xB8/x7B/x1D/x80/x7C/xFF/xD0/x8B/xE5/x33/xC0/x50/x83/xEC/x08"
- "/xC6/x45/xF4/x63/xC6/x45/xF5/x61/xC6/x45/xF6/x6C/xC6/x45/xF7/x63/xC6/x45/xF8"
- "/x2E/xC6/x45/xF9/x65/xC6/x45/xFA/x78/xC6/x45/xFB/x65/x6A/x05/x8D/x45/xF4/x50"
- "/xB8/x0D/x25/x86/x7C/xFF/xD0/x8B/xE5/x5D/xC3";
-
- void main()
- {
- __asm
- {
- lea eax,shellcode;
- call eax;
- }
- }
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。