Search code examples
linuxwindowsfrida

Frida: spawn a Windows/Linux process with command-line arguments


When starting frida you can provide path to an executable that frida should execute and attach to it:

frida -l myscript.js process_to_spawn.exe

I have an executable needs to be started with additional parameters, otherwise it directly terminates. Is there a way to start a new executable and provide command-line arguments for the newly started process?

I already tried

frida -l myscript.js process_to_spawn.exe --argForProcess
frida -l myscript.js "process_to_spawn.exe --argForProcess"

but both variants don't work. Frida tries to interpret all arguments and thus can not pass arguments to the spawned process. And the second variant also does not work because frida is not able to find the executable to be started.

Is there a way to spawn an executable on the local OS (e.g. Windows or Linux) by frida and provide command-line arguments?

I can not attach to a running process because the functions I want to hook are only executed once directly after start-up, so I have to spawn the process using frida.


Solution

  • The problem seems to be that the argument starts with a -. For regular arguments that don't start with a - using the frida option -f works:

    frida -l myscript.js -f process_to_spawn.exe argForProcess
    

    But as I need the argument --argForProcess the only way I found was hooking the main method which processes the command-line arguments and modify the arguments before main is called.

    The following code works on Windows 10 which seem to pass the arguments as wchar/"Unicode"/UTF-16 string. It changes argc and argv parameters of main from one argument (the executable itself) to two (the executable plus one argument).

    let mainPointer = DebugSymbol.fromName("main").address;
    Interceptor.attach(mainPointer, {
        onEnter(args) {
            // args[0] = int argc
            // args[1] = wchar *argv[]
    
            let myarg1 = Memory.allocUtf16String("Myexecutable.exe");
            let myarg2 = Memory.allocUtf16String("--argumentX");
            let newArgv = Memory.alloc(2 * Process.pointerSize); // allocate space for the two argument pointers
            newArgv.writePointer(myarg1);
            newArgv.add(Process.pointerSize).writePointer(myarg2);
    
            // save all created memory blocks so they don't get garbage collected before main method is completed
            this.myarg1 = myarg1; 
            this.myarg2 = myarg2;
            this.newArgs = newArgv;
            
            // Overwrite the argument counter and the argument char**
            args[0] = ptr(2);
            args[1] = newArgs;
            
            console.log("main(" + args[0] + ", " + args[1].readPointer().readUtf16String() + ", " + args[1].add(Process.pointerSize).readPointer().readUtf16String() + ")");
        }
    });