HTool is a static analysis tool derived from
otool(1) that is shipped with the Xcode Developer Tools, and inspired by
jtool(1). In the long term the aim for HTool is to have significant functionality such as analysing Mach-O’s, FAT/Universal Binaries, DYLD Shared Cache, macOS and iOS Kernel’s, iBoot, SEPOS, SecureROM and future firmware files, quick and easy disassembly, and an lldb-like interface for analysing and disassembling Mach-O files.
There are no dependencies. You will be able to download and run with (hopefully) no issues. HTool heavily relies on Libhelper for it’s Mach-O capabilities, which is Opensource. You can check out Libhelper here. However, unlike Libhelper I have no current plans to Opensource HTool, but please refer to the FAQ for more on this. You can also skip to Downloads if you aren’t interested in the docs.
HTool is designed to run on macOS, both x86_64 and arm64, with iOS and Linux support planned for final release.
A few quick notes:
– No, I have no plans to opensource HTool at any point. Libhelper probably makes up 40-50% of HTool’s source code, and that’s opensource and free for you to use and modify! HTool just builds on the functionality provided by libhelper.
Mash – Mash, or Mach-O Shell, is experimental functionality of HTool intended to act like lldb for dynamically analysing Mach-O files. It was very buggy in the previous versions, and significant changes made to libhelper to improve memory usage have broken it entirely. I have new plans for Mash, although it will still perform the same function. There may be another beta for Mash soon, it may even take shape as it’s own tool, I haven’t quite decided yet.
Supported file formats – HTool supports any 64 bit Mach-O, whether that be arm64 or x86. In terms of firmware files, any 64 bit firmware is supported up to the iPhone 12. If future devices or iOS/macOS versions break anything, I’ll release an update addressing that.
Operating Systems – Currently HTool supports macOS on both arm64 and x86_64. There will be iOS support in an upcoming Beta, however Linux support may be delayed until a later version.
Distribution – For now HTool will be distributed via this website, however I’m planning on adding it to some package manager, probably Homebrew. When this happens, I’ll most likely opt to ship libhelper as a dynamically-linked, rather than statically-linked, library so bugs that only occur in libhelper and do not require changes in HTool can be patched that way. This might change though.
All versions of HTool are available here! Even the old Beta’s in case something is wrong in a newer version. Once the final version is released, I’ll remove beta’s for that version from this list.
This version of HTool is the latest and supports macOS on both arm64 and x86_64 architectures. The executable is bundled as a Universal Binary, so no need to download separate versions for Apple Silicon. Once downloaded, please run the
install.sh script so the
man page is installed correctly - otherwise you may opt to copy the files yourself.
Please Note: This is a beta version and may have issues and/or missing functionality.
Initial release of HTool. In these versions functionality is very limited. No arm64 support is present for macOS, nor iOS on beta 2. These downloads are available for debugging and testing purposes, and I discourage you from using them. Please refer to the versions above for the latest.
----------------------------------------------------- HTool 1.2.0 ----------------------------------------------------- Usage: htool [options] FILE Docs: man htool Mach-O Options: -h, --header: Dump Mach-O, DYLD Shared Cache, or FAT header. -l, --loadcmd: List all Mach-O Load Commands and Segments. -L, --libs: List all Mach-O Shared Libraries. -S, --symbols: List all Mach-O Symbols. -sym-dbg: Include debug symbols. -sym-sect: Include section data. -arch: Specify an architecture to load (FAT files) Static Analysis: -a, --analyse: Quick analysis of SecureROM, SEPOS, iBoot & Kernelcache -la: List all embedded payloads (SEP, iBoot, KEXTs) -e [NAME]: Extract payload[s], option specifier Information: -v, --version: Print HTool version --help: Print HTool help Environment Variables: H_ARCH Select an Architecture. x86_64, arm64, arm64e.
Anyone who has used htool v1.0 may notice the significant change in menu and option layout. v1.2.0 merges a lot of the original functionality into single commands. For example, rather than have seperate commands for analysing different firmware files, it’s now simply
This page is intend to detail each command, and give examples. You can obtain a more brief description of the commands by running
man htool. To ensure the man command works, please run the install script.
- Mach-O Options
- Static Analysis Options
The basic Mach-O functionality of
otool(1) is implemented within HTool, being inspecting the Mach-O header, Segment and Load Commands, Dynamic/Shared libraries and symbol information. Other
otool(1) functionality is implemented, such as dealing with FAT/Universal Binary’s.
Support for DYLD Shared Cache parsing is planned, and being actively worked on.
Dump a Mach-O Header
My first article on this blog was discussing the Mach-O file format. As I mention there, they have carefully constructed headers so DYLD and the launchd can understand how to load it. There are different types of Mach-O so this header is extremely important - as with any executable format.
One can get this information by adding the
--help flag when running HTool. See this example:
There are six properties in a Mach-O header: Magic, type, cpu type, cpu subtype, number of load commands, and the size of the load commands. HTool attempts to fetch a string descriptor of these values, so where we have the header magic, we have “0xfeedfacf (Mach-O 64 bit)” to make it clear the file is a 64 bit Mach-O. The type shows clearly that this is a Mach Executable, whereas if you were to run HTool on something such as a Kernel Extension, you would get the string “Mach Kernel Extension Bundle”. The CPU type is described in two parts, the
cpusubtype, and these are both displayed, although HTool will make an attempt at working out the actual name. In the event this fails, for example a newly released iOS Kernel with a new CPU subtype, the string “arm64_unk” would be displayed. Lastly is the number of Load Commands, and the size the load command region takes up following the header.
In some cases, especially with macOS 11.0, we have FAT/Universal Binaries. These archives contain one or more Mach-O’s, and have their own FAT header. This header details the number of architectures within the archive, and their offset. HTool can handle these too:
Dump Mach-O Load Commands
Load Commands describe to the Kernel how to load a given Mach-O file. Commands range from simply describing hte source version and tools used to compile the executable, to how the kernel should map the file into memory, where the
main() function is, and what dynamic libraries to load.
Listing the load commands can be done with
--loadcmds which, along with basically every other option, can be run together so you could run
-h -l to print both the header info and load commands together.
This can also be used on a FAT archive. By passing the
-arch flag as well, you can choose the architecture within the FAT file to inspect, take
xcrun as an example, where it contains both x86_64 and arm64e architectures:
-l on a FAT archive without specifying the architecture with
-arch will print the FAT header again, but instead expanding the Mach-O headers for all the contained architectures.
A significant amount of detail for each load command is presented using this option, especially with segment commands. If we look at the above image, take the
__TEXT segment. Firstly we have the LC index, showing as
LC 01, and the area of the file/memory that segment will take up. Directly underneath that we have the load command name, the mapping for the segment once loading into memory, in this case the
__TEXT segment is readable and executable, but not writable - you most likely wouldn’t find a writeable and executable segment. And next to that is the name of the segment.
Underneath that we have a small table detailing all the sections contained within the segment. The name, size and offset, showing the range, are displayed.
If we now turn our attention to something like LC_SYMTAB, this lists the regular symbol information contained in the Mach-O, detailing the offset of the symbol and string table within the file, and the size of the string table.
There may be some load commands that aren’t yet implemented, these are work in progress as there is dozens of them.
Dump Mach-O Shared Libraries
While Shared/Dynamically linked libraries are shown with the
LC_LOAD_DYLIB load command, they can be viewed separately with the
--libs command. Some extra version information is printed with this method:
HTool’s symbol functionality is derived partly from the design of
nm(1). You can list all symbols, as defined by
LC_SYMTAB with the
-S option, or
There are two optional flags for the
-sym-dbg. The first displays the section the symbol is defined in, and the latter display and debug symbols. Currently, these cannot be used together, but this is planned.
Static Analysis Options
HTool has a significant static analysis functionality aimed at analysing firmware files for macOS, iOS, watchOS, tvOS, iBridgeOS, etc. The eventual aim is for the Kernel, Kernelcache, iBoot, SEPOS, SecureROM and probably Device Tree to be supported, however it’s currently limited to the iOS Kernelcache, macOS Kernel (not to be confused with the M1 IPSW Kernelcaches) & iOS iBoot.
The analysis function can be run by passing
--analyse when running HTool. There are other flags,
-e which I’ll explain in the relevant sections.
Currently, HTool can analyse either an iOS Kernelcache (meaning from an IPSW), or a macOS Kernel (/System/Library/Kernels/*). Support for macOS Apple Silicon Kernelcaches, and for other Darwin Operating Systems, is planned.
As an example, I’ll run
--analyse using the
kernel.release.t8101 kernel on macOS, which is for the M1-based Mac’s.
HTool will run some checks to determine which type of Kernel it has been given. There are five types of Kernel that it can detect: xnu-arm64 (macOS), xnu-dtk (macOS), xnu-x86 (macOS), Merged new-style (iOS) and Split old-style (iOS). This type both determines how the Kernel is handled, and is displayed besides the “XNU Type:” label.
Looking further up, we start with “Darwin Version” and “XNU Version”. This is extracted from the file and is the same information that would be printed by
uname -a. Next is the “Compile Time” showing when the kernel was last compiled.
The “Device Type” label is a tricky one to calculate. There is a flaw in macOS arm64 Kernels in that they do not contain the correct platform identifier - whereas the Kernel Extension do. This, as S1guza kindly pointed out, is because Apple likely just reuse the build config used for other SoC’s of the same type. In reality, the M1’s are T8027’s.
Despite that, HTool will attempt to work out the SoC Brand name. In the case of the T8101 macOS kernel, HTool knows that this is used by both the M1 Mac’s, and A14 Bionic iPhone’s, so it prints the string “M1/A14 Bionic” to represent them both. Where there is an “Unknown” string, this is intended to show the platform identifier, which would be T8101, however this is still inaccurate and I’m working on a way where it will show the correct identifier for M1 Mac’s.
Now, iOS Kernel caches are bundled with their Kernel Extensions (KEXTs), whereas macOS Kernel’s aren’t. If we analyse an iOS kernel, it will also list the number of KEXTs. There are two options here, we can list all the KEXT names, using
-la, or extract a specific one with
com.apple.driver.AppleDiskImages2, will be extracted to your current directory. As they are Mach-O’s, you can go ahead and run
-l to inspect it. (Note: new-style iOS Kernel’s have KEXT segment merged with the rest of the kernel, see here).
Analysis of iBoot file is currently limited, as I’m still learning about their format myself. Currently, HTool can determine similar details about iBoot as it can about the Kernel (version, device, etc), plus embedded firmwares that it contains. The embedded firmware are for co-processors on iOS devices, for example the Power Management Unit (PMU). These embedded images are either in RAW or LZFSE format. HTool can currently find, decompress, show details and extract the LZFSE images.
-la option has no effect here as there are so few embedded images that it’s not required to hide them by default. The
-e still has the same effect, as show here:
To print the current version of HTool, use
--version. To print the help menu, either run
htool as so, or with
--help. You can view the docs by running
man htool once you’ve installed properly.
Legacy Mach-O Shell (Mash)
Mach-O Shell, or Mash, is console for interacting and manipulating Mach-O files. There are a number of features planned for Mash, including an in-depth disassembler and possibly decompiler, however for now, the following features are available.
Please note: Mash is versioned differently to HTool, and may be split into a seperate binary in the future. It is currently in Alpha, so commands are likely to be changed, added or removed. More documentation on how to use Mash will be released once it has entered either the Beta stage, or fully released.
Mash has a number of primary commands, with some of those having “sub-commands”. Most commands have both full, and short-hand types, for example the command
print segment all can also be written as
p s all. Mash also makes use of Editline, so has tab-completion when working with files.
Mash uses “sessions”, so currently you cannot reload, nor load a new file while in the same session. To begin working on a new file, either quit out of the current session, or open a new command line window. The aim of sessions is to be able to save progress and/or changes to a file while working in Mash.
Forgive the fairly brief overview of commands, the reason for this is that I’m constantly changing how Mash works, so command names and functionality change. With it’s release I will include The following is the current set of Mash Commands that I will discuss:
There are a few generic commands to know about first of all. Starting with,
h. This will simply print a help menu with a summary of all the primary commands, this includes the full command name, the short name, and a description.
ls. This is simply a wrapper around
ls(1) and allows one to use
ls for finding files when trying to load a Mach-O into Mash.
version command gives a version summary for mash in a similar format of HTool’s
q command does what it says on the tin - it will quit back to the command line - and
l, will load and verify a Mach-O file for that particular session. A file can also be loaded when running the command, like so:
htool --mash <file>.
The Print command is used to print particular parts of a load Mach-O file, and is the first of the primary commands for working with Mach-O files that I’m implementing. Firstly, is the Help command, similarly called with either
print help or
p h. Note: When using the short names, they are interchangable, for example the command
print h will work just fine. If you enter a command without it’s option flag, for example
print segment, a small help menu will be shown to guide you to entering the correct option.
To start, the Load Commands of a Mach-O can be printed using
print commands <opt>, or
p lc <opt>, with the
<opt> being either the keyword
all, or the name of a load command, such as
LC_SOURCE_VERSION. The output of this will be similar to the output of
htool -l <file> just with Segment Commands removed.
Segment commands can be printed in a similar way using
print segment <opt>, or
p s <opt>. Again, with
<opt> being either
all or all segments, or the name of the segment, e.g.
__TEXT. And again, the output will be similar to
htool -l <file> with the Load Commands removed.
A loaded file’s Symbols can be printed using
print symbol <opt> or
p sym <opt>. In this case,
<opt> has a few more options. With the standard
htool -S option, there are flags for printing debug symbols and for including the section each symbol is defined in. With Mash, that same functionality is included. To print all symbols, replace
all, for debug symbols replace with
all-dbg, and for section defines, replace with
all-sect. Again, with the
-S option, these cannot be used together - yet.
Finally, libraries. This is a very simple command, as there is not options to give it. It will print all linked libraries, like the
htool -L command. It can be invoked either with
print libs, or
If you read through all of this, thank you. I hope I made sense but if there is anything you’re still unclear about then feel free to ask me. These docs will be updated as I release new versions of HTool.