In this part of our Labeless series, we will discuss the theory behind Labeless scripting. If, however, you’re new to all this Labeless stuff, please refer to the previous articles in this series as they will be helpful in explaining on what’s going on here.
In the tutorial below we will show what requirements are necessary to be satisfied in order to make scripting work and what goals can be achieved with its help. At the end of this theoretical article we will provide links to practical examples you can use to get to grips with it better.
Contents
Requirements
In order for all the scripting features to be unleashed, one of the following debuggers must be used:
OllyDbg 1.10 has certain API limitations which do not allow analysts to perform flawless tracing operations and the execution of `Step in`, `Step over` commands. That’s why only OllyDbg v.2 is mentioned.
If your favorite debugger is not in the list you can either start a new debugging session or migrate the current debugging session with the help of the OllyMigrate plugin:
http://low-priority.appspot.com/ollymigrate/
The topic of the day is Labeless so we will leave the discussion of migration issues for another time. For now we can say, though, that this solution exists and what’s more, it’s working. We’ve tried it ourselves.
The idea behind extracting info from the debugger dynamically is simple: execute script in the debugger so that some instructions are executed in the code, then read the results from memory and pass this info to IDA.
It all can be achieved via execution of Python scripts on both sides: IDA and, well, debugger. The scheme is provided below:
As usual, the Labeless plugin has to be installed on the debugger side also (it’s not shown on the scheme to underline that all the work from the user side is accomplished in IDA).
The window for remote script execution is available from the menu…
…in the main Labeless working screen:
…Or in the toolbar:
After whichever way is chosen, the following tab appears (resizable with IDA main window):
A description of the outlined buttons is as follows:
Flag toggles on/off verbose log output.
Note that script will be executed only in the window it’s currently present:
Note that latest Labeless versions have line numbers alongside the script boxes:
This part of script does not differ from usual IDA scripting: the same API functions, the same principles.
However, an additional tweak is available: information may be shared with debugger via __extern__ variable. Just write anything to this variable and it can be retrieved on debugger side.
To use script functionality in IDA you may refer directly to an API that resides in a `.\python` folder in the IDA root directory, for example:
This part of script uses Labeless API wrappers on top of the Python API for considered debuggers.
It also allows sharing information with IDA side via the __result__ variable. The principle is the same as for __extern__ in IDA-side script: just write anything to this variable and it will be readable back on the other side.
Details of implementation for both supported debuggers are described below.
Originally OllyDbg 2.01 hasn’t provided any Python API for scripting. The only way to interact with debugger was by creating native C\C++ plugins.
Python API was added by a fellow with the nickname `overcl0k` and described here in detail: https://github.com/0vercl0k/ollydbg2-python. It can be treated as a Python wrapper on top of C\C++ API of OllyDbg 2.01.
Labeless, in turn, uses this functionality and extends it further with high level wrappers.
The whole scheme is provided below:
API for OllyDbg 2.01 resides here:
https://github.com/a1ext/labeless/tree/master/deploy/labeless/backend/ollydbg20
There are several modules there:
To call a module function in the script the following format must be used:
ll.[module_name].[function]
Or you can import it directly and use the full name “Labeless”:
import labeless
labeless.[module_name].[function]
Either way is correct but “ll” is shorter and is usually chosen for faster script development.
Let’s see an example of function call with Labeless scripting. We take `ReadMemory` function from `memory` module:
It will be called like this:
ll.memory.ReadMemory
So keep in mind that when an unusual `ll.[module].[func]` construction is encountered in the code, it’s a part of Labeless API. You will see more examples in scripts provided in the next articles.
x64dbg also hasn’t provided Python API for scripting “out-of-the-box”: at the moment of Labeless implementation there was no fully-fledged solution for Python wrapper. a1ex.t, the author of Labeless, decided to implement one himself and included it directly into the Labeless bundle. The scheme is provided below:
There is also another Python wrapper API for x64dbg available nowadays. It is not used in Labeless as both projects were being developed simultaneously and could not rely one to the other: https://github.com/x64dbg/x64dbgpy.
API for x64dbg resides here:
https://github.com/a1ext/labeless/tree/master/deploy/labeless/backend/x64dbg
Function names are slightly different but usage principle and format for function calls is the same as in OllyDbg case.
There may be different goals for scripts to accomplish, for example:
Some of these may be accomplished using only IDA, like extracting an algorithm and re-implementing it in script. However, isn’t it simpler just to call necessary sequence of functions right from the original code without digging into internals of its implementation? If you agree, then Labeless is here to assist.
Real case examples follow in the next parts – so let’s continue straight to them!