smallworld.emulators¶
- class smallworld.emulators.Emulator(platform: Platform)¶
An emulation environment.
- Parameters:
platform – Platform metadata for emulation.
- abstractmethod read_register_content(name: str) int¶
Read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- Raises:
SymbolicValueError – If the register contains a non-collapsible symbolic value
- read_register_symbolic(name: str) BV¶
Read the content of a register, allowing symbolic output.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
name – The name of the register
- Returns:
The register’s content as a z3 expression
- read_register_type(name: str) Any | None¶
Read the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s type
- read_register_label(name: str) str | None¶
Read the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s label.
- read_register(name: str) int¶
A helper to read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- abstractmethod write_register_content(name: str, content: None | int | BV) None¶
Write some content to a register.
- Parameters:
name – The name of the register to write.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- write_register_type(name: str, type: Any | None = None) None¶
Write the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
type – The type of the register to write. To unset the register type, this may be set to None.
- write_register_label(name: str, label: str | None = None) None¶
Write the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
label – The label of the register to write. To unset the register label, this may be set to None.
- write_register(name: str, content: None | int | BV) None¶
A helper to write the content of a register.
- Parameters:
name – The name of the register.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator cannot handle bitvector expressions
- abstractmethod read_memory_content(address: int, size: int) bytes¶
Read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- read_memory_symbolic(address: int, size: int) BV¶
Read memory content from a specific address as a symbolic expression.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
A z3 expression of size * 8 bits read from address
- read_memory_type(address: int, size: int) Any | None¶
Read memory type from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s type.
- read_memory_label(address: int, size: int) str | None¶
Read memory label from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s label.
- read_memory(address: int, size: int) bytes¶
A helper to read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address.
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- abstractmethod map_memory(address: int, size: int) None¶
Map memory of a given size.
If the requested allocation overlaps with existing regions, this will fill in the gaps.
- Parameters:
address – The requested address of the allocation.
size – The size of the allocation.
- abstractmethod get_memory_map() List[Tuple[int, int]]¶
Retrieve the memory map as understood by the emulator.
- Returns:
The list of tuples (start, end) of the mapped segments
- abstractmethod write_memory_content(address: int, content: bytes | BV) None¶
Write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator can’t handle them
- write_memory_type(address: int, size: int, type: Any | None = None) None¶
Set the type of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
type – The type of the register to write. To unset the register type, this may be set to None.
- write_memory_label(address: int, size: int, label: str | None = None) None¶
Set the label of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
label – The label of the register to write. To unset the register label, this may be set to None.
- write_memory(address: int, content: bytes | BV) None¶
A helper to write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- write_code(address: int, content: bytes) None¶
Write executable memory at a specific address.
Implementations can take advantage of this if they store code and memory differently.
Otherwise, it should be identical to write_memory().
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- get_bounds() List[Tuple[int, int]]¶
Get a list of all registered execution bounds.
- Returns:
A list of registered execution bounds.
- add_bound(start: int, end: int) None¶
Add valid execution bounds.
If execution leaves these bounds Emulators should raise EmulationBoundsError.
If execution bounds are not specified, Emulators should allow execution anywhere.
- Parameters:
start – The start address of a valid executable region.
end – The end address of a valid executable region.
- get_exit_points() Set[int]¶
Get a list of all registered exit points.
- Returns:
A list of registered exit points.
- add_exit_point(address: int) None¶
Add an exit point.
If execution reaches an exit point emulation should stop.
- Parameters:
address – The address of the exit point.
- abstractmethod step_instruction() None¶
Single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- abstractmethod step_block() None¶
Single block step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- step() None¶
Helper for single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- abstractmethod run() None¶
Run execution indefinitely.
Emulation should stop if an exit point is reached or execution leaves valid bounds.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- get_thumb() bool¶
For applicable platforms, checks if the CPU is in ARM or Thumb mode.
- Returns:
True if in Thumb mode, otherwise False.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- set_thumb(enabled=True) None¶
For applicable platforms, set the CPU to Thumb or ARM mode.
- Parameters:
enabled – True for Thumb mode, False for ARM mode.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- abstract property description: str¶
A description of this analysis.
Descriptions should be a single sentence, lowercase, with no final punctuation for proper formatting.
- abstract property name: str¶
The name of this analysis.
Names should be kebab-case, all lowercase, no whitespace for proper formatting.
- abstract property version: str¶
The version string for this analysis.
We recommend using Semantic Versioning
- class smallworld.emulators.InstructionHookable¶
An Emulator mixin that supports instruction hooking.
- abstractmethod hook_instruction(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific instruction by address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- abstractmethod unhook_instruction(address: int) None¶
Unhook a specific instruction by address.
- Parameters:
address – The address of the hook to remove.
- abstractmethod unhook_instructions() None¶
Unhook all system interrupts.
- class smallworld.emulators.FunctionHookable¶
An Emulator mixin that supports function hooking.
- abstractmethod hook_function(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific function by address.
After the hook function is called, the Emulator will step out of the current function so that the hook essentially replaces a function call to the given address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- abstractmethod unhook_function(address: int) None¶
Unhook a specific function by address.
- Parameters:
address – The address of the hook to remove.
- class smallworld.emulators.MemoryReadHookable¶
An Emulator mixin that supports memory read hooking.
- abstractmethod hook_memory_read(start: int, end: int, function: Callable[[Emulator, int, int, bytes], bytes | None]) None¶
Hook memory reads within a given range, handling concrete values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: bytes ) -> bytes: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_read_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook memory reads within a given range, handling symbolic values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- abstractmethod unhook_memory_read(start: int, end: int) None¶
Unhook a specific memory region read by address range.
- Parameters:
start – The start address of the memory read hook to remove.
end – The end address of the memory read hook to remove.
- abstractmethod hook_memory_reads(function: Callable[[Emulator, int, int, bytes], bytes | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, data: bytes ) -> typing.Optional[bytes]: # "data" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_reads_symbolic(function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "data" represents the data fetched by the emulator # The return value is what should be reported to the guest ...
- abstractmethod unhook_memory_reads() None¶
Unhook any ‘all reads’ handlers
- class smallworld.emulators.MemoryWriteHookable¶
An Emulator mixin that supports memory write hooking.
- abstractmethod hook_memory_write(start: int, end: int, function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook memory writes within a given range, handling concrete values.
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_write_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], None]) None¶
Hook memory writes within a given range, handling symbolic values
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- abstractmethod unhook_memory_write(start: int, end: int) None¶
Unhook a specific memory region write by address range.
- Parameters:
start – The start address of the memory write hook to remove.
end – The end address of the memory write hook to remove.
- abstractmethod hook_memory_writes(function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook all memory writes, handling concrete values.
- Parameters:
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_writes_symbolic(function: Callable[[Emulator, int, int, BV], None]) None¶
Hook all memory writes, handling symbolic values
- Parameters:
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- abstractmethod unhook_memory_writes() None¶
Unhook any global memory write hook.
- class smallworld.emulators.InterruptHookable¶
An Emulator mixin that supports interrupt hooking.
- abstractmethod hook_interrupts(function: Callable[[Emulator, int], None]) None¶
Hook any system interrupts.
- Parameters:
function – The function to execute when an interrupt is triggered.
Example
The hook function looks like:
def hook(emulator: Emulator, interrupt: int) -> None: ...
- abstractmethod unhook_interrupts() None¶
Unhook all system interrupts.
- abstractmethod hook_interrupt(interrupt: int, function: Callable[[Emulator], None]) None¶
Hook a specific system interrupt.
- Parameters:
function – The function to execute when the interrupt is triggered.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- abstractmethod unhook_interrupt(interupt: int) None¶
Unhook a specific system interrupt.
- Parameters:
interrupt – The interrupt to unhook.
- class smallworld.emulators.ConstrainedEmulator¶
Emulator that supports constraints
It must also support some means of evaluating constraints, probably an SMT solver or similar.
- abstractmethod add_constraint(expr: Bool) None¶
Add a constraint to the emulator
A constraint is an expression that this emulator will use to limit the possible values of unbound variables. It will only consider execution states where all constraints can evaluate to True.
Constraints must be Boolean expressions; the easiest form is the equality or inequality of two bitvector expressions.
- Parameters:
expr – The constraint expression to add
- abstractmethod get_constraints() List[Bool]¶
Retrieve all constraints applied to this emulator.
- Returns:
A list of constraint expressions
- abstractmethod satisfiable(extra_constraints: List[Bool] = []) bool¶
Check if the current set of constraints is satisfiable
This checks if there’s a way to assign variables such that all constraint expressions evaluate to “True”. If not, the state can’t exist as described.
The emulator tracks its own set of constraints, added by the harness or built up durring execution. The caller can provide additional constraints for testing. These are not permanently added to the emulator.
- Parameters:
extra_constraints – A list of additional constraints to consider.
- Returns:
True if the constraint system is satisfiable. False otherwise.
- abstractmethod eval_atmost(expr: BV, most: int) List[int]¶
Find a maximum number of solutions to a bitvector expression
This attempts to find concrete solutions to expr given the constraints on the emulator.
It will return between 1 and most solutions, inclusive. It will raise exceptions if there are no solutions, or more than requested.
- Parameters:
expr – The expression to evaluate
most – The inclusive upper limit on solutions
- Returns:
A list of integer solutions to expr
- Raises:
UnsatError – If there are no solutions for expr given constraints
SymbolicValueError – If there are more than most solutions for expr given constraints
- abstractmethod eval_atleast(expr: BV, least: int) List[int]¶
Find a minimum number of solutions to a bitvector expression
This attempts to find concrete solutions to expr given the constraints on the emulator.
It will return least solutions. It will raise an exception if there are fewer than least solutions possible.
- Parameters:
expr – The expression to evaluate
least – The number of solutions to retrieve
- Returns:
A list of integer solutions to expr
- Raises:
UnsatError – If there are no solutions for expr given constraints
SymbolicValueError – If there are fewer than least solutions for expr given constraints
- class smallworld.emulators.UnicornEmulator(platform: Platform)¶
An emulator for the Unicorn emulation engine.
- read_register_content(name: str) int¶
Read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- Raises:
SymbolicValueError – If the register contains a non-collapsible symbolic value
- read_register_label(name: str) str | None¶
Read the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s label.
- read_register(name: str) int¶
A helper to read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- write_register_content(name: str, content: None | int | BV) None¶
Write some content to a register.
- Parameters:
name – The name of the register to write.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- write_register_label(name: str, label: str | None = None) None¶
Write the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
label – The label of the register to write. To unset the register label, this may be set to None.
- write_register(name: str, content: None | int | BV) None¶
A helper to write the content of a register.
- Parameters:
name – The name of the register.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator cannot handle bitvector expressions
- read_memory_content(address: int, size: int) bytes¶
Read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- read_memory_label(address: int, size: int) str | None¶
Read memory label from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s label.
- read_memory(address: int, size: int) bytes¶
A helper to read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address.
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- map_memory(address: int, size: int) None¶
Map memory of a given size.
If the requested allocation overlaps with existing regions, this will fill in the gaps.
- Parameters:
address – The requested address of the allocation.
size – The size of the allocation.
- get_memory_map() List[Tuple[int, int]]¶
Retrieve the memory map as understood by the emulator.
- Returns:
The list of tuples (start, end) of the mapped segments
- write_memory_content(address: int, content: bytes | BV) None¶
Write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator can’t handle them
- write_memory_label(address: int, size: int, label: str | None = None) None¶
Set the label of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
label – The label of the register to write. To unset the register label, this may be set to None.
- write_memory(address: int, content: bytes | BV) None¶
A helper to write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- hook_instruction(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific instruction by address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- hook_function(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific function by address.
After the hook function is called, the Emulator will step out of the current function so that the hook essentially replaces a function call to the given address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- get_thumb() bool¶
For applicable platforms, checks if the CPU is in ARM or Thumb mode.
- Returns:
True if in Thumb mode, otherwise False.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- set_thumb(enabled=True) None¶
For applicable platforms, set the CPU to Thumb or ARM mode.
- Parameters:
enabled – True for Thumb mode, False for ARM mode.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- step_instruction() None¶
Single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- step_block() None¶
Single block step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- run() None¶
Run execution indefinitely.
Emulation should stop if an exit point is reached or execution leaves valid bounds.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- add_bound(start: int, end: int) None¶
Add valid execution bounds.
If execution leaves these bounds Emulators should raise EmulationBoundsError.
If execution bounds are not specified, Emulators should allow execution anywhere.
- Parameters:
start – The start address of a valid executable region.
end – The end address of a valid executable region.
- add_exit_point(address: int) None¶
Add an exit point.
If execution reaches an exit point emulation should stop.
- Parameters:
address – The address of the exit point.
- get_bounds() List[Tuple[int, int]]¶
Get a list of all registered execution bounds.
- Returns:
A list of registered execution bounds.
- get_exit_points() Set[int]¶
Get a list of all registered exit points.
- Returns:
A list of registered exit points.
- hook_interrupt(intno: int, function: Callable[[Emulator], None]) None¶
Hook a specific system interrupt.
- Parameters:
function – The function to execute when the interrupt is triggered.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- hook_interrupts(function: Callable[[Emulator, int], None]) None¶
Hook any system interrupts.
- Parameters:
function – The function to execute when an interrupt is triggered.
Example
The hook function looks like:
def hook(emulator: Emulator, interrupt: int) -> None: ...
- hook_memory_read(start: int, end: int, function: Callable[[Emulator, int, int, bytes], bytes | None]) None¶
Hook memory reads within a given range, handling concrete values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: bytes ) -> bytes: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_read_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook memory reads within a given range, handling symbolic values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_reads(function: Callable[[Emulator, int, int, bytes], bytes | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, data: bytes ) -> typing.Optional[bytes]: # "data" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_reads_symbolic(function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "data" represents the data fetched by the emulator # The return value is what should be reported to the guest ...
- hook_memory_write(start: int, end: int, function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook memory writes within a given range, handling concrete values.
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_write_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], None]) None¶
Hook memory writes within a given range, handling symbolic values
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_writes(function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook all memory writes, handling concrete values.
- Parameters:
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_writes_symbolic(function: Callable[[Emulator, int, int, BV], None]) None¶
Hook all memory writes, handling symbolic values
- Parameters:
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- read_memory_symbolic(address: int, size: int) BV¶
Read memory content from a specific address as a symbolic expression.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
A z3 expression of size * 8 bits read from address
- read_memory_type(address: int, size: int) Any | None¶
Read memory type from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s type.
- read_register_symbolic(name: str) BV¶
Read the content of a register, allowing symbolic output.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
name – The name of the register
- Returns:
The register’s content as a z3 expression
- read_register_type(name: str) Any | None¶
Read the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s type
- step() None¶
Helper for single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- unhook_function(address: int) None¶
Unhook a specific function by address.
- Parameters:
address – The address of the hook to remove.
- unhook_instruction(address: int) None¶
Unhook a specific instruction by address.
- Parameters:
address – The address of the hook to remove.
- unhook_instructions()¶
Unhook all system interrupts.
- unhook_interrupt(intno: int) None¶
Unhook a specific system interrupt.
- Parameters:
interrupt – The interrupt to unhook.
- unhook_interrupts()¶
Unhook all system interrupts.
- unhook_memory_read(start: int, end: int) None¶
Unhook a specific memory region read by address range.
- Parameters:
start – The start address of the memory read hook to remove.
end – The end address of the memory read hook to remove.
- unhook_memory_reads()¶
Unhook any ‘all reads’ handlers
- unhook_memory_write(start: int, end: int) None¶
Unhook a specific memory region write by address range.
- Parameters:
start – The start address of the memory write hook to remove.
end – The end address of the memory write hook to remove.
- unhook_memory_writes()¶
Unhook any global memory write hook.
- write_code(address: int, content: bytes) None¶
Write executable memory at a specific address.
Implementations can take advantage of this if they store code and memory differently.
Otherwise, it should be identical to write_memory().
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- write_memory_type(address: int, size: int, type: Any | None = None) None¶
Set the type of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
type – The type of the register to write. To unset the register type, this may be set to None.
- write_register_type(name: str, type: Any | None = None) None¶
Write the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
type – The type of the register to write. To unset the register type, this may be set to None.
- exception smallworld.emulators.UnicornEmulationError(uc_err: UcError, pc: int, msg: str, details: dict)¶
- add_note()¶
Exception.add_note(note) – add a note to the exception
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- exception smallworld.emulators.UnicornEmulationMemoryReadError(uc_err: UcError, pc: int, msg: str, details: dict)¶
- add_note()¶
Exception.add_note(note) – add a note to the exception
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- exception smallworld.emulators.UnicornEmulationMemoryWriteError(uc_err: UcError, pc: int, msg: str, details: dict)¶
- add_note()¶
Exception.add_note(note) – add a note to the exception
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- exception smallworld.emulators.UnicornEmulationExecutionError(uc_err: UcError, pc: int, msg: str, details: dict)¶
- add_note()¶
Exception.add_note(note) – add a note to the exception
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- class smallworld.emulators.AngrEmulator(platform: Platform, preinit=None, init=None)¶
Angr symbolic execution emulator
This is primarily designed to support symbolic execution, although subclasses can configure angr however they like.
One challenge with symbolic execution is that it doesn’t work on a single machine state, but rather multiple machine states representing parallel execution paths.
As such, this interface doesn’t yet fully support all features of the base Emulator class; it’s not clear what reading or writing machine state means when there’s more than one state.
- initialize()¶
Initialize the emulator
To take advantage of CLE, we need to know about all code before we initialize the angr state objects. However, applying register and memory changes requires access to the angr state object.
SmallWorld doesn’t support ordering how state is applied, so I need to collect it, then apply it once emulation starts.
This function is invoked automatically when you cycle the emulator, but you’re free to invoke it early if you want.
- read_register_symbolic(name: str) BV¶
Read the content of a register, allowing symbolic output.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
name – The name of the register
- Returns:
The register’s content as a z3 expression
- read_register_content(name: str) int¶
Read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- Raises:
SymbolicValueError – If the register contains a non-collapsible symbolic value
- read_register_type(name: str) Any | None¶
Read the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s type
- read_register_label(name: str) str | None¶
Read the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s label.
- write_register_content(name: str, content: None | int | BV) None¶
Write some content to a register.
- Parameters:
name – The name of the register to write.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- write_register_type(name: str, type: Any | None = None) None¶
Write the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
type – The type of the register to write. To unset the register type, this may be set to None.
- write_register_label(name: str, label: str | None = None) None¶
Write the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
label – The label of the register to write. To unset the register label, this may be set to None.
- read_memory_content(address: int, size: int) bytes¶
Read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- read_memory_symbolic(address: int, size: int) BV¶
Read memory content from a specific address as a symbolic expression.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
A z3 expression of size * 8 bits read from address
- read_memory_type(address: int, size: int) Any | None¶
Read memory type from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s type.
- read_memory_label(address: int, size: int) str | None¶
Read memory label from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s label.
- map_memory(address: int, size: int) None¶
Map memory of a given size.
If the requested allocation overlaps with existing regions, this will fill in the gaps.
- Parameters:
address – The requested address of the allocation.
size – The size of the allocation.
- get_memory_map() List[Tuple[int, int]]¶
Retrieve the memory map as understood by the emulator.
- Returns:
The list of tuples (start, end) of the mapped segments
- write_memory_content(address: int, content: bytes | BV) None¶
Write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator can’t handle them
- write_memory_type(address: int, size: int, type: Any | None = None) None¶
Set the type of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
type – The type of the register to write. To unset the register type, this may be set to None.
- write_memory_label(address: int, size: int, label: str | None = None) None¶
Set the label of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
label – The label of the register to write. To unset the register label, this may be set to None.
- write_code(address: int, content: bytes)¶
Write executable memory at a specific address.
Implementations can take advantage of this if they store code and memory differently.
Otherwise, it should be identical to write_memory().
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- hook_instruction(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific instruction by address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- unhook_instruction(address: int) None¶
Unhook a specific instruction by address.
- Parameters:
address – The address of the hook to remove.
- unhook_instructions() None¶
Unhook all system interrupts.
- hook_function(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific function by address.
After the hook function is called, the Emulator will step out of the current function so that the hook essentially replaces a function call to the given address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- unhook_function(address: int) None¶
Unhook a specific function by address.
- Parameters:
address – The address of the hook to remove.
- hook_syscall(number: int, function: Callable[[Emulator], None]) None¶
Hook a specific syscall by number.
This hook will fire if emulation hits a platform-specific syscall instruction invoking the specified syscall number.
Emulation will resume at the instruction after the syscall. To change this, the handler should modify the PC register in the emulator.
- Parameters:
number – The syscall number to handle
function – The handler function for this syscall
- unhook_syscall(number: int) None¶
Unhook a specific syscall by number.
- Parameters:
number – The syscall number to unhook
- hook_syscalls(function: Callable[[Emulator, int], None]) None¶
Hook all syscalls
This hook will fire if emulation hits a platform-specific syscall instruction.
Emulation will resume at the instruction after the syscall. To change this, the handler should modify the PC register in the emulator.
- Parameters:
function – The handler function for all syscalls
- unhook_syscalls() None¶
Unhook all syscalls
- hook_memory_read_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook memory reads within a given range, handling symbolic values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_read(start: int, end: int, function: Callable[[Emulator, int, int, bytes], bytes | None])¶
Hook memory reads within a given range, handling concrete values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: bytes ) -> bytes: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- unhook_memory_read(start: int, end: int)¶
Unhook a specific memory region read by address range.
- Parameters:
start – The start address of the memory read hook to remove.
end – The end address of the memory read hook to remove.
- hook_memory_reads_symbolic(function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "data" represents the data fetched by the emulator # The return value is what should be reported to the guest ...
- hook_memory_reads(function: Callable[[Emulator, int, int, bytes], bytes | None])¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, data: bytes ) -> typing.Optional[bytes]: # "data" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- unhook_memory_reads() None¶
Unhook any ‘all reads’ handlers
- hook_memory_write_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], None]) None¶
Hook memory writes within a given range, handling symbolic values
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_write(start: int, end: int, function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook memory writes within a given range, handling concrete values.
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- unhook_memory_write(start: int, end: int) None¶
Unhook a specific memory region write by address range.
- Parameters:
start – The start address of the memory write hook to remove.
end – The end address of the memory write hook to remove.
- hook_memory_writes_symbolic(function: Callable[[Emulator, int, int, BV], None]) None¶
Hook all memory writes, handling symbolic values
- Parameters:
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_writes(function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook all memory writes, handling concrete values.
- Parameters:
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- unhook_memory_writes() None¶
Unhook any global memory write hook.
- step_instruction() None¶
Single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- step_block() None¶
Single block step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- step() None¶
Helper for single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- run()¶
Run execution indefinitely.
Emulation should stop if an exit point is reached or execution leaves valid bounds.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- visit_states(function: Callable[[Emulator], None], stash: str = 'active') None¶
Visit every state in the selected frontier
This lets you work around the fact that most operations only work at emulation start, or in linear mode.
- enable_linear()¶
Enable linear execution
This doesn’t actually concretize anything; it just kills execution when it hits an unconstrained branch.
- get_bounds() List[Tuple[int, int]]¶
Get a list of all registered execution bounds.
- Returns:
A list of registered execution bounds.
- add_bound(start: int, end: int) None¶
Add valid execution bounds.
If execution leaves these bounds Emulators should raise EmulationBoundsError.
If execution bounds are not specified, Emulators should allow execution anywhere.
- Parameters:
start – The start address of a valid executable region.
end – The end address of a valid executable region.
- get_exit_points() Set[int]¶
Get a list of all registered exit points.
- Returns:
A list of registered exit points.
- add_exit_point(address: int) None¶
Add an exit point.
If execution reaches an exit point emulation should stop.
- Parameters:
address – The address of the exit point.
- add_constraint(expr: Bool) None¶
Add a constraint to the emulator
A constraint is an expression that this emulator will use to limit the possible values of unbound variables. It will only consider execution states where all constraints can evaluate to True.
Constraints must be Boolean expressions; the easiest form is the equality or inequality of two bitvector expressions.
- Parameters:
expr – The constraint expression to add
- get_constraints() List[Bool]¶
Retrieve all constraints applied to this emulator.
- Returns:
A list of constraint expressions
- satisfiable(extra_constraints: List[Bool] = []) bool¶
Check if the current set of constraints is satisfiable
This checks if there’s a way to assign variables such that all constraint expressions evaluate to “True”. If not, the state can’t exist as described.
The emulator tracks its own set of constraints, added by the harness or built up durring execution. The caller can provide additional constraints for testing. These are not permanently added to the emulator.
- Parameters:
extra_constraints – A list of additional constraints to consider.
- Returns:
True if the constraint system is satisfiable. False otherwise.
- eval_atmost(expr: BV, most: int) List[int]¶
Find a maximum number of solutions to a bitvector expression
This attempts to find concrete solutions to expr given the constraints on the emulator.
It will return between 1 and most solutions, inclusive. It will raise exceptions if there are no solutions, or more than requested.
- Parameters:
expr – The expression to evaluate
most – The inclusive upper limit on solutions
- Returns:
A list of integer solutions to expr
- Raises:
UnsatError – If there are no solutions for expr given constraints
SymbolicValueError – If there are more than most solutions for expr given constraints
- eval_atleast(expr: BV, least: int) List[int]¶
Find a minimum number of solutions to a bitvector expression
This attempts to find concrete solutions to expr given the constraints on the emulator.
It will return least solutions. It will raise an exception if there are fewer than least solutions possible.
- Parameters:
expr – The expression to evaluate
least – The number of solutions to retrieve
- Returns:
A list of integer solutions to expr
- Raises:
UnsatError – If there are no solutions for expr given constraints
SymbolicValueError – If there are fewer than least solutions for expr given constraints
- add_extension(name: str, ext: Any) None¶
Add extra data to the machine state.
This allows users to tie data structures to the emulator’s execution states, allowing path-specific data tracking.
Only one extension with a given name can be tied to a given state. Usually, extensions are assigned before emulation starts, but it’s perfectly possible to assign them later, either in linear mode, or through the emulator stub provided to a hook.
All extensions must be compatible with copy.deepcopy().
- Parameters:
name – ID string used to retrieve the extension
ext – The extension
- Raises:
KeyError – name is already taken
- get_extension(name: str) Any¶
Fetch extra data from the machine state
- Parameters:
name – ID string used to retrieve the extension
- Returns:
Whatever was assigned to name using add_extension
- Raises:
KeyError – If no extension exists tied to name
- property byteorder: Literal['big', 'little']¶
Get the byteorder string for this platform
- Returns:
‘big’ or ‘little’, appropriately-typed as literals.
- get_thumb() bool¶
For applicable platforms, checks if the CPU is in ARM or Thumb mode.
- Returns:
True if in Thumb mode, otherwise False.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- read_memory(address: int, size: int) bytes¶
A helper to read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address.
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- read_register(name: str) int¶
A helper to read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- set_thumb(enabled=True) None¶
For applicable platforms, set the CPU to Thumb or ARM mode.
- Parameters:
enabled – True for Thumb mode, False for ARM mode.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- write_memory(address: int, content: bytes | BV) None¶
A helper to write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- write_register(name: str, content: None | int | BV) None¶
A helper to write the content of a register.
- Parameters:
name – The name of the register.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator cannot handle bitvector expressions
- exception smallworld.emulators.PathTerminationSignal¶
Exception allowing an analysis to terminate an execution path.
- add_note()¶
Exception.add_note(note) – add a note to the exception
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- class smallworld.emulators.PandaEmulator(platform: Platform, arg_overrides: Dict[str, str] = {})¶
An emulator for the Panda emulation engine.
- Parameters:
arch – Architecture ID string
mode – Mode ID string
byteorder – Byteorder
- class ThreadState(*values)¶
- class PandaThread(manager, thread_state, arg_overrides: Dict[str, str] = {})¶
- run()¶
Method representing the thread’s activity.
You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.
- property daemon¶
A boolean value indicating whether this thread is a daemon thread.
This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.
The entire Python program exits when only daemon threads are left.
- getName()¶
Return a string used for identification purposes only.
This method is deprecated, use the name attribute instead.
- property ident¶
Thread identifier of this thread or None if it has not been started.
This is a nonzero integer. See the get_ident() function. Thread identifiers may be recycled when a thread exits and another thread is created. The identifier is available even after the thread has exited.
- isDaemon()¶
Return whether this thread is a daemon.
This method is deprecated, use the daemon attribute instead.
- is_alive()¶
Return whether the thread is alive.
This method returns True just before the run() method starts until just after the run() method terminates. See also the module function enumerate().
- join(timeout=None)¶
Wait until the thread terminates.
This blocks the calling thread until the thread whose join() method is called terminates – either normally or through an unhandled exception or until the optional timeout occurs.
When the timeout argument is present and not None, it should be a floating-point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened – if the thread is still alive, the join() call timed out.
When the timeout argument is not present or None, the operation will block until the thread terminates.
A thread can be join()ed many times.
join() raises a RuntimeError if an attempt is made to join the current thread as that would cause a deadlock. It is also an error to join() a thread before it has been started and attempts to do so raises the same exception.
- property name¶
A string used for identification purposes only.
It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor.
- property native_id¶
Native integral thread ID of this thread, or None if it has not been started.
This is a non-negative integer. See the get_native_id() function. This represents the Thread ID as reported by the kernel.
- setDaemon(daemonic)¶
Set whether this thread is a daemon.
This method is deprecated, use the .daemon property instead.
- setName(name)¶
Set the name string for this thread.
This method is deprecated, use the name attribute instead.
- start()¶
Start the thread’s activity.
It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.
This method will raise a RuntimeError if called more than once on the same thread object.
- read_register_content(name: str) int¶
Read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- Raises:
SymbolicValueError – If the register contains a non-collapsible symbolic value
- write_register_content(name: str, content: None | int | BV) None¶
Write some content to a register.
- Parameters:
name – The name of the register to write.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- read_memory_content(address: int, size: int) bytes¶
Read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- map_memory(address: int, size: int) None¶
Map memory of a given size.
If the requested allocation overlaps with existing regions, this will fill in the gaps.
- Parameters:
address – The requested address of the allocation.
size – The size of the allocation.
- get_memory_map() List[Tuple[int, int]]¶
Retrieve the memory map as understood by the emulator.
- Returns:
The list of tuples (start, end) of the mapped segments
- write_memory_content(address: int, content: bytes | BV) None¶
Write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator can’t handle them
- run() None¶
Run execution indefinitely.
Emulation should stop if an exit point is reached or execution leaves valid bounds.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- step_block() None¶
Single block step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- add_bound(start: int, end: int) None¶
Add valid execution bounds.
If execution leaves these bounds Emulators should raise EmulationBoundsError.
If execution bounds are not specified, Emulators should allow execution anywhere.
- Parameters:
start – The start address of a valid executable region.
end – The end address of a valid executable region.
- add_exit_point(address: int) None¶
Add an exit point.
If execution reaches an exit point emulation should stop.
- Parameters:
address – The address of the exit point.
- get_bounds() List[Tuple[int, int]]¶
Get a list of all registered execution bounds.
- Returns:
A list of registered execution bounds.
- get_exit_points() Set[int]¶
Get a list of all registered exit points.
- Returns:
A list of registered exit points.
- get_thumb() bool¶
For applicable platforms, checks if the CPU is in ARM or Thumb mode.
- Returns:
True if in Thumb mode, otherwise False.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- hook_function(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific function by address.
After the hook function is called, the Emulator will step out of the current function so that the hook essentially replaces a function call to the given address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- hook_instruction(address: int, function: Callable[[Emulator], None]) None¶
Hook a specific instruction by address.
- Parameters:
address – The address of the hook.
function – The function to execute when the address is reached.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- hook_interrupt(intno: int, function: Callable[[Emulator], None]) None¶
Hook a specific system interrupt.
- Parameters:
function – The function to execute when the interrupt is triggered.
Example
The hook function looks like:
def hook(emulator: Emulator) -> None: ...
- hook_interrupts(function: Callable[[Emulator, int], None]) None¶
Hook any system interrupts.
- Parameters:
function – The function to execute when an interrupt is triggered.
Example
The hook function looks like:
def hook(emulator: Emulator, interrupt: int) -> None: ...
- hook_memory_read(start: int, end: int, function: Callable[[Emulator, int, int, bytes], bytes | None]) None¶
Hook memory reads within a given range, handling concrete values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: bytes ) -> bytes: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_read_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook memory reads within a given range, handling symbolic values
Note that this will trigger for any read that overlaps the specified range, and will report all data read, not just the overlap. Hooks should expect to handle partial or oddly-sized reads.
If the hook chooses to override the data being read, it must return data of the same size as the original read.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is read.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "content" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_reads(function: Callable[[Emulator, int, int, bytes], bytes | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, data: bytes ) -> typing.Optional[bytes]: # "data" represents the information the emulator would have fetched. # The return value is what should be reported to the emulator. # If return is "None", the original value of "content" will be reported. ...
- hook_memory_reads_symbolic(function: Callable[[Emulator, int, int, BV], BV | None]) None¶
Hook all memory reads, handling concrete values
- Parameters:
function – The function to execute when the memory region is read.
Example
The hook function looks like:
def hook( emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV ) -> typing.Optional[claripy.ast.bv.BV]: # "data" represents the data fetched by the emulator # The return value is what should be reported to the guest ...
- hook_memory_write(start: int, end: int, function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook memory writes within a given range, handling concrete values.
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_write_symbolic(start: int, end: int, function: Callable[[Emulator, int, int, BV], None]) None¶
Hook memory writes within a given range, handling symbolic values
Note that this will trigger for any write that overlaps the specified range, and will report all data written, not just the overlap. Hooks should expect to handle partial or oddly-sized writes.
- Parameters:
start – The start address of the memory range to hook.
end – The end address of the memory range to hook.
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_writes(function: Callable[[Emulator, int, int, bytes], None]) None¶
Hook all memory writes, handling concrete values.
- Parameters:
function – The function to execute when the memory region is written.
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- hook_memory_writes_symbolic(function: Callable[[Emulator, int, int, BV], None]) None¶
Hook all memory writes, handling symbolic values
- Parameters:
function – The function to execute when the memory region is written.
- Raises:
NotImplementedError – If this emulator doesn’t support symbolic operations
Example
The hook function looks like:
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None: # "content" is the value written by the guest. # Hooks are responsible for completing the write to the emulator's state ...
- read_memory(address: int, size: int) bytes¶
A helper to read memory content from a specific address.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
size bytes read from address.
- Raises:
SymbolicValueError – If the memory range contains a non-collapsible symbolic value
- read_memory_label(address: int, size: int) str | None¶
Read memory label from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s label.
- read_memory_symbolic(address: int, size: int) BV¶
Read memory content from a specific address as a symbolic expression.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
A z3 expression of size * 8 bits read from address
- read_memory_type(address: int, size: int) Any | None¶
Read memory type from a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region.
- Returns:
The memory region’s type.
- read_register(name: str) int¶
A helper to read the content of a register.
- Parameters:
name – The name of the register.
- Returns:
The register’s content.
- read_register_label(name: str) str | None¶
Read the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s label.
- read_register_symbolic(name: str) BV¶
Read the content of a register, allowing symbolic output.
If the implementation of read_register_content() raises SymbolicValueError, this must be implemented.
- Parameters:
name – The name of the register
- Returns:
The register’s content as a z3 expression
- read_register_type(name: str) Any | None¶
Read the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
- Returns:
The register’s type
- set_thumb(enabled=True) None¶
For applicable platforms, set the CPU to Thumb or ARM mode.
- Parameters:
enabled – True for Thumb mode, False for ARM mode.
- Raises:
ConfigurationError – if not using an ARM32 platform.
NotImplementedError – if not using a supported emulator.
- step() None¶
Helper for single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- step_instruction() None¶
Single instruction step execution.
- Raises:
EmulationBoundsError – if execution steps out of bounds.
- unhook_function(address: int) None¶
Unhook a specific function by address.
- Parameters:
address – The address of the hook to remove.
- unhook_instruction(address: int) None¶
Unhook a specific instruction by address.
- Parameters:
address – The address of the hook to remove.
- unhook_instructions()¶
Unhook all system interrupts.
- unhook_interrupt(intno: int) None¶
Unhook a specific system interrupt.
- Parameters:
interrupt – The interrupt to unhook.
- unhook_interrupts()¶
Unhook all system interrupts.
- unhook_memory_read(start: int, end: int) None¶
Unhook a specific memory region read by address range.
- Parameters:
start – The start address of the memory read hook to remove.
end – The end address of the memory read hook to remove.
- unhook_memory_reads()¶
Unhook any ‘all reads’ handlers
- unhook_memory_write(start: int, end: int) None¶
Unhook a specific memory region write by address range.
- Parameters:
start – The start address of the memory write hook to remove.
end – The end address of the memory write hook to remove.
- unhook_memory_writes()¶
Unhook any global memory write hook.
- write_code(address: int, content: bytes) None¶
Write executable memory at a specific address.
Implementations can take advantage of this if they store code and memory differently.
Otherwise, it should be identical to write_memory().
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- write_memory(address: int, content: bytes | BV) None¶
A helper to write content to memory at a specific address.
Note
Written memory should already be mapped by some call to map_memory().
- Parameters:
address – The address of the memory region.
content – The content to write.
- Raises:
SymbolicValueError – If content is a bitvector expression, and this emulator doesn’t support them.
- write_memory_label(address: int, size: int, label: str | None = None) None¶
Set the label of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
label – The label of the register to write. To unset the register label, this may be set to None.
- write_memory_type(address: int, size: int, type: Any | None = None) None¶
Set the type of memory at a specific address.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
address – The address of the memory region.
size – The size of the memory region
type – The type of the register to write. To unset the register type, this may be set to None.
- write_register(name: str, content: None | int | BV) None¶
A helper to write the content of a register.
- Parameters:
name – The name of the register.
content – The content to write.
- Raises:
TypeError – If content is a BV, and this emulator cannot handle bitvector expressions
- write_register_label(name: str, label: str | None = None) None¶
Write the label of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
label – The label of the register to write. To unset the register label, this may be set to None.
- write_register_type(name: str, type: Any | None = None) None¶
Write the type of a register.
Note
Implementing this behavior is optional and not necessarily supported by all Emulators.
- Parameters:
name – The name of the register.
type – The type of the register to write. To unset the register type, this may be set to None.
- smallworld.emulators.GhidraEmulator(platform: Platform) AbstractGhidraEmulator¶
Factory for creating a GhidraEmulator
Importing any of the pyghidra packages requires booting up a JVM, which takes several seconds. It also doesn’t work if Java and Ghidra are not configured.
Rather than requiring all SmallWorld users to sit through this process, export a factory method that looks exactly like an Emulator constructor. Only boot pyghidra if the factory is called, and only import GhidraEmulator if successful.
See GhidraEmulator in pcode.py for the actua emulator class.
- Parameters:
platform – The platform to use when creating the emulator
- Returns:
A GhidraEmulator object