Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

840 lines
27 KiB

#include <ntos.h>
#include <nturtl.h>
#include <windows.h>
#include <imagehlp.h>
#include <symhelp.h>
#include <stdio.h>
#include <stdlib.h>
#include <wtypes.h>
#include <ntstatus.dbg>
#include <winerror.dbg>
#include <netevent.h>
#include <netevent.dbg>
#if !DBG
int
_cdecl
main(
int argc,
char *argv[]
)
{
fprintf( stderr, "RESMON: This tool is only available for checked builds.\n" );
return 1;
}
#else
CHAR EventBuffer[ 4*4096 ];
PRTL_EVENT_ID_INFO CreateProcessEventId;
PRTL_EVENT_ID_INFO ExitProcessEventId;
PRTL_EVENT_ID_INFO LoadModuleEventId;
PRTL_EVENT_ID_INFO UnloadModuleEventId;
PRTL_EVENT_ID_INFO PageFaultEventId;
BOOL VerboseFlag;
VOID
LoadSymbolsForEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
);
VOID
UnloadSymbolsForEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
);
VOID
UnloadProcessForEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
);
VOID
DumpEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
);
LPSTR
FindSymbolicNameForStatus(
DWORD Id
);
BOOL
LoadSymbolsFilter(
HANDLE UniqueProcess,
LPSTR ImageFilePath,
DWORD ImageBase,
DWORD ImageSize,
LOAD_SYMBOLS_FILTER_REASON Reason
)
{
switch( Reason ) {
case LoadSymbolsPathNotFound:
fprintf( stderr,
"RESMON: Unable to fimd symbols for %s\n",
ImageFilePath
);
break;
case LoadSymbolsDeferredLoad:
if (VerboseFlag) {
fprintf( stderr,
"RESMON: Remembering %s based at [%08x..%08x) in CID: %x\n",
ImageFilePath,
ImageBase,
ImageBase + ImageSize,
UniqueProcess
);
}
break;
case LoadSymbolsLoad:
fprintf( stderr,
"RESMON: Loading symbols for %s based at %08x in CID: %x\n",
ImageFilePath,
ImageBase,
UniqueProcess
);
break;
case LoadSymbolsUnload:
if (VerboseFlag) {
fprintf( stderr,
"RESMON: Unloading symbols for %s based at %08x in CID: %x\n",
ImageFilePath,
ImageBase,
UniqueProcess
);
}
break;
case LoadSymbolsUnableToLoad:
fprintf( stderr,
"RESMON: Unable to load symbols for %s\n",
ImageFilePath
);
break;
}
return TRUE;
}
VOID
InitializeSymbolPathEnvVar( VOID )
{
DWORD n;
char Buffer[ MAX_PATH ];
n = GetEnvironmentVariable( "_NT_SYMBOL_PATH", Buffer, sizeof( Buffer ) );
if (n == 0) {
n = GetEnvironmentVariable( "SystemRoot", Buffer, sizeof( Buffer ) );
if (n != 0) {
strcat( Buffer, "\\Symbols" );
SetEnvironmentVariable( "_NT_SYMBOL_PATH", Buffer );
fprintf( stderr, "RESMON: Default _NT_SYMBOL_PATH to %s\n", Buffer );
}
}
return;
}
int
_cdecl
main(
int argc,
char *argv[]
)
{
BOOL fShowUsage;
PCHAR s, s1;
ULONG ProcessId;
HANDLE Process, ThreadToResume;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING Unicode;
NTSTATUS Status;
PRTL_EVENT_LOG EventLog;
PRTL_EVENT Event;
PRTL_EVENT_ID_INFO EventId;
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
PCHAR CommandLine;
ULONG EventLogFlags;
ULONG EventClassMask;
ULONG ProcessCreateFlags;
InitializeSymbolPathEnvVar();
VerboseFlag = FALSE;
EventClassMask = 0xFFFFFFFF;
CommandLine = NULL;
ProcessId = 0xFFFFFFFF;
fShowUsage = FALSE;
ProcessCreateFlags = CREATE_SUSPENDED;
while (--argc) {
s = *++argv;
if (*s == '-' || *s == '/') {
while (*++s) {
switch( toupper( *s ) ) {
case 'M':
if (--argc) {
s1 = *++argv;
if (isalpha( *s1 )) {
EventClassMask = 0;
while (*s1) {
switch( toupper( *s1 ) ) {
case 'H':
if (isdigit( s1[1] )) {
while (isdigit( *++s1 )) {
switch (*s1) {
case '0': EventClassMask |= RTL_EVENT_CLASS_PROCESS_HEAP ; break;
case '1': EventClassMask |= RTL_EVENT_CLASS_PRIVATE_HEAP ; break;
case '2': EventClassMask |= RTL_EVENT_CLASS_KERNEL_HEAP ; break;
case '3': EventClassMask |= RTL_EVENT_CLASS_GDI_HEAP ; break;
case '4': EventClassMask |= RTL_EVENT_CLASS_USER_HEAP ; break;
case '5': EventClassMask |= RTL_EVENT_CLASS_CONSOLE_HEAP ; break;
case '6': EventClassMask |= RTL_EVENT_CLASS_DESKTOP_HEAP ; break;
case '7': EventClassMask |= RTL_EVENT_CLASS_CSR_SHARED_HEAP; break;
default:
fprintf( stderr, "RESMON: Invalid heap class digit '%c' flag.\n", *s1 );
fShowUsage = TRUE;
break;
}
}
s1 -= 1;
}
else {
EventClassMask |= RTL_EVENT_CLASS_HEAP_ALL;
}
break;
case 'O':
EventClassMask |= RTL_EVENT_CLASS_OB;
break;
case 'F':
EventClassMask |= RTL_EVENT_CLASS_IO;
break;
case 'V':
EventClassMask |= RTL_EVENT_CLASS_VM;
break;
case 'P':
EventClassMask |= RTL_EVENT_CLASS_PAGE_FAULT;
break;
case 'T':
EventClassMask |= RTL_EVENT_CLASS_TRANSITION_FAULT;
break;
default:
fprintf( stderr, "RESMON: Invalid event class letter '%c' flag.\n", *s1 );
fShowUsage = TRUE;
break;
}
s1 += 1;
}
}
else {
Status = RtlCharToInteger( s1, 16, &EventClassMask );
}
}
else {
fprintf( stderr, "RESMON: Missing process id of -%c flag.\n", *s );
fShowUsage = TRUE;
}
break;
case 'P':
if (--argc) {
s1 = *++argv;
ProcessId = atoi( s1 );
}
else {
fprintf( stderr, "RESMON: Missing process id of -%c flag.\n", *s );
fShowUsage = TRUE;
}
break;
case 'O':
EventLogFlags |= RTL_EVENT_LOG_INHERIT;
break;
case '2':
ProcessCreateFlags |= CREATE_NEW_CONSOLE;
break;
case 'V':
VerboseFlag = TRUE;
break;
case '?':
case 'H':
fShowUsage = TRUE;
break;
default:
fprintf( stderr, "RESMON: Invalid flag - '%c'\n", *s );
fShowUsage = TRUE;
break;
}
}
}
else
if (fShowUsage) {
break;
}
else
if (CommandLine != NULL) {
fShowUsage = TRUE;
break;
}
else {
CommandLine = s;
}
}
if (fShowUsage) {
fprintf( stderr, "usage: RESMON [-h] [-o] [-m EventMask] [-p ProcessId | Command]\n" );
fprintf( stderr, "where: -h - displays this help message.\n" );
fprintf( stderr, " -o - monitor all sub-processes too.\n" );
fprintf( stderr, " -m EventMask - specifies which events to monitor.\n" );
fprintf( stderr, " Default is all events. EventMask\n" );
fprintf( stderr, " consists of one or more letters\n" );
fprintf( stderr, " which stand for the following:\n" );
fprintf( stderr, " H[n] - heap events.\n" );
fprintf( stderr, " 0 - process heap.\n" );
fprintf( stderr, " 1 - private heap.\n" );
fprintf( stderr, " 2 - CSRSS heap.\n" );
fprintf( stderr, " 3 - CSR Port heap.\n" );
fprintf( stderr, " F - file events.\n" );
fprintf( stderr, " O - object events.\n" );
fprintf( stderr, " V - virtual memory events.\n" );
fprintf( stderr, " P - page faults.\n" );
fprintf( stderr, " -p ProcessId - specifies which process to monitor.\n" );
fprintf( stderr, " Default is -1 which is the Windows\n" );
fprintf( stderr, " SubSystem process.\n" );
fprintf( stderr, " Command - if -p is not specified then a command to\n" );
fprintf( stderr, " execute may be specified in quotes.\n" );
return 1;
}
ThreadToResume = NULL;
if (CommandLine != NULL) {
RtlZeroMemory( &StartupInfo, sizeof( StartupInfo ) );
StartupInfo.cb = sizeof( StartupInfo );
StartupInfo.lpReserved = NULL;
StartupInfo.lpReserved2 = NULL;
StartupInfo.lpDesktop = NULL;
StartupInfo.lpTitle = CommandLine;
StartupInfo.dwX = 0;
StartupInfo.dwY = 1;
StartupInfo.dwXSize = 100;
StartupInfo.dwYSize = 100;
StartupInfo.dwFlags = 0;//STARTF_SHELLOVERRIDE;
StartupInfo.wShowWindow = SW_SHOWNORMAL;
if (!CreateProcess( NULL,
CommandLine,
NULL,
NULL,
TRUE,
ProcessCreateFlags,
NULL,
NULL,
&StartupInfo,
&ProcessInformation
)
) {
fprintf( stderr, "RESMON: CreateProcess( %s ) failed - %lu\n", CommandLine, GetLastError() );
return 1;
}
Process = ProcessInformation.hProcess;
ThreadToResume = ProcessInformation.hThread;
ProcessId = ProcessInformation.dwProcessId;
InitializeImageDebugInformation( LoadSymbolsFilter, Process, TRUE, TRUE );
}
else
if (ProcessId == 0xFFFFFFFF) {
RtlInitUnicodeString( &Unicode, L"\\WindowsSS" );
InitializeObjectAttributes( &ObjectAttributes,
&Unicode,
0,
NULL,
NULL
);
Status = NtOpenProcess( &Process,
MAXIMUM_ALLOWED,
&ObjectAttributes,
NULL
);
if (!NT_SUCCESS( Status )) {
fprintf( stderr, "OpenProcess( %wZ ) failed - %lx\n", &Unicode, Status );
return 1;
}
InitializeImageDebugInformation( LoadSymbolsFilter, Process, FALSE, TRUE );
}
else {
Process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ProcessId );
if (!Process) {
fprintf( stderr, "OpenProcess( %ld ) failed - %lx\n", ProcessId, GetLastError() );
return 1;
}
InitializeImageDebugInformation( LoadSymbolsFilter, Process, FALSE, TRUE );
}
Status = RtlCreateEventLog( Process,
EventLogFlags,
EventClassMask,
&EventLog
);
CloseHandle( Process );
if (NT_SUCCESS( Status )) {
if (ThreadToResume != NULL) {
printf( "Monitoring Command '%s'\n", CommandLine );
ResumeThread( ThreadToResume );
CloseHandle( ThreadToResume );
}
else
if (ProcessId == 0xFFFFFFFF) {
printf( "Monitoring Windows SubSystem Process\n" );
}
else {
printf( "Monitoring Process %d\n", ProcessId );
}
printf( " Events to monitor:" );
if (EventClassMask & RTL_EVENT_CLASS_HEAP_ALL) {
printf( " Heap(" );
if (EventClassMask & RTL_EVENT_CLASS_PROCESS_HEAP) {
printf( " Process" );
}
if (EventClassMask & RTL_EVENT_CLASS_PRIVATE_HEAP) {
printf( " Private" );
}
if (EventClassMask & RTL_EVENT_CLASS_KERNEL_HEAP) {
printf( " Kernel" );
}
if (EventClassMask & RTL_EVENT_CLASS_GDI_HEAP) {
printf( " GDI" );
}
if (EventClassMask & RTL_EVENT_CLASS_USER_HEAP) {
printf( " User" );
}
if (EventClassMask & RTL_EVENT_CLASS_CONSOLE_HEAP) {
printf( " Console" );
}
if (EventClassMask & RTL_EVENT_CLASS_DESKTOP_HEAP) {
printf( " Desktop" );
}
if (EventClassMask & RTL_EVENT_CLASS_CSR_SHARED_HEAP) {
printf( " CSR Shared" );
}
printf( ")" );
}
if (EventClassMask & RTL_EVENT_CLASS_OB) {
printf( " Object" );
}
if (EventClassMask & RTL_EVENT_CLASS_IO) {
printf( " File I/O" );
}
if (EventClassMask & RTL_EVENT_CLASS_VM) {
printf( " Virtual Memory" );
}
if (EventClassMask & RTL_EVENT_CLASS_PAGE_FAULT) {
printf( " Page Faults" );
}
if (EventClassMask & RTL_EVENT_CLASS_TRANSITION_FAULT) {
printf( " Transition Page Faults" );
}
printf( "\n" );
Event = (PRTL_EVENT)EventBuffer;
while (TRUE) {
if (EventLog->CountOfClients == 0) {
break;
}
Status = RtlWaitForEvent( EventLog, sizeof( EventBuffer ), Event, &EventId );
if (!NT_SUCCESS( Status )) {
fprintf( stderr, "RESMON: RtlWaitForEventFailed - %x\n", Status );
}
if (CreateProcessEventId == NULL &&
!_stricmp( EventId->Name, "CreateProcess" )
) {
CreateProcessEventId = EventId;
}
else
if (ExitProcessEventId == NULL &&
!_stricmp( EventId->Name, "ExitProcess" )
) {
ExitProcessEventId = EventId;
}
else
if (LoadModuleEventId == NULL &&
!_stricmp( EventId->Name, "LoadModule" )
) {
LoadModuleEventId = EventId;
}
else
if (UnloadModuleEventId == NULL &&
!_stricmp( EventId->Name, "UnloadModule" )
) {
UnloadModuleEventId = EventId;
}
else
if (PageFaultEventId == NULL &&
!_stricmp( EventId->Name, "PageFault" )
) {
PageFaultEventId = EventId;
}
if (CreateProcessEventId == EventId ||
LoadModuleEventId == EventId
) {
LoadSymbolsForEvent( Event, EventId );
DumpEvent( Event, EventId );
}
else
if (ExitProcessEventId == EventId) {
EventLog->CountOfClients -= 1;
DumpEvent( Event, EventId );
UnloadProcessForEvent( Event, EventId );
}
else
if (UnloadModuleEventId == EventId) {
DumpEvent( Event, EventId );
UnloadSymbolsForEvent( Event, EventId );
}
else {
DumpEvent( Event, EventId );
}
}
RtlDestroyEventLog( EventLog );
}
else {
if (ThreadToResume != NULL) {
fprintf( stderr, "RESMON: Unable (%x) to monitor Command '%s'\n", Status, CommandLine );
TerminateThread( ThreadToResume, GetLastError() );
CloseHandle( ThreadToResume );
}
else {
fprintf( stderr, "RESMON: Unable (%x) to monitor Process %d\n", Status, ProcessId );
}
}
return 0;
}
VOID
LoadSymbolsForEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
)
{
PULONG ParameterData;
PWSTR Src;
UNICODE_STRING UnicodeString;
ANSI_STRING ImageFilePath;
ULONG ImageBase;
ULONG ImageSize;
ParameterData = (PULONG)((PCHAR)Event + Event->OffsetToParameterData);
Src = (PWSTR)ParameterData;
RtlInitUnicodeString( &UnicodeString, Src );
RtlUnicodeStringToAnsiString( &ImageFilePath, &UnicodeString, TRUE );
while (*Src++) {
}
ParameterData = (PULONG)ALIGN_UP( Src, ULONG );
ImageBase = *ParameterData++;
ImageSize = *ParameterData++;
AddImageDebugInformation( Event->ClientId.UniqueProcess,
ImageFilePath.Buffer,
ImageBase,
ImageSize
);
RtlFreeAnsiString( &ImageFilePath );
return;
}
VOID
UnloadSymbolsForEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
)
{
PULONG ParameterData;
PWSTR Src;
UNICODE_STRING UnicodeString;
ANSI_STRING ImageFilePath;
ULONG ImageBase;
ParameterData = (PULONG)((PCHAR)Event + Event->OffsetToParameterData);
Src = (PWSTR)ParameterData;
RtlInitUnicodeString( &UnicodeString, Src );
RtlUnicodeStringToAnsiString( &ImageFilePath, &UnicodeString, TRUE );
while (*Src++) {
}
ParameterData = (PULONG)ALIGN_UP( Src, ULONG );
ImageBase = *ParameterData;
RemoveImageDebugInformation( Event->ClientId.UniqueProcess,
ImageFilePath.Buffer,
ImageBase
);
RtlFreeAnsiString( &ImageFilePath );
return;
}
VOID
UnloadProcessForEvent(
IN PRTL_EVENT Event,
PRTL_EVENT_ID_INFO EventId
)
{
PULONG ParameterData;
ULONG ExitCode;
ParameterData = (PULONG)((PCHAR)Event + Event->OffsetToParameterData);
ExitCode = *ParameterData;
RemoveImageDebugInformation( Event->ClientId.UniqueProcess,
NULL,
0
);
return;
}
VOID
DumpEvent(
IN PRTL_EVENT Event,
IN PRTL_EVENT_ID_INFO EventId
)
{
ULONG i, j;
PRTL_EVENT_PARAMETER_INFO ParameterInfo;
PRTL_EVENT_PARAMETER_VALUE_INFO ValueInfo;
PULONG ParameterData;
USHORT StackBackTraceLength;
ULONG StackBackTrace[ MAX_STACK_DEPTH ];
ULONG NumberFlagsFound;
PWSTR Src;
LPSTR AnsiSrc;
CHAR NameBuffer[ 256 ];
printf( "%04x.%04x - %s(",
Event->ClientId.UniqueProcess,
Event->ClientId.UniqueThread,
EventId->Name
);
ParameterData = (PULONG)((PCHAR)Event + Event->OffsetToParameterData);
if (StackBackTraceLength = Event->StackBackTraceLength) {
RtlMoveMemory( StackBackTrace, (Event + 1), StackBackTraceLength * sizeof( ULONG ));
}
ParameterInfo = (PRTL_EVENT_PARAMETER_INFO)
((PCHAR)EventId + EventId->OffsetToParameterInfo);
for (i=0; i<EventId->NumberOfParameters; i++) {
if (i != 0) {
printf( "," );
}
if (ParameterInfo->Label[ 0 ] != '\0') {
printf( " %s: ", ParameterInfo->Label );
}
else {
printf( " " );
}
switch( ParameterInfo->Type ) {
//
// No additional data for these parameter types;
//
case RTL_EVENT_STATUS_PARAM:
if (PageFaultEventId == EventId) {
switch (*ParameterData) {
case STATUS_PAGE_FAULT_TRANSITION: AnsiSrc = "Transition"; break;
case STATUS_PAGE_FAULT_DEMAND_ZERO: AnsiSrc = "DemandZero"; break;
case STATUS_PAGE_FAULT_COPY_ON_WRITE: AnsiSrc = "CopyOnWrite"; break;
case STATUS_PAGE_FAULT_GUARD_PAGE: AnsiSrc = "Guard"; break;
case STATUS_PAGE_FAULT_PAGING_FILE: AnsiSrc = "Disk"; break;
default:
AnsiSrc = NULL;
break;
}
}
else {
AnsiSrc = FindSymbolicNameForStatus( *ParameterData );
}
if (AnsiSrc) {
printf( "%s", AnsiSrc );
ParameterData += 1;
break;
}
case RTL_EVENT_ULONG_PARAM:
printf( "%08x", *ParameterData++ );
break;
case RTL_EVENT_ADDRESS_PARAM:
GetSymbolicNameForAddress( Event->ClientId.UniqueProcess,
*ParameterData++,
NameBuffer,
sizeof( NameBuffer )
);
printf( "%s", NameBuffer );
break;
case RTL_EVENT_ENUM_PARAM:
ValueInfo = (PRTL_EVENT_PARAMETER_VALUE_INFO)((PCHAR)ParameterInfo + ParameterInfo->OffsetToValueNames);
for (j=0; j<ParameterInfo->NumberOfValueNames; j++) {
if (ValueInfo->Value == *ParameterData) {
ParameterData += 1;
printf( "%s", ValueInfo->ValueName );
ValueInfo = NULL;
break;
}
ValueInfo = (PRTL_EVENT_PARAMETER_VALUE_INFO)
((PCHAR)ValueInfo + ValueInfo->Length);
}
if (ValueInfo) {
printf( "%08x", *ParameterData++ );
}
break;
case RTL_EVENT_FLAGS_PARAM:
ValueInfo = (PRTL_EVENT_PARAMETER_VALUE_INFO)((PCHAR)ParameterInfo + ParameterInfo->OffsetToValueNames);
NumberFlagsFound = 0;
for (j=0; j<ParameterInfo->NumberOfValueNames; j++) {
if (ValueInfo->Value & *ParameterData) {
if (NumberFlagsFound++ != 0) {
printf( " | " );
}
printf( "%s", ValueInfo->ValueName );
}
ValueInfo = (PRTL_EVENT_PARAMETER_VALUE_INFO)
((PCHAR)ValueInfo + ValueInfo->Length);
}
if (NumberFlagsFound == 0) {
printf( "%08x", *ParameterData );
}
ParameterData += 1;
break;
case RTL_EVENT_PWSTR_PARAM:
case RTL_EVENT_PUNICODE_STRING_PARAM:
Src = (PWSTR)ParameterData;
printf( "'%ws'", Src );
while (*Src++) {
}
ParameterData = (PULONG)ALIGN_UP( Src, ULONG );
break;
case RTL_EVENT_PANSI_STRING_PARAM:
AnsiSrc = (LPSTR)ParameterData;
printf( "'%s'", AnsiSrc );
while (*AnsiSrc++) {
}
ParameterData = (PULONG)ALIGN_UP( AnsiSrc, ULONG );
break;
case RTL_EVENT_STRUCTURE_PARAM:
default:
break;
}
ParameterInfo = (PRTL_EVENT_PARAMETER_INFO)
((PCHAR)ParameterInfo + ParameterInfo->Length);
}
printf( " )\n" );
for (i=0; i<StackBackTraceLength; i++) {
GetSymbolicNameForAddress( Event->ClientId.UniqueProcess,
StackBackTrace[ i ],
NameBuffer,
sizeof( NameBuffer )
);
printf( " %s\n", NameBuffer );
}
printf( " )\n" );
return;
}
LPSTR
FindSymbolicNameForStatus(
DWORD Id
)
{
ULONG i;
i = 0;
if (Id == 0) {
return "STATUS_SUCCESS";
}
if (Id & 0xC0000000) {
while (ntstatusSymbolicNames[ i ].SymbolicName) {
if (ntstatusSymbolicNames[ i ].MessageId == (NTSTATUS)Id) {
return ntstatusSymbolicNames[ i ].SymbolicName;
}
else {
i += 1;
}
}
}
while (winerrorSymbolicNames[ i ].SymbolicName) {
if (winerrorSymbolicNames[ i ].MessageId == Id) {
return winerrorSymbolicNames[ i ].SymbolicName;
}
else {
i += 1;
}
}
while (neteventSymbolicNames[ i ].SymbolicName) {
if (neteventSymbolicNames[ i ].MessageId == Id) {
return neteventSymbolicNames[ i ].SymbolicName;
}
else {
i += 1;
}
}
return NULL;
}
#endif // DBG