Inject JavaScript to explore native apps on Windows, Mac, Linux and iOS
frida.re
frida.re
- There's this new hot app everybody's so excited about, but it's only available for iOS and you'd love to interop with it. You realize it's relying on encrypted network protocols and tools like Wireshark just won't cut it. You pick up Frida and use it for API tracing. (frida-trace)
- You're building a desktop app which has been deployed at a customer's site. There's a problem but the built-in logging code just isn't enough. You need to send your customer a custom build with lots of expensive logging code. Then you realize you could just use Frida and build an application-specific tool that will add all the diagnostics you need, and in just a few lines of Python. No need to send the customer a new custom build - you just send the tool which will work on many versions of your app.
- You'd like to build a Wireshark on steroids with support for sniffing encrypted protocols. It could even manipulate function calls to fake network conditions that would otherwise require you to set up a test lab.
- Your in-house app could use some black-box tests without polluting your production code with logic required only for exotic testing.
1. All the examples show attaching to an already running process. Is there a way to inject into a process from the moment it starts? I've got something I've been wanting to look at that is packed and the part I want to analyze happens right after unpacking but before UI comes up.
2. It looks like this would work even with software that uses some of the anti-debugging techniques like checking for an attached debugger etc... Is that right?
2. Yes this is indeed the case - and using Frida's Stalker (code tracer) you can even trace code without software/hardware breakpoints or any modifications to the original code.
Sorry, I'm at work so I don't have much time to investigate, but how does it know what the arguments of the functions are? Is it just walking the stack until it finds something that looks like a return address, then assume everything before that is an argument?
Also, what kind of hooking does it support? I am only really familiar with windows DLLs, but is it able to hook the Import Address Table? How does this work with statically linked binaries when it can't just walk the IAT?
This stuff can probably be answered by looking at the source, but my curiosity currently is overruled by deadlines.
Regarding the number of function arguments it doesn't know that, so that's something you need to know at the higher level. It is however safe to access arguments out of bounds, just expect "garbage" values if you access values beyond the Nth argument of an N argument function. Also, using Frida's Memory API (Memory.readUtf8String() for example) you'll get a JS exception thrown if you attempt to access an invalid address.
As for IAT, Frida is agnostic as far as hooking goes, it only needs the address of the function in memory (which you can obtain through for example Module.enumerateExports("kernel32.dll", ...)). How it works is that it dynamically rewrites/relocates the start of the function with a JMP to a trampoline that executes your JS hook, then the overwritten instruction(s) and finally jumps back to the next instruction after the overwritten ones.
Regarding functions in static libraries you can use Process.enumerateRanges() or Module.enumerateRanges() and Memory.scan() together to find the functions you're interested in, and then just Interceptor.attach() to them.
Hope this makes things a bit clearer!
Have you considered the (sort of edge) case when arguments are passed in registers? For example (in the VC compiler, as far as I remember) the "this" pointer is generally passed in the register ECX instead of being pushed onto the stack. In those cases it might be useful to have access to the register contents inside the JS callback.
Along a similar line, the EAX register is generally used for return values. It might be useful to provide access to that as well (through another callback?), although that would probably require changing how your trampoline works so that it replaces the return address in the stack... (i miss working with low level things sometimes).
Keep up the awesome work :D
My explanation of the hooking was a bit oversimplified, there is indeed support for hooking the return. Just implement onLeave(retval) in addition to onEnter(args), and you'll have access to the return value (coming from EAX/RAX).
Feedback is most appreciated, so please let me know if there's any issues. :)
- I can't install it with `pip` instead of `easy_install`. It would be nice to support this as well.
$ sudo pip install frida
[sudo] password for ***:
Downloading/unpacking frida
Could not find any downloads that satisfy the requirement frida
No distributions at all found for frida
Storing complete log in /home/***/.pip/pip.log
- After installing with `easy_install` I now have problems with running a simple example: $ frida-trace -i 'recv*' ls
Failed to attach: libffi.so.5: cannot open shared object file: No such file or directory
Traceback (most recent call last):
File "/usr/local/bin/frida-trace", line 9, in <module>
load_entry_point('frida==1.0.5', 'console_scripts', 'frida-trace')()
File "/usr/local/lib/python2.7/dist-packages/frida-1.0.5-py2.7-linux-x86_64.egg/frida/tracer.py", line 525, in main
frida.shutdown()
File "/usr/local/lib/python2.7/dist-packages/frida-1.0.5-py2.7-linux-x86_64.egg/frida/__init__.py", line 13, in shutdown
get_device_manager()._manager.close()
File "/usr/local/lib/python2.7/dist-packages/frida-1.0.5-py2.7-linux-x86_64.egg/frida/__init__.py", line 22, in get_device_manager
import _frida
ImportError: libffi.so.5: cannot open shared object file: No such file or directory
- `View on Github` links to the organization page and I'm not sure where to submit these issues. (frida-core? frida-python? frida-tracer?)Hope we'll get the pip issue sorted in the near future, need to do some more research into what's possible when not relying on eggs for binary releases (ran into issues when we tried to use bdist_dumb, so we postponed it for later).
UPDATE: Think "show less, explain more". That might help many.
UPDATE2: Or in fact, "Tell me, don't show me" :)
On top of this C core there are multiple language bindings (Python, .NET and a browser plugin), and it is very easy to build further bindings for other languages and environments (Node.js could be a future binding if anyone's interested in helping out with that).
For anybody that does want to try this before the node-bindings are available, maybe package it with node-python? https://npmjs.org/package/node-python
Cycript is an Objective-C/JavaScript bridge that allows you to inject code into native applications on Mac OS X or iOS (either using a jailbroken device, into the simulator, or using an SDK to embed into your application). (I do not currently support Windows, or runtimes like .NET.) It features a highly-interactive REPL with runtime grammar-assisted tab completion and live syntax highlighting. Users type am enhanced JavaScript syntax that includes a number of features from C and Objective-C.
Here is a link to a talk I gave at 360|iDev demonstrating its usage, as well as how to download the current beta version for Mac OS X 10.9 and the iOS 7 version of Xcode. I am also here linking to the Cycript website (which still sucks, but gets the gist across of what Cycript is and how one interacts with it; the talk is better, though, and more up-to-date) as well as the iPhone Dev Wiki (which has a lot of third-party documentation).
http://www.youtube.com/watch?v=5d1cK0nq4GY
http://iphonedevwiki.net/index.php/Cycript
Cycript lets you swap out implementations of native code in an Objective-C application, and can do do at the C function level quite easily when combined with Substrate (which is very easy to call out to, as Cycript has quite sophisticated support for FFI due to the large amounts of C-specific syntax and bridging it has; the next release is going to be even better at this, with the syntax now supporting type signatures specified using C-style type signatures, and with C++11 lambda syntax for more direct construction).
To compare, Frida looks a little more like a scriptable debugger, whereas Cycript is designed more to interact with applications as they are being used. With Frida, you use a Python API to inject JavaScript snippets into the other app, and then do IPC back and forth with your code. Cycript instead gives you an interactive console to a JavaScript environment running in the other application, with IPC implicit in the REPL. (FWIW, there are advantages to the kind of approach Frida has, and adding features to Cycript to make it a little more like a debugger have been on my todo list.)
It could also probably be used to circumvent licensing protection logic. Will be a nightmare for many.
As to what you can do with this; since a program basically consists of logic (function calls) + data, you can change any behavior of a program by modifying the function calls and return values. For example, I have previously used these techniques to extend MSN (Windows Live) Messenger to support third party chat networks (Facebook, Google Talk), even though the program didn't expose any APIs to extend functionality (but by simply hooking and injecting data into network calls such as recv and send).
In those old times, this was done using a combination of W32dasm, SoftIce and Hiew ( a hex-editor that allowed you to view the instructions in a PE exe file).
The most impressive crack of this type I remember seeing was one where the "demo" version of a 3D-modelling program did not have the "Save file" routine (it was completely absent from the exe) and which was implemented as part of a crack (including GetSaveFileName dialog and all). That was some amazing stuff there.
If I understand correctly, this program offers a 'dedicated' process to achieve similar functionality.
Installation requirements: "Windows, Mac OS X or Linux" (from http://www.frida.re/docs/installation/)
I tried this with notepad.exe on Windows 8.1 64-bit and this command:
frida-trace -i "CreateFile*" notepad.exe
produces this exception after saving a file from Notepad:
ValueError: invalid literal for int() with base 16: '0x7ffb216c62b8L'
I tried with another app and was able to trace OpenGL calls trivially. Very nice work.