Beginner Tutorial #8 Breakpoints Theory v1.41 |
| The Target: none |
| The Tools: Ollydbg 1.10 |
| The Protection: none |
Other Information: |
Best viewed in Firefox at 1280x1024
|
Introduction: |
|
Well' once since the first tutorial of the beginners series you learnt that there are different breakpoints and that the can be used in different ways, but no one till now (in this series of tutorials of course) told you what are the differencies among all the breakpoints types we can set. Even if you barely know what happens under the hood of breakpoints, it would suffice to understand why there are different usages for each of them. First of all there's a big distinction between the breakpoints, there are Software Breakpoints and Hardware Breakpoints...
|
|
Hardware Breakpoints: |
|
The latter ones, Hardware Breakpoints, are directly supported by the CPU, using some special registers, called debug registers. There are four debug registers: DR0, DR1, DR2, DR3. They store the linear addresses of four breakpoints. The break conditions of each of these breakpoints are inside a special CPU register, the DR7 register. When any of these conditions are TRUE, the processor throws an INT 1 exception and the control is passed to the debugger. There are four possible breaking conditions foreseen by the CPU:
Once you set an Hardware Breakpoint, the debugger will check to see if the trap bit of the flags register is set. If so, an INT 1 debug exception is generated automatically by the CPU, and the control is passed to the debugger, or generally speaking the exception handler registered in the system. Considerations The advantage on the other hand is that the Hardware Breakpoints are almost undetectable by the software, the only way they can use to detect that an hardware breakpoint is set is to read the DR0..DR7 values: a code could detect tracing (debugging) by analizing the flags register (DR7). Unfortunately, it is only possible to work with these registers in ring0. For the meaning of flags of DR7 and generally for all concerns Debug Registers, read the Section “Debug Registers” in Chapter 15 of the “IA-32 Intel Architecture Software Developer’s Manual, Volume 3”, available at http://developer.intel.com/design/pentium4/manuals/253668.htm As such, we can use some tricks for switching over into ring0. For example I'm reporting here an example taken from the Pavol Cerven's book "Crackproof your Software" (excellent reading I suggest to all of you). .386 This technique is one of the few ways to discover debug breakpoints, and it makes possible to delete them without stopping the application in the debugger. However, rather than delete them, usually the application goes to an incorrect ending. Unfortunately, the trick (and all the other similar ones) works only in Windows 9x because of the need to switch over into ring0. Generally speaking the Cerven's book mentioned describes three ways
to switch a normal program running in ring3 into ring0, but only in
Windows 9x. Windows NT, 2000, and XP systems were secured against these
methods because of the prevalence of viruses that take advantage of
them. (Older Windows NT versions did allow this switch, but after it was
misused a few times, the possibility was removed from the system). Update: changing debug registers in ring3 code You can also experiment on your own using the following simple ASM code (also compiled and included into this archive) which uses the SEH mechanism to erase the debug registers and then return to the normal excution. See for example the code here attached, (many thanks a lot to Neitsa for writing it). The structure is very simple, try to place an hardware breakpoint in one of the NOP in the example and then place a normal BP into the first instruction of the SEH handler, and follow what happens. .686 Concluding this section, then theoretically in order for a debugger to be invisible it needs to recognize the instructions for reading the flags register, emulate their execution and return always zero as value of the trap flags. Not that easy to be done indeed! Using Hardware Breakpoints in Olly:
This things usually happens with compressors or complex packers such as Armadillo or Execryptor or AsProtect. A second advantage of HW breakpoints is that given that are a property of the CPU are not related to a specific Olly instance, so it's easy to set an HW breakpoint to a specific memory address from one istance of Olly and then open another Olly istance of the same program and have also the second program to break at the address specified by the first Olly. Well, seems complex., but it's indeed really useful: suppose you have a packed program, packed with AsProtect for example. You would open one istance of Olly (well hidden with all HideDebugger plugins) and run the target program. Suppose that during the Manual Unpacking you will need to stop at a specific memory address to see if something happened (indeed is a step of the way to manually unpack AsProtect) or to change a registry value. In order to not interfere with AsProtect you would likely set an hardware breakpoint at a specific address. Now once that HW Breakpoint is set try to reduce the first istance of Olly (do not close it) and open another one. Launch also this second istance of Olly with the target program and let it run freely. What happens? Well happens that the second Olly will break where the first Olly placed the HW breakpoint (a part from relocations of course) This behaviour happens because the HW Breakpoints are directly handled by the CPU and it's the CPU that issues the debug event and are not associated to a specific process, but only to a specific memory address. There's nothing much than this to say about Hardware breakpoints indeed..so let move on on the more complex software breakpoint .. Well indeed this method is one of the trick used for example to handle some packers such as ActiveMark also.
|
|
Software Breakpoints: |
|||
|
A Software Breakpoint is the only type of breakpooints that cannot be hidden without writing a full-scale processor emulator. If you place this one byte of code -- 0xCC at the beginning of an instruction, it will cause an INT 0x3 exception when an attempt is made to execute it. The handler of INT 0x3 gains control and can do whatever it wishes with a program. However, before the interrupt handler is called, the current values of the flags register, the pointer of the code segment (the CS register), and the instruction pointer (the IP register) are placed onto the stack. In addition, the interrupts are disabled (the IF flag is cleared), and the trap flag is cleared. Therefore, a call of the debug interrupt does not differ from a call of any other interrupt. To learn the point of the program in which the halt has occurred, the debugger pulls the saved values of registers off the stack, taking into account that CS:IP points to the next instruction to be executed. So generally it is complex to set a breakpoint in an arbitrary place of the program. The debugger should save the current value of the memory location at the specified address, then write the code 0xCC there. Before exiting the debug interrupt, the debugger should return everything to its former place, and should modify IP saved in the stack so that it points to the beginning of the restored instruction. (Otherwise, it points to its middle.)
Considerations For a program bein debugger a possible solution to discover whether at least one point has been set, is to count its checksum. To do this, it may use MOV, MOVS, LODS, POP, CMP, CMPS, or any other instructions. For example let's take a look to the following simple protection scheme (from Karsperky Book, Haker Disassembling Uncovered), using the XOR trick to decrypt a string. int main(int argc,
char* argv[]) After starting the program normally, the line "Hello, Free World!" should appear on the screen. But when the program is run under the debugger, even with at least one breakpoint set within the limits of BeginCode and EndCode, senseless garbage like "Jgnnm."Dpgg"Umpnf#0" will show up on the screen. Protection can be strengthened considerably if the procedure computing the checksum is placed into a separate thread engaged in another useful process, making the protective mechanism as unobtrusive as possible.
If the above case the key used is directly obtained from the code among the BeginCode and the EndCode addresses Let see it directly into Olly (using the supplied main.exe into this archive).
You can find again what we just wrote in the C code above. Try excercising yourself with this protection, it's not so uncommon to find it in weak protected programs in real life...if you excercise here, you'll be ready to recognize it whenever you'll find it.. Of course the above sample is simple, consider that the code might be complicated using exception, thread and other amenities to complicate lifes of who, like us, likes to follow the ASM code.. Note for those of you
who read the Shub-Nigurrath Oraculum's tutorial This will overcome those protections only checking the exception status or the 0xCC value being present, but not those doing complex checksums on memory.
|
|
References: |
|
As you can see there are different usages for breakpoints just because they are implemented differently, but consider that none of them is undetectable, thus do not rely, once a breakpoint is set, on your program to stop on it. Always be aware that the program can detect it's presence and delete it or modify itself behaviour to counteract an attack. Combining these two tecniques lead to conceptually simple routines useful to erase all the breakpoints placed in "sensitive" peices of code, either hardware and software breakpoints. I suggest the following further readings from now on to complete this argument..
and essentially all the tutorials seens around (also others on our tutorials page) which always make use of breakpoints..
|
|
Conclusion: |
|
[Nilrem] [JDog45] [Shub - Nigurrath] [MaDMAn_H3rCuL3s] [Ferrari] [Kruger] [Teerayoot] [R@dier] [ThunderPwr] [Eggi] [EJ12N] [Stickman 373] [Bone Enterprise] Thanks to all the people who take time to write tutorials. Thanks to all the people who continue to develop better tools. Thanks to Exetools, Woodmann, SND, TSRH, MP2K and all the others for being a great place of learning. Thanks also to The Codebreakers Journal, and the Anticrack forum. If you have any suggestions, comments or corrections contact me in usual places.. |