Page 1 of 1

Advanced Debugging Tips

Posted: Wed Feb 07, 2007 2:53 am
by gnif
Hi all,

Over the years of playing with delphi/assembler... etc. I have learnt some very usefull ways to debug code when for some reason or another you can not put a breakpoint in the IDE (eg: self modifying code, injected dll, remote process).

Please note though, I am completly self-taught, so this information may not be complete, and some terms may be inaccurate

The CPU window
When I first saw this window, it scared me, full of numbers and this "assembler" stuff that only the pros knew. The Delphi documentation on it is very limited since it requires an understanding of x86 operations.

In Delphi, bring up the CPU window (CTRL+ALT+C) and I will explain what each part of it is.

The top left pane
This window contains the actuall CPU instructions, this is assembler. If you widen the CPU window, an extra column of numbers will be displayed.

The first column is the address in virtual memory that the line is at, the one that the green arrow points to is the current EIP (Enhanced Instruction Pointer), the EIP is the address of the code the CPU is about to execute.

The seccond column (the one that shows up if you expand the window) is the hex OP codes, these are the compiled assembler instuctions and is what the CPU reads. For example, 0x50 is "push eax" and 0x90 is "nop".

The third column is the human readable assembler, assembler is always in the format <OPERATION><VALUES>, if there are no values for the operation, then its just the operation.

eg, here is a small sample:

Code: Select all

push eax <-- eax is a param
pop eax  <-- eax is a param
pushad   <-- no params for this operation
popad    <-- no params for this operation
ret 8    <-- byte param for this one, but is optional.
The bottom pane
This contains the actual memory and is really usefull if you want to check that a variable is being set properly, you can look up the address of a variable to see its raw value, for example:

Code: Select all

var
  MyVar: String;
begin
  MyVar := 'example';
  ShowMessage('$'+IntToHex(Integer(@MyVar), 8));
  Beep;
end;
Put a breakpoint on the beep line run the app and write down the address displayed. The "beep" is just to give us somthing to break on that delphi won't optomise out. If you open the CPU window, right click in the memory pane, select "Goto Address" and type in the address you wrote down. You should see the raw value of the variable, including the length bytes which you don't normally see using a delphi watch.

The bottom right pane
This is the cpu stack you have heard mentioned around the place. The stack is like a pile of paper, each one has some information on it, to access/read a single piece of paper you need to know its location or address, you can also take a page off the top, or put one on the top.

The CPU stack also has a size limit, just like a pile of paper, there is only so many pages, you have probarbly already seen the odd "Stack Overflow" error caused by overfilling the stack.

The below procedure will create a stack overflow error:

Code: Select all

procedure OverflowMe;
begin
  OverflowMe;
end;
So how is it used?
The "push" operation is used to put a new value onto the top of the stack, "pop" operation is used to remove a value from the top of the stack. You may have noticed that in the top middle pane there is a value called "ESP", this stands for Enhanced Stack Pointer. ESP always is equil to the current location of the stack.

Dont be fooled though, the stack is backwards, when you push a value onto the stack, the address decreases, when you pop a value off, the address increases.

The stack is also used by the "call" and "ret" operations, "call" pushes the current EIP + 5 onto the stack and then changes the EIP to the address it was given. The "ret" operation sets the value of EIP to the address that the "call" operation pushed onto the stack and then pops it from the stack. This provides a way to re-use code in assembler.

The top middle window

Ok, you have explained EIP and ESP, but there are others there, what are they?

These are the CPU registers, they are used for storing temporary values for calculations and other things. Since they are physically inside the CPU, they are MUCH MUCH MUCH faster then RAM/Memory, so efficient use of these will make for a very fast program.

The basic registers are:
EAX - Generic 32 bit (8 byte) register
EBX - Generic 32 bit (8 byte) register
ECX - Generic 32 bit (8 byte) register
EDX - Generic 32 bit (8 byte) register
EDI - Not sure myself, I have never used it, google it
EBP - Again, not sure
ESP - Stack Pointer
EIP - Current CPU address
EFL - Again, nto sure.

These all start with an "E" because they are "Enhanced", this means they are 32 bit registers that store 8 bytes, AX, BX, CX.... etc all exist aswell, they can be used to access only 4 bytes of the 8 if you only need 16 bits.

The top right pane
Thses are the cpu flags pane... I dont know much about these as I have never had to do anything with them.

Done for now
Ok, there is the basics you need to know to get started... in the next post I will explain some little tricks you can use to help debugging.

Posted: Wed Feb 07, 2007 2:54 am
by gnif
Part 2 - Debugging tips

Ok, now you understand the basics of the CPU window, this should be a bit eaiser to explain.

CPUs use things called interrupts, they do exactly that, they interrupt the current program flow so the CPU can do somthing else. We dont need to know much at all about this, other then that interrupt 3 is the breakpoint interrupt.

When you set a breakpoint in Delphi, it automatically inserts the instruction for an interrupt where its needed, this "magic" instruction is:

Code: Select all

asm
  int 3
end;
Now, your probarbly thinking, what the hell can I do with that? well, when you inject a dll into a remote process, you cant insert breakpoints and see whats happening... so we can cheat a little and compile a breakpoint into the dll, for example:

Code: Select all

function NextWhatever(): HRESULT; stdcall;
begin
  asm int 3 end;
  ShowMessage('Do Stuff');
end;
Now, if you injected this and the breakpoint was triggered, the host application would crash with an un-handled breakpoint error, this is because there is no debugger attached.

Ok, this is starting to sound cool, how do I get this debugger to work?
This is the fun part... There is two methods to this, the first one is the easier

Attach to process
once the target application is running, in delphi under the Run menu, select "Attach to Process", then look for the program in the list, select it and then press the attach button. The CPU window will now pop-up, just press F9 to resume the program as Delphi pauses it.

Now trigger your injected code, delphi should pop-up the CPU window again on the "int 3" line.

I cant attach before the breakpoint is triggered
Thats where this method is used, in the Run menu, select "Parameters", click the browse button and locate the executable of the target application. Then press ok and then press F9 (Run).

Delphi should pop-up the CPU window on the "int 3" line.

It isnt working, whats wrong?
There are many things that can stop you from attaching, usually its Anti-Debugging code to stop craking, this is beyond the scope of this article as it requires an advanced asm understanding and some knowleage in application cracking.

Where else can I use this method?
I have found this method VERY handy when writing code that modifies itself... placing the "int 3" operation into the modified code to allow debugging is always a bonus.

PS: the op code for "int 3" is 0xCC

And that ends this for now... if there is anything I have missed post here and let me know and I will update this information.

Posted: Wed Feb 07, 2007 8:22 am
by madshi
Thanks!

Posted: Wed Feb 14, 2007 3:02 am
by gnif
No problems :)
Thanks for the sticky :)

8 bits = 1 Byte, so...

Posted: Thu Jun 07, 2007 9:31 am
by anudedeus
If those registers store 32 bits, they store 4 bytes, not 8, as you mentioned.
In the same way, the 16 bits ones store 2 bytes.
Cheers, Axp.

Re: Advanced Debugging Tips

Posted: Thu Jul 12, 2007 2:13 am
by zenic
gnif wrote: The basic registers are:
EAX - Generic 32 bit (8 byte) register
EBX - Generic 32 bit (8 byte) register
ECX - Generic 32 bit (8 byte) register
EDX - Generic 32 bit (8 byte) register
EDI - Not sure myself, I have never used it, google it
EBP - Again, not sure
ESP - Stack Pointer
EIP - Current CPU address
EFL - Again, nto sure.
the "E" prefix means "Extended", so "EAX" is "Extended Accumulator". I'll expand on your register list:

EAX - the Accumulator, but used for all sorts of things
ECX - the Count register - whenever doing repeated operations ("REP" prefix) this will be the number of times it is repeated.
ESI - "Source Index" - when doing memory copies etc, this is the address that it will be read from.
EDI - "Destination Index" - the memory location that is written to during copies and writes.
EBP - the Base Pointer. Used by high level languages (such as C) to reference parameters that are passed to the function - you'll see this when they do something like "PUSH EBP; MOV EBP, ESP; ADD EBP,4;" at the start of the function.
EFL - Flags register - a whole bunch of bits that control different things, such as whether an overflow occurred.