This is where we hit the first challenges trying to talk to it from a Linuxhost. First off, the iOS device needs a USB vendor request to mode-switch itinto exposing the new interfaces. This part is easy, as the usbmuxd daemon cando this for us if we set the environment variable USBMUXD_DEFAULT_DEVICE_MODEto 3. So far so good.
Download https://tinurll.com/2yMAFF
We quickly developed a kernel driver patch to lift the requirement for astatus endpoint, and this got it working. Later we realized that we should stillrequire a status endpoint for the tethering interface, so we ended up refiningour patch a bit further. The plan is to submit that in the next few days.
Then, knowing which services are listening on which ports, the host looks up theTunnel service. This service lets the host establish a tunnel to the device,acting as a VPN to allow it to communicate with the services inside that tunnel.Since setting up such a tunnel requires a pairing relationship between the hostand the device, it means that the services inside the tunnel allow the host todo a lot more things than the services outside the tunnel.
The base protocol is the same as with RSD, and after some back and forthinvolving a pairing parameters binary blob and some cryptography, a pairingrelationship is either created or verified. At this point the two endpoints areusing encrypted communications, and the host asks the Tunnel service to set up atunnel listener.
Another area that needs future improvement is that we only support cabledconnectivity on macOS. This should be easy to improve on once we have updatedfrida-server and frida-gadget so they listen on tunnel interfaces whenever theyappear.
After thinking about this for a while, it occurred to me that we could providea generic abstraction that lets the application talk to any service that theywant. So last week @hsorbo and I filled up our coffee cups and got startedon just that.
The string passed into open_service() is the address where the service can bereached, which starts with a protocol identifier followed by colon and theservice name. This returns an implementation of the Service interface, whichlooks like this:
Then, later, to shut things down, cancel() may be called. The close signalis useful to know when a Service is no longer available, e.g. because thedevice was unplugged or you sent it an invalid message causing it to close theconnection.
Another improvement in the same area is that you can now return binary dataalongside a JSON-serializable JavaScript value. We previously only supportedreturning one or the other. This is now also finally supported.
The main pain point with the previous situation was having to deal with both 1)and 2), since they were involved in all of the main components. This meant thatsomething as simple as adding a source file would require knowledge of twodifferent build systems. Not only that, but contributors on Linux for example,would typically have a hard time testing their Visual Studio build systemchanges.
We discovered way late that Frida 16.1.0 broke Module#enumerateExports() on someELF binaries, and this is now finally fixed. It turned out to be a bug in thebounds-checking that I added when making Gum.ElfModule a cross-platform API,when it got support for offline use-cases like that of our Barebone backend.(Where we use it to dynamically inject Rust code into OS kernels and bare-metaltargets.)
Those of you using Frida on Apple platforms may have noticed thatModule#enumerateImports() provides you with import objects that always have aslot property. One way you can use this is to write a new pointer to thataddress, letting you rebind imports on a per-module basis. Super-handy ifInterceptor is unable to hook a function, or for scenarios where you want toavoid inline hooks.
Just a quick bug-fix release to roll back two of the Interceptor/Relocator arm64changes that went into the previous release. Turns out that these need some morerefinement before they can land, so we will roll them back for now.
Our Module API now also provides enumerateSections() andenumerateDependencies(). And for when you want to scan loaded modules forspecific section names, our existing module ApiResolver now lets you dothis with ease:
I ended up buying a second cat door and, lo and behold, no more issues. The oldone ended up collecting dust for a while. Something I kept thinking of waswhether I could debug it, and perhaps even extend the software to do more usefulthings.
Seeing as two of the other pads are connected to SWDIO and SWCLK, used forSerial Wire Debug (SWD), the natural next step was to hook up a Raspberry PiDebug Probe to those. After getting that set up, I fired up OpenOCD:
As for Interceptor, my thinking was that basic functionality would beimplemented using breakpoints. But, only if the user supplies JavaScriptcallbacks. If function pointers are supplied instead, we could perform inlinehooking so the target can run without any traps/ping-pongs with the host. Thismeans it could even be used for observing and modifying hot code inside an OSkernel or MCU firmware.
One of the cooler use-cases there is definitely Corellium, as it means we caninstrument the iOS kernel. Using a Tamarin Cable it should even be possibleto get this working on a checkm8-exploitable physical device.
So, on MCUs and unknown kernels you will have to tell Frida where, in physicalmemory, we may clobber if you want to use intrusive features such as RustModule,Interceptor in its inline hooking mode, Memory.alloc(), etc.
The next thing you might want to do is pass external symbols into yourRustModule. For example if you want to call internal kernel functions from yourRust code. This is accomplished by declaring them like this:
For those of you familiar with our CModule API, this part is exactly the same.You can also use NativeCallback to implement portions host-side, in JavaScript,but this needs to be handled with care to avoid performance bottlenecks. Goingin the opposite direction there is also NativeFunction, which you can use tocall into your Rust code from JavaScript.
You may notice that the JS APIs implemented only cover a subset, and not allfeatures are available on non-arm64 targets yet. But all of this will improve asthe backend matures. (Pull-requests are super-welcome!)
Just a quick bug-fix release reviving support for Android x86/x86_64 systemswith ARM emulation. This is still a blind spot in our CI, and I forgot all aboutit while working on the new Linux injector. Kudos to @stopmosk for promptlyreporting and helping triage this regression.
Time for a bug-fix release with only one change: turns out the ARMv8 BTI interopintroduced in 16.0.14 is problematic on Apple A12+ SoCs when running inarm64e mode, i.e. with pointer authentication enabled.
Our new Linux injector has a fully asynchronous design, without any dangerousblocking operations that can result in deadlocks. It is also the first injectorto support providing a control channel to the injected payload.
The main theme of this release is improved support for jailbroken iOS. We nowsupport iOS 16.3, including app listing and launching. Also included is improvedsupport for iOS 15, and some regression fixes for older iOS versions.
The most exciting change in this release is all about performance. Programs thatwould previously take a while to start when launched using Frida should now be alot quicker to start. This long-standing bottleneck was so bad that an app witha lot of libraries could fail to launch due to Frida slowing down its startuptoo much.
Next up we have a fix for a long-standing reliability issue. Turns out ourfile-descriptors used for IPC did not have SO_NOSIGPIPE set, so we couldsometimes end up in a situation where either Frida or the target processterminated abruptly, and the other side would end up getting zapped by SIGPIPEwhile trying to write().
While doing all of this we also tracked down a crash on iOS where frida-serverwould get killed due to EXC_GUARD during injection on iOS >= 15. That has nowalso been fixed, just in time for the release!
Another exciting piece of news is that @mrmacete improved our DebugSymbolAPI to consistently provide the full path instead of only the filename. This wasa long-standing inconsistency across our different platform backends. While atit he also exposed the column, so you also get that in addition to the linenumber.
Turns out a serious stability regression made it into Frida 16.0.3, where ourout-of-process dynamic linker for Apple OSes could end up crashing the targetprocess. This is especially disastrous when the target process is launchd, as itresults in a kernel panic. Thanks to the amazing work of @mrmacete, thisembarrassing regression is now fixed. ? Enjoy!
One of the exciting contributions this time around came from @tmm1, whoopened a whole bunch of pull-requests adding support for tvOS. Yay! As part oflanding these I took the opportunity to add support for watchOS as well.
This also turned out to be a great time to simplify the build system, gettingrid of complexity introduced to support non-Meson build systems such asautotools. So as part of this clean-up we now have separate binaries forSimulator targets such as the iOS Simulator, tvOS Simulator, etc. Previously weonly supported the x86_64 iOS Simulator, and now arm64 is covered as well.
So because the new dyld now chains to another copy of itself, inside thedyld_shared_cache, Frida was placing a breakpoint in the version mapped in fromthe filesystem, instead of the one in the cache. Obviously that never got hit,so we would end up timing out while waiting for this to happen.
We also have a brand new release of frida-tools, which thanks to @tmm1 has anew and exciting feature. The frida-ls-devices tool now displays higherfidelity device names, with OS name and version displayed in a fourth column:
As part of implementing this, I extended GumJS so a snapshot can be passed tocreate_script(), together with the source code of the agent. There is alsosnapshot_script(), used to create the snapshot in the first place.
b1e95dc632