Wx64ST:一款轻松可修改的C语言Shellcode模板

admin 2024年8月31日09:37:00评论19 views字数 8351阅读27分50秒阅读模式

Wx64ST:一款轻松可修改的C语言Shellcode模板

 

关于windows_x64_shellcode_template

windows_x64_shellcode_template简称为Wx64ST,它是一款功能强大的Shellcode模板,该模板基于C语言编写,其简单、可扩展和易于修改等特性可以帮助广大安全研究人员轻松开发适用于Windows x64的Shellcode。

 

Wx64ST:一款轻松可修改的C语言Shellcode模板

 

值得一提的是,该模板代码可以加载LoadLibraryA和GetProcAddress,并以C语言方式暴露HMODULE给kernel32.dll。

 

除此之外,模板提供的函数中包含了很多注释内容,以供广大研究人员参考。

工具要求

VS 2015 / VS 2017

工具安装

广大研究人员可以直接使用下列命令将该项目源码克隆至本地:

git clone https://github.com/rainerzufalldererste/windows_x64_shellcode_template.git
cd windows_x64_shellcode_template
git submodule update --init --recursive
create_project.bat

 

该shellcode_template项目包括开始开发自定义Shellcode的所有内容。

如何检索Shellcode

有很多方法可以检索生成的 shellcode。最简单的方法可能是直接进入Visual Studio 调试器并切换到void shellcode_template(),然后打开反汇编视图 (Ctrl+Alt+D)。请确保打开显示代码字节并关闭显示源代码和地址以简化输出:

48 89 5C 24 08       mov         qword ptr [rsp+8],rbx  
57                   push        rdi  
48 83 EC 30          sub         rsp,30h  
65 48 8B 04 25 60 00 00 00 mov         rax,qword ptr gs:[0000000000000060h]  
33 D2                xor         edx,edx  
49 B8 47 65 74 50 72 6F 63 41 mov         r8,41636F7250746547h  
48 8B 48 18          mov         rcx,qword ptr [rax+18h]  
48 8B 41 20          mov         rax,qword ptr [rcx+20h]  
48 8B 08             mov         rcx,qword ptr [rax]  
48 8B 01             mov         rax,qword ptr [rcx]  
48 8B 78 20          mov         rdi,qword ptr [rax+20h]  
48 63 47 3C          movsxd      rax,dword ptr [rdi+3Ch]  
44 8B 8C 38 88 00 00 00 mov         r9d,dword ptr [rax+rdi+0000000000000088h]  
41 8B 44 39 20       mov         eax,dword ptr [r9+rdi+20h]  
48 03 C7             add         rax,rdi  
48 63 08             movsxd      rcx,dword ptr [rax]  
4C 39 04 39          cmp         qword ptr [rcx+rdi],r8  
 ...

 

现在只需移除标签和反汇编代码即可,剩下的就是Shellcode:

48 89 5C 24 08
57
48 83 EC 30
65 48 8B 04 25 60 00 00 00
33 D2
49 B8 47 65 74 50 72 6F 63 41
48 8B 48 18
48 8B 41 20
48 8B 08
48 8B 01
48 8B 78 20
48 63 47 3C
44 8B 8C 38 88 00 00 00
41 8B 44 39 20
48 03 C7
48 63 08
4C 39 04 39
 ...

或者,您可以将代码粘贴到像godbolt.org这样的在线编译器中,然后将生成的 MSVC 程序集(不调用任何内部函数,例如缓冲区安全检查或 memcpy)(即使用x64 msvc v19.latest)复制到像https://defuse.ca/online-x86-assembler.htm/O2 /GS-这样的在线汇编程序中。然后只需复制生成的Shellcode即可。

 

当使用在线编译器时,你可能需要稍微清理一下汇编代码,如下所示:

x$ = 32
void shellcode_template(void) PROC               ; shellcode_template, COMDAT
$LN10:
        mov     QWORD PTR [rsp+8], rbx
        push    rdi
        sub     rsp, 48                             ; 00000030H
        mov     rax, QWORD PTR gs:96
        xor     edx, edx
        mov     r8, 4711732171926431047             ; 41636f7250746547H
        mov     rcx, QWORD PTR [rax+24]
        mov     rax, QWORD PTR [rcx+32]
        mov     rcx, QWORD PTR [rax]
        mov     rax, QWORD PTR [rcx]
        mov     rdi, QWORD PTR [rax+32]
        movsxd  rax, DWORD PTR [rdi+60]
        mov     r9d, DWORD PTR [rax+rdi+136]
        mov     eax, DWORD PTR [r9+rdi+32]
        add     rax, rdi
        movsxd  rcx, DWORD PTR [rax]
        cmp     QWORD PTR [rcx+rdi], r8
        je      SHORT $LN3@shellcode_
        npad    2
$LL2@shellcode_:
        movsxd  rcx, DWORD PTR [rax+4]
        lea     rax, QWORD PTR [rax+4]
        inc     edx
        cmp     QWORD PTR [rcx+rdi], r8
        jne     SHORT $LL2@shellcode_
$LN3@shellcode_:
        mov     ecx, DWORD PTR [r9+rdi+36]
        mov     rax, 8242266044863967052      ; 7262694c64616f4cH
        ...

 

可以通过一些查找和替换将代码变成这样:

shellcode_template:
        mov     qword ptr [rsp+8], rbx
        push    rdi
        sub     rsp, 48
        mov     rax, qword ptr gs:96
        xor     edx, edx
        mov     r8, 4711732171926431047
        mov     rcx, qword ptr [rax+24]
        mov     rax, qword ptr [rcx+32]
        mov     rcx, qword ptr [rax]
        mov     rax, qword ptr [rcx]
        mov     rdi, qword ptr [rax+32]
        movsxd  rax, DWORD ptr [rdi+60]
        mov     r9d, DWORD ptr [rax+rdi+136]
        mov     eax, DWORD ptr [r9+rdi+32]
        add     rax, rdi
        movsxd  rcx, DWORD ptr [rax]
        cmp     qword ptr [rcx+rdi], r8
        je      SHORT _function_found
        
        ; `npad    2` can be turned into two `nop`s.
 
        nop
        nop
 
 
_find_next_function:
        movsxd  rcx, DWORD ptr [rax+4]
        lea     rax, qword ptr [rax+4]
        inc     edx
        cmp     qword ptr [rcx+rdi], r8
        jne     SHORT _find_next_function
 
 
_function_found:
        mov     ecx, DWORD ptr [r9+rdi+36]
        mov     rax, 8242266044863967052
        ...

 

生成的Shellcode

下面给出的是该项目提供的Shellcode样例,它将执行下列操作:

1、在kernel32.dll中查找GetProcAddress;

2、从kernel32.dll检索LoadLibraryA;

3、加载useR32.dll;

4、从useR32.dll检索MessageBoxA;

5、显示一个消息提示框;

6、从kernel32.dll检索ExitProcess;

7、调用ExitProcess;

 

0x48, 0x89, 0x5C, 0x24, 0x08, 0x57, 0x48, 0x83, 0xEC, 0x30, 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60,
  0x00, 0x00, 0x00, 0x33, 0xD2, 0x49, 0xB8, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x41, 0x48,
  0x8B, 0x48, 0x18, 0x48, 0x8B, 0x41, 0x20, 0x48, 0x8B, 0x08, 0x48, 0x8B, 0x01, 0x48, 0x8B, 0x78,
  0x20, 0x48, 0x63, 0x47, 0x3C, 0x44, 0x8B, 0x8C, 0x38, 0x88, 0x00, 0x00, 0x00, 0x41, 0x8B, 0x44,
  0x39, 0x20, 0x48, 0x03, 0xC7, 0x48, 0x63, 0x08, 0x4C, 0x39, 0x04, 0x39, 0x74, 0x12, 0x66, 0x90,
  0x48, 0x63, 0x48, 0x04, 0x48, 0x8D, 0x40, 0x04, 0xFF, 0xC2, 0x4C, 0x39, 0x04, 0x39, 0x75, 0xF0,
  0x41, 0x8B, 0x4C, 0x39, 0x24, 0x48, 0xB8, 0x4C, 0x6F, 0x61, 0x64, 0x4C, 0x69, 0x62, 0x72, 0x48,
  0x03, 0xCF, 0x48, 0x63, 0xD2, 0x4C, 0x0F, 0xBF, 0x04, 0x51, 0x48, 0x8D, 0x54, 0x24, 0x20, 0x41,
  0x8B, 0x4C, 0x39, 0x1C, 0x48, 0x03, 0xCF, 0x4A, 0x63, 0x1C, 0x81, 0x48, 0x8B, 0xCF, 0x48, 0x03,
  0xDF, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xC7, 0x44, 0x24, 0x28, 0x61, 0x72, 0x79, 0x41, 0xFF,
  0xD3, 0x48, 0xB9, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x48, 0xC7, 0x44, 0x24, 0x28,
  0x6C, 0x6C, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8D, 0x4C, 0x24, 0x20, 0xFF, 0xD0,
  0x48, 0xB9, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x48, 0xC7, 0x44, 0x24, 0x28, 0x6F,
  0x78, 0x41, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8D, 0x54, 0x24, 0x20, 0x48, 0x8B, 0xC8,
  0xFF, 0xD3, 0x48, 0xB9, 0x48, 0x61, 0x73, 0x74, 0x61, 0x20, 0x6C, 0x61, 0x4C, 0x8D, 0x44, 0x24,
  0x2F, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8D, 0x54, 0x24, 0x20, 0x48, 0xB9, 0x20, 0x76, 0x69,
  0x73, 0x74, 0x61, 0x21, 0x00, 0x45, 0x33, 0xC9, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x33, 0xC9, 0xFF,
  0xD0, 0x48, 0xB8, 0x45, 0x78, 0x69, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x48, 0xC7, 0x44, 0x24, 0x28,
  0x65, 0x73, 0x73, 0x00, 0x48, 0x8D, 0x54, 0x24, 0x20, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0x8B,
  0xCF, 0xFF, 0xD3, 0xB9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0x48, 0x8B, 0x5C, 0x24, 0x40, 0x48,
  0x83, 0xC4, 0x30, 0x5F, 0xC3

 

工具使用演示

下面给出的是一个示例应用程序,演示了如何使用Wx64ST在子进程内执行生成的Shellcode:

 


// Load Process Environment Block.
  PEB *pProcessEnvironmentBlock = (PEB *)__readgsqword(0x60);
 
  // `pProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList` contains a double linked list.
  // `Flink` and `Blink` are pointers to the next and previous element.
  //
  // All Windows executables should have the following module order.
  //  1. The module of the current executable.
  //  2. `ntdll.dll` (`%windir%System32ntdll.dll`)
  //  3. `kernel32.dll` (`%windir%System32kernel32.dll`)
  //
  //  ... followed by other modules.
  //
  // In order to get the `GetProcAddress` function we need to therefore get the third item (`Flink->Flink->Flink`).
  // We use the `CONTAINING_RECORD` macro to retrieve the associated table entry.
  LDR_DATA_TABLE_ENTRY *pKernel32TableEntry = CONTAINING_RECORD(pProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList.Flink->Flink->Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
 
  // We've ended up at the base address of `kernel32.dll`.
  IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER *)pKernel32TableEntry->DllBase;
 
  // In order to get the exported functions we need to go to the NT PE header.
  IMAGE_NT_HEADERS *pNtHeader = (IMAGE_NT_HEADERS *)((size_t)pDosHeader + pDosHeader->e_lfanew);
 
  // From the NtHeader we can extract the virtual address of the export directory of this module.
  IMAGE_EXPORT_DIRECTORY *pExports = (IMAGE_EXPORT_DIRECTORY *)((size_t)pDosHeader + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
 
  // The exports directory contains both a list of function _names_ of this module and the associated _addresses_ of the functions.
  const int32_t *pNameOffsets = (const int32_t *)((size_t)pDosHeader + pExports->AddressOfNames);
  
  // We will use this struct to store strings.
  // We are using a struct to make sure strings don't end up in another section of the executable where we wouldn't be able to address them in a different process.
  struct
  {
    uint64_t text0, text1;
  } x;
 
  // We're now looking for the `GetProcAddress` function. Since there's no other function starting with `GetProcA` we'll just find that instead.
  x.text0 = 0x41636F7250746547; // `GetProcA`
 
  int32_t i = 0;
 
  // We're just extracting the first 8 bytes of the strings and compare them to `GetProcA`. We'll find it eventually.
  while (*(uint64_t *)((size_t)pDosHeader + pNameOffsets[i]) != x.text0)
    ++i;
 
  // We have found the index of `GetProcAddress`.
 
  // The entry at an index in `AddressOfNames` corresponds to an entry at the same index in `AddressOfNameOrdinals`, which resolves the index of a given name to it's corresponding entry in `AddressOfFunctions`. (DLLs can export unnamed functions, which will not be listed in `AddressOfNames`.)
  // Let's get the function name ordinal offsets and function offsets in order to retrieve the location of `GetProcAddress` in memory.
  const int16_t *pFunctionNameOrdinalOffsets = (const int16_t *)((size_t)pDosHeader + pExports->AddressOfNameOrdinals);
  const int32_t *pFunctionOffsets = (const int32_t *)((size_t)pDosHeader + pExports->AddressOfFunctions);
 
  // Now resolve the index in `pFunctionOffsets` from `pFunctionNameOrdinalOffsets` to get the address of the desired function in memory.
  typedef FARPROC(*GetProcAddressFunc)(HMODULE, const char *);
  GetProcAddressFunc pGetProcAddress = (GetProcAddressFunc)(const void *)((size_t)pDosHeader + pFunctionOffsets[pFunctionNameOrdinalOffsets[i]]);
 
  // Now that we've got `GetProcAddress`, let's use it to get `LoadLibraryA`.
 
  // A HMODULE is just a pointer to the base address of a module.
  HMODULE kernel32Dll = (HMODULE)pDosHeader;
 
  // Get `LoadLibraryA`.
  x.text0 = 0x7262694C64616F4C; // `LoadLibr`
  x.text1 = 0x0000000041797261; // `aryA����`
 
  typedef HMODULE(*LoadLibraryAFunc)(const char *);
  LoadLibraryAFunc pLoadLibraryA = (LoadLibraryAFunc)pGetProcAddress(kernel32Dll, (const char *)&x.text0);

 

项目地址

windows_x64_shellcode_template:

https://github.com/rainerzufalldererste/windows_x64_shellcode_template

 

Wx64ST:一款轻松可修改的C语言Shellcode模板
https://godbolt.org/
https://defuse.ca/online-x86-assembler.htm

 

 

 

原文始发于微信公众号(FreeBuf):Wx64ST:一款轻松可修改的C语言Shellcode模板

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月31日09:37:00
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Wx64ST:一款轻松可修改的C语言Shellcode模板https://cn-sec.com/archives/3115636.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息