March 3, 2022 | 15:44

Hook Qt's QString using Frida

Recently, I wanted to understand what a Windows program built with Qt 4.7 is doing under the hood, in particular I investigated the use of the QString class. For that I used Frida to hook some of the classes methods.

To get started, I created a simple program that makes use of the two methods fromAscii and append:

#include <QString>
#include <stdio.h>
#include <Windows.h>

int main() {

int i = 1;

	const char* str = "awesome";
	QString qstr = QString::fromAscii(str);
	QString qstr2 = QString("string");
	printf("%d %s\n", i, qstr.toUtf8().data());
 return 0;

When executed, the program repeatedly appends one QString to the other and prints the result:


With the following Frida script both functions get hooked to log relevant arguments resp. return values to the console, and to modify one of the QStrings. I got inspired by this and this issue on Frida’s Github repo, however both functions didn’t work for me.


var module = "QtCore4.dll";

// get string from QString
function convertQStringToString(qStringInput){
	var toascii = new NativeFunction(Module.findExportByName(module, '_ZNK7QString7toAsciiEv'), 'void', ['pointer', 'pointer']);
	var allocSpace = Memory.alloc(Process.pointerSize);
	var qByteArray = Memory.readPointer(allocSpace);
	var todata = new NativeFunction(Module.findExportByName(module, '_ZN10QByteArray4dataEv'), 'pointer' , ['pointer']);
	var str = todata(allocSpace).readCString();
	return str;

// create QString
function convertStringToQString(stringInput){
    var fromutf8 = new NativeFunction(Module.findExportByName(module, '_ZN7QString8fromUtf8EPKci'), 'void', ['pointer', 'pointer', 'int']);
    var cStrPointer = Memory.allocUtf8String(stringInput);
    var retQString = Memory.alloc(Process.pointerSize);
	fromutf8(retQString,cStrPointer, -1);
    return retQString;

// hook QString::fromAscii( const char * str, int size = -1 )
var fromAsciiFunc = "_ZN7QString9fromAsciiEPKci";
Interceptor.attach(Module.findExportByName(module, fromAsciiFunc), {
  onEnter: function (args) {
    // print "str" argument to console
    var str = args[1].readCString();
    console.log(fromAsciiFunc + ": \t '" + str + "'");

// hook QString & QString::append ( const QString & str )
var appendFunc = "_ZN7QString6appendERKS_";
var newQString = convertStringToQString("frida");
Interceptor.attach(Module.findExportByName(module, appendFunc), {
  onEnter: function (args) {
    //  replace the appended QString with our own
    args[1] = newQString;
  onLeave: function (retval) {
    // print returned QString to console
    var str = convertQStringToString(retval);
    console.log(appendFunc + ": \t '" + str + "'");

Run the script with frida.exe -l .\hook.js hello.exe while hello.exe is executed, and string will change:


© Pavel Pi 2021

Powered by Hugo & Kiss'Em.