I'm using Frida to replace some win32 calls such as CreateFileW. I need to replace because I need to fundamentally change how the call works for various reasons. I'm finding that if I try to do something which indicates failure by setting a thread-local error (e.g. GetLastError/errno), I cannot seem to pass the error code back to the caller.
For example, the following code results in the output which follows.
import atexit
import os
import time
import signal
import sys
import frida
from dataclasses import dataclass
from typing import Any, Callable, cast, Union
from frida_tools.tracer import main
pid = frida.spawn(program="C:\\Windows\\System32\\notepad.exe", argv=["notepad.exe", "badfile"])
def do_attach_no_catch(pid):
session = frida.attach(pid)
script = session.create_script("""
const createFileWPtr = Module.getExportByName(null, 'CreateFileW');
const createFileWInput = ['pointer', 'int', 'int', 'pointer', 'int', 'int', 'pointer']
const createFileW = new SystemFunction(createFileWPtr, 'uint64', createFileWInput)
Interceptor.replace(createFileWPtr, new NativeCallback((fileName, access, shareMode, secAttr, createDisp, flags, templateFile) => {
send("Running createW")
const asStr = fileName.readUtf16String();
send(`Got ${asStr}`);
const result = createFileW(fileName, access, shareMode, secAttr, createDisp, flags, templateFile);
send(result)
this.lastError = result.lastError
return result.value
}, 'uint64', createFileWInput))
Interceptor.flush();
""")
def on_message(message, data):
print(message)
script.on('message', on_message)
script.load()
session.resume()
def do_attach(pid):
do_attach_no_catch(pid)
print("Starting")
do_attach(pid)
frida.resume(pid)
while True:
time.sleep(1)
Output:
{'type': 'send', 'payload': 'Running createW'}
{'type': 'send', 'payload': 'Got C:\\Windows\\Globalization\\Sorting\\sortdefault.nls'}
{'type': 'send', 'payload': {'value': '800', 'lastError': 0}}
{'type': 'send', 'payload': 'Running createW'}
{'type': 'send', 'payload': 'Got C:\\Windows\\Fonts\\staticcache.dat'}
{'type': 'send', 'payload': {'value': '836', 'lastError': 0}}
{'type': 'send', 'payload': 'Running createW'}
{'type': 'send', 'payload': 'Got C:\\Windows\\Registration\\R000000000006.clb'}
{'type': 'send', 'payload': {'value': '1000', 'lastError': 0}}
{'type': 'send', 'payload': 'Running createW'}
{'type': 'send', 'payload': 'Got C:\\Windows\\System32\\OLEACCRC.DLL'}
{'type': 'send', 'payload': {'value': '1016', 'lastError': 0}}
{'type': 'send', 'payload': 'Running createW'}
{'type': 'send', 'payload': 'Got badfile.txt'}
{'type': 'send', 'payload': {'value': '18446744073709551615', 'lastError': 2}}
{'type': 'send', 'payload': 'Running createW'}
{'type': 'send', 'payload': 'Got C:\\Windows\\System32\\imageres.dll'}
{'type': 'send', 'payload': {'value': '1180', 'lastError': 0}}
It's worth noting that notepad, at the end, pops up an error dialog saying no error happened -- i.e. it received an error code of 0. The documentation of the javascript api implies that setting this.lastError should do the trick. The docs mention that it exists in attach, and that replace is provided with a this object whose properties are similar to attach's.
I'm wondering if I'm just missing some simple integration which allows me to pass back the error code from the underlying function call, or whether this is fundamentally impossible with Frida as it stands.