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)[source]¶ Create a python function that call raw machine code
Parameters: Returns: the created function
Return type: function
- The
windows.native_execalso 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: X86CpuidResult
-
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
-
windows.native_exec.cpuid.x64_cpuid(req)[source]¶ Performs a CPUID in 64bits mode
Return type: X86CpuidResult
-
windows.native_exec.cpuid.x86_cpuid(req)[source]¶ Performs a CPUID in 32bits mode
Return type: X86CpuidResult
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_accessobject 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]EXPRmay describe:BASE | INDEX * SCALE | DISPLACEMENTor 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.2.1. Available Instructions in X86 assembler¶
Note
Not all encodings may be implemented for each of the instructions.
Byte and Raw are not x86 instruction and allow to insert arbitrary data to the generated code.
Listing:
- Add
- And
- Byte
- Cmp
- CmpsB
- CmpsD
- CmpsW
- Cpuid
- Dec
- In
- Inc
- Int
- Int3
- Iret
- Lea
- Mov
- Movsb
- Movsd
- Nop
- Not
- Or
- Out
- Pop
- Popad
- Popfd
- Push
- Pushad
- Pushfd
- Raw
- Ret
- Retf
- Rol
- Ror
- ScasB
- ScasD
- ScasW
- Shl
- Shr
- StosB
- StosD
- StosW
- Sub
- Test
- Xchg
- Xor
Note
Raw: Output raw data from an hexadecimal string
>>> windows.native_exec.simple_x64.Raw("90C332FCFF").get_code()
'\x90\xc32\xfc\xff'
Byte: Output a raw byte
>>> windows.native_exec.simple_x86.Byte(0x42).get_code()
'B'
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.3.1. Available Instructions in X64 assembler¶
Note
Not all encodings may be implemented for each of the instructions.
Raw is not an x64 instruction and allow to insert arbitrary data to the generated code.
- Listing:
- Add
- And
- Cmp
- CmpsB
- CmpsD
- CmpsQ
- CmpsW
- Cpuid
- Dec
- In
- Inc
- Int
- Int3
- Lea
- Mov
- Nop
- Not
- Or
- Out
- Pop
- Popfq
- Push
- Pushfq
- Raw
- Ret
- Retf
- Retf32
- ScasB
- ScasD
- ScasQ
- ScasW
- Shl
- Shr
- Sub
- Test
- Xchg
- Xor
Note
Raw: Output raw data from an hexadecimal string
>>> windows.native_exec.simple_x64.Raw("90C332FCFF").get_code()
'\x90\xc32\xfc\xff'
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:
StrlenW64A 64bits wide-string STRLEN (Label(":FUNC_STRLENW64"))
StrlenA64A 64bits ASCII STRLEN (Label(":FUNC_STRLENA64"))
GetProcAddress64A 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
StrlenW32A 32bits wide-string STRLEN (Label(":FUNC_STRLENW32"))
StrlenA32A 32bits ASCII STRLEN (Label(":FUNC_STRLENA32"))
GetProcAddress32A 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