The jtool utility started as a companion utility to the 1st edition of MacOS internals, because I wanted to demonstrate Mach-O format intrinstics, and was annoyed with XCode's otool(1). Along the way, jtool absorbed additional Mach-O commands such as atos(1), dyldinfo(1), nm(1), segedit(1), pagestuff(1), strings(1) , and even codesign(1) and the informal ldid. Most importantly, it can be run on a variety of platforms - OS X, iOS, and even Linux, where Apple's tools don't exist. But that's not all. jtool provides many many novel features: in-binary search functionalitysymbol injectionbuilt-in disassembler functionality with (limited but constantly improving) emulation capabilities, which already outdo fancy commercial GUI disassemblers.Color terminal output, enabled by JCOLOR=1 As the code got more and more complex, I decided to rewrite jtool from scratch, bringing you jtool2 - and effectively deprecating the v1 binary. New features in jtool2 include: --analyze to automatically analyze any Mach-O, generating a companion file.kernelcache symbolication (what I formerly provided via joker) - which has become even more important since the advent of monolithic (\"1469\") kernelcaches, with no more symbols. jtool2 finds syscalls, Mach traps, MIG tables, interesting (for me, at least) functions, and IOKit objects - thousands of objects in all.Panic log symbolication: *OS panic logs are JSON and have little to no symbols - but --symbolicate (with a companion file prebuilt by --analyze) will rectify that.jtool and jtool2 ENTIRELY FREE for use of any type (AISE), and the latest version can always be found right here. For the legacy v1 download, click here, which I'm leaving here because I still am not finished with Objective-C support in v2.
For universal (fat) files, jtool provides the same -arch switch to single out a particular architecture. There are several differences from otool:jtool will refuse to touch a fat binary unless you specify the architecture You can specify the architecture with -arch, or specify ARCH= as an environment variable. This makes it useful to set a default. You can specify an architecture by numberThe last option there seems unusual - after all, how many architectures can there be in a fat file Yeah, well, I thought so too, until I encountered TaiG's 8.4 Jailbreak, which not only uses fat binaries of some 26-27 architectures, but also uses duplicate entries - confusing otool since it only matches the first one - but jtool can single out a particular slice this way. (q.v my writeup on that jailbreak here for an example).dyldinfo(1) compatible optionsThe dyldinfo(1) utility is really useful to explore the inner workings of Apple's dynamic loader. But it's not available for iOS. jtool can match most of dyldinfo's options easily, and can in fact emulate it busybox-style, if you symbolically link dyldinfo to it and call it:Zephyr: morpheus$ ln -s `which jtool` /tmp/dyldinfoZephyr: morpheus$ !$/tmp/dyldinfoUsage: dyldinfo [-arch ] -dylibs print dependent dylibs-rebase print addresses dyld will adjust if file not loaded at preferred address-bind print addresses dyld will set based on symbolic lookups-weak_bind print symbols which dyld must coalesce-lazy_bind print addresses dyld will lazily set on first use-function_starts print table of function start addresses# Call jtool with some dyldinfo option:Zephyr: morpheus$ /tmp/dyldinfo -bind /bin/lsbind information:segment section address type addend dylib symbol__DATA __got 0x100005000 pointer 0 libSystem.B.dylib __DefaultRuneLocale__DATA __got 0x100005008 pointer 0 libSystem.B.dylib ___stack_chk_guard__DATA __got 0x100005010 pointer 0 libSystem.B.dylib ___stderrp__DATA __got 0x100005018 pointer 0 libSystem.B.dylib ___stdoutp__DATA __got 0x100005020 pointer 0 libSystem.B.dylib _optind__DATA __nl_symbol_ptr 0x100005028 pointer 0 libSystem.B.dylib dyld_stub_binder# Call the real binary:Zephyr: morpheus$ dyldinfo -bind /bin/lsbind information:segment section address type addend dylib symbol__DATA __got 0x100005000 pointer 0 libSystem __DefaultRuneLocale__DATA __got 0x100005008 pointer 0 libSystem ___stack_chk_guard__DATA __got 0x100005010 pointer 0 libSystem ___stderrp__DATA __got 0x100005018 pointer 0 libSystem ___stdoutp__DATA __got 0x100005020 pointer 0 libSystem _optind__DATA __nl_symbol_ptr 0x100005028 pointer 0 libSystem dyld_stub_binder# Show weak binds: (Thanks Guhyeon)Zephyr: morpheus$ jtool -weak_bind /usr/sbin/weakpass_edit bind information:segment section address index dylib symbol__DATA __la_symbol_ptr 0x100003040 this-image __ZdlPv__DATA __la_symbol_ptr 0x100003048 this-image __ZnwmSince jtool basically mimics dyldinfo 1:1, refer to the latter's man(1) page for more detail. I use -function_starts, -bind and -lazy_bind most often.
Apple prelinks most dylibs and plugins into a \"Shared Library Cache\". The SLC is located in /var/db/dyld (OS X) and /System/Library/Caches/com.apple.dyld (iOS). The OS X cache also has a \"map\", but the iOS one doesn't have a map.
But why extract A key feature of Jtool that other decachers do not have, is its ability to work on a dylib while still in the cache! This not only saves you disk space, but also allows you to see how cached dylibs interact with eachother (e.g. cross dylib calls). To use this feature, simply specify \":\" as a delimiter between the cache and the dylib name. All the standard features (e.g. -l, -S, etc), work, but the really useful feature is -d. For example:
Hi could you guys please help me I'm trying to inject my dylib into my ipa but everytime it starts signing and fails and says failed to inject dylib. I replaced my certificates I started all over again with the ipa and so but nothing works please help
First, compile the following code (e.g. clang -framework AppKit -framework Foundation -o ProxyFix.dylib -dynamiclib /path/to/code.m) to create a library we can inject. This was also mostly written by 1110101001; I tweaked it to work with apps that use two-level namespaces.
We now need to insert this library into the Dictionary application. Luckily, macOS comes with a built-in mechanism for injecting code in the form of DYLD_INSERT_LIBRARIES. If you, like me, are running an ancient and lovably-hackable version of macOS such as 10.9, all you need to do is run your app after setting this environmental variable. For example, run in Terminal: 1e1e36bf2d