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:
  • 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.X64CpuidResult[source]
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.is_amd_proc()[source]

get_vendor_id() == ‘AuthenticAMD’

windows.native_exec.cpuid.is_intel_proc()[source]

get_vendor_id() == ‘GenuineIntel’

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:
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:
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] or seg:[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.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:

  • 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