Memory Aliasing Between Functions
So far we have seen how two pointers can point to the same memory address. Now we want to examine a more important case.
Suppose we have a function that modifies a value in memory and another function reads the same value from memory.
The point here is that these two functions may use different pointers, but both access the same address.
This is very important in reverse engineering, because we may not notice the relationship between them by examining each function alone.
A simple example with
C
void set_value(int *p)
{
*p = 100;
}
int get_value(int *q)
{
return *q;
}
int main()
{
int value = 10;
set_value(&value);
int result = get_value(&value);
return result;
}
What is happening here?
First, the value is 10
Then the address of value is given to the set_value function
The set_value function changes the value at that address to 100
Then the same address is given to the get_value function and the new value is read from memory
Finally, the result is 100
The main point is that the pointers p and q have different names and variables, but in this example they both access the same memory location
So the connection between these two functions is formed through memory, not through the return value of one of them
Now, how does this look in assembly?
Suppose the set_value function is compiled like this
set_value:
mov dword ptr [rdi], 100
ret
This example is written according to the System V AMD64 calling convention, which is commonly used in 64-bit Linux programs
According to this convention, the first argument of the function is placed in the RDI register
Now let's examine this instruction
mov dword ptr [rdi], 100
This instruction writes the number 100 to the address located in RDI
Note that the value of RDI is different from the value stored in memory
RDI
holds the address and the expression [rdi] refers to the data located at that address
Now look at the get_value function
get_value:
mov eax, dword ptr [rdi]
ret
Here the four-byte value located at the address RDI is read and placed in EAX. Since the return value of the function is of type int, this value is stored in the register EAX is returned, so one function writes to memory and another function reads from the same memory, provided that the address given to both functions points to the same memory location.
Now how do we find it in reverse engineering?
When you are examining a binary file in Ghidra or Disassembler, follow these steps
Step 1:
Examine the function arguments
See what pointers the function receives and whether it uses them to read or write memory
Step 2:
Look for memory write instructions
For example, consider the following command
mov dword ptr [rdi], 100
This command shows that the function uses the address in RDI to write data
Step 3:
Examine other functions
See if other functions receive the same address or associated pointer and later read something from that memory
Don't just look for identical variable or register names - the address may be passed through another register, stored in a structure, or obtained with several calculation steps
Step 4:
Look for relationships between functions
Don't just look at the function name or its return value - a function may change memory It does not return any value, but the effect of its change can be seen in another function a few steps later.
Therefore, you must follow the path of transferring pointers and reading and writing memory. An important point about Must Alias and May Alias.
We cannot always be sure that two pointers point to the same address based on the similarity of the arguments. Here we have two important concepts.
Must Alias means that according to the information and conditions we have examined, two pointers must point to the same memory location.
May Alias means that two pointers may point to the same memory location, but the available information is not enough to prove this definitively. This difference is very important in program analysis.
Post #1889
35
ReverseEngineering Memory Aliasing بین توابع تا اینجا دیدیم که چطور ممکنه دو تا Pointer به یه آدرس از حافظه اشاره کنن حالا میخوایم یه حالت مهمتر رو بررسی کنیم فرض کنید یه تابع داریم که یه مقدار رو توی حافظه تغییر میده و یه تابع دیگه همون مقدار رو از حافظه میخونه نکته اینجاست…