Code Auditor's ToolboxBefore you can analyze large chunks of code effectively, you need some tools that enable you to navigate code comfortably and perform related tasks such as fuzz-testing. This section introduces some major software tools for navigation of both source and binary code, debugging, fuzz-testing, and automated code auditing. Coverage of each tool includes an overview of its feature set and an assessment of its strengths and weaknesses. Code auditors vary in what type of tools they're comfortable with, so spend some time testing each product, and find the ones that suit you best. The overview tables also indicate which tools have a free version available. Code auditors tend to be creatures of habit. Most get familiar with certain tools and then never try competing tools because of the effort required to change their workflow. However, the state of the art changes rapidly, and new tools can introduce new capabilities that make code review much easier. If possible, take time to explore different products; you might find some features in competing tools that aren't available in your current tools. Source Code NavigatorsSource code navigators enable you to manage both small and large source-code projects easily and efficiently. Although most programming suites come with IDE software, source code navigators vary slightly by focusing on reading and following the code instead of building it (although many IDEs have similar functions and might be adequate for analyzing code). Some features of good source code navigators include the following:
CscopeCscope, summarized in Table 4-21, is a useful utility with cross-referencing features in an easy-to-use text interface and search-and-replace features for making text substitutions over multiple source files. This utility doesn't offer a satisfactory code navigation environment because of the limited features it supports, but it's not designed to be an auditing environment. However, it can be a useful complement to other products, particularly Ctags, as both products make up for each other's drawbacks.
CtagsCtags is an extension of the VIM editor designed for navigating source code. It offers a number of interesting features, although many features listed in Table 4-22 are actually part of VIM, not Ctags. It works by generating a file containing locations of data elements (structures, functions, variables, type definitions, preprocessor macros, and so on), and then referring to that file when users look up definitions. It's easy to use (for those familiar with VIM), and when combined with features already in VIM, it creates a functional code-navigating environment.
One of the main drawbacks of Ctags is that occasionally it jumps to the wrong place during a definition lookup. It might jump to a prototype instead of the actual function, for example. It can be particularly problem prone when a lot of indirection is involved in the code being examined. The second main drawback is that it doesn't have cross-referencing features; however, using this tool with Cscope can work around that limitation. Source NavigatorSource Navigator (see Table 4-23) is a GUI IDE developed primarily for use on Linux (and other UNIX-based OSs), but it also runs on Windows. It offers a rich feature set, including support for multiple languages, cross-referencing (text as well as pictorial), text searching, and definition lookups. It's an excellent product because the interface is simple and fast, and the engine works well. (It doesn't get definition lookups wrong, as other products sometimes do.)
Many auditors tend to prefer console environments for code auditing, but some of the features Source Navigator offers make code auditing in a GUI environment reasonably efficient. It does have a couple of drawbacks, however. First, it seems to have problems occasionally when dealing with large source trees (which can cause the application to crash). This problem isn't common, but it does happen. Second, it lacks syntax highlighting, which can make following code a little more difficult. Code SurferCode Surfer (summarized in Table 4-24), a product by Grammatech, is specifically designed for code-auditing tasks. It extends the basic function of code navigators with additional features such as slicing. Slicing is a mechanism for syntax highlighting based on variables the user wants to track and what code paths are affected by that variable. This feature can be useful for enforcing the control-flow and data-flow sensitivities of your analysis.
UnderstandUnderstand by SciTools (summarized in Table 4-25) is designed for analyzing large codebases and supports a number of different languages. It's available as a GUI for both Windows and UNIX OSs. Understand is one of the most full-featured source code reading environment available today (with an especially easy-to-use and configurable interface). Understand also has a scripting interface for automating source-code analysis tasks.
DebuggersDebugging is an integral part of a code auditor's job. It might be helpful when tracking down what code paths are used under a given set of circumstances, tracking down a fault that occurred as a result of black box testing, or verifying a vulnerability that has been located in the code. Quite a selection of debuggers are available for both Windows and UNIX-based OSs, and many have support for any architecture the OS is available on (to varying degrees). The level of sophistication in debuggers varies widely, as do their feature sets, so familiarize yourself with a number of debuggers to see which one suits you best. The following features are some good things to look for when selecting a debugger:
The following sections describe some popular debuggers available for different OSs. GNU Debugger (GDB)GDB, summarized in Table 4-26, is probably the most widely used debugger for UNIX-based systems. It's a console debugger (although GUI front ends are available) that offers a fairly rich feature set and is quite easy to use (if you're familiar with assembly code and general debugger usea requirement if you plan to be effective with a debugger). Most of the commands use a similar syntax, so after you familiarize yourself with the basics, the rest comes easily. GDB is useful when you have source code access to the code you're debugging, as you can compile it with debugging information. (This level of information is specific to ELF binaries, a common binary file format on contemporary UNIX variants.) You can step through assembly code, and GDB shows the line of source code relating to the instruction being carried out. This feature makes it easy to do fault tracing or see what's going wrong when attempting to exercise code paths to test potential vulnerabilities in the code.
GDB also has a scripting interface, which is useful for creating customized commands that can speed up debugging. The scripting interface is quite limited in many ways; for example, it can't keep state information between command calls. It's primarily meant for defining macros for a series of commands instead of building fully featured plug-ins, which is a shame. GDB also lacks a couple of features. On-the-fly assembly would be useful, as would memory searching. (There's no command to search through memory, although it's fairly easy to make a script to do so.) The interface can be a bit awkward for tasks such as editing data in memory (compared with a debugger such as SoftICE, covered later in this section). Further, GDB has a limitation when a process spawns several child processes: tracing into children can be difficult. Having said that, other UNIX debuggers have similar limitations, so it's not a GDB-specific issue. GDB supports non-Intel architectures, but sometimes it doesn't work quite as well on others; specifically, debugging sparc binaries is known to cause problems. OllyDbgOllyDbg is a free user land Windows debugger with an easy-to-use GUI for analyzing programs at runtime (see Table 4-27).
OllyDbg is feature rich and simplifies some time-consuming debugging tasks. Some of OllyDbg's features include the following:
In addition to basic debugging capabilities, Ollydbg has a sophisticated engine that enables developing plug-ins for extending the debugger's functionality. Some plug-ins include OllyDump (available at www.openrce.org/downloads/details/108/OllyDump), which allows the in-memory image of a process to be dumped to disk, and HeapVis (available at http://labs.idefense.com/labs.php?show=8#a8), a tool for visualizing the program heap's current state. SoftICESoftICE from Compuware, summarized in Table 4-28, is a popular kernel-level debugger for Windows OSs. Because SoftICE runs in kernel mode, it can be used to debug user land applications and kernel drivers (or the kernel itself). SoftICE has a number of helpful features, including remote debugging, on-the-fly assembly, an efficient command language, and powerful search, replace, and edit features. Compuware recently discontinued SoftICE; however, it remains a popular Windows kernal debugger.
Binary Navigation ToolsNot all the applications you audit are available as source code. In fact, source code often isn't provided, so you must audit the program binaries by reading the application's assembly code and figuring out how it works from there. You need some tools that aid in binary navigation so that examining executables is less cumbersome. Some good features for binary navigation tools include the following:
IDA ProIDA Pro, summarized in Table 4-29, is the tool for binary navigation and a mandatory part of code reviewers' toolkit. Get this product if you don't have itthat's an order! IDA Pro can be used to interpret many binary file formats targeted for a range of processors, so it's useful for nearly any sort of binary you encounter.
Note Even if IDA doesn't recognize the file format you're trying to analyze, it's possible to construct a loader module for specific binary types by using the IDA plug-in interface. IDA Pro has a rich (and unparalleled) feature set, which includes the following:
IDA also integrates debugging into its disassembler product. This product can be used instead of a standalone debugger and has the advantage of combining static analysis features with live debugging for a more comprehensive reverse-engineering environment. The debugger in IDA also has a lot of the features that other popular debuggers have. BinNaviBinNavi is an exciting new product by Sabre (see Table 4-30). Developed as an IDA plug-in targeted at code auditors who want to understand a program's inner workings more clearly, BinNavi provides a graphical representation of a binary that users can navigate easily. Call trees or internal function workings can be expressed in a variety of graphical formats, from circular graphs to tree flowcharts. BinNavi enables users to pinpoint interesting code paths quickly by eliminating extraneous code paths and saving different views of the same binary that highlight the paths being analyzed. Graph nodes can be colored separately to help highlight certain components in a function or call tree.
Graphing is just one of the tools that BinNavi provides for annotation. Users can also maintain detailed notes on each node on a graph, and these notes can be found quickly by using saved views and BinNavi's built-in search capabilities. Of course, the features described so far are useful for static analysis, but users need to be able to correlate their notes with runtime instances of the application. Therefore, BinNavi also gives users basic debugging capabilities, so they can select nodes to break on for further analysis while the process is running. The latest version of BinNavi offers some Python scripting capabilities to perform some of the features mentioned in the previous section on debuggers. Fuzz-Testing ToolsAt times, fuzz-testing is required as part of an audit in addition to code review. Fuzz-testing can be useful for finding bugs missed during the code audit because of complex code constructs and time constraints. This testing can be invaluable in ensuring that you have caught the most readily detected vulnerabilities. A good fuzz-testing tool should be protocol aware or capable of scripting so that it can provide a thorough test of known problems with the protocol in question. In addition, some new fuzz-testing tools might attempt intelligent attack vectors, which means they receive results of a request and use that information to build further requests to target potential problem areas. SPIKESPIKE, summarized in Table 4-31, is a protocol-independent fuzz-testing tool. It gives users a number of preformulated scripts for testing products that use known protocols as well as a powerful scripting language for creating scripts to test arbitrary protocols.
Dave Aitel (author of SPIKE) has written an interesting paper on the merits of block-based protocol analysis (decomposing protocol data into blocks for the purposes of size management and information discovery), the model on which SPIKE is built. You can find this paper at www.immunitysec.com/downloads/advantages_of_block_based_analysis.html. In addition, a proxy component is available for SPIKE for dealing with Web application testing environments. |