Replace a win32 call and set lastError

Viewed 78

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.

0 Answers
Related