Another approach is using LD_PRELOAD with Frida to be able to write the instrumentation logic in JavaScript: https://www.frida.re/docs/gadget/ This also supports monitoring the .js file for changes and reloading the instrumentation logic live, which is great for game tweaks. Just save the file and instantly see the results.
HN user
oleavr
[ my public key: https://keybase.io/oleavr; my proof: https://keybase.io/oleavr/sigs/8qaXkpzIEMxpYSBm-mWsi2ihbO3dOz9rtuL6zCJ1k2Q ]
Yes, http://www.frida.re/ can do this at runtime – no need to recompile to add new probes.
Just heard from Tyilo, in #frida on irc.freenode.net, that replacing mach_vm_* with vm_* makes the test-case work on 32-bit devices, where apparently mach_vm_* are missing.
Yay!
Excellent! :)
That's interesting. Does it work for any processes at all? Would you be interested in trying to reproduce it with the latest Frida from git?
Hey,
and thanks for checking it out! The currently released version of Frida, 1.6.8, doesn't have the work-around and triggers the kernel panic described in the blog post. The work-around landed in git last night and will be part of 1.6.9 to be released soon; hopefully by tomorrow if all goes to plan. Feel free to clone and build Frida yourself if you'd like to play with it in the meantime (or make sure you never attach more than once to any process). Sorry for the inconvenience!
Feel free to drop by #frida on irc.freenode.net, btw!
Cheers!
Oops, in retrospect I should have resisted my OCD-fueled urge to link every single reference to be consistent. :p
Speaking as its creator and maintainer, it's been a pet project for the last 5 years (7 if you start from frida-gum, the code instrumentation engine), but to this day it's still rather obscure considering its potential. I regret not spending more time marketing the project over the years, so these days I'm doing my best to make up for that. :)
Is it a 64-bit device? Does the program crash or exit gracefully? If it crashes, try bumping the library index argument here:
library = (char *) _dyld_get_image_header (1);
If you're unlucky library at index 1 contains mach_vm_read_overwrite and is suddenly no longer executable (since we change its second memory page from R-X to RW- due to stock kernels not allowing RWX pages).
Aha, interesting. Does the program crash or exit gracefully?
Where does it crash? Try bumping the argument on line 21 – if you're unlucky library at index 1 contains mach_vm_read_overwrite and is suddenly no longer executable (since we change its second memory page from R-X to RW- due to stock kernels not allowing RWX pages).
I only tested it on 64-bit systems, where it triggers the kernel panic from both 32- and 64-bit processes (i386, x86_64, arm, and arm64). Hardware-wise it crashes every single device I've tried (MacBook Pro, iMac, iPhone 6, etc.), so this is not tied to any specific hardware.
Interesting, that's potentially very good news! To be sure, could you try again with the latest code snippet? I forgot to remove the VM_PROT_EXECUTE flag for non-jailbroken devices.
The mach_vm.h header has been replaced with a dummy version in recent iOS SDKs, so you’ll have to copy it from your OS X SDK and adjust the include. Just updated the post, and also removed VM_PROT_EXECUTE from the mach_vm_protect call for compatibility with non-jailbroken devices.
The screen turns blue – yes, blue, not joking – for a brief moment, and the system reboots. :)
Location: Stavanger, Norway
Remote: Yes
Willing to relocate: No
Technologies: Polyglot software development for desktop, mobile, web, and backend.
Résumé/CV: https://no.linkedin.com/in/oleavr
Email: oleavr at gmail dot com
---
I'm the founding author of several open source projects like http://www.frida.re, https://github.com/frida/cryptoshark, and https://code.google.com/p/ospy/. Extremely passionate about reverse-engineering, which started with libmimic, where I reverse-engineered a proprietary video codec from scratch (see: http://tech.slashdot.org/story/05/04/05/0240236/logitech-msn...). Have a diverse background spanning IM protocols, video conferencing, codecs, automotive hacking, dynamic binary instrumentation, GUI toolkits, web technologies, and most recently the music industry (Soundrop.fm and Show.co).
As you can see from the source code in the projects mentioned, I master C, C++, C#, Vala, Python, JavaScript, etc., and I'm also fluent in assembly for several architectures (IA-32, x86-64, ARM, AArch64, etc.). I also have years of experience building GUI apps for Windows, Mac, Linux, iOS and Android, and did a lot of backend development in Erlang. Through my experience building Frida I implemented features ranging from dynamic rewriting of function prologues for x86 and ARM 32- and 64-bit, dynamic trampolines, all the way to building a code tracer based on dynamic recompilation (see: https://medium.com/@oleavr/anatomy-of-a-code-tracer-b081aadb...)
I am available for both individual projects and long-term positions, but I can only work remotely.
There's internal support for them in Frida, but it's not currently exposed to the public API (which CryptoShark uses). The main focus has been on proprietary apps so far, but it would definitely be a very welcome feature for a future version.
Thanks, that's spot on! I just updated it. Hope you don't mind that I based it on your excellent and to-the-point description. :)
Frida is still looking for contributors: http://www.frida.re
There's a lot of fun things to hack on. Drop by #frida on FreeNode to learn more.
Thanks a lot! This appears to be an issue with the Frida build system and the Linux buildbot slave. We're investigating and will hopefully have a bugfix release out in the next few hours.
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).
1. This is supported through frida.spawn() and frida.resume(). This is however only implemented in the Mac backend for now.
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.
That's spot on. Regarding license protection logic that is also true, but maybe this could help with further nails in the DRM coffin — software running on the end-user's hardware is never safe against tampering. :)
This is unfortunate but no secret (have a look at frida-website's README), it was the best I could do with my non-existant design skills. :/ This is one area where I hope someone with such skills could help us out (it's mentioned in the `Contributing` section on the website).
Ok, I'll try to make it happen as soon as possible.
Ahh yes, exposing registers is planned and very trivial to implement, as it's available at the C code level, just needs to be exposed to the script runtime (V8). Future versions may also allow specifying an ABI, so args[0] maps to ecx for thiscall in 32-bit mode.
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. :)
Oops, that's a silly bug in frida-gum (sorry!), it should strip off the "L" suffix when calling toString() on a NativePointer object. As a band-aid you can either try with a 32-bit target process or locally hack it in your installed frida/core.py (just strip off the trailing "L" anywhere there's an int(a, 16) call. Expect a bugfix release tomorrow evening to fix this proper, so don't hesitate to let me know of any other issues.
frida-gum is LGPL and the rest of the code is GPLv3+. This is subject to change - if it's an issue for someone I'm all for changing to a more liberal license (Frida has very few authors so relicensing is trivial).
No worries, the Frida website could definitely have explained things better!
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!
Awesome! I'll try to get a tutorial on that written tomorrow evening. By the way, feel free to drop by #frida on FreeNode if you have any questions or would like to bounce ideas. :)
It sounds like Frida and Cycript have similar goals - REPL and other cool applications are planned and meant to be built on top of the core that is currently exposed to Python, .NET and a browser plugin (I built a cheesy WebGL network sniffeer running in the browser, the basic idea was to build an online collaborative reverse-engineering app where users with the plugin installed can live stream data and everybody collaborates on analyzing it online. Pure crack, I know, but I would personally love to have such a tool).