Introduction
Welcome modder!
Native Memory Scripter is a plugin which allows you to create a native plugin by writing Python scripts. This saves a lot of time and makes the process of native plugin dev a lot easier.
You can find all the information you need in this technical document. If there are any api’s missing or things that you feel can/should be improved, don’t hesitate to make an issue report or even a pr.
Features
- Use Python to manipulate memory
- Assembly of plaintext asm / disassembly of bytes
- Virtual method table hooking
- Module search, loading, and unloading
- Segment search (pages)
- External symbol search in modules with name demangling support
- Import address table search and hooking
- Pattern scanning for bytes in memory (supports AVX2, SSE4.2, and regular scalar scanning)
- Memory manipulation (read, write, set, and allocate memory)
- Call native functions from python, and hook (vmt, iat, and jmp) native functions with a python callback, along with trampoline to call the original
- Powered by a JIT compiler
- Written in Rust 🦀
License
This software has a source-available non-open source license. This software:
- may only be used in personal use for the purpose in which it was redistributed by the original creator
- may be forked, however modifications are not allowed
- may be compiled in its unmodified form
- modifications and compiling with modifications are allowed under the condition that you submit your changes back to the main repo
- cannot be redistributed
- cannot be used/re-used in your own projects
- cannot be used for any commercial purposes
- cannot be sold
- code cannot be used in any way for any purpose. it is copyrighted
For full terms, please see the license
Disclaimer
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Configuration
The configuration uses toml and is stored at native-memory-scripter.toml
alongside the dll.
dev
This section contains developer settings.
key | type | description |
---|---|---|
console | bool | Shows or hides the debug console. |
dev_mode | bool | Shows or hides dev mode.1 |
Dev mode is a special mode that spawns an interactive python interpreter window that you can script in while the game is running
log
This section controls the built in logger.
key | type | description |
---|---|---|
level | str | Allows you to fine tune what gets logged. |
targets | bool | Show or hide log targets.2 |
A target is a piece of information that describes what part of the code a particular message came from. The target is the code’s namespace by default.
Project Layout and Setup
In the same directory native-memory-scripter.dll
is inside, the directory layout will be as follows
│ native-memory-scripter.dll
│ native-memory-scripter.log
│ native-memory-scripter.toml
│
└───native-scripts
│
├───script
│ plugin.toml
│ main.py
│ module1.py
│
└───_packages
└───libs
package1.py
At the top level is the dll’s config file and a log file.
Plugin folder names can be named anything, but it’s strongly recommended to stick to the same name as your plugin.
Native Plugin Scripts
Each native plugin script must be placed in a folder, along with a plugin.toml
describing the plugin and a main.py
which is the plugin’s entry point. Each plugin is concurrently run in a separate python interpreter. Scripts may import any local module from their own directory, e.g. import module1
.
Plugin details
Every plugin must provide a plugin.toml
that describes the plugin
[plugin]
name = "My Plugin Name"
author = "Plugin Author"
description = "Description of my plugin"
version = "0.1.0"
Libraries
The _packages
directory is where modules are stored that can be used across multiple scripts. Every script can import from here with e.g. from libs import package1
Best Practices
It is important to keep some best practices in mind when making a script, so that things continue to work properly.
Please ensure you follow these tips carefully.
Code with API changes in mind
Code with API changes in mind
Api may change between plugin versions as this product is updated.
Because of that, it is very important to script against specific versions of native memory scripter so you can account for any api changes and keep things running smoothly with no errors on the user side. Using this technique, you can support multiple versions seamlessly. You can check the plugin version in your script by using info.version. All api changes are catalogued in the changelog.
Beware of Dropping
Beware of Dropping
Objects that require allocation such as WStr
, Callable
, and others, automatically free their memory when deleted or reclaimed by gc. This can serve as a source of hidden UB since it can cause a UAF. Because of this, even allocated code can suddenly disappear during execution!
Make sure that any allocated objects in Python stay alive during the duration you’re using them. This is absolutely crucial. This especially applies when returning some allocated data from a callback function. If the data goes out of scope, python reclaims it in gc, so your returned data is now UAF.
If you need to debug if something is dropping prematurely, turning on trace logs which will help you determine when drops are happening.
Tips and Tricks
Use the struct
module
Use the struct
module
Use the python struct
module to pack and unpack custom structs over ffi.
Let’s say you received a ptr to a struct:
#![allow(unused)] fn main() { #[repr(C)] struct Foo { foo: u32, bar: u64, baz: *const () // platform sized ptr } }
Then you could pack or unpack it in python like so
import struct
class Foo:
def __init__(self, bar, baz, some_ptr):
self.bar = bar
self.baz = baz
self.some_ptr = some_ptr
def pack(self):
return struct.pack('IQP', self.bar, self.baz, self.some_ptr)
@classmethod
def unpack(cls, packed):
bar, baz, some_ptr = struct.unpack('IQP', packed)
return cls(bar, baz, some_ptr)
Store bytes in hex
Store bytes in hex
This is relatively simple, but useful way to store your bytes in a readable format.
mybytes = bytes.fromhex('00 00 00 00')
Here be Dragons 🐉
This goes without saying, but anything can happen when editing a process’s memory. This requires extensive knowledge, reverse engineering, and a delicate touch. There is no limit to the UB this can cause. Most of these functions are unsafe and will easily cause UB if used wrong. A crash is the best case scenario.
You have been warned! Author takes no responsibility in case of accidents.
If you need help with anything or need to understand api safety invariants, feel free to visit my discord.
FAQ
Why does it keep crashing?
This is almost certainly the result of UB. See if you can check the following:
-
are the function arguments correct?
-
is the function return correct?
-
is the function abi correct?
-
are you following all safety invariants when reading, writing, and changing protections on memory?
-
is the address you’re hooking able to be hooked at the assembly level? not all addresses will work because of things like function size or where you placed the hook.
-
if executing the trampoline fails, did you hook at a location where relocating old instructions to the trampoline works? for example, instructions which are relative to their location cannot be relocated.
asm
This module allows you to assemble and disassemble assembly instructions
Function: assemble
Assembles asm instruction(s) from a string
This function is safe
Parameters
This function has multiple calling types.
First
Assemble a single instruction
code: str
- a string with the instruction to assemble, e.g.jmp [rip]
Second
Assemble multiple instructions (with runtime address)
code: str
- a string with the instructions to assemble, e.g.jmp [rip]; nop
.runtime_address: int
- the address to annotate each instruction with.
Exceptions
If instruction fails to assemble
Return Value
Returns an Inst
representing the assembled instruction
Function: code_len
Given a starting address and minimum length, finds the closest byte length that form valid instructions
This function is unsafe 🐉
- The
code
address must at minimum be valid for reads frommin_length
up to the nearest instruction end
Parameters
code: int
- the starting address of the codemin_length: int
- the minimum desired byte length you want
Exceptions
If it fails to diassemble
Return Value
Returns an int
representing the length in bytes of the nearest valid instructions to the min_length
Function: disassemble
Disassemble instructions.
Parameters
This function has multiple calling types.
First (address)
Disassemble single instruction at address.
This call is unsafe 🐉
Address must be valid for up to 16 bytes read.
address: int
- the starting address of the code to disassemble.
Second (address)
Disassemble all instructions from an address, with a runtime address.
This call is unsafe 🐉
Address must be valid for up to size read.
address: int
- the starting address of the code to disassemble.size: int
- how many bytes into the address to read.runtime_address: int
- the address to annotate each instruction with.
Third (address)
Disassemble count
instructions from address.
This call is unsafe 🐉
Address must be valid for up to size read.
address: int
- the starting address of the code to disassemble.size: int
- how many bytes into the address to read.runtime_address: int
- the address to annotate each instruction with.count: int
- how many instructions to disassemble.
First (bytes)
Disassemble all bytes from into instructions.
This call is safe
bytes: bytes
- the bytes to disassemble.
Second (bytes)
Disassemble all bytes from into instructions, with runtime address.
This call is safe
bytes: bytes
- the bytes to disassemble.runtime_address: int
- the address to annotate each instruction with.
Third (bytes)
Disassemble count
instructions from address.
This call is safe
bytes: bytes
- the bytes to disassemble.runtime_address: int
- the address to annotate each instruction with.count: int
- how many instructions to disassemble.
Exceptions
If it fails to diassemble
Return Value
Returns an Inst
representing the disassembled instruction
Example
import asm
foo = bytes.fromhex('00 00 00 00')
insts = asm.disassemble(foo)
# pretty print each instruction
for i in insts:
print(i)
objects
Object: Inst
An assembly instruction
Properties
address: int
If the runtime_address
parameter was used, this will be the instruction’s offset from that base address. Otherwise, the address starts at a default offset of 0
.
bytes: bytearray
The instructions binary data.
mnemonic: str
The instruction’s mnemonic.
op_str: str
The instruction’s operands.
cffi
This module allows you to call C functions from python, or use python callbacks for your hooks, as well as allowing you to call the trampoline.
How?
This leverages a JIT compiler to generate a machine code wrapper on the fly which has the same signature as the original native function. This wrapper then translates the native args to python, calls your python function with the args, and translates the return value back to native. In this way, it’s transparent, just as if it were the real function. This also generates a trampoline to call the original code.
In the case of NativeCall
– just the trampoline portion is used.
The bundled python interpreter is also compiled with JIT support to make your python functions run faster, though this may compile only under limited circumstances right now.
You must manually enable it. To make use of it, call __jit__()
on any python function. If your function is uncompilable, you will quickly know as it’ll throw an exception.
Module: Type
These types are meant to be used in NativeCall
and Callable
.
Floats
Python type: int
F32
F64
Unsigned
Python type: int
U8
U16
U32
U64
U128
Signed
Python type: int
I8
I16
I32
I64
I128
Strings
CStr
Python type: str
When received as a Callback
argument or a NativeCall
return, it’s a python string without null terminator. When used as a NativeCall
argument and Callback
return, you MUST include a null terminator in the string.
WStr
NativeCall
return type / Callback
argument: int
(pointer to address)
NativeCall
argument / Callback
return type: WStr
This may or may not be null terminated, depends on api requirements. Some functions require you to pass a length, sometimes it needs to be null terminated. This is up to you to manage according to the api.
On a Callback
, an argument of this type will be a ptr. On a NativeCall
, a return of this type will be a ptr. In order to convert the ptr into a string you can use, see WStr
.
To return a WStr
from a Callback
, or give a WStr
argument to a NativeCall
, use WStr
.
Chars
Python type: str
Char
Python type: str
(1 character that can fit in a u8
)
1 byte
WChar
Python type: str
(1 character that can fit in a u16
)
2 bytes
Misc
Ptr
Python type: int
Bool
Python type: boolean
Struct(size: int)
Python type: bytes
This is a by-value struct (not a ptr to a struct). You can use this type in arg or return position to indicate receiving or returning a struct by value.
The size must be correct or it’ll be ub.
Example
import cffi
def foo(arg: int):
pass
c = cffi.Callable(foo, cffi.Types.U64)
Module: Conv
These types are meant to be used in NativeCall
and Callable
.
Calling Conventions
C
This is the default.
WindowsFastcall
Stdcall
Example
import cffi
def foo():
pass
c = cffi.Callable(foo, cffi.Types.U64, conv = cffi.Conv.C)
objects
Object: Callable
Hook a function and use a python function as the hooks callback.
Constructor
Callable[[*args], Any]
- Any args and Any return type. Constrained to the types available inType
. Must match the following signature passed in to the constructor.*args
- AnyType
’s matching the corresponding native function’s argument types.**kwargs
-ret
for theType
return value, andconv
to change the calling convention.
Drop
The allocated callback code and trampoline code will automatically be freed when this is deleted or reclaimed.
Properties
address: int
The address of the jitted callback function (the code that is a stand-in replacement of a native function and calls your python callback).
code_size: int
The size of the jitted callback function in bytes.
trampoline_address:
The address of the underlying trampoline (the trampoline fn that the jitpoline calls).
trampoline_size
The size of the underlying trampoline.
jitpoline_address
The address of the jitpoline (the jitted trampoline that __call__
calls).
Magic
This object implements __call__()
. You may call this object with your args and it will call the trampoline.
Using the call function is unsafe 🐉
You must use the correct arguments / return types, otherwise using the function will be ub.
Additionally, your callback function MUST gracefully handle all possible exceptions and return something. If it there’s an uncaught exception, it is UB. But to protect the program, it will instantly crash instead. You should fix it asap.
If you specified a return type, you MUST always return a value of that type, even if your function caught an exception.
Methods
hook
jmp
hook from
address. This will attempt to allocate within ± 2GB of from
address so it can use a 5
byte jmp
, but if it’s unable to it will use 14
byte jmp
.
This function is unsafe 🐉
from
must point to axr
function with the same signature as your callable (abi, parameters, and return).
hook_iat
Hook an import address table entry.
This function is unsafe 🐉
entry: IATSymbol
- the iat symbol to hook.
Exceptions
If virtual protect fails.
hook_vmt
Hook a virtual method table entry.
This function is unsafe 🐉
index
must be a valid index, and abi, args, and return must all be correct types.
vtable: VTable
- the vtable within which to hook.index: int
- the index of the vtable method to hook.
Exceptions
If virtual protect fails.
unhook
Unhook the callback.
This function is unsafe 🐉
Exceptions
If virtual protect fails.
Example
import modules
import symbols
import cffi
# this will be called every time the original code calls "createTestClass"
def foo():
# call the trampoline
val = callable(obj)
return val
module = modules.load("Dll1.dll")
create = symbols.find(module, "createTestClass")
callable = cffi.Callable(foo, ret = cffi.Type.U64)
callable.hook(create)
# unhook the callback
callable.unhook()
Object: NativeCall
Call a native function from Python.
Constructor
address: int|Symbol
- The address orSymbol
to call.*args
- AnyType
’s matching the corresponding native function’s argument types.**kwargs
-ret
for theType
return value, andconv
to change the calling convention.
Drop
The allocated code will automatically be freed when this is deleted or reclaimed.
Magic
This object implements __call__()
. You may call this object with your args and it will call the underlying native function.
Using the call function is unsafe 🐉
You must use the correct arguments / return types, otherwise calling this is ub.
Example
import modules
import symbols
import cffi
module = modules.load("Dll1.dll")
create = symbols.find(module, "createTestClass")
one = symbols.find(module, "callTestMethod")
two = symbols.find(module, "callTestMethod2")
create = cffi.NativeCall(create, ret = cffi.Type.U64)
obj = create()
one = cffi.NativeCall(one, cffi.Type.U64)
one(obj)
two = cffi.NativeCall(two, cffi.Type.U64)
two(obj)
Object: WStr
Converts a WStr
python string to a wstr pointer, or a pointer to a python string.
Drop
Memory is freed when this object is deleted or reclaimed by gc.
Constructor
This constructor has two ways to call it. One way to convert a python string to WStr
, and another way to convert an address to a python string.
Python string to WStr
When used this way, it converts your python string to a type that you can return in a Callable
or give as an argument to a NativeCall
.
This call is safe
data: str
- the string to convert toWStr
. do not put a null terminator in it, use the kwarg for that.**kwargs
-null: boolean
- insert a null terminator at the end of your string.
Address to WStr
When used this way, it converts a WStr
pointer to this type, allowing you to access it as a python string.
Use either one of the null
or len
kwargs to tell this type how to decode the string from the address. Only 1 of these is allowed, do not use both kwargs.
This call is unsafe 🐉
address
must be a valid address for reads up tolen
or up to the next null terminator
address: int
- theWStr
pointer address.**kwargs
-null: boolean
- decode a string with a null terminator.**kwargs
-len: int
- decode a string with a specific length. this is not byte length. this is element length. that is, one element is a u16 (2 bytes).**kwargs
-lossy: boolean
- do not raise exception if provided string is not valid utf8. Warning, will return a string yes, but invalid characters will have been replaced with�
.
Using the type
To convert a WStr
to a regular python string, just do str(foo)
on your WStr
type.
Properties
size: int
The byte size of the WStr
. (The number of u16
elements is size / 2
)
address: int
The address to the WStr
’s buffer.
Exceptions
If you supply an address and both null and len kwargs.
If you supply the address but neither null or len kwargs.
If the utf16 string to decode from an address is not a valid utf8 string (try using the lossy kwarg!).
If the first arg is not an address (int
) or str
.
If there is no first arg.
If you provide types to arg or kwargs that do not match the listed types.
hook
This module allows you to use regular jmp hooks.
How?
The from
address is replaced with a 5 or 14 byte jmp (depending on whether target address is within 32-bits or not).
The old code that was replaced is placed at the beginning of the trampoline, and a jmp is made back to the original function, but right after the original jmp we placed.
The custom hook function is free to call the trampoline if it wishes to.
The jmp can actually be placed anywhere, not necessarily at the beginning of the function. But you will have to make sure that this works properly in the assembly.
Certain instructions cannot be relocated to the trampoline. For example, instructions which use a relative address require themselves to be at the original address. It is your job to ensure the location that gets replaced is capable of being replaced. Or you could also just not call the trampoline.
Function: hook
Hooks an address by placing a jmp at the target and creating a trampoline to execute the original function.
This function is unsafe 🐉
from
must be a valid address which can be written to, and must be a valid location to write a jmp of 5 or 14 bytes at.to
must be a valid target location, and must properly handle the requirements of the assembly at the jmp site.
If the from
address is within 32-bits of the to
address, will write a 5 byte jmp, otherwise will write a 14 byte jmp.
Parameters
from: int
- the address to hook.to: int
- the address to redirect thefrom
address to.
Exceptions
If virtual protect fails, or fails to get the underlying code len.
Return Value
Returns a Trampoline
which can be used to execute the original code at the hooked location.
objects
Object: Trampoline
An import address table symbol.
Drop
Trampoline will free the underlying trampoline code, and unhook the target.
Properties
address: int
The address of the trampoline function.
size: int
The size of the trampoline function in bytes.
Methods
unhook
Unhook the hooked function.
This function is unsafe 🐉
Exceptions
If virtual protect fails.
iat
This module allows one to search through a Module
’s IAT (import address table) and hook the entries.
How?
The module’s internal structures to find its import addresss table, then we extract the needed information from it. After that, all that needs to be done is write a new ptr to the iat’s entry for that specific function.
Function: enum
Returns a list of all import address table entries in a Module
.
This function is safe
Parameters
module:
- the module to get the symbols for.Module
Exceptions
If module in memory is invalid or cannot otherwise be read.
Return Value
Returns a [IATSymbol]
Function: enum_demangled
Returns a list of all import address table entries in a Module
and demangles the names.
This function is safe
Parameters
module:
- the module to get the symbols for.Module
Exceptions
If module in memory is invalid or cannot otherwise be read.
Return Value
Returns a [IATSymbol]
Function: find
Finds an IATSymbol
in a module Module
.
This function is safe
Parameters
This function has two calling signatures.
Name / Ordinal
module:
- the module to get the symbols for.Module
name: str|u16
- the symbol name or ordinal number to look for. must be exact case-sensitive match.
Name / Ordinal and Dll name
module:
- the module to get the symbols for.Module
dll_name: str
- the dll name to look for the symbol in. is an exact case sensitive match, e.g.fooBar.dll
.name: str|u16
- the symbol name or ordinal number to look for. must be exact case-sensitive match.
Exceptions
If module in memory is invalid or cannot otherwise be read.
Return Value
Returns a IATSymbol
if found, or None
if not found.
Function: find_demangled
Finds an IATSymbol
in a module Module
and demangles its name.
This function is safe
Parameters
This function has two calling signatures.
Name
module:
- the module to get the symbols for.Module
name: str
- the symbol name to look for. must be exact case-sensitive match.
Name and Dll name
module:
- the module to get the symbols for.Module
dll_name: str
- the dll name to look for the symbol in. is an exact case sensitive match, e.g.fooBar.dll
.name: str
- the symbol name to look for. must be a case-sensitive fuzzy match. this means your search term matches by case-exactly, however it is a contains search, e.g. searching forFooBar
invoid symbol FooBarBaz()
matches, butfoobar
won’t match.
Exceptions
If module in memory is invalid or cannot otherwise be read.
Return Value
Returns a IATSymbol
if found, or None
if not found.
objects
Object: IATSymbol
An import address table symbol.
Drop
IAT entry will automatically unhook itself once deleted or garbage collected.
Properties
name: Optional[str]
The name of the symbol.
ordinal: Optional[int]
The ordinal of the symbol.
dll_name: str
The name of the dll.
orig_fn: int
A pointer to the original iat entry function.
iat: int
A pointer to this IAT entry. Writing an address to this will hook it.
Methods
hook
Hook this iat entry.
This function is unsafe 🐉
address
must point to axr
function with the same signature as the original (abi, parameters, and return).
address: int
- the function address to redirect the iat entry to.
Exceptions
If virtual protect fails.
unhook
Unhook this iat entry.
This function is unsafe 🐉
Exceptions
If virtual protect fails.
info
This module contains useful native memory scripter plugin information to scripts. This can also give you context in your scripts.
One such useful property is version, which gives you native memory scripter’s current version. This lets you handle api changes gracefully even when there are different native memory scripter versions installed on users computers.
Property: version
gets the version of the plugin
Return Value
Example
import info
version = info.version
if version.major == 0 and version.minor == 1:
pass
objects
Version
represents the plugin’s version
Properties
major: int
The plugin’s major version number
minor: int
The plugin’s minor version number
patch: int
The plugin’s patch version number
log
This module contains functions for printing different log types to the console or log file.
Function: trace
Log a trace message to the console/log file.
This function is safe
Parameters
*args
- any parameter to log.[kwarg] sep: str
- the separator. default' '
.
Exceptions
If object string and repr can’t be printed.
Function: debug
Log a debug message to the console/log file.
This function is safe
Parameters
*args
- any parameter to log.[kwarg] sep: str
- the separator. default' '
.
Exceptions
If object string and repr can’t be printed.
Function: info
Log an info message to the console/log file.
This function is safe
Parameters
*args
- any parameter to log.[kwarg] sep: str
- the separator. default' '
.
Exceptions
If object string and repr can’t be printed.
Function: warn
Log a warning message to the console/log file.
This function is safe
Parameters
*args
- any parameter to log.[kwarg] sep: str
- the separator. default' '
.
Exceptions
If object string and repr can’t be printed.
Function: error
Log an error message to the console/log file.
This function is safe
Parameters
*args
- any parameter to log.[kwarg] sep: str
- the separator. default' '
.
Exceptions
If object string and repr can’t be printed.
mem
This module contains the api for editing the current processes memory.
Function: alloc
Allocates size
bytes of memory with protection flags Prot
in the calling process.
This function is safe
Parameters
size: int
- the size of memory to be allocated. If the size is 0, the function will allocate a full page of memory. If a specific size is provided, that amount of memory will be allocated, aligned to the next page size.prot: Prot
- the protection flags.
Exceptions
If allocation failed.
Return Value
Returns an Alloc
.
Function: alloc_granularity
The granularity for the starting address at which virtual memory can be allocated.
This function is safe
Return Value
Returns an int
.
Function: alloc_in
Allocates size
bytes of memory with protection flags Prot
in the calling process.
This function is safe
Parameters
This function can be called in 2 ways:
With align
begin_addr: int
- the beginning address of the region you want to allocate inside. this will be rounded up to the next system allocation granularity.end_addr: int
- the ending address of the region you want to allocate inside. this will be rounded down to previous system allocation granularity.size: int
- the size of memory to be allocated.align: int
- the power-of-2 alignment. align must be0
, or power-of-2, >= system allocation granularity, and must be a multiple of system allocation granularity. specifying0
automatically aligns on the system allocation granularity.prot: Prot
- the protection flags.
Without align
Align will automatically be set to 0
for this.
begin_addr: int
- the beginning address of the region you want to allocate inside. this will be rounded up to the next system allocation granularity.end_addr: int
- the ending address of the region you want to allocate inside. this will be rounded down to previous system allocation granularity.size: int
- the size of memory to be allocated.prot: Prot
- the protection flags.
Exceptions
If allocation failed. If begin_addr >= end_addr
. If align
is not power of 2, less than system allocation granularity, or not a multiple of system allocation granularity. If begin addresses next rounded up to granularity is not within begin..end
. If end address rounded down to granularity is not within begin..end
. If begin and/or end addresses are outside of minimum/maximum application address.
Return Value
Returns an Alloc
.
Function: deep_pointer
Calculates a deep pointer address by applying a series of offsets to a base address and dereferencing intermediate pointers.
This function is unsafe 🐉
Parameters
base: int
- the base address to start at.offsets: [int]
- the offsets used to navigate through the memory addresses. must be unsigned.
Exceptions
If memory address is null, or no offsets were provided.
Return Value
An int
representing the final address.
Function: read
Reads size
bytes starting at src
address into bytearray.
This function is unsafe 🐉
src
must be a valid address for reads up tosize
Parameters
src: int
- the base address to read from.size: int
- the amount of bytes to read.
Return Value
Returns a bytearray
of the read bytes.
Function: set
Set dst
address + size
bytes to byte
This function is unsafe 🐉
dst
must be a valid address for writes up tosize
Parameters
dst: int
- the destination address to write to.byte: int
- the byte to set the memory to.size: int
- the amount of bytes from thedst
to set.
Function: write
Write some bytes to dst
.
This function is unsafe 🐉
dst
must be a valid address for writes up to size of bytearray.
Parameters
src: bytearray
- the bytes to write to target.dst: int
- the destination address to write to.
Function: prot
Change the protection of a block of memory.
This function is unsafe 🐉
Parameters
address: int
- the base address to change the protection on.size: int
- how many bytes from the base address to change.prot:
- the protection flag.Prot
Exceptions
If changing the protection failed.
Return Value
The old Prot
.
objects
Object: Alloc
An allocation.
Drop
Memory will be automatically freed when deleted or gc reclaims it.
Properties
address: int
The address of the allocation.
Object: Prot
The protection flags.
Properties
NONE: Prot
No protection flags
X: Prot
Executable flag
R: Prot
Read flag
W: Prot
Write flag
XR: Prot
Executable + Read flag
XW: Prot
Executable + Write flag
RW: Prot
Read + Write flag
XRW: Prot
Executable + Read + Write flag
Example
import mem
flag = mem.Prot.X
modules
This module lets one find, enumerate over, load, and unload modules.
Function: load
Load a dll into the process.
This function is safe
Parameters
path: str
- the full path to the dll.
Exceptions
If LoadLibraryW
fails.
Return Value
Returns a Module
.
Function: unload
Unload a module from the process.
This function is safe
Modules are only ever unloaded from a process once their internal refcount reaches 0. This only decreases the refcount by 1.
Don’t repeatedly call this without reason, or you will unload the module from memory prematurely when it’s still being used 🐉.
Parameters
path: str
- the full path to the dll.
Exceptions
If GetModuleHandleW
or FreeLibrary
fails.
Function: find
Find a module by name.
This function is safe
Parameters
name: str
- the name to search for. exact case-sensitive match, including extension. e.g.foobar.dll
.
Exceptions
If unable to create a snapshot, no modules exist, unable to convert from utf16 to utf8, or load library.
Return Value
Returns a Module
if found, None
if not found.
Function: enum
Return a list of all modules
This function is safe
Exceptions
If unable to create a snapshot, no modules exist, unable to convert from utf16 to utf8, or load library.
Return Value
Returns a [
containing all of the process’s modules.Module
]
objects
Object: Module
A module.
Drop
Module will unload once gc collects this.
An unloaded module does not necessarily mean it’s unloaded from memory. Windows holds a refcount, and when free library is called, the refcount decreases by 1. This handle increases refcount by 1 when it’s made so it’s always safe to use as long as the handle is alive, thus it’s safe to decrease it by 1.
Properties
base: int
The base address of the module.
end: int
The end address of the module.
size: int
The size of the module.
path: str
The full path to the module.
name: str
The name of the module, e.g. foobar.dll
.
popup
This module lets you create windows popups.
Please only use this for things that are important. Spamming pointless popups is really bad ux. Prefer logging over popups, and popups only as a last resort.
Function: error
Shows an error popup.
This function is safe
Parameters
title: str
- the title of the popup.message: str
- the message in the popup.
Function: exclamation
Shows an exclamation popup.
This function is safe
Parameters
title: str
- the title of the popup.message: str
- the message in the popup.
Function: info
Shows an info popup.
This function is safe
Parameters
title: str
- the title of the popup.message: str
- the message in the popup.
Function: question
Shows a question popup.
This function is safe
Parameters
title: str
- the title of the popup.message: str
- the message in the popup.
Function: warn
Shows a warning popup.
This function is safe
Parameters
title: str
- the title of the popup.message: str
- the message in the popup.
scan
This module contains functions for searching through memory for pattern masks.
If the computer has AVX2, this is used. If not, but it has SSE4.2, then this is used. If it has none of those, then a regular scalar search is used.
AVX2 and SSE4.2 can reach search speeds of about 1.8gb/s, and scalar search can reach about 1gb/s.
Function: data
Scan for a given set of bytes starting at address
for scan_size
bytes.
This function is unsafe 🐉
address
must be a valid address for reads up toscan_size
scan_size
must be a valid length
Parameters
data: bytearray
- the data to search for.address: int
- the address to start looking from.scan_size: int
- how many bytes to search for from the starting address.
Return Value
On success, it returns an int
representing the found location’s memory address. On failure, it returns None
.
Function: pattern
Searches address
for scan_size
bytes for a match given some bytes and a pattern.
This function is unsafe 🐉
address
must be a valid address for reads up toscan_size
scan_size
must be a valid length
Parameters
pattern: bytearray
- the data to search for. if some bytes are masked out, it’s customary to leave them at0
.mask: str
- the mask for the bytes. usex
for a known byte and?
for an unknown byte. example,xx?x?xx?
address: int
- the starting address to look for the pattern at.scan_size: int
- how many bytes to search for from the starting address.
Return Value
On success, it returns an int
representing the found location’s memory address. On failure, it returns None
.
Function: sig
Searches address
for scan_size
bytes for a given IDA-style signature.
This function is unsafe 🐉
address
must be a valid address for reads up toscan_size
scan_size
must be a valid length
Parameters
sig: str
- an IDA-style signature to search for, e.g.11 22 33 ?? 44 ?? 55 ?? ??
, where11
is a known byte and??
is an unknown byte.address: int
- the starting address to look for the pattern at.scan_size: int
- how many bytes to search for from the starting address.
Return Value
On success, it returns an int
representing the found location’s memory address. On failure, it returns None
.
segments
This module finds segments (pages) within a Module
.
Function: enum
Return a list of all segments
This function is safe
Return Value
Returns a [
containing all of the process’s segments.Segment
]
Function: find
Finds the segment of a given address.
This function is safe
Parameters
address: int
- the address you want to find belongs to what segment.
Return Value
Returns the Segment
corresponding to the address. If it cannot find it, will return None
.
objects
Object: Segment
A Module
’s external symbol.
Properties
base: int
The base address of the segment.
end: int
The end address of the segment.
size: int
The size of the segment.
prot: Prot
The protection of the segment.
symbols
This module finds and demangles external symbols from a Module
.
Function: demangle
Demangle a symbol.
Supports C++ (GCC-style compilers and MSVC), Rust (both legacy and v0), Swift (up to Swift 5.3), and ObjC (only symbol detection).
This function is safe
Parameters
name: str
- the mangled symbol to demangle.
Return Value
On success, it returns str
representing the demangled symbol. On failure, it returns None
.
Function: enum
Returns a list of all symbols for a Module
.
This function is safe
Parameters
module:
- the module to get all symbols from.Module
Exceptions
If module memory is invalid, or cannot find any exports.
Return Value
Returns a [
.Symbol
]
Function: enum_demangled
Returns a list of all demangled symbols for a Module
.
This function is safe
Parameters
module:
- the module to get all demangled symbols from.Module
Exceptions
If module memory is invalid, or cannot find any exports.
Return Value
Returns a [
.Symbol
]
Function: find
Returns the memory address of a symbol. The search is case-sensitive and must be an exact match.
This function is safe
Parameters
module:
- the module to search through.Module
name: str
- the name of the symbol to search for. case-sensitive exact search.
Exceptions
If module memory is invalid, or cannot find any exports.
Return Value
Returns an int
representing the memory address of the symbol. If not found, returns None
.
Function: find_demangled
Returns the memory address of a demangled symbol. The search is fuzzy, but case-sensitive.
This function is safe
Parameters
module:
- the module to search through.Module
name: str
- the name of the symbol to search for. case-sensitive fuzzy search. this means your search term matches by case-exactly, however it is a contains search, e.g. searching forFooBar
invoid symbol FooBarBaz()
matches, butfoobar
won’t match.
Exceptions
If module memory is invalid, or cannot find any exports.
Return Value
Returns an int
representing the memory address of the symbol. If not found, returns None
.
objects
Object: Symbol
A Module
’s external symbol.
Properties
name: str
The name of the of the module, e.g. foobar.dll
.
address: int
The address of the symbol.
vtable
This module contains helpers to hook c++ virtual method tables.
How?
We find the correct index offset in the vtable’s array of pointers and write a new ptr to that location.
objects
VTable
Hook a c++ vtable.
Constructor
address: int
- the base address of the vtable.
Drop
When this is deleted, it will automatically reset all hooks.
Methods
hook
Hooks a vtable by index.
This function is unsafe 🐉
index
must be a valid vtable index.dst
must point to axr
function with the same signature as the original (abi, parameters, and return).
index: int
- the index to hook.dst: int
- the function address to redirect the vtable entry to.
Exceptions
If virtual protect fails.
unhook
Unhooks a vtable by index.
This function is unsafe 🐉
index
must be a valid previously hooked vtable index.
index: int
- the index to unhook.
Exceptions
If virtual protect fails.
get_original
Get a pointer to the original function stored at a previously hooked index.
This function is safe
index: int
- the index to unhook.
Return Value
Returns an int
representing a ptr to the original vtable function if index was previously hooked, otherwise returns None
.
reset
Resets all previously hooked vtable entries back to their original functions.
This function is unsafe 🐉
Exceptions
If virtual protect fails.