1498 lines
46 KiB
C++
1498 lines
46 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
scexts.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This function contains the eventlog ntsd debugger extensions
|
|||
|
|
|||
|
Each DLL entry point is called with a handle to the process being
|
|||
|
debugged, as well as pointers to functions.
|
|||
|
|
|||
|
This process cannot just _read data in the process being debugged.
|
|||
|
Therefore, some macros are defined that will copy data from
|
|||
|
the debuggee process into a location in this processes memory.
|
|||
|
The GET_DATA and GET_STRING macros (defined in this file) are used
|
|||
|
to _read memory in the process being debugged. The DebuggeeAddr is the
|
|||
|
address of the memory in the debuggee process. The LocalAddr is the
|
|||
|
address of memory in the debugger (this programs context) that data is
|
|||
|
to be copied into. Length describes the number of bytes to be copied.
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Dan Lafferty (DanL) 12-Aug-1993
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <windows.h>
|
|||
|
#include <ntsdexts.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#include <malloc.h>
|
|||
|
#include <time.h>
|
|||
|
#include <winsvc.h>
|
|||
|
#include <dataman.h>
|
|||
|
#include <tstr.h>
|
|||
|
|
|||
|
//#define DbgPrint(_x_) (lpOutputRoutine) _x_
|
|||
|
#define DbgPrint(_x_)
|
|||
|
#define MAX_NAME 256
|
|||
|
#define printf (lpOutputRoutine)
|
|||
|
|
|||
|
#define GET_DATA(DebugeeAddr, LocalAddr, Length) \
|
|||
|
Status = ReadProcessMemory( \
|
|||
|
GlobalhCurrentProcess, \
|
|||
|
(LPVOID)DebugeeAddr, \
|
|||
|
LocalAddr, \
|
|||
|
Length, \
|
|||
|
NULL \
|
|||
|
);
|
|||
|
//
|
|||
|
// This macro copies a string from the debuggee
|
|||
|
// process, one character at a time into this
|
|||
|
// process's address space.
|
|||
|
//
|
|||
|
// CODEWORK: This macro should check the length
|
|||
|
// to make sure we don't overflow the LocalAddr
|
|||
|
// buffer. Perhaps this should be a function
|
|||
|
// rather than a macro.
|
|||
|
//
|
|||
|
#define GET_STRING(DebugeeAddr, LocalAddr, Length) \
|
|||
|
\
|
|||
|
{ \
|
|||
|
WCHAR UnicodeChar; \
|
|||
|
LPWSTR pDest; \
|
|||
|
LPWSTR pSource; \
|
|||
|
pDest = LocalAddr; \
|
|||
|
pSource = DebugeeAddr; \
|
|||
|
do { \
|
|||
|
\
|
|||
|
Status = ReadProcessMemory( \
|
|||
|
GlobalhCurrentProcess, \
|
|||
|
(LPVOID)pSource, \
|
|||
|
&UnicodeChar, \
|
|||
|
sizeof(WCHAR), \
|
|||
|
NULL \
|
|||
|
); \
|
|||
|
\
|
|||
|
*pDest = UnicodeChar; \
|
|||
|
pDest++; \
|
|||
|
pSource++; \
|
|||
|
} while (UnicodeChar != L'\0');}
|
|||
|
|
|||
|
//=======================
|
|||
|
// Function Prototypes
|
|||
|
//=======================
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
|
|||
|
VOID
|
|||
|
BackDepend(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
DumpFwdDependentNames(
|
|||
|
LPSERVICE_RECORD pServiceRecord
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
DumpBkwdDependentNames(
|
|||
|
LPSERVICE_RECORD pServiceRecord
|
|||
|
);
|
|||
|
|
|||
|
LPIMAGE_RECORD
|
|||
|
DumpImageRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
LPIMAGE_RECORD pImageRecord,
|
|||
|
LPDWORD NumBytes, // number of bytes in GroupRecord.
|
|||
|
BOOL JustSizeInfo
|
|||
|
);
|
|||
|
|
|||
|
LPLOAD_ORDER_GROUP
|
|||
|
DumpGroupRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
LPLOAD_ORDER_GROUP pGroupRecord,
|
|||
|
LPDWORD NumBytes, // number of bytes in GroupRecord.
|
|||
|
BOOL JustSizeInfo
|
|||
|
);
|
|||
|
|
|||
|
LPSERVICE_RECORD
|
|||
|
DumpServiceRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
LPSERVICE_RECORD pServiceRecord,
|
|||
|
LPDWORD NumBytes, // number of bytes in ServiceRecord.
|
|||
|
LPDWORD NumDependBytes, // number of bytes in DependRecords.
|
|||
|
BOOL JustSizeInfo
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
FindServiceRecordByName(
|
|||
|
LPSTR ServiceName,
|
|||
|
LPSERVICE_RECORD *pServiceRecord
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
GetDependTreeSize(
|
|||
|
LPSERVICE_RECORD pServiceRecord,
|
|||
|
LPDWORD pNumDependStructs,
|
|||
|
LPDWORD pNumBytes,
|
|||
|
BOOL StartDepend
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
ConvertToUnicode(
|
|||
|
OUT LPWSTR *UnicodeOut,
|
|||
|
IN LPSTR AnsiIn
|
|||
|
);
|
|||
|
|
|||
|
HANDLE GlobalhCurrentProcess;
|
|||
|
BOOL Status;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the global function pointers
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
InitFunctionPointers(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis
|
|||
|
)
|
|||
|
{
|
|||
|
//
|
|||
|
// Load these to speed access if we haven't already
|
|||
|
//
|
|||
|
|
|||
|
if (!lpOutputRoutine) {
|
|||
|
lpOutputRoutine = lpExtensionApis->lpOutputRoutine;
|
|||
|
lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
|
|||
|
lpCheckControlCRoutine = lpExtensionApis->lpCheckControlCRoutine;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Stick this in a global
|
|||
|
//
|
|||
|
|
|||
|
GlobalhCurrentProcess = hCurrentProcess;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ServiceRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
Dump Service Records.
|
|||
|
|
|||
|
Arguments:
|
|||
|
hCurrentProcess - Handle for the process being debugged.
|
|||
|
|
|||
|
hCurrentThread - Handle for the thread that has the debugger focus.
|
|||
|
|
|||
|
dwCurrentPc - Current Program Counter?
|
|||
|
|
|||
|
lpExtensionApis - Pointer to a structure that contains pointers to
|
|||
|
various routines. (see \nt\public\sdk\inc\ntsdexts.h)
|
|||
|
typedef struct _NTSD_EXTENSION_APIS {
|
|||
|
DWORD nSize;
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_GET_SYMBOL lpGetSymbolRoutine;
|
|||
|
PNTSD_DISASM lpDisasmRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
} NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
|
|||
|
|
|||
|
lpArgumentString - This is a pointer to a string that contains
|
|||
|
space seperated arguments that are passed to debugger
|
|||
|
extension function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD pDatabaseAnchor;
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
LPSERVICE_RECORD pServiceRecord;
|
|||
|
DWORD numBytes=0;
|
|||
|
DWORD numDependBytes=0;
|
|||
|
DWORD numEntries=0;
|
|||
|
LPSTR pToken;
|
|||
|
|
|||
|
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
|
|||
|
|
|||
|
printf("ArgumentString = %s\n\n",lpArgumentString);
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the top of the Service Database.
|
|||
|
//
|
|||
|
pDatabaseAnchor = (lpGetExpressionRoutine)("ServiceDatabase");
|
|||
|
|
|||
|
//
|
|||
|
// Get the first service record.
|
|||
|
// This is a dummy record that points to the first real record.
|
|||
|
//
|
|||
|
GET_DATA(pDatabaseAnchor, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
pServiceRecord = ServiceRecord.Next;
|
|||
|
|
|||
|
if (_strnicmp(lpArgumentString, "mem", 3) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Dump Memory Usage only.
|
|||
|
//--------------------------------------
|
|||
|
do {
|
|||
|
pServiceRecord = DumpServiceRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pServiceRecord,
|
|||
|
&numBytes,
|
|||
|
&numDependBytes,
|
|||
|
TRUE);
|
|||
|
numEntries++;
|
|||
|
} while (pServiceRecord != NULL);
|
|||
|
printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
|
|||
|
printf("NumEntries = %d\n",numEntries);
|
|||
|
}
|
|||
|
|
|||
|
else if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Find a particular Service Record
|
|||
|
// based on Name.
|
|||
|
//--------------------------------------
|
|||
|
pToken = strtok(lpArgumentString+6," ,\t\n");
|
|||
|
if (pToken == NULL) {
|
|||
|
printf("A Name was not given\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
if (FindServiceRecordByName(pToken, &pServiceRecord)) {
|
|||
|
pServiceRecord = DumpServiceRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pServiceRecord,
|
|||
|
&numBytes,
|
|||
|
&numDependBytes,
|
|||
|
FALSE);
|
|||
|
printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
|
|||
|
printf("NumEntries = %d\n",1);
|
|||
|
}
|
|||
|
else {
|
|||
|
printf("No service record found for \"%s\"\n", pToken);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (_strnicmp(lpArgumentString, "address=", 8) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Find a particular Service Record
|
|||
|
// based on Address.
|
|||
|
//--------------------------------------
|
|||
|
pToken = strtok(lpArgumentString+9," ,\t\n");
|
|||
|
if (pToken == NULL) {
|
|||
|
printf("An Address was not given\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
LPSERVICE_RECORD ServiceAddress;
|
|||
|
LPSTR pMore;
|
|||
|
|
|||
|
ServiceAddress = (LPSERVICE_RECORD)strtoul(pToken, &pMore, 16);
|
|||
|
printf("pToken = %s\n",pToken);
|
|||
|
printf("strtoul on Service Address yields %d(decimal) %x(hex)\n",
|
|||
|
ServiceAddress, ServiceAddress);
|
|||
|
|
|||
|
pServiceRecord = DumpServiceRecord(
|
|||
|
hCurrentProcess,
|
|||
|
ServiceAddress,
|
|||
|
&numBytes,
|
|||
|
&numDependBytes,
|
|||
|
FALSE);
|
|||
|
|
|||
|
printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
|
|||
|
printf("NumEntries = %d\n",1);
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
//--------------------------------------
|
|||
|
// Dump All Service Records.
|
|||
|
//--------------------------------------
|
|||
|
do {
|
|||
|
pServiceRecord = DumpServiceRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pServiceRecord,
|
|||
|
&numBytes,
|
|||
|
&numDependBytes,
|
|||
|
FALSE);
|
|||
|
numEntries++;
|
|||
|
} while (pServiceRecord != NULL);
|
|||
|
printf("NumSRBytes = %d NumDependBytes = %d\n",numBytes,numDependBytes);
|
|||
|
printf("NumEntries = %d\n",numEntries);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
Dependencies(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
Dump Service Record Dependencies.
|
|||
|
|
|||
|
Arguments:
|
|||
|
hCurrentProcess - Handle for the process being debugged.
|
|||
|
|
|||
|
hCurrentThread - Handle for the thread that has the debugger focus.
|
|||
|
|
|||
|
dwCurrentPc - Current Program Counter?
|
|||
|
|
|||
|
lpExtensionApis - Pointer to a structure that contains pointers to
|
|||
|
various routines. (see \nt\public\sdk\inc\ntsdexts.h)
|
|||
|
typedef struct _NTSD_EXTENSION_APIS {
|
|||
|
DWORD nSize;
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_GET_SYMBOL lpGetSymbolRoutine;
|
|||
|
PNTSD_DISASM lpDisasmRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
} NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
|
|||
|
|
|||
|
lpArgumentString - This is a pointer to a string that contains
|
|||
|
space seperated arguments that are passed to debugger
|
|||
|
extension function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD pDatabaseAnchor;
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
LPSERVICE_RECORD pServiceRecord;
|
|||
|
DWORD numBytes=0;
|
|||
|
DWORD numEntries=0;
|
|||
|
LPSTR pToken;
|
|||
|
|
|||
|
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
|
|||
|
|
|||
|
printf("ArgumentString = %s\n\n",lpArgumentString);
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the top of the Service Database.
|
|||
|
//
|
|||
|
pDatabaseAnchor = (lpGetExpressionRoutine)("ServiceDatabase");
|
|||
|
|
|||
|
//
|
|||
|
// Get the first service record.
|
|||
|
// This is a dummy record that points to the first real record.
|
|||
|
//
|
|||
|
GET_DATA(pDatabaseAnchor, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
pServiceRecord = ServiceRecord.Next;
|
|||
|
|
|||
|
if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Find a particular Service Record
|
|||
|
// based on Name.
|
|||
|
//--------------------------------------
|
|||
|
pToken = strtok(lpArgumentString+6," ,\t\n");
|
|||
|
if (pToken == NULL) {
|
|||
|
printf("A Name was not given\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
if (FindServiceRecordByName(pToken, &pServiceRecord)) {
|
|||
|
DumpFwdDependentNames(pServiceRecord);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (_strnicmp(lpArgumentString, "address=", 8) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Find a particular Service Record
|
|||
|
// based on Address.
|
|||
|
//--------------------------------------
|
|||
|
pToken = strtok(lpArgumentString+9," ,\t\n");
|
|||
|
if (pToken == NULL) {
|
|||
|
printf("An Address was not given\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
LPSERVICE_RECORD ServiceAddress;
|
|||
|
LPSTR pMore;
|
|||
|
|
|||
|
ServiceAddress = (LPSERVICE_RECORD)strtoul(pToken, &pMore, 16);
|
|||
|
printf("pToken = %s\n",pToken);
|
|||
|
printf("strtoul on Service Address yields %d(decimal) %x(hex)\n",
|
|||
|
ServiceAddress, ServiceAddress);
|
|||
|
|
|||
|
DumpFwdDependentNames(ServiceAddress);
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BackDepend(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
Dump Service Record Dependencies.
|
|||
|
|
|||
|
Arguments:
|
|||
|
hCurrentProcess - Handle for the process being debugged.
|
|||
|
|
|||
|
hCurrentThread - Handle for the thread that has the debugger focus.
|
|||
|
|
|||
|
dwCurrentPc - Current Program Counter?
|
|||
|
|
|||
|
lpExtensionApis - Pointer to a structure that contains pointers to
|
|||
|
various routines. (see \nt\public\sdk\inc\ntsdexts.h)
|
|||
|
typedef struct _NTSD_EXTENSION_APIS {
|
|||
|
DWORD nSize;
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_GET_SYMBOL lpGetSymbolRoutine;
|
|||
|
PNTSD_DISASM lpDisasmRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
} NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
|
|||
|
|
|||
|
lpArgumentString - This is a pointer to a string that contains
|
|||
|
space seperated arguments that are passed to debugger
|
|||
|
extension function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD pDatabaseAnchor;
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
LPSERVICE_RECORD pServiceRecord;
|
|||
|
DWORD numBytes=0;
|
|||
|
DWORD numEntries=0;
|
|||
|
LPSTR pToken;
|
|||
|
|
|||
|
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
|
|||
|
|
|||
|
printf("ArgumentString = %s\n\n",lpArgumentString);
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the top of the Service Database.
|
|||
|
//
|
|||
|
pDatabaseAnchor = (lpGetExpressionRoutine)("ServiceDatabase");
|
|||
|
|
|||
|
//
|
|||
|
// Get the first service record.
|
|||
|
// This is a dummy record that points to the first real record.
|
|||
|
//
|
|||
|
GET_DATA(pDatabaseAnchor, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
pServiceRecord = ServiceRecord.Next;
|
|||
|
|
|||
|
if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Find a particular Service Record
|
|||
|
// based on Name.
|
|||
|
//--------------------------------------
|
|||
|
pToken = strtok(lpArgumentString+6," ,\t\n");
|
|||
|
if (pToken == NULL) {
|
|||
|
printf("A Name was not given\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
if (FindServiceRecordByName(pToken, &pServiceRecord)) {
|
|||
|
printf("Backwards dependencies:\n");
|
|||
|
DumpBkwdDependentNames(pServiceRecord);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (_strnicmp(lpArgumentString, "address=", 8) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Find a particular Service Record
|
|||
|
// based on Address.
|
|||
|
//--------------------------------------
|
|||
|
pToken = strtok(lpArgumentString+9," ,\t\n");
|
|||
|
if (pToken == NULL) {
|
|||
|
printf("An Address was not given\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
LPSERVICE_RECORD ServiceAddress;
|
|||
|
LPSTR pMore;
|
|||
|
|
|||
|
ServiceAddress = (LPSERVICE_RECORD)strtoul(pToken, &pMore, 16);
|
|||
|
printf("pToken = %s\n",pToken);
|
|||
|
printf("strtoul on Service Address yields %d(decimal) %x(hex)\n",
|
|||
|
ServiceAddress, ServiceAddress);
|
|||
|
|
|||
|
DumpBkwdDependentNames(ServiceAddress);
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ImageRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
Dump ImageRecords.
|
|||
|
|
|||
|
Arguments:
|
|||
|
hCurrentProcess - Handle for the process being debugged.
|
|||
|
|
|||
|
hCurrentThread - Handle for the thread that has the debugger focus.
|
|||
|
|
|||
|
dwCurrentPc - Current Program Counter?
|
|||
|
|
|||
|
lpExtensionApis - Pointer to a structure that contains pointers to
|
|||
|
various routines. (see \nt\public\sdk\inc\ntsdexts.h)
|
|||
|
typedef struct _NTSD_EXTENSION_APIS {
|
|||
|
DWORD nSize;
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_GET_SYMBOL lpGetSymbolRoutine;
|
|||
|
PNTSD_DISASM lpDisasmRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
} NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
|
|||
|
|
|||
|
lpArgumentString - This is a pointer to a string that contains
|
|||
|
space seperated arguments that are passed to debugger
|
|||
|
extension function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD pDatabaseAnchor;
|
|||
|
IMAGE_RECORD ImageRecord;
|
|||
|
LPIMAGE_RECORD pImageRecord;
|
|||
|
DWORD numBytes=0;
|
|||
|
DWORD numEntries=0;
|
|||
|
|
|||
|
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
|
|||
|
|
|||
|
printf("ArgumentString = %s\n\n",lpArgumentString);
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the top of the Service Database.
|
|||
|
//
|
|||
|
pDatabaseAnchor = (lpGetExpressionRoutine)("ImageDatabase");
|
|||
|
|
|||
|
//
|
|||
|
// Get the first service record.
|
|||
|
// This is a dummy record that points to the first real record.
|
|||
|
//
|
|||
|
GET_DATA(pDatabaseAnchor, &ImageRecord, sizeof(ImageRecord))
|
|||
|
pImageRecord = ImageRecord.Next;
|
|||
|
|
|||
|
if (_strnicmp(lpArgumentString, "mem", 3) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Dump Memory Usage only.
|
|||
|
//--------------------------------------
|
|||
|
do {
|
|||
|
pImageRecord = DumpImageRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pImageRecord,
|
|||
|
&numBytes,
|
|||
|
TRUE);
|
|||
|
numEntries++;
|
|||
|
} while (pImageRecord != NULL);
|
|||
|
printf("NumIRBytes = %d\n",numBytes);
|
|||
|
printf("NumEntries = %d\n",numEntries);
|
|||
|
}
|
|||
|
|
|||
|
else if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
//--------------------------------------
|
|||
|
// Dump All Image Records.
|
|||
|
//--------------------------------------
|
|||
|
do {
|
|||
|
pImageRecord = DumpImageRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pImageRecord,
|
|||
|
&numBytes,
|
|||
|
FALSE);
|
|||
|
numEntries++;
|
|||
|
} while (pImageRecord != NULL);
|
|||
|
|
|||
|
printf("NumIRBytes = %d\n",numBytes);
|
|||
|
printf("NumEntries = %d\n",numEntries);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
GroupRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
Dump GroupRecords.
|
|||
|
|
|||
|
Arguments:
|
|||
|
hCurrentProcess - Handle for the process being debugged.
|
|||
|
|
|||
|
hCurrentThread - Handle for the thread that has the debugger focus.
|
|||
|
|
|||
|
dwCurrentPc - Current Program Counter?
|
|||
|
|
|||
|
lpExtensionApis - Pointer to a structure that contains pointers to
|
|||
|
various routines. (see \nt\public\sdk\inc\ntsdexts.h)
|
|||
|
typedef struct _NTSD_EXTENSION_APIS {
|
|||
|
DWORD nSize;
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_GET_SYMBOL lpGetSymbolRoutine;
|
|||
|
PNTSD_DISASM lpDisasmRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
} NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
|
|||
|
|
|||
|
lpArgumentString - This is a pointer to a string that contains
|
|||
|
space seperated arguments that are passed to debugger
|
|||
|
extension function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD pDatabaseAnchor;
|
|||
|
DWORD pStandaloneAnchor;
|
|||
|
LOAD_ORDER_GROUP StandaloneGroupRecord;
|
|||
|
LOAD_ORDER_GROUP GroupRecord;
|
|||
|
LPLOAD_ORDER_GROUP pStandaloneGroupRecord;
|
|||
|
LPLOAD_ORDER_GROUP pGroupRecord;
|
|||
|
DWORD numBytes=0;
|
|||
|
DWORD numEntries=0;
|
|||
|
|
|||
|
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
|
|||
|
|
|||
|
printf("ArgumentString = %s\n\n",lpArgumentString);
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the top of the Service Database.
|
|||
|
//
|
|||
|
pDatabaseAnchor = (lpGetExpressionRoutine)("OrderGroupList");
|
|||
|
pStandaloneAnchor = (lpGetExpressionRoutine)("StandaloneGroupList");
|
|||
|
|
|||
|
//
|
|||
|
// Get the first service record.
|
|||
|
// This is a dummy record that points to the first real record.
|
|||
|
//
|
|||
|
GET_DATA(pDatabaseAnchor, &GroupRecord, sizeof(GroupRecord))
|
|||
|
pGroupRecord = GroupRecord.Next;
|
|||
|
GET_DATA(pStandaloneAnchor, &StandaloneGroupRecord, sizeof(GroupRecord))
|
|||
|
pStandaloneGroupRecord = StandaloneGroupRecord.Next;
|
|||
|
|
|||
|
if (_strnicmp(lpArgumentString, "mem", 3) == 0) {
|
|||
|
//--------------------------------------
|
|||
|
// Dump Memory Usage only.
|
|||
|
//--------------------------------------
|
|||
|
printf("ORDER GROUP LIST:\n");
|
|||
|
do {
|
|||
|
pGroupRecord = DumpGroupRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pGroupRecord,
|
|||
|
&numBytes,
|
|||
|
TRUE);
|
|||
|
numEntries++;
|
|||
|
} while (pGroupRecord != NULL);
|
|||
|
|
|||
|
printf("STANDALONE GROUP LIST:\n");
|
|||
|
pGroupRecord = pStandaloneGroupRecord;
|
|||
|
do {
|
|||
|
pGroupRecord = DumpGroupRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pGroupRecord,
|
|||
|
&numBytes,
|
|||
|
TRUE);
|
|||
|
numEntries++;
|
|||
|
} while (pGroupRecord != NULL);
|
|||
|
printf("NumGRBytes = %d\n",numBytes);
|
|||
|
printf("NumEntries = %d\n",numEntries);
|
|||
|
}
|
|||
|
|
|||
|
else if (_strnicmp(lpArgumentString, "name=", 5) == 0) {
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
//--------------------------------------
|
|||
|
// Dump All Group Records.
|
|||
|
//--------------------------------------
|
|||
|
printf("ORDER GROUP LIST:\n");
|
|||
|
do {
|
|||
|
pGroupRecord = DumpGroupRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pGroupRecord,
|
|||
|
&numBytes,
|
|||
|
FALSE);
|
|||
|
numEntries++;
|
|||
|
} while (pGroupRecord != NULL);
|
|||
|
|
|||
|
printf("STANDALONE GROUP LIST:\n");
|
|||
|
pGroupRecord = pStandaloneGroupRecord;
|
|||
|
do {
|
|||
|
pGroupRecord = DumpGroupRecord(
|
|||
|
hCurrentProcess,
|
|||
|
pGroupRecord,
|
|||
|
&numBytes,
|
|||
|
FALSE);
|
|||
|
numEntries++;
|
|||
|
} while (pGroupRecord != NULL);
|
|||
|
|
|||
|
printf("NumGRBytes = %d\n",numBytes);
|
|||
|
printf("NumEntries = %d\n",numEntries);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
FindServiceRecordByName(
|
|||
|
LPSTR ServiceName,
|
|||
|
LPSERVICE_RECORD *pServiceRecord
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceName - This is the name of the service that we are looking for.
|
|||
|
|
|||
|
pServiceRecord - A pointer to a location to where the pointer to the
|
|||
|
service record is to be placed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
TRUE - Success
|
|||
|
FALSE - The name couldn't be found in any of the service records.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
WCHAR StringBuffer[200];
|
|||
|
LPWSTR uniNameString;
|
|||
|
|
|||
|
if (!ConvertToUnicode(&uniNameString,ServiceName)) {
|
|||
|
printf("Could not convert to unicode\n");
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
//
|
|||
|
// Find a Service Record that matches the name in the uniNameString.
|
|||
|
//
|
|||
|
do {
|
|||
|
//
|
|||
|
// Map the memory for the service record into our process.
|
|||
|
//
|
|||
|
GET_DATA(*pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
|
|||
|
//
|
|||
|
// Get the ServiceName String.
|
|||
|
//
|
|||
|
GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
|
|||
|
if (_wcsicmp(StringBuffer, uniNameString) == 0) {
|
|||
|
//
|
|||
|
// If a name match was found, return SUCCESS.
|
|||
|
//
|
|||
|
LocalFree(uniNameString);
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
*pServiceRecord = ServiceRecord.Next;
|
|||
|
} while (*pServiceRecord != NULL);
|
|||
|
|
|||
|
LocalFree(uniNameString);
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
ConvertToUnicode(
|
|||
|
OUT LPWSTR *UnicodeOut,
|
|||
|
IN LPSTR AnsiIn
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function translates an AnsiString into a Unicode string.
|
|||
|
A new string buffer is created by this function. If the call to
|
|||
|
this function is successful, the caller must take responsibility for
|
|||
|
the unicode string buffer that was allocated by this function.
|
|||
|
The allocated buffer should be free'd with a call to LocalFree.
|
|||
|
|
|||
|
NOTE: This function allocates memory for the Unicode String.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AnsiIn - This is a pointer to an ansi string that is to be converted.
|
|||
|
|
|||
|
UnicodeOut - This is a pointer to a location where the pointer to the
|
|||
|
unicode string is to be placed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - The conversion was successful.
|
|||
|
|
|||
|
FALSE - The conversion was unsuccessful. In this case a buffer for
|
|||
|
the unicode string was not allocated.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS ntStatus;
|
|||
|
DWORD bufSize;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
ANSI_STRING ansiString;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer for the unicode string.
|
|||
|
//
|
|||
|
|
|||
|
bufSize = (strlen(AnsiIn)+1) * sizeof(WCHAR);
|
|||
|
|
|||
|
*UnicodeOut = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (UINT)bufSize);
|
|||
|
|
|||
|
if (*UnicodeOut == NULL) {
|
|||
|
printf("ScConvertToUnicode:LocalAlloc Failure %ld\n",GetLastError());
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the string structures
|
|||
|
//
|
|||
|
RtlInitAnsiString( &ansiString, AnsiIn);
|
|||
|
|
|||
|
unicodeString.Buffer = *UnicodeOut;
|
|||
|
unicodeString.MaximumLength = (USHORT)bufSize;
|
|||
|
unicodeString.Length = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Call the conversion function.
|
|||
|
//
|
|||
|
ntStatus = RtlAnsiStringToUnicodeString (
|
|||
|
&unicodeString, // Destination
|
|||
|
&ansiString, // Source
|
|||
|
(BOOLEAN)FALSE); // Allocate the destination
|
|||
|
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
|
|||
|
printf("ScConvertToUnicode:RtlAnsiStringToUnicodeString Failure %lx\n",
|
|||
|
ntStatus);
|
|||
|
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the pointer location with the unicode string buffer pointer.
|
|||
|
//
|
|||
|
*UnicodeOut = unicodeString.Buffer;
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
LPSERVICE_RECORD
|
|||
|
DumpServiceRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
LPSERVICE_RECORD pServiceRecord,
|
|||
|
LPDWORD NumBytes, // number of bytes in ServiceRecord.
|
|||
|
LPDWORD NumDependBytes, // number of bytes in DependRecords.
|
|||
|
BOOL JustSizeInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
WCHAR StringBuffer[200];
|
|||
|
DWORD NameStringSize;
|
|||
|
DWORD EntrySize=0;
|
|||
|
DWORD DependEntrySize=0;
|
|||
|
DWORD numDependStructs=0;
|
|||
|
|
|||
|
//------------------------------------------
|
|||
|
// Dump Size information only.
|
|||
|
//------------------------------------------
|
|||
|
if (JustSizeInfo) {
|
|||
|
EntrySize += sizeof(SERVICE_RECORD);
|
|||
|
GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
|
|||
|
NameStringSize = WCSSIZE(StringBuffer);
|
|||
|
EntrySize += NameStringSize;
|
|||
|
printf("\t\t\t\tAddress = 0x%lx\r%ws\n",pServiceRecord,StringBuffer);
|
|||
|
#ifdef remove
|
|||
|
if (NameStringSize < 22) {
|
|||
|
printf("\t");
|
|||
|
}
|
|||
|
#endif
|
|||
|
GET_STRING(ServiceRecord.DisplayName, StringBuffer, sizeof(StringBuffer))
|
|||
|
if (ServiceRecord.DisplayName != ServiceRecord.DisplayName) {
|
|||
|
EntrySize += WCSSIZE(StringBuffer);
|
|||
|
}
|
|||
|
if (ServiceRecord.Dependencies != NULL) {
|
|||
|
GET_STRING(ServiceRecord.Dependencies, StringBuffer, sizeof(StringBuffer))
|
|||
|
EntrySize += WCSSIZE(StringBuffer);
|
|||
|
}
|
|||
|
GetDependTreeSize(&ServiceRecord,&numDependStructs, &DependEntrySize, TRUE);
|
|||
|
GetDependTreeSize(&ServiceRecord,&numDependStructs, &DependEntrySize, FALSE);
|
|||
|
|
|||
|
|
|||
|
*NumBytes += EntrySize;
|
|||
|
printf(" SRBytes=%d DependBytes=%d TotalBytes=%d\n",
|
|||
|
EntrySize,
|
|||
|
DependEntrySize,
|
|||
|
*NumBytes);
|
|||
|
|
|||
|
*NumDependBytes += DependEntrySize;
|
|||
|
return (ServiceRecord.Next);
|
|||
|
}
|
|||
|
//------------------------------------------
|
|||
|
// Dump other information.
|
|||
|
//------------------------------------------
|
|||
|
*NumBytes += sizeof(SERVICE_RECORD);
|
|||
|
//
|
|||
|
// Map the memory for the service record into our process.
|
|||
|
//
|
|||
|
GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
|
|||
|
//
|
|||
|
// Get the ServiceName and DisplayName Strings.
|
|||
|
//
|
|||
|
GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
|
|||
|
NameStringSize = WCSSIZE(StringBuffer);
|
|||
|
*NumBytes += NameStringSize;
|
|||
|
|
|||
|
printf("ServiceName : %ws (0x%lx)\n",StringBuffer,pServiceRecord);
|
|||
|
|
|||
|
GET_STRING(ServiceRecord.DisplayName, StringBuffer, sizeof(StringBuffer))
|
|||
|
if (ServiceRecord.DisplayName != ServiceRecord.DisplayName) {
|
|||
|
*NumBytes += WCSSIZE(StringBuffer);
|
|||
|
}
|
|||
|
printf("DisplayName : %ws\n",StringBuffer);
|
|||
|
|
|||
|
printf("ResumeNum : %d\t\t", ServiceRecord.ResumeNum);
|
|||
|
printf("ServerAnnounce : %d\n", ServiceRecord.ServerAnnounce);
|
|||
|
printf("Signature : 0x%lx\t", ServiceRecord.Signature);
|
|||
|
printf("UseCount : %d\n", ServiceRecord.UseCount);
|
|||
|
printf("StatusFlag : %d\t\t",ServiceRecord.StatusFlag);
|
|||
|
printf("pImageRecord : 0x%lx\n",ServiceRecord.ImageRecord);
|
|||
|
|
|||
|
printf(" **** STATUS **** \n"
|
|||
|
" dwServiceType : 0x%lx\t",ServiceRecord.ServiceStatus.dwServiceType);
|
|||
|
printf("dwCurrentState : 0x%lx\n",ServiceRecord.ServiceStatus.dwCurrentState);
|
|||
|
printf(" dwControlsAccepted : 0x%lx\t",ServiceRecord.ServiceStatus.dwControlsAccepted);
|
|||
|
printf("dwWin32ExitCode : 0x%lx\n",ServiceRecord.ServiceStatus.dwWin32ExitCode);
|
|||
|
printf(" dwSpecificExitCode : 0x%lx\t",ServiceRecord.ServiceStatus.dwServiceSpecificExitCode);
|
|||
|
printf("dwCheckPoint : 0x%lx\n",ServiceRecord.ServiceStatus.dwCheckPoint);
|
|||
|
printf(" dwWaitHint : 0x%lx\n",ServiceRecord.ServiceStatus.dwWaitHint);
|
|||
|
|
|||
|
printf("StartType : %d\t\t",ServiceRecord.StartType);
|
|||
|
printf("ErrorControl : %d\n",ServiceRecord.ErrorControl);
|
|||
|
printf("Tag : 0x%x\t\t",ServiceRecord.Tag);
|
|||
|
printf("StartDepend : 0x%lx\n",ServiceRecord.StartDepend);
|
|||
|
if (ServiceRecord.StopDepend > (LPDEPEND_RECORD)10) {
|
|||
|
printf("StopDepend : 0x%lx\t",ServiceRecord.StopDepend);
|
|||
|
}
|
|||
|
else {
|
|||
|
printf("StopDepend : 0x%lx\t\t",ServiceRecord.StopDepend);
|
|||
|
}
|
|||
|
|
|||
|
if (ServiceRecord.Dependencies != NULL) {
|
|||
|
GET_STRING(ServiceRecord.Dependencies, StringBuffer, sizeof(StringBuffer))
|
|||
|
*NumBytes += WCSSIZE(StringBuffer);
|
|||
|
printf("Dependencies : %ws\n",StringBuffer);
|
|||
|
}
|
|||
|
else {
|
|||
|
printf("Dependencies : (none)\n");
|
|||
|
}
|
|||
|
|
|||
|
printf("pServiceSd : 0x%lx\t",ServiceRecord.ServiceSd);
|
|||
|
printf("StartError : %d\n",ServiceRecord.StartError);
|
|||
|
printf("StartState : 0x%lx\t\t",ServiceRecord.StartState);
|
|||
|
printf("pMemberOfGroup : 0x%lx\n",ServiceRecord.MemberOfGroup);
|
|||
|
printf("pRegistryGroup : 0x%lx\n",ServiceRecord.RegistryGroup);
|
|||
|
printf("pCrashRecord : 0x%lx\n\n",ServiceRecord.CrashRecord);
|
|||
|
|
|||
|
GetDependTreeSize(&ServiceRecord,&numDependStructs, NumBytes, TRUE);
|
|||
|
GetDependTreeSize(&ServiceRecord,&numDependStructs, NumBytes, FALSE);
|
|||
|
|
|||
|
|
|||
|
return (ServiceRecord.Next);
|
|||
|
}
|
|||
|
|
|||
|
LPIMAGE_RECORD
|
|||
|
DumpImageRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
LPIMAGE_RECORD pImageRecord,
|
|||
|
LPDWORD NumBytes, // number of bytes in ImageRecord.
|
|||
|
BOOL JustSizeInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
IMAGE_RECORD ImageRecord;
|
|||
|
WCHAR StringBuffer[200];
|
|||
|
DWORD NameStringSize;
|
|||
|
DWORD EntrySize=0;
|
|||
|
DWORD DependEntrySize=0;
|
|||
|
DWORD numDependStructs=0;
|
|||
|
|
|||
|
//------------------------------------------
|
|||
|
// Dump Size information only.
|
|||
|
//------------------------------------------
|
|||
|
if (JustSizeInfo) {
|
|||
|
EntrySize += sizeof(IMAGE_RECORD);
|
|||
|
GET_DATA(pImageRecord, &ImageRecord, sizeof(ImageRecord))
|
|||
|
GET_STRING(ImageRecord.ImageName, StringBuffer, sizeof(StringBuffer))
|
|||
|
NameStringSize = WCSSIZE(StringBuffer);
|
|||
|
EntrySize += NameStringSize;
|
|||
|
printf("%ws \tAddress = 0x%lx\n",StringBuffer,pImageRecord);
|
|||
|
#ifdef remove
|
|||
|
if (NameStringSize < 22) {
|
|||
|
printf("\t");
|
|||
|
}
|
|||
|
#endif
|
|||
|
*NumBytes += EntrySize;
|
|||
|
printf(" IRBytes=%d TotalBytes=%d\n",EntrySize,*NumBytes);
|
|||
|
return (ImageRecord.Next);
|
|||
|
}
|
|||
|
//------------------------------------------
|
|||
|
// Dump other information.
|
|||
|
//------------------------------------------
|
|||
|
*NumBytes += sizeof(IMAGE_RECORD);
|
|||
|
//
|
|||
|
// Map the memory for the service record into our process.
|
|||
|
//
|
|||
|
GET_DATA(pImageRecord, &ImageRecord, sizeof(ImageRecord))
|
|||
|
|
|||
|
//
|
|||
|
// Get the ImageName and DisplayName Strings.
|
|||
|
//
|
|||
|
GET_STRING(ImageRecord.ImageName, StringBuffer, sizeof(StringBuffer))
|
|||
|
NameStringSize = WCSSIZE(StringBuffer);
|
|||
|
*NumBytes += NameStringSize;
|
|||
|
|
|||
|
printf("ImageName : %ws (0x%lx)\n",StringBuffer,pImageRecord);
|
|||
|
|
|||
|
printf(" Pid : %d\t\t", ImageRecord.Pid);
|
|||
|
printf("ServiceCount : %d\n", ImageRecord.ServiceCount);
|
|||
|
printf(" PipeHandle : 0x%lx\t", ImageRecord.PipeHandle);
|
|||
|
printf("ProcessHandle : 0x%lx\n", ImageRecord.ProcessHandle);
|
|||
|
printf(" StatusFlag : 0x%lx\n",ImageRecord.TokenHandle);
|
|||
|
|
|||
|
return (ImageRecord.Next);
|
|||
|
}
|
|||
|
|
|||
|
LPLOAD_ORDER_GROUP
|
|||
|
DumpGroupRecord(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
LPLOAD_ORDER_GROUP pGroupRecord,
|
|||
|
LPDWORD NumBytes, // number of bytes in GroupRecord.
|
|||
|
BOOL JustSizeInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LOAD_ORDER_GROUP GroupRecord;
|
|||
|
WCHAR StringBuffer[200];
|
|||
|
DWORD NameStringSize;
|
|||
|
DWORD EntrySize=0;
|
|||
|
DWORD DependEntrySize=0;
|
|||
|
DWORD numDependStructs=0;
|
|||
|
|
|||
|
//------------------------------------------
|
|||
|
// Dump Size information only.
|
|||
|
//------------------------------------------
|
|||
|
if (JustSizeInfo) {
|
|||
|
EntrySize += sizeof(LOAD_ORDER_GROUP);
|
|||
|
GET_DATA(pGroupRecord, &GroupRecord, sizeof(GroupRecord))
|
|||
|
GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
|
|||
|
NameStringSize = WCSSIZE(StringBuffer);
|
|||
|
EntrySize += NameStringSize;
|
|||
|
printf("\t\t\t\tAddress = 0x%lx\r%ws\n",pGroupRecord,StringBuffer);
|
|||
|
*NumBytes += EntrySize;
|
|||
|
printf(" GRBytes=%d TotalBytes=%d\n",EntrySize,*NumBytes);
|
|||
|
return (GroupRecord.Next);
|
|||
|
}
|
|||
|
//------------------------------------------
|
|||
|
// Dump other information.
|
|||
|
//------------------------------------------
|
|||
|
*NumBytes += sizeof(LOAD_ORDER_GROUP);
|
|||
|
//
|
|||
|
// Map the memory for the service record into our process.
|
|||
|
//
|
|||
|
GET_DATA(pGroupRecord, &GroupRecord, sizeof(GroupRecord))
|
|||
|
|
|||
|
//
|
|||
|
// Get the GroupName and DisplayName Strings.
|
|||
|
//
|
|||
|
GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
|
|||
|
NameStringSize = WCSSIZE(StringBuffer);
|
|||
|
*NumBytes += NameStringSize;
|
|||
|
|
|||
|
printf("GroupName : %ws (0x%lx)\n",StringBuffer,pGroupRecord);
|
|||
|
printf(" RefCount : %d\n", GroupRecord.RefCount);
|
|||
|
|
|||
|
return (GroupRecord.Next);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
GetDependTreeSize(
|
|||
|
LPSERVICE_RECORD pServiceRecord,
|
|||
|
LPDWORD pNumDependStructs,
|
|||
|
LPDWORD pNumBytes,
|
|||
|
BOOL StartDepend
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
pServiceRecord - This is a pointer to a ServiceRecord that is already
|
|||
|
mapped into our address space.
|
|||
|
pNumDependStructs -
|
|||
|
pNumBytes -
|
|||
|
StartDepend - TRUE indicates to look through StartDepend list.
|
|||
|
FALSE indicates to look through StopDepend list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DEPEND_RECORD DependRecord;
|
|||
|
BOOL MoreRecords=TRUE;
|
|||
|
|
|||
|
if (StartDepend) {
|
|||
|
if (pServiceRecord->StartDepend == NULL) {
|
|||
|
return;
|
|||
|
}
|
|||
|
printf(" StartDependRecordAddress = 0x%x\n",pServiceRecord->StartDepend);
|
|||
|
GET_DATA(pServiceRecord->StartDepend, &DependRecord, sizeof(DependRecord))
|
|||
|
}
|
|||
|
else {
|
|||
|
if (pServiceRecord->StopDepend == NULL) {
|
|||
|
return;
|
|||
|
}
|
|||
|
printf(" StopDependRecordAddress = 0x%x\n",pServiceRecord->StopDepend);
|
|||
|
GET_DATA(pServiceRecord->StopDepend, &DependRecord, sizeof(DependRecord))
|
|||
|
}
|
|||
|
|
|||
|
if (pServiceRecord->StartDepend != NULL) {
|
|||
|
do {
|
|||
|
*pNumBytes += sizeof(DependRecord);
|
|||
|
(*pNumDependStructs)++;
|
|||
|
|
|||
|
if (DependRecord.Next != NULL) {
|
|||
|
printf(" DependRecordAddress = 0x%x\n",DependRecord.Next);
|
|||
|
GET_DATA(DependRecord.Next, &DependRecord, sizeof(DependRecord))
|
|||
|
}
|
|||
|
else {
|
|||
|
MoreRecords = FALSE;
|
|||
|
}
|
|||
|
} while ((MoreRecords) && (*pNumDependStructs < 50));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
DumpFwdDependentNames(
|
|||
|
LPSERVICE_RECORD pServiceRecord
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
DEPEND_RECORD DependRecord;
|
|||
|
LOAD_ORDER_GROUP GroupRecord;
|
|||
|
UNRESOLVED_DEPEND UnresolvedRecord;
|
|||
|
WCHAR StringBuffer[200];
|
|||
|
static CHAR LeadingSpaces[80]="";
|
|||
|
BOOL MoreRecords=TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Map the memory for the service record into our process.
|
|||
|
//
|
|||
|
GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
|
|||
|
//
|
|||
|
// Get the ServiceName String.
|
|||
|
//
|
|||
|
GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
|
|||
|
printf("%s%ws (service) depends on: \t\n",LeadingSpaces,StringBuffer);
|
|||
|
|
|||
|
strcat(LeadingSpaces," ");
|
|||
|
|
|||
|
if (ServiceRecord.StartDepend != NULL) {
|
|||
|
GET_DATA(ServiceRecord.StartDepend, &DependRecord, sizeof(DependRecord))
|
|||
|
do {
|
|||
|
switch (DependRecord.DependType) {
|
|||
|
case TypeDependOnService:
|
|||
|
DumpFwdDependentNames(DependRecord.DependService);
|
|||
|
break;
|
|||
|
case TypeDependOnGroup:
|
|||
|
GET_DATA(DependRecord.DependGroup, &GroupRecord, sizeof(GroupRecord))
|
|||
|
GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
|
|||
|
printf("%s%ws (group)\n", LeadingSpaces,StringBuffer);
|
|||
|
break;
|
|||
|
case TypeDependOnUnresolved:
|
|||
|
GET_DATA(DependRecord.DependUnresolved, &UnresolvedRecord, sizeof(UnresolvedRecord))
|
|||
|
GET_STRING(UnresolvedRecord.Name, StringBuffer, sizeof(StringBuffer))
|
|||
|
printf("%s%ws (unresolved)\n", LeadingSpaces,StringBuffer);
|
|||
|
break;
|
|||
|
default:
|
|||
|
printf("%s(Unknown Depend Type)\n",LeadingSpaces);
|
|||
|
MoreRecords = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (DependRecord.Next != NULL) {
|
|||
|
GET_DATA(DependRecord.Next, &DependRecord, sizeof(DependRecord))
|
|||
|
}
|
|||
|
else {
|
|||
|
MoreRecords = FALSE;
|
|||
|
}
|
|||
|
} while (MoreRecords);
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
printf("%s(nothing)\n",LeadingSpaces);
|
|||
|
}
|
|||
|
LeadingSpaces[strlen(LeadingSpaces)-2] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
DumpBkwdDependentNames(
|
|||
|
LPSERVICE_RECORD pServiceRecord
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SERVICE_RECORD ServiceRecord;
|
|||
|
DEPEND_RECORD DependRecord;
|
|||
|
LOAD_ORDER_GROUP GroupRecord;
|
|||
|
UNRESOLVED_DEPEND UnresolvedRecord;
|
|||
|
WCHAR StringBuffer[200];
|
|||
|
static CHAR LeadingSpaces[80]="";
|
|||
|
BOOL MoreRecords=TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Map the memory for the service record into our process.
|
|||
|
//
|
|||
|
GET_DATA(pServiceRecord, &ServiceRecord, sizeof(ServiceRecord))
|
|||
|
|
|||
|
//
|
|||
|
// Get the ServiceName String.
|
|||
|
//
|
|||
|
GET_STRING(ServiceRecord.ServiceName, StringBuffer, sizeof(StringBuffer))
|
|||
|
printf("%s%ws (service): \t\n",LeadingSpaces,StringBuffer);
|
|||
|
|
|||
|
strcat(LeadingSpaces," ");
|
|||
|
|
|||
|
if (ServiceRecord.StopDepend != NULL) {
|
|||
|
GET_DATA(ServiceRecord.StopDepend, &DependRecord, sizeof(DependRecord))
|
|||
|
do {
|
|||
|
switch (DependRecord.DependType) {
|
|||
|
case TypeDependOnService:
|
|||
|
DumpBkwdDependentNames(DependRecord.DependService);
|
|||
|
break;
|
|||
|
case TypeDependOnGroup:
|
|||
|
GET_DATA(DependRecord.DependGroup, &GroupRecord, sizeof(GroupRecord))
|
|||
|
GET_STRING(GroupRecord.GroupName, StringBuffer, sizeof(StringBuffer))
|
|||
|
printf("%s%ws (group)\n", LeadingSpaces,StringBuffer);
|
|||
|
break;
|
|||
|
case TypeDependOnUnresolved:
|
|||
|
GET_DATA(DependRecord.DependUnresolved, &UnresolvedRecord, sizeof(UnresolvedRecord))
|
|||
|
GET_STRING(UnresolvedRecord.Name, StringBuffer, sizeof(StringBuffer))
|
|||
|
printf("%s%ws (unresolved)\n", LeadingSpaces,StringBuffer);
|
|||
|
break;
|
|||
|
default:
|
|||
|
printf("%s(Unknown Depend Type)\n",LeadingSpaces);
|
|||
|
MoreRecords = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (DependRecord.Next != NULL) {
|
|||
|
GET_DATA(DependRecord.Next, &DependRecord, sizeof(DependRecord))
|
|||
|
}
|
|||
|
else {
|
|||
|
MoreRecords = FALSE;
|
|||
|
}
|
|||
|
} while (MoreRecords);
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
printf("%s(nothing)\n",LeadingSpaces);
|
|||
|
}
|
|||
|
LeadingSpaces[strlen(LeadingSpaces)-2] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
help(
|
|||
|
HANDLE hCurrentProcess,
|
|||
|
HANDLE hCurrentThread,
|
|||
|
DWORD dwCurrentPc,
|
|||
|
PNTSD_EXTENSION_APIS lpExtensionApis,
|
|||
|
LPSTR lpArgumentString
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Provides online help for the user of this debugger extension.
|
|||
|
|
|||
|
Arguments:
|
|||
|
hCurrentProcess - Handle for the process being debugged.
|
|||
|
|
|||
|
hCurrentThread - Handle for the thread that has the debugger focus.
|
|||
|
|
|||
|
dwCurrentPc - Current Program Counter?
|
|||
|
|
|||
|
lpExtensionApis - Pointer to a structure that contains pointers to
|
|||
|
various routines. (see \nt\public\sdk\inc\ntsdexts.h)
|
|||
|
typedef struct _NTSD_EXTENSION_APIS {
|
|||
|
DWORD nSize;
|
|||
|
PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
|
|||
|
PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
|
|||
|
PNTSD_GET_SYMBOL lpGetSymbolRoutine;
|
|||
|
PNTSD_DISASM lpDisasmRoutine;
|
|||
|
PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
|||
|
} NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS;
|
|||
|
|
|||
|
lpArgumentString - This is a pointer to a string that contains
|
|||
|
space seperated arguments that are passed to debugger
|
|||
|
extension function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
|
|||
|
|
|||
|
printf("\nService Controller NTSD Extensions\n");
|
|||
|
|
|||
|
if (!lpArgumentString || *lpArgumentString == '\0' ||
|
|||
|
*lpArgumentString == '\n' || *lpArgumentString == '\r')
|
|||
|
{
|
|||
|
printf("\tServiceRecord - dump a ServiceRecord structure\n");
|
|||
|
printf("\tDependencies - dump a Service's Dependencies\n");
|
|||
|
printf("\tBackDepend - dump a Service's that depend on this service\n");
|
|||
|
printf("\tImageRecord - dump an ImageRecord structure\n");
|
|||
|
printf("\tGroupRecord - dump a GroupRecord structure\n");
|
|||
|
printf("\n\tEnter help <cmd> for detailed help on a command\n");
|
|||
|
}
|
|||
|
else if (!_stricmp(lpArgumentString, "ServiceRecord")) {
|
|||
|
printf("\tServiceRecord <arg>, where <arg> can be one of:\n");
|
|||
|
printf("\t\tno argument - dump all ServiceRecord structures\n");
|
|||
|
printf("\t\tmem - dump ServiceRecord Address Info only\n");
|
|||
|
printf("\t\tname= <name> - dump the ServiceRecord for <name>\n");
|
|||
|
printf("\t\taddress= <address> - dump the ServiceRecord at specified address\n");
|
|||
|
}
|
|||
|
else if (!_stricmp(lpArgumentString, "Dependencies")) {
|
|||
|
printf("\tDependencies <arg>, where <arg> can be one of:\n");
|
|||
|
printf("\t\tname= <name> - dump the Dependency Chain for <name>\n");
|
|||
|
printf("\t\taddress= <address> - dump the Dependency Chain for address\n");
|
|||
|
}
|
|||
|
else if (!_stricmp(lpArgumentString, "BackDepend")) {
|
|||
|
printf("\tDependencies <arg>, where <arg> can be one of:\n");
|
|||
|
printf("\t\tname= <name> - dump the Dependency Chain for <name>\n");
|
|||
|
printf("\t\taddress= <address> - dump the Dependency Chain for address\n");
|
|||
|
}
|
|||
|
else if (!_stricmp(lpArgumentString, "ImageRecord")) {
|
|||
|
printf("\t\tmem - dump ImageRecord Memory Info only\n");
|
|||
|
}
|
|||
|
else if (!_stricmp(lpArgumentString, "GroupRecord")) {
|
|||
|
printf("\t\tmem - dump GroupRecord Memory Info only\n");
|
|||
|
}
|
|||
|
else {
|
|||
|
printf("\tInvalid command [%s]\n", lpArgumentString);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|