Chapter 9 Notes
to accompany Sikorski and Honig, Practical Malware Analysis, no starch press
Debugging
"Debuggers are designed to allow developers to measure and control the internal state and execution of a program."
Source-level vs. assembly-level debuggers
Kernel- vs. User-mode Debugging
- "Kernel debugging is performed on two systems because there is only one kernel; if the kernel is at a breakpoint, no applications can be running on the system. One system runs the code that is being debugged, and another runs the debugger."
- Actually, WinDbg supports local kernel-mode debugging, but the functionality is limited
- gdb is widely used on UNIX systems, and (IIRC) it supports kernel debugging
- single-stepping allows you to explore a segment of code one isntruction at a time, but this is slow going!
- Example 9-2 shows use of single-stepping to unravel an XOR-based obfuscated string
Stepping-Over vs. Stepping-Into
- Choosing whether to single-step into function calls. Once a function is understood, why take the time?
- Does Virtual Box have Record/Replay, as VMWare Player does?
Pausing Execution with Breakpoints
- Probably the more familiar way to use a debugger, especially at source level
- Useful to set breakpoints before function calls, and right after they return
- X86 supports threee types of breakpoints: software, hardware, and conditional
Software Breakpoints
- Software breakpoint uses 0xCC instruction to raise a breakpoint interrupt
- Debugger will keep track of the instruction that was there, but the 0xCC is written to memory at that location
- Note that self-modifying code can erase breakpoints
- Code that checks its own integrity will notice the changed instruction
- I like the OllyDbg interface! Better than xgdb :-)
Hardware Breakpoints
- Hardware breakpoints stop at a certain location, without resorting to modifying the code in memory
- Hardware breakpoints can be set to stop at access (read or write), or change, as well as execution
- But x86 architecture has only FOUR hardware breakpoint registers:-(
- And running code can change these registers, erasing your breakpoints :-( Messing with hardware breakpoint registers is a strong malware indicator.
Conditional Breakpoints
- Conditional breakpoints are software breakpoints that really break when certain conditions are true
- A CB may, for example, be attached to a function call with certain values for certain parameters
- Could be used to test for system calls with "unusual" arguments
- Charles thinks it would be cool to have libraries of CBs, that could be set up in advance for DLL files maybe.
- An immunity plugin to support this would be a good Master's topic!
Exceptions
- Such as null pointer or divide by zero
- Debugger gets the first chance to handle an exception. followed by any handler the program being debugged might set up
- If no handler has been set up, the debuggers gets a second chance, else the program is allowed to crash.
Common Exceptions
- INT 3
- trap flag in flags register is used to do single-stepping
- memory access exception (corrupt point? invalid base address? access contol?)
- trying to execute a privileged instruction in user mode (e.g. write to hardware, modify memory page tables)
Modifying Execution with a Debugger (in Practice)
- "You can change the control flags, the instruction pointer, or the code itself to modify the way that a program executes."
- To look at a certain function, modify memory to hold some input, set IP to the function, and single step through the function to see what happens
- Example from PMA - malware that behanves differently depending on user's language
- Call GetSystemDefaultLCID
- For Chinese, exit quietly. For English, display a message box. For Indonesian or Japanese, write garbage to hard disk.
- Before the branch, set the LCID to the desired value, and let it rip!