Search code examples
c++reverse-engineeringinstrumentationfrida

How to Read Arguments in a Function Call with Frida


I am using frida-trace to attach a handler to a certain function in my c++ console application. here is the code from the target application in C++:

string Add(int a, int b) {
    ostringstream oss;
    oss << a << " + " << b << " = " << (a + b);
    return oss.str();
}

It's the "add" function from a basic calculator app that takes two integers and returns the summation in a string format (e.g., 1 + 1 = 2) I am able to find the function and create a "handler" with Frida using this command; frida-trace -s "Add" SimpleCalculator.exe

Note that I will be calling the Add method with the parameters 1 and 1 throughout the tests. I am able to detect when the function gets called, for example;

onEnter(log, args, state) {
    log('Add method was called...')
},

Now, I want to read what arguments were passed to the function. I tried using "args" array to read arguments, but this array seems to hold memory addresses and not actual values. This is understandable, but I couldn't figure out how I can retrieve the actual values using these addresses. If I log the addresses;

onEnter(log, args, state) {
    log(args[0]);
    log(args[1]);
},

The output is;

0xf65aeff6e0
0x1

Using the values from the args array to create a NativePointer does not seem to affect the value (which I would expect);

onEnter(log, args, state) {
  var a = new NativePointer(args[0]);
  log(a);
},

This simply prints the same address for the 1st argument as simply doing log(args[0]) (the output is 0xf65aeff6e0). I then tried readInt(), but this prints 539697201 which is not the correct argument value (it's supposed to print 1). I also tried toInt32(), and combining them in various different ways, but with no luck. I tried Memory.readInt(a) as well, but it gives the same random value (539697201). log(args[0].toInt32());, on the other hand, gives a different random value of 1756755344. Can someone help me figure out how I can read the arguments that were passed to the function?

Here is the sample app including the executables (/x64/Release): https://github.com/Emrebener/FridaUseCase1


Solution

  • Decompiling the executable from your repo I get the following function definition for Add:

    Add(std::string *result, long double a, long double b)

    Looks like the compiler doe not use the return value, instead the first argument is used as out parameter. Thus the random values you get as first argument is the allocated memory for the return string.

    If you want to read the two parameters you have to use arg[1] and arg[2]:

    onEnter(log, args, state) {
        log(args[1].toInt32());
        log(args[2].toInt32());
    },
    

    Learned lesson: When using Frida for a program you have the source code, always make sure to look at a function using a decompiler like Ghidra/IDA to make sure the compiler has not modified the code in an unexpected way.