This article will address the growing need for automation in reverse engineering (Reverse Engineering Automation), how the introduction of automation into the research process can save valuable time and aid the retrieval of information without which, either our research would be less thorough, or it would be conducted on a significantly smaller scale.
Also in this article, I will present examples of automation scripts, and will make them accessible via my Github account. I also invite you to add further examples, beyond those examples found in this article, and to send me Pull Requests, so that I can add them.
Why is Automation Needed in Reverse Engineering?
First of all, I feel it is important to point out that Reverse Engineering Automation saves investigation time but does not replace the rest of the process, and secondly, for reasons including the following:
- Repeated actions
- Dynamic code fragments that are detected at a later stage of the program (Crypters, Packers).
- Bypassing software protections, such as SSDT.
- Allocating memory of the software running within Ollydbg
The differences between Ollydbg2-Python and Ollydbg2-Playtime:
- The scripting language is Lua (we are somewhat familiar with it from Nmap and Nginx)
- Offers a range of solutions, such as Event Listeners, Code Patch (you can read in autorun/detours.lua how they change the GetTickCount), and convenient functions for retrieval from memory (such as ReadMemoryString).
- Comes with well-ordered, user-friendly documentation.
- Allows you to use code that runs automatically with Ollydbg activation (AutoRun).
- Comes with sample scripts.
- Semi-Open Source – meaning that the API on the Lua server, also known as the core, is Open Source but the code of the Plugin Loader is closed. After some discussion with the Plugin developer, I got help from him and I realized that he was selling the product source code.
- The scripting language is Python (We are somewhat familiar with this from Immunity Debugger and Ida Python)
- Right now, there are no Event Listeners, Code Patch or convenient functions for retrieval of content from memory.
- Is supplied without documentation.
- Does not permit the use of code to run automatically with Ollydbg activation.
- Comes with sample scripts.
- Ctypes: A few words about using the C Variables, C Structures and C DLLs directly from the Python code. I recommend reading more about this in the Python documentation.
- Fully Open Source – all the code is open in Github, enabling people like us to contribute code and to reduce the gaps from Ollydbg-Playtime.
Example of the Capabilities of Ollydbg2-Playtime:
There are situations where we need to perform an action whenever we encounter a specific function. In such cases, the IsDebuggerPresent function is repeated several times. I will demonstrate how you can use Automation to change the value returned by this function (whoever is not familiar with this function can read the article on Anti Anti-Debugging in Bulletin 0x04).
Let us review the following screen picture:
You can see here that after the return of the IsDebuggerPresent function, a check is run to verify whether EAX is equal to 0. If so, the function will push to the stack the “Hello User" string, which is currently not the case, but maybe we should retrace our steps a little to see how we reached this command.
- We searched the IsDebuggerPresent function by clicking CTR + G.
- We set a Breakpoint to enable stopping, when the function is called.
- We clicked CTRL + F9 to reach the point where the function returns (another option is to view the return address in the stack).
- We clicked F8 to advance a step beyond the function call and arrived at the check to verify whether EAX is equal to 0 (TEST EAX, EAX and then JZ).
- And now we want to reset EAX to simulate a situation where IsBuggerPresent returns False.
Explanation of the Script
In the script, I used one of the special capabilities of Ollydbg2-Playtime, and this is the Event Listeners. With the aid of the Event Listeners, we can take action whenever the DLL is called, whenever there is a Breakpoint, or whenever a new Thread is created, and so on.
- GPA: This is the function that looks for API Functions (IsDebuggerPresent in Kernel32).
- Listen ("Int3Breakpoint", function((info) end): Here we are declaring a function (Callback) which is called when the Breakpoint event occurs.
We take the return address from the stack using Pop, and return it to the stack using Push (we could also do this by reading the memory from the ESP address). The isDebuggerPresentRet variable will help us next time to know whether the Breakpoint event indicates the return address of the IsDebuggerPresent function, indicating that IsDebuggerPresent function is complete. For this to happen, we used the SetInt3Breakpoint function to set a new Breakpoint for the existing address with the isDebuggerPresentRet variable. Finally, when we reach the situation where we have reached the destination (we are at the existing address with the isDebuggerPresentRet variable). We will reset the EAX register and then delete the Breakpoint using Removelnt3Breakpoint.
The Purpose of the Script
The purpose of the script is to prevent the IsDebuggerPresent Anti-Debugging function from interfering with the product testing. Of course, there are more elegant ways to do this, and there are plugins specifically designed for it, but this example enabled me to easily demonstrate the use of Event Listeners in Ollydbg2-Playtime.
Example of the Capabilities Ollydbg2-Python
There are situations in which we need to extract information from a memory segment of a particular piece of software. In our case, it will be a global array of structures that contain information that is useful for us in order to examine the software. The problem is that the array is large and contains pointers, so it will take us a long time to read it all without automatic operation.
In the above image, we can see a code segment of the main function. In this code segment, there is a loop that runs across the global array and prints the data in it. In reality, running over the global array will be silent and the software will not print the array elements. (An array of software programs with lists of Files, Registry, and so on).
Here, we have already accessed the data structure, and we can understand its structure – (int, char *, callback - void *) Also in the first element, there is a pointer to the Test1 string.
All we have to do now is find the global array start address, run on the array and print the array elements.
To find the start address of the array, we first need to find the initial string of the Test1 array, and then identify the element pointing towards it. We can see that Test1 is present in the rdata section, and the array itself is located in the data section, information that will help us build the script.
Clarification of the Script
Initially, we will define the App structure, which will represent the data structure containing the global array, and then we will define auxiliary functions:
- bswap: Function that converts Big Endian into Little Endian (Addresses in Intel processors are represented in Little Endian).
- get_section: Function that returns the starting address of a particular Section (for example, rdata, data or code).
- get_string: Function that reads a string from memory – does not exist in the Ollydbg2-Python
- FindHexInPage: Function that looks for a Hex in a particular memory segment and returns its address.
- ReadMemory: As its name implies, reads a memory segment within a certain large memory from a specified address.
- Obtaining the address of the Test1 string using the FindHexInPage function and get_section (to search in the rdata section).
- Obtaining the address of the Test1 string pointer using the same functions and bswap to convert the address to Little Endian; searching for the address in the data section, as we saw in the investigation.
- The first element in the App structure starts with int and is the Index of the array, so we will need to subtract the size of the Int from the address to get the start address of the array.
- What is left is the loop that will run and print every element of the array. Here, we will use get_string to print the string in the App structure which is the name of the application, we will use ReadMemory for reading a memory segment with the size as the structure and from_buffer_copy to fill the structure with the memory segment that was extracted by the ReadMemory
The Purpose of the Script
The purpose of the script is to print all the elements of a global array, enabling us to go through it easily. Another way to find out the address of the beginning of the array is to find the unique Pattern of the Assembly commands of the loop running on the array. (The code is complicated to explain, so I will load it into Git and will not explain it here).
The Script Output
By using Reverse Engineering Automation, we can save valuable investigation time. Python is one of the ultimate languages for scripting because of its large community of users and libraries such as Ctypes, Struct, and so on.
I recommend adding code to Plugins such as Ollydbg2-Python to make them more useful.
At the moment, I am working intensively on writing a Plugin for the first x64dbg Open Source Debugger (x64dbg-Python) to enable Reverse Engineering Automation also for x64dbg. I am going to incorporate ideas from Ollydbg2-Python and Ollydbg2-Playtime, and to add my own ideas, such a Dump Process function to help automate Unpacking, and more.
You are invited to contribute code to each of the projects in my Git account. I will try to approve code written in compliance with my standards and with those of the x64dbg developers with whom I am in contact on a daily basis to move this project forward rapidly and correctly.
Soon I will also upload some code samples for use with x64dbg-Python as I showed in this article on Ollydbg2-Python.
Links for Further Reading:
- My Github Profile:
- All the code samples of scripts in this articles, including demo programs:
- Digital Whisper Anti Anti-Debugging:
- Ctypes Python Documentation:
- Little Endian Byte Order (Endianness)