If you want to search the memory of the emulated PSP using external tools by attaching to the PPSSPP process' memory space in Windows, you're gonna need a pointer to the base address.
To get it, you can use one of the following methods:
Debug -> Copy PSP memory base address
from the menubar (since 1.15)WM_USER_GET_BASE_POINTER
window message (since 1.14)WM_USER_GET_BASE_POINTER
Used to query a pointer to the base address of the PPSSPP process. Available since 1.14.
const UINT WM_USER_GET_BASE_POINTER = WM_APP + 0x3118; // 0xB118
You can send this message with the following values of lParam
to the main window of PPSSPP, to get access to the following information:
0
- Lower 32 bits of pointer to the base of emulated memory1
- Upper 32 bits of pointer to the base of emulated memory2
- Lower 32 bits of pointer to the pointer to the base of emulated memory (since 1.15)3
- Upper 32 bits of pointer to the pointer to the base of emulated memory (since 1.15)The point (hah) of the latter two is that that is valid across execution of multiple games, while the former is not, which may be useful in some cases.
WM_USER_GET_EMULATION_STATE
Returns 1
if a game is running, 0
otherwise.
Available since 1.15.4.
const UINT WM_USER_GET_EMULATION_STATE = WM_APP + 0x3119; // 0xB119
Note that all of the addresses and offsets below represent a PPSSPPWindows64.exe
process running on x86-64 Windows.
A PPSSPPWindows.exe
process running on x86-64 Windows has addressess and offsets that look "similar" enough to be recognizable, but they are all in 32 bits.
PSP Memory Base Address: the address in Windows memory where the emulated PSP's memory starts from (0x0
in PSP memory). Usually something like 0x0000_01??_????_???
or 0x0000_02??_????_????
.
PSP Memory Base Pointer: the pointer to PSP Memory Base Address. The address where the value is the address in Windows memory where the emulated PSP's memory starts from. Its value is the PSP Memory Base Address
. Its address is usually something like 0x0000_7ff?_????_????
.
PSP User Memory Address: the address 0x0880_0000
in the emulated PSP's memory where game data starts from. (Mind the different characters!) The addresses of game variables (offset1 in pointer paths) are higher than this (already contain 0x0880_0000
).
PPSSPP Process Base Address: the address in Windows memory where the memory of a PPSSPPWindows64.exe
process starts from. Often referred to as PPSSPPWindows64.exe. Usually something like 0x0000_7ff?_????_????
.
PPSSPP Base Offset (to PSP Memory Base Pointer): the offset in Windows memory, such that
PPSSPP Process Base Address + PPSSPP Process Base Offset == address of PSP Memory Base Pointer
.
Seems to be between 0x00A0_0000
and 0x0100_0000
. A constant that is usually different for each build.
Memory addresses in Cheat Engine can be saved either in static address format or in pointer format. Pointer format is preferred, because it will keep the memory address valid throughout multiple sessions, as long as you don't switch PPSSPP versions.
Here is an illustration of memory addresses using the terminology above:
Members of ingame composite data types (such as structs and objects) cannot be saved as memory addresses in a way that they would remain valid throughout multiple sessions. The pointer to the start of an object can be saved as such, but in order to calculate the address of any object member we need to delve into Lua scripting.
In the example below we have the object members saved as dummy memory addresses, all children of a Lua script.
The idea is to calculate the addresses of the object members and display the memory addresses when the Lua script is activated.
Here is the said Lua script:
(In the screenshot the base pointer is calculated using a manually retrieved base offset.)
This method will work throughout mutliple sessions.
Things to keep in mind:
-- By "25094" on GitHub
function GetEmuBase()
local command = 0xB118
local emuHWND = findWindow("PPSSPPWnd")
local pointer = {}
local result = sendMessage(emuHWND, command, 0, 0)
pointer[1] = tonumber(result)
result = sendMessage(emuHWND, command, 0, 1)
pointer[2] = tonumber(result)
local lower = pointer[1]
local upper = pointer[2]
local combinedPointer = (upper * 0x100000000) + lower
return tonumber(combinedPointer)
end
You can add this inside of any auto assembler script at the start or inside the enable part and it should run fine if you remember to add {$lua}
before the code.
More will be added in the future.