Manipulating the memory of an arbitrary process allows us to control its internal behavior to cause another operation than the programmed one. For example:
We are going to use the windows crate to manipulate the memory of a process as we wish.
We just need to create a new Rust project and add the windows crate to the dependencies in the Cargo.toml
file.
cargo init --bin memory-hacking
We are going to create a dummy program to manipulate its memory. The dummy program is going to be a simple loop that prints a message every second.
Our dummy program is going to print the process ID, the pointer to the text, and the text itself every second. Our goal is to change the text from another process.
Before we can manipulate the memory of another process, we need to get a handle to it. We are going to use the OpenProcess
function to get the handle. The OpenProcess
function is used to open an existing local process object and returns a handle to the process object. We only need to know the process ID.
We are going to read the memory of the dummy program to get the pointer to the text. We are going to create a function that makes this task easier for us, and we can also pass it any type of primitive data to be able to receive the correct value.
Now we are going to use this in conjunction with what we have written previously. To manipulate data in memory we must have the pointer where it is stored:
All that remains is to run our dummy program, copy the PID, the memory pointer, place it in our main.rs and simultaneously run our script to read its memory. If we did everything right then we will see the following result:
Now that we can read the memory of another process, we can also write to it. We are going to create a function that makes this task easier for us, and we can also pass it any type of primitive data to be able to write the correct value.
We already have our function to write to memory, but we have to make a change in the way we open the process.
Previously we had the following line, which opens a read-only process.
let handle = unsafe { OpenProcess(PROCESS_VM_READ, false, pid) };
Now we are going to open the process with all the permissions to be able to write to it.
let handle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, false, pid) };
Now we can use the function we wrote earlier to manipulate the memory value of our victim process. Let's call it from our main function.
If we did everything right, we will see the following result:
Here is the complete code:
We can also read strings from memory, but we need to know the length of the string to be able to read it. We are going to create a function "read_str" that will use the previous "read" function to read each character of the string and join it.
Just as we can read strings, we can also write a utility function to write a series of characters in order to memory. Remember that we must have the size of the string before writing it.
We can really put many useful uses to this, it's just a matter of using our manipulation. Rust is a powerful language to perform all kinds of tasks :p
bc1q4uzvtx6nsgt7pt7678p9rqel4hkhskpxvck8uq
0x7a70a0C1889A9956460c3c9DCa8169F25Bb098af
7UcE4PzrHoGqFKHyVgsme6CdRSECCZAoWipsHntu5rZx