mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Add support for 64bits injection + hooks
This commit is contained in:
+3
-1
@@ -1,4 +1,6 @@
|
||||
from utils import *
|
||||
import k32testing
|
||||
from winobject import System, CurrentProcess
|
||||
from utils import VirtualProtected
|
||||
|
||||
system = System()
|
||||
current_process = CurrentProcess()
|
||||
|
||||
@@ -13,6 +13,8 @@ class Flag(long):
|
||||
NULL = Flag("NULL", 0)
|
||||
MAX_PATH = Flag("MAX_PATH", 260)
|
||||
ANYSIZE_ARRAY = Flag("ANYSIZE_ARRAY", 1)
|
||||
IMAGE_SIZEOF_SHORT_NAME = Flag("IMAGE_SIZEOF_SHORT_NAME", 8)
|
||||
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = Flag("IMAGE_NUMBEROF_DIRECTORY_ENTRIES", 16)
|
||||
WARMING_NOT_SAME_FLAG_FOR_WINXP = Flag("WARMING_NOT_SAME_FLAG_FOR_WINXP", 0)
|
||||
PROCESS_ALL_ACCESS = Flag("PROCESS_ALL_ACCESS", 0x001F0FFF)
|
||||
THREAD_ALL_ACCESS = Flag("THREAD_ALL_ACCESS", 0x001F03FF)
|
||||
|
||||
@@ -3,7 +3,7 @@ from ctypes import *
|
||||
from ctypes.wintypes import *
|
||||
from winstructs import *
|
||||
|
||||
functions = ['ExitProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtQuerySystemInformation', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualProtect', 'VirtualQuery', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'SetThreadContext', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource']
|
||||
functions = ['ExitProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtQuerySystemInformation', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualProtect', 'VirtualQuery', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'SetThreadContext', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion']
|
||||
|
||||
# ExitProcess(uExitCode):
|
||||
ExitProcessPrototype = WINFUNCTYPE(VOID, UINT)
|
||||
@@ -173,3 +173,15 @@ LoadResourceParams = ((1, 'hModule'), (1, 'hResInfo'))
|
||||
LockResourcePrototype = WINFUNCTYPE(LPVOID, HGLOBAL)
|
||||
LockResourceParams = ((1, 'hResData'),)
|
||||
|
||||
# GetVersionExA(lpVersionInformation):
|
||||
GetVersionExAPrototype = WINFUNCTYPE(BOOL, LPOSVERSIONINFOA)
|
||||
GetVersionExAParams = ((1, 'lpVersionInformation'),)
|
||||
|
||||
# GetVersionExW(lpVersionInformation):
|
||||
GetVersionExWPrototype = WINFUNCTYPE(BOOL, LPOSVERSIONINFOW)
|
||||
GetVersionExWParams = ((1, 'lpVersionInformation'),)
|
||||
|
||||
# GetVersion():
|
||||
GetVersionPrototype = WINFUNCTYPE(DWORD)
|
||||
GetVersionParams = ()
|
||||
|
||||
|
||||
+154
-7
@@ -18,10 +18,11 @@ CHAR = c_char
|
||||
FARPROC = PVOID
|
||||
HGLOBAL = PVOID
|
||||
HRESULT = c_long
|
||||
ULONGLONG = c_ulonglong
|
||||
PHANDLE = POINTER(HANDLE)
|
||||
VOID = DWORD
|
||||
|
||||
structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_PEB_LDR_DATA', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS', '_MEMORY_BASIC_INFORMATION', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES']
|
||||
structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_PEB_LDR_DATA', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_MEMORY_BASIC_INFORMATION', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW']
|
||||
|
||||
enums = ['_SYSTEM_INFORMATION_CLASS']
|
||||
|
||||
@@ -269,6 +270,60 @@ class _IMAGE_DATA_DIRECTORY(Structure):
|
||||
IMAGE_DATA_DIRECTORY = _IMAGE_DATA_DIRECTORY
|
||||
PIMAGE_DATA_DIRECTORY = POINTER(_IMAGE_DATA_DIRECTORY)
|
||||
|
||||
# Struct _IMAGE_SECTION_HEADER definitions
|
||||
class _IMAGE_SECTION_HEADER(Structure):
|
||||
_fields_ = [
|
||||
("Name", BYTE * IMAGE_SIZEOF_SHORT_NAME),
|
||||
("VirtualSize", DWORD),
|
||||
("VirtualAddress", DWORD),
|
||||
("SizeOfRawData", DWORD),
|
||||
("PointerToRawData", DWORD),
|
||||
("PointerToRelocations", DWORD),
|
||||
("PointerToLinenumbers", DWORD),
|
||||
("NumberOfRelocations", WORD),
|
||||
("NumberOfLinenumbers", WORD),
|
||||
("Characteristics", DWORD),
|
||||
]
|
||||
PIMAGE_SECTION_HEADER = POINTER(_IMAGE_SECTION_HEADER)
|
||||
IMAGE_SECTION_HEADER = _IMAGE_SECTION_HEADER
|
||||
|
||||
# Struct _IMAGE_OPTIONAL_HEADER64 definitions
|
||||
class _IMAGE_OPTIONAL_HEADER64(Structure):
|
||||
_fields_ = [
|
||||
("Magic", WORD),
|
||||
("MajorLinkerVersion", BYTE),
|
||||
("MinorLinkerVersion", BYTE),
|
||||
("SizeOfCode", DWORD),
|
||||
("SizeOfInitializedData", DWORD),
|
||||
("SizeOfUninitializedData", DWORD),
|
||||
("AddressOfEntryPoint", DWORD),
|
||||
("BaseOfCode", DWORD),
|
||||
("ImageBase", ULONGLONG),
|
||||
("SectionAlignment", DWORD),
|
||||
("FileAlignment", DWORD),
|
||||
("MajorOperatingSystemVersion", WORD),
|
||||
("MinorOperatingSystemVersion", WORD),
|
||||
("MajorImageVersion", WORD),
|
||||
("MinorImageVersion", WORD),
|
||||
("MajorSubsystemVersion", WORD),
|
||||
("MinorSubsystemVersion", WORD),
|
||||
("Win32VersionValue", DWORD),
|
||||
("SizeOfImage", DWORD),
|
||||
("SizeOfHeaders", DWORD),
|
||||
("CheckSum", DWORD),
|
||||
("Subsystem", WORD),
|
||||
("DllCharacteristics", WORD),
|
||||
("SizeOfStackReserve", ULONGLONG),
|
||||
("SizeOfStackCommit", ULONGLONG),
|
||||
("SizeOfHeapReserve", ULONGLONG),
|
||||
("SizeOfHeapCommit", ULONGLONG),
|
||||
("LoaderFlags", DWORD),
|
||||
("NumberOfRvaAndSizes", DWORD),
|
||||
("DataDirectory", IMAGE_DATA_DIRECTORY * IMAGE_NUMBEROF_DIRECTORY_ENTRIES),
|
||||
]
|
||||
PIMAGE_OPTIONAL_HEADER64 = POINTER(_IMAGE_OPTIONAL_HEADER64)
|
||||
IMAGE_OPTIONAL_HEADER64 = _IMAGE_OPTIONAL_HEADER64
|
||||
|
||||
# Struct _IMAGE_OPTIONAL_HEADER definitions
|
||||
class _IMAGE_OPTIONAL_HEADER(Structure):
|
||||
_fields_ = [
|
||||
@@ -302,20 +357,42 @@ class _IMAGE_OPTIONAL_HEADER(Structure):
|
||||
("SizeOfHeapCommit", DWORD),
|
||||
("LoaderFlags", DWORD),
|
||||
("NumberOfRvaAndSizes", DWORD),
|
||||
("DataDirectory", PIMAGE_DATA_DIRECTORY),
|
||||
("DataDirectory", IMAGE_DATA_DIRECTORY * IMAGE_NUMBEROF_DIRECTORY_ENTRIES),
|
||||
]
|
||||
PIMAGE_OPTIONAL_HEADER = POINTER(_IMAGE_OPTIONAL_HEADER)
|
||||
IMAGE_OPTIONAL_HEADER = _IMAGE_OPTIONAL_HEADER
|
||||
PIMAGE_OPTIONAL_HEADER32 = POINTER(_IMAGE_OPTIONAL_HEADER)
|
||||
IMAGE_OPTIONAL_HEADER32 = _IMAGE_OPTIONAL_HEADER
|
||||
|
||||
# Struct _IMAGE_NT_HEADERS64 definitions
|
||||
class _IMAGE_NT_HEADERS64(Structure):
|
||||
_fields_ = [
|
||||
("Signature", DWORD),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER64),
|
||||
]
|
||||
PIMAGE_NT_HEADERS64 = POINTER(_IMAGE_NT_HEADERS64)
|
||||
IMAGE_NT_HEADERS64 = _IMAGE_NT_HEADERS64
|
||||
|
||||
# Struct _IMAGE_NT_HEADERS definitions
|
||||
class _IMAGE_NT_HEADERS(Structure):
|
||||
_fields_ = [
|
||||
("Signature", DWORD),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER32),
|
||||
]
|
||||
PIMAGE_NT_HEADERS = POINTER(_IMAGE_NT_HEADERS)
|
||||
IMAGE_NT_HEADERS = _IMAGE_NT_HEADERS
|
||||
IMAGE_NT_HEADERS32 = _IMAGE_NT_HEADERS
|
||||
PIMAGE_NT_HEADERS32 = POINTER(_IMAGE_NT_HEADERS)
|
||||
|
||||
# Struct _IMAGE_IMPORT_DESCRIPTOR definitions
|
||||
class _IMAGE_IMPORT_DESCRIPTOR(Structure):
|
||||
_fields_ = [
|
||||
("OriginalFirstThunk", DWORD),
|
||||
("TimeDateStamp", DWORD),
|
||||
("ForwarderChain", DWORD),
|
||||
("Name", DWORD),
|
||||
("FirstThunk", DWORD),
|
||||
]
|
||||
IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR
|
||||
PIMAGE_IMPORT_DESCRIPTOR = POINTER(_IMAGE_IMPORT_DESCRIPTOR)
|
||||
|
||||
# Struct _MEMORY_BASIC_INFORMATION definitions
|
||||
class _MEMORY_BASIC_INFORMATION(Structure):
|
||||
@@ -519,3 +596,73 @@ class _TOKEN_PRIVILEGES(Structure):
|
||||
TOKEN_PRIVILEGES = _TOKEN_PRIVILEGES
|
||||
PTOKEN_PRIVILEGES = POINTER(_TOKEN_PRIVILEGES)
|
||||
|
||||
# Struct _OSVERSIONINFOA definitions
|
||||
class _OSVERSIONINFOA(Structure):
|
||||
_fields_ = [
|
||||
("dwOSVersionInfoSize", DWORD),
|
||||
("dwMajorVersion", DWORD),
|
||||
("dwMinorVersion", DWORD),
|
||||
("dwBuildNumber", DWORD),
|
||||
("dwPlatformId", DWORD),
|
||||
("szCSDVersion", CHAR * 128),
|
||||
]
|
||||
POSVERSIONINFOA = POINTER(_OSVERSIONINFOA)
|
||||
OSVERSIONINFOA = _OSVERSIONINFOA
|
||||
LPOSVERSIONINFOA = POINTER(_OSVERSIONINFOA)
|
||||
|
||||
# Struct _OSVERSIONINFOW definitions
|
||||
class _OSVERSIONINFOW(Structure):
|
||||
_fields_ = [
|
||||
("dwOSVersionInfoSize", DWORD),
|
||||
("dwMajorVersion", DWORD),
|
||||
("dwMinorVersion", DWORD),
|
||||
("dwBuildNumber", DWORD),
|
||||
("dwPlatformId", DWORD),
|
||||
("szCSDVersion", WCHAR * 128),
|
||||
]
|
||||
RTL_OSVERSIONINFOW = _OSVERSIONINFOW
|
||||
PRTL_OSVERSIONINFOW = POINTER(_OSVERSIONINFOW)
|
||||
LPOSVERSIONINFOW = POINTER(_OSVERSIONINFOW)
|
||||
POSVERSIONINFOW = POINTER(_OSVERSIONINFOW)
|
||||
OSVERSIONINFOW = _OSVERSIONINFOW
|
||||
|
||||
# Struct _OSVERSIONINFOEXA definitions
|
||||
class _OSVERSIONINFOEXA(Structure):
|
||||
_fields_ = [
|
||||
("dwOSVersionInfoSize", DWORD),
|
||||
("dwMajorVersion", DWORD),
|
||||
("dwMinorVersion", DWORD),
|
||||
("dwBuildNumber", DWORD),
|
||||
("dwPlatformId", DWORD),
|
||||
("szCSDVersion", CHAR * 128),
|
||||
("wServicePackMajor", WORD),
|
||||
("wServicePackMinor", WORD),
|
||||
("wSuiteMask", WORD),
|
||||
("wProductType", BYTE),
|
||||
("wReserved", BYTE),
|
||||
]
|
||||
OSVERSIONINFOEXA = _OSVERSIONINFOEXA
|
||||
POSVERSIONINFOEXA = POINTER(_OSVERSIONINFOEXA)
|
||||
LPOSVERSIONINFOEXA = POINTER(_OSVERSIONINFOEXA)
|
||||
|
||||
# Struct _OSVERSIONINFOEXW definitions
|
||||
class _OSVERSIONINFOEXW(Structure):
|
||||
_fields_ = [
|
||||
("dwOSVersionInfoSize", DWORD),
|
||||
("dwMajorVersion", DWORD),
|
||||
("dwMinorVersion", DWORD),
|
||||
("dwBuildNumber", DWORD),
|
||||
("dwPlatformId", DWORD),
|
||||
("szCSDVersion", WCHAR * 128),
|
||||
("wServicePackMajor", WORD),
|
||||
("wServicePackMinor", WORD),
|
||||
("wSuiteMask", WORD),
|
||||
("wProductType", BYTE),
|
||||
("wReserved", BYTE),
|
||||
]
|
||||
PRTL_OSVERSIONINFOEXW = POINTER(_OSVERSIONINFOEXW)
|
||||
LPOSVERSIONINFOEXW = POINTER(_OSVERSIONINFOEXW)
|
||||
OSVERSIONINFOEXW = _OSVERSIONINFOEXW
|
||||
POSVERSIONINFOEXW = POINTER(_OSVERSIONINFOEXW)
|
||||
RTL_OSVERSIONINFOEXW = _OSVERSIONINFOEXW
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@ import native_exec
|
||||
import ctypes
|
||||
import windows.generated_def.winfuncs as winfuncs
|
||||
import windows.generated_def.windef as windef
|
||||
from windows.generated_def.winstructs import *
|
||||
|
||||
DWORD = ctypes.wintypes.DWORD
|
||||
HANDLE = ctypes.wintypes.HANDLE
|
||||
|
||||
class Callback(object):
|
||||
def __init__(self, *types):
|
||||
@@ -37,6 +36,7 @@ for func in winfuncs.functions:
|
||||
CallBackDeclaration.__name__ = callback_name
|
||||
add_callback_to_module(CallBackDeclaration())
|
||||
|
||||
|
||||
|
||||
class IATHook(object):
|
||||
|
||||
@@ -55,7 +55,6 @@ class IATHook(object):
|
||||
self.realfunction = ctypes.WINFUNCTYPE(*types)(IAT_entry.nonhookvalue)
|
||||
self.is_enable = False
|
||||
|
||||
|
||||
def transform_arguments(self, types):
|
||||
res = []
|
||||
for type in types:
|
||||
@@ -66,12 +65,12 @@ class IATHook(object):
|
||||
return res
|
||||
|
||||
def enable(self):
|
||||
with utils.VirtualProtected(self.entry.addr, 0x4, windef.PAGE_EXECUTE_READWRITE):
|
||||
with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), windef.PAGE_EXECUTE_READWRITE):
|
||||
self.entry.value = self.stub
|
||||
self.is_enable = True
|
||||
|
||||
def disable(self):
|
||||
with utils.VirtualProtected(self.entry.addr, 0x4, windef.PAGE_EXECUTE_READWRITE):
|
||||
with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), windef.PAGE_EXECUTE_READWRITE):
|
||||
self.entry.value = self.entry.nonhookvalue
|
||||
self.is_enable = False
|
||||
|
||||
@@ -85,6 +84,7 @@ class IATHook(object):
|
||||
adapted_args.append(ctypes.c_char_p((value)))
|
||||
else:
|
||||
adapted_args.append(value)
|
||||
|
||||
def real_function(*args):
|
||||
if args == ():
|
||||
args = adapted_args
|
||||
|
||||
+70
-33
@@ -1,35 +1,88 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
import utils
|
||||
from native_exec.simple_x86 import *
|
||||
import windows
|
||||
|
||||
|
||||
RPython = os.getcwd() + r'\..\RPython'
|
||||
sys.path.append(RPython)
|
||||
#import master
|
||||
|
||||
def generate_python_exec_shellcode(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR):
|
||||
# 32 to 32 injection
|
||||
def generate_python_exec_shellcode_32(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR):
|
||||
from native_exec.simple_x86 import *
|
||||
LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA')
|
||||
GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress')
|
||||
code = MultipleInstr()
|
||||
# Load python27.dll
|
||||
code += Push_X(PYDLL_addr)
|
||||
code += Mov_EAX_X(LoadLibraryA)
|
||||
code += Call_EAX()
|
||||
# Get PyInit function into pythondll
|
||||
code += Push_EAX()
|
||||
code += Pop_EDI()
|
||||
code += Push_X(PyInit)
|
||||
code += Push_EDI()
|
||||
code += Mov_EBX_X(GetProcAddress)
|
||||
code += Call_EBX()
|
||||
# Call PyInit
|
||||
code += Call_EAX()
|
||||
# Get PyRun function into pythondll
|
||||
code += Push_X(PyRun)
|
||||
code += Push_EDI()
|
||||
code += Call_EBX()
|
||||
# Call PyInit with python code to exec
|
||||
code += Push_X(PYCODE_ADDR)
|
||||
code += Call_EAX()
|
||||
code += Int3()
|
||||
code += Pop_EDI()
|
||||
code += Ret()
|
||||
return code.get_code()
|
||||
|
||||
# 64 to 64 injection
|
||||
def generate_python_exec_shellcode_64(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR):
|
||||
from native_exec.simple_x64 import *
|
||||
LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA')
|
||||
GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress')
|
||||
|
||||
Reserve_space_for_call = MultipleInstr([Push_RDI()] * 4)
|
||||
Clean_space_for_call = MultipleInstr([Pop_RDI()] * 4)
|
||||
|
||||
code = MultipleInstr()
|
||||
# Do stack alignement
|
||||
code += Push_RAX()
|
||||
# Load python27.dll
|
||||
code += Mov_RCX_X(PYDLL_addr)
|
||||
code += Mov_RAX_X(LoadLibraryA)
|
||||
code += Reserve_space_for_call
|
||||
code += Call_RAX()
|
||||
code += Clean_space_for_call
|
||||
code += Push_RAX()
|
||||
code += Pop_RCX()
|
||||
# Save RCX
|
||||
code += Push_RCX()
|
||||
# Align stack
|
||||
code += Push_RDI()
|
||||
# Get PyInit function into pythondll
|
||||
code += Reserve_space_for_call
|
||||
code += Mov_RDX_X(PyInit)
|
||||
code += Mov_RBX_X(GetProcAddress)
|
||||
code += Call_RBX()
|
||||
# Call PyInit
|
||||
code += Call_RAX()
|
||||
code += Clean_space_for_call
|
||||
# Remove Stack align
|
||||
code += Pop_RDI()
|
||||
# Restore pythondll base into rcx
|
||||
code += Pop_RCX()
|
||||
# Get PyRun function into pythondll
|
||||
code += Mov_RDX_X(PyRun)
|
||||
code += Reserve_space_for_call
|
||||
code += Call_RBX()
|
||||
# Call PyInit with python code to exec
|
||||
code += Mov_RCX_X(PYCODE_ADDR)
|
||||
code += Call_RAX()
|
||||
code += Clean_space_for_call
|
||||
# Remove stack alignement
|
||||
code += Pop_RAX()
|
||||
code += Ret()
|
||||
return code.get_code()
|
||||
|
||||
|
||||
def inject_python_command(process, code_injected, PYDLL="python27.dll\x00"):
|
||||
PyInitT = "Py_Initialize\x00"
|
||||
@@ -57,36 +110,20 @@ def inject_python_command(process, code_injected, PYDLL="python27.dll\x00"):
|
||||
|
||||
|
||||
SHELLCODE_ADDR = remote_addr
|
||||
shellcode = generate_python_exec_shellcode(PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR)
|
||||
if process.bitness == 32:
|
||||
shellcode = generate_python_exec_shellcode_32(PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR)
|
||||
else:
|
||||
shellcode = generate_python_exec_shellcode_64(PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR)
|
||||
process.write_memory(SHELLCODE_ADDR, shellcode)
|
||||
return SHELLCODE_ADDR
|
||||
|
||||
|
||||
|
||||
def execute_python_code(process, code):
|
||||
print("me = {0}".format(windows.current_process.bitness))
|
||||
print("him = {0}".format(process.bitness))
|
||||
if windows.current_process.bitness != process.bitness:
|
||||
raise NotImplementedError("Cannot perform 32 <-> 64 injection")
|
||||
shellcode_remote_addr = inject_python_command(process, code)
|
||||
return process.create_thread(shellcode_remote_addr, 0)
|
||||
|
||||
remote_slave_launcher = """
|
||||
import sys
|
||||
import ctypes
|
||||
|
||||
sys.path.append(r'{0}')
|
||||
import slave
|
||||
|
||||
sys.path.append(r'{1}')
|
||||
import windows
|
||||
|
||||
name_pool = {{'ctypes' : ctypes, '__import__' : __import__, 'windows' : windows}}
|
||||
s = slave.RemotePythonSlave.create(name_pool)
|
||||
slave.debug_run(s)
|
||||
""".format(RPython, os.getcwd())
|
||||
|
||||
|
||||
def launch_remote_slave(process):
|
||||
import master
|
||||
execute_python_code(process, remote_slave_launcher)
|
||||
m = master.RemotePython.create()
|
||||
return m
|
||||
|
||||
|
||||
|
||||
+10
-3
@@ -62,14 +62,17 @@ class ApiProxy(object):
|
||||
doc = doc if doc else ""
|
||||
python_proxy.__doc__ = doc + "\nErrcheck:\n " + self.error_check.__doc__
|
||||
params_name = [param[1] for param in params]
|
||||
def check_arguments(*args):
|
||||
def perform_call(*args):
|
||||
if len(params_name) != len(args):
|
||||
print("ERROR:")
|
||||
print("Expected params: {0}".format(params_name))
|
||||
print("Just Got params: {0}".format(args))
|
||||
raise ValueError("I do not have all parameters: how is that possible ?")
|
||||
for param_name, param_value in zip(params_name, args):
|
||||
if param_value is NeededParameter:
|
||||
raise TypeError("{0}: Missing Mandatory parameter <{1}>".format(self.func_name, param_name))
|
||||
return c_prototyped(*args)
|
||||
setattr(python_proxy, "ctypes_function", check_arguments)
|
||||
setattr(python_proxy, "ctypes_function", perform_call)
|
||||
return python_proxy
|
||||
|
||||
class Kernel32Proxy(ApiProxy):
|
||||
@@ -123,6 +126,10 @@ GetCurrentProcess = TransparentKernel32Proxy("GetCurrentProcess")
|
||||
def VirtualAlloc(lpAddress=0, dwSize=NeededParameter, flAllocationType=MEM_COMMIT, flProtect=PAGE_EXECUTE_READWRITE):
|
||||
return VirtualAlloc.ctypes_function(lpAddress, dwSize, flAllocationType, flProtect)
|
||||
|
||||
@Kernel32Proxy("VirtualAllocEx")
|
||||
def VirtualAllocEx(hProcess, lpAddress=0, dwSize=NeededParameter, flAllocationType=MEM_COMMIT, flProtect=PAGE_EXECUTE_READWRITE):
|
||||
return VirtualAllocEx.ctypes_function(hProcess, lpAddress, dwSize, flAllocationType, flProtect)
|
||||
|
||||
@Kernel32Proxy("CreateRemoteThread")
|
||||
def CreateRemoteThread(hProcess=NeededParameter, lpThreadAttributes=None, dwStackSize=0,
|
||||
lpStartAddress=NeededParameter, lpParameter=NeededParameter, dwCreationFlags=0, lpThreadId=None):
|
||||
@@ -193,7 +200,7 @@ def WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize=None, lpNumberOf
|
||||
"""Computer nSize with len(lpBuffer) if not given"""
|
||||
if nSize is None:
|
||||
nSize = len(lpBuffer)
|
||||
return WriteProcessMemory.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead)
|
||||
return WriteProcessMemory.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten)
|
||||
|
||||
@Kernel32Proxy("CreateToolhelp32Snapshot")
|
||||
def CreateToolhelp32Snapshot(dwFlags, th32ProcessID=0):
|
||||
|
||||
+135
-12
@@ -2,6 +2,9 @@ import ctypes
|
||||
import mmap
|
||||
import platform
|
||||
|
||||
import windows
|
||||
import windows.k32testing as k32api
|
||||
|
||||
class PyObj(ctypes.Structure):
|
||||
_fields_ = [("ob_refcnt", ctypes.c_size_t),
|
||||
("ob_type", ctypes.c_void_p)] #must be cast
|
||||
@@ -36,7 +39,7 @@ class Win32MyMap(MyMap):
|
||||
#access = mmap.ACCESS_READ | mmap.ACCESS_WRITE
|
||||
#return cls(-1, size, access=access)
|
||||
access = mmap.ACCESS_READ | mmap.ACCESS_WRITE
|
||||
addr = ctypes.windll.kernel32.VirtualAlloc(0, size, 0x1000, 0x40)
|
||||
addr = k32api.VirtualAlloc(0, size, 0x1000, 0x40)
|
||||
|
||||
new_map = (ctypes.c_char * size).from_address(addr)
|
||||
new_map.addr = addr
|
||||
@@ -95,15 +98,13 @@ allocator = CustomAllocator()
|
||||
|
||||
|
||||
def get_functions():
|
||||
# Windows only with python27.dll | improve this
|
||||
# Windows only with python27.dll | improve this ?
|
||||
import sys
|
||||
|
||||
sys.path.append(r"C:\Users\hakril\Documents\Work\Python_Injection")
|
||||
|
||||
import windows
|
||||
PyGILState_Ensure = windows.get_func_addr('python27', 'PyGILState_Ensure')
|
||||
PyObject_CallObject = windows.get_func_addr('python27', 'PyObject_CallObject')
|
||||
PyGILState_Release = windows.get_func_addr('python27', 'PyGILState_Release')
|
||||
|
||||
PyGILState_Ensure = windows.utils.get_func_addr('python27', 'PyGILState_Ensure')
|
||||
PyObject_CallObject = windows.utils.get_func_addr('python27', 'PyObject_CallObject')
|
||||
PyGILState_Release = windows.utils.get_func_addr('python27', 'PyGILState_Release')
|
||||
return [PyGILState_Ensure, PyObject_CallObject, PyGILState_Release]
|
||||
|
||||
def analyse_callback(callback):
|
||||
@@ -114,16 +115,17 @@ def analyse_callback(callback):
|
||||
raise ValueError("Need a ctypes PyCFuncPtr")
|
||||
return obj_id
|
||||
|
||||
from simple_x86 import *
|
||||
|
||||
|
||||
# For windows 32 bits with stdcall
|
||||
def generate_stub(callback):
|
||||
from simple_x86 import *
|
||||
obj_id = analyse_callback(callback)
|
||||
|
||||
c_callback = ctypes.c_ulong.from_address(id(callback._objects['0']) + 0xc).value
|
||||
c_callback = ctypes.c_ulong.from_address(id(callback._objects['0']) + 3 * ctypes.sizeof(ctypes.c_void_p)).value
|
||||
gstate_save_addr = allocator.reserve_int()
|
||||
return_addr_save_addr = allocator.reserve_int()
|
||||
|
||||
|
||||
save_ebx = allocator.reserve_int()
|
||||
save_ecx = allocator.reserve_int()
|
||||
save_edx = allocator.reserve_int()
|
||||
@@ -155,6 +157,7 @@ def generate_stub(callback):
|
||||
code += Mov_EAX_X(c_callback)
|
||||
code += Call_EAX()
|
||||
|
||||
# TODO : Remove this and setup callback as WinFuncType
|
||||
for i in range(len(callback.argtypes)):
|
||||
code += Pop_EBX()
|
||||
|
||||
@@ -181,12 +184,132 @@ def generate_stub(callback):
|
||||
code += Mov_EDI_DX(save_edi)
|
||||
code += Ret()
|
||||
return code
|
||||
|
||||
# For windows 32 bits with stdcall
|
||||
def generate_stub_64(callback):
|
||||
from simple_x64 import *
|
||||
obj_id = analyse_callback(callback)
|
||||
|
||||
c_callback = ctypes.c_ulong.from_address(id(callback._objects['0']) + 3 * ctypes.sizeof(ctypes.c_void_p)).value
|
||||
gstate_save_addr = allocator.reserve_int()
|
||||
return_addr_save_addr = allocator.reserve_int()
|
||||
|
||||
Reserve_space_for_call = MultipleInstr([Push_RDI()] * 4)
|
||||
Clean_space_for_call = MultipleInstr([Pop_RDI()] * 4)
|
||||
|
||||
save_rbx = allocator.reserve_int()
|
||||
save_rcx = allocator.reserve_int()
|
||||
save_rdx = allocator.reserve_int()
|
||||
save_rsi = allocator.reserve_int()
|
||||
save_rdi = allocator.reserve_int()
|
||||
|
||||
ensure, objcall, release = get_functions()
|
||||
print("save_rbx = {0}".format(hex(save_rbx)))
|
||||
|
||||
### Shellcode ###
|
||||
code = MultipleInstr()
|
||||
|
||||
code += Mov_RAX_X(save_rbx)
|
||||
code += Mov_DRAX_RBX()
|
||||
|
||||
code += Mov_RAX_X(save_rcx)
|
||||
code += Mov_DRAX_RCX()
|
||||
|
||||
code += Mov_RAX_X(save_rdx)
|
||||
code += Mov_DRAX_RDX()
|
||||
|
||||
code += Mov_RAX_X(save_rsi)
|
||||
code += Mov_DRAX_RSI()
|
||||
|
||||
code += Mov_RAX_X(save_rdi)
|
||||
code += Mov_DRAX_RDI()
|
||||
|
||||
# need to save other registers ?
|
||||
|
||||
code += Mov_RAX_X(ensure)
|
||||
code += Reserve_space_for_call
|
||||
code += Call_RAX()
|
||||
code += Clean_space_for_call
|
||||
code += Mov_DX_RAX(gstate_save_addr)
|
||||
#Save real return addr (for good argument parsing by the callback)
|
||||
code += Pop_RAX()
|
||||
code += Mov_DX_RAX(return_addr_save_addr)
|
||||
# Restore parameters for real function call
|
||||
code += Mov_RAX_X(save_rbx)
|
||||
code += Mov_RBX_DRAX()
|
||||
code += Mov_RAX_X(save_rcx)
|
||||
code += Mov_RCX_DRAX()
|
||||
code += Mov_RAX_X(save_rdx)
|
||||
code += Mov_RDX_DRAX()
|
||||
code += Mov_RAX_X(save_rsi)
|
||||
code += Mov_RSI_DRAX()
|
||||
code += Mov_RAX_X(save_rdi)
|
||||
code += Mov_DRAX_RDI()
|
||||
code += Reserve_space_for_call
|
||||
# Call python code
|
||||
code += Mov_RAX_X(c_callback)
|
||||
code += Clean_space_for_call
|
||||
code += Call_RAX()
|
||||
code += Mov_RAX_DX(return_addr_save_addr)
|
||||
code += Push_RAX()
|
||||
code += Mov_RAX_X(release)
|
||||
code += Reserve_space_for_call
|
||||
code += Call_RAX()
|
||||
code += Clean_space_for_call
|
||||
# Restore registers
|
||||
code += Mov_RAX_X(save_rbx)
|
||||
code += Mov_RBX_DRAX()
|
||||
code += Mov_RAX_X(save_rcx)
|
||||
code += Mov_RCX_DRAX()
|
||||
code += Mov_RAX_X(save_rdx)
|
||||
code += Mov_RDX_DRAX()
|
||||
code += Mov_RAX_X(save_rsi)
|
||||
code += Mov_RSI_DRAX()
|
||||
code += Mov_RAX_X(save_rdi)
|
||||
code += Mov_DRAX_RDI()
|
||||
code += Ret()
|
||||
|
||||
|
||||
###### CODE 32 %%%%%%%%
|
||||
#
|
||||
##Save real return addr (for good argument parsing by the callback)
|
||||
#
|
||||
## TODO : Remove this and setup callback as WinFuncType
|
||||
#for i in range(len(callback.argtypes)):
|
||||
# code += Pop_EBX()
|
||||
#
|
||||
## Restore real return value
|
||||
#code += Mov_EBX_DX(return_addr_save_addr)
|
||||
#code += Push_EBX()
|
||||
#
|
||||
## Save return value
|
||||
#code += Push_EAX()
|
||||
#code += Mov_EBX_DX(gstate_save_addr)
|
||||
#code += Push_EBX()
|
||||
#
|
||||
#code += Mov_EAX_X(release)
|
||||
#code += Call_EAX()
|
||||
#
|
||||
## Discard `release` argument
|
||||
#code += Pop_EAX()
|
||||
## Restore return value
|
||||
#code += Pop_EAX()
|
||||
#code += Mov_EBX_DX(save_ebx)
|
||||
#code += Mov_ECX_DX(save_ecx)
|
||||
#code += Mov_EDX_DX(save_edx)
|
||||
#code += Mov_ESI_DX(save_esi)
|
||||
#code += Mov_EDI_DX(save_edi)
|
||||
#code += Ret()
|
||||
return code
|
||||
|
||||
|
||||
def generate_callback_stub(callback, types):
|
||||
func_type = ctypes.CFUNCTYPE(*types)
|
||||
c_callable = func_type(callback)
|
||||
stub = generate_stub(c_callable)
|
||||
if windows.current_process.bitness == 32:
|
||||
stub = generate_stub(c_callable)
|
||||
else:
|
||||
stub = generate_stub_64(c_callable)
|
||||
stub_addr = allocator.write_code(stub.get_code())
|
||||
generate_callback_stub.l.append((stub, c_callable))
|
||||
return stub_addr
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import struct
|
||||
import sys
|
||||
# This code should really be rewritten..
|
||||
|
||||
this_module = sys.modules[__name__]
|
||||
|
||||
@@ -164,10 +165,48 @@ class Mov_DX_Reg(object):
|
||||
|
||||
generate_reg_modr(Mov_DX_Reg)
|
||||
|
||||
def generate_reg_indirect_modr_byte(reg_dst_bits, reg_src_bits):
|
||||
# reg, [reg] or [reg], reg
|
||||
return "00{0}{1}".format(reg_dst_bits, reg_src_bits)
|
||||
|
||||
def generate_reg_reg_deref(instr_cls, src_first=True):
|
||||
"generate the Mov_Reg_DReg and Mov_DReg_Reg"
|
||||
for reg_src_name, reg_src_bits in reg_opcode.items():
|
||||
for reg_dst_name, reg_dst_bits in reg_opcode.items():
|
||||
if reg_dst_name in ("EBP", "ESP") or reg_src_name in ("EBP", "ESP"):
|
||||
# Not same encoding -> Not implemented
|
||||
continue
|
||||
class Reg_DReg_instruction(X86Instruction):
|
||||
mnemo = instr_cls.mnemo.format(reg_dst_name, reg_src_name)
|
||||
name = instr_cls.name.format(reg_dst_name, reg_src_name)
|
||||
if src_first:
|
||||
modr_code = generate_reg_indirect_modr_byte(reg_src_bits, reg_dst_bits)
|
||||
else:
|
||||
modr_code = generate_reg_indirect_modr_byte(reg_dst_bits, reg_src_bits)
|
||||
code = instr_cls.instruction_bits + chr(int(modr_code, 2)).encode("hex")
|
||||
Reg_DReg_instruction.__name__ = Reg_DReg_instruction.name
|
||||
add_instruction(Reg_DReg_instruction.__name__, Reg_DReg_instruction)
|
||||
|
||||
|
||||
class Mov_Reg_DReg(object):
|
||||
name = 'Mov_{0}_D{1}'
|
||||
mnemo = 'mov [{0}], {1}'
|
||||
instruction_bits = '8B'
|
||||
|
||||
generate_reg_reg_deref(Mov_Reg_DReg, False)
|
||||
|
||||
class Mov_DReg_Reg(object):
|
||||
name = 'Mov_D{0}_{1}'
|
||||
mnemo = 'mov {0}, [{1}]'
|
||||
instruction_bits = '89'
|
||||
|
||||
generate_reg_reg_deref(Mov_DReg_Reg, True)
|
||||
|
||||
|
||||
def generate_reg_reg_modr_byte(reg_dst_bits, reg_src_bits):
|
||||
# reg, reg
|
||||
return "11{0}{1}".format(reg_src_bits, reg_dst_bits)
|
||||
|
||||
|
||||
def generate_reg_reg_modr(instr_cls):
|
||||
for reg_src_name, reg_src_bits in reg_opcode.items():
|
||||
@@ -209,13 +248,18 @@ class JNZ(OneBindX86Instruction):
|
||||
|
||||
def get_code(self):
|
||||
return super(JNZ, self).get_code() + self.instr_block.get_code()
|
||||
|
||||
|
||||
|
||||
class MultipleInstr(object):
|
||||
|
||||
def __init__(self):
|
||||
self.instrs = []
|
||||
def __init__(self, init_instrs=()):
|
||||
self.instrs = list(init_instrs)
|
||||
|
||||
def __iadd__(self, value):
|
||||
if type(value) == MultipleInstr:
|
||||
self.instrs.extend(value.instrs)
|
||||
return self
|
||||
self.instrs.append(value)
|
||||
return self
|
||||
|
||||
|
||||
+175
-282
@@ -1,200 +1,27 @@
|
||||
import ctypes
|
||||
from generated_def.winstructs import BYTE, WORD, DWORD, PVOID, CHAR
|
||||
|
||||
import windows
|
||||
|
||||
from generated_def.winstructs import *
|
||||
|
||||
# This must go to windefs
|
||||
IMAGE_DIRECTORY_ENTRY_EXPORT = 0
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT = 1
|
||||
|
||||
|
||||
IMAGE_ORDINAL_FLAG32 = 0x80000000
|
||||
IMAGE_ORDINAL_FLAG64 = 0x8000000000000000
|
||||
|
||||
|
||||
def RedefineCtypesStruct(struct, replacement):
|
||||
class NewStruct(ctypes.Structure):
|
||||
_fields_ = transform_ctypes_fields(struct, replacement_)
|
||||
NewStruct.__name__ = struct.__name__
|
||||
return NewStruct
|
||||
|
||||
def transform_ctypes_fields(struct, replacement):
|
||||
return [(name, replacement.get(name, type)) for name, type in struct._fields_]
|
||||
|
||||
def PEFile(baseaddr):
|
||||
|
||||
class PEFile(object):
|
||||
def __init__(self):
|
||||
self.baseaddr = baseaddr
|
||||
|
||||
def get_DOS_HEADER(self):
|
||||
return IMAGE_DOS_HEADER.from_address(baseaddr)
|
||||
|
||||
def get_NT_HEADER(self):
|
||||
return self.get_DOS_HEADER().get_NT_HEADER()
|
||||
|
||||
def get_OptionalHeader(self):
|
||||
return self.get_NT_HEADER().OptionalHeader
|
||||
|
||||
def get_DataDirectory(self):
|
||||
return self.get_OptionalHeader().DataDirectory
|
||||
|
||||
def get_DataDirectoryAddr(self, number):
|
||||
return self.get_DataDirectory()[number]
|
||||
|
||||
def get_IMPORT_DESCRIPTORS(self):
|
||||
return self.get_OptionalHeader().get_IMPORT_DESCRIPTORS()
|
||||
|
||||
def get_EXPORT_DIRECTORY(self):
|
||||
return self.get_OptionalHeader().get_EXPORT_DIRECTORY()
|
||||
|
||||
@property
|
||||
def exports(self):
|
||||
return self.get_EXPORT_DIRECTORY().get_exports()
|
||||
|
||||
@property
|
||||
def IAT(self):
|
||||
res = {}
|
||||
for import_descriptor in self.get_OptionalHeader().get_IMPORT_DESCRIPTORS():
|
||||
res.setdefault(import_descriptor.Name.str.lower(),[]).extend(import_descriptor.get_IAT())
|
||||
return res
|
||||
|
||||
# TODO: get imports by parsing other modules exports if no INT
|
||||
@property
|
||||
def imports(self):
|
||||
res = {}
|
||||
for import_descriptor in self.get_OptionalHeader().get_IMPORT_DESCRIPTORS():
|
||||
INT = import_descriptor.get_INT()
|
||||
IAT = import_descriptor.get_IAT()
|
||||
if INT is not None:
|
||||
for iat_entry, (ord, name) in zip(IAT, INT):
|
||||
iat_entry.name = name
|
||||
iat_entry.ord = ord
|
||||
res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT)
|
||||
return res
|
||||
|
||||
current_pe = PEFile()
|
||||
|
||||
class IMAGE_DOS_HEADER(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("e_magic", CHAR * 2),
|
||||
("e_cblp", WORD),
|
||||
("e_cp", WORD),
|
||||
("e_crlc", WORD),
|
||||
("e_cparhdr", WORD),
|
||||
("e_minalloc", WORD),
|
||||
("e_maxalloc", WORD),
|
||||
("e_ss", WORD),
|
||||
("e_sp", WORD),
|
||||
("e_csum", WORD),
|
||||
("e_ip", WORD),
|
||||
("e_cs", WORD),
|
||||
("e_lfarlc", WORD),
|
||||
("e_ovno", WORD),
|
||||
("e_res", WORD * 4),
|
||||
("e_oemid", WORD),
|
||||
("e_oeminfo", WORD),
|
||||
("e_res2", WORD * 10),
|
||||
("e_lfanew", DWORD),
|
||||
]
|
||||
|
||||
def get_NT_HEADER(self):
|
||||
return IMAGE_NT_HEADERS.from_address(baseaddr + self.e_lfanew)
|
||||
|
||||
|
||||
class IMAGE_FILE_HEADER(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Machine", WORD),
|
||||
("NumberOfSections", WORD),
|
||||
("TimeDateStamp", DWORD),
|
||||
("PointerToSymbolTable", DWORD),
|
||||
("NumberOfSymbols", DWORD),
|
||||
("SizeOfOptionalHeader", WORD),
|
||||
("Characteristics", WORD),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_DATA_DIRECTORY(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("VirtualAddress", DWORD),
|
||||
("Size", DWORD),
|
||||
]
|
||||
|
||||
class IMAGE_OPTIONAL_HEADER(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Magic", WORD),
|
||||
("MajorLinkerVersion", BYTE),
|
||||
("MinorLinkerVersion", BYTE),
|
||||
("SizeOfCode", DWORD),
|
||||
("SizeOfInitializedData", DWORD),
|
||||
("SizeOfUninitializedData", DWORD),
|
||||
("AddressOfEntryPoint", DWORD),
|
||||
("BaseOfCode", DWORD),
|
||||
("BaseOfData", DWORD),
|
||||
("ImageBase", DWORD),
|
||||
("SectionAlignment", DWORD),
|
||||
("FileAlignment", DWORD),
|
||||
("MajorOperatingSystemVersion", WORD),
|
||||
("MinorOperatingSystemVersion", WORD),
|
||||
("MajorImageVersion", WORD),
|
||||
("MinorImageVersion", WORD),
|
||||
("MajorSubsystemVersion", WORD),
|
||||
("MinorSubsystemVersion", WORD),
|
||||
("Win32VersionValue", DWORD),
|
||||
("SizeOfImage", DWORD),
|
||||
("SizeOfHeaders", DWORD),
|
||||
("CheckSum", DWORD),
|
||||
("Subsystem", WORD),
|
||||
("DllCharacteristics", WORD),
|
||||
("SizeOfStackReserve", DWORD),
|
||||
("SizeOfStackCommit", DWORD),
|
||||
("SizeOfHeapReserve", DWORD),
|
||||
("SizeOfHeapCommit", DWORD),
|
||||
("LoaderFlags", DWORD),
|
||||
("NumberOfRvaAndSizes", DWORD),
|
||||
("DataDirectory", IMAGE_DATA_DIRECTORY * 16),
|
||||
]
|
||||
|
||||
def tst(self):
|
||||
import_descriptor_rva = self.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
|
||||
if import_descriptor_rva == 0:
|
||||
return []
|
||||
import_descriptor_addr = baseaddr + import_descriptor_rva
|
||||
res = []
|
||||
current_import_descriptor = IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
|
||||
return current_import_descriptor
|
||||
|
||||
def get_IMPORT_DESCRIPTORS(self):
|
||||
import_descriptor_rva = self.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
|
||||
if import_descriptor_rva == 0:
|
||||
return []
|
||||
import_descriptor_addr = baseaddr + import_descriptor_rva
|
||||
res = []
|
||||
current_import_descriptor = IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
|
||||
while current_import_descriptor.FirstThunk.value != 0:
|
||||
res.append(current_import_descriptor)
|
||||
import_descriptor_addr += ctypes.sizeof(IMPORT_DESCRIPTOR)
|
||||
current_import_descriptor = IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
|
||||
return res
|
||||
|
||||
def get_EXPORT_DIRECTORY(self):
|
||||
export_directory_rva = self.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
|
||||
if export_directory_rva == 0:
|
||||
return None
|
||||
export_directory_addr = baseaddr + export_directory_rva
|
||||
return IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr)
|
||||
|
||||
|
||||
class IMAGE_NT_HEADERS(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Signature", CHAR * 2),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_SECTION_HEADER(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Name", BYTE * 8),
|
||||
("VirtualSize", DWORD),
|
||||
("VirtualAddress", DWORD),
|
||||
("SizeOfRawData", DWORD),
|
||||
("PointerToRawData", DWORD),
|
||||
("PointerToRelocations", DWORD),
|
||||
("PointerToLinenumbers", DWORD),
|
||||
("NumberOfRelocations", WORD),
|
||||
("NumberOfLinenumbers", WORD),
|
||||
("Characteristics", DWORD),
|
||||
]
|
||||
|
||||
class RVA(DWORD):
|
||||
@property
|
||||
def addr(self):
|
||||
@@ -202,8 +29,7 @@ def PEFile(baseaddr):
|
||||
|
||||
def __repr__(self):
|
||||
return "<DWORD {0} (RVA to '{1}')>".format(self.value, hex(self.addr))
|
||||
|
||||
# Good idea ?
|
||||
|
||||
class StringRVa(RVA):
|
||||
@property
|
||||
def str(self):
|
||||
@@ -214,11 +40,23 @@ def PEFile(baseaddr):
|
||||
|
||||
def __int__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
|
||||
|
||||
class IMPORT_BY_NAME(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Hint", WORD),
|
||||
("Name", BYTE)
|
||||
]
|
||||
|
||||
class THUNK_DATA(ctypes.Union):
|
||||
_fields_ = [
|
||||
("Ordinal", PVOID),
|
||||
("AddressOfData", PVOID)
|
||||
]
|
||||
|
||||
class IATEntry(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("value", DWORD)]
|
||||
("value", PVOID)]
|
||||
|
||||
@classmethod
|
||||
def create(cls, addr, ord, name):
|
||||
@@ -246,102 +84,157 @@ def PEFile(baseaddr):
|
||||
self.hook.disable()
|
||||
self.hook = None
|
||||
return True
|
||||
|
||||
class PEFile(object):
|
||||
def __init__(self):
|
||||
self.baseaddr = baseaddr
|
||||
|
||||
def get_DOS_HEADER(self):
|
||||
return IMAGE_DOS_HEADER.from_address(baseaddr)
|
||||
|
||||
|
||||
class IMPORT_DESCRIPTOR(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("OriginalFirstThunk", RVA),
|
||||
("TimeDateStamp", DWORD),
|
||||
("ForwarderChain", DWORD),
|
||||
("Name", StringRVa),
|
||||
("FirstThunk", RVA)]
|
||||
|
||||
|
||||
def get_INT(self):
|
||||
if not self.OriginalFirstThunk.value:
|
||||
return None
|
||||
int_addr = self.OriginalFirstThunk.addr
|
||||
int_entry = THUNK_DATA.from_address(int_addr)
|
||||
def get_NT_HEADER(self):
|
||||
return self.get_DOS_HEADER().get_NT_HEADER()
|
||||
|
||||
def get_OptionalHeader(self):
|
||||
return self.get_NT_HEADER().OptionalHeader
|
||||
|
||||
def get_DataDirectory(self):
|
||||
return self.get_OptionalHeader().DataDirectory
|
||||
|
||||
def get_IMPORT_DESCRIPTORS(self):
|
||||
import_datadir = self.get_DataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||
if import_datadir.VirtualAddress == 0:
|
||||
print("get_IMPORT_DESCRIPTORS : VirtualAddress == 0")
|
||||
return []
|
||||
import_descriptor_addr = RVA(import_datadir.VirtualAddress).addr
|
||||
current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
|
||||
res = []
|
||||
while int_entry.Ordinal:
|
||||
if int_entry.Ordinal & IMAGE_ORDINAL_FLAG32:
|
||||
res += [(int_entry.Ordinal & 0x7fffffff, None)]
|
||||
else:
|
||||
import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData)
|
||||
name = ctypes.c_char_p(ctypes.addressof(import_by_name) + IMPORT_BY_NAME.Name.offset).value
|
||||
res.append((import_by_name.Hint, name))
|
||||
int_addr += ctypes.sizeof(THUNK_DATA)
|
||||
while current_import_descriptor.FirstThunk:
|
||||
res.append(current_import_descriptor)
|
||||
import_descriptor_addr += ctypes.sizeof(self.IMAGE_IMPORT_DESCRIPTOR)
|
||||
current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
|
||||
return res
|
||||
|
||||
|
||||
#def get_EXPORT_DIRECTORY(self):
|
||||
# return self.get_OptionalHeader().get_EXPORT_DIRECTORY()
|
||||
|
||||
#@property
|
||||
#def exports(self):
|
||||
# return self.get_EXPORT_DIRECTORY().get_exports()
|
||||
|
||||
# TODO: get imports by parsing other modules exports if no INT
|
||||
@property
|
||||
def imports(self):
|
||||
res = {}
|
||||
for import_descriptor in self.get_IMPORT_DESCRIPTORS():
|
||||
INT = import_descriptor.get_INT()
|
||||
IAT = import_descriptor.get_IAT()
|
||||
if INT is not None:
|
||||
for iat_entry, (ord, name) in zip(IAT, INT):
|
||||
iat_entry.name = name
|
||||
iat_entry.ord = ord
|
||||
res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT)
|
||||
return res
|
||||
|
||||
# Will be usable as `self.IMPORT_DESCRIPTOR`
|
||||
class IMAGE_IMPORT_DESCRIPTOR(ctypes.Structure):
|
||||
_fields_ = transform_ctypes_fields(IMAGE_IMPORT_DESCRIPTOR, {"Name" : StringRVa, "OriginalFirstThunk" : RVA, "FirstThunk" : RVA})
|
||||
|
||||
def get_INT(self):
|
||||
if not self.OriginalFirstThunk.value:
|
||||
return None
|
||||
int_addr = self.OriginalFirstThunk.addr
|
||||
int_entry = THUNK_DATA.from_address(int_addr)
|
||||
return res
|
||||
|
||||
|
||||
#def get_IAT(self):
|
||||
# iat_addr = self.FirstThunk.addr
|
||||
# iat_entry = THUNK_DATA.from_address(iat_addr)
|
||||
# res = []
|
||||
# INT_iter = iter(self.get_INT())
|
||||
# while iat_entry.Ordinal:
|
||||
# try:
|
||||
# ordinal, name = next(INT_iter) #Should never StopIteration as IAT and INT are the same size
|
||||
# except StopIteration:
|
||||
# raise ValueError("Int shorter than IAT")
|
||||
# res.append(IATEntry.create(iat_addr, ordinal, name))
|
||||
# iat_addr += ctypes.sizeof(THUNK_DATA)
|
||||
# iat_entry = THUNK_DATA.from_address(iat_addr)
|
||||
# return res
|
||||
|
||||
def get_IAT(self):
|
||||
iat_addr = self.FirstThunk.addr
|
||||
iat_entry = THUNK_DATA.from_address(iat_addr)
|
||||
res = []
|
||||
while iat_entry.Ordinal:
|
||||
res.append(IATEntry.create(iat_addr, -1, "??"))
|
||||
iat_addr += ctypes.sizeof(THUNK_DATA)
|
||||
res = []
|
||||
while int_entry.Ordinal:
|
||||
if int_entry.Ordinal & IMAGE_ORDINAL_FLAG32:
|
||||
res += [(int_entry.Ordinal & 0x7fffffff, None)]
|
||||
else:
|
||||
import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData)
|
||||
name = ctypes.c_char_p(ctypes.addressof(import_by_name) + IMPORT_BY_NAME.Name.offset).value
|
||||
res.append((import_by_name.Hint, name))
|
||||
int_addr += ctypes.sizeof(THUNK_DATA)
|
||||
int_entry = THUNK_DATA.from_address(int_addr)
|
||||
return res
|
||||
|
||||
def get_IAT(self):
|
||||
iat_addr = self.FirstThunk.addr
|
||||
iat_entry = THUNK_DATA.from_address(iat_addr)
|
||||
return res
|
||||
|
||||
|
||||
|
||||
class IMPORT_BY_NAME(ctypes.Structure):
|
||||
res = []
|
||||
while iat_entry.Ordinal:
|
||||
res.append(IATEntry.create(iat_addr, -1, "??"))
|
||||
iat_addr += ctypes.sizeof(THUNK_DATA)
|
||||
iat_entry = THUNK_DATA.from_address(iat_addr)
|
||||
return res
|
||||
|
||||
current_pe = PEFile()
|
||||
|
||||
class IMAGE_DOS_HEADER(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Hint", WORD),
|
||||
("Name", BYTE)
|
||||
]
|
||||
|
||||
class THUNK_DATA(ctypes.Union):
|
||||
_fields_ = [
|
||||
("Ordinal", DWORD),
|
||||
("AddressOfData", DWORD)
|
||||
]
|
||||
|
||||
class IMAGE_EXPORT_DIRECTORY(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("Characteristics", DWORD),
|
||||
("TimeDateStamp", DWORD),
|
||||
("MajorVersion", WORD),
|
||||
("MinorVersion", WORD),
|
||||
("Name", StringRVa),
|
||||
("Base", DWORD),
|
||||
("NumberOfFunctions", DWORD),
|
||||
("NumberOfNames", DWORD),
|
||||
("AddressOfFunctions", RVA),
|
||||
("AddressOfNames", RVA),
|
||||
("AddressOfNameOrdinals", RVA),
|
||||
("e_magic", CHAR * 2),
|
||||
("e_cblp", WORD),
|
||||
("e_cp", WORD),
|
||||
("e_crlc", WORD),
|
||||
("e_cparhdr", WORD),
|
||||
("e_minalloc", WORD),
|
||||
("e_maxalloc", WORD),
|
||||
("e_ss", WORD),
|
||||
("e_sp", WORD),
|
||||
("e_csum", WORD),
|
||||
("e_ip", WORD),
|
||||
("e_cs", WORD),
|
||||
("e_lfarlc", WORD),
|
||||
("e_ovno", WORD),
|
||||
("e_res", WORD * 4),
|
||||
("e_oemid", WORD),
|
||||
("e_oeminfo", WORD),
|
||||
("e_res2", WORD * 10),
|
||||
("e_lfanew", DWORD),
|
||||
]
|
||||
|
||||
def get_exports(self):
|
||||
NameOrdinals = (WORD * self.NumberOfNames).from_address(self.AddressOfNameOrdinals.addr)
|
||||
NameOrdinals = list(NameOrdinals)
|
||||
Functions = (RVA * self.NumberOfFunctions).from_address(self.AddressOfFunctions.addr)
|
||||
Names = (StringRVa * self.NumberOfNames).from_address(self.AddressOfNames.addr)
|
||||
res = []
|
||||
for nb,func in enumerate(Functions):
|
||||
if nb in NameOrdinals:
|
||||
name = Names[NameOrdinals.index(nb)]
|
||||
else:
|
||||
name = None
|
||||
res.append((nb, func, name))
|
||||
return res
|
||||
|
||||
def get_NT_HEADER(self):
|
||||
if windows.current_process.bitness == 32:
|
||||
return IMAGE_NT_HEADERS32.from_address(baseaddr + self.e_lfanew)
|
||||
return IMAGE_NT_HEADERS64.from_address(baseaddr + self.e_lfanew)
|
||||
|
||||
#
|
||||
# def get_EXPORT_DIRECTORY(self):
|
||||
# export_directory_rva = self.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
|
||||
# if export_directory_rva == 0:
|
||||
# return None
|
||||
# export_directory_addr = baseaddr + export_directory_rva
|
||||
# return IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr)
|
||||
#
|
||||
|
||||
|
||||
#class IMAGE_EXPORT_DIRECTORY(ctypes.Structure):
|
||||
# _fields_ = [
|
||||
# ("Characteristics", DWORD),
|
||||
# ("TimeDateStamp", DWORD),
|
||||
# ("MajorVersion", WORD),
|
||||
# ("MinorVersion", WORD),
|
||||
# ("Name", StringRVa),
|
||||
# ("Base", DWORD),
|
||||
# ("NumberOfFunctions", DWORD),
|
||||
# ("NumberOfNames", DWORD),
|
||||
# ("AddressOfFunctions", RVA),
|
||||
# ("AddressOfNames", RVA),
|
||||
# ("AddressOfNameOrdinals", RVA),
|
||||
# ]
|
||||
#
|
||||
# def get_exports(self):
|
||||
# NameOrdinals = (WORD * self.NumberOfNames).from_address(self.AddressOfNameOrdinals.addr)
|
||||
# NameOrdinals = list(NameOrdinals)
|
||||
# Functions = (RVA * self.NumberOfFunctions).from_address(self.AddressOfFunctions.addr)
|
||||
# Names = (StringRVa * self.NumberOfNames).from_address(self.AddressOfNames.addr)
|
||||
# res = []
|
||||
# for nb,func in enumerate(Functions):
|
||||
# if nb in NameOrdinals:
|
||||
# name = Names[NameOrdinals.index(nb)]
|
||||
# else:
|
||||
# name = None
|
||||
# res.append((nb, func, name))
|
||||
# return res
|
||||
#
|
||||
return current_pe
|
||||
+1
-14
@@ -2,6 +2,7 @@ import ctypes
|
||||
import ctypes.wintypes
|
||||
from windows.hooks import *
|
||||
|
||||
# Example of callback for IAT hooks
|
||||
|
||||
@Callback(ctypes.c_ulong, ctypes.c_ulong)
|
||||
def exit_callback(x, real_function):
|
||||
@@ -11,20 +12,6 @@ def exit_callback(x, real_function):
|
||||
return real_function(1234)
|
||||
return 0
|
||||
|
||||
tt = False
|
||||
|
||||
DWORD = ctypes.wintypes.DWORD
|
||||
|
||||
@Callback(DWORD, DWORD , DWORD, DWORD, DWORD)
|
||||
def valloc_callback(*args, **kwargs):
|
||||
global tt
|
||||
real_function = kwargs['real_function']
|
||||
print("Try to virtual alloc with {0}".format([hex(x) for x in args]))
|
||||
tt = not tt
|
||||
if tt:
|
||||
return real_function()
|
||||
return 0
|
||||
|
||||
@CreateFileACallback
|
||||
def createfile_callback(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile, real_function):
|
||||
print("Trying to open {0}".format(lpFileName))
|
||||
|
||||
@@ -4,7 +4,7 @@ import generated_def.windef as windef
|
||||
import winobject
|
||||
import copy
|
||||
import native_exec
|
||||
import generated_def.winstructs as winstructs
|
||||
from generated_def.winstructs import *
|
||||
|
||||
# Function resolution !
|
||||
|
||||
@@ -19,7 +19,6 @@ def get_func_addr(dll_name, func_name):
|
||||
|
||||
def enumerate_processes():
|
||||
process_entry = winobject.WinProcess()
|
||||
#process_entry = winstructs.PROCESSENTRY32()
|
||||
process_entry.dwSize = ctypes.sizeof(process_entry)
|
||||
snap = kernel32proxy.CreateToolhelp32Snapshot(windef.TH32CS_SNAPPROCESS, 0)
|
||||
kernel32proxy.Process32First(snap, process_entry)
|
||||
@@ -40,33 +39,18 @@ def enumerate_threads():
|
||||
threads.append(copy.copy(thread_entry))
|
||||
return threads
|
||||
|
||||
class System(object):
|
||||
|
||||
@property
|
||||
def processes(self):
|
||||
return enumerate_processes()
|
||||
|
||||
@property
|
||||
def threads(self):
|
||||
return enumerate_threads()
|
||||
|
||||
class CurrentProcess(object):
|
||||
get_peb = None
|
||||
def is_wow_64(hProcess):
|
||||
try:
|
||||
fnIsWow64Process = get_func_addr("kernel32.dll", "IsWow64Process")
|
||||
except kernel32proxy.Kernel32Error:
|
||||
return False
|
||||
IsWow64Process = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.POINTER(BOOL))(fnIsWow64Process)
|
||||
Wow64Process = BOOL()
|
||||
res = IsWow64Process(hProcess, ctypes.byref(Wow64Process))
|
||||
if res:
|
||||
return bool(Wow64Process)
|
||||
raise ctypes.WinError()
|
||||
|
||||
get_peb_32_code = '64a130000000c3'.decode('hex')
|
||||
|
||||
def get_peb_builtin(self):
|
||||
if self.get_peb is not None:
|
||||
return self.get_peb
|
||||
get_peb = native_exec.create_function(self.get_peb_32_code, [winstructs.PVOID])
|
||||
self.get_peb = get_peb
|
||||
return get_peb
|
||||
|
||||
@property
|
||||
def peb(self):
|
||||
return winobject.PEB.from_address(self.get_peb_builtin()())
|
||||
|
||||
|
||||
class VirtualProtected(object):
|
||||
def __init__(self, addr, size, new_protect):
|
||||
if (addr % 0x1000):
|
||||
@@ -76,7 +60,7 @@ class VirtualProtected(object):
|
||||
self.new_protect = new_protect
|
||||
|
||||
def __enter__(self):
|
||||
self.old_protect = winstructs.DWORD()
|
||||
self.old_protect = DWORD()
|
||||
kernel32proxy.VirtualProtect(self.addr, self.size, self.new_protect, ctypes.byref(self.old_protect))
|
||||
return self
|
||||
|
||||
|
||||
+102
-5
@@ -1,7 +1,11 @@
|
||||
import ctypes
|
||||
import os
|
||||
|
||||
import windows
|
||||
import utils
|
||||
import k32testing as kernel32proxy
|
||||
import injection
|
||||
import native_exec
|
||||
|
||||
from generated_def.winstructs import *
|
||||
import pe_parse
|
||||
@@ -22,7 +26,28 @@ class AutoHandle(object):
|
||||
if hasattr(self, "_handle"):
|
||||
kernel32proxy.CloseHandle(self._handle)
|
||||
|
||||
|
||||
class System(object):
|
||||
|
||||
@property
|
||||
def processes(self):
|
||||
return utils.enumerate_processes()
|
||||
|
||||
@property
|
||||
def threads(self):
|
||||
return utils.enumerate_threads()
|
||||
|
||||
@property
|
||||
def bitness(self):
|
||||
if os.environ["PROCESSOR_ARCHITECTURE"].lower() != "x86":
|
||||
return 64
|
||||
if "PROCESSOR_ARCHITEW6432" in os.environ:
|
||||
return 64
|
||||
return 32
|
||||
|
||||
|
||||
# May have a common class with WinProcess for is_wow_64 and stuff
|
||||
|
||||
|
||||
class WinThread(THREADENTRY32, AutoHandle):
|
||||
@property
|
||||
def tid(self):
|
||||
@@ -41,6 +66,39 @@ class WinThread(THREADENTRY32, AutoHandle):
|
||||
def __repr__(self):
|
||||
return '<{0} {1} owner "{2}" at {3}>'.format(self.__class__.__name__, self.tid, self.owner.name, hex(id(self)))
|
||||
|
||||
|
||||
class CurrentProcess(object):
|
||||
get_peb = None
|
||||
get_peb_32_code = '64a130000000c3'.decode('hex')
|
||||
|
||||
# mov rax,QWORD PTR gs:0x60
|
||||
# ret
|
||||
get_peb_64_code = "65488B042560000000C3".decode('hex')
|
||||
|
||||
def get_peb_builtin(self):
|
||||
if self.get_peb is not None:
|
||||
return self.get_peb
|
||||
if self.bitness == 32:
|
||||
get_peb = native_exec.create_function(self.get_peb_32_code, [PVOID])
|
||||
else:
|
||||
get_peb = native_exec.create_function(self.get_peb_64_code, [PVOID])
|
||||
self.get_peb = get_peb
|
||||
return get_peb
|
||||
|
||||
@property
|
||||
def peb(self):
|
||||
return PEB.from_address(self.get_peb_builtin()())
|
||||
|
||||
@property
|
||||
def bitness(self):
|
||||
"""Return 32 or 64"""
|
||||
import platform
|
||||
bits = platform.architecture()[0]
|
||||
return int(bits[:2])
|
||||
|
||||
@property
|
||||
def is_wow_64(self):
|
||||
return utils.is_wow_64(kernel32proxy.GetCurrentProcess())
|
||||
|
||||
class WinProcess(PROCESSENTRY32, AutoHandle):
|
||||
is_pythondll_injected = 0
|
||||
@@ -63,6 +121,18 @@ class WinProcess(PROCESSENTRY32, AutoHandle):
|
||||
|
||||
def __repr__(self):
|
||||
return '<{0} "{1}" pid {2} at {3}>'.format(self.__class__.__name__, self.name, self.pid, hex(id(self)))
|
||||
|
||||
@property
|
||||
def is_wow_64(self):
|
||||
return utils.is_wow_64(self.handle)
|
||||
|
||||
@property
|
||||
def bitness(self):
|
||||
if windows.system.bitness == 32:
|
||||
return 32
|
||||
if self.is_wow_64:
|
||||
return 32
|
||||
return 64
|
||||
|
||||
def virtual_alloc(self, size):
|
||||
return kernel32proxy.VirtualAllocEx(self.handle, dwSize=size)
|
||||
@@ -73,7 +143,35 @@ class WinProcess(PROCESSENTRY32, AutoHandle):
|
||||
def read_memory(self, addr, size):
|
||||
return kernel32proxy.ReadProcessMemory(self.handle, addr, nSize=size)
|
||||
|
||||
## CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId):
|
||||
#CreateRemoteThreadPrototype = WINFUNCTYPE(HANDLE, HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD)
|
||||
|
||||
def NtCreateThreadEx(self, addr, param):
|
||||
print("CALLING SPECIAL NtCreateThreadEx")
|
||||
NtCreateThreadExAddr = utils.get_func_addr("ntdll.dll", "NtCreateThreadEx")
|
||||
NtCreateThreadEx = WINFUNCTYPE(HRESULT, PHANDLE, LPSECURITY_ATTRIBUTES, PVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID, BOOL, DWORD, DWORD, DWORD, PVOID)(NtCreateThreadExAddr)
|
||||
thread_handle = HANDLE()
|
||||
res = NtCreateThreadEx(byref(thread_handle), None, None, self.handle, addr, param, False, 0, 0, 0, None)
|
||||
print("RES = {0}".format(hex(res & 0xffffffff)))
|
||||
if res:
|
||||
raise WinError()
|
||||
|
||||
def RtlCreateUserThread(self, addr, param):
|
||||
print("CALLING SPECIAL RtlCreateUserThread")
|
||||
RtlCreateUserThreadAddr = utils.get_func_addr("ntdll.dll", "RtlCreateUserThread")
|
||||
RtlCreateUserThread = WINFUNCTYPE(HRESULT, HANDLE, LPSECURITY_ATTRIBUTES, BOOL, ULONG, PULONG, PULONG, PVOID, PVOID, PHANDLE, PVOID)(RtlCreateUserThreadAddr)
|
||||
thread_handle = HANDLE()
|
||||
tmp1 = DWORD()
|
||||
tmp2 = DWORD()
|
||||
res = RtlCreateUserThread(self.handle, None, False, 0, None, None, addr, param, None, None)
|
||||
print("RES = {0}".format(hex(res & 0xffffffff)))
|
||||
if res:
|
||||
raise WinError()
|
||||
|
||||
|
||||
def create_thread(self, addr, param):
|
||||
if windows.current_process.bitness == 32 and self.bitness == 64:
|
||||
raise NotImplementedError("Injection 32 to 64")
|
||||
return kernel32proxy.CreateRemoteThread(hProcess=self.handle, lpStartAddress=addr, lpParameter=param)
|
||||
|
||||
def load_library(self, dll_path):
|
||||
@@ -87,12 +185,11 @@ class WinProcess(PROCESSENTRY32, AutoHandle):
|
||||
self.write_memory(x, code)
|
||||
return self.create_thread(x, 0)
|
||||
|
||||
def get_remote_python(self):
|
||||
return injection.launch_remote_slave(self)
|
||||
def execute_python(self, pycode):
|
||||
return injection.execute_python_code(self, pycode)
|
||||
|
||||
|
||||
class LoadedModule(LDR_DATA_TABLE_ENTRY):
|
||||
|
||||
@property
|
||||
def baseaddr(self):
|
||||
return self.DllBase
|
||||
@@ -135,8 +232,8 @@ class PEB(PEB):
|
||||
# This or changing the __repr__ of LSA_UNICODE_STRING
|
||||
raw_cmd = self.ProcessParameters.contents.CommandLine
|
||||
return WinUnicodeString.from_address(ctypes.addressof(raw_cmd))
|
||||
|
||||
@property
|
||||
|
||||
def modules(self):
|
||||
res = []
|
||||
list_entry_ptr = ctypes.cast(self.Ldr.contents.InMemoryOrderModuleList.Flink, LIST_ENTRY_PTR)
|
||||
|
||||
Reference in New Issue
Block a user