Cipher Book Review, Issue E147

Practical Binary analysis : build your own Linux tools for binary instrumentation, analysis, and disassembly
by Dennis Andriesse

No Starch Press 2019.
ISBN 1-59327-912-4, 978-1-59327-912-7

Reviewed by  Sven Dietrich   Jan. 25, 2019 

Some of us find fun and enjoyment in taking apart computer binaries (executable code) for understanding its functionality, its strengths, and its weaknesses. We look at machine code produced from source code (often C or C++) by compilers with various optimization and protection levels, and realize that the result may only barely resemble the original logical flow. Add the twist of malicious code writers who add obfuscation on many levels, and we immediately face an even tougher challenge for understanding these bits presented to us, sometimes in a time-critical fashion when dealing with incident response.

Dennis Andriesse has put together a book that combines the necessary knowledge and tools enabling the reader to grasp not only the fundamentals of binary analysis, but also to put the newfound knowledge to the test in practical and illustrative examples of binary analysis.

The book is structured into four parts, with the first three of which contain a total of thirteen chapters, and the last part contains four appendices.

After a foreword by Herbert Bos, who does a fine job of placing this book in context, the first part of the book contains four chapters providing an overview needed for this context: how a binary executable file is structured, what the ELF and PE binary formats look like, and how you can build a parser (really: a binary loader) with libbfd to analyze binaries and extract interesting information. These are formats found on Linux and macOS systems (ELF) and on Windows (PE). The book focuses on the popular and widespread Intel x86 architecture, often referring to the 64-bit variant x86-64, or x64 for short.

Part two provides binary analysis fundamentals, such as disassembly of code in a static or dynamic manner (non-running vs. running), or a combination of both. While the book does not provide a full coverage of disassembly techniques, it does differentiate between linear and recursive disassembly approaches and recommends use cases for each. The last chapter in this part gets into modifying binaries with a hex editor, something not for the faint of heart.

Part three is really the heavy hitter in this book with six chapters covering the more advanced techniques for binary analysis. Here we find examples of customizing the binary analysis, modifying and instrumenting binaries, performing data flow analysis also known as dynamic taint analysis, and symbolic execution. One example shows how to detect Heartbleed, an SSL/TLS vulnerability, using dynamic taint analysis.

Part four with the appendices is a mix of a crash course on x86 assembly, more details on ELF injection, a list of binary analysis tools, and a list of articles, research articles and books for quenching the thirst for more knowledge.

Overall, this book is fun to read. It is quite suitable for the reader who is curious about how binaries are structured, what information can be gleaned from them (such as control flow, data flow, functionality, and even protection or obfuscation mechanisms), and for a course in software security or malware analysis. Reading the book brought back memories of old times spent modifying the Commodore 64 OS with peeks and pokes in the 1980s, and editing an A/UX (an ancestor of macOS) device driver in the 1990s, with the intent of retaining functionality after the demise of the software company that created the device driver.

Sven Dietrich reviews technology and security books for IEEE Cipher. He welcomes your thoughts at spock at ieee dot org