[memhack] DLL Reference - Redacted-Rice/ITB-RedactedRiceExts GitHub Wiki
DLL Reference
The memhack DLL provides low-level memory and process access functions. These functions are the foundation that powers all struct operations, but you typically don't need to call them directly.
Additional to the functions defined here, the DLL also provides a C++ implementation of a [[memory scanner | [memhack] scanner] which can be used real time. This is useful for reverse engineering and also for finding dynamic values run time with no clear pointer chain found via reverse engineering
Prefer Using Structs Instead
For modders: You should use the struct system instead of calling DLL functions directly. This documentation is mainly for understanding how memhack works internally or for advanced use cases.
The struct system provides significant advantages over direct DLL calls:
- Type safety/using the correct type
- Automatic validation of the memory to the degree defined by the struct
- Instant event/hook firing via setters
- Convinience & Readability - its easier to use and tell whats going on using the structs
When to Use DLL Directly
You might need direct DLL access for:
- Reverse engineering unknown memory structures
- Advanced memory scanning or pattern matching
- Working internal to memhack with struct manager
Safety Warnings
Important: Direct memory access can easily crash the game or corrupt the game state and save file. These should be mostly mitigating using the existing structs and the added game functions for accessing them
Overview
The memhack DLL is exposed at memhack.dll and provides three main interfaces:
memhack.dll.memory- Memory read/write operationsmemhack.dll.process- Process informationmemhack.dll.scanner- Runtime capable scanner. Separated out into its own page.
Memory Operations
The memory interface provides functions for reading and writing different data types.
Read Functions
| Function | Return Type | Description |
|---|---|---|
readByte(address) |
int | Read 1 byte (0-255) |
readInt(address) |
int | Read 4-byte signed integer |
readBool(address) |
bool | Read 1-byte boolean |
readFloat(address) |
float | Read 4-byte float |
readDouble(address) |
double | Read 8-byte double |
readPointer(address) |
int | Read 4-byte pointer (32-bit address) |
readNullTermString(address, maxLength) |
string | Read null-terminated string |
readByteArray(address, length) |
string | Read binary data |
Write Functions
| Function | Description |
|---|---|
writeByte(address, value) |
Write 1 byte |
writeInt(address, value) |
Write 4-byte signed integer |
writeBool(address, value) |
Write 1-byte boolean |
writeFloat(address, value) |
Write 4-byte float |
writeDouble(address, value) |
Write 8-byte double |
writePointer(address, value) |
Write 4-byte pointer |
writeNullTermString(address, value, maxLength) |
Write null-terminated string |
writeByteArray(address, value) |
Write binary data |
Memory Management
| Function | Description |
|---|---|
allocNullTermString(str) |
Allocate memory for string, returns pointer |
freeNullTermString(address) |
Free memory allocated by allocNullTermString |
isAccessAllowed(address, size, isWrite) |
Check if memory region is accessible |
getAccessibleSize(address, isWrite) |
Returns how many bytes are accessible from address for read/write |
getUserdataAddr(userdata) |
Get memory address of Lua userdata object |
Constants
| Name | Value | Description |
|---|---|---|
MAX_NULL_TERM_STRING_LENGTH |
2048 |
Maximum null terminated string length for string read/write helpers |
MAX_BYTE_ARRAY_LENGTH |
65536 |
Maximum byte array length for byte-array helpers |
Process Operations
| Function | Return Type | Description |
|---|---|---|
getExeBase() |
int | Get base address of game executable |
getHeapRegions(write) |
table | Get list of heap memory regions (see below) |
getHeapRegions
Returns a table of heap memory regions. Each region has:
base- Base address of the regionsize- Size of the region in bytesend- End address of the region (base + size)
The write parameter (boolean) determines whether to return writable regions only.
Example:
-- Get readable heap regions
local regions = memhack.dll.process.getHeapRegions(false)
for i, region in ipairs(regions) do
LOG(string.format("Region %d: 0x%X - 0x%X (size: %d)",
i, region.base, region.end, region.size))
end
Example: Direct Memory Access
Note: You should use structs instead of direct DLL calls when possible.
Note: If you are replacing objects in the game, do NOT deallocate them as the game will handle it. Only deallocate if you are using it on the Lua side and not passing ownership to the game
-- Reading memory directly
local address = 0x12345678
local value = memhack.dll.memory.readInt(address)
LOG("Value at address: " .. value)
-- Writing memory directly
memhack.dll.memory.writeInt(address, 42)
-- Getting game's base address
local exeBase = memhack.dll.process.getExeBase()
LOG(string.format("Game exe base: 0x%X", exeBase))
-- Allocating string memory
local str = "Hello World"
local strPtr = memhack.dll.memory.allocNullTermString(str)
LOG(string.format("Allocated string at: 0x%X", strPtr))
-- We allocated and kept ownership so we need to free as well
memhack.dll.memory.freeNullTermString(strPtr)
Example: Getting Userdata Address
Get the memory address of a game object:
local pawn = Board:GetPawn(0)
local pawnAddr = memhack.dll.memory.getUserdataAddr(pawn)
LOG(string.format("Pawn is at address: 0x%X", pawnAddr))
local game = Game
local gameAddr = memhack.dll.memory.getUserdataAddr(game)
LOG(string.format("Game object at: 0x%X", gameAddr))
Example: Memory Validation
Check if memory is safe to access:
local address = 0x12345678
local size = 256
local isReadable = memhack.dll.memory.isAccessAllowed(address, size, false)
local isWritable = memhack.dll.memory.isAccessAllowed(address, size, true)
if isReadable then
local data = memhack.dll.memory.readByteArray(address, size)
end