Another Writing method for WindBG plug-in - Debugger Engine Extension

zhaozj2021-02-12  142

http://www.blogcn.com/user8/flier_lu/index.html?id=2178387

After reading the SCZ "MSDN Series (11) - Give Softice Write Plugin", I can't help yourself try the WINDBG plugin, huh, huh. However, I chose to write methods with another WindBG plug-in with different small four. Windbg's latest version of the SDKHELP directory has a debugext.chm file, there is a very detailed Windbg plugin to write documents. This is mentioned that WindBG supports two types of plug-ins: DBGENG extensions and WDBGEXTS extensions. The former is a debugging extension that is defined in DBGENG.H; the latter is a dedicated debugging extension that is defined in WDBGEXTS.H. The use of the latter is the latter interface, which is more concise, or it can be well supported by Softice; I choose the previous plugin type, more powerful, and other tools that support the Debugger Engine API outside Windbg Such as Visual Studio.net support. Similar to the WDBGEXTS type extension, the DBGENG type extension must implement a initial callback function:

The following is quoted:

HRESULT CALLBACK DebugExtensioninitialize (Out Pulong Version, Out Pulong Flags);

This function is called when using the .load command to load the plugin, return to the version information of the plugin. Such as

The following is quoted:

Const int exts_version_major = 1;

const Int EXTS_VERSION_MINOR = 0;

Extern "C" HRESULT CALLBACK DebugExtensioninitialize (Out Polong Version, Out Pulong Flags)

{

* Version = debug_extension_version (exts_version_major, exts_version_minor);

* Flags = 0;

Return S_OK;

}

When defining the plug-in callback function, you must use the extern "c" to specify the function name of this function uses the name format with the C compatible, and build a .def file definition entry name, such as

The following is quoted:

Library Clrexts

Exports

DebugExtensionInitialize

DebugExtensionunInInInIn

DebugExtensionNotify

KNOWNStructOutput

Help

Showcontext

Here, create a new DBGENG type plugin CLREXTS completes the CLR debugging support extension, and exports four standard callback functions. In addition to DebugextensionInitialize must have, the other three callback functions are optional.

The following is quoted:

Void Callback DebugExtensionNotify (in Ulong Notify, In Ulong64 Argument);

The DebuggExtensionNotify function is called when the status conversion of the debug session is called to inform the plugin to adjust your status. Notify parameter can have four values: DEBUG_NOTIFY_SESSION_ACTIVE: debug session is active DEBUG_NOTIFY_SESSION_INACTIVE: not active debugging session DEBUG_NOTIFY_SESSION_ACCESSIBLE: debugging session was interrupted and can be accessed DEBUG_NOTIFY_SESSION_INACCESSIBLE: debugging session and resume execution of the concept can not access the debug session, indicating whether you are debugging a In the process; and according to the debug status, the interrupt target program is running and the debugger gets control, the debug session is interrupted and accessible (debug_notify_session_accessible). The debug plugin can adjust the control method of the target debug process by tracking changes in these states. The following is quoted:

Void Callback DebugExtensionunInInitialize (Void);

The DebugextensionunInInInInIze function is called when the plugin is uninstalled by the .unload command.

The following is quoted:

HResult Callback KnownstructOutput (in Ulong Flag, in Ulong64 Address, In Pstr Structname, Out Pstr Buffer, In Out Pulong Buffers);

The last KNOWNStructOput callback function is less used, used to provide this debug plugin supports the list of profiles, and prints the specified structure content of the specified address. Without the WDBGEXTS type plugin, the debug interface of the DBGENG type plugin can be obtained by the debugcreate function, call the COM interface.

The following is quoted:

HRESULT DebugCreate (In Refiid InterfaceID, Out Pvoid ​​* Interface);

You can also be obtained by the parameters of the plugin command. The universal command interface of the plugin is as follows:

The following is quoted:

HRESULT Callback (* PDebug_extension_call) (in Optional PCSTR ARGS);

The first parameter client is a debug interface, and the other is the parameter string of the command. You can use a simple packaging class CDebugClient to pack the IDEBUGCLIENT interface, and its constructor automatically obtain debug interfaces.

The following is quoted:

Class CDebugClient

{

Private:

HRESULT M_HR;

CComptr M_SPDebugClient;

CCOMQIPTR M_SPDebugControl;

WINDBG_EXTENSION_APIS32 m_EXTENSIONAPIS;

PUBLIC:

CDebugClient (Void);

}

CDebugClient :: CDebugClient (void)

{

m_hr = debugcreate (__ uuidof (idebugclient), (pvoid *) & m_spdebugclient);

IF (successededed (m_hr))

{

m_spdebugControl = m_spdebugclient;

m_extensionapis.nsize = sizeof (m_extensionapis);

M_hr = m_spdebugControl-> getWindBGextensionaPis32 (& m_extensionaPis);

}

The DEBUGCREATE function constructs a new IDEBugClient interface instance and places the object m_spdebugclient of the ATL interface package CCIMPTR and can obtain an IdeBugControl interface instance from this interface query. IDEBUGCONTROL :: GetWindBGextensionAPIS32 can get the debug interface function set compatible with the WDBGEXTS type plugin. However, we will see that DBGENG's corresponding interface is much stronger than Windbg's traditional function set function. For the IdeBugClient instance given for the inlet of the plug-in command, you can save the construction process, such as

The following is quoted:

CDebugClient :: CDebugClient (IDEBUGCLIENT * DBG)

: M_outlevel (Oldefault), M_hr (S_OK), M_SPDebugClient (DBG)

{

IF (DBG)

{

m_spdebugControl = m_spdebugclient;

m_extensionapis.nsize = sizeof (m_extensionapis);

M_hr = m_spdebugControl-> getWindBGEXTENSIONAPIS32 (& M_EXTensionAPIS);

}

}

After you understand the creation and packaging methods of the debug interface, you can create the first plug-in command, Help, display a help string to the debugger

The following is quoted:

Extern "C" HRESULT CALLBACK HELP (IDEBUGCLIENT * Client, In Optional PCSTR ARGS)

{

Unreferenced_Parameter (ARGS);

CDebugClient DebugClient (client);

IF (debugclient.getlasthResult ())) Return DebugClient.getlasthResult ();

DebugClient.info ("Help for% S"

"Help - Show this Help", EXTS_NAME);

Return DebugClient.getlasthResult ();

}

Unreferenced_Parameter is a macro that is used to explicitly reference the function parameters that will not be used once, avoid the compiler warning; then use the command parameter to construct the CDebugClient instance, and determine if its constructor is valid; then call the CDEBugClient package INFO function Print a bunch Help string; finally returns the final call status of DEBUGCLIENT. The function logic is very simple, it is no longer, look at the output of the string.

The following is quoted:

ENUM OUTPUTLEVEL

{

Olall,

Oldebug,

Olinfo,

Olwarning,

Olerror,

#ifdef _Debug

Oldefault = OLALL

#ELSE

Oldefault = olinfo

#ENDIF

}

Class CDebugClient

{

Private:

Outputlevel m_outlevel;

}

First define 5 default output levels, all, debugging, information, warnings, and errors; then define the information display level of the debug interface.

The following is a reference: Class CDebugClient

{

PUBLIC:

Void OutputString (OutputLevel LVL, Const Char * FMT, VA_LIST ARGS) Const;

Void OutputString (Outputlevel LVL, Const Char * FMT, ...) Const;

Void DOLOG (Outputlevel Level, Const Char * FMT, VA_LIST ARGS) Const

{

IF (m_outlevel <= level) OutputString (Level, FMT, ARGS);

}

#define def_log_level (name) void name (const char * fmt, ...) const

{

VA_LIST ARGS;

VA_START (ARGS, FMT);

DOLOG (OL ## Name, FMT, ARGS);

VA_END (ARGS);

}

DEF_LOG_LEVEL (Debug);

DEF_LOG_LEVEL (INFO);

DEF_LOG_LEVEL (WARNING);

DEF_LOG_LEVEL (ERROR);

}

The actual information output is done in the outputstring function, while DOLOG determines whether or not the output information is required according to the information level of the current debug interface. And use the DEF_LOG_LEVEL macro definition four commonly used information output functions.

The following is quoted:

Void CDebugClient :: OutputString (OutputLevel LVL, Const Char * FMT, VA_LIST ARGS) Const

{

#if 1

Static Ulong Outputmask [] = {

0,

Debug_output_verbose,

Debug_output_normal,

Debug_output_warning,

Debug_output_error

}

M_spDebugcontrol-> OutputValist (Outputmask [LVL], FMT, ARGS);

#ELSE

Std :: string Str;

Str.resize (_Vscprintf (FMT, ARGS) 1, 0);

_VSnprintf (const_cast ), str.size (), fmt, args;

m_extensionapis.lpoutputeroutine (str.c_str ());

#ENDIF

}

Void CDebugClient :: OutputString (OutputLevel LVL, Const Char * fmt, ...) Const

{

VA_LIST ARGS;

VA_START (ARGS, FMT);

OutputString (LVL, FMT, ARGS);

VA_END (ARGS);

}

OutputString can be output through the OutputValist method of IdebugControl, or by the traditional WDBGEXTS debug interface of the LPOUTPUTROUTINE function output. The former has the advantage that the corresponding output mask can be set according to the information output level. If Oldebug corresponds to debug_output_verbose, this type of information is only displayed when Windbg opens Verbose mode (menu view / verbose output), which is ideal for debugging of plugins. After understanding the general use of the debug interface function, you will then write a function of the actual meaning, that is, the showcontext function in a small four article, the code is as follows:

The following is quoted:

#define offsetof (Type, Member) ((SIZE_T) 0) -> Member) Extern "C" HRESULT CALLBACK SHOWCONTEXT (IdebugClient * Client, In Optional PCSTR ARGS)

{

CDebugClient DebugClient (client);

IF (debugclient.getlasthResult ())) Return DebugClient.getlasthResult ();

DebugClient.debug ("% s: Call Externsion Function ShowContext with arguments -% s", eXTS_NAME, ARGS);

Std :: string buf;

DWORD dwsize = offsetof (PContext, ExtendedRegisters);

BUF.Resize (dwsize);

DWORD DWADDRESS = DebugClient.evaluate (ARGS);

DebugClient.debug ("% s: get expression"% s "'s value% x", EXTS_NAME, ARGS, DWADDRESS;

IF (Dewclient.ReadMemory (dwaddress, buf) == dwsize)

{

PCONText PCTXT = (PContext) buf.c_str ();

DebugClient.info ("EAX =% 08X EBX =% 08X ECX =% 08X EDX =% 08X ESI =% 08X"

"EDI =% 08X EBP =% 08X ESP =% 08X EIP =% 08X EFLAGS =% 08X"

"CS =% 04X DS =% 04X SS =% 04X ES =% 04X FS =% 04X GS =% 04x",

PCTXT-> EAX, PCTXT-> EBX, PCTXT-> ECX, PCTXT-> EDX, PCTXT-> ESI,

PCTXT-> EDI, PCTXT-> EBP, PCTXT-> ESP, PCTXT-> EIP, PCTXT-> EFLAGS,

(Word) PCTXT-> Segcs, (Word) PCTXT-> SEGDS, (WORD) PCTXT-> segss,

(Word) PCTXT-> Seges, (Word) PCTXT-> SEGFS, (WORD) PCTXT-> seggs;

}

Else

{

DebugClient.warning ("% s: cannot Read Process Memory @% x", EXTS_NAME, DWADDRESS;

}

Return DebugClient.getlasthResult ();

}

The code logic is simple: first get the debug interface; then call the DEBUGCLIENT.EVALUATE function analysis command parameter, get the target address; then call the DEBUGCLIENT.ReadMemory function to read the contents of the Context structure from the specified address; final call debugclient.info function Output information. The OFFSTOF Macro is a tip that acquires the length of the content of the structure, and the relative offset of the specified field in the structure is obtained by enforcing the 0 address to the structural pointer. The following is quoted:

Size_t CDebugClient :: EVALUATE (Const Char * LPEXPIEN)

{

Debug_Value value;

M_hr = m_spdebugControl-> Evaluate (lpexpression, debug_value_int32, & value, null);

Return Value.i32;

}

CDEBUGCLIENT :: Evaluate function Simply invokes the evaction function of the IDEBUGCONTROL interface to complete the calculation of the expression. For example, "ShowContext * (ESP 4)" command, the content of the command line parameter args is "* (ESP 4)", and the EVALUATE function can calculate this expression to get a determined address. The debug_value_int32 parameter specifies that you need to get a 32-bit integer; Debug_Value is a federal type similar to Variant, and the user holds a variety of possible types of parameters.

The following is quoted:

Size_t CDebugClient :: ReadMemory (size_t offset, void * buf, size_t size) const

{

Ulong readbytes;

#if 1

CCOMQIPTR SpDebugDataSpaces; M_SpdebugClient;

SpdebugDataSpaces-> Readvirtual (Offset, BUF, SIZE, & ReadBytes);

#ELSE

M_EXTensionApis.lpreadProcessMemoryRoutine (Offset, Buf, Size, & ReadBytes);

#ENDIF

Return Readbytes;

}

Size_t cdebugclient :: readMemory (size_t offset, std :: string&b) const

{

Return Readmemory (Offset, Const_cast ), buf.size ());

}

ReadMemory is relatively simple, can read the virtual memory of the target process through the IDEBUGDATASPACES interface or WDBGEXTS compatible interface. At this point, the necessary content prepared for a DBGENG type plugin has been basically introduced, and there will be a chance to detail the specific usage method of debug interface, huh, huh btw: Do not find the code that I want to compile directly. I am different from the small four habits, only provide a detailed introduction to the need to write full code. If you want to actually run, you will work hard, huh, huh.

转载请注明原文地址:https://www.9cbs.com/read-6592.html

New Post(0)