PyQBDI Bindings API

The PyQBDI API is almost the same as the C++ API.

When the library is loaded as a preloaded library, the variable pyqbdi.__preload__ is set to True.

State

The state available depends of the architecture (X86 or X86-64).

class pyqbdi.GPRState
AVAILABLE_GPR

shadow of rbp

NUM_GPR

shadow of eflags

REG_BP

shadow of rbp

REG_LR

not available on X86_64

REG_PC

shadow of rip

REG_RETURN

shadow of rax

REG_SP

shadow of rsp

__getitem__(self: pyqbdi.GPRState, index: int) → int

Get a register like QBDI_GPR_GET

__setitem__(self: pyqbdi.GPRState, index: int, value: int) → int

Set a register like QBDI_GPR_SET

eflags
r10
r11
r12
r13
r14
r15
r8
r9
rax
rbp
rbx
rcx
rdi
rdx
rip
rsi
rsp
class pyqbdi.FPRState
cs

x87 FPU Instruction Pointer Selector

dp

x87 FPU Instruction Operand(Data) Pointer offset

ds

x87 FPU Instruction Operand(Data) Pointer Selector

fcw

x87 FPU control word

fop

x87 FPU Opcode

fsw

x87 FPU status word

ftw

x87 FPU tag word

ip

x87 FPU Instruction Pointer offset

mxcsr

MXCSR Register state

mxcsrmask

MXCSR mask

rfcw

x87 FPU control word

rfsw

x87 FPU status word

stmm0

ST0/MM0

stmm1

ST1/MM1

stmm2

ST2/MM2

stmm3

ST3/MM3

stmm4

ST4/MM4

stmm5

ST5/MM5

stmm6

ST6/MM6

stmm7

ST7/MM7

xmm0

XMM 0

xmm1

XMM 1

xmm10

XMM 10

xmm11

XMM 11

xmm12

XMM 12

xmm13

XMM 13

xmm14

XMM 14

xmm15

XMM 15

xmm2

XMM 2

xmm3

XMM 3

xmm4

XMM 4

xmm5

XMM 5

xmm6

XMM 6

xmm7

XMM 7

xmm8

XMM 8

xmm9

XMM 9

ymm0

YMM0[255:128]

ymm1

YMM1[255:128]

ymm10

YMM10[255:128]

ymm11

YMM11[255:128]

ymm12

YMM12[255:128]

ymm13

YMM13[255:128]

ymm14

YMM14[255:128]

ymm15

YMM15[255:128]

ymm2

YMM2[255:128]

ymm3

YMM3[255:128]

ymm4

YMM4[255:128]

ymm5

YMM5[255:128]

ymm6

YMM6[255:128]

ymm7

YMM7[255:128]

ymm8

YMM8[255:128]

ymm9

YMM9[255:128]

VM

class pyqbdi.VM
addCodeAddrCB(self: pyqbdi.VM, address: int, pos: pyqbdi.InstPosition, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Register a callback for when a specific address is executed.

addCodeCB(self: pyqbdi.VM, pos: pyqbdi.InstPosition, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Register a callback event for every instruction executed.

addCodeRangeCB(self: pyqbdi.VM, start: int, end: int, pos: pyqbdi.InstPosition, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Register a callback for when a specific address range is executed.

addInstrumentedModule(self: pyqbdi.VM, name: str) → bool

Add the executable address ranges of a module to the set of instrumented address ranges.

addInstrumentedModuleFromAddr(self: pyqbdi.VM, addr: int) → bool

Add the executable address ranges of a module to the set of instrumented address ranges using an address belonging to the module.

addInstrumentedRange(self: pyqbdi.VM, start: int, end: int) → None

Add an address range to the set of instrumented address ranges.

addMemAccessCB(self: pyqbdi.VM, type: pyqbdi.MemoryAccessType, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Register a callback event for every memory access matching the type bitfield made by the instructions.

addMemAddrCB(self: pyqbdi.VM, address: int, type: pyqbdi.MemoryAccessType, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Add a virtual callback which is triggered for any memory access at a specific address matching the access type. Virtual callbacks are called via callback forwarding by a gate callback triggered on every memory access. This incurs a high performance cost.

addMemRangeCB(self: pyqbdi.VM, start: int, end: int, type: pyqbdi.MemoryAccessType, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Add a virtual callback which is triggered for any memory access at a specific address range matching the access type. Virtual callbacks are called via callback forwarding by a gate callback triggered on every memory access. This incurs a high performance cost.

addMnemonicCB(self: pyqbdi.VM, mnemonic: str, pos: pyqbdi.InstPosition, cbk: Callable[[pyqbdi.VM, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) → object

Register a callback event if the instruction matches the mnemonic.

addVMEventCB(*args, **kwargs)

Overloaded function.

  1. addVMEventCB(self: pyqbdi.VM, mask: pyqbdi.VMEvent, cbk: Callable[[pyqbdi.VM, pyqbdi.VMState, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) -> object

Register a callback event for a specific VM event.

  1. addVMEventCB(self: pyqbdi.VM, mask: int, cbk: Callable[[pyqbdi.VM, pyqbdi.VMState, pyqbdi.GPRState, pyqbdi.FPRState, object], pyqbdi.VMAction], data: object) -> object

Register a callback event for a specific VM event.

call(self: pyqbdi.VM, function: int, args: List[int]) → Tuple[bool, int]

Call a function using the DBI (and its current state).

clearAllCache(self: pyqbdi.VM) → None

Clear the entire translation cache.

clearCache(self: pyqbdi.VM, start: int, end: int) → None

Clear a specific address range from the translation cache.

deleteAllInstrumentations(self: pyqbdi.VM) → None

Remove all the registered instrumentations.

deleteInstrumentation(self: pyqbdi.VM, id: int) → None

Remove an instrumentation.

getBBMemoryAccess(self: pyqbdi.VM) → List[pyqbdi.MemoryAccess]

Obtain the memory accesses made by the last executed basic block.

getFPRState(self: pyqbdi.VM) → pyqbdi.FPRState

Obtain the current floating point register state.

getGPRState(self: pyqbdi.VM) → pyqbdi.GPRState

Obtain the current general purpose register state.

getInstAnalysis(*args, **kwargs)

Overloaded function.

  1. getInstAnalysis(self: pyqbdi.VM, type: pyqbdi.AnalysisType = AnalysisType.ANALYSIS_INSTRUCTION|AnalysisType.ANALYSIS_DISASSEMBLY) -> pyqbdi.InstAnalysis

Obtain the analysis of an instruction metadata. Analysis results are cached in the VM.

  1. getInstAnalysis(self: pyqbdi.VM, type: int) -> pyqbdi.InstAnalysis

Obtain the analysis of an instruction metadata. Analysis results are cached in the VM.

getInstMemoryAccess(self: pyqbdi.VM) → List[pyqbdi.MemoryAccess]

Obtain the memory accesses made by the last executed instruction.

instrumentAllExecutableMaps(self: pyqbdi.VM) → bool

Adds all the executable memory maps to the instrumented range set.

precacheBasicBlock(self: pyqbdi.VM, pc: int) → bool

Pre-cache a known basic block

recordMemoryAccess(self: pyqbdi.VM, type: pyqbdi.MemoryAccessType) → bool

Add instrumentation rules to log memory access using inline instrumentation and instruction shadows.

removeAllInstrumentedRanges(self: pyqbdi.VM) → None

Remove all instrumented ranges.

removeInstrumentedModule(self: pyqbdi.VM, name: str) → bool

Remove the executable address ranges of a module from the set of instrumented address ranges.

removeInstrumentedModuleFromAddr(self: pyqbdi.VM, addr: int) → bool

Remove the executable address ranges of a module from the set of instrumented address ranges using an address belonging to the module.

removeInstrumentedRange(self: pyqbdi.VM, start: int, end: int) → None

Remove an address range from the set of instrumented address ranges.

run(self: pyqbdi.VM, start: int, stop: int) → bool

Start the execution by the DBI.

setFPRState(self: pyqbdi.VM, fprState: pyqbdi.FPRState) → None

Set the FPR state.

setGPRState(self: pyqbdi.VM, gprState: pyqbdi.GPRState) → None

Set the GPR state.

Callback

pyqbdi.InstPosition = <class 'pyqbdi.InstPosition'>

Position relative to an instruction.

Members:

PREINST : Positioned before the instruction.

POSTINST : Positioned after the instruction.

class pyqbdi.MemoryAccess
accessAddress

Address of accessed memory

instAddress

Address of instruction making the access

size

Size of memory access (in bytes)

type

Memory access type (READ / WRITE)

value

Value read from / written to memory

pyqbdi.MemoryAccessType = <class 'pyqbdi.MemoryAccessType'>

Memory access type (read / write / …)

Members:

MEMORY_READ : Memory read access

MEMORY_WRITE : Memory write access

MEMORY_READ_WRITE : Memory read/write access

pyqbdi.VMAction = <class 'pyqbdi.VMAction'>

The callback results.

Members:

CONTINUE : The execution of the basic block continues.

BREAK_TO_VM : The execution breaks and returns to the VM causing a complete reevaluation of the execution state. A BREAK_TO_VM is needed to ensure that modifications of the Program Counter or the program code are taken into account.

STOP : Stops the execution of the program. This causes the run function to return early.

pyqbdi.VMEvent = <class 'pyqbdi.VMEvent'>

Members:

SEQUENCE_ENTRY : Triggered when the execution enters a sequence.

SEQUENCE_EXIT : Triggered when the execution exits from the current sequence.

BASIC_BLOCK_ENTRY : Triggered when the execution enters a basic block.

BASIC_BLOCK_EXIT : Triggered when the execution exits from the current basic block.

BASIC_BLOCK_NEW : Triggered when the execution enters a new (~unknown) basic block.

EXEC_TRANSFER_CALL : Triggered when the ExecBroker executes an execution transfer.

EXEC_TRANSFER_RETURN : Triggered when the ExecBroker returns from an execution transfer.

class pyqbdi.VMState
basicBlockEnd

The current basic block end address which can also be the execution transfer destination.

basicBlockStart

The current basic block start address which can also be the execution transfer destination.

event

The event(s) which triggered the callback (must be checked using a mask: event & BASIC_BLOCK_ENTRY).

sequenceEnd

The current sequence end address which can also be the execution transfer destination.

sequenceStart

The current sequence start address which can also be the execution transfer destination.

InstAnalysis

pyqbdi.AnalysisType = <class 'pyqbdi.AnalysisType'>

Instruction analysis type

Members:

ANALYSIS_INSTRUCTION : Instruction analysis (address, mnemonic, …)

ANALYSIS_DISASSEMBLY : Instruction disassembly

ANALYSIS_OPERANDS : Instruction operands analysis

ANALYSIS_SYMBOL : Instruction symbol

class pyqbdi.InstAnalysis
address

Instruction address (if ANALYSIS_INSTRUCTION)

affectControlFlow

True if instruction affects control flow (if ANALYSIS_INSTRUCTION)

disassembly

Instruction disassembly (if ANALYSIS_DISASSEMBLY)

instSize

Instruction size (in bytes) (if ANALYSIS_INSTRUCTION)

isBranch

True if instruction acts like a ‘jump’ (if ANALYSIS_INSTRUCTION)

isCall

True if instruction acts like a ‘call’ (if ANALYSIS_INSTRUCTION)

isCompare

True if instruction is a comparison (if ANALYSIS_INSTRUCTION)

isPredicable

True if instruction contains a predicate (~is conditional) (if ANALYSIS_INSTRUCTION)

isReturn

True if instruction acts like a ‘return’ (if ANALYSIS_INSTRUCTION)

mayLoad

True if instruction ‘may’ load data from memory (if ANALYSIS_INSTRUCTION)

mayStore

True if instruction ‘may’ store data to memory (if ANALYSIS_INSTRUCTION)

mnemonic

LLVM mnemonic (if ANALYSIS_INSTRUCTION)

module

Instruction module name (if ANALYSIS_SYMBOL and found)

numOperands

Number of operands used by the instruction (if ANALYSIS_OPERANDS)

operands

Structure containing analysis results of an operand provided by the VM (if ANALYSIS_OPERANDS)

symbol

Instruction symbol (if ANALYSIS_SYMBOL and found)

symbolOffset

Instruction symbol offset (if ANALYSIS_SYMBOL)

class pyqbdi.OperandAnalysis
flag

Operand flag

regAccess

Register access type (r, w, rw)

regCtxIdx

Register index in VM state

regName

Register name

regOff

Sub-register offset in register (in bits)

size

Operand size (in bytes)

type

Operand type

value

Operand value (if immediate), or register Id

pyqbdi.RegisterAccessType = <class 'pyqbdi.RegisterAccessType'>

Access type (R/W/RW) of a register operand

Members:

REGISTER_UNUSED : Unused register

REGISTER_READ : Register read access

REGISTER_WRITE : Register write access

REGISTER_READ_WRITE : Register read/write access

pyqbdi.OperandType = <class 'pyqbdi.OperandType'>

Operand type

Members:

OPERAND_INVALID : Invalid operand

OPERAND_IMM : Immediate operand

OPERAND_GPR : Register operand

OPERAND_PRED : Predicate operand

pyqbdi.OperandFlag = <class 'pyqbdi.OperandFlag'>

Operand flag

Members:

OPERANDFLAG_NONE : No flag

OPERANDFLAG_ADDR : The operand is used to compute an address

OPERANDFLAG_PCREL : The value of the operand is PC relative

OPERANDFLAG_UNDEFINED_EFFECT : The operand role isn’t fully defined

Memory and process map

pyqbdi.getModuleNames() → List[str]

Get a list of all the module names loaded in the process memory.

pyqbdi.getCurrentProcessMaps(full_path: bool = False) → List[pyqbdi.MemoryMap]

Get a list of all the memory maps (regions) of the current process.

pyqbdi.getRemoteProcessMaps(pid: int, full_path: bool = False) → List[pyqbdi.MemoryMap]

Get a list of all the memory maps (regions) of a process.

pyqbdi.Permission = <class 'pyqbdi.Permission'>

Memory access rights.

Members:

PF_NONE : No access

PF_READ : Read access

PF_WRITE : Write access

PF_EXEC : Execution access

class pyqbdi.MemoryMap
name

Region name (useful when a region is mapping a module).

permission

Region access rights (PF_READ, PF_WRITE, PF_EXEC).

range

A range of memory (region), delimited between a start and an (excluded) end address.

pyqbdi.alignedAlloc(size: int, align: int) → int

Allocate a block of memory of a specified sized with an aligned base address.

pyqbdi.alignedFree(ptr: int) → None

Free a block of aligned memory allocated with alignedAlloc.

pyqbdi.allocateVirtualStack(gprstate: pyqbdi.GPRState, size: int) → object

Allocate a new stack and setup the GPRState accordingly. The allocated stack needs to be freed with alignedFree(). The result was int, or None if the allocation fails.

pyqbdi.simulateCall(ctx: pyqbdi.GPRState, returnAddress: int, args: List[int] = []) → None

Simulate a call by modifying the stack and registers accordingly.

Range

class pyqbdi.Range
contains(*args, **kwargs)

Overloaded function.

  1. contains(self: pyqbdi.Range, t: int) -> bool

Return True if an value is inside current range boundaries.

  1. contains(self: pyqbdi.Range, r: pyqbdi.Range) -> bool

Return True if a range is inside current range boundaries.

end

Range end value (always excluded).

intersect(self: pyqbdi.Range, r: pyqbdi.Range) → pyqbdi.Range

Return the intersection of two ranges.

overlaps(self: pyqbdi.Range, r: pyqbdi.Range) → bool

Return True if a range is overlapping current range lower or/and upper boundary.

size(self: pyqbdi.Range) → int

Return the total length of a range.

start

Range start value.

Miscellaneous

pyqbdi.__arch__
pyqbdi.__platform__
pyqbdi.__preload__

Library load with pyqbdipreload

pyqbdi.__os__
pyqbdi.__version__

Version of QBDI

PyQBDI Bindings Helpers

In addition of C++ API, some helper are available:

Memory helpers

pyqbdi.readMemory(address: int, size: int) → bytes

Read a content from a base address.

Parameters:
  • address – Base address
  • size – Read size
Returns:

Bytes of content.

Warning

This API is hazardous as the whole process memory can be read.

pyqbdi.readRword(address: int) → int

Read a rword to the specified address

Parameters:address – Base address
Returns:the value as a unsigned integer

Warning

This API is hazardous as the whole process memory can be read.

pyqbdi.writeMemory(address: int, bytes: str) → None

Write a memory content to a base address.

Parameters:
  • address – Base address
  • bytes – Memory content

Warning

This API is hazardous as the whole process memory can be written.

pyqbdi.writeRword(address: int, value: int) → None

Write a rword in a base address.

Parameters:
  • address – Base address
  • value – The value to write, as a unsigned integer

Warning

This API is hazardous as the whole process memory can be written.

pyqbdi.allocateRword() → int

Allocate a raw memory space to store a rword.

Returns:Address to a memory space to store a rword
pyqbdi.allocateMemory(length: int) → int

Allocate a raw memory space of specified length.

Parameters:length – length of the memory space to allocate
Returns:Address to the allocated memory
pyqbdi.freeMemory(address: int) → None

Free a memory space allocate with allocateRword or allocateMemory.

Parameters:address – Address of the allocated memory

Float helpers

pyqbdi.encodeFloat(val: float) → int

Encode a float as a signed integer.

Parameters:val – Float value
Returns:a sigend integer
pyqbdi.decodeFloat(val: int) → float

Encode a sigend integer as a float.

Parameters:val – signed integer value
Returns:a float
pyqbdi.encodeFloatU(val: float) → int

Encode a float as an unsigned interger.

Parameters:val – Float value
Returns:an unsigned integer
pyqbdi.decodeFloatU(val: int) → float

Encode an unsigend integer as a float.

Parameters:val – unsigned integer value
Returns:a float
pyqbdi.encodeDouble(val: float) → int

Encode a double as a signed integer.

Parameters:val – Double value
Returns:a sigend integer
pyqbdi.decodeDouble(val: int) → float

Encode a sigend integer as a double.

Parameters:val – signed integer value
Returns:a double
pyqbdi.encodeDoubleU(val: float) → int

Encode a double as an unsigned interger.

Parameters:val – Double value
Returns:an unsigned integer
pyqbdi.decodeDoubleU(val: int) → float

Encode an unsigend integer as a double.

Parameters:val – unsigned integer value
Returns:a double

For more conversion, you may want to use the struct library of Python.