mirror of
https://github.com/frida/frida-core.git
synced 2026-11-09 10:09:38 -10:00
Compare commits
2
Commits
main
...
feature/gumpharo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6b853d490 | ||
|
|
c3ba7814d3 |
No files matched your search
@@ -63,7 +63,7 @@ if build_agent
|
||||
link_depends: extra_link_depends,
|
||||
vs_module_defs: 'frida-agent.def',
|
||||
override_options: ['b_asneeded=true'],
|
||||
dependencies: [gio_dep, gee_dep, gum_dep, gumjs_dep, base_dep, pipe_dep, tls_provider_dep, payload_dep],
|
||||
dependencies: [gio_dep, gee_dep, gum_dep, gumjs_dep, gumpharo_dep, base_dep, pipe_dep, tls_provider_dep, payload_dep],
|
||||
)
|
||||
|
||||
operations = ['--move', 'constructor', 'frida_libc_shim_init', 'first']
|
||||
|
||||
@@ -2274,7 +2274,11 @@ namespace Frida {
|
||||
/**
|
||||
* The V8 runtime.
|
||||
*/
|
||||
V8;
|
||||
V8,
|
||||
/**
|
||||
* The Pharo runtime.
|
||||
*/
|
||||
PHARO;
|
||||
|
||||
public static ScriptRuntime from_nick (string nick) throws Error {
|
||||
return Marshal.enum_from_nick<ScriptRuntime> (nick);
|
||||
|
||||
@@ -49,7 +49,7 @@ payload = static_library('frida-payload-' + api_version, payload_sources,
|
||||
],
|
||||
vala_header: 'frida-payload.h',
|
||||
vala_vapi: f'frida-payload-@[email protected]',
|
||||
dependencies: [gio_dep, gee_dep, json_glib_dep, gum_dep, gumjs_dep, base_dep],
|
||||
dependencies: [gio_dep, gee_dep, json_glib_dep, gum_dep, gumjs_dep, gumpharo_dep, base_dep],
|
||||
install: true,
|
||||
install_dir: [true, header_install_dir, true],
|
||||
)
|
||||
|
||||
+155
-17
@@ -91,7 +91,27 @@ namespace Frida {
|
||||
if (name == null)
|
||||
name = "script%u".printf (script_id.handle);
|
||||
|
||||
Gum.ScriptBackend backend = pick_backend (options.runtime);
|
||||
ScriptRuntime runtime = options.runtime;
|
||||
if (runtime == DEFAULT)
|
||||
runtime = preferred_runtime;
|
||||
|
||||
#if HAVE_GUMPHARO
|
||||
if (runtime == PHARO) {
|
||||
if (source == null)
|
||||
throw new Error.NOT_SUPPORTED ("The Pharo runtime cannot load precompiled scripts");
|
||||
|
||||
var instance = new PharoScriptInstance (script_id, new Gum.PharoScript (name, source));
|
||||
instances[script_id] = instance;
|
||||
|
||||
instance.closed.connect (on_instance_closed);
|
||||
instance.message.connect (on_instance_message);
|
||||
instance.debug_message.connect (on_instance_debug_message);
|
||||
|
||||
return instance;
|
||||
}
|
||||
#endif
|
||||
|
||||
Gum.ScriptBackend backend = pick_backend (runtime);
|
||||
|
||||
Gum.Script script;
|
||||
try {
|
||||
@@ -109,7 +129,8 @@ namespace Frida {
|
||||
return Source.REMOVE;
|
||||
});
|
||||
|
||||
var instance = new ScriptInstance (script_id, script);
|
||||
var js_instance = new JSScriptInstance (script_id, script);
|
||||
ScriptInstance instance = js_instance;
|
||||
instances[script_id] = instance;
|
||||
|
||||
instance.closed.connect (on_instance_closed);
|
||||
@@ -175,7 +196,9 @@ namespace Frida {
|
||||
}
|
||||
|
||||
public Gum.Script eternalize_script (AgentScriptId script_id) throws Error {
|
||||
var instance = get_instance (script_id);
|
||||
var instance = get_instance (script_id) as JSScriptInstance;
|
||||
if (instance == null)
|
||||
throw new Error.NOT_SUPPORTED ("Only JavaScript scripts may be eternalized");
|
||||
|
||||
var script = instance.eternalize ();
|
||||
|
||||
@@ -231,7 +254,7 @@ namespace Frida {
|
||||
source.attach (Gum.ScriptBackend.get_scheduler ().get_js_context ());
|
||||
}
|
||||
|
||||
public sealed class ScriptInstance : Object, RpcPeer {
|
||||
public abstract class ScriptInstance : Object, RpcPeer {
|
||||
public signal void closed ();
|
||||
public signal void message (string json, Bytes? data);
|
||||
public signal void debug_message (string message);
|
||||
@@ -241,6 +264,120 @@ namespace Frida {
|
||||
construct;
|
||||
}
|
||||
|
||||
public abstract async void close ();
|
||||
public abstract async void flush ();
|
||||
public abstract async void load () throws Error;
|
||||
public abstract void post (string json, Bytes? data) throws Error;
|
||||
public abstract async void prepare_for_termination (TerminationReason reason);
|
||||
public abstract void unprepare_for_termination ();
|
||||
|
||||
public abstract async void post_rpc_message (string json, Bytes? data, Cancellable? cancellable)
|
||||
throws Error, IOError;
|
||||
|
||||
public virtual void interrupt () throws Error {
|
||||
throw new Error.NOT_SUPPORTED ("Interrupt is not available for this runtime");
|
||||
}
|
||||
|
||||
public virtual async void terminate () {
|
||||
yield close ();
|
||||
}
|
||||
|
||||
public virtual void enable_debugger () throws Error {
|
||||
throw new Error.NOT_SUPPORTED ("Debugger is not available for this runtime");
|
||||
}
|
||||
|
||||
public virtual void disable_debugger () {
|
||||
}
|
||||
|
||||
public virtual void post_debug_message (string message) throws Error {
|
||||
throw new Error.NOT_SUPPORTED ("Debugger is not available for this runtime");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_GUMPHARO
|
||||
public sealed class PharoScriptInstance : ScriptInstance {
|
||||
private Gum.PharoScript? script;
|
||||
|
||||
private State state = CREATED;
|
||||
|
||||
private enum State {
|
||||
CREATED,
|
||||
LOADED,
|
||||
UNLOADED,
|
||||
DESTROYED
|
||||
}
|
||||
|
||||
private RpcClient rpc_client;
|
||||
|
||||
public PharoScriptInstance (AgentScriptId script_id, Gum.PharoScript script) {
|
||||
Object (script_id: script_id);
|
||||
|
||||
this.script = script;
|
||||
script.set_message_handler (on_message);
|
||||
}
|
||||
|
||||
construct {
|
||||
rpc_client = new RpcClient (this);
|
||||
}
|
||||
|
||||
public override async void close () {
|
||||
if (state == DESTROYED)
|
||||
return;
|
||||
|
||||
if (state == LOADED) {
|
||||
script.unload ();
|
||||
state = UNLOADED;
|
||||
}
|
||||
|
||||
script = null;
|
||||
state = DESTROYED;
|
||||
|
||||
closed ();
|
||||
}
|
||||
|
||||
public override async void flush () {
|
||||
yield close ();
|
||||
}
|
||||
|
||||
public override async void load () throws Error {
|
||||
if (state != CREATED)
|
||||
throw new Error.INVALID_OPERATION ("Script cannot be loaded in its current state");
|
||||
|
||||
script.load ();
|
||||
|
||||
state = LOADED;
|
||||
}
|
||||
|
||||
public override void post (string json, Bytes? data) throws Error {
|
||||
if (state != LOADED)
|
||||
throw new Error.INVALID_OPERATION ("Only active scripts may be posted to");
|
||||
|
||||
script.post (json, data);
|
||||
}
|
||||
|
||||
public override async void prepare_for_termination (TerminationReason reason) {
|
||||
}
|
||||
|
||||
public override void unprepare_for_termination () {
|
||||
}
|
||||
|
||||
private void on_message (Gum.PharoScript script, string json, Bytes? data) {
|
||||
bool handled = rpc_client.try_handle_message (json);
|
||||
if (!handled)
|
||||
this.message (json, data);
|
||||
}
|
||||
|
||||
public override async void post_rpc_message (string json, Bytes? data, Cancellable? cancellable)
|
||||
throws Error, IOError {
|
||||
if (script == null)
|
||||
throw new Error.INVALID_OPERATION ("Script is destroyed");
|
||||
script.post (json, data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public sealed class JSScriptInstance : ScriptInstance {
|
||||
public Gum.Script? script {
|
||||
get {
|
||||
return _script;
|
||||
@@ -274,7 +411,7 @@ namespace Frida {
|
||||
|
||||
private RpcClient rpc_client;
|
||||
|
||||
public ScriptInstance (AgentScriptId script_id, Gum.Script script) {
|
||||
public JSScriptInstance (AgentScriptId script_id, Gum.Script script) {
|
||||
Object (script_id: script_id, script: script);
|
||||
}
|
||||
|
||||
@@ -282,7 +419,7 @@ namespace Frida {
|
||||
rpc_client = new RpcClient (this);
|
||||
}
|
||||
|
||||
public async void close () {
|
||||
public override async void close () {
|
||||
if (close_request != null) {
|
||||
try {
|
||||
yield close_request.future.wait_async (null);
|
||||
@@ -338,7 +475,7 @@ namespace Frida {
|
||||
close_request.resolve (true);
|
||||
}
|
||||
|
||||
public async void flush () {
|
||||
public override async void flush () {
|
||||
if (close_request == null)
|
||||
close.begin ();
|
||||
|
||||
@@ -349,7 +486,7 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
public async void load () throws Error {
|
||||
public override async void load () throws Error {
|
||||
if (state != CREATED)
|
||||
throw new Error.INVALID_OPERATION ("Script cannot be loaded in its current state");
|
||||
|
||||
@@ -362,11 +499,11 @@ namespace Frida {
|
||||
load_request.resolve (true);
|
||||
}
|
||||
|
||||
public void interrupt () {
|
||||
public override void interrupt () throws Error {
|
||||
script.interrupt ();
|
||||
}
|
||||
|
||||
public async void terminate () {
|
||||
public override async void terminate () {
|
||||
script.interrupt ();
|
||||
|
||||
yield close ();
|
||||
@@ -397,7 +534,7 @@ namespace Frida {
|
||||
return result;
|
||||
}
|
||||
|
||||
public async void prepare_for_termination (TerminationReason reason) {
|
||||
public override async void prepare_for_termination (TerminationReason reason) {
|
||||
if (state == LOADED) {
|
||||
schedule_on_js_thread (() => {
|
||||
script.get_stalker ().flush ();
|
||||
@@ -408,7 +545,7 @@ namespace Frida {
|
||||
yield ensure_dispose_called (reason);
|
||||
}
|
||||
|
||||
public void unprepare_for_termination () {
|
||||
public override void unprepare_for_termination () {
|
||||
if (state == DISPOSED) {
|
||||
state = LOADED;
|
||||
dispose_request = null;
|
||||
@@ -448,7 +585,7 @@ namespace Frida {
|
||||
dispose_request.resolve (true);
|
||||
}
|
||||
|
||||
public void post (string json, Bytes? data) throws Error {
|
||||
public override void post (string json, Bytes? data) throws Error {
|
||||
switch (state) {
|
||||
case LOADING:
|
||||
case LOADED:
|
||||
@@ -460,17 +597,17 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
public void enable_debugger () throws Error {
|
||||
public override void enable_debugger () throws Error {
|
||||
if (_script != null)
|
||||
_script.set_debug_message_handler (on_debug_message);
|
||||
}
|
||||
|
||||
public void disable_debugger () {
|
||||
public override void disable_debugger () {
|
||||
if (_script != null)
|
||||
_script.set_debug_message_handler (null);
|
||||
}
|
||||
|
||||
public void post_debug_message (string message) {
|
||||
public override void post_debug_message (string message) throws Error {
|
||||
if (_script != null)
|
||||
_script.post_debug_message (message);
|
||||
}
|
||||
@@ -485,7 +622,8 @@ namespace Frida {
|
||||
this.debug_message (message);
|
||||
}
|
||||
|
||||
private async void post_rpc_message (string json, Bytes? data, Cancellable? cancellable) throws Error, IOError {
|
||||
public override async void post_rpc_message (string json, Bytes? data, Cancellable? cancellable)
|
||||
throws Error, IOError {
|
||||
if (script == null)
|
||||
throw new Error.INVALID_OPERATION ("Script is destroyed");
|
||||
script.post (json, data);
|
||||
|
||||
@@ -382,6 +382,12 @@ if have_in_tree_payloads
|
||||
endif
|
||||
gumjs_inspector_dep = dependency('frida-gumjs-inspector-1.0', default_options: ['default_library=static'])
|
||||
|
||||
gumpharo_dep = dependency('frida-gumpharo-' + api_version, required: false)
|
||||
have_gumpharo = gumpharo_dep.found()
|
||||
if have_gumpharo
|
||||
vala_flags += '--define=HAVE_GUMPHARO'
|
||||
endif
|
||||
|
||||
gee_options = [
|
||||
'default_library=static',
|
||||
'disable-introspection=true',
|
||||
@@ -669,6 +675,9 @@ gumjs_inspector_vala_args = ['--pkg=frida-gumjs-inspector-1.0', gum_vala_args]
|
||||
|
||||
if have_in_tree_payloads
|
||||
gumjs_vala_args = ['--pkg=frida-gumjs-1.0', '--pkg=gio-2.0', gum_vala_args]
|
||||
if have_gumpharo
|
||||
gumjs_vala_args += ['--pkg=frida-gumpharo-' + api_version]
|
||||
endif
|
||||
|
||||
have_v8 = gumjs_dep.get_variable('gumjs_v8') == 'enabled'
|
||||
if have_v8
|
||||
|
||||
Reference in new issue
Block a user