Recently I've been working on a function written in assembly (NASM dialect) that was to be compiled and then loaded and executed at runtime by an Objective C application. The function was to search in a library image (in memory, MACH-O) for the address of a given method from a given class (using Objective C export sections), and it was composed of a 4 level loop. And, as one my figure, it didn't work as it should. At first, I tried to debug it by hand, but since it was a four level loop, with a ton of iterations, I soon gave up, and switched to a more automagical method - which I now describe to you (later I found out that the mechanics my function used are invalid, but thats a story for another day).

Back to the automagical method - the idea was, as always, pretty simple - I wanted to use the "print it" debugging method (basically you print out everything you can on the screen / to some file, and analyze it later to check if something has an unforeseen/invalid value), but, it is not as easy to do it in assembly as it is in C/PHP/Python/etc, since you have to know the address of a printf/puts function, and be able to add several lines of code to print each interesting thing (this can be a problem if you have limited space), and also, you have to remember about storing the environment before the printf call (since the debug messages should not mess up the execution flow). However, as one knows, it is fairly simple to check the value of anything from a debugger - let's say from GDB (the favorite *nix debugger!). But... (there is always a but...) it takes a while to setup the GDB to print the right stuff at the right time - basically you have to create some scripts that do that. And, you'll have to update these screens after each address change - jumping from the disassembler (to check the address) to the script editor (to replace the old address with the new one) can be a real pain sometimes.

So, why not to make a tool that will create a proper gdb script for us? Let's just tell the tool in the source code how what actions do we want it to perform, and let it handle the rest!

The internals of such a tool are really really simple (the approach has some glitches, but it works perfectly in most cases...) and are divided into a few parts.

The first part is embedded in the assembly source code, and it contains GDB scripts with actions that should be taken by the debugger in that place. An example embedded-gdb-script looks like this:

GDB_BP
 ; echo Section name under ESI:
 ; print (char*)$esi
 ; ---GDB_BP


GDB_BP is a macro thats defined as 4x nop, and it serves a double-purpose: 1st - the string "GDB_BP" itself is a signature detected by another piece of the mechanism; 2nd - the 4 nops are also a signature, detected by yet another piece of the same mechanism. This two pieces work this way:

1. The first signature is detected in the provided source (the GDB_BP string in a line with %macro is omitted), and it reads the gdb script starting from line after the GDB_BP, until it reached the ---GDB_BP string. This script is stored (as a whole) on The Script List - it's added at the end of that list.
2. The 4 nops signature is detected in the provided compiled assembly file, and it's address is calculated (the start address of the place in memory where these opcodes will be loaded also has to be provided) - then, the address is stored in The Script List in the Nth element (there N is the number of detected signature), and in the file the first nop is changed to int3 (CC byte).
After these two steps, the final gdb script is generated - it looks like this:

define gdbhelpfunc
 set disassembly-flavor intel
 set logging file gdbhelplog.txt
 set logging overwrite
 set logging on
 display/1i $eip
 set $endautoscan=0
 while $endautoscan==0
   c
   set $endautoscan=1
   if ($eip)==(THE CALCULATED ADDRESS+1)
     SCRIPT FROM THE SCRIPT LIST (without the semicolons etc)
   end
   ...OTHER SIMILAR IFS...
 end
 set logging off
end
   

And now, after we have the script ready, we launch the gdb, break on some main or sth, load the script (source script_name.gdb), and launch the function (gdbhelpfunc) and the rest is automagical - everything is logged into gdbhelplog.txt.

So, as you can see, it's simple - just find some signatures, and generate some script - nothing more then a few printfs and freads - but it really makes life simpler! The source code is at the bottom of this post (C++, not really safe, but it works). Oh, the GDB_BP macro looks like this:

%macro GDB_BP 0
 nop
 nop
 nop
 nop
%endmacro


Download: gdbhelper.cpp (7kb)

P.S. The unicorn has been found by:
1. Netrix
2. deus
3. Patrykuss
4. mieszkos
5. doorsteps
6. Zombiak
7. Dab
8. makhzi
9. cyriel
Good luck to people who still look for it ;>

Comments:

2009-10-09 11:10:21 = lallous
{
Creative as usual, thanks for sharing!
}

Add a comment:

Nick:
URL (optional):
Math captcha: 4 ∗ 5 + 9 =