mirror of
https://github.com/frida/frida-python
synced 2026-06-08 14:16:17 +00:00
Compare commits
456 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dbe7868509 | |||
| a0867d30b9 | |||
| 0666e8d33c | |||
| 60c30102bf | |||
| d50d5cc6d0 | |||
| ddeaad5254 | |||
| c68cd908d3 | |||
| 5b6d9f378a | |||
| 0839e57d3b | |||
| 5215b5b2c8 | |||
| 54dca1d5da | |||
| 8eafeb24d9 | |||
| 1b75d93858 | |||
| c2145f3589 | |||
| 0a9995df51 | |||
| 0f3ffd4032 | |||
| 2da64cb7ca | |||
| f81c3183a1 | |||
| d2861db65b | |||
| 06210bec40 | |||
| 4934e18a0e | |||
| fe987827e9 | |||
| 0ef38236e8 | |||
| 0fab765f91 | |||
| a6c02cb7ee | |||
| 6033dd0904 | |||
| 77e94e24a1 | |||
| c97343dc83 | |||
| e1ffe5fd50 | |||
| c7314098c6 | |||
| 41d769fa4d | |||
| 044d23eef7 | |||
| 1641af6ca3 | |||
| e513eca572 | |||
| 15260bfa4a | |||
| dec8aca9ae | |||
| 8c69b9d032 | |||
| f57b0c1cfa | |||
| fd2c1f2424 | |||
| a9caf62a0c | |||
| 8bc4415f34 | |||
| e3eca3179c | |||
| ef190d9957 | |||
| 1e06ebe9a3 | |||
| 925378439c | |||
| 7ae323a3cd | |||
| 9c5985c254 | |||
| b469134be4 | |||
| 9933d916ae | |||
| 09cac4e2a5 | |||
| 6b49e14ce1 | |||
| 7711fa12ac | |||
| d468dc038c | |||
| 58ff000596 | |||
| 3652e985d8 | |||
| 210c56e1b2 | |||
| b3d6aa8ffe | |||
| 16eb645844 | |||
| b7b1fcf0ff | |||
| 978b756134 | |||
| 7b1fc43a42 | |||
| 244cf6926b | |||
| 24b941fb8a | |||
| e2b340eda1 | |||
| 2b306c6d30 | |||
| 57cee13b43 | |||
| 23aa442826 | |||
| 65236f3b05 | |||
| e52e7a95bd | |||
| 3b57222cfa | |||
| 319ac9e699 | |||
| 2e842a4e44 | |||
| f9bf571497 | |||
| 8f50f743e1 | |||
| 6da337df6f | |||
| e29d41806c | |||
| 8faf01dc2e | |||
| 4286667bc6 | |||
| 86d4b4b4bf | |||
| b5808d7b27 | |||
| 5466050755 | |||
| 4db854a02c | |||
| cc9a78ef19 | |||
| 22ed1fac3c | |||
| 9b15bde24e | |||
| a613d87b08 | |||
| 9ef240eff4 | |||
| 43a443f582 | |||
| dcc95216fd | |||
| 69e7c6c0ce | |||
| 3278173be8 | |||
| d8fa422062 | |||
| 3943d2eed2 | |||
| 8030b5aa68 | |||
| fa5f378176 | |||
| a814a4aa9b | |||
| a48ff22b6f | |||
| eb4f8d37f3 | |||
| 60a4a032d6 | |||
| 9f46dfaa80 | |||
| e57ca181f8 | |||
| 0fccd75bc7 | |||
| dea4ffb1c9 | |||
| da17d3badb | |||
| 33922241fc | |||
| fb8fdbb231 | |||
| 0f50b58a04 | |||
| f63ea5903f | |||
| a99767e501 | |||
| 07bbd3d488 | |||
| 81403cf383 | |||
| 2ea0b944a2 | |||
| 35c412c6cf | |||
| ec4524d155 | |||
| d9d53a89cc | |||
| dfb002de49 | |||
| 0f56e44abd | |||
| d28a2a4988 | |||
| 1fc39289ef | |||
| 2c757a08f3 | |||
| fc735c048f | |||
| 4d84536160 | |||
| 9e51c78c5c | |||
| a6d51e8384 | |||
| 3e80ed726d | |||
| 985410b6ff | |||
| 21c7b9ee6a | |||
| 7fba1cdc67 | |||
| a709856e2a | |||
| c3afe6089d | |||
| 6435a78d13 | |||
| 09175036ea | |||
| e0c90c5203 | |||
| 9f463fb602 | |||
| 9fdee2270f | |||
| 6e536a56b1 | |||
| 74925d082e | |||
| bf1245ddb0 | |||
| 0f247e9439 | |||
| 17aae5fe5c | |||
| 477a90534e | |||
| c87cdca293 | |||
| 30968b3805 | |||
| 5e3f27d0cb | |||
| 904461eb01 | |||
| dc652faa90 | |||
| f5ba22ad36 | |||
| dccb6810ca | |||
| 82441c6d61 | |||
| 323dca48c2 | |||
| ef71f0fa92 | |||
| e92e829f6d | |||
| 5793fb5528 | |||
| cac6993d87 | |||
| 714b7f8626 | |||
| ab0b9e98ae | |||
| 19a7fa4f45 | |||
| 38552a368a | |||
| 38724cab58 | |||
| b60d085ad9 | |||
| 1a4afbcc62 | |||
| 9e15cab647 | |||
| 9ef1c9c1f7 | |||
| 3da6af4759 | |||
| a9075822b1 | |||
| 2e61509c04 | |||
| aa9396c6b0 | |||
| 6530b2a7d4 | |||
| 2d833af062 | |||
| 9f6ab2d384 | |||
| a005f1bf4c | |||
| 59a24aa48f | |||
| 782d626419 | |||
| 3aa122f4fd | |||
| ef315fc0ad | |||
| daf93eea54 | |||
| 5d02a36906 | |||
| ba8daa423d | |||
| afb27bfa7c | |||
| 93a201acf2 | |||
| ca1cdad96a | |||
| fbc83cc9bf | |||
| b838e1df9a | |||
| e2409be987 | |||
| b061ea43d2 | |||
| a50a62999a | |||
| 3a47d33ee8 | |||
| ea93d827bb | |||
| 8d4c05f664 | |||
| 2f78c96622 | |||
| 4b5aa28119 | |||
| 4f87afa0f1 | |||
| 82272945ac | |||
| bf496a81d9 | |||
| c2dcae3ff4 | |||
| 0cb42c47dc | |||
| 0e3a9fb551 | |||
| 4e16e5c667 | |||
| 09d6c7b044 | |||
| e11efce5c2 | |||
| e174be9998 | |||
| eae3d1dc65 | |||
| 2d26b94c7d | |||
| f396958dfe | |||
| 93fb33206f | |||
| aed3c1b7bf | |||
| 690da0652d | |||
| bec6221c02 | |||
| 53479e1814 | |||
| 68bc65ecd4 | |||
| 6492081c92 | |||
| 262b984e23 | |||
| 730ec03652 | |||
| 25f96f92d3 | |||
| dec23f9ef5 | |||
| 906d27bcb7 | |||
| b0018c9812 | |||
| 5e011e6d64 | |||
| b68dda4eb5 | |||
| 6fbe238c1a | |||
| 4d750dfe58 | |||
| fe1c61ce5d | |||
| ea91df0d77 | |||
| b78ae7555f | |||
| b456683f2d | |||
| ddfe2b1a3b | |||
| 329795dbfc | |||
| e9c62fd581 | |||
| 40e945107d | |||
| 6c27bf0da7 | |||
| d37451f3bc | |||
| 6d4e4e27ee | |||
| 33a9c51387 | |||
| 4344eb9220 | |||
| 3a94e642d7 | |||
| 7a5948a95a | |||
| bbe926c606 | |||
| b653958fa4 | |||
| bca5146b74 | |||
| 2bd254702c | |||
| 82ee16d299 | |||
| 51501ceacb | |||
| ef45347385 | |||
| 0024f6719a | |||
| 87de091250 | |||
| cf4870e13d | |||
| 2ac00cb1e2 | |||
| dd94c73d4f | |||
| 40eb2dae38 | |||
| 73004f9598 | |||
| a0e9e64346 | |||
| 2706e19615 | |||
| 6edaf679ac | |||
| c2c45ce231 | |||
| 0180450178 | |||
| e07370158d | |||
| f73fdff4ee | |||
| b565fa19dc | |||
| 58d5ea9e2f | |||
| 91826487e1 | |||
| b1abfd53fa | |||
| 1afde6cb34 | |||
| 6bee5f45f3 | |||
| efc1009ece | |||
| 3def865cf8 | |||
| 3c41862ac5 | |||
| 4bd11602d7 | |||
| d07c8a16cd | |||
| 4e6d28cba7 | |||
| e0562ed0bc | |||
| 9dc17772cd | |||
| 0f9f4a5da8 | |||
| 4a9fb75adf | |||
| c37ef15695 | |||
| f6ad8a504d | |||
| 808e4ab6b5 | |||
| 50ee91f63f | |||
| 56dc49b5fb | |||
| 4cbb5881bd | |||
| 6ff0e34ca3 | |||
| 4df903dca5 | |||
| 6ed81cbfb6 | |||
| 98cc4c44bc | |||
| 6190b3c57b | |||
| 212973bbc1 | |||
| 79f7ae1deb | |||
| 522366a55e | |||
| 8017d10e3e | |||
| e78a5fd3b3 | |||
| 5cbef2fb1f | |||
| 8694918de7 | |||
| ab16fe04c5 | |||
| a1d1740541 | |||
| 09d2a1aa54 | |||
| 215669c151 | |||
| f7b08f8375 | |||
| 133687aafc | |||
| 06130770e1 | |||
| 2d72d0be57 | |||
| d463d7f2f2 | |||
| 11613adee6 | |||
| 8dc6509929 | |||
| 3f8b122ce7 | |||
| 29abf88e31 | |||
| 5370147e85 | |||
| 507917744d | |||
| 8f2858fd8d | |||
| c2cf7fa951 | |||
| 9ff0651481 | |||
| 2674d6ef7d | |||
| 5d65919693 | |||
| d453cdd5ba | |||
| e8fd88f3d4 | |||
| 414cf0e029 | |||
| 76825537e8 | |||
| 2ab18cf80f | |||
| aaa703436b | |||
| 387962ab9d | |||
| 97f4c236a6 | |||
| 88cb2c97b8 | |||
| ec5035fd96 | |||
| bd883147ed | |||
| f7c32b2772 | |||
| 68009a8df9 | |||
| 85d56a0e45 | |||
| 228610a79c | |||
| d4b1b6aa8b | |||
| 29661c6b3b | |||
| d5b2a6fd18 | |||
| b862e9ae82 | |||
| 6e6f84969d | |||
| d6933eccf3 | |||
| 3bee61ffdb | |||
| 647e45f8bf | |||
| 5b6cfeba8b | |||
| c2b8043d8d | |||
| 69a4fa2ad2 | |||
| 546f65f25b | |||
| 168fcd5fe6 | |||
| 2ae7df42d0 | |||
| e8eff270ce | |||
| 62b6839d12 | |||
| d83456efe7 | |||
| fa62593fed | |||
| 305d2c1360 | |||
| 67b563a72c | |||
| d988aa2920 | |||
| d346babcf9 | |||
| 96a3777eb0 | |||
| 6c4ad9bf98 | |||
| 0490814f79 | |||
| 3c21f23327 | |||
| fe24ef56d1 | |||
| 2d8dca8d53 | |||
| 77f7d0f3c3 | |||
| c8f3b40aad | |||
| 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 @@
|
|||||||
|
github: frida
|
||||||
@@ -42,18 +42,16 @@ class Application:
|
|||||||
print("✔ enable_child_gating()")
|
print("✔ enable_child_gating()")
|
||||||
session.enable_child_gating()
|
session.enable_child_gating()
|
||||||
print("✔ create_script()")
|
print("✔ create_script()")
|
||||||
script = session.create_script(
|
script = session.create_script("""\
|
||||||
"""\
|
Interceptor.attach(Module.getGlobalExportByName('open'), {
|
||||||
Interceptor.attach(Module.getExportByName(null, 'open'), {
|
onEnter(args) {
|
||||||
onEnter: function (args) {
|
|
||||||
send({
|
send({
|
||||||
type: 'open',
|
type: 'open',
|
||||||
path: Memory.readUtf8String(args[0])
|
path: args[0].readUtf8String()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message)))
|
script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message)))
|
||||||
print("✔ load()")
|
print("✔ load()")
|
||||||
script.load()
|
script.load()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def on_uninjected(id):
|
|||||||
print("on_uninjected id=%u" % id)
|
print("on_uninjected id=%u" % id)
|
||||||
|
|
||||||
|
|
||||||
(target, library_path) = sys.argv[1:]
|
target, library_path = sys.argv[1:]
|
||||||
|
|
||||||
device = frida.get_local_device()
|
device = frida.get_local_device()
|
||||||
device.on("uninjected", on_uninjected)
|
device.on("uninjected", on_uninjected)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def on_uninjected(id):
|
|||||||
print("on_uninjected id=%u" % id)
|
print("on_uninjected id=%u" % id)
|
||||||
|
|
||||||
|
|
||||||
(target, library_path) = sys.argv[1:]
|
target, library_path = sys.argv[1:]
|
||||||
|
|
||||||
device = frida.get_local_device()
|
device = frida.get_local_device()
|
||||||
device.on("uninjected", on_uninjected)
|
device.on("uninjected", on_uninjected)
|
||||||
|
|||||||
@@ -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)
|
||||||
+2
-4
@@ -1,8 +1,7 @@
|
|||||||
import frida
|
import frida
|
||||||
|
|
||||||
session = frida.attach("Twitter")
|
session = frida.attach("Twitter")
|
||||||
script = session.create_script(
|
script = session.create_script("""\
|
||||||
"""\
|
|
||||||
rpc.exports = {
|
rpc.exports = {
|
||||||
hello: function () {
|
hello: function () {
|
||||||
return 'Hello';
|
return 'Hello';
|
||||||
@@ -11,8 +10,7 @@ rpc.exports = {
|
|||||||
oops;
|
oops;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
script.load()
|
script.load()
|
||||||
api = script.exports_sync
|
api = script.exports_sync
|
||||||
print("api.hello() =>", api.hello())
|
print("api.hello() =>", api.hello())
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ class Application:
|
|||||||
self._session = session
|
self._session = session
|
||||||
session.on("detached", lambda *args: self._reactor.schedule(lambda: self._on_detached(*args)))
|
session.on("detached", lambda *args: self._reactor.schedule(lambda: self._on_detached(*args)))
|
||||||
|
|
||||||
script = session.create_script(
|
script = session.create_script("""
|
||||||
"""
|
|
||||||
let _puts = null;
|
let _puts = null;
|
||||||
|
|
||||||
Interceptor.attach(DebugSymbol.getFunctionByName('f'), {
|
Interceptor.attach(DebugSymbol.getFunctionByName('f'), {
|
||||||
@@ -48,8 +47,7 @@ function puts(s) {
|
|||||||
}
|
}
|
||||||
_puts(Memory.allocUtf8String(s));
|
_puts(Memory.allocUtf8String(s));
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
self._script = script
|
self._script = script
|
||||||
script.on("message", lambda *args: self._reactor.schedule(lambda: self._on_message(*args)))
|
script.on("message", lambda *args: self._reactor.schedule(lambda: self._on_message(*args)))
|
||||||
script.load()
|
script.load()
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
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()
|
||||||
+20
-3
@@ -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:
|
try:
|
||||||
from . import _frida
|
from . import _frida
|
||||||
@@ -23,6 +23,7 @@ Relay = _frida.Relay
|
|||||||
PortalService = core.PortalService
|
PortalService = core.PortalService
|
||||||
EndpointParameters = core.EndpointParameters
|
EndpointParameters = core.EndpointParameters
|
||||||
Compiler = core.Compiler
|
Compiler = core.Compiler
|
||||||
|
PackageManager = core.PackageManager
|
||||||
FileMonitor = _frida.FileMonitor
|
FileMonitor = _frida.FileMonitor
|
||||||
Cancellable = core.Cancellable
|
Cancellable = core.Cancellable
|
||||||
|
|
||||||
@@ -85,14 +86,30 @@ def kill(target: core.ProcessTarget) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def attach(
|
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:
|
) -> core.Session:
|
||||||
"""
|
"""
|
||||||
Attach to a process
|
Attach to a process
|
||||||
:param target: the PID or name of the 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:
|
def inject_library_file(target: core.ProcessTarget, path: str, entrypoint: str, data: str) -> int:
|
||||||
|
|||||||
+136
-1
@@ -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.
|
Attach to a PID.
|
||||||
"""
|
"""
|
||||||
@@ -342,6 +352,12 @@ class Device(Object):
|
|||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def open_service(self, address: str) -> Service:
|
||||||
|
"""
|
||||||
|
Open a device-specific service.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
def unpair(self) -> None:
|
def unpair(self) -> None:
|
||||||
"""
|
"""
|
||||||
Unpair device.
|
Unpair device.
|
||||||
@@ -629,6 +645,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):
|
class Session(Object):
|
||||||
@property
|
@property
|
||||||
def pid(self) -> int:
|
def pid(self) -> int:
|
||||||
@@ -729,8 +764,13 @@ class Compiler(Object):
|
|||||||
self,
|
self,
|
||||||
entrypoint: str,
|
entrypoint: str,
|
||||||
project_root: Optional[str] = None,
|
project_root: Optional[str] = None,
|
||||||
|
output_format: Optional[str] = None,
|
||||||
|
bundle_format: Optional[str] = None,
|
||||||
|
type_check: Optional[str] = None,
|
||||||
source_maps: Optional[str] = None,
|
source_maps: Optional[str] = None,
|
||||||
compression: Optional[str] = None,
|
compression: Optional[str] = None,
|
||||||
|
platform: Optional[str] = None,
|
||||||
|
externals: Optional[Sequence[str]] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Build an agent.
|
Build an agent.
|
||||||
@@ -741,12 +781,107 @@ class Compiler(Object):
|
|||||||
self,
|
self,
|
||||||
entrypoint: str,
|
entrypoint: str,
|
||||||
project_root: Optional[str] = None,
|
project_root: Optional[str] = None,
|
||||||
|
output_format: Optional[str] = None,
|
||||||
|
bundle_format: Optional[str] = None,
|
||||||
|
type_check: Optional[str] = None,
|
||||||
source_maps: Optional[str] = None,
|
source_maps: Optional[str] = None,
|
||||||
compression: Optional[str] = None,
|
compression: Optional[str] = None,
|
||||||
|
platform: Optional[str] = None,
|
||||||
|
externals: Optional[Sequence[str]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Continuously build an agent.
|
Continuously build an agent.
|
||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
|
|
||||||
|
class PackageManager(Object):
|
||||||
|
@property
|
||||||
|
def registry(self) -> str:
|
||||||
|
"""
|
||||||
|
The registry being used.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
@registry.setter
|
||||||
|
def registry(self, value: str) -> None:
|
||||||
|
"""
|
||||||
|
Change the registry to use.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
def search(
|
||||||
|
self,
|
||||||
|
query: str,
|
||||||
|
offset: Optional[int] = None,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
) -> PackageSearchResult:
|
||||||
|
"""
|
||||||
|
Search for packages to install.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
def install(
|
||||||
|
self,
|
||||||
|
project_root: Optional[str] = None,
|
||||||
|
role: Optional[str] = None,
|
||||||
|
specs: Optional[Sequence[str]] = None,
|
||||||
|
omits: Optional[Sequence[str]] = None,
|
||||||
|
) -> PackageInstallResult:
|
||||||
|
"""
|
||||||
|
Install one or more packages.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
class Package(Object):
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
"""
|
||||||
|
Package name.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self) -> str:
|
||||||
|
"""
|
||||||
|
Package version.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Package description.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Package URL.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
class PackageSearchResult(Object):
|
||||||
|
@property
|
||||||
|
def packages(self) -> List[Package]:
|
||||||
|
"""
|
||||||
|
Batch of matching packages.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total(self) -> int:
|
||||||
|
"""
|
||||||
|
Total matching packages.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
|
class PackageInstallResult(Object):
|
||||||
|
@property
|
||||||
|
def packages(self) -> List[Package]:
|
||||||
|
"""
|
||||||
|
The toplevel packages that are installed.
|
||||||
|
"""
|
||||||
|
...
|
||||||
|
|
||||||
__version__: str
|
__version__: str
|
||||||
|
|||||||
+1326
-284
File diff suppressed because it is too large
Load Diff
+257
-76
@@ -33,10 +33,15 @@ if sys.version_info >= (3, 8):
|
|||||||
else:
|
else:
|
||||||
from typing_extensions import Literal, TypedDict
|
from typing_extensions import Literal, TypedDict
|
||||||
|
|
||||||
if sys.version_info >= (3, 11):
|
if sys.version_info >= (3, 10):
|
||||||
from typing import NotRequired
|
from typing import ParamSpec
|
||||||
else:
|
else:
|
||||||
from typing_extensions import NotRequired
|
from typing_extensions import ParamSpec
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
from typing import NotRequired, cast
|
||||||
|
else:
|
||||||
|
from typing_extensions import NotRequired, cast
|
||||||
|
|
||||||
from . import _frida
|
from . import _frida
|
||||||
|
|
||||||
@@ -72,15 +77,18 @@ def _filter_missing_kwargs(d: MutableMapping[Any, Any]) -> None:
|
|||||||
d.pop(key)
|
d.pop(key)
|
||||||
|
|
||||||
|
|
||||||
R = TypeVar("R")
|
P = ParamSpec("P")
|
||||||
|
R = TypeVar("R", covariant=True)
|
||||||
|
|
||||||
|
|
||||||
def cancellable(f: Callable[..., R]) -> Callable[..., R]:
|
def cancellable(f: Callable[P, R]) -> Callable[P, R]:
|
||||||
|
# currently there is no way to type properly the extended callable with optional cancellable parameter
|
||||||
|
# ref: https://github.com/python/typing/discussions/1905#discussioncomment-11696995
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapper(*args: Any, **kwargs: Any) -> R:
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
||||||
cancellable = kwargs.pop("cancellable", None)
|
cancellable = kwargs.pop("cancellable", None)
|
||||||
if cancellable is not None:
|
if cancellable is not None:
|
||||||
with cancellable:
|
with cast(Cancellable, cancellable):
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
@@ -176,7 +184,8 @@ class ScriptExportsSync:
|
|||||||
js_name = _to_camel_case(name)
|
js_name = _to_camel_case(name)
|
||||||
|
|
||||||
def method(*args: Any, **kwargs: Any) -> Any:
|
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
|
return method
|
||||||
|
|
||||||
@@ -202,7 +211,8 @@ class ScriptExportsAsync:
|
|||||||
js_name = _to_camel_case(name)
|
js_name = _to_camel_case(name)
|
||||||
|
|
||||||
async def method(*args: Any, **kwargs: Any) -> Any:
|
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
|
return method
|
||||||
|
|
||||||
@@ -210,6 +220,16 @@ class ScriptExportsAsync:
|
|||||||
return self._script.list_exports_sync()
|
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):
|
class ScriptErrorMessage(TypedDict):
|
||||||
type: Literal["error"]
|
type: Literal["error"]
|
||||||
description: str
|
description: str
|
||||||
@@ -339,9 +359,6 @@ class Script:
|
|||||||
@overload
|
@overload
|
||||||
def on(self, signal: Literal["message"], callback: ScriptMessageCallback) -> None: ...
|
def on(self, signal: Literal["message"], callback: ScriptMessageCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Add a signal handler
|
Add a signal handler
|
||||||
@@ -358,9 +375,6 @@ class Script:
|
|||||||
@overload
|
@overload
|
||||||
def off(self, signal: Literal["message"], callback: ScriptMessageCallback) -> None: ...
|
def off(self, signal: Literal["message"], callback: ScriptMessageCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Remove a signal handler
|
Remove a signal handler
|
||||||
@@ -404,7 +418,7 @@ class Script:
|
|||||||
Asynchronously list all the exported attributes from the script's rpc
|
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)
|
assert isinstance(result, list)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -413,7 +427,7 @@ class Script:
|
|||||||
List all the exported attributes from the script's rpc
|
List all the exported attributes from the script's rpc
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = self._rpc_request("list")
|
result = self._rpc_request(["list"])
|
||||||
assert isinstance(result, list)
|
assert isinstance(result, list)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -429,7 +443,7 @@ class Script:
|
|||||||
)
|
)
|
||||||
return self.list_exports_sync()
|
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()
|
loop = asyncio.get_event_loop()
|
||||||
future: asyncio.Future[Any] = asyncio.Future()
|
future: asyncio.Future[Any] = asyncio.Future()
|
||||||
|
|
||||||
@@ -442,14 +456,14 @@ class Script:
|
|||||||
request_id = self._append_pending(on_complete)
|
request_id = self._append_pending(on_complete)
|
||||||
|
|
||||||
if not self.is_destroyed:
|
if not self.is_destroyed:
|
||||||
self._send_rpc_call(request_id, *args)
|
self._send_rpc_call(request_id, args, data)
|
||||||
else:
|
else:
|
||||||
self._on_destroyed()
|
self._on_destroyed()
|
||||||
|
|
||||||
return future
|
return future
|
||||||
|
|
||||||
@cancellable
|
@cancellable
|
||||||
def _rpc_request(self, *args: Any) -> Any:
|
def _rpc_request(self, args: Any, data: Optional[bytes] = None) -> Any:
|
||||||
result = RPCResult()
|
result = RPCResult()
|
||||||
|
|
||||||
def on_complete(value: Any, error: Optional[Union[RPCException, _frida.InvalidOperationError]]) -> None:
|
def on_complete(value: Any, error: Optional[Union[RPCException, _frida.InvalidOperationError]]) -> None:
|
||||||
@@ -466,7 +480,7 @@ class Script:
|
|||||||
request_id = self._append_pending(on_complete)
|
request_id = self._append_pending(on_complete)
|
||||||
|
|
||||||
if not self.is_destroyed:
|
if not self.is_destroyed:
|
||||||
self._send_rpc_call(request_id, *args)
|
self._send_rpc_call(request_id, args, data)
|
||||||
|
|
||||||
cancellable = Cancellable.get_current()
|
cancellable = Cancellable.get_current()
|
||||||
cancel_handler = cancellable.connect(on_cancelled)
|
cancel_handler = cancellable.connect(on_cancelled)
|
||||||
@@ -495,10 +509,8 @@ class Script:
|
|||||||
self._pending[request_id] = callback
|
self._pending[request_id] = callback
|
||||||
return request_id
|
return request_id
|
||||||
|
|
||||||
def _send_rpc_call(self, request_id: int, *args: Any) -> None:
|
def _send_rpc_call(self, request_id: int, args: Any, data: Optional[bytes]) -> None:
|
||||||
message = ["frida:rpc", request_id]
|
self.post(["frida:rpc", request_id, *args], data)
|
||||||
message.extend(args)
|
|
||||||
self.post(message)
|
|
||||||
|
|
||||||
def _on_rpc_message(self, request_id: int, operation: str, params: List[Any], data: Optional[Any]) -> None:
|
def _on_rpc_message(self, request_id: int, operation: str, params: List[Any], data: Optional[Any]) -> None:
|
||||||
if operation in ("ok", "error"):
|
if operation in ("ok", "error"):
|
||||||
@@ -509,7 +521,10 @@ class Script:
|
|||||||
value = None
|
value = None
|
||||||
error = None
|
error = None
|
||||||
if operation == "ok":
|
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:
|
else:
|
||||||
error = RPCException(*params[0:3])
|
error = RPCException(*params[0:3])
|
||||||
|
|
||||||
@@ -680,34 +695,22 @@ class Session:
|
|||||||
_filter_missing_kwargs(kwargs)
|
_filter_missing_kwargs(kwargs)
|
||||||
return PortalMembership(self._impl.join_portal(address, **kwargs))
|
return PortalMembership(self._impl.join_portal(address, **kwargs))
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(
|
def on(
|
||||||
self,
|
self,
|
||||||
signal: Literal["detached"],
|
signal: Literal["detached"],
|
||||||
callback: SessionDetachedCallback,
|
callback: SessionDetachedCallback,
|
||||||
) -> None: ...
|
) -> None:
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
|
||||||
"""
|
"""
|
||||||
Add a signal handler
|
Add a signal handler
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._impl.on(signal, callback)
|
self._impl.on(signal, callback)
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(
|
def off(
|
||||||
self,
|
self,
|
||||||
signal: Literal["detached"],
|
signal: Literal["detached"],
|
||||||
callback: SessionDetachedCallback,
|
callback: SessionDetachedCallback,
|
||||||
) -> None: ...
|
) -> None:
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
|
||||||
"""
|
"""
|
||||||
Remove a signal handler
|
Remove a signal handler
|
||||||
"""
|
"""
|
||||||
@@ -750,9 +753,6 @@ class Bus:
|
|||||||
@overload
|
@overload
|
||||||
def on(self, signal: Literal["message"], callback: BusMessageCallback) -> None: ...
|
def on(self, signal: Literal["message"], callback: BusMessageCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Add a signal handler
|
Add a signal handler
|
||||||
@@ -769,9 +769,6 @@ class Bus:
|
|||||||
@overload
|
@overload
|
||||||
def off(self, signal: Literal["message"], callback: BusMessageCallback) -> None: ...
|
def off(self, signal: Literal["message"], callback: BusMessageCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Remove a signal handler
|
Remove a signal handler
|
||||||
@@ -792,6 +789,64 @@ class Bus:
|
|||||||
traceback.print_exc()
|
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: ...
|
||||||
|
|
||||||
|
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: ...
|
||||||
|
|
||||||
|
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
|
"""
|
||||||
|
Remove a signal handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._impl.off(signal, callback)
|
||||||
|
|
||||||
|
|
||||||
DeviceSpawnAddedCallback = Callable[[_frida.Spawn], None]
|
DeviceSpawnAddedCallback = Callable[[_frida.Spawn], None]
|
||||||
DeviceSpawnRemovedCallback = Callable[[_frida.Spawn], None]
|
DeviceSpawnRemovedCallback = Callable[[_frida.Spawn], None]
|
||||||
DeviceChildAddedCallback = Callable[[_frida.Child], None]
|
DeviceChildAddedCallback = Callable[[_frida.Child], None]
|
||||||
@@ -828,6 +883,14 @@ class Device:
|
|||||||
|
|
||||||
return self._impl.is_lost()
|
return self._impl.is_lost()
|
||||||
|
|
||||||
|
@cancellable
|
||||||
|
def override_option(self, name: str, value: Any) -> None:
|
||||||
|
"""
|
||||||
|
Override a backend-specific option
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._impl.override_option(name, value)
|
||||||
|
|
||||||
@cancellable
|
@cancellable
|
||||||
def query_system_parameters(self) -> Dict[str, Any]:
|
def query_system_parameters(self) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
@@ -983,13 +1046,26 @@ class Device:
|
|||||||
target: ProcessTarget,
|
target: ProcessTarget,
|
||||||
realm: Optional[str] = None,
|
realm: Optional[str] = None,
|
||||||
persist_timeout: Optional[int] = 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:
|
) -> Session:
|
||||||
"""
|
"""
|
||||||
Attach to a process
|
Attach to a process
|
||||||
:param target: the PID or name of the process
|
:param target: the PID or name of the process
|
||||||
"""
|
"""
|
||||||
|
|
||||||
kwargs = {"realm": realm, "persist_timeout": persist_timeout}
|
kwargs = {
|
||||||
|
"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,
|
||||||
|
}
|
||||||
_filter_missing_kwargs(kwargs)
|
_filter_missing_kwargs(kwargs)
|
||||||
return Session(self._impl.attach(self._pid_of(target), **kwargs)) # type: ignore
|
return Session(self._impl.attach(self._pid_of(target), **kwargs)) # type: ignore
|
||||||
|
|
||||||
@@ -1019,6 +1095,14 @@ class Device:
|
|||||||
|
|
||||||
return IOStream(self._impl.open_channel(address))
|
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
|
@cancellable
|
||||||
def unpair(self) -> None:
|
def unpair(self) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -1059,9 +1143,6 @@ class Device:
|
|||||||
@overload
|
@overload
|
||||||
def on(self, signal: Literal["lost"], callback: DeviceLostCallback) -> None: ...
|
def on(self, signal: Literal["lost"], callback: DeviceLostCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Add a signal handler
|
Add a signal handler
|
||||||
@@ -1093,9 +1174,6 @@ class Device:
|
|||||||
@overload
|
@overload
|
||||||
def off(self, signal: Literal["lost"], callback: DeviceLostCallback) -> None: ...
|
def off(self, signal: Literal["lost"], callback: DeviceLostCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Remove a signal handler
|
Remove a signal handler
|
||||||
@@ -1213,9 +1291,6 @@ class DeviceManager:
|
|||||||
@overload
|
@overload
|
||||||
def on(self, signal: Literal["changed"], callback: DeviceManagerChangedCallback) -> None: ...
|
def on(self, signal: Literal["changed"], callback: DeviceManagerChangedCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Add a signal handler
|
Add a signal handler
|
||||||
@@ -1232,9 +1307,6 @@ class DeviceManager:
|
|||||||
@overload
|
@overload
|
||||||
def off(self, signal: Literal["changed"], callback: DeviceManagerChangedCallback) -> None: ...
|
def off(self, signal: Literal["changed"], callback: DeviceManagerChangedCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
def off(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Remove a signal handler
|
Remove a signal handler
|
||||||
@@ -1259,7 +1331,7 @@ class EndpointParameters:
|
|||||||
_filter_missing_kwargs(kwargs)
|
_filter_missing_kwargs(kwargs)
|
||||||
|
|
||||||
if authentication is not None:
|
if authentication is not None:
|
||||||
(auth_scheme, auth_data) = authentication
|
auth_scheme, auth_data = authentication
|
||||||
if auth_scheme == "token":
|
if auth_scheme == "token":
|
||||||
kwargs["auth_token"] = auth_data
|
kwargs["auth_token"] = auth_data
|
||||||
elif auth_scheme == "callback":
|
elif auth_scheme == "callback":
|
||||||
@@ -1405,9 +1477,6 @@ class PortalService:
|
|||||||
@overload
|
@overload
|
||||||
def on(self, signal: Literal["message"], callback: PortalServiceMessageCallback) -> None: ...
|
def on(self, signal: Literal["message"], callback: PortalServiceMessageCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
def on(self, signal: str, callback: Callable[..., Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Add a signal handler
|
Add a signal handler
|
||||||
@@ -1469,10 +1538,17 @@ CompilerFinishedCallback = Callable[[], None]
|
|||||||
CompilerOutputCallback = Callable[[str], None]
|
CompilerOutputCallback = Callable[[str], None]
|
||||||
CompilerDiagnosticsCallback = Callable[[List[CompilerDiagnostic]], None]
|
CompilerDiagnosticsCallback = Callable[[List[CompilerDiagnostic]], None]
|
||||||
|
|
||||||
|
CompilerOutputFormat = Literal["unescaped", "hex-bytes", "c-string"]
|
||||||
|
CompilerBundleFormat = Literal["esm", "iife"]
|
||||||
|
CompilerTypeCheck = Literal["full", "none"]
|
||||||
|
CompilerSourceMaps = Literal["included", "omitted"]
|
||||||
|
CompilerCompression = Literal["none", "terser"]
|
||||||
|
CompilerPlatform = Literal["neutral", "gum", "browser"]
|
||||||
|
|
||||||
|
|
||||||
class Compiler:
|
class Compiler:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._impl = _frida.Compiler(get_device_manager()._impl)
|
self._impl = _frida.Compiler()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return repr(self._impl)
|
return repr(self._impl)
|
||||||
@@ -1482,10 +1558,24 @@ class Compiler:
|
|||||||
self,
|
self,
|
||||||
entrypoint: str,
|
entrypoint: str,
|
||||||
project_root: Optional[str] = None,
|
project_root: Optional[str] = None,
|
||||||
source_maps: Optional[str] = None,
|
output_format: Optional[CompilerOutputFormat] = None,
|
||||||
compression: Optional[str] = None,
|
bundle_format: Optional[CompilerBundleFormat] = None,
|
||||||
|
type_check: Optional[CompilerTypeCheck] = None,
|
||||||
|
source_maps: Optional[CompilerSourceMaps] = None,
|
||||||
|
compression: Optional[CompilerCompression] = None,
|
||||||
|
platform: Optional[CompilerPlatform] = None,
|
||||||
|
externals: Optional[Sequence[str]] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
kwargs = {"project_root": project_root, "source_maps": source_maps, "compression": compression}
|
kwargs: dict[str, Any] = {
|
||||||
|
"project_root": project_root,
|
||||||
|
"output_format": output_format,
|
||||||
|
"bundle_format": bundle_format,
|
||||||
|
"type_check": type_check,
|
||||||
|
"source_maps": source_maps,
|
||||||
|
"compression": compression,
|
||||||
|
"platform": platform,
|
||||||
|
"externals": externals,
|
||||||
|
}
|
||||||
_filter_missing_kwargs(kwargs)
|
_filter_missing_kwargs(kwargs)
|
||||||
return self._impl.build(entrypoint, **kwargs)
|
return self._impl.build(entrypoint, **kwargs)
|
||||||
|
|
||||||
@@ -1494,10 +1584,24 @@ class Compiler:
|
|||||||
self,
|
self,
|
||||||
entrypoint: str,
|
entrypoint: str,
|
||||||
project_root: Optional[str] = None,
|
project_root: Optional[str] = None,
|
||||||
source_maps: Optional[str] = None,
|
output_format: Optional[CompilerOutputFormat] = None,
|
||||||
compression: Optional[str] = None,
|
bundle_format: Optional[CompilerBundleFormat] = None,
|
||||||
|
type_check: Optional[CompilerTypeCheck] = None,
|
||||||
|
source_maps: Optional[CompilerSourceMaps] = None,
|
||||||
|
compression: Optional[CompilerCompression] = None,
|
||||||
|
platform: Optional[CompilerPlatform] = None,
|
||||||
|
externals: Optional[Sequence[str]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
kwargs = {"project_root": project_root, "source_maps": source_maps, "compression": compression}
|
kwargs: dict[str, Any] = {
|
||||||
|
"project_root": project_root,
|
||||||
|
"output_format": output_format,
|
||||||
|
"bundle_format": bundle_format,
|
||||||
|
"type_check": type_check,
|
||||||
|
"source_maps": source_maps,
|
||||||
|
"compression": compression,
|
||||||
|
"platform": platform,
|
||||||
|
"externals": externals,
|
||||||
|
}
|
||||||
_filter_missing_kwargs(kwargs)
|
_filter_missing_kwargs(kwargs)
|
||||||
return self._impl.watch(entrypoint, **kwargs)
|
return self._impl.watch(entrypoint, **kwargs)
|
||||||
|
|
||||||
@@ -1513,10 +1617,11 @@ class Compiler:
|
|||||||
@overload
|
@overload
|
||||||
def on(self, signal: Literal["diagnostics"], callback: CompilerDiagnosticsCallback) -> None: ...
|
def on(self, signal: Literal["diagnostics"], callback: CompilerDiagnosticsCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
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)
|
self._impl.on(signal, callback)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@@ -1531,10 +1636,86 @@ class Compiler:
|
|||||||
@overload
|
@overload
|
||||||
def off(self, signal: Literal["diagnostics"], callback: CompilerDiagnosticsCallback) -> None: ...
|
def off(self, signal: Literal["diagnostics"], callback: CompilerDiagnosticsCallback) -> None: ...
|
||||||
|
|
||||||
@overload
|
|
||||||
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
PackageManagerInstallProgressCallback = Callable[
|
||||||
|
[
|
||||||
|
Literal[
|
||||||
|
"initializing",
|
||||||
|
"preparing-dependencies",
|
||||||
|
"resolving-package",
|
||||||
|
"fetching-resource",
|
||||||
|
"package-already-installed",
|
||||||
|
"downloading-package",
|
||||||
|
"package-installed",
|
||||||
|
"resolving-and-installing-all",
|
||||||
|
"complete",
|
||||||
|
],
|
||||||
|
float,
|
||||||
|
Optional[str],
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
]
|
||||||
|
|
||||||
|
PackageRole = Literal["runtime", "development", "optional", "peer"]
|
||||||
|
|
||||||
|
|
||||||
|
class PackageManager:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._impl = _frida.PackageManager()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return repr(self._impl)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def registry(self):
|
||||||
|
return self._impl.registry
|
||||||
|
|
||||||
|
@registry.setter
|
||||||
|
def registry(self, value):
|
||||||
|
self._impl.registry = value
|
||||||
|
|
||||||
|
@cancellable
|
||||||
|
def search(
|
||||||
|
self,
|
||||||
|
query: str,
|
||||||
|
offset: Optional[int] = None,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
) -> _frida.PackageSearchResult:
|
||||||
|
kwargs = {
|
||||||
|
"offset": offset,
|
||||||
|
"limit": limit,
|
||||||
|
}
|
||||||
|
_filter_missing_kwargs(kwargs)
|
||||||
|
return self._impl.search(query, **kwargs)
|
||||||
|
|
||||||
|
@cancellable
|
||||||
|
def install(
|
||||||
|
self,
|
||||||
|
project_root: Optional[str] = None,
|
||||||
|
role: Optional[PackageRole] = None,
|
||||||
|
specs: Optional[Sequence[str]] = None,
|
||||||
|
omits: Optional[Sequence[PackageRole]] = None,
|
||||||
|
) -> _frida.PackageInstallResult:
|
||||||
|
kwargs: Dict[str, Any] = {
|
||||||
|
"project_root": project_root,
|
||||||
|
"role": role,
|
||||||
|
"specs": specs,
|
||||||
|
"omits": omits,
|
||||||
|
}
|
||||||
|
_filter_missing_kwargs(kwargs)
|
||||||
|
return self._impl.install(**kwargs)
|
||||||
|
|
||||||
|
def on(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None:
|
||||||
|
self._impl.on(signal, callback)
|
||||||
|
|
||||||
|
def off(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None:
|
||||||
self._impl.off(signal, callback)
|
self._impl.off(signal, callback)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
Submodule releng updated: 6bad5eec71...1442ae5a7a
@@ -1,6 +1,6 @@
|
|||||||
[wrap-git]
|
[wrap-git]
|
||||||
url = https://github.com/frida/frida-core.git
|
url = https://github.com/frida/frida-core.git
|
||||||
revision = 16.2.4
|
revision = 17.11.0
|
||||||
depth = 1
|
depth = 1
|
||||||
|
|
||||||
[provide]
|
[provide]
|
||||||
|
|||||||
+21
-8
@@ -31,19 +31,26 @@ class TestRpc(unittest.TestCase):
|
|||||||
name="test-rpc",
|
name="test-rpc",
|
||||||
source="""\
|
source="""\
|
||||||
rpc.exports = {
|
rpc.exports = {
|
||||||
add: function (a, b) {
|
add(a, b) {
|
||||||
var result = a + b;
|
const result = a + b;
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
throw new Error("No");
|
throw new Error("No");
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
sub: function (a, b) {
|
sub(a, b) {
|
||||||
return a - b;
|
return a - b;
|
||||||
},
|
},
|
||||||
speak: function () {
|
speak() {
|
||||||
var buf = Memory.allocUtf8String("Yo");
|
const buf = Memory.allocUtf8String("Yo");
|
||||||
return Memory.readByteArray(buf, 2);
|
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.add(2, 3), 5)
|
||||||
self.assertEqual(agent.sub(5, 3), 2)
|
self.assertEqual(agent.sub(5, 3), 2)
|
||||||
self.assertRaises(Exception, lambda: agent.add(1, -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):
|
def test_post_failure(self):
|
||||||
script = self.session.create_script(
|
script = self.session.create_script(
|
||||||
|
|||||||
Reference in New Issue
Block a user