Reversing is complex. Yet software developers often turn to reverse engineering when faced with a challenging task: enhancing software security, making software compatible with third-party components, maintaining legacy code, and so on.
At Apriorit, we have more than a decade of reverse engineering experience. Over the years, our researchers have collected a rich selection of efficient tools for reverse engineering.
In this article, we describe the main reverse engineering programs we rely on in our work and show practical examples of how to use them. This article will be useful for readers who are familiar with assembly language and network interaction principles and who have experience programming for Windows using API functions.
Contents:
There are so many different software applications where the source code is hidden from sight. But there are a number of situations when we do need to understand the logic of how a certain platform or application functions, its algorithms, and specifics. Thatโs when legal software reversing โ a service provided by Apriorit for more than a decade โ is needed.
The efficiency of the reversing process depends heavily on two factors:
- The expertise of the reverse engineer
- The set of tools and techniques used
To learn more about the skills you might need and the specifics of Windows software reversing, check out our previous article describing the reversing process step by step. In this post, we discuss some of the best software reverse engineering tools for Windows.
In the second half of the article, youโll find a brief example of how to use each of these tools in practice.
Looking for skilled reverse engineering developers?
Whether you need to reverse undocumented functions, research your solutionโs feasibility, or address any other blockers, Aprioritโs experts are ready to help.
Top 9 reverse engineering tools
Itโs hard to name the best software for reverse engineering โ there are quite a few options, and each resolves a specific task in the multistep reversing process. Below, we overview the nine main tools used for reverse engineering by Apriorit researchers:
- IDA Pro, Hex Rays
- CFF Explorer
- API Monitor
- WinHex
- Ghidra
- Fiddler
- Scylla
- Relocation Section Editor
- PEiD
Letโs get started.
1. IDA Pro, Hex Rays
IDA Pro is one of the best tools for reverse engineering. Itโs an interactive disassembler that has a built-in command language (IDC) and supports a number of executable formats for various processors and operating systems. IDA Pro also has a great number of plugins that can extend the disassemblerโs functionality even further.
The main advantage of IDA Pro is that it allows you to interactively change any element of the displayed data:
- Give names to functions, variables, data structures, etc.
- Change data representation (as numbers, strings in various encodings, data structures)
- Build diagrams and code flow graphs to simplify the understanding of disassembled code
- Use type information about function arguments and structure definitions from C++ so that arguments and variables are automatically named
- Automatically recognize and name standard library functions in assembler code
- And much more
Aside from the disassembler itself, letโs also look closer at some IDA plugins.
Hex-Rays Decompiler
This IDA plugin can turn native processor code into a more readable, C-like version. The Hex-Rays Decompiler produces rather accurate C code comparable to that produced by a human reverse engineer. It correctly decompiles code produced by various C++ compilers, no matter the architecture. However, Hex-Rays Decompiler might have issues with processing complex assembler code, where the original code was specifically modified by adding the inline assembler or some manual optimization was made.
Lighthouse
This plugin enables you to mark the execution path within the disassembler. As a result, you can understand which pieces of code are taking part in the execution and if they are involved in some algorithm or feature.
Basically, this plugin loads reports of code coverage tools into the IDA database and marks pieces of code depending on how many times they were executed. This makes it clear which part of the code is worth your attention while browsing the disassembly.
ClassInformer
This plugin is intended to be used on binaries built by Visual Studio and searches for RTTI information stored in the data section of the executable file. RTTI information allows the plugin to find the class names and virtual methods of C++ classes and name them for the user. Also, ClassInformer can present you with a list of found classes.
BinDiff by zynamix
This tool uses the IDA engine to compare binaries as assembler code instead of a stream of bytes. BinDiff can pinpoint differences in the code of two versions of the same program (down to changes in a specific function) as a list of instructions which were added, removed, or replaced. Changes can also be represented as code flow graphs.
IDA-Function-Tagger
This plugin analyzes imported functions and functions that call them and then groups them by tags: cryptography-related, registry-related, network-related, etc. Such grouping makes it easier to find the part of the code responsible for specific operations.
ida-x86emu
This plugin emulates the execution of disassembled code without the need to run the application under analysis in a debugger. Using this plugin, you can emulate the result of executing any piece of code without the risk of modifying something in the system. All you need to do is specify the start values of CPU registers. Then you can do a step-by-step execution.
Read also
How to Reverse Engineer an iOS App and macOS Software
Get the complete practical guide to decompiling iOS and macOS apps, including an overview of tools and languages your team can use.
2. CFF Explorer
CFF Explorer is a suite of tools for portable executable (PE) editing which includes:
- PE and HEX editors
- Resource editor
- Import editor
- Signature scanner
- Address converter
- Disassembler
- Dependency analyzer
- And more
3. API Monitor
API Monitor is an application for intercepting API function calls made by apps and services. This tool can also display input and output data. It can also be used for reverse engineering API calls.
By default, API Monitor contains definitions for over 13,000 API functions and more than 1,300 COM interface methods.
4. WinHex
WinHex is a hex editor that provides a rich set of features and development tools for Windows.
WinHex can display checksums or code of software files, which is something a regular text editor is unable to do.
5. Ghidra
Ghidra is an open-source and cross-platform reverse engineering tool that helps users to analyze binaries on many platforms (Windows, macOS, Linux). Ghidra supports a lot of popular formats such as PE, COFF, macOS, Mach-O, ELF, and DBG. It can disassemble instructions for x86, x86_64, ARM, AARCH64, and other architectures.
The main features of Ghidra include:
- Code Browser โ displays and helps to work with a programโs instructions and data
- Debugger โ relies on pluggable connectors for third-party debuggers, enabling Ghidra to be extended and integrated with additional debuggers
- Decompiler โ automatically converts the binary representation of individual functions into a high-level C representation
- Function Bit Patterns Explorer โ discovers patterns in the bytes around function starts and returns
- Ghidra Script Manager โ allows for rapid development of extended Ghidra functionality
6. Fiddler
Fiddler is a proxy that you can use to intercept HTTP/HTTPS traffic going between your application and the server, monitor it, and analyze it. Fiddler can intercept HTTP/HTTPS traffic system-wide. You can also add plugins (e.g. wbxml view, which can decode wbxml) and display requests/responses in different views.
Fiddler has a built-in hex editor and can generate requests based on a selected request or create a custom request. In addition, the Request to Code plugin allows you to get ready code that executes requests in C#, Visual Basic, or Python.
7. Scylla
Scylla is an application for dumping a running application process and restoring the PE import table. With its help, you can get a totally restored PE file that can be run by the operating system.
8. Relocation Section Editor
Relocation Section Editor is an application used for editing the relocation table in PE files. The main purpose of this tool is to modify the relocation table in case of patching relocatable pieces of code. But itโs often used to remove the relocation table altogether when restoring a protected file.
A protected file actually contains the relocation table for the unpacker code only. The relocation table for the real code is usually hidden within the unpacker data. Thus, in case a dump is being recovered, there are two ways to restore the missing relocation table for the real code:
- Force the application to be loaded at two different base addresses, then compare the dumps to see which parts of the code are being patched and make a new relocation table.
- Remove the relocation table completely and specify in the PE file header that the file is not relocatable.
9. PEiD
PEiD is one of the best reverse engineering tools to detect the packer. By analyzing entropy, PEiD can detect whether an application is packed.
There are also various useful plugins that help to analyze PE files. For instance, the KANAL (Krypto Analyzer for PEiD) plugin analyzes a PE file for the presence of known encryption algorithms.
These are the nine tools that reverse engineers at Apriorit often turn to when working on Windows reversing projects. As you can see, each of these pieces of software for reverse engineering solves a very unique, specific set of tasks. In the next section, we provide practical examples that display the role and importance of each of these tools in Windows reversing.
Related project
Improving a SaaS Cybersecurity Platform with Competitive Features and Quality Maintenance
Explore how Aprioritโs skilled reverse engineers helped our client analyze and improve their complex software.
Practical example of working with reverse engineering software
Letโs see how we can use each of these tools to research a Windows application. As an example, we are going to use a test application [.exe] that you can download and analyze on your own.
1. Opening the researched executable with IDA Pro
Letโs load our test application to IDA Pro. We receive the following message:
This means that something has gone wrong with the application: its import table canโt be found. At this point, we only need to press the OK button. Once we do that, IDA Pro provides us with the following results of application analysis:
As you can see, the import table is almost empty. Its upper part shows that it was possible to detect a small piece of code (the blue part), and the left part shows which functions were detected (in our case, very few).
There is also a set of undetected bytes above the start function. We suppose that the application is packed by means of some packer. PEiD will help us determine which packer was used.
2. Getting information about the packer with PEiD
Now, we need to load our application in PEiD.
In Screenshot 13 above, you can see that the Entry Point is located in the UPX1 section. However, this fact alone doesnโt really tell us much, so we need to run a scan.
To start the scanning process, go to Options, choose Hardcore Scan, and click Save:
Next, select the folder where the application is located. After scanning is complete, we receive the following result:
As you can see from Screenshot 15, the application is packed using the UPX tool. To unpack it, we are going to use CFF Explorer.
Read also
How to Control Application Operations: Reverse Engineering an API Call and Creating Custom Hooks on Windows
Combine reverse engineering and API hooking to get full control over applicationโs behavior and improve its security.
3. Unpacking the application with CFF Explorer
To unpack our sample application with CFF Explorer, we need to go to the UPX Utility page in the main menu of CFF Explorer and press the Unpack button:
After that, we can upload the already unpacked application to IDA Pro and restore the assembler code.
We upload our application to IDA Pro once more, and when the system asks us whether to upload symbols from the server, we agree. Here is the result of application analysis in IDA Pro:
You can see in Screenshot 17 that we now have some readable code, more detected functions, and an import table (Screenshot 18). At this point, we can run the application and debug it in IDA Pro. In the disassembler, select Debugger > Select Debugger > Local Win32 debugger and then press F9. After that, we receive the following warning message:
Our tested application detected that it was debugged. To continue with our analysis, we need to disable debugger detection first.
See the import table:
At once, we can notice the NtQueryInformationProcess function. After clicking on it, we get the following list of xref functions:
Clicking on the function, we can see where itโs called. The third parameter is an output parameter. If it equals 1, then a debugger is attached to the application; if it equals 0, thereโs no debugger attached to the app.
Letโs see where the result of this function is written:
As you can see in Screenshot 22, the third parameter contains the address of the local variable (var_8). After a function call, the result of the function is checked (test eax, eax). Then the value of var_8 is checked, and if itโs not 0, the value is written to the byte_131443C variable.
Letโs check if the byte_131443C variable is used somewhere else in this function:
Weโll start from the end. This value contains the result from al (lower bytes). Before that, the esi result is written to eax, and 1 is written to esi. Above, we see the condition for writing 1 to esi: if ecx + 2 does not equal 0. The value in ecx is large fs:30h (and then + 2). It verifies that a debuggerโs presence has bypassed the IsDebuggerPresent function (a field of undocumented PEB structure).
Letโs rename this variable. To do so, press N or right-click on the function and select Rename.
Now we need to check if the g_isDebbugerPresent variable is used anywhere else:
There is โโฆโ in the end, so this variable is used in more than one place. Place the cursor over it and click X, or right-click and select Jump to xref to operand:
We already know the first four places where this variable is used, but not the last one. Letโs find it:
In Screenshot 26, we see that the variable checks if esi equals 0, and if it doesnโt, we receive the message that there is a debugger.
Gladly, this verification can be removed. Weโll consider one way to do that a bit later, when we get to working with the Hiew tool.
Itโs noteworthy that IDA Pro also allows for patching memory and code. In order to quickly find the needed piece of code, weโll run the Rebase program in IDA Pro to get the same offset as in Hiew. In IDA Pro, select Edit > Segments > Rebase program and enter the value 0x400000 in the opened window:
Letโs get the address of the code that performs the comparison. As you can see from Screenshot 28 below, the address is 0ั 4012F0:
We need to write down this address, as we are going to use it later in Ghidra.
Read also
How to Reverse Engineer Software (Windows) the Right Way
Dive into theoretical and practical aspects of reverse engineering Windows apps. Choose debuggers, disassemblers, and other tools fit for your project, as well as analyze our real-life reversing example.
4. Modifying the executed statements in Ghidra
Now we need to load our application in Ghidra. Create a project using File โ New Projectโฆ
Then, choose the green dragon icon in Tool Chest, which represents Ghidraโs CodeBrowser.
Press I to import the executable into the workspace. After that, Ghidra will suggest analyzing the executable. Click Analyze.
Now, letโs proceed to examine our address 0x4012F0. Press G and type the address 0x4012F0 into the box:
Now, we can replace this code with, say, jmp to jump to a specific address so that this condition is never satisfied (in most cases, it can jump to the code we want to be executed next).
Letโs jump to the address 0x40130E.
Right-click on this instruction address and select Patch Instruction.
After patching it, we see some leftover bytes because the instruction length has been decreased.
Patching a longer instruction with a shorter one is not a problem because we can create padding with NOP instructions. Letโs patch the leftover bytes:
If we try to run our test application now, it crashes.When looking at the assembler code, we see that the new jmp will call ESI further down the code, and ESI will contain garbage instead of the MessageBox function address. Since weโre jumping over the address 0x004012F8, weโre skipping mov esi, dword ptr [โUSER32.DLL::MessageBoxA]
. Thus, ESI will not be initialized, and the application will crash at 0x0040130E.
Therefore, letโs apply some creativity and jump to 0x004012F7 to move the MessageBoxA function address to ESI. This way, we also donโt skip the PUSH ESI command to avoid stack corruption (we have the POP ESI command at 0x0040132B). After that, letโs jmp to 0x00401317, the control flow branch where the application is considered to be registered, and replace 0x003D131E with NOPs.
This is what we get:
The cmp command is double-byte, starting with 12F0, and the address starts with 12F2. We can see that jmp is a one-byte command and that its address 05 is relative, meaning it shouldnโt be in the relocation table.
Thus, we have to remove the 12F2 value from the relocation table. To do so, we need to open the current version of our test application with the Relocation Section Editor.
5. Deleting a value from the relocation table with Relocation Section Editor
We start by loading the test application and finding the target value: 0x004012F2.
Next, we remove the target value and save the test application.
Related project
Developing Software for a Drone Battery Charging and Data Management Unit
Discover how we delivered an efficient and helpful MVP of the drone battery recharging kit to our client using the combination of reverse engineering, virtualization, and development skills.
6. Modifying values in the relocation table with CFF Explorer
Now itโs time to open our test application in CFF Explorer. We have found the value โ 1332 โ on which delta for MessageBox used to be added.
Letโs replace the value 1332 with the value 132B, the new offset by which MessageBox can be found. If we run the test application now, it wonโt crash or show a warning message about a detected debugger.
Next, we move to working with the MessageBox function calls.
7. API Monitor
This program is used to monitor API calls and contains a number of known API functions it can monitor. You can also add your own functions to API Monitor and use this tool to monitor network function calls and research passed parameters (of course, if traffic is not encrypted).
Letโs monitor our application. Weโll try to find the call for the MessageBox function:
Weโre interested only in the API functions that can show a message window. So we select only them in User32.dll.
In API Monitor, select File > Monitor New Process and set the path to our file. After running our process, we see the list of called functions. Letโs try to find MessageBox:
API Monitor shows which parameters were passed to the MessageBox function. Also, we can set different breakpoints for a function:
If we run monitoring of our file, weโll get the following results:
Screenshot 47 also shows the parameters passed to the MessageBox function.
8. WinHex
Now, we move to working with binaries so we can find the code that we previously detected with IDA Pro and API Monitor. But before exploring a binary, we need to determine its type with a hex editor. In our example, we use WinHex.
Open the file with WinHex:
The MZ signature at the zero offset corresponds to PE format files (executables or shared libraries), so this is an exe file or dll.
Most file formats have unique signatures. For example, hereโs what a dump file looks like in WinHex:
9. Scylla
To show you how to work with Scylla, we are going to once again use a packed application, but we wonโt be unpacking it this time. Instead, we’ll dump its memory and try to run it.
To do that, we open the packed executable file in IDA Pro. This time, we need to find the original entry point (OEP) into the application rather than the entry point of the packer.
The pusha command saves general-purpose registers to the stack. In the end, there should be the popa command which pushes the stored register values. After the popa command, there is a jmp to the original point of entry. You can use the Search for text option by pressing Alt + T and look for the popa command.
Below the popa command, there is jmp 40A191, which will eventually move to the original entry point.
Letโs put a breakpoint in jmp and run the debugger.
Now, we can try to follow jmp. However, IDA Pro displays another warning message:
This message means that there is no code at the point weโre going to. Therefore, IDA will create instructions in disassembled listings on the basis of bytes pointed to by the Extended Instruction Pointer (EIP).
0x00971A91 is the address of the original entry point after unpacking the application into memory.
Now, without closing IDA Pro, open Scylla in order to create the applicationโs dump and restore the applicationโs import table from it.
In the process list, choose our application and put the OEP address into the field. Then choose first IAT Autosearch and then Get imports. As a result, Scylla will show that the import table has been found.
Letโs make an application dump: press Dump, save the dump, then click Fix Dump and select the previously saved application.
If we run our application now, it will crash, so we need to remove the relocation table. To do so, open the modified dump file (it has the _SCY prefix) in CFF Explorer.
Set 0 in the Relocation Directory RVA field.
Next, we need to check whether the ImageBase is the same that the application loaded into memory.
You can find the ImageBase value in IDA Pro by going to Edit > Segments > Rebase program.
Letโs save and run the test application. Now, it will run as if it were packed.
Conclusion
When applied properly, reverse engineering can help you strengthen the security and improve the performance of your solution. However, quality reverse engineering is impossible without using the right set of tools and techniques.
In this article, we covered some of the best reverse engineering software that our team of professional reversers uses when researching software. Most of these tools can only be used for solving specific tasks, but when combined, they provide you with all the capabilities necessary for extensive software analysis.
Want to see if reverse engineering is the right approach for your next project? Get in touch with us using the form below.
Need to enhance your productโs security and efficiency?
Speed up your software development, choose the suitable toolset, and help you deliver a protected and reliable solution with the help of Aprioritโs experienced reverse engineers.