3. windows.native_exec
– Native Code Execution¶
windows.native_exec
allows to create Python
functions calling native code.
it also provides a simple assembler for x86 and x64.
windows.native_exec
provides those functions:
- windows.native_exec.create_function(code, types, calling_convention=<function CFUNCTYPE>)[source]¶
Create a python function that call raw machine code
- Parameters:
code (str) – Raw machine code that will be called
types (list) – Return type and parameters type (see
ctypes
)
- Returns:
the created function
- Return type:
function
- The
windows.native_exec
also contains some submodules:
3.1. windows.native_exec.cpuid
– Interface to native CPUID¶
- class windows.native_exec.cpuid.X86AmdCpuidFamilly[source]¶
- fields = ['SteppingID', 'ModelID', 'FamilyID', 'Reserved2', 'ExtendedModel', 'ExtendedFamily', 'Reserved']¶
Fields of the Structure
- class windows.native_exec.cpuid.X86CpuidResult[source]¶
Raw result of the CPUID instruction
- fields = ['EAX', 'EBX', 'ECX', 'EDX']¶
Fields of the Structure
- class windows.native_exec.cpuid.X86IntelCpuidFamilly[source]¶
- fields = ['SteppingID', 'ModelID', 'FamilyID', 'ProcessorType', 'Reserved2', 'ExtendedModel', 'ExtendedFamily', 'Reserved']¶
Fields of the Structure
- windows.native_exec.cpuid.do_cpuid(req)[source]¶
Performs a CPUID for the current process bitness
- Return type:
- windows.native_exec.cpuid.get_proc_family_model()[source]¶
Extracts the family and model based on vendorId
- Return type:
(ComputedFamily, ComputedModel)
- windows.native_exec.cpuid.get_vendor_id()[source]¶
Extracts the VendorId string from CPUID
- Return type:
str
Demo:
>>> import windows.native_exec.cpuid
>>> windows.native_exec.cpuid.do_cpuid(0)
<windows.native_exec.cpuid.X86CpuidResult object at 0x0330D990>
>>> x = windows.native_exec.cpuid.do_cpuid(0)
>>> x.EAX
13L
>>> x.EBX
1970169159L
>>> windows.native_exec.cpuid.get_vendor_id()
'GenuineIntel'
>>> windows.native_exec.cpuid.get_proc_family_model()
(6L, 58L)
3.2. windows.native_exec.simple_x86
– X86 Assembler¶
The windows.native_exec.simple_x86
module allows to create simple x86 code.
- Its features are:
Forward - Backward jump (using labels)
Non-string interface for conditional/context dependent generation
Note
The assembler DOES NOT handle every instruction at all.
The assembler instructions are Python
object that may accept arguments representing
the mnemonic operands.
- These parameters can be of type:
str
(register)int
(int)mem_access
(memory access)
- class windows.native_exec.simple_x86.mem_access(base, index, scale, disp, prefix)¶
- base¶
Alias for field number 0
- disp¶
Alias for field number 3
- index¶
Alias for field number 1
- prefix¶
Alias for field number 4
- scale¶
Alias for field number 2
- The
mem_access
object can be created: By hand
Using
create_displacement()
Using
mem()
- windows.native_exec.simple_x86.create_displacement(base=None, index=None, scale=None, disp=0, prefix=None)[source]¶
Creates a X86 memory access description
- windows.native_exec.simple_x86.deref(disp)[source]¶
Create a memory access for an immediate value
Ex: [0x42424242]
- windows.native_exec.simple_x86.mem(data)[source]¶
Parse a memory access string of format
[EXPR]
orseg:[EXPR]
EXPR
may describe:BASE | INDEX * SCALE | DISPLACEMENT
or any combinaison (in this order)
Instruction assembling:
>>> import windows.native_exec.simple_x86 as x86
>>> import random
>>> x86.Mov
<class 'windows.native_exec.simple_x86.Mov'>
>>> instr = x86.Mov("EAX", "EBX")
>>> instr
<windows.native_exec.simple_x86.Mov object at 0x03243770>
>>> instr.get_code()
'\x89\xd8'
>>> x86.Mov("EAX", 0x42424242).get_code()
'\xc7\xc0BBBB'
>>> x86.Mov("EAX", x86.create_displacement(base="EAX", disp=random.randint(0, 0xffffffff))).get_code()
'\x8b\x80\x977\n&'
>>> x86.Mov(x86.mem("[EBX + EDI * 2 + 0x11111111]"), "EAX").get_code()
'\x89\x84{\x11\x11\x11\x11'
>>> x86.Mov(x86.mem("gs:[EBX + EDI * 2 + 0x11111111]"), "EAX").get_code()
'e\x89\x84{\x11\x11\x11\x11'
windows.native_exec.simple_x86
also provides an interface to complex shellcode assembling
including jump and label via the MultipleInstr
class.
Shellcode assembling:
import windows.native_exec.simple_x86 as x86
code = x86.MultipleInstr()
code += x86.Label(":BEGIN")
code += x86.Jmp(":BEGIN")
print(repr(code.get_code()))
# '\xeb\xfe'
Another example from a project:
IO_STACK_INPUT_BUFFER_LEN = x86.mem('[ESI + 8]')
IO_STACK_INPUT_BUFFER = x86.mem('[ESI + 0x10]')
INPUT_BUFFER_SIZE = x86.mem('[ECX]')
INPUT_BUFFER_PORT = x86.mem('[ECX + 4]')
INPUT_BUFFER_VALUE = x86.mem('[ECX + 8]')
out_ioctl = x86.MultipleInstr()
out_ioctl += x86.Cmp(IO_STACK_INPUT_BUFFER_LEN, 0xc) # size indicator / port / value
out_ioctl += x86.Jnz(":FAIL")
out_ioctl += x86.Mov('ECX', IO_STACK_INPUT_BUFFER)
out_ioctl += x86.Mov('EDX', INPUT_BUFFER_PORT)
out_ioctl += x86.Mov('EAX', INPUT_BUFFER_VALUE)
out_ioctl += x86.Mov('ECX', INPUT_BUFFER_SIZE)
out_ioctl += x86.Cmp('ECX', 0x1)
out_ioctl += x86.Jnz(":OUT_2_OR_4")
out_ioctl += x86.Out('DX', 'AL')
out_ioctl += x86.Jmp(':SUCCESS')
out_ioctl += x86.Label(":OUT_2_OR_4")
out_ioctl += x86.Cmp('ECX', 0x2)
out_ioctl += x86.Jnz(":OUT_4")
out_ioctl += x86.Out('DX', 'AX')
out_ioctl += x86.Jmp(':SUCCESS')
out_ioctl += x86.Label(":OUT_4")
out_ioctl += x86.Out('DX', 'EAX')
out_ioctl += x86.Label(":SUCCESS")
out_ioctl += x86.Xor('EAX', 'EAX')
out_ioctl += x86.Ret()
out_ioctl += x86.Label(":FAIL")
out_ioctl += x86.Mov('EAX', 0x0C000000D)
out_ioctl += x86.Ret()
out_ioctl.get_code()
'\x81~\x08\x0c\x00\x00\x00u&\x8bN\x10\x8bQ\x04\x8bA\x08\x8b\t\x81\xf9\x01\x00\x00\x00u\x03\xee\xeb\r\x81\xf9\x02\x00\x00\x00u\x04f\xef\xeb\x01\xef1\xc0\xc3\xc7\xc0\r\x00\x00\xc0\xc3'
3.3. windows.native_exec.simple_x64
– X64 Assembler¶
Same things as windows.native_exec.simple_x86
- The only things that change are:
The registers name
windows.native_exec.simple_x64
handles 32 and 64 bits operations.
Demo:
>>> import windows.native_exec.simple_x64 as x64
>>> x64.Mov("RAX", "R13").get_code()
'L\x89\xe8'
>>> x64.Mov("EAX", "EDI").get_code()
'\x89\xf8'
>>> x64.Mov("RAX", "EDI").get_code()
"""
ValueError: Size mismatch
"""
>>> x64.Mov("RAX", x64.mem("[EAX]")).get_code()
'gH\x8b\x00'
>>> x64.Mov("RAX", x64.mem("[RAX]")).get_code()
'H\x8b\x00'
>>> x64.Mov("EAX", x64.mem("[RAX]")).get_code()
'\x8b\x00'
>>> x64.Mov("EAX", x64.mem("[EAX]")).get_code()
'g\x8b\x00'
3.4. windows.native_exec.nativeutils
– Native utility functions¶
This module contains some native-code functions that can be used for various purposes.
Each function export a label that allow another MultipleInstr
to call the code of the function.
The current functions are:
StrlenW64
A 64bits wide-string STRLEN (Label(":FUNC_STRLENW64")
)
StrlenA64
A 64bits ASCII STRLEN (Label(":FUNC_STRLENA64")
)
GetProcAddress64
A 64bits export resolver (Label(":FUNC_GETPROCADDRESS64")
)
Arg1: The DLL (wstring)
Arg2: The API (string)
Return value:
0xfffffffffffffffe if the DLL is not found
0xffffffffffffffff if the API is not found
The address of the function
StrlenW32
A 32bits wide-string STRLEN (Label(":FUNC_STRLENW32")
)
StrlenA32
A 32bits ASCII STRLEN (Label(":FUNC_STRLENA32")
)
GetProcAddress32
A 32bits export resolver (Label(":FUNC_GETPROCADDRESS32")
)
Arg1: The DLL (wstring)
Arg2: The API (string)
Return value:
0xfffffffe if the DLL is not found
0xffffffff if the API is not found
The address of the function
To use those functions in a MultipleInstr
just call the label in your code and append the function at
the end of your MultipleInstr
Example:
RemoteManualLoadLibray = x86.MultipleInstr()
RemoteManualLoadLibray += x86.Mov("ECX", x86.mem("[ESP + 4]"))
RemoteManualLoadLibray += x86.Push(x86.mem("[ECX + 4]"))
RemoteManualLoadLibray += x86.Push(x86.mem("[ECX]"))
RemoteManualLoadLibray += x86.Call(":FUNC_GETPROCADDRESS32")
RemoteManualLoadLibray += x86.Push(x86.mem("[ECX + 8]"))
RemoteManualLoadLibray += x86.Call("EAX") # LoadLibrary
RemoteManualLoadLibray += x86.Pop("ECX")
RemoteManualLoadLibray += x86.Pop("ECX")
RemoteManualLoadLibray += x86.Ret()
RemoteManualLoadLibray += GetProcAddress32