Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added cshell #509

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "releng"]
path = releng
url = https://github.com/frida/releng.git
[submodule "src/cshell/frida-cshell"]
path = src/cshell/frida-cshell
url = https://github.com/WorksButNotTested/frida-cshell.git
52 changes: 38 additions & 14 deletions inject/inject.vala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Frida.Inject {
private static string? target_name;
private static string? realm_str;
private static string? script_path;
private static bool cshell;
private static string? script_runtime_str;
private static string? parameters_str;
private static bool eternalize;
Expand All @@ -21,6 +22,7 @@ namespace Frida.Inject {
{ "name", 'n', 0, OptionArg.STRING, ref target_name, "attach to NAME", "NAME" },
{ "realm", 'r', 0, OptionArg.STRING, ref realm_str, "attach in REALM", "REALM" },
{ "script", 's', 0, OptionArg.FILENAME, ref script_path, null, "JAVASCRIPT_FILENAME" },
{ "cshell", 'C', 0, OptionArg.NONE, ref cshell, "Load the C-Shell", null },
{ "runtime", 'R', 0, OptionArg.STRING, ref script_runtime_str, "Script runtime to use", "qjs|v8" },
{ "parameters", 'P', 0, OptionArg.STRING, ref parameters_str, "Parameters as JSON, same as Gadget", "PARAMETERS_JSON" },
{ "eternalize", 'e', 0, OptionArg.NONE, ref eternalize, "Eternalize script and exit", null },
Expand Down Expand Up @@ -69,15 +71,24 @@ namespace Frida.Inject {
}
}

if (script_path == null || script_path == "") {
printerr ("Path to JavaScript file must be specified\n");
return 4;
}

string? script_source = null;
if (script_path == "-") {
if (cshell) {
if (script_path != null && script_path != "") {
printerr ("Cannot specify both -s and -C options\n");
return 4;
}
script_path = null;
script_source = read_stdin ();
script_source = CShellScript.get_source ();
} else {
if (script_path == null || script_path == "") {
printerr ("Path to JavaScript file must be specified\n");
return 5;
}

if (script_path == "-") {
script_path = null;
script_source = read_stdin ();
}
}

ScriptRuntime script_runtime = DEFAULT;
Expand All @@ -86,34 +97,39 @@ namespace Frida.Inject {
script_runtime = ScriptRuntime.from_nick (script_runtime_str);
} catch (Error e) {
printerr ("%s\n", e.message);
return 5;
return 6;
}
}

var parameters = new Json.Node.alloc ().init_object (new Json.Object ());
if (parameters_str != null) {
if (parameters_str == "") {
printerr ("Parameters argument must be specified as JSON if present\n");
return 6;
return 7;
}

try {
var root = Json.from_string (parameters_str);
if (root.get_node_type () != OBJECT) {
printerr ("Failed to parse parameters argument as JSON: not an object\n");
return 7;
return 8;
}

parameters.take_object (root.get_object ());
} catch (GLib.Error e) {
printerr ("Failed to parse parameters argument as JSON: %s\n", e.message);
return 8;
return 9;
}
}

if (interactive && eternalize) {
printerr ("Cannot specify both -e and -i options\n");
return 9;
return 10;
}

if (cshell && eternalize) {
printerr ("Cannot specify both -e and -C options\n");
return 11;
}

application = new Application (device_id, spawn_file, target_pid, target_name, options, script_path, script_source,
Expand Down Expand Up @@ -249,7 +265,15 @@ namespace Frida.Inject {

uint pid;
if (spawn_file != null) {
pid = yield device.spawn (spawn_file, null, io_cancellable);
/*
* If frida-inject is supposed to be interactive, then don't connect any spawned
* child process to the TTY.
*/
var options = new SpawnOptions ();
if (interactive || cshell) {
options.stdio = PIPE;
}
pid = yield device.spawn (spawn_file, options, io_cancellable);
} else if (target_name != null) {
var proc = yield device.get_process_by_name (target_name, null, io_cancellable);
pid = proc.pid;
Expand All @@ -265,7 +289,7 @@ namespace Frida.Inject {
yield r.start ();
script_runner = r;

if (interactive)
if (interactive || cshell)
watch_stdin ();

if (spawn_file != null) {
Expand Down
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ have_fruity_backend = get_option('fruity_backend').allowed()
have_droidy_backend = get_option('droidy_backend').allowed()
have_socket_backend = get_option('socket_backend').allowed()
have_barebone_backend = quickjs_dep.found()
have_cshell_backend = get_option('cshell_backend').allowed()
have_compiler_backend = get_option('compiler_backend') \
.disable_if(not have_local_backend, error_message: 'compiler backend requires the local backend for script execution') \
.disable_auto_if(host_os == 'watchos') \
Expand Down Expand Up @@ -388,7 +389,8 @@ foreach b : [['local', have_local_backend],
['droidy', have_droidy_backend],
['socket', have_socket_backend],
['barebone', have_barebone_backend],
['compiler', have_compiler_backend]]
['compiler', have_compiler_backend],
['cshell', have_cshell_backend]]
if b[1]
vala_flags += '--define=HAVE_@0@_BACKEND'.format(b[0].to_upper())
endif
Expand Down
6 changes: 6 additions & 0 deletions meson.options
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ option('barebone_backend',
description: 'Include the Barebone backend',
)

option('cshell_backend',
type: 'feature',
value: 'auto',
description: 'Include the CShell backend',
)

option('compiler_backend',
type: 'feature',
value: 'auto',
Expand Down
2 changes: 2 additions & 0 deletions src/cshell/cshell.resources
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[resource-compiler]
namespace = Frida.Data.Cshell
8 changes: 8 additions & 0 deletions src/cshell/cshell.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Frida {
public class CShellScript : Object {
public static string get_source () {
string runtime_js = (string) Frida.Data.Cshell.get_frida_cshell_js_blob ().data;
return runtime_js;
}
}
}
1 change: 1 addition & 0 deletions src/cshell/frida-cshell
Submodule frida-cshell added at 19f574
54 changes: 54 additions & 0 deletions src/cshell/generate-frida-cshell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3

import os
from pathlib import Path
import platform
import shutil
from subprocess import PIPE, STDOUT, CalledProcessError
import subprocess
import sys


def generate_runtime(input_dir, output_dir):
output_dir.mkdir(parents=True, exist_ok=True)

runtime_reldir = Path("frida-cshell")
runtime_srcdir = input_dir / runtime_reldir
runtime_intdir = output_dir / runtime_reldir
if runtime_intdir.exists():
shutil.rmtree(runtime_intdir)
shutil.copytree(runtime_srcdir, runtime_intdir)

npm = os.environ.get("NPM", make_script_filename("npm"))
try:
subprocess.run([npm, "install"], stdout=PIPE, stderr=STDOUT, cwd=runtime_intdir, check=True)
shutil.copy(runtime_intdir / "frida-cshell.js", output_dir)
except CalledProcessError as e:
message = "\n".join([
"",
"***",
"Failed to bootstrap the CShell backend script runtime:",
"\t" + str(e),
"It appears Node.js is not installed.",
"We need it for processing JavaScript code at build-time.",
"Check PATH or set NPM to the absolute path of your npm binary.",
"***\n",
e.stdout.decode("utf-8")
])
raise EnvironmentError(message)


def make_script_filename(name):
build_os = platform.system().lower()
extension = ".cmd" if build_os == "windows" else ""
return name + extension


if __name__ == "__main__":
input_dir, output_dir = [Path(d).resolve() for d in sys.argv[1:3]]

try:
generate_runtime(input_dir, output_dir)
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)
76 changes: 76 additions & 0 deletions src/cshell/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
backend_sources += files(
'cshell.vala',
)
cshell_script_runtime = custom_target('frida-cshell',
input: [
'frida-cshell/src/breakpoints/bps.ts',
'frida-cshell/src/breakpoints/bp.ts',
'frida-cshell/src/breakpoints/memory.ts',
'frida-cshell/src/breakpoints/regs.ts',
'frida-cshell/src/cmdlets/assembly.ts',
'frida-cshell/src/cmdlets/bp.ts',
'frida-cshell/src/cmdlets/bt.ts',
'frida-cshell/src/cmdlets/copy.ts',
'frida-cshell/src/cmdlets/dump.ts',
'frida-cshell/src/cmdlets/exit.ts',
'frida-cshell/src/cmdlets/fd.ts',
'frida-cshell/src/cmdlets/help.ts',
'frida-cshell/src/cmdlets/history.ts',
'frida-cshell/src/cmdlets/ld.ts',
'frida-cshell/src/cmdlets/math.ts',
'frida-cshell/src/cmdlets/mod.ts',
'frida-cshell/src/cmdlets/read.ts',
'frida-cshell/src/cmdlets/reg.ts',
'frida-cshell/src/cmdlets/src.ts',
'frida-cshell/src/cmdlets/sym.ts',
'frida-cshell/src/cmdlets/thread.ts',
'frida-cshell/src/cmdlets/var.ts',
'frida-cshell/src/cmdlets/vm.ts',
'frida-cshell/src/cmdlets/write.ts',
'frida-cshell/src/commands/cmdlets.ts',
'frida-cshell/src/commands/cmdlet.ts',
'frida-cshell/src/commands/command.ts',
'frida-cshell/src/entrypoint.ts',
'frida-cshell/src/io/char.ts',
'frida-cshell/src/io/input.ts',
'frida-cshell/src/io/output.ts',
'frida-cshell/src/io/parser.ts',
'frida-cshell/src/io/token.ts',
'frida-cshell/src/memory/mem.ts',
'frida-cshell/src/memory/overlay.ts',
'frida-cshell/src/misc/base64.ts',
'frida-cshell/src/misc/format.ts',
'frida-cshell/src/misc/numeric.ts',
'frida-cshell/src/terminal/history.ts',
'frida-cshell/src/terminal/line.ts',
'frida-cshell/src/vars/vars.ts',
'frida-cshell/src/vars/var.ts',
],
output: [
'frida-cshell.js',
],
command: [
find_program('generate-frida-cshell.py'),
meson.current_source_dir(),
meson.current_build_dir(),
],
)
backend_sources += custom_target('frida-data-cshell',
input: [
'cshell.resources',
cshell_script_runtime,
],
output: [
'frida-data-cshell.vapi',
'frida-data-cshell.h',
'frida-data-cshell.c',
'frida-data-cshell-blob.S',
],
command: [
resource_compiler,
'--toolchain=' + host_toolchain,
'-c', '@INPUT0@',
'-o', join_paths(meson.current_build_dir(), 'frida-data-cshell'),
'@INPUT1@',
],
)
4 changes: 4 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,10 @@ if have_barebone_backend
subdir('barebone')
endif

if have_cshell_backend
subdir('cshell')
endif

if host_os_family != 'windows'
backend_vala_args_private += '--pkg=posix'
endif
Expand Down
Loading