mirror of
https://github.com/frida/frida-python
synced 2026-06-08 14:16:17 +00:00
Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7416839ae5 | |||
| 5c782dcc1c | |||
| de4f0e906d | |||
| 623cb160f8 | |||
| 3c265a483d | |||
| f43a1ed12c | |||
| 9201c4c007 | |||
| 135dac88ec | |||
| 28e8b1f32e | |||
| 0b7bde2fd4 | |||
| 6a18d4c4cc | |||
| 9a3ec81843 | |||
| ec55dcb3bc | |||
| e5404ae4eb | |||
| 64396bce72 | |||
| ccdd63dccc | |||
| e8f69618da | |||
| d809147cd0 | |||
| 24cc1fbcc9 | |||
| 7a2762ecc7 | |||
| d92b8e684c | |||
| 7c17bd5330 | |||
| 5991067e4e | |||
| 0780e5f813 | |||
| ce326094be | |||
| 092f6c38a1 | |||
| 9e83d29bd9 | |||
| 90533db5d4 | |||
| 30e009997e | |||
| 32e3c1922b | |||
| 69c5696aee | |||
| 0394ff3585 | |||
| c15b92fd55 | |||
| c53b453059 | |||
| d467d91e4f | |||
| ed3fdb8ce0 | |||
| 4d4632dbbe | |||
| aab9c4e76f | |||
| 2be19bcdad | |||
| 915c0678bd | |||
| 573a5a7d24 | |||
| 148ca1461d | |||
| 8eb4987563 | |||
| 84c7375044 | |||
| 267d5d555d | |||
| e219e5edbc | |||
| 70aaa04070 | |||
| 463fd65f03 | |||
| 41c3092dfe | |||
| 1b11eeab12 | |||
| 10aad4273c | |||
| d921e98e0c | |||
| 8935cf3651 | |||
| 2e3b9474bf | |||
| 582c2860c0 | |||
| 7c7947ee7c | |||
| 0f68038a10 | |||
| e9a3a37ea1 | |||
| f642de8a6b | |||
| c541ac027c | |||
| facd6756b2 | |||
| f29f486c0d | |||
| 2135414777 | |||
| ba032180c6 | |||
| b29cbcd499 | |||
| 55cdadea6a | |||
| 17d39c725c | |||
| 72f1d651b6 | |||
| 6d5c64d215 | |||
| 2b5f6492a2 | |||
| 316f88974d | |||
| fee73e852b | |||
| 37847fd8c9 | |||
| 7158638eb9 | |||
| 77d9c51109 | |||
| 040fa5536b | |||
| c9226b976a | |||
| d851e4eb6a | |||
| ccea05e00b | |||
| 6416edc773 | |||
| ce718c1dc9 | |||
| 0b854499cd | |||
| 243cce22e6 | |||
| c4d0fe55a5 | |||
| f3d767ecb6 | |||
| 8838d885ce | |||
| 213e373056 | |||
| 8b888558c7 | |||
| de55d964a0 | |||
| e920bad7f5 | |||
| 2b947e6d75 | |||
| 9992e8ad7a | |||
| 3c7eb89653 | |||
| 16f1be2a88 | |||
| 280c6d73f3 | |||
| 140dc6d13a | |||
| eac203e327 | |||
| bc3429a80d | |||
| e929477ecd | |||
| ebeb7a86b1 |
@@ -0,0 +1,9 @@
|
||||
import pprint
|
||||
|
||||
import frida
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
deviceinfo = device.open_service("dtx:com.apple.instruments.server.services.deviceinfo")
|
||||
response = deviceinfo.request({"method": "runningProcesses"})
|
||||
pprint.pp(response)
|
||||
@@ -0,0 +1,27 @@
|
||||
import sys
|
||||
|
||||
import frida
|
||||
|
||||
|
||||
def on_message(message):
|
||||
print("on_message:", message)
|
||||
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
opengl = device.open_service("dtx:com.apple.instruments.server.services.graphics.opengl")
|
||||
opengl.on("message", on_message)
|
||||
opengl.request(
|
||||
{
|
||||
"method": "setSamplingRate:",
|
||||
"args": [5.0],
|
||||
}
|
||||
)
|
||||
opengl.request(
|
||||
{
|
||||
"method": "startSamplingAtTimeInterval:",
|
||||
"args": [0.0],
|
||||
}
|
||||
)
|
||||
|
||||
sys.stdin.read()
|
||||
@@ -0,0 +1,31 @@
|
||||
import sys
|
||||
|
||||
import frida
|
||||
|
||||
|
||||
def on_message(message):
|
||||
print("on_message:", message)
|
||||
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
control = device.open_service("dtx:com.apple.instruments.server.services.processcontrol")
|
||||
control.on("message", on_message)
|
||||
pid = control.request(
|
||||
{
|
||||
"method": "launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:",
|
||||
"args": [
|
||||
"",
|
||||
"no.oleavr.HelloIOS",
|
||||
{},
|
||||
[],
|
||||
{
|
||||
"StartSuspendedKey": False,
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
control.request({"method": "startObservingPid:", "args": [pid]})
|
||||
|
||||
print(f"App spawned, PID: {pid}. Kill it to see an example message being emitted.")
|
||||
sys.stdin.read()
|
||||
@@ -0,0 +1,15 @@
|
||||
import sys
|
||||
|
||||
import frida
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: {sys.argv[0]} outfile.png", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
outfile = sys.argv[1]
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
screenshot = device.open_service("dtx:com.apple.instruments.server.services.screenshot")
|
||||
png = screenshot.request({"method": "takeScreenshot"})
|
||||
with open(outfile, "wb") as f:
|
||||
f.write(png)
|
||||
@@ -0,0 +1,29 @@
|
||||
import time
|
||||
|
||||
import frida
|
||||
|
||||
|
||||
def on_message(message):
|
||||
print("on_message:", message)
|
||||
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
sysmon = device.open_service("dtx:com.apple.instruments.server.services.sysmontap")
|
||||
sysmon.on("message", on_message)
|
||||
sysmon.request(
|
||||
{
|
||||
"method": "setConfig:",
|
||||
"args": [
|
||||
{
|
||||
"ur": 1000,
|
||||
"cpuUsage": True,
|
||||
"sampleInterval": 1000000000,
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
sysmon.request({"method": "start"})
|
||||
time.sleep(5)
|
||||
sysmon.request({"method": "stop"})
|
||||
time.sleep(1)
|
||||
@@ -0,0 +1,7 @@
|
||||
import frida
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
diag = device.open_service("plist:com.apple.mobile.diagnostics_relay")
|
||||
diag.request({"type": "query", "payload": {"Request": "Sleep", "WaitForDisconnect": True}})
|
||||
diag.request({"type": "query", "payload": {"Request": "Goodbye"}})
|
||||
@@ -0,0 +1,64 @@
|
||||
import pprint
|
||||
import sys
|
||||
from threading import Thread
|
||||
|
||||
import frida
|
||||
|
||||
|
||||
def main():
|
||||
device = frida.get_usb_device()
|
||||
|
||||
stdout_uuid, stdout_stream = create_stdio_socket(device)
|
||||
stderr_uuid, stderr_stream = create_stdio_socket(device)
|
||||
|
||||
appservice = device.open_service("xpc:com.apple.coredevice.appservice")
|
||||
response = appservice.request(
|
||||
{
|
||||
"CoreDevice.featureIdentifier": "com.apple.coredevice.feature.launchapplication",
|
||||
"CoreDevice.action": {},
|
||||
"CoreDevice.input": {
|
||||
"applicationSpecifier": {
|
||||
"bundleIdentifier": {"_0": "no.oleavr.HelloIOS"},
|
||||
},
|
||||
"options": {
|
||||
"arguments": [],
|
||||
"environmentVariables": {},
|
||||
"standardIOUsesPseudoterminals": True,
|
||||
"startStopped": False,
|
||||
"terminateExisting": True,
|
||||
"user": {"active": True},
|
||||
"platformSpecificOptions": b'<?xml version="1.0" encoding="UTF-8"?><plist version="1.0"><dict/></plist>',
|
||||
},
|
||||
"standardIOIdentifiers": {
|
||||
"standardOutput": ("uuid", stdout_uuid),
|
||||
"standardError": ("uuid", stderr_uuid),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
pprint.pp(response)
|
||||
|
||||
workers = set()
|
||||
for stream, sink in {(stdout_stream, sys.stdout), (stderr_stream, sys.stderr)}:
|
||||
t = Thread(target=process_console_output, args=(stream, sink))
|
||||
t.start()
|
||||
workers.add(t)
|
||||
for worker in workers:
|
||||
worker.join()
|
||||
|
||||
|
||||
def create_stdio_socket(device):
|
||||
stream = device.open_channel("tcp:com.apple.coredevice.openstdiosocket")
|
||||
return (stream.read_all(16), stream)
|
||||
|
||||
|
||||
def process_console_output(stream, sink):
|
||||
while True:
|
||||
chunk = stream.read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
sink.write(chunk.decode("utf-8"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,15 @@
|
||||
import pprint
|
||||
|
||||
import frida
|
||||
|
||||
device = frida.get_usb_device()
|
||||
|
||||
appservice = device.open_service("xpc:com.apple.coredevice.appservice")
|
||||
response = appservice.request(
|
||||
{
|
||||
"CoreDevice.featureIdentifier": "com.apple.coredevice.feature.listprocesses",
|
||||
"CoreDevice.action": {},
|
||||
"CoreDevice.input": {},
|
||||
}
|
||||
)
|
||||
pprint.pp(response)
|
||||
@@ -342,6 +342,12 @@ class Device(Object):
|
||||
"""
|
||||
...
|
||||
|
||||
def open_service(self, address: str) -> Service:
|
||||
"""
|
||||
Open a device-specific service.
|
||||
"""
|
||||
...
|
||||
|
||||
def unpair(self) -> None:
|
||||
"""
|
||||
Unpair device.
|
||||
@@ -629,6 +635,25 @@ class Script(Object):
|
||||
"""
|
||||
...
|
||||
|
||||
class Service(Object):
|
||||
def activate(self) -> None:
|
||||
"""
|
||||
Activate the service.
|
||||
"""
|
||||
...
|
||||
|
||||
def cancel(self) -> None:
|
||||
"""
|
||||
Cancel the service.
|
||||
"""
|
||||
...
|
||||
|
||||
def request(self, parameters: Any) -> Any:
|
||||
"""
|
||||
Perform a request.
|
||||
"""
|
||||
...
|
||||
|
||||
class Session(Object):
|
||||
@property
|
||||
def pid(self) -> int:
|
||||
|
||||
+477
-253
File diff suppressed because it is too large
Load Diff
+98
-13
@@ -176,7 +176,8 @@ class ScriptExportsSync:
|
||||
js_name = _to_camel_case(name)
|
||||
|
||||
def method(*args: Any, **kwargs: Any) -> Any:
|
||||
return script._rpc_request("call", js_name, args, **kwargs)
|
||||
request, data = make_rpc_call_request(js_name, args)
|
||||
return script._rpc_request(request, data, **kwargs)
|
||||
|
||||
return method
|
||||
|
||||
@@ -202,7 +203,8 @@ class ScriptExportsAsync:
|
||||
js_name = _to_camel_case(name)
|
||||
|
||||
async def method(*args: Any, **kwargs: Any) -> Any:
|
||||
return await script._rpc_request_async("call", js_name, args, **kwargs)
|
||||
request, data = make_rpc_call_request(js_name, args)
|
||||
return await script._rpc_request_async(request, data, **kwargs)
|
||||
|
||||
return method
|
||||
|
||||
@@ -210,6 +212,16 @@ class ScriptExportsAsync:
|
||||
return self._script.list_exports_sync()
|
||||
|
||||
|
||||
def make_rpc_call_request(js_name: str, args: Sequence[Any]) -> Tuple[List[Any], Optional[bytes]]:
|
||||
if args and isinstance(args[-1], bytes):
|
||||
raw_args = args[:-1]
|
||||
data = args[-1]
|
||||
else:
|
||||
raw_args = args
|
||||
data = None
|
||||
return (["call", js_name, raw_args], data)
|
||||
|
||||
|
||||
class ScriptErrorMessage(TypedDict):
|
||||
type: Literal["error"]
|
||||
description: str
|
||||
@@ -404,7 +416,7 @@ class Script:
|
||||
Asynchronously list all the exported attributes from the script's rpc
|
||||
"""
|
||||
|
||||
result = await self._rpc_request_async("list")
|
||||
result = await self._rpc_request_async(["list"])
|
||||
assert isinstance(result, list)
|
||||
return result
|
||||
|
||||
@@ -413,7 +425,7 @@ class Script:
|
||||
List all the exported attributes from the script's rpc
|
||||
"""
|
||||
|
||||
result = self._rpc_request("list")
|
||||
result = self._rpc_request(["list"])
|
||||
assert isinstance(result, list)
|
||||
return result
|
||||
|
||||
@@ -429,7 +441,7 @@ class Script:
|
||||
)
|
||||
return self.list_exports_sync()
|
||||
|
||||
def _rpc_request_async(self, *args: Any) -> asyncio.Future[Any]:
|
||||
def _rpc_request_async(self, args: Any, data: Optional[bytes] = None) -> asyncio.Future[Any]:
|
||||
loop = asyncio.get_event_loop()
|
||||
future: asyncio.Future[Any] = asyncio.Future()
|
||||
|
||||
@@ -442,14 +454,14 @@ class Script:
|
||||
request_id = self._append_pending(on_complete)
|
||||
|
||||
if not self.is_destroyed:
|
||||
self._send_rpc_call(request_id, *args)
|
||||
self._send_rpc_call(request_id, args, data)
|
||||
else:
|
||||
self._on_destroyed()
|
||||
|
||||
return future
|
||||
|
||||
@cancellable
|
||||
def _rpc_request(self, *args: Any) -> Any:
|
||||
def _rpc_request(self, args: Any, data: Optional[bytes] = None) -> Any:
|
||||
result = RPCResult()
|
||||
|
||||
def on_complete(value: Any, error: Optional[Union[RPCException, _frida.InvalidOperationError]]) -> None:
|
||||
@@ -466,7 +478,7 @@ class Script:
|
||||
request_id = self._append_pending(on_complete)
|
||||
|
||||
if not self.is_destroyed:
|
||||
self._send_rpc_call(request_id, *args)
|
||||
self._send_rpc_call(request_id, args, data)
|
||||
|
||||
cancellable = Cancellable.get_current()
|
||||
cancel_handler = cancellable.connect(on_cancelled)
|
||||
@@ -495,10 +507,8 @@ class Script:
|
||||
self._pending[request_id] = callback
|
||||
return request_id
|
||||
|
||||
def _send_rpc_call(self, request_id: int, *args: Any) -> None:
|
||||
message = ["frida:rpc", request_id]
|
||||
message.extend(args)
|
||||
self.post(message)
|
||||
def _send_rpc_call(self, request_id: int, args: Any, data: Optional[bytes]) -> None:
|
||||
self.post(["frida:rpc", request_id, *args], data)
|
||||
|
||||
def _on_rpc_message(self, request_id: int, operation: str, params: List[Any], data: Optional[Any]) -> None:
|
||||
if operation in ("ok", "error"):
|
||||
@@ -509,7 +519,10 @@ class Script:
|
||||
value = None
|
||||
error = None
|
||||
if operation == "ok":
|
||||
value = params[0] if data is None else data
|
||||
if data is not None:
|
||||
value = (params[1], data) if len(params) > 1 else data
|
||||
else:
|
||||
value = params[0]
|
||||
else:
|
||||
error = RPCException(*params[0:3])
|
||||
|
||||
@@ -792,6 +805,70 @@ class Bus:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
ServiceCloseCallback = Callable[[], None]
|
||||
ServiceMessageCallback = Callable[[Any], None]
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, impl: _frida.Service) -> None:
|
||||
self._impl = impl
|
||||
|
||||
@cancellable
|
||||
def activate(self) -> None:
|
||||
"""
|
||||
Activate the service
|
||||
"""
|
||||
|
||||
self._impl.activate()
|
||||
|
||||
@cancellable
|
||||
def cancel(self) -> None:
|
||||
"""
|
||||
Cancel the service
|
||||
"""
|
||||
|
||||
self._impl.cancel()
|
||||
|
||||
def request(self, parameters: Any) -> Any:
|
||||
"""
|
||||
Perform a request
|
||||
"""
|
||||
|
||||
return self._impl.request(parameters)
|
||||
|
||||
@overload
|
||||
def on(self, signal: Literal["close"], callback: ServiceCloseCallback) -> None: ...
|
||||
|
||||
@overload
|
||||
def on(self, signal: Literal["message"], callback: ServiceMessageCallback) -> None: ...
|
||||
|
||||
@overload
|
||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
||||
|
||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||
"""
|
||||
Add a signal handler
|
||||
"""
|
||||
|
||||
self._impl.on(signal, callback)
|
||||
|
||||
@overload
|
||||
def off(self, signal: Literal["close"], callback: ServiceCloseCallback) -> None: ...
|
||||
|
||||
@overload
|
||||
def off(self, signal: Literal["message"], callback: ServiceMessageCallback) -> None: ...
|
||||
|
||||
@overload
|
||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
||||
|
||||
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||
"""
|
||||
Remove a signal handler
|
||||
"""
|
||||
|
||||
self._impl.off(signal, callback)
|
||||
|
||||
|
||||
DeviceSpawnAddedCallback = Callable[[_frida.Spawn], None]
|
||||
DeviceSpawnRemovedCallback = Callable[[_frida.Spawn], None]
|
||||
DeviceChildAddedCallback = Callable[[_frida.Child], None]
|
||||
@@ -1019,6 +1096,14 @@ class Device:
|
||||
|
||||
return IOStream(self._impl.open_channel(address))
|
||||
|
||||
@cancellable
|
||||
def open_service(self, address: str) -> Service:
|
||||
"""
|
||||
Open a device-specific service
|
||||
"""
|
||||
|
||||
return Service(self._impl.open_service(address))
|
||||
|
||||
@cancellable
|
||||
def unpair(self) -> None:
|
||||
"""
|
||||
|
||||
+1
-1
Submodule releng updated: 6bad5eec71...4622f5c4c4
@@ -1,6 +1,6 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/frida/frida-core.git
|
||||
revision = 16.2.4
|
||||
revision = 16.5.6
|
||||
depth = 1
|
||||
|
||||
[provide]
|
||||
|
||||
+21
-8
@@ -31,19 +31,26 @@ class TestRpc(unittest.TestCase):
|
||||
name="test-rpc",
|
||||
source="""\
|
||||
rpc.exports = {
|
||||
add: function (a, b) {
|
||||
var result = a + b;
|
||||
add(a, b) {
|
||||
const result = a + b;
|
||||
if (result < 0)
|
||||
throw new Error("No");
|
||||
throw new Error("No");
|
||||
return result;
|
||||
},
|
||||
sub: function (a, b) {
|
||||
sub(a, b) {
|
||||
return a - b;
|
||||
},
|
||||
speak: function () {
|
||||
var buf = Memory.allocUtf8String("Yo");
|
||||
speak() {
|
||||
const buf = Memory.allocUtf8String("Yo");
|
||||
return Memory.readByteArray(buf, 2);
|
||||
}
|
||||
},
|
||||
speakWithMetadata() {
|
||||
const buf = Memory.allocUtf8String("Yo");
|
||||
return ['soft', Memory.readByteArray(buf, 2)];
|
||||
},
|
||||
processData(val, data) {
|
||||
return { val, dump: hexdump(data, { header: false }) };
|
||||
},
|
||||
};
|
||||
""",
|
||||
)
|
||||
@@ -52,7 +59,13 @@ rpc.exports = {
|
||||
self.assertEqual(agent.add(2, 3), 5)
|
||||
self.assertEqual(agent.sub(5, 3), 2)
|
||||
self.assertRaises(Exception, lambda: agent.add(1, -2))
|
||||
self.assertListEqual([x for x in iter(agent.speak())], [0x59, 0x6F])
|
||||
self.assertEqual(agent.speak(), b"\x59\x6f")
|
||||
meta, data = agent.speak_with_metadata()
|
||||
self.assertEqual(meta, "soft")
|
||||
self.assertEqual(data, b"\x59\x6f")
|
||||
result = agent.process_data(1337, b"\x13\x37")
|
||||
self.assertEqual(result["val"], 1337)
|
||||
self.assertEqual(result["dump"], "00000000 13 37 .7")
|
||||
|
||||
def test_post_failure(self):
|
||||
script = self.session.create_script(
|
||||
|
||||
Reference in New Issue
Block a user