// this function is called to process every breakpoint entry, so it should be as fast as possible. void normal_break (DEBUG_EVENT *db) { t_disassembly dis; DWORD address; HANDLE process; HANDLE thread; node *bp_node; bool stalking = false; DWORD tick_count; CONTEXT context; LDT_ENTRY selector_entry; DWORD fs_base; DWORD stack_top; DWORD stack_bottom; tick_count = GetTickCount(); address = (DWORD)(db->u.Exception.ExceptionRecord.ExceptionAddress); thread = dbg.FindThread((DWORD)db->dwThreadId)->hThread; process = dbg.getProcessHandle(); // bring the called function to the top of the list. //function_list = splay(address, function_list); // ensure the breakpoint lies in a module we are stalking. for (node *cursor = bp_modules; cursor != NULL; cursor = cursor->next) { if (address >= cursor->base && address <= cursor->base + cursor->size) { stalking = true; break; } } // if we're not stalking the current module, return now. if (!stalking) return; // // if we're recording, log the entry to the appropriate recorder file. // if (recorder_mode != NOT_RECORDING) { //function_list->recorded[recorder_mode]++; //printf("T:%04x [R%d] %08X %-25s [%5u] ", db->dwThreadId, recorder_mode, address, function_list->name, function_list->recorded[recorder_mode]); if (disassemble_flag) printf("%08x T:%08x [R%d] %08X ", tick_count, db->dwThreadId, recorder_mode, address); if ((bp_node = ps_node_find_by_address(address, bp_modules)) != NULL) fprintf(recorder, "%08x:%08x:%s:%08x:%08x\n", tick_count, db->dwThreadId, bp_node->name, bp_node->base, address - bp_node->base); } // else, not recording. else { if (disassemble_flag) printf("%08x T:%08x [bp] %08X ", tick_count, db->dwThreadId, address); } // if enabled, print the disassembly at the breakpoint address. if (disassemble_flag) { // XXX - wonder if there is any significant speed increase when we skip just the disassembly output. if (dbg.Disassemble(thread, address, &dis)) printf("%s\n", dis.mnemonic.c_str()); else printf("\n"); } // if we are recording and register enumeration / dereferencing is enabled, process the registers we are interested in. if (recorder_mode != NOT_RECORDING && reg_enum_flag) { context.ContextFlags = CONTEXT_FULL; // get the thread context (containing the register values). if (GetThreadContext(thread, &context) == 0) return; // get the thread selector entry and calculate the 32-bit address for the FS register. if (GetThreadSelectorEntry(thread, context.SegFs, &selector_entry) == 0) return; fs_base = selector_entry.BaseLow + (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24); // determine the top/bottom of the debuggee's stack. ReadProcessMemory(process, (void *)(fs_base + 4), &stack_top, 4, NULL); ReadProcessMemory(process, (void *)(fs_base + 8), &stack_bottom, 4, NULL); ps_analyze_register(process, tick_count, address, bp_node, stack_top, stack_bottom, context.Eax, "EAX"); ps_analyze_register(process, tick_count, address, bp_node, stack_top, stack_bottom, context.Ebx, "EBX"); ps_analyze_register(process, tick_count, address, bp_node, stack_top, stack_bottom, context.Ecx, "ECX"); ps_analyze_register(process, tick_count, address, bp_node, stack_top, stack_bottom, context.Edx, "EDX"); ps_analyze_register(process, tick_count, address, bp_node, stack_top, stack_bottom, context.Esi, "ESI"); ps_analyze_register(process, tick_count, address, bp_node, stack_top, stack_bottom, context.Edi, "EDI"); } // to restore the break point we just processed: // - save the breakpoint address. // - enable single stepping. // - let the single step handler restore the breakpoint and disable single stepping. if (!dbg.one_time) { dbg.breakpoint_restore = address; dbg.breakpoint_restore_thread = thread; dbg.SetSingleStep(thread, true); } }
////////////////////////////////////////////////////////////////////////////////////////////////////////// // callback functions // void initial_break (DEBUG_EVENT *db) { char line[256], module[128]; DWORD f_offset, offset, base, size; int loaded = 0; node *bp_node; dbg.ActivateTraces(); printf("initial break, tid = %04x.\n\n", dbg.FindThread( (DWORD)db->dwThreadId )->hThread); if (!dbg.get_thandle()) { printf("manually setting thread handle.\n"); dbg.set_thandle(dbg.FindThread( (DWORD)db->dwThreadId )->hThread); } // if an initial breakpoint list was provided, process it. if (bpl != NULL) { printf("loading breakpoints from %s\n", breakpoint_list); // process the breakpoint list line by line. for (int i = 0; fgets(line, sizeof(line), bpl) != NULL; i++) { // line format: module name:function offset:offset // ignore malformatted lines. if (sscanf(line, "%127[^:]:%08x:%08x", module, &f_offset, &offset) == 0) continue; // determine if this module already exists in our linked list. // if not attempt to locate the module in memory. if ((bp_node = ps_node_find_by_name(module, bp_modules)) == NULL) { // attempt to determine the module address / size. if (!ps_base_address(module, &base, &size)) { printf("failed locating base address for module %s\n", module); continue; } // add a bp_node to the linked list. bp_node = (node *) malloc(sizeof(node)); bp_node->base = base; bp_node->size = size; strncpy(bp_node->name, module, sizeof(bp_node->name) - 1); ps_node_add(bp_node, &bp_modules, &num_bp_modules); } // the '-25' means we want to reserve 25 left justified characters for the name. // the '.25' specifies that we want the string truncated after 25 characters. //printf("Setting breakpoint @%08x [%-25.25s] ... ", address, name); if (!dbg.bpx(bp_node->base + offset)) { //printf("failed setting breakpoint @ 0x%08x\n", bp_node->base + offset); continue; } // at this point a breakpoint was successfully loaded. loaded++; if (i % 100 == 0) printf("setting breakpoint %d\r", i); // add function to splay tree. //if (offset == f_offset) // function_list = splay_insert(address, name, function_list); } printf("done. %d of %d breakpoints set.\n", loaded, i); fclose(bpl); } // display the command menu. ps_commands(); }