Reading Cross-Process Memory Data for Android Mobile Game Reverse Engineering
Reading Target Process Memory
To read memory from a target Android game, we first need the app's PID, which we already know how to dynamically retrieve. We will use a Linux system call to read cross-process memory, demonstrated with a shooter game example.
Memory Reading via process_vm_readv Syscall
Linux provides the process_vm_readv system call accessed via the __NR_process_vm_readv call number. This system call enables direct memory transfer between separate processes, elimintaing extra data copying steps and keeping overhead low for memory reading tasks.
process_vm_readv requires the following arguments:
- PID of the target process to read memory from
- Pointer to a local
struct iovecarray describing output buffers in the current process - Number of
iovecentries in the local array - Pointer to a remote
struct iovecarray describing memory regions to read in the target process - Number of
iovecentries in the remote array - Unused flags, set to 0 for this use case
Practical Implementation Example
With PID already obtained, the only missing information is the target memory address holding the value we want to read. We can use Game Guardian to locate the address of the in-game score variable:
- Launch the game and search for the initial score (usually 0) in Game Guardian
- Defeat enemies to change the score, then search for the new updated score
- Repeat the refinement process until you are left with a single address that matches the current score value
In this test example, the resulting address from Game Guardian is 13168330 in hexadecimal, so we use 0x13168330 as the target address in code. We also need to specify the number of bytes to reead: for 64-bit Android 12, we read 8 bytes for an integer value in this example.
The base function for reading an integer from the target process is:
int read_target_int(pid_t target_pid, long long target_addr) {
struct iovec local_iov, remote_iov;
int result_buf;
local_iov.iov_base = &result_buf;
local_iov.iov_len = 8;
remote_iov.iov_base = (void *)target_addr;
remote_iov.iov_len = 8;
syscall(__NR_process_vm_readv,
target_pid,
&local_iov,
1,
&remote_iov,
1,
0);
return result_buf;
}
Call the function with your obtained PID and target address to get the score:
long long score_addr = 0x13168330;
int current_score = read_target_int(target_pid, score_addr);
printf(