Skip to content
Merged
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
6 changes: 3 additions & 3 deletions examples/child_gating.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ def _instrument(self, pid):
print("✔ create_script()")
script = session.create_script(
"""\
Interceptor.attach(Module.getExportByName(null, 'open'), {
onEnter: function (args) {
Interceptor.attach(Module.getGlobalExportByName('open'), {
onEnter(args) {
send({
type: 'open',
path: Memory.readUtf8String(args[0])
path: args[0].readUtf8String()
});
}
});
Expand Down
80 changes: 80 additions & 0 deletions examples/spawn_gating.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import threading

from frida_tools.application import Reactor

import frida


class Application:
def __init__(self):
self._stop_requested = threading.Event()
self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait())

self._device = frida.get_usb_device()
self._sessions = set()
self._sessions_lock = threading.Lock()

self._device.on("spawn-added", lambda spawn: self._reactor.schedule(lambda: self._on_spawn_added(spawn)))
self._device.on("spawn-removed", lambda spawn: self._reactor.schedule(lambda: self._on_spawn_removed(spawn)))

def run(self):
self._reactor.schedule(lambda: self._start())
self._reactor.run()

def _start(self):
self._device.enable_spawn_gating()

def _instrument(self, pid):
print(f"✔ attach(pid={pid})")
session = self._device.attach(pid)
session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason)))
print("✔ create_script()")
script = session.create_script(
"""\
const puts = new NativeFunction(Module.getGlobalExportByName('puts'), 'int', ['pointer']);
puts(Memory.allocUtf8String('Hello from Frida agent'));
Interceptor.attach(Module.getGlobalExportByName('open'), {
onEnter(args) {
send({
type: 'open',
path: args[0].readUtf8String()
});
}
});
"""
)
script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message)))
print("✔ load()")
script.load()
print(f"✔ resume(pid={pid})")
self._device.resume(pid)
with self._sessions_lock:
self._sessions.add(session)

def _on_spawn_added(self, spawn):
print(f"⚡ spawn_added: {spawn}")
t = threading.Thread(target=self._handle_spawn, args=(spawn,))
t.start()

def _handle_spawn(self, spawn):
if "/bin/ls" in spawn.identifier:
self._instrument(spawn.pid)
else:
pid = spawn.pid
print(f"✔ resume(pid={pid})")
self._device.resume(pid)

def _on_spawn_removed(self, spawn):
print(f"⚡ spawn_removed: {spawn}")

def _on_detached(self, pid, session, reason):
print(f"⚡ detached: pid={pid}, reason='{reason}'")
with self._sessions_lock:
self._sessions.remove(session)

def _on_message(self, pid, message):
print(f"⚡ message: pid={pid}, payload={message['payload']}")


app = Application()
app.run()
22 changes: 19 additions & 3 deletions frida/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union

try:
from . import _frida
Expand Down Expand Up @@ -86,14 +86,30 @@ def kill(target: core.ProcessTarget) -> None:


def attach(
target: core.ProcessTarget, realm: Optional[str] = None, persist_timeout: Optional[int] = None
target: core.ProcessTarget,
realm: Optional[str] = None,
persist_timeout: Optional[int] = None,
exceptor: Optional[str] = None,
unwind_broker: Optional[bool] = None,
exit_monitor: Optional[bool] = None,
thread_suspend_monitor: Optional[bool] = None,
linker_notifier_offsets: Optional[Sequence[int]] = None,
) -> core.Session:
"""
Attach to a process
:param target: the PID or name of the process
"""

return get_local_device().attach(target, realm=realm, persist_timeout=persist_timeout)
return get_local_device().attach(
target,
realm=realm,
persist_timeout=persist_timeout,
exceptor=exceptor,
unwind_broker=unwind_broker,
exit_monitor=exit_monitor,
thread_suspend_monitor=thread_suspend_monitor,
linker_notifier_offsets=linker_notifier_offsets,
)


def inject_library_file(target: core.ProcessTarget, path: str, entrypoint: str, data: str) -> int:
Expand Down
30 changes: 29 additions & 1 deletion frida/_frida/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,17 @@ class Device(Object):
"""
...

def attach(self, pid: int, realm: Optional[str] = None, persist_timeout: Optional[int] = None) -> "Session":
def attach(
self,
pid: int,
realm: Optional[str] = None,
persist_timeout: Optional[int] = None,
exceptor: Optional[str] = None,
unwind_broker: Optional[bool] = None,
exit_monitor: Optional[bool] = None,
thread_suspend_monitor: Optional[bool] = None,
linker_notifier_offsets: Optional[Sequence[int]] = None,
) -> "Session":
"""
Attach to a PID.
"""
Expand Down Expand Up @@ -354,6 +364,12 @@ class Device(Object):
"""
...

def override_option(self, name: str, value: Any) -> None:
"""
Override a backend-specific option.
"""
...

def query_system_parameters(self) -> Dict[str, Any]:
"""
Returns a dictionary of information about the host system.
Expand Down Expand Up @@ -611,6 +627,12 @@ class Script(Object):
"""
...

def interrupt(self) -> None:
"""
Interrupt any JavaScript currently executing in the script.
"""
...

def post(self, message: str, data: Optional[Union[str, bytes]] = None) -> None:
"""
Post a JSON-encoded message to the script.
Expand All @@ -623,6 +645,12 @@ class Script(Object):
"""
...

def terminate(self) -> None:
"""
Interrupt execution and unload the script.
"""
...

def enable_debugger(self, port: Optional[int]) -> None:
"""
Enable the Node.js compatible script debugger
Expand Down
Loading
Loading