Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1583 lines
53 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
ndrexts.cxx
Abstract:
This file contains ntsd debugger extensions for RPC NDR.
Author:
Mike Zoran (mzoran) September 3, 1999
Revision History:
--*/
#define USE_STUBLESS_PROXY
#include "ndrextsp.hxx"
#include "orpcexts.h"
#include "basicinf.hxx"
// =======================================================================
//
// Project wide global variables
//
EXT_API_VERSION ApiVersion = {
VER_PRODUCTVERSION_W >> 8,
VER_PRODUCTVERSION_W & 0xFF,
EXT_API_VERSION_NUMBER,
0
};
BOOL OldExtensions=TRUE;
BOOL ExtensionsInitialized=FALSE;
USHORT SavedMajorVersion=0;
USHORT SavedMinorVersion=0;
BOOL ChkTarget; // is debuggee a CHK build?
// ntstatus to error name lookup
#include <ntstatus.dbg>
EXTERN_C HANDLE ProcessHandle = 0;
EXTERN_C BOOL fKD = 0;
// Settings
NDREXTS_STUBMODE_TYPE ContextStubMode = OICF;
NDREXTS_DIRECTION_TYPE ContextDirection = IN_BUFFER_MODE;
BOOL ContextPickling = FALSE;
BOOL ContextRobust = FALSE;
NDREXTS_VERBOSITY VerbosityLevel = MEDIUM;
// Printing
class DEBUGGER_STREAM_BUFFER : public FORMATTED_STREAM_BUFFER
{
protected:
virtual void SystemOutput(const char *p);
virtual BOOL SystemPollCtrlC();
} DbgOutStream; // Stream to output to the debugger.
void DEBUGGER_STREAM_BUFFER::SystemOutput(const char *p)
{
dprintf(p);
}
BOOL DEBUGGER_STREAM_BUFFER::SystemPollCtrlC()
{
return ::PollCtrlC();
}
FORMATTED_STREAM_BUFFER & dout = DbgOutStream;
//
// Project wide memory management
//
void * __cdecl ::operator new(size_t Bytes)
{
void *p = HeapAlloc(GetProcessHeap(), 0, Bytes);
if ( !p )
{
throw bad_alloc();
}
return p;
}
void __cdecl ::operator delete (void *p)
{
HeapFree(GetProcessHeap(),0,p);
}
const char CExceptionText[] = "C Exception";
class SEHException : public exception
{
unsigned int ExceptionCode;
const char *GenerateString(unsigned int Id)
{
int i = 0;
while ( ntstatusSymbolicNames[i].SymbolicName )
{
if ( ntstatusSymbolicNames[i].MessageId == Id )
{
return ntstatusSymbolicNames[i].SymbolicName;
}
i++;
}
return CExceptionText;
}
public:
SEHException(unsigned int c) : exception(GenerateString(c)) ,ExceptionCode(c)
{
}
virtual unsigned int GetExceptionCode(void)
{
return ExceptionCode;
}
};
void _cdecl SEHTranslator(unsigned int ExceptionCode, struct _EXCEPTION_POINTERS* ExceptionPointers)
{
throw SEHException(ExceptionCode);
}
extern "C" {
DllMain(
HANDLE hModule,
DWORD dwReason,
DWORD dwReserved
)
{
switch ( dwReason )
{
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_ATTACH:
_set_se_translator(SEHTranslator);
break;
}
return TRUE;
}
VOID
WinDbgExtensionDllInit(
PWINDBG_EXTENSION_APIS lpExtensionApis,
USHORT MajorVersion,
USHORT MinorVersion
)
{
ExtensionApis = *lpExtensionApis;
SavedMajorVersion = MajorVersion;
SavedMinorVersion = MinorVersion;
ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
OldExtensions = FALSE;
ExtensionsInitialized = TRUE;
fKD = 1;
return;
}
VOID
CheckVersion(
VOID
)
{
#if DBG
char Kind[] = "Checked";
#else
char Kind[] = "Free";
#endif
char *VersionKind = (SavedMajorVersion==0x0f) ? "Free" : "Checked";
if ( (SavedMajorVersion != 0x0c) || (SavedMinorVersion !=
VER_PRODUCTBUILD) )
{
dout << '\n';
dout << "*** Extension DLL(" << VER_PRODUCTBUILD << " " << Kind
<< ") does not match target system(" << SavedMinorVersion
<< " " << VersionKind << ") \n";
dout << '\n';
}
}
LPEXT_API_VERSION
ExtensionApiVersion(
VOID
)
{
return &ApiVersion;
}
} // extern "C"
ULONG
ReadProcessMemoryThunk(
ULONG_PTR offset,
PVOID lpBuffer,
ULONG cb,
PULONG lpcbBytesRead
)
{
SIZE_T RealBytesRead;
ULONG rc = ReadProcessMemory(hCurrentProcess, (PVOID)offset, lpBuffer, cb, &RealBytesRead);
*lpcbBytesRead = rc ? (ULONG)RealBytesRead : 0;
return rc;
}
ULONG
WriteProcessMemoryThunk(
ULONG_PTR offset,
LPVOID lpBuffer,
ULONG cb,
PULONG lpcbBytesWritten
)
{
SIZE_T RealBytesWritten;
ULONG rc = WriteProcessMemory(hCurrentProcess, (PVOID)offset, lpBuffer, cb, &RealBytesWritten);
*lpcbBytesWritten = rc ? (ULONG)RealBytesWritten : 0;
return rc;
}
typedef VOID (*PEXTENSION_API_ROUTINE)(VOID);
LPSTR lpArgumentString;
DWORD
ExtensionWrapRoutine(
IN LPVOID ExtensionRoutine
)
{
try
{
// Parse extension arguments.
ExtensionArgumentString = lpArgumentString;
ExtensionArgs.clear();
if ( lpArgumentString )
{
size_t c = strlen(lpArgumentString) + 1;
char *p = (char *)_alloca(c);
const char seps[] = " \t\n";
memcpy(p, lpArgumentString, c);
p = strtok(p, seps);
while ( p )
{
ExtensionArgs.push_back(string(p));
p = strtok(NULL, seps);
}
}
// Run the actual extension
(*((PEXTENSION_API_ROUTINE)ExtensionRoutine))();
}
catch ( exception & e )
{
dout << '\n';
dout << "An unexpected error occured.\n";
dout << e.what() << '\n';
}
return 0;
}
VOID
InitExtensionApi(IN HANDLE hCurrentProcess,
IN HANDLE hCurrentThread,
IN DWORD_PTR dwCurrentPc,
IN PWINDBG_EXTENSION_APIS lpExtensionsApis,
IN LPSTR lpArgumentString,
IN PEXTENSION_API_ROUTINE ExtensionRoutine
)
{
// Initialize global variables for extension
::hCurrentProcess = ProcessHandle = hCurrentProcess;
::hCurrentThread = hCurrentThread;
::dwCurrentPc = dwCurrentPc;
::lpArgumentString = lpArgumentString;
::fKD = 1;
//Windbg does not pass this, it uses WinDbgExtensionDllInit
if (!ExtensionsInitialized)
{
if ( OldExtensions )
{
memset(&ExtensionApis, 0, sizeof(ExtensionApis));
if ( sizeof(WINDBG_OLD_EXTENSION_APIS) == lpExtensionsApis->nSize )
{
memcpy(&ExtensionApis, lpExtensionsApis, lpExtensionsApis->nSize);
ExtensionApis.lpReadProcessMemoryRoutine = ReadProcessMemoryThunk;
ExtensionApis.lpWriteProcessMemoryRoutine = (PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE)WriteProcessMemoryThunk;
}
else if ( lpExtensionsApis->nSize >= sizeof(WINDBG_EXTENSION_APIS) )
{
memcpy(&ExtensionApis, lpExtensionsApis, sizeof(WINDBG_EXTENSION_APIS));
}
}
else
memcpy(&ExtensionApis, lpExtensionsApis, sizeof(WINDBG_EXTENSION_APIS));
}
::Myprintf = ExtensionApis.lpOutputRoutine;
ExtensionWrapRoutine(ExtensionRoutine);
}
#define DECLARE_EXTAPI_STUB(apiname) \
\
VOID \
do##apiname(VOID); \
\
extern "C" \
VOID \
apiname(IN HANDLE hCurrentProcess, \
IN HANDLE hCurrentThread, \
IN DWORD_PTR dwCurrentPc, \
IN PWINDBG_EXTENSION_APIS lpExtensionApis, \
IN LPSTR lpArgumentString \
) \
{ \
InitExtensionApi(hCurrentProcess, \
hCurrentThread, \
dwCurrentPc, \
lpExtensionApis, \
lpArgumentString, \
do##apiname); \
} \
#define DECLARE_EXTAPI(apiname) \
VOID \
do##apiname(VOID) \
// EXTENSION SETTINGS AND HELP
DECLARE_EXTAPI_STUB(help)
DECLARE_EXTAPI_STUB(version)
DECLARE_EXTAPI_STUB(settings)
// COMMON STRUCTURE PRINTERS
DECLARE_EXTAPI_STUB(cltinterface)
DECLARE_EXTAPI_STUB(rpcversion)
DECLARE_EXTAPI_STUB(syntaxid)
DECLARE_EXTAPI_STUB(srvinterface)
DECLARE_EXTAPI_STUB(stubdesc)
DECLARE_EXTAPI_STUB(stubmsg)
// FORMAT STRING PRINTERS
DECLARE_EXTAPI_STUB(procheader)
DECLARE_EXTAPI_STUB(procparamlist)
DECLARE_EXTAPI_STUB(proc)
DECLARE_EXTAPI_STUB(type)
DECLARE_EXTAPI_STUB(proxy)
DECLARE_EXTAPI_STUB(stub)
DECLARE_EXTAPI_STUB(proxyproc)
DECLARE_EXTAPI_STUB(stubproc)
// BUFFER PRINTERS
DECLARE_EXTAPI_STUB(procbuffer)
DECLARE_EXTAPI_STUB(typebuffer)
DECLARE_EXTAPI_STUB(pickleheader)
// MISC
DECLARE_EXTAPI_STUB(basicinfo)
// MISC TEST CODE
DECLARE_EXTAPI_STUB(testctrlc)
typedef VOID (*PSIMPLE_EXTAPI_ONE_NUMPARAM)(UINT64);
typedef VOID (*PPRINT_USAGE_ROUTINE)(VOID);
VOID ProcessSimpleExtapiOneNumParam(PSIMPLE_EXTAPI_ONE_NUMPARAM pDoRoutine,
PPRINT_USAGE_ROUTINE pHelpRoutine)
{
size_t size = ExtensionArgs.size();
if (size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0) {
(*pHelpRoutine)();
return;
}
if (size != 1) {
dout << "Incorrect syntax.\n";
(*pHelpRoutine)();
return;
}
UINT64 NumberParam = GetExpression(ExtensionArgs.at(0).c_str());
(*pDoRoutine)(NumberParam);
}
#define DECLARE_SIMPLE_EXAPI_ONE_NUMPARAM_STUB(apiname,helproutine) \
VOID do2##apiname(UINT64 Parameter); \
VOID \
do##apiname(VOID) \
{ \
ProcessSimpleExtapiOneNumParam(do2##apiname,helproutine); \
} \
VOID \
do2##apiname(UINT64 Parameter) \
VOID ParseBasicInfo(BASIC_INFO *BasicInfo)
{
if (_strcmpi(ExtensionArgs.at(0).c_str(), "stubmsg") == 0)
{
UINT64 StubMessageAddress = GetExpression(ExtensionArgs.at(1).c_str());
dout << "Detecting settings using MIDL_STUB_MESSAGE at " << HexOut(StubMessageAddress) << ".\n";
BasicInfo->GetInfoFromStubMessage(StubMessageAddress);
}
else if (_strcmpi(ExtensionArgs.at(0).c_str(), "rpcmsg") == 0)
{
UINT64 RpcMessageAddress = GetExpression(ExtensionArgs.at(1).c_str());
dout << "Detecting settings using RPC_MESSAGE at " << HexOut(RpcMessageAddress) << ".\n";
BasicInfo->GetInfoFromRpcMessage(RpcMessageAddress);
}
else
{
ABORT("Structure type must be stubmsg or rpcmsg!\n")
return;
}
}
DECLARE_EXTAPI(help)
{
dout <<
"NDREXTS: NDR DEBUGGER EXTENSIONS. \n"
" \n"
"EXTENSION SETTINGS AND HELP: \n"
"version Version information. \n"
"help This message. \n"
"settings Print extension settings. \n"
"settings <variable> <value> Set extension settings. \n"
" \n"
"COMMON STRUCTURE PRINTERS: \n"
"cltinterface <address> RPC_CLIENT_INTERFACE \n"
"rpcversion <address> RPC_VERSION \n"
"syntaxid <address> RPC_SYNTAX_IDENTIFIER \n"
"srvinterface <address> RPC_SERVER_INTERFACE \n"
"stubdesc <address> MIDL_STUB_DESC \n"
"stubmsg <address> MIDL_STUB_MESSAGE \n"
" \n"
"FORMAT STRING PRINTERS: \n"
"proc <procaddr> <typeaddr> Print the proc format. \n"
"proc (rpcmsg|stubmsg) <address> Print the proc format. \n"
"procheader <address> Print the proc header. \n"
"procheader (rpcmsg|stubmsg) <address> Print the proc header. \n"
"procparam <procaddr> <typeaddr> Print the param list. \n"
"proxy <ProxyAddr> Print OLE proxy information. \n"
"proxyproc <ProxyAddr> <ProcNum> Print specified proxy procedure info. \n"
"stub <StubAddr> Print OLE stub information. \n"
"stubproc <StubAddr> <ProcNum> Print specified stub procedure info. \n"
"type <address> Print the type string. \n"
" \n"
"BUFFER PRINTERS: \n"
"pickleheader <address> Print type or proc pickling header. \n"
"procbuffer <buf> <len> <proca> <typea> Print the proc marshling buffer. \n"
"procbuffer (rpcmsg|stubmsg) <addres> Print the proc marshling buffer. \n"
"typebuffer <buffer> <len> <typea> Print a single type from buffer. \n"
" \n"
"MISC: \n"
"basicinfo (rpcmsg|stubmsg) <address> Basic debugging info(use first). \n"
"Type commandname /? for more information. \n"
" \n"
;
}
DECLARE_EXTAPI(version)
{
#if DBG
PCHAR DebuggerType = "Checked";
#else
PCHAR DebuggerType = "Free";
#endif
if ( !OldExtensions )
{
PCHAR BuildKind = SavedMajorVersion == 0x0c ? "Checked" : "Free";
dout << DebuggerType << " NDR Extension dll for Build " << VER_PRODUCTBUILD
<< " debugging " << BuildKind << " Build " << SavedMinorVersion << '\n';
}
else
{
dout << DebuggerType << " NDR Extension dll for Build " << VER_PRODUCTBUILD
<< " debugging unknown Build \n";
}
}
//
// Settings management
//
void PrintSettingsUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.settings \n"
"!ndrexts.settings <variable> <value> \n"
" \n"
"The first form displays the current settings. The second form sets the given \n"
"setting to the given value. \n"
" \n"
"First form parameters: \n"
" None. \n"
" \n"
"Second form parameters: \n"
" variable: The name of the variable to set. \n"
" value: Value to set the variable to. \n"
" \n"
"The following variables are available: \n"
" StubMode: (OS | OI | OIC | OICF | OIF) \n"
" Sets the MIDL mode that the stub was generated in. \n"
" Direction: (IN | OUT) \n"
" Sets the type of parameters in the RPC buffer. \n"
" Pickling: (ON | OFF) \n"
" RPC buffer is a pickling buffer. \n"
" Robust: (ON | OFF) \n"
" Long correlation descriptors are used. This is a default only and \n"
" will be overridden if the extension can detect this. \n"
" \n"
" Verbosity: (LOW | MEDIUM | HIGH) \n"
" Level of detail for output. \n"
" \n";
}
VOID DisplaySettings()
{
dout << "Current NDREXTS settings:\n";
dout << "Verbosity: ";
switch ( VerbosityLevel )
{
case LOW:
dout << "LOW\n";
break;
case MEDIUM:
dout << "MEDIUM\n";
break;
case HIGH:
dout << "HIGH\n";
break;
default:
ABORT(" Corrupt verbosity level. \n" );
}
dout << "StubMode: ";
switch ( ContextStubMode )
{
case OS:
dout << "OS\n";
break;
case OI:
dout << "OI\n";
break;
case OIC:
dout << "OIC\n";
break;
case OICF:
dout << "OICF\n";
break;
case OIF:
dout << "OIF\n";
break;
default:
ABORT("Corrupt StubMode\n");
}
dout << "Direction: ";
switch ( ContextDirection )
{
case IN_BUFFER_MODE:
dout << "IN\n";
break;
case OUT_BUFFER_MODE:
dout << "OUT\n";
break;
default:
ABORT("Corrupt direction\n");
}
dout << "Pickling: " << ( ContextPickling ? "ON" : "OFF" ) << '\n';
dout << "Robust: " << ( ContextRobust ? "ON" : "OFF" ) << '\n';
dout << '\n';
}
VOID SetSetting(LPCSTR VariableName, LPCSTR Value )
{
if ( _strcmpi(VariableName, "Verbosity") == 0 )
{
LPCSTR Level = Value;
if ( _strcmpi( Level, "LOW" ) == 0 )
{
VerbosityLevel = LOW;
}
else if ( _strcmpi( Level, "MEDIUM" ) == 0 )
{
VerbosityLevel = MEDIUM;
}
else if ( _strcmpi( Level, "HIGH" ) == 0 )
{
VerbosityLevel = HIGH;
}
else
{
dout << Level << " is an invalid verbosity level.\n";
PrintSettingsUsage();
}
}
else if ( _strcmpi(VariableName, "StubMode") == 0 )
{
LPCSTR Mode = Value;
if ( _strcmpi(Mode, "OS") == 0 )
{
ContextStubMode = OS;
}
else if ( _strcmpi(Mode, "OI") == 0 )
{
ContextStubMode = OI;
}
else if ( _strcmpi(Mode, "OIC") == 0 )
{
ContextStubMode = OIC;
}
else if ( _strcmpi(Mode, "OICF") == 0 )
{
ContextStubMode= OICF;
}
else if ( _strcmpi(Mode, "OIF") == 0 )
{
ContextStubMode = OIF;
}
else
{
dout << Mode << " is an invalid StubMode.\n";
PrintSettingsUsage();
return;
}
}
else if ( _strcmpi(VariableName, "Direction") == 0 )
{
LPCSTR Direction = Value;
if ( _strcmpi(Direction, "IN") == 0 )
{
ContextDirection = IN_BUFFER_MODE;
}
else if ( _strcmpi(Direction, "OUT") == 0 )
{
ContextDirection = OUT_BUFFER_MODE;
}
else
{
dout << Direction << " is an invalid direction.\n";
PrintSettingsUsage();
return;
}
}
else if ( _strcmpi(VariableName, "Pickling") == 0 )
{
LPCSTR PicklingMode = Value;
if ( _stricmp(PicklingMode,"ON") == 0 )
{
ContextPickling = TRUE;
}
else if ( _stricmp(PicklingMode,"OFF") == 0 )
{
ContextPickling = FALSE;
}
else
{
dout << PicklingMode << " must be either ON or OFF.\n";
PrintSettingsUsage();
}
}
else if ( _strcmpi(VariableName, "Robust") == 0 )
{
LPCSTR RobustMode = Value;
if ( _stricmp(RobustMode,"ON") == 0 )
{
ContextRobust = TRUE;
}
else if ( _stricmp(RobustMode,"OFF") == 0 )
{
ContextRobust = FALSE;
}
else
{
dout << RobustMode << " must be either ON or OFF.\n";
PrintSettingsUsage();
}
}
else
{
dout << VariableName << " is an unknown variable name.\n";
PrintSettingsUsage();
return;
}
}
DECLARE_EXTAPI(settings)
{
size_t size = ExtensionArgs.size();
if ( size == 1 && (_strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0) )
{
PrintSettingsUsage();
}
else if ( size == 0 )
{
DisplaySettings();
}
else if ( size == 2 )
{
SetSetting( ExtensionArgs.at(0).c_str(), ExtensionArgs.at(1).c_str() );
}
else
{
dout << "Incorrect number of arguments!\n";
PrintSettingsUsage();
}
}
//
// Basic structure dumpers
//
#define DECLARE_SIMPLE_STRUCT_PRINTER(apiname,structtype) \
VOID Print##apiname##Usage(VOID) \
{ \
dout << \
"Syntax: \n" \
"!ndrexts." #apiname "<address> \n" \
" \n" \
"Prints a " #structtype " at address. \n" \
" \n" \
"Parameters: \n" \
" Address: address of " #structtype " to print. \n" \
"\n"; \
} \
\
VOID \
do2##apiname(UINT64 Address) \
{ \
dout << "Printing " #structtype " at " << HexOut(Address) << '\n'; \
structtype structdata; \
ReadMemory(Address, &structdata); \
IndentLevel l(dout); \
Print(dout, structdata, VerbosityLevel); \
dout << '\n'; \
} \
\
VOID \
do##apiname(VOID) \
{ \
ProcessSimpleExtapiOneNumParam(do2##apiname,Print##apiname##Usage);\
} \
\
DECLARE_SIMPLE_STRUCT_PRINTER(cltinterface,RPC_CLIENT_INTERFACE);
DECLARE_SIMPLE_STRUCT_PRINTER(rpcversion,RPC_VERSION);
DECLARE_SIMPLE_STRUCT_PRINTER(syntaxid,RPC_SYNTAX_IDENTIFIER);
DECLARE_SIMPLE_STRUCT_PRINTER(srvinterface,RPC_SERVER_INTERFACE);
DECLARE_SIMPLE_STRUCT_PRINTER(stubdesc,MIDL_STUB_DESC);
DECLARE_SIMPLE_STRUCT_PRINTER(stubmsg,MIDL_STUB_MESSAGE);
//
// Format string printing
//
void PrintProcHeaderUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.procheader <address> \n"
"!ndrexts.procheader (rpcmsg|stubmsg) <address> \n"
" \n"
"Prints the format string for the procedure header located at address. \n"
"The first form requires the address of the format string on the command line. \n"
"The second format requires the address of the stubmsg or rpcmsg and an \n"
"attempt is made to automatically detect the procedure header. \n"
" \n"
"First form parameters: \n"
" address: Address of the procedure header. \n"
" \n"
"Second form parameters: \n"
" (rpcmsg | stubmsg): Indicates if address is a stubmsg or rpcmsg. \n"
" address: Address of the structure used for detection. \n"
" \n"
"The following setting have an effect on this command: \n"
" \n"
" StubMode: MIDL mode used to compile the stub. \n"
" \n";
}
DECLARE_EXTAPI(procheader)
{
size_t size = ExtensionArgs.size();
UINT64 ProcFormat;
if ( size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0 )
{
PrintProcHeaderUsage();
return;
}
else if (size == 2)
{
BASIC_INFO BasicInfo;
try
{
ParseBasicInfo(&BasicInfo);
}
catch(exception e)
{
dout << e.what();
PrintProcHeaderUsage();
return;
}
if (!BasicInfo.ProcFormatAddressIsAvailable)
{
dout << "Unable to detect information!\n";
return;
}
ProcFormat = BasicInfo.ProcFormatAddress;
}
else if ( size == 1 )
{
ProcFormat = GetExpression(ExtensionArgs.at(0).c_str());
}
else
{
dout << "Incorrect syntax.\n";
PrintProcHeaderUsage();
return;
}
dout << "Using proc format string at " << HexOut(ProcFormat) << ":\n";
FORMAT_PRINTER FormatPrinter(dout);
FormatPrinter.PrintProcHeader(ProcFormat, ContextStubMode);
}
void PrintProcParamListUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.procparam <procaddress> <typeaddress> \n"
" \n"
"Prints the parameter list at procaddress. \n"
" \n"
"Parameters: \n"
" procaddress: Address of the parameter list. \n"
" typeaddress: Address of the type format array. \n"
" \n"
"The following setting have an effect on this command: \n"
" \n"
" StubMode: MIDL mode used to compile the stub. \n"
" \n";
}
DECLARE_EXTAPI(procparamlist)
{
size_t size = ExtensionArgs.size();
UINT64 ProcFormat, TypeFormat;
if ( size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0 )
{
PrintProcParamListUsage();
return;
}
if (size == 2)
{
ProcFormat = GetExpression(ExtensionArgs.at(0).c_str());
TypeFormat = GetExpression(ExtensionArgs.at(1).c_str());
}
else {
dout << "Incorrect syntax.\n";
PrintProcParamListUsage();
return;
}
dout << "Using proc format at " << HexOut(ProcFormat) << " and type format at "
<< HexOut(TypeFormat) << ":\n";
FORMAT_PRINTER FormatPrinter(dout);
FormatPrinter.PrintProcParamList(ProcFormat, TypeFormat, ContextStubMode);
}
void PrintProcUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.proc <procaddress> <tpeaddress> \n"
"!ndrexts.proc (rpcmsg|stubmsg) <address> \n"
" \n"
"Prints the format string for the procedure located at address. \n"
"The first form requires the address of the format strings on the command line.\n"
"The second format requires the address of the stubmsg or rpcmsg and an \n"
"attempt is made to automatically detect the proc format string and the type \n"
"format array. \n"
" \n"
"First form parameters: \n"
" procaddress: Address of the procedure format string. \n"
" typeaddress: Address of start of type format string array. \n"
" \n"
"Second form parameters: \n"
" (rpcmsg | stubmsg): Indicates if address is a stubmsg or rpcmsg. \n"
" address: Address of the structure used for detection. \n"
" \n"
"The following setting have an effect on this command: \n"
" \n"
" StubMode: MIDL mode used to compile the stub. \n"
" \n";
}
DECLARE_EXTAPI(proc)
{
size_t size = ExtensionArgs.size();
UINT64 ProcFormat, TypeFormat;
if ( size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0 )
{
PrintProcUsage();
return;
}
if (size == 2)
{
try
{
BASIC_INFO BasicInfo;
ParseBasicInfo(&BasicInfo);
if (!BasicInfo.ProcFormatAddressIsAvailable || !BasicInfo.StubDescIsAvailable)
{
dout << "Unable to detect information!\n";
return;
}
ProcFormat = BasicInfo.ProcFormatAddress;
TypeFormat = (UINT64)BasicInfo.StubDesc.pFormatTypes;
}
catch(...)
{
ProcFormat = GetExpression(ExtensionArgs.at(0).c_str());
TypeFormat = GetExpression(ExtensionArgs.at(1).c_str());
}
}
else {
dout << "Incorrect syntax.\n";
PrintProcUsage();
return;
}
dout << "Using proc format at " << HexOut(ProcFormat) << " and type format at "
<< HexOut(TypeFormat) << ":\n";
FORMAT_PRINTER FormatPrinter(dout);
FormatPrinter.PrintProc(ProcFormat, TypeFormat, ContextStubMode);
}
void PrintTypeUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.type <typeaddress> \n"
" \n"
"Prints the type format string at typeaddress. \n"
" \n"
"First form parameters: \n"
" typeaddres: Address of the type format string. \n"
" \n"
"The following setting have an effect on this command: \n"
" \n"
" Robust: ON if long correlation descriptors are used. \n"
" \n";
}
DECLARE_EXTAPI(type)
{
size_t size = ExtensionArgs.size();
if ( size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0 )
{
PrintTypeUsage();
return;
}
if ( size != 1 )
{
dout << "Incorrect syntax.\n";
PrintTypeUsage();
return;
}
UINT64 TypeFormat = GetExpression(ExtensionArgs.at(0).c_str());
FORMAT_PRINTER FormatPrinter(dout);
dout << "Using type format string at " << HexOut(TypeFormat) << ":\n";
FormatPrinter.PrintTypeFormat(TypeFormat, ContextRobust);
}
//
// Buffer printing
//
void PrintProcBufferUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.procbuffer <buffer> <len> <procaddr> <typeaddr> \n"
"!ndrexts.procbuffer (rpcmsg|stubmsg) address \n"
" \n"
"Pretty prints a RPC buffer for a procedure call. If the second form is used, \n"
"the format strings and buffer settings are detected from the rpcmsg or stubmsg.\n"
" \n"
"Parameters: \n"
" buffer: address of the RPC buffer \n"
" len: length of the RPC buffer \n"
" procaddr: address of the procedure format string. \n"
" typeaddr: address of the start of type format string table. \n"
" \n"
"Second form parameters: \n"
" (rpcmsg | stubmsg): Indicates if address is a stubmsg or rpcmsg. \n"
" address: Address of the structure used for detection. \n"
" \n"
"The following setting have an effect on this command: \n"
" \n"
" StubMode: MIDL mode used to compile the stub. \n"
" Direction: Determines if the buffer contains IN or OUT parameters. \n"
" Pickling: ON if buffer is a procedure pickling buffer. \n"
" \n";
}
DECLARE_EXTAPI(procbuffer)
{
size_t size = ExtensionArgs.size();
UINT64 BufferAddress;
ULONG BufferLength;
UINT64 ProcAddress;
UINT64 TypeAddress;
if ( size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0 )
{
PrintProcBufferUsage();
return;
}
if ( size == 2 )
{
BASIC_INFO BasicInfo;
try
{
ParseBasicInfo(&BasicInfo);
}
catch(exception e)
{
dout << e.what();
PrintProcBufferUsage();
return;
}
if (!BasicInfo.RpcMessageIsAvailable || !BasicInfo.StubDescIsAvailable
|| !BasicInfo.ProcFormatAddressIsAvailable)
{
dout << "Unable to get settings.\n\n";
return;
}
BufferAddress = (UINT64)BasicInfo.RpcMessage.Buffer;
BufferLength = BasicInfo.RpcMessage.BufferLength;
ProcAddress = BasicInfo.ProcFormatAddress;
TypeAddress = (UINT64)BasicInfo.StubDesc.pFormatTypes;
}
else if (4 == size)
{
BufferAddress = GetExpression(ExtensionArgs.at(0).c_str());
BufferLength = GetExpression(ExtensionArgs.at(1).c_str());
ProcAddress = GetExpression(ExtensionArgs.at(2).c_str());
TypeAddress = GetExpression(ExtensionArgs.at(3).c_str());
}
else
{
dout << "Incorrect syntax.\n";
PrintProcBufferUsage();
return;
}
BUFFER_PRINTER BufferPrinter( dout, BufferAddress, BufferLength,
ProcAddress, TypeAddress );
dout << "Printing proc buffer.\n";
dout << "Buffer address: " << HexOut(BufferAddress) << ".\n";
dout << "Buffer length: " << HexOut(BufferLength) << ".\n";
dout << "Procedure format string: " << HexOut(ProcAddress) << ".\n";
dout << "Type format table: " << HexOut(TypeAddress) << ".\n";
dout << '\n';
BufferPrinter.OutputBuffer(ContextStubMode,ContextDirection, ContextPickling);
}
VOID PrintTypeBufferUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.typebuffer <buffer> <len> <typeaddr> \n"
" \n"
"Pretty prints a since type from an RPC buffer. \n"
" \n"
"Parameters: \n"
" buffer: address of the start of the type in the RPC buffer. \n"
" len: remaining length of the RPC buffer \n"
" typeaddr: address of type format string for this type. \n"
" \n"
" \n"
"The following setting have an effect on this command: \n"
" \n"
" Pickling: ON if buffer is a type pickling buffer. \n"
" Robust: ON if long correlation descriptors are used. \n"
" \n";
}
DECLARE_EXTAPI(typebuffer)
{
size_t size = ExtensionArgs.size();
if ( size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0 )
{
PrintProcBufferUsage();
return;
}
if (size == 3)
{
UINT64 BufferAddress = GetExpression(ExtensionArgs.at(0).c_str());
ULONG BufferLength = GetExpression(ExtensionArgs.at(1).c_str());
UINT64 TypeAddress = GetExpression(ExtensionArgs.at(2).c_str());
BUFFER_PRINTER BufferPrinter( dout, BufferAddress, BufferLength,
TypeAddress, TypeAddress );
dout << "Printing type buffer.\n";
dout << "Buffer address: " << HexOut(BufferAddress) << ".\n";
dout << "Buffer length: " << HexOut(BufferLength) << ".\n";
dout << "Type format string: " << HexOut(TypeAddress) << ".\n";
dout << '\n';
BufferPrinter.OutputTypeBuffer(ContextPickling, ContextRobust);
}
else
{
dout << "Incorrect syntax!\n";
PrintTypeBufferUsage();
return;
}
}
VOID PrintPickleHeaderUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.pickleheader <address> \n"
" \n"
"Prints the pickling header at address. Detects type or proc header. \n"
" \n"
"Parameters: \n"
" Address: Address of the type or procedure pickling header. \n"
" \n";
}
DECLARE_SIMPLE_EXAPI_ONE_NUMPARAM_STUB(pickleheader,PrintPickleHeaderUsage)
{
UINT64 Address = Parameter;
TYPE_PICKLING_HEADER TypeHeader;
PROC_PICKLING_HEADER ProcHeader;
ReadMemory(Address, &TypeHeader);
// MS proc headers always have a (short)0xcccc filler where the type header size is.
// MS type headers always have 8 for the size.
if ((USHORT)0xCCCC == TypeHeader.HeaderSize)
{
dout << "Printing proc pickling header at " << HexOut(Address) << ".\n";
ReadMemory(Address, &ProcHeader);
IndentLevel l(dout);
Print(dout, ProcHeader, VerbosityLevel);
return;
}
if (sizeof(TypeHeader) == TypeHeader.HeaderSize)
{
dout << "Printing type pickling header at " << HexOut(Address) << ".\n";
}
else
{
dout << "Unsure what type of header this is. Printing as a type header.\n";
dout << "Address: " << HexOut(Address) << ".\n";
}
IndentLevel l(dout);
Print(dout, TypeHeader, VerbosityLevel);
dout << '\n';
}
void PrintProxyUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.proxy <address> \n"
" \n"
"Prints information about DCOM proxy located at address. \n"
" \n"
"Parameters: \n"
" Address: This pointer for the proxy. \n"
" \n";
}
DECLARE_EXTAPI(proxy)
{
size_t size = ExtensionArgs.size();
if (size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0) {
PrintProxyUsage();
}
if (size != 1) {
Myprintf("Incorrect syntax.\n");
PrintProxyUsage();
return;
}
ULONG_PTR pAddr = GetExpression(ExtensionArgs.at(0).c_str());
CNDRPROXY Proxy(pAddr,dout);
Proxy.InitIfNecessary();
Proxy.PrintProxy();
}
void PrintStubUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.stub <address> \n"
" \n"
"Prints information about DCOM proxy located at address. \n"
" \n"
"Parameters: \n"
" Address: Address of the stub. \n"
" \n";
}
DECLARE_EXTAPI(stub)
{
size_t size = ExtensionArgs.size();
if (size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0) {
PrintStubUsage();
}
if (size != 1) {
Myprintf("Incorrect syntax.\n");
PrintStubUsage();
}
ULONG_PTR pAddr = GetExpression(ExtensionArgs.at(0).c_str());
CNDRSTUB Stub(pAddr, dout);
Stub.PrintStub();
}
void PrintProxyProcUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.proxyproc <address> <ProcNum> \n"
" \n"
"Prints the format string for the proc in the proxy. \n"
" \n"
"Parameters: \n"
" Address: Address of proxy. \n"
" ProcNum: Proc number to dump information for. \n"
" \n";
}
DECLARE_EXTAPI(proxyproc)
{
size_t size = ExtensionArgs.size();
if (size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0) {
PrintProxyProcUsage();
}
if (size != 2) {
dout << "Incorrect syntax.\n";
PrintProxyProcUsage();
}
ULONG_PTR pAddr = GetExpression(ExtensionArgs.at(0).c_str());
ULONG_PTR nProcNum = GetExpression(ExtensionArgs.at(1).c_str());
CNDRPROXY Proxy(pAddr,dout);
Proxy.PrintProc(nProcNum);
return;
}
void PrintStubProcUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.stubproc <address> <ProcNum> \n"
" \n"
"Prints the format string for the stub in the proxy. \n"
" \n"
"Parameters: \n"
" Address: Address of stub. \n"
" ProcNum: Proc number to dump information for. \n"
" \n";
}
DECLARE_EXTAPI(stubproc)
{
size_t size = ExtensionArgs.size();
if (size == 1 && _strcmpi(ExtensionArgs.at(0).c_str(), "/?") == 0) {
PrintStubProcUsage();
}
if (size != 2) {
dout << "Incorrect syntax.\n";
PrintStubProcUsage();
}
ULONG_PTR pAddr = GetExpression(ExtensionArgs.at(0).c_str());
ULONG_PTR nProcNum = GetExpression(ExtensionArgs.at(1).c_str());
CNDRSTUB Stub(pAddr,dout);
Stub.PrintProc(nProcNum);
return;
}
//
// Misc
//
VOID PrintBasicInfoUsage()
{
dout <<
"Syntax: \n"
"!ndrexts.basicinfo (rpcmsg|stubmsg) <address> \n"
" \n"
"Prints basic debugging information about the current call. \n"
"Try this first when debugging a problem. \n"
" \n"
"Parameters: \n"
" Address: Address of the RPC_MESSAGE or MIDL_STUB_MESSAGE. \n"
" \n";
}
DECLARE_EXTAPI(basicinfo)
{
size_t size = ExtensionArgs.size();
if ((1 == size) && (_strcmpi(ExtensionArgs.at(0).c_str(), "/?")==0) )
{
PrintBasicInfoUsage();
return;
}
if ( size != 2 )
{
dout << "Wrong number of arguments!\n";
PrintBasicInfoUsage();
return;
}
BASIC_INFO BasicInfo;
try
{
ParseBasicInfo(&BasicInfo);
}
catch(exception e)
{
dout << e.what();
PrintBasicInfoUsage();
}
BasicInfo.PrintInfo(dout);
}
DECLARE_EXTAPI(testctrlc)
{
ULONG i = 0;
while(1)
{
dout << "This is my test " << i++ << ".\n";
}
}
//
// C entry points
//
ULONG NoopCheckCtrlC() {
return 0;
}
void NonNtsdInit()
{
CHAR szBuffer[10]; // long enough to hold low/medium/high
DWORD len;
fKD = 0;
hCurrentProcess = ProcessHandle = GetCurrentProcess();
Myprintf = (PWINDBG_OUTPUT_ROUTINE)printf;
memset(&ExtensionApis,0,sizeof(WINDBG_EXTENSION_APIS) );
ExtensionApis.nSize = sizeof(WINDBG_EXTENSION_APIS);
ExtensionApis.lpReadProcessMemoryRoutine = (PWINDBG_READ_PROCESS_MEMORY_ROUTINE)ReadProcessMemoryThunk;
ExtensionApis.lpOutputRoutine = (PWINDBG_OUTPUT_ROUTINE)printf;
ExtensionApis.lpCheckControlCRoutine = (PWINDBG_CHECK_CONTROL_C)NoopCheckCtrlC;
len = GetEnvironmentVariable("NDR_VERBOSE",(LPTSTR)szBuffer,10);
// invalid value, assuming endium
if (len == 0 || len > 10 )
{
VerbosityLevel = MEDIUM;
}
else
{
if ( _strcmpi( szBuffer, "LOW" ) == 0 )
{
VerbosityLevel = LOW;
}
else if ( _strcmpi( szBuffer, "MEDIUM" ) == 0 )
{
VerbosityLevel = MEDIUM;
}
else if ( _strcmpi( szBuffer, "HIGH" ) == 0 )
{
VerbosityLevel = HIGH;
}
}
}
class STDOUT_STREAM_BUFFER : public FORMATTED_STREAM_BUFFER
{
protected:
virtual void SystemOutput(const char *p);
virtual BOOL SystemPollCtrlC();
} StdoutFormattedStream;; // Stream to output to stdout.
void STDOUT_STREAM_BUFFER::SystemOutput(const char *p)
{
printf(p);
}
BOOL STDOUT_STREAM_BUFFER::SystemPollCtrlC()
{
return FALSE;
}
FORMATTED_STREAM_BUFFER & conout = StdoutFormattedStream;
#define BEGIN_C_ENTRY \
NonNtsdInit(); \
try { \
#define END_C_ENTRY \
} \
catch ( exception & e ) \
{ \
conout << '\n'; \
conout << "An unexpected error occurred.\n"; \
conout << e.what() << '\n'; \
} \
EXTERN_C void STDAPICALLTYPE
NdrpDumpProxy(
IN LPVOID pAddr)
{
BEGIN_C_ENTRY;
CNDRPROXY Proxy((ULONG_PTR)pAddr,conout);
Proxy.PrintProxy();
END_C_ENTRY;
}
EXTERN_C void STDAPICALLTYPE
NdrpDumpProxyProc(
IN LPVOID pAddr,
IN ULONG_PTR nProcNum)
{
BEGIN_C_ENTRY;
CNDRPROXY Proxy((ULONG_PTR)pAddr, conout);
Proxy.PrintProc(nProcNum);
END_C_ENTRY;
}
EXTERN_C void STDAPICALLTYPE
NdrpDumpStub(
IN LPVOID pAddr)
{
BEGIN_C_ENTRY;
long nCount = 0;
CNDRSTUB Stub((ULONG_PTR)pAddr,conout);
if (HIGHVERBOSE)
Stub.PrintStub();
nCount = Stub.GetDispatchCount();
// I don't care about IUnknown methods. Don't care about IDispatch for now
for (int i = 3; i < nCount; i++)
Stub.PrintProc(i);
END_C_ENTRY;
}
EXTERN_C void STDAPICALLTYPE
NdrpDumpStubProc(
IN LPVOID pAddr,
IN ULONG_PTR nProcNum)
{
BEGIN_C_ENTRY;
CNDRSTUB Stub((ULONG_PTR)pAddr,conout);
Stub.PrintProc(nProcNum);
END_C_ENTRY;
}