The Details are all available in the Javascript API documentation for Interceptor
below is a small demo
assuming you have a source code as below the adder function will be called from 3 places
for a total of 26 times
#include <stdio.h>
int adder( int a , int b) {
return a+b;
}
int addonce (int a, int b) {
return adder(a,b);
}
int addtwice (int a, int b) {
return adder(a,b) + adder (a,b);
}
int addntimes(int a, int b, int c) {
int res = 0;
for (int i = 0; i < c; i++ ) {
res = res + adder(a,b);
}
return res;
}
void main(void) {
getchar();
printf("%d\n", addonce(2,3));
printf("%d\n", addtwice(2,3));
printf("%d\n", addntimes(2,3,10));
printf("%d\n", addonce(2,3)+addtwice(2,3)+addntimes(2,3,10));
}
compiled with vs 2017 community and executed
cl /Zi /W4 /analyze /Od /EHsc mulcall.cpp /link / release
5
10
50
65
Frida python script
import frida
import sys
session = frida.attach("mulcall.exe")
script = session.create_script("""
Interceptor.attach
(
ptr("%s"),
{
onEnter: function(args)
{
console.log("entering intercepted function will return to " + this.returnAddress);
} ,
onLeave: function(retval)
{
console.log( "leaving intercepted function returning " + retval.toInt32());
}
}
);
""" % int(sys.argv[1], 16))
def on_message(message, data):
print(message)
script.on('message', on_message)
script.load()
sys.stdin.read()
you need the address of adder function that you have to pass (in your case the 5xxx address of sub_yyyy) be aware ASLR may come into play you always need a fresh address of the running instance not some stale address of past instances
you will run the script like this
python friscript.py 7ff670901000
the 0x00007ff670901000 is the address of adder() for me
I have executed the exe and it is waiting for a keypress
now I run the above script
it attaches and waits until I press a key in the waiting instance
here is the output of Frida
python friscript.py 7ff670901000
entering intercepted function will return to 0x7ff670901039
leaving intercepted function returning 5
entering intercepted function will return to 0x7ff670901069
leaving intercepted function returning 5
entering intercepted function will return to 0x7ff67090107a
leaving intercepted function returning 5
entering intercepted function will return to 0x7ff6709010d4
leaving intercepted function returning 5 (10 times)
entering intercepted function will return to 0x7ff670901039
leaving intercepted function returning 5
entering intercepted function will return to 0x7ff670901069
leaving intercepted function returning 5
entering intercepted function will return to 0x7ff67090107a
leaving intercepted function returning 5
entering intercepted function will return to 0x7ff6709010d4
leaving intercepted function returning 5 (10 times)
EDIT to address Comment
if eax is a pointer to some type (ansi,wide,utf8,utf16,bytearray,struct *)
use the appropriate helper function in onLeave {}
here is an implementation for a function returning a struct *
struct { int a , char * b }
// hack for getting the next member of struct (adding pointer size of
// 32bit machine read documents to see if you can cast the return
// value to proper structure type
// so that we can use (foo *) (this.context.eax)->a
// instead of hacks like add(4)
foo = Memory.readPointer(this.context.eax.add(4))
blah = Memory.readCString(foo)
log( blah )