Debug Tutorial Part 4: Writing WINDBG Extensions

Windbg dump分析 学习总结 Windbg核心调试之dump分析 http://www.pediy.com/kssd/pediy08/pediy8-428.htm 标 题: Windbg核心调试之dump分析 作 者:Lvg 时 间:2006-11-17 12:56  链 接:http://bbs.pediy.com/showthread.php?threadid=35044 调试环境:winxp sp2+wind 阅读详情

Introduction

Welcome to the fourth installment of this debugging series. In this installment, we will be getting a bit away from actual debugging for a bit and dive into creating helpful debugging aids. I definitely would never condone writing debugging aids just to write them. I would find a reason to write something, perhaps something you do all the time that gets tedious. Once you have found something you would love to automate, I would then see how you could automate it.

This is what I have done. During my debugging escapades, I always search the stack and other locations for strings. Why do I do this? People are not computers, we understand language rather than numbers. This being the case, a lot of applications and even drivers are written based upon strings. I would not say everything is a string, but there's usually a string somewhere. If you think about it, you really don't need strings at all. We could all just use numbers and never use another string again. Some may think well, when you expose a UI of course, you're going to eventually run into a string somewhere... Well, doesn't have to be that way, now does it? I mean, I'm not even talking about just User Interfaces, I'm talking about the guts of programs that aren't even exposed to the user at all. Programmers are still human and like to talk in some language beyond binary. This being the case, even the internals of applications sometimes use strings to represent things. You can find strings just about anywhere, even in drivers.

So There're Strings, So What?

Well, they provide an added level of readability to an application. This is the first rule of thumb, perhaps if you could find a string somewhere on the stack, you could better track down what the application is doing. These strings could be environment strings, file names, device names (COM1, /Device/xxxx, etc.), names of other objects, user names, GUIDs, etc. This information can better help track down what the application is doing and where it could be in your program.

Another interesting concept is, I don't know this for a fact, but it's my belief that the most common buffer overruns are due to invalid string manipulations. Whether it be forgetting the NULL character, or misjudging allocation since an API returns # of characters and not # of bytes. If a string overwrote memory in your program and you can find the string, it's a lot easier to track down who created it.

Where do we start?

I start on the stack. I have a trap, the first thing I do after "KB" and "DDS ESP" would then be to use "DC ESP". This command dumps the DWORDs on one side and the printable characters on the other. Let's see an example of this:

0:000> dc esp
0006febc  77d43a09 77d43c7d 0006fefc 00000000  .:.w}<.w........
0006fecc  00000000 00000000 00000000 0006ff1c  ................
0006fedc  010028e4 0006fefc 00000000 00000000  .(..............
0006feec  00000000 00000000 77e7ad86 00091ee7  ...........w....
0006fefc  001a03e4 00000118 0000ffff bf8a75ed  .............u..
0006ff0c  0768a2ca 00000229 00000251 00000000  ..h.)...Q.......
0006ff1c  0006ffc0 01006c54 01000000 00000000  ....Tl..........
0006ff2c  00091ee7 0000000a 00000000 00000000  ................
0:000> dc
0006ff3c  7ffdf000 80543940 f544fc5c 00000044  ....@9T./.D.D...
0006ff4c  00092b28 00092b48 00092b70 00000000  (+..H+..p+......
0006ff5c  00000000 00000000 00000000 00000000  ................
0006ff6c  00000000 00000000 00000000 00000000  ................
0006ff7c  00000000 ffffffff ffffffff ffffffff  ................
0006ff8c  00091ee7 00000000 00000001 00272620  ............ &'.
0006ff9c  00272d00 00000000 00000000 0006ff34  .-'.........4...
0006ffac  e24296d0 0006ffe0 01006d14 01001888  ..B......m......
0:000>
0006ffbc  00000000 0006fff0 77e814c7 00000000  ...........w....
0006ffcc  00000000 7ffdf000 f544fcf0 0006ffc8  ..........D.....
0006ffdc  80534504 ffffffff 77e94809 77e91210  .ES......H.w...w
0006ffec  00000000 00000000 00000000 01006ae0  .............j..
0006fffc  00000000 78746341 00000020 00000001  ....Actx .......
0007000c  00000654 0000007c 00000000 00000020  T...|....... ...
0007001c  00000000 00000014 00000001 00000003  ................
0007002c  00000034 000000ac 00000001 00000000  4...............
0:000>
0007003c  00000000 00000000 00000000 00000000  ................
0007004c  00000002 00000000 00000000 00000000  ................
0007005c  00000168 00000190 00000000 2d59495b  h...........[IY-
0007006c  000002f8 00000032 0000032c 000002b8  ....2...,.......
0007007c  00000010 00000002 0000008c 00000002  ................
0007008c  00000001 000000ac 00000538 00000001  ........8.......
0007009c  00000002 000005e4 00000070 00000001  ........p.......
000700ac  64487353 0000002c 00000001 00000001  SsHd,...........
0:000>
000700bc  00000003 00000002 0000008c 00000001  ................
000700cc  00000000 0000002c 0000005e 0000005e  ....,...^...^...
000700dc  00000000 00000000 00000000 00000000  ................
000700ec  00000000 00000000 00000000 00000000  ................
000700fc  00000000 00000002 00000028 00000034  ........(...4...
0007010c  003a0043 0057005c 004e0049 004f0044  C.:./.W.I.N.D.O.
0007011c  00530057 0030002e 0057005c 006e0069  W.S...0./.W.i.n.
0007012c  00780053 005c0073 00000000 00000000  S.x.s./.........

I started notepad.exe and just broke into it, then dumped the stack of the primary (and only) thread. The strings on the stack are "local arrays", such as declaring char x[10]; in your function. These aren't the only strings in a program though. There are others and these others are stored in pointers that are declared as local variables and even passed to functions such as CreateFile. The first parameter of CreateFile takes a string.

So, what do I usually do? I then search the stack for memory locations which could be strings and I then do "DC" again on them or "DA" for Dump ANSI string or "DU" for Dump Unicode String. The problem with this is that it's slow and tedious. I could not find any debugger command to do this for me (if there is one, let me know), so I ended up writing my own.

Writing Your Own?

WINDBG supports DLLs created by anyone as long as they export functions and behave in a manner defined by Microsoft. This means you can write PLUGINS! It used to be that people would write plug-ins to !<mydatastructure> <address> which basically dumped the members of their data structure along with the names. However, WINDBG supports the "dt" command that if you have a PDB (symbol file) it can do this for you without writing any code! Let's see an example of this.

Using the "dt <yourdll>!<your data structure>" will dump the structure's content along with their names. Let's look at a quick example.

0:000> dt ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 SpareBool        : UChar
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void
   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : Ptr32 Void
   +0x018 ProcessHeap      : Ptr32 Void
   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
   +0x020 FastPebLockRoutine : Ptr32 Void
   +0x024 FastPebUnlockRoutine : Ptr32 Void
   +0x028 EnvironmentUpdateCount : Uint4B
   +0x02c KernelCallbackTable : Ptr32 Void
   +0x030 SystemReserved   : [1] Uint4B
   +0x034 ExecuteOptions   : Pos 0, 2 Bits
   +0x034 SpareBits        : Pos 2, 30 Bits
   +0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK
   +0x03c TlsExpansionCounter : Uint4B
   +0x040 TlsBitmap        : Ptr32 Void
   +0x044 TlsBitmapBits    : [2] Uint4B
   +0x04c ReadOnlySharedMemoryBase : Ptr32 Void
   +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
   +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
   +0x058 AnsiCodePageData : Ptr32 Void
   +0x05c OemCodePageData  : Ptr32 Void
   +0x060 UnicodeCaseTableData : Ptr32 Void
   +0x064 NumberOfProcessors : Uint4B
   +0x068 NtGlobalFlag     : Uint4B
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER
   +0x078 HeapSegmentReserve : Uint4B
   +0x07c HeapSegmentCommit : Uint4B
   +0x080 HeapDeCommitTotalFreeThreshold : Uint4B
   +0x084 HeapDeCommitFreeBlockThreshold : Uint4B
   +0x088 NumberOfHeaps    : Uint4B
   +0x08c MaximumNumberOfHeaps : Uint4B
   +0x090 ProcessHeaps     : Ptr32 Ptr32 Void
   +0x094 GdiSharedHandleTable : Ptr32 Void
   +0x098 ProcessStarterHelper : Ptr32 Void
   +0x09c GdiDCAttributeList : Uint4B
   +0x0a0 LoaderLock       : Ptr32 Void
   +0x0a4 OSMajorVersion   : Uint4B
   +0x0a8 OSMinorVersion   : Uint4B
   +0x0ac OSBuildNumber    : Uint2B
   +0x0ae OSCSDVersion     : Uint2B
   +0x0b0 OSPlatformId     : Uint4B
   +0x0b4 ImageSubsystem   : Uint4B
   +0x0b8 ImageSubsystemMajorVersion : Uint4B
   +0x0bc ImageSubsystemMinorVersion : Uint4B
   +0x0c0 ImageProcessAffinityMask : Uint4B
   +0x0c4 GdiHandleBuffer  : [34] Uint4B
   +0x14c PostProcessInitRoutine : Ptr32
   +0x150 TlsExpansionBitmap : Ptr32 Void
   +0x154 TlsExpansionBitmapBits : [32] Uint4B
   +0x1d4 SessionId        : Uint4B
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
   +0x1e8 pShimData        : Ptr32 Void
   +0x1ec AppCompatInfo    : Ptr32 Void
   +0x1f0 CSDVersion       : _UNICODE_STRING
   +0x1f8 ActivationContextData : Ptr32 Void
   +0x1fc ProcessAssemblyStorageMap : Ptr32 Void
   +0x200 SystemDefaultActivationContextData : Ptr32 Void
   +0x204 SystemAssemblyStorageMap : Ptr32 Void
   +0x208 MinimumStackCommit : Uint4B
0:000>

We just dumped out the structure information for the _PEB structure defined by Windows. We will now attempt to find our PEB and dump this address.

0:000> !teb
TEB at 7ffde000
    ExceptionList:        0006ffb0
    StackBase:            00070000
    StackLimit:           0005f000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7ffde000
    EnvironmentPointer:   00000000
    ClientId:             00000b80 . 00000f40
    RpcHandle:            00000000
    Tls Storage:          00000000
    PEB Address:          7ffdf000
    LastErrorValue:       0
    LastStatusValue:      c0000034
    Count Owned Locks:    0
    HardErrorMode:        0
0:000> dt ntdll!_PEB 7ffdf000
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0x1 ''
   +0x003 SpareBool        : 0 ''
   +0x004 Mutant           : 0xffffffff
   +0x008 ImageBaseAddress : 0x01000000
   +0x00c Ldr              : 0x00191ea0
   +0x010 ProcessParameters : 0x00020000
   +0x014 SubSystemData    : (null)
   +0x018 ProcessHeap      : 0x00090000
   +0x01c FastPebLock      : 0x77fc49e0
   +0x020 FastPebLockRoutine : 0x77f5b2a0
   +0x024 FastPebUnlockRoutine : 0x77f5b380
   +0x028 EnvironmentUpdateCount : 1
   +0x02c KernelCallbackTable : 0x77d42a38
   +0x030 SystemReserved   : [1] 0
   +0x034 ExecuteOptions   : 0y00
   +0x034 SpareBits        : 0y000000000000000000000000000000 (0)
   +0x038 FreeList         : (null)
   +0x03c TlsExpansionCounter : 0
   +0x040 TlsBitmap        : 0x77fc4680
   +0x044 TlsBitmapBits    : [2] 0x7ff
   +0x04c ReadOnlySharedMemoryBase : 0x7f6f0000
   +0x050 ReadOnlySharedMemoryHeap : 0x7f6f0000
   +0x054 ReadOnlyStaticServerData : 0x7f6f0688  -> (null)
   +0x058 AnsiCodePageData : 0x7ffb0000
   +0x05c OemCodePageData  : 0x7ffc1000
   +0x060 UnicodeCaseTableData : 0x7ffd2000
   +0x064 NumberOfProcessors : 1
   +0x068 NtGlobalFlag     : 0x70
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER 0xffffe86d`079b8000
   +0x078 HeapSegmentReserve : 0x100000
   +0x07c HeapSegmentCommit : 0x2000
   +0x080 HeapDeCommitTotalFreeThreshold : 0x10000
   +0x084 HeapDeCommitFreeBlockThreshold : 0x1000
   +0x088 NumberOfHeaps    : 5
   +0x08c MaximumNumberOfHeaps : 0x10
   +0x090 ProcessHeaps     : 0x77fc5a80  -> 0x00090000
   +0x094 GdiSharedHandleTable : 0x00360000
   +0x098 ProcessStarterHelper : (null)
   +0x09c GdiDCAttributeList : 0x14
   +0x0a0 LoaderLock       : 0x77fc1774
   +0x0a4 OSMajorVersion   : 5
   +0x0a8 OSMinorVersion   : 1
   +0x0ac OSBuildNumber    : 0xa28
   +0x0ae OSCSDVersion     : 0x100
   +0x0b0 OSPlatformId     : 2
   +0x0b4 ImageSubsystem   : 2
   +0x0b8 ImageSubsystemMajorVersion : 4
   +0x0bc ImageSubsystemMinorVersion : 0
   +0x0c0 ImageProcessAffinityMask : 0
   +0x0c4 GdiHandleBuffer  : [34] 0
   +0x14c PostProcessInitRoutine : (null)
   +0x150 TlsExpansionBitmap : 0x77fc4660
   +0x154 TlsExpansionBitmapBits : [32] 0
   +0x1d4 SessionId        : 0
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER 0x0
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER 0x0
   +0x1e8 pShimData        : (null)
   +0x1ec AppCompatInfo    : (null)
   +0x1f0 CSDVersion       : _UNICODE_STRING "Service Pack 1"
   +0x1f8 ActivationContextData : 0x00080000
   +0x1fc ProcessAssemblyStorageMap : 0x000929a8
   +0x200 SystemDefaultActivationContextData : 0x00070000
   +0x204 SystemAssemblyStorageMap : (null)
   +0x208 MinimumStackCommit : 0
0:000>

If you remember correctly, the !teb gives you the "thread environment block". A part of this block will show you the PEB for a process. Now, you see that not only does it print the information contained in the data structure, it also knows how to display the information based upon the type of data. Why did I show you this? This is because of what I specified above. The first thing people do or want to do is start to write debug extensions to dump all their data structures and this is not feasible anymore! You then have to keep changing your debug code every time you add or move information around. It's best to use the "dt" command and painlessly find all the data contained in any of your internal data structures.

Starting To Write The Extension

So, my proposed extension is !dumpstrings. This will go through a memory location and dump all the pointers. I can then do !dumpstrings esp and dump the strings to all pointers on the stack.

First, let's start with how you write the extension. WINDBG requires you at least export two functions. These functions in my source are posted below:

/***********************************************************
 * ExtensionApiVersion
 *
 * Purpose: WINDBG will call this function to get the version
 *          of the API
 *
 *  Parameters:
 *     Void
 *
 *  Return Values:
 *     Pointer to a EXT_API_VERSION structure.
 *
 ***********************************************************/              
LPEXT_API_VERSION WDBGAPI ExtensionApiVersion (void)
{
    return &g_ExtApiVersion;
}


/***********************************************************
 * WinDbgExtensionDllInit
 *
 * Purpose: WINDBG will call this function to initialize
 *          the API
 *
 *  Parameters:
 *     Pointer to the API functions, Major Version, Minor Version
 *
 *  Return Values:
 *     Nothing
 *
 ***********************************************************/              
VOID WDBGAPI WinDbgExtensionDllInit (PWINDBG_EXTENSION_APIS 
           lpExtensionApis, USHORT usMajorVersion, 
           USHORT usMinorVersion)
{
     ExtensionApis = *lpExtensionApis;
}

The first function, ExtensionApiVersion, simply returns a version, and all we do is supply version numbers that WINDBG would expect to make it happy. Here is the declaration of g_ExtApiVersion.

/***********************************************************
 * Global Variable Needed For Versioning
 ***********************************************************/              
EXT_API_VERSION g_ExtApiVersion = {
         5 ,
         5 ,
         EXT_API_VERSION_NUMBER ,
         0
     } ;

The EXT_API_VERSION_NUMBER is declared in wdbgexts.h. Please note that there are other variations of debugger extension DLLs, such as using ntsdexts.h. I am going over just one simple example that works with the current CDB and WinDbg debuggers that you can download off of Microsoft's web site. I am also using windbgexts.h, not ntsdexts.h. If you look at your SDK include files, you will notice you have both headers.

So, how is EXT_API_VESRION_NUMBER declared? On my system, it is declared as:

#define EXT_API_VERSION_NUMBER   5

typedef struct EXT_API_VERSION {
    USHORT  MajorVersion;
    USHORT  MinorVersion;
    USHORT  Revision;
    USHORT  Reserved;
} EXT_API_VERSION, *LPEXT_API_VERSION;

Where did you come up with 5, 5? I just debugged some of the other extensions that come with WINDBG to find those numbers. I also found that older WINDBGs use 3, 5. This is really a moot point though, we just need a basic frame work written, after which we can simply write all the commands we want! I'm not big on making things like this big issues or digging deep into their meaning when, it's really irrelevant to me as long as my extension loads.

The WinDbgExtensionDllInit API simply gives your application a virtual function table. This table *must* be named a certain name. Well, it doesn't have to be but it's easier when it is. The reason is that the windbgexts.h contains macros to make function calls to functions stored in this structure. If you don't use the same name, you'll have to create the calls yourself. This is my global in the code:

/***********************************************************
 * Global Variable Needed For Functions
 ***********************************************************/              
WINDBG_EXTENSION_APIS ExtensionApis = {0};

It's really no big deal, the macros just make it a little easier, that's all. You can do whatever you like though. This is the dump of WINDBGEXTS.H macros:

#define dprintf          (ExtensionApis.lpOutputRoutine)
#define GetExpression    (ExtensionApis.lpGetExpressionRoutine)
#define GetSymbol        (ExtensionApis.lpGetSymbolRoutine)
#define Disassm          (ExtensionApis.lpDisasmRoutine)
#define CheckControlC    (ExtensionApis.lpCheckControlCRoutine)
#define ReadMemory       (ExtensionApis.lpReadProcessMemoryRoutine)
#define WriteMemory      (ExtensionApis.lpWriteProcessMemoryRoutine)
#define GetContext       (ExtensionApis.lpGetThreadContextRoutine)
#define SetContext       (ExtensionApis.lpSetThreadContextRoutine)
#define Ioctl            (ExtensionApis.lpIoctlRoutine)
#define StackTrace       (ExtensionApis.lpStackTraceRoutine)

What's next? Aside from these two APIs, you can have a CheckVersion() function to force your extension to only use commands on certain versions of WINDBG. I found this completely useless and didn't implement it as it's not required. So, let's just write a function!

The first function will be simple. We'll do "!help" which will dump the help.

/***********************************************************
 * !help
 *
 * Purpose: WINDBG will call this API when the user types !help
 *          
 *
 *  Parameters:
 *     N/A
 *
 *  Return Values:
 *     N/A
 *
 ***********************************************************/
DECLARE_API (help)
{
    dprintf("Toby's Debug Extensions/n/n");
    dprintf("!dumpstrings <ADDRESS register> - Dumps 20 strings in"/
       "ANSI/UNICODE using this address as a pointer to strings (useful for" /
       "dumping strings on the stack) /n");
       /* String Split so it is readable in this article. */
}

dprintf(); is basically, "debug printf" and it's exactly like printf()! It will print output to the debugger. The DECLARE_API(<command>) is a simple way to declare the API name. Remember, the name you give the function is the name you use in the debugger. I called this help, so to use it, it's !help or !<dllname>.help. This is a simple function that will simply display a help message to the user.

The next thing we want to do is implement our string function. This function will take a parameter which will be a memory address. I also want it to work like current commands, if you do dc <address> then dc again, it will continue where it left off dumping the memory. So, let's see what I've come up with.

/***********************************************************
 * !dumpstrings
 *
 * Purpose: WINDBG will call this API when the user types !dumpstrings
 *          
 *
 *  Parameters:
 *     !dumpstrings or !dumpstrings <ADDRESS register>
 *
 *  Return Values:
 *     N/A
 *
 ***********************************************************/
DECLARE_API (dumpstrings)
{
    static ULONG Address = 0;
    ULONG  GetAddress, StringAddress, Index = 0, Bytes;
    WCHAR MyString[51] = {0};
    
    
    GetAddress = GetExpression(args);

    if(GetAddress != 0)
    {
        Address = GetAddress;
    }
        
    dprintf("STACK   ADDR   STRING /n");

    for(Index = 0; Index < 4*20; Index+=4)
    {
        memset(MyString, 0, sizeof(MyString));
        
        Bytes = 0;

        ReadMemory(Address + Index, &StringAddress, 
                           sizeof(StringAddress), &Bytes);

        if(Bytes)
        {
           Bytes = 0;

           ReadMemory(StringAddress, MyString, 
                 sizeof(MyString) - 2, &Bytes);

           if(Bytes)
           {
              dprintf("%08x : %08x = (UNICODE) /"%ws/"/n", 
                       Address + Index, StringAddress, MyString);
              dprintf("%08x : %08x = (ANSI)    /"%s/"/n", 
                       Address + Index, StringAddress, MyString);
           }
           else
           {
              dprintf("%08x : %08x =  Address Not Valid/n", 
                             Address + Index, StringAddress);
           }
        }
        else
        {
           dprintf("%08x : Address Not Valid/n", Address + Index);
        }
    }

    Address += Index;
}

So, the first function I use is GetExpression(). On the newer WINDBGs, it works like this. ADDRESS GetExpression(SYMBOLIC STRING). You pass in a symbolic string, such as the arguments to the command and it attempts to resolve it to an address. The arguments to the command are stored in args, so I pass in args. This will resolve symbols, addresses or even registers to numbers as would be with the case of passing in ESP.

I now have a static variable. If GetExpression() returned 0, it's possible there are no arguments. If this is the case, I use Address, my static variable. This works if someone does !dumpstrings. It will continue where it left off. At the end of the function, I always save Address as being the next location to dump.

The next function I use is dprintf() which works just like using printf. I've explained this one already, so onto the next tidbit. Addresses are 4 bytes long, so I will increment this address by 4 each time around in the loop. I want to dump 20 addresses, so I loop from 0 to 4*20. Very simple indeed.

Now, you cannot simply reference the memory returned as you are not in the process space of the application. So, WINDBG provides functions to do this such as ReadMemory(). (The windbgexts.h provides prototypes for all the APIs, so you can experiment if you cannot find the API online.) The ReadMemory() function takes 4 arguments:

ReadMemory(Address In Process To Read,
           Local Variable to store the memory read, 
           size of the local variable, 
           pointer to a DWORD that returns the number 
           of bytes read from the memory location);

So, we pass in our pointer to the memory in the application, a pointer to place the data on return, then receive the number of bytes. If no bytes are returned, we print an invalid memory address; if the bytes are returned, we then reference this memory location to read up to 49 bytes (we have 51 and put two NULLs at the end for Unicode support). If I was able to read anything, I then attempt to display it using the dprintf() function in ANSI then in UNICODE. If the memory returns 0 bytes, I print an error specifying it's not a valid address. This is all very simple.

The next thing we need to do is create our .DEF file. This file will simply export our functions.

LIBRARY "TDBG.DLL"

EXPORTS
    WinDbgExtensionDllInit
    ExtensionApiVersion
    dumpstrings
    help

Now, we need to build it. I like using make files and I use Visual Slickedit as my editor. I don't use the VC++ IDE at all. So, in the project, I've created a make file. This is how you would set it up. First, run VCVARS32.BAT which is located in the BIN directory of your VC++ installation. I moved mine to C:/ for easier use. The next thing to do is simply type "nmake" in the directory that the source code was extracted to.

C:/Programming/Programs/debugext/src/debug>/vcvars32
Setting environment for using Microsoft Visual C++ tools.
C:/Programming/Programs/debugext/src/debug>nmake

Microsoft (R) Program Maintenance Utility   Version 6.00.8168.0
Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

        cl /nologo /MD /W3 /Oxs /Zi  /I "./inc"  /D "WIN32" /DLL /D "_WINDOWS"
/Fr./obj/i386// /Fo./obj/i386// /Fd./obj/i386// /c ./tdbg.c
tdbg.c
C:/PROGRA~1/MICROS~2/VC98/INCLUDE/wdbgexts.h(526) : warning C4101: 'li' : unrefe
renced local variable
        link.exe /DLL /nologo /def:tdbg.def /out:../../bin/tdbg.dll  /pdb:tdbg.p
db /debug /debugtype:both USER32.LIB  KERNEL32.LIB ./obj/i386/tdbg.obj
   Creating library ../../bin/tdbg.lib and object ../../bin/tdbg.exp
        rebase.exe -b 0x00100000 -x ../../bin -a ../../bin/tdbg.dll

REBASE: Total Size of mapping 0x00010000
REBASE: Range 0x00100000 -0x00110000

C:/Programming/Programs/debugext/src/debug>nmake clean

Microsoft (R) Program Maintenance Utility   Version 6.00.8168.0
Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

Deleted file - C:/Programming/Programs/debugext/src/debug/obj/i386/tdbg.obj
Deleted file - C:/Programming/Programs/debugext/src/debug/obj/i386/tdbg.sbr
Deleted file - C:/Programming/Programs/debugext/src/debug/obj/i386/vc60.pdb

C:/Programming/Programs/debugext/src/debug>

If you want to build again, you'd need to either change the source so the date is updated or type "nmake clean" to rebuild. You should now have a binary.

 Volume in drive C has no label.
 Volume Serial Number is 2CF8-F7B5

 Directory of C:/Programming/Programs/debugext/bin

03/25/2004  08:56 PM    <DIR>          .
03/25/2004  08:56 PM    <DIR>          ..
03/25/2004  09:53 PM             2,412 tdbg.dbg
03/25/2004  09:53 PM            20,752 tdbg.dll
03/25/2004  09:53 PM             1,044 tdbg.exp
03/25/2004  09:53 PM             2,538 tdbg.lib
03/25/2004  09:53 PM            82,944 tdbg.pdb
               5 File(s)        109,690 bytes
               2 Dir(s)  12,229,009,408 bytes free

Simply copy this binary to a location that can be found by your WinDbg, such as your windows directory. You can specify the path to load these extensions using !load and !unload (to unload the extension if you built a new version/ want to force the debugger to unload it so you can reload the next one). You can use !<dll name>.<function name> or just !<function name>. The mentioning of the binary name will force WINDBG to look for it to load it. It can also help to distinguish between which DLL to use for a command if multiple DLL extensions export it.

Let's Try It Out

Now that we have created our debug extension, I move it to a location where WINDBG can load it (such as my windows directory). I then use "!tdbg.dumpstrings esp" to dump all the strings on the stack. This is the same application (restarted so addresses may change) restarted (I verified with dc esp, I get the same strings on the stack as before). I now want to dump all the pointers to strings on the stack. Let's try this and see what happens!

0:000> !tdbg.dumpstrings esp
STACK   ADDR   STRING
0006febc : 77d43a09 = (UNICODE) ""
0006febc : 77d43a09 = (ANSI)    "┬►"
0006fec0 : 77d43c7d = (UNICODE) ""
0006fec0 : 77d43c7d = (ANSI)    "ïN♦ü∙☻☺"
0006fec4 : 0006fefc = (UNICODE) ""
0006fec4 : 0006fefc = (ANSI)    "▐♥↔"
0006fec8 : 00000000 =  Address Not Valid
0006fecc : 00000000 =  Address Not Valid
0006fed0 : 00000000 =  Address Not Valid
0006fed4 : 00000000 =  Address Not Valid
0006fed8 : 0006ff1c = (UNICODE) ""
0006fed8 : 0006ff1c = (ANSI)    "└ ♠"
0006fedc : 010028e4 = (UNICODE) ""
0006fedc : 010028e4 = (ANSI)    "à└uöΦ├∩   5î¢"
0006fee0 : 0006fefc = (UNICODE) ""
0006fee0 : 0006fefc = (ANSI)    "▐♥↔"
0006fee4 : 00000000 =  Address Not Valid
0006fee8 : 00000000 =  Address Not Valid
0006feec : 00000000 =  Address Not Valid
0006fef0 : 00000000 =  Address Not Valid
0006fef4 : 77e7ad86 = (UNICODE) ""
0006fef4 : 77e7ad86 = (ANSI)    "â|___FCKpd___14diams;"
0006fef8 : 00091ee8 = (UNICODE) ""
0006fef8 : 00091ee8 = (ANSI)    ""
0006fefc : 001d03de = (UNICODE) ""
0006fefc : 001d03de = (ANSI)    ""
0006ff00 : 00000118 =  Address Not Valid
0006ff04 : 0000ffff =  Address Not Valid
0006ff08 : bf8a75ed =  Address Not Valid
0:000> !tdbg.dumpstrings
STACK   ADDR   STRING
0006ff0c : 077d5cc8 =  Address Not Valid
0006ff10 : 000001f3 =  Address Not Valid
0006ff14 : 000001df =  Address Not Valid
0006ff18 : 00000000 =  Address Not Valid
0006ff1c : 0006ffc0 = (UNICODE) ""
0006ff1c : 0006ffc0 = (ANSI)    "≡ ♠"
0006ff20 : 01006c54 = (UNICODE) ""
0006ff20 : 01006c54 = (ANSI)    "ï≡ëuä9]ΣuV §▄↕"
0006ff24 : 01000000 = (UNICODE) ""
0006ff24 : 01000000 = (ANSI)    "MZÉ"
0006ff28 : 00000000 =  Address Not Valid
0006ff2c : 00091ee8 = (UNICODE) ""
0006ff2c : 00091ee8 = (ANSI)    ""
0006ff30 : 0000000a =  Address Not Valid
0006ff34 : 00000000 =  Address Not Valid
0006ff38 : 00000000 =  Address Not Valid
0006ff3c : 7ffdf000 = (UNICODE) ""
0006ff3c : 7ffdf000 = (ANSI)    ""
0006ff40 : 80543940 =  Address Not Valid
0006ff44 : f4910c5c =  Address Not Valid
0006ff48 : 00000044 =  Address Not Valid
0006ff4c : 00092b30 = (UNICODE) ""
0006ff4c : 00092b30 = (ANSI)    ""
0006ff50 : 00092b50 = (UNICODE) ""
0006ff50 : 00092b50 = (ANSI)    "WinSta0/Default"
0006ff54 : 00092b78 = (UNICODE) ""
0006ff54 : 00092b78 = (ANSI)    "C:/WINDOWS.0/System32/notepad.exe"
0006ff58 : 00000000 =  Address Not Valid
0:000> !tdbg.dumpstrings
STACK   ADDR   STRING
0006ff5c : 00000000 =  Address Not Valid
0006ff60 : 00000000 =  Address Not Valid
0006ff64 : 00000000 =  Address Not Valid
0006ff68 : 00000000 =  Address Not Valid
0006ff6c : 00000000 =  Address Not Valid
0006ff70 : 00000000 =  Address Not Valid
0006ff74 : 00000000 =  Address Not Valid
0006ff78 : 00000000 =  Address Not Valid
0006ff7c : 00000000 =  Address Not Valid
0006ff80 : ffffffff =  Address Not Valid
0006ff84 : ffffffff =  Address Not Valid
0006ff88 : ffffffff =  Address Not Valid
0006ff8c : 00091ee8 = (UNICODE) ""
0006ff8c : 00091ee8 = (ANSI)    ""
0006ff90 : 00000000 =  Address Not Valid
0006ff94 : 00000001 =  Address Not Valid
0006ff98 : 00272620 = (UNICODE) ""
0006ff98 : 00272620 = (ANSI)    "(&'"
0006ff9c : 00272d00 = (UNICODE) ""
0006ff9c : 00272d00 = (ANSI)    "░-'"
0006ffa0 : 00000000 =  Address Not Valid
0006ffa4 : 00000000 =  Address Not Valid
0006ffa8 : 0006ff34 = (UNICODE) ""
0006ffa8 : 0006ff34 = (ANSI)    ""

We found two strings on the stack. Not bad and all I did was start Notepad. I didn't do anything else. This is a simple example of how this API could be used. Take a memory location and dump out all the pointers to strings. You are always going to get garbage and invalid address dumped on the stack (or any memory location for that matter). It's the valid addresses that contain strings that we are looking for.

Conclusion

I hope you enjoyed learning how to write a debug extension and hopefully even find the example useful! There are other APIs listed which you can look up or perhaps another tutorial can explain them in the future. The basics of reading memory and displaying information were covered. Hopefully, in the future, we can explore more advanced debugging commands.

About Toby Opferman

疾风气象大模型4.0白皮书 《疾风气象大模型白皮书摘要》 疾风气象大模型(J-AFM)是国内首个基于3D建模的气象智能平台,突破传统二维气象分析的局限,采用体素化技术构建"x-y-z-t"四维统一模型,实现从分钟级短临到30天跨时效的连续预测。核心技术包括:1)多源数据三维同化,融合雷达、卫星、风廓线等异构数据;2)物理约束AI解码器,嵌入能量守恒、湍流封闭等气象原理;3)行业适配插件,服务风电、光伏、航空等领域,如山地风场尾流校正、云影短临预测。平台支持批流一体推理与边缘部署,提供概率化输出和误差溯源能力,显著降 阅读详情

相关推荐

Labview程序框架介绍

当掌握LabVIEW基础知识并达到,理解单个小型模块程序会相对轻松。而若想进一步探索大型程序,就必然需要了解程序框架相关内容。LabVIEW常用的程序架构包括等。在多年工作中,我接触过的众多高级工程师所开发的大型程序,基本都基于这些架构搭建。接下来,将为大家详细介绍这些框架。

Misterlhw的博客 4623

编译dll时debug和release版命名不同遇到的问题

我在project->setting->link里面把debug的输出改为MyDllD.dll,release版仍保持为MyDll.dll,其相应的lib文件分别为MyDllD.lib和MyDll.lib。我把debug版用到其他程序时,在project->setting->link中设置链接库为MyDllD.lib,把MyDllD.dll放到相应目录下,运行时总是说找不到MyDll.dll,按道

Richard的专栏 979

【IC】Redhawk-SC输入件配置

Redhawk sc

u011808788的博客 1778

在使用cppunit,搭建测试环境时遇到的问题以及解决办法(仅供参考)

文章很实用,但是我在vs2012下配置又出现了更奇葩的问题 原文地址:在使用cppunit,搭建测试环境时遇到的问题以及解决办法(仅供参考)作者:每天up 2013-1-22 11:20:11. ------ Build started: Project: cppunit, Configuration: Debug Win32 ------ Build started 20

yiling2012的专栏 1309

ComfyUI-Impact-Subpack插件安装避坑指南:为什么你的UltralyticsDetectorProvider节点还是找不到?

本文深入解析了ComfyUI-Impact-Subpack插件的安装与排障问题,特别是针对UltralyticsDetectorProvider节点缺失的常见问题提供了详细的解决方案。从底层机制到高阶应用,涵盖了手动安装、模型配置、性能优化等关键步骤,帮助用户彻底解决插件依赖关系断裂问题。

Jerry的专栏 1152

Godot4 TileMap分层绘制全攻略:解决角色、树木遮挡混乱,打造正确视觉层级

本文详细介绍了Godot4 TileMap分层绘制技术,通过图层管理和Y-Sort功能解决2D游戏中角色与物体的遮挡问题。从基础图层设置到高级优化策略,帮助开发者打造符合自然视觉规律的场景层次,提升游戏沉浸感。特别针对TileMap和TileSet的使用提供了实用技巧和代码示例。

weixin_28717411的博客 514

windbg 插件编写 ---基础篇

标 题: WinDbg插件编写——基础篇作 者:Lvg时 间:2007-01-29 00:43  链 接:http://bbs.pediy.com/showthread.php?t=38729 WinDbg插件编写——基础篇     本文只是简略的描述了一下WinDbg扩展命令的编写步骤及方法,更详细的请看他的帮助文档,起到一个抛砖引玉的作用就行了。 Win

superliuxing的专栏 1988

IT资产管理(三)之GLPI资产录入

glpi 在 10 版本之后已经有自带的 glpi-agent 代理程序可自动获取服务器、电脑等的信息并进行自动录入和更新,不再依赖 10 版本之前的 fusioninventory 插件或者第三方资产统计平台 OCS Inventory 等

予挚之的博客 2996

Latex Section 段落标题编号设置的问题

问题: 在撰写论文时,有些会议论文或期刊的latex模版下载下来后会发现,仅仅使用 \Section{Introduction}以及\subsection{},即一级段落标题和二级段落标题,编译后该标题前并没有数字排序或者有数字但是不想要数字。 解决方法: 这和会议或者期刊论文官方给定的latex包里的一个文件有关系。文件夹里会包含一个后缀名为cls的文件(*.cls),这个是定义排版的文件,所以section的标题风格也在此定义了。打开该文件,搜索“section”字眼,可以看到跳转到section

Lily's Blog 1万+

RK3588平台开发系列讲解(硬件篇-功能外设2)

RK3588 芯片内置两个USB3.0 OTG控制器(内嵌2个USB2.0 OTG,下图绿色处),1个USB3.0 HOST 控制器,2个USB2.0 HOST控制器。这些控制器与PHY的内部复用图如下:USB3.0 OTG0 控制器支持SS/HS/FS/LS, 内嵌的USB2.0(HS/FS/LS)信号采用USB2.0 OTG PHY, 信号名见下图的红色方框内;RK3588目前仅此接口支持做Fireware的Download,应用中请务必要预留出。

whm128的博客 2512

15 RK3568 RTL8111 PCIE

我这边扩了三个网卡。pcie3.0拆分了1+1lane。需要注意自己的reset引脚修改为自身rtl引脚即可。1、调试pcie 扩展网卡 RTL8111。

qq_39451352的博客 182

WinDbg调试推荐材料

Debug Tutorial Part 1: Beginning Debugging Using CDB and NTSDLearn how to debug problems in software.Debug Tutorial Part 2: The StackIntroduction to the most important ally in the fight against bugs, ...

iteye_10234的博客 177

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

VC下发布的Release版程序的异常捕捉

寻找Release版程发生异常退出的地方比Debug版麻烦得多。发生异常的时候windows通常会弹出一个错误对话框,点击详细信息,我们能获得出错的地址和大概的出错信息,然后可以用以下办法分析我们的程序。  一. 用MAP文件定位异常代码位置。1.如何生成map文件打开“Project →Project Settings”,选择 C/C++ 选项卡,在“Debug Info”栏选择

WLV的专栏 5706

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

如何完成Windbg插件

WinDbg插件编写――基础篇本文只是简略的描述了一下WinDbg扩展命令的编写步骤及方法,更详细的请看他的帮助文档,起到一个抛砖引玉的作用就行了。WinDbg是老盖自己家出的调试器,功能很强大。即可调试用户态,也可以调试核心态程序。本文主要介绍他插件(准确讲应该是扩展命令)的编写方法。WinDbg的扩展命令和OD一样是通过DLL文件导出的。一.插件的类型他有两种不同类型的DLL文件:1.DbgE

IT杂谈 3253

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Making WinDbg Your Friend - Creating Debugger Extensions (编写windbg扩展)

转自osronline What can be more fun than trying to scan through your private data structures using WinDbg’s Command window?  Anyone who has tried to walk data structures from within WinDbg will know,

lixiangminghate的专栏 607

WinDbg——拓展DLL开发入门

WinDbg提供了接口实现第三方开发自定义功能的库。 废话少说,以下是最简单的一个Demo,只包含一个help指令。   实现   主要包含两个点: 1. 实现DebugExtensionInitialize 函数,这是实现WinDbg拓展DLL必须实现的;WinDbg在载入此DLL会调用。 2. 导出函数   创建一个简单的DLL工程。 源码如下: .h #includ...

依然那霖哥 1467

微软技术日报 11-09:.NET 8 与 9 明日同时停止支持,注册表编辑器出了 WinUI 3 版

今天这四条消息的共同点是收口。.NET 8 和 9 的支持期到点,注册表编辑器的新界面只放在仓库里给人看,GitHub 把一类危险触发器按住默认,微软在安全报告里把防线从地址黑名单挪到行为。收口并不等于关门。.NET 10 还在支持期里,被按住的触发器可以用策略按文件放回来,实验室里的样例随时可能变成产品。区别在于这些动作要有人签字,不再是默认开着。如果今天只做一件事,去看一眼构建机上的 .NET 版本。明天之后,8 和 9 的漏洞补丁不会再来了。

海盗Sharp的博客 390

AI驱动数据处理的安全边界:行业现状、风险权衡与本地化实践路径

本文基于第三方数据,分析AI用于数据处理的安全议题。大模型应用加速普及,但伴随数据出境、影子AI、幻觉与成本失控等风险。行业共识指向“脚本复用”路径:将分析逻辑本地化固化,实现数据可控、结果可复现、成本可降。产品如数以轻舟提供本地处理、多模型接入与一次付费永久使用方案。建议企业从数据落点、可控性、可复现性与合规性四维度评估选型,推动AI在安全边界内释放价值。

数据矿工-数据化运营博客 328

微软技术日报 11-08:Foundry 与 Entra 各挂一个 10.0 分漏洞,Foundry 接 fal 五款视频模型

这一周的动作可以分成两类。一类在收。Copilot 从电视上退场,搜索里的 AI 改成可选,云端漏洞只发通知不收补丁。共同点是承认铺得太开,代价比预期高。另一类在放。Foundry 一次摆上五个视频模型,容器版应用网关一个入口挂 64 个 MCP 服务器。共同点是把能力做成可组合的积木,让使用者按需挑。两个方向背后是同一个判断。把能力塞到每一个界面上,短期看覆盖率高,长期要解释为什么删不掉。新的做法是先给一个能关的开关,再谈覆盖。对每天写代码的人来说,今天有两样现成的东西可以试。

海盗Sharp的博客 419

微软技术周报 11-02~11-09:VS Code 混装 Claude 与 Codex、EF Core 11 静默改行为、.NET 11 倒计时

11 月 6 日,Power Platform 通过消息中心通知管理员,Copilot Studio、Power Automate 和 Power Apps 里所有跑在 Anthropic Claude、xAI Grok 以及旧版 GPT 上的 prompt,12 月 2 日自动迁移到 GPT-6 系列,档位价格不变,模型选择收窄到一条产品线。效果是这样的:让 Claude 评审一个 Copilot chat 写出的方案,或者把同样的任务交给 Codex,两边并排跑在同一个会话里。更要紧的是下周的时间线。

海盗Sharp的博客 989

MAI-Cyber-1 深度解析:微软首个网络安全专用模型

微软没有去做"更大的安全大模型",而是用一颗 137B 总参、仅 5B 激活的稀疏 MoE 专用模型,配上 90/10 的"小模型铺量、大模型兜底"路由,在 CyberGym 基准上拿到 95.95% 的同时把成本砍掉一半——这标志着 AI 安全从"通用模型加提示词"进入了"专用模型加系统工程"的时代。

Simple_Pure的博客 327

微软输入法标点乱跳解决方案

微软拼音输入法常因“中文输入时使用英文标点”开关被意外开启,导致标点自动切换为英文且快捷键失效。本文提供一键批处理脚本,通过修改注册表(HKCU\Software\Microsoft\InputMethod\Settings\CHS)强制锁定中文标点,覆盖多个相关键值,确保设置持久生效。相比手动操作,该方案可抵御更新、同步等导致的配置重置,提升稳定性。执行后需重启输入法或系统以使更改生效,建议提前备份注册表。

谙弆悕博士的技术博客! 370

微软2026年11月补丁星期二解析:1094个 CVE、Outlook 零日 CVE-2026-124194 与修复优先级

微软11月补丁星期二修复1094个 CVE,唯一在野利用的 Outlook 零日 CVE-2026-124194 只评为“中等”,修复随 Office 更新下发、不在 Windows 累积更新里。本文整理漏洞分布、严重级漏洞分类处置与三档修复优先级。

SplashtopLoki的博客 217
上一篇: Debug Tutorial Part 2: The Stack
下一篇: Debug Tutorial Part 5: Handle Leaks
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值