Skip to content

Instantly share code, notes, and snippets.

@Romern
Last active January 1, 2025 18:21
Show Gist options
  • Save Romern/bd39b3b486e420fff1b0be7551cbfd3a to your computer and use it in GitHub Desktop.
Save Romern/bd39b3b486e420fff1b0be7551cbfd3a to your computer and use it in GitHub Desktop.
Calling a c++ class constructor and a function on that constructor using Frida
#include <iostream>
#include <string>
class Greeter {
private:
std::string message;
public:
Greeter(const std::string& msg) : message(msg) {}
void sayHello() const {
std::cout << message << std::endl;
}
};
int main() {
Greeter greeter("Hello, World!");
greeter.sayHello();
return 0;
}
// std::string has some more needed fields apparently, so simply calling allocUtf8String is not enough
// but calling readUtf8String() is enough
// note that this is library specific
function allocateStdString(stringData) {
var ptrToStr = Memory.allocUtf8String(stringData);
var stringObjectPointer = Memory.alloc(Process.pointerSize);
var stringConstructorPointer = Module.findExportByName(null, '_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm');
var stringConstructor = new NativeFunction(stringConstructorPointer, 'void', ['pointer', 'pointer', 'ulong']);
stringConstructor(stringObjectPointer, ptrToStr, stringData.length);
return stringObjectPointer;
}
function findSymbolByName(moduleName, symbolName) {
var symbols = Module.enumerateSymbols(moduleName);
return symbols.find(function(sym) {
return sym.name === symbolName;
});
}
// actual code
function instantiateAndCallObject() {
var exampleObject = Memory.alloc(Process.pointerSize);
var printString = allocateStdString('Test!');
GreeterConstructor(exampleObject, printString);
SayHello(exampleObject);
}
// definining functions
var constructorAddress = findSymbolByName('a.out', '_ZN7GreeterC1ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE').address;
var sayHelloAddress = Module.findExportByName(null, '_ZNK7Greeter8sayHelloEv');
var GreeterConstructor = new NativeFunction(constructorAddress, 'void', ['pointer', 'pointer']);
var SayHello = new NativeFunction(sayHelloAddress, 'void', ['pointer']);
// for exiting the program before the usual main function is called
var exit = new NativeFunction(Module.findExportByName(null, 'exit'), 'void', ['int']);
// run the code right before main is called, as std::cout needs to be initialized somehow
Interceptor.attach(Module.findExportByName(null, 'main'), {
onEnter: function (args) {
console.log('Got into main(), running code...');
instantiateAndCallObject();
console.log('Ran code!');
exit(0);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment