关于windows_x64_shellcode_template
windows_x64_shellcode_template简称为Wx64ST,它是一款功能强大的Shellcode模板,该模板基于C语言编写,其简单、可扩展和易于修改等特性可以帮助广大安全研究人员轻松开发适用于Windows x64的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%\System32\ntdll.dll`) // 3. `kernel32.dll` (`%windir%\System32\kernel32.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\0\0\0\0` typedef HMODULE(*LoadLibraryAFunc)(const char *); LoadLibraryAFunc pLoadLibraryA = (LoadLibraryAFunc)pGetProcAddress(kernel32Dll, (const char *)&x.text0);
项目地址
windows_x64_shellcode_template:【GitHub传送门】
参考资料
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)