HTool

Introduction

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:

  • Opensource?
    – 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.

Downloads

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.

Version 1.2.0

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.

Platform Version Link
macOS htool-v1.2.0-b1 Download

Version 1.0.0

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.

Platform Version Link
macOS `htool-v1.0.0-b2 Download
macOS `htool-v1.0.0-b1 Download
iOS `htool-v1.0.0-b1 Download

Documentation

-----------------------------------------------------
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 --analyse.

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

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 -h or --help flag when running HTool. See this example:

HTool `-h` command example.

HTool -h command 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 cputype and 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:

HTool `-h` command example with FAT archive.

HTool -h command example with FAT archive.

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 -l or --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.

HTool `-l` command example.

HTool -l command example.

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:

HTool `-l` command example on FAT file.

HTool -l command example on FAT file.

Running -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 -L or --libs command. Some extra version information is printed with this method:

HTool `-L` command example.

HTool -L command example.

List Symbols

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 --symbols.

HTool `-S` command example.

HTool -S command example.

There are two optional flags for the -S option: -sym-sect and -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.

HTool `-S` command example with `-sym-sect`.

HTool -S command example with -sym-sect.

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, -la and -e which I’ll explain in the relevant sections.

Kernel

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 `--analyse` for M1 macOS Kernel.

HTool --analyse for M1 macOS Kernel.

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 -e [name].

HTool `--analyse` with `-la`.

HTool --analyse with -la.

HTool `--analyse` with `-e com.apple.driver.AppleDiskImages2`.

HTool --analyse with -e com.apple.driver.AppleDiskImages2.

That KEXT, com.apple.driver.AppleDiskImages2, will be extracted to your current directory. As they are Mach-O’s, you can go ahead and run -h or -l to inspect it. (Note: new-style iOS Kernel’s have KEXT segment merged with the rest of the kernel, see here).

HTool `-h -l com.apple.driver.AppleDiskImages2`.

HTool -h -l com.apple.driver.AppleDiskImages2.


iBoot

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.

The -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:

HTool `--analyse` command example with `-e AppleSMCFirmware-1631.102.1.d42_whitney.REL`.

HTool --analyse command example with -e AppleSMCFirmware-1631.102.1.d42_whitney.REL.

Information

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.

HTool `--version`.

HTool --version.


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:

HTool `--mash` command example.

HTool --mash command example.

Generic commands.

There are a few generic commands to know about first of all. Starting with, help, or 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.

Next is list, or 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.

The version command gives a version summary for mash in a similar format of HTool’s --version command.

The quit or q command does what it says on the tin - it will quit back to the command line - and load, or 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 <opt> with 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 p l.


Summary

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.