Listing 1: ext.c Sample debugger extensions
#include "wdjexts.h" // hello_dbg // simple extension DECLARE_API(hello_dbg) { // print a message to the debug console using the raw callback // function supplied by ExtensionApis. (ExtensionApis.lpOutputRoutine)("Hello, Debugger!\n"); dprintf(" hCurrentProcess = %Xh\n", hCurrentProcess); dprintf(" hCurrentThread = %Xh\n", hCurrentThread); dprintf(" dwProcessor = %Xh\n", dwProcessor); dprintf(" dwCurrentPc = %Xh\n", dwCurrentPc); // note that either args will be NULL or args[0] will // be 0 if no arguments were specified, depending on // the debugger. dprintf(" args = \"%s\"\n", args && args[0] ? args : "<none>"); } // WinDbg will invoke this routine when the user invokes either // !wdjext.help or simply !wdjext.?. DECLARE_API(help) { dprintf("hello_dbg "); dprintf("Example routine that prints out args\n"); dprintf("dis <code address> "); dprintf("Disassembles an instruction at <address>\n"); dprintf("eflags "); dprintf("Shows EFLAGS register contents\n"); dprintf("mdl <MDL *> "); dprintf("Dumps an MDL structure\n"); dprintf("special_regs "); dprintf("Displays special registers like GDTR and TRx\n"); dprintf("getkrnlver "); dprintf("Displays information about the remote kernel\n"); } // dis // demonstrates the use of the Disassm() API DECLARE_API(dis) { ULONG Address; CHAR Buffer[256]; // better safe than sorry ULONG rc; UINT Displacement; if (!args || !args[0]) { dprintf("usage: dis <code address>\n"); return; } // Get the address at which to disassemble Address = GetExpression(args); if (!Address) { dprintf("Couldn't evaluate expression \"%s\"\n", args); return; } // Get and print the symbolic name for this address. Note // that Buffer must be large enough to hold any symbol or // it will be overwritten. GetSymbol( (PVOID)Address, &Buffer[0], &Displacement); dprintf("%s+%d:\n", Buffer, Displacement); // Disassemble the instruction at the given address. Again, // Buffer had better be big enough. On return, Address will // point to the next instruction. rc = Disassm( &Address, (PCHAR)&Buffer, FALSE); if (rc) dprintf("%s", Buffer); else dprintf("Disassembly failed at %Xh\n", Address); } DECLARE_API(mdl) { ULONG rc; DWORD MdlAddress; CSHORT MdlSize; PMDL Mdl; ULONG BytesRead; PULONG CurrentPage, EndPage; if (!args || !args[0]) { dprintf("usage: mdl <MDL address>\n"); return; } MdlAddress = GetExpression(args); if (!MdlAddress) { dprintf("Couldn't evaluate expression \"%s\"\n", args); return; } // First, read the size so we know how much memory to allocate rc = ReadMemory( MdlAddress + FIELD_OFFSET(MDL, Size), &MdlSize, sizeof(MdlSize), &BytesRead ); if (!rc || BytesRead != sizeof(MdlSize) ) { dprintf("Failed to read memory at %Xh\n", MdlAddress); return; } // sanity check on size. We'll let it go, but we only dump out // the base structure. if ( MdlSize < sizeof(MDL) || MdlSize > (CSHORT)0x400 ) { dprintf("WARNING: Mdl size is %d bytes; probably not a " "valid MDL.\n", MdlSize); MdlSize = sizeof(MDL); } Mdl = (PMDL) LocalAlloc( LPTR, MdlSize ); if (!Mdl) { dprintf("Failed to allocate memory!\n"); return; } // read in the entire MDL rc = ReadMemory( (ULONG)MdlAddress, Mdl, MdlSize, &BytesRead ); if (!rc || BytesRead != (ULONG)MdlSize) { dprintf("Failed to read memory at %Xh\n", MdlAddress); LocalFree( Mdl ); return; } // dump it dprintf("MDL at %X:\n", MdlAddress); dprintf(" Next: %08X\n", Mdl->Next); dprintf(" Size: %04Xh\n", Mdl->Size); dprintf(" Flags: %04Xh\n", Mdl->MdlFlags); #define PRINT_FLAG(_f) \ if (Mdl->MdlFlags & _f) dprintf(" %s\n", #_f); PRINT_FLAG(MDL_MAPPED_TO_SYSTEM_VA); PRINT_FLAG(MDL_PAGES_LOCKED); PRINT_FLAG(MDL_SOURCE_IS_NONPAGED_POOL); PRINT_FLAG(MDL_ALLOCATED_FIXED_SIZE); PRINT_FLAG(MDL_PARTIAL); PRINT_FLAG(MDL_PARTIAL_HAS_BEEN_MAPPED ); PRINT_FLAG(MDL_IO_PAGE_READ); PRINT_FLAG(MDL_WRITE_OPERATION); PRINT_FLAG(MDL_PARENT_MAPPED_SYSTEM_VA); PRINT_FLAG(MDL_LOCK_HELD ); PRINT_FLAG(MDL_SYSTEM_VA); PRINT_FLAG(MDL_IO_SPACE); PRINT_FLAG(MDL_NETWORK_HEADER ); PRINT_FLAG(MDL_MAPPING_CAN_FAIL); PRINT_FLAG(MDL_ALLOCATED_MUST_SUCCEED); #undef PRINT_FLAG dprintf(" Process: %08X\n", Mdl->Process); dprintf(" MappedSystemVa: %08X\n", Mdl->MappedSystemVa); dprintf(" StartVa: %08X\n", Mdl->StartVa); dprintf(" ByteCount: %8X\n", Mdl->ByteCount); dprintf(" ByteOffset: %8X\n", Mdl->ByteOffset); dprintf(" Pages:\n"); CurrentPage = (PDWORD)(Mdl + 1); EndPage = (PDWORD)((PCHAR)Mdl + MdlSize); while (CurrentPage < EndPage) dprintf(" %8X\n", CurrentPage++); LocalFree( Mdl ); } DECLARE_API(eflags) { CONTEXT Context; wdjGetContext((USHORT)dwProcessor, &Context); if (Context.EFlags & 0x00000001) dprintf(" Carry\n"); if (Context.EFlags & 0x00000004) dprintf(" Parity\n"); if (Context.EFlags & 0x00000010) dprintf(" Aux Carry\n"); if (Context.EFlags & 0x00000040) dprintf(" Zero\n"); if (Context.EFlags & 0x00000080) dprintf(" Sign\n"); if (Context.EFlags & 0x00000100) dprintf(" Trap\n"); if (Context.EFlags & 0x00000200) dprintf(" Interrupt\n"); if (Context.EFlags & 0x00000400) dprintf(" Direction\n"); if (Context.EFlags & 0x00000800) dprintf(" Overflow\n"); if (Context.EFlags & 0x00004000) dprintf(" Nested Task\n"); dprintf(" I/O Priviledge Level: %d\n", (Context.EFlags && 0x3000) >> 12); } DECLARE_API(special_regs) { KSPECIAL_REGISTERS r; wdjGetSpecialRegisters((USHORT)dwProcessor, &r); dprintf("Cr0=%08X Cr2=%08X Cr3=%08X Cr4=%08X\n", r.Cr0, r.Cr2, r.Cr3, r.Cr4); dprintf("Dr0=%08X Dr1=%08X Dr2=%08X Dr3=%08X\n", r.KernelDr0, r.KernelDr1, r.KernelDr2, r.KernelDr3); dprintf("Dr6=%08X Dr7=%08X\n", r.KernelDr6, r.KernelDr7); dprintf("Tr=%04X\n", r.Tr); dprintf("GDT: Base=%08X Limit=%04X\n", r.Gdtr.Base, r.Gdtr.Limit); dprintf("IDT: Base=%08X Limit=%04X\n", r.Idtr.Base, r.Idtr.Limit); } DECLARE_API(getkrnlver) { ULONG rc; DBGKD_GET_VERSION VersionInfo; #if EXT_API_VERSION_NUMBER >= 5 rc = wdjGetKernelVersion(&VersionInfo); #else rc = FALSE; // IG_GET_KERNEL_VERSION not supported #endif if (!rc) { dprintf("Could not get kernel version information!\n"); return; } dprintf("MajorVersion: %d (%04Xh)\n", VersionInfo.MajorVersion, VersionInfo.MajorVersion); dprintf("MinorVersion: %d (%04Xh)\n", VersionInfo.MinorVersion, VersionInfo.MinorVersion); dprintf("ProtocolVersion: %04Xh\n", VersionInfo.ProtocolVersion); dprintf("Flags: %04Xh\n", VersionInfo.Flags); dprintf("KernBase: %08Xh\n", VersionInfo.KernBase); dprintf("PsLoadedModuleList:%08Xh\n", VersionInfo.PsLoadedModuleList); dprintf("MachineType: %04Xh\n", VersionInfo.MachineType); } //End of File