As discussed in Chapter 8, there are several different types of breakpoints, and OllyDbg supports all of those types. By default, it uses software breakpoints, but you can also use hardware breakpoints. Additionally, you can set conditional breakpoints, as well as set breakpoints on memory.
You can add or remove a breakpoint by selecting the instruction in the disassembler window and pressing F2. You can view the active breakpoints in a program by selecting View ▶ Breakpoints or clicking the B icon in the toolbar.
After you close or terminate a debugged program, OllyDbg will typically save the breakpoint locations you set, which will enable you to debug the program again with the same breakpoints (so you don’t need to set the breakpoints again). Table 9-2 shows a complete listing of OllyDbg’s breakpoints.
Table 9-2. OllyDbg Breakpoint Options
Function | Right-click menu selection | Hotkey |
---|---|---|
Software breakpoint | Breakpoint ▸ Toggle | F2 |
Conditional breakpoint | Breakpoint ▸ Conditional | SHIFT-F2 |
Hardware breakpoint | Breakpoint ▸ Hardware, on Execution | |
Memory breakpoint on access (read, write, or execute) | Breakpoint ▸ Memory, on Access | F2 (select memory) |
Memory breakpoint on write | Breakpoint ▸ Memory, on Write |
Software breakpoints are particularly useful when debugging a string decoder function. Recall
from Chapter 1 that strings can be a useful way to gain insight into
a program’s functionality, which is why malware authors often try to obfuscate strings. When
malware authors do this, they often use a string decoder, which is called before each string is
used. Example 9-2 shows an example with calls to String_Decoder
after obfuscated data is pushed on the stack.
Example 9-2. A string decoding breakpoint
push offset "4NNpTNHLKIXoPm7iBhUAjvRKNaUVBlr" call String_Decoder ... push offset "ugKLdNlLT6emldCeZi72mUjieuBqdfZ" call String_Decoder ...
The obfuscated data is often decoded into a useful string on the stack, so the only way to see it is to view the stack once the string decoder is complete. Therefore, the best place to set a breakpoint to view all of the strings is at the end of the string decoder routine. In this way, each time you choose Play in OllyDbg, the program will continue executing and will break when a string is decoded for use. This method will identify only the strings the program uses as it uses them. Later in this chapter, we will discuss how to modify instructions to decode all of the strings at once.
As you learned in the previous chapter, conditional breakpoints are software breakpoints that will break only if a certain condition is true. OllyDbg allows you to set conditional breakpoints using expressions; each time the software breakpoint is hit, the expression is evaluated. If the expression result is nonzero, execution pauses.
Be careful when using conditional breakpoints. Setting one may cause your program to run much more slowly, and if you are incorrect about your condition, the program may never stop running.
Conditional software breakpoints can be particularly useful when you want to save time when trying to pause execution once a certain parameter is passed to a frequently called API function, as demonstrated in the following example.
You can use conditional breakpoints to detect memory allocations above a certain size. Consider Poison Ivy, a popular backdoor, which receives commands through the Internet from a command-and-control server operated by an attacker. The commands are implemented in shellcode, and Poison Ivy allocates memory to house the shellcode it receives. However, most of the memory allocations performed in Poison Ivy are small and uninteresting, except when the command-and-control server sends a large quantity of shellcode to be executed.
The best way to catch the Poison Ivy allocation for that shellcode is to set a conditional
breakpoint at the VirtualAlloc
function in
Kernel32.dll. This is the API function that Poison Ivy uses to dynamically
allocate memory; therefore, if you set a conditional breakpoint when the allocation size is greater
than 100 bytes, the program will not pause when the smaller (and more frequent) memory allocations
occur.
To set our trap, we can begin by putting a standard breakpoint at the start of the VirtualAlloc
function to run until the breakpoint is hit. Figure 9-7 shows the stack window when a breakpoint is hit
at the start of VirtualAlloc
.
The figure shows the top five items on the stack. The return address is first, followed by the
four parameters (Address
, Size
, AllocationType
, and Protect
) for VirtualAlloc
. The parameters are labeled
next to their values and location in the stack. In this example, 0x29 bytes are to be allocated.
Since the top of the stack is pointed to by the ESP register in order to access the Size
field, we must reference it in memory as [ESP+8]
.
Figure 9-8 shows the disassembler window
when a breakpoint is hit at the start of VirtualAlloc
. We set a
conditional breakpoint when [ESP+8]>100
, in order to catch
Poison Ivy when it is about to receive a large amount of shellcode. To set this conditional software
breakpoint, follow these steps:
Right-click in the disassembler window on the first instruction of the function, and select Breakpoint ▶ Conditional. This brings up a dialog asking for the conditional expression.
Set the expression and click OK. In this example, use
[ESP+8]>100
.
Click Play and wait for the code to break.
OllyDbg provides functionality for setting hardware breakpoints through the use of dedicated hardware registers, as described in Chapter 8.
Hardware breakpoints are powerful because they don’t alter your code, stack, or any target resource. They also don’t slow down execution speed. As we noted in the previous chapter, the problem with hardware breakpoints is that you can set only four at a time.
To set hardware breakpoints on an instruction, right-click that instruction and select Breakpoint ▶ Hardware, on Execution.
You can tell OllyDbg to use hardware breakpoints instead of software breakpoints by default by using the Debugging Options menu. You might do this in order to protect against certain anti-debugging techniques, such as software breakpoint scanning, as we’ll discuss in Chapter 16.
OllyDbg supports memory breakpoints, allowing you to set a breakpoint on a chunk of memory in order to have the code break on access to that memory. OllyDbg supports the use of software and hardware memory breakpoints, as well as the ability to specify whether you want it to break on read, write, execute, or any access.
To set a basic memory breakpoint, select a portion of memory in the memory dump window or a section in the memory map, right-click it, and select Breakpoint ▶ Memory, on Access. You can set only one memory breakpoint at a time. The previously set memory breakpoint is removed if you set a new one.
OllyDbg implements software memory breakpoints by changing the attributes of memory blocks containing your selection. However, this technique is not always reliable and can bring with it considerable overhead. Therefore, you should use memory breakpoints sparingly.
Memory breakpoints are particularly useful during malware analysis when you want to find out when a loaded DLL is used: you can use a memory breakpoint to pause execution as soon as code in the DLL is executed. To do this, follow these steps:
Bring up the Memory Map window and right-click the DLL’s .text
section (the section that contains the program’s executable code).
Select Set Memory Breakpoint on Access.
Press F9 or click the play button to resume execution.
The program should break when execution ends up in the DLL’s .text
section.
18.224.67.235