|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
elfexts.c
Abstract:
This function contains the eventlog ntsd debugger extensions
Author:
Dan Hinsley (DanHi) 22-May-1993 IvanBrug 06 21 2001 converted to the latest debugger
Revision History:
--*/
#include <elfmain.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <elf.h>
#include <elfdef.h>
#include <elfcommn.h>
#include <elfproto.h>
#include <svcsp.h>
#include <elfextrn.h>
#define DbgPrint(_x_)
#define MAX_NAME 256
#define GET_DATA(DebugeeAddr, LocalAddr, Length) \
Status = ReadMemory( \ (MEMORY_ADDRESS)DebugeeAddr, \ (PVOID)LocalAddr, \ (ULONG)(Length), \ NULL \ );
HANDLE GlobalhCurrentProcess; BOOL Status;
LPWSTR GetUnicodeString( PUNICODE_STRING pUnicodeString ) { MEMORY_ADDRESS Pointer; UNICODE_STRING UnicodeString;
GET_DATA(pUnicodeString, &UnicodeString, sizeof(UNICODE_STRING)) Pointer = (MEMORY_ADDRESS) UnicodeString.Buffer; UnicodeString.Buffer = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, UnicodeString.Length + sizeof(WCHAR)); GET_DATA(Pointer, UnicodeString.Buffer, UnicodeString.Length)
return(UnicodeString.Buffer); }
MEMORY_ADDRESS GetLogFileAddress( LPSTR LogFileName, PLOGFILE LogFile ) { ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; MEMORY_ADDRESS Pointer = 0; MEMORY_ADDRESS LogFileAnchor = 0; LPWSTR ModuleName = 0; //
// Convert the string to UNICODE
//
RtlInitAnsiString(&AnsiString, LogFileName); RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
//
// Walk the logfile list looking for a match
//
LogFileAnchor = (MEMORY_ADDRESS)GetExpression("eventlog!LogFilesHead");
if (LogFileAnchor) { GET_DATA(LogFileAnchor, &Pointer, sizeof(MEMORY_ADDRESS));
while (Pointer != LogFileAnchor) { GET_DATA(Pointer, LogFile, sizeof(LOGFILE)) ModuleName = GetUnicodeString(LogFile->LogModuleName); if (!_wcsicmp(ModuleName, UnicodeString.Buffer)) { break; } LocalFree(ModuleName); Pointer = (MEMORY_ADDRESS) LogFile->FileList.Flink; } } else { dprintf("unable to resolve %s\n","eventlog!LogFilesHead"); }
RtlFreeUnicodeString(&UnicodeString);
if (Pointer == LogFileAnchor) { return(0); } else { LocalFree(ModuleName); return(Pointer); } }
//
// Dump an individual record
//
MEMORY_ADDRESS DumpRecord( MEMORY_ADDRESS Record, DWORD RecordNumber, MEMORY_ADDRESS StartOfFile, MEMORY_ADDRESS EndOfFile ) { MEMORY_ADDRESS BufferLen = 0; PCHAR TimeBuffer; PEVENTLOGRECORD EventLogRecord; LPWSTR Module; LPWSTR Computer; MEMORY_ADDRESS FirstPiece = 0; time_t TempAligned;
GET_DATA(Record, &BufferLen, sizeof(DWORD));
//
// See if it's a ELF_SKIP_DWORD, and if it is, return the top of the
// file
//
if (BufferLen == ELF_SKIP_DWORD) { return(StartOfFile + sizeof(ELF_LOGFILE_HEADER)); }
//
// See if it's the EOF record
//
if (BufferLen == ELFEOFRECORDSIZE) { return(0); }
BufferLen += sizeof(DWORD); // get room for length of next record
EventLogRecord = (PEVENTLOGRECORD) LocalAlloc(LMEM_ZEROINIT, BufferLen);
//
// If the record wraps, grab it piecemeal
//
if (EndOfFile && BufferLen + Record > EndOfFile) { FirstPiece = EndOfFile - Record; GET_DATA(Record, EventLogRecord, FirstPiece); GET_DATA((StartOfFile + sizeof(ELF_LOGFILE_HEADER)), ((PBYTE) EventLogRecord + FirstPiece), BufferLen - FirstPiece); } else { GET_DATA(Record, EventLogRecord, BufferLen); }
//
// If it's greater than the starting record, print it out
//
if (EventLogRecord->RecordNumber >= RecordNumber) { dprintf("\nRecord %d is %d [0x%X] bytes long starting at %p\n", EventLogRecord->RecordNumber, EventLogRecord->Length, EventLogRecord->Length, Record); Module = (LPWSTR)(EventLogRecord+1); Computer = (LPWSTR)((PBYTE) Module + ((wcslen(Module) + 1) * sizeof(WCHAR))); dprintf("\tGenerated by %ws from system %ws\n", Module, Computer);
TempAligned = EventLogRecord->TimeGenerated; TimeBuffer = ctime(&TempAligned); if (TimeBuffer) { dprintf("\tGenerated at %s", TimeBuffer); } else { dprintf("\tGenerated time field is blank\n"); } TempAligned = EventLogRecord->TimeWritten; TimeBuffer = ctime(&TempAligned); if (TimeBuffer) { dprintf("\tWritten at %s", TimeBuffer); } else { dprintf("\tTime written field is blank\n"); }
dprintf("\tEvent Id = %d\n", EventLogRecord->EventID); dprintf("\tEventType = "); switch (EventLogRecord->EventType) { case EVENTLOG_SUCCESS: dprintf("Success\n"); break; case EVENTLOG_ERROR_TYPE: dprintf("Error\n"); break; case EVENTLOG_WARNING_TYPE: dprintf("Warning\n"); break; case EVENTLOG_INFORMATION_TYPE: dprintf("Information\n"); break; case EVENTLOG_AUDIT_SUCCESS: dprintf("Audit Success\n"); break; case EVENTLOG_AUDIT_FAILURE: dprintf("Audit Failure\n"); break; default: dprintf("Invalid value 0x%X\n", EventLogRecord->EventType); } dprintf("\t%d strings at offset 0x%X\n", EventLogRecord->NumStrings, EventLogRecord->StringOffset); dprintf("\t%d bytes of data at offset 0x%X\n", EventLogRecord->DataLength, EventLogRecord->DataOffset); }
if (FirstPiece) { Record = StartOfFile + sizeof(ELF_LOGFILE_HEADER) + BufferLen -FirstPiece; } else { Record += EventLogRecord->Length; }
LocalFree(EventLogRecord); return(Record); }
//
// Dump a record, or all records, or n records
//
DECLARE_API(record) { MEMORY_ADDRESS Pointer = 0; LOGFILE LogFile; MEMORY_ADDRESS StartOfFile; MEMORY_ADDRESS EndOfFile = 0; DWORD RecordNumber = 0;
INIT_API(); //
// Evaluate the argument string to get the address of
// the record to dump.
//
while (isspace(*lpArgumentString)) lpArgumentString++;
if (lpArgumentString && *lpArgumentString) { if (*lpArgumentString == '.') { if (GetLogFileAddress(lpArgumentString+1, &LogFile) == 0) { dprintf("Logfile %s not found\n", lpArgumentString+1); return; } Pointer = ((MEMORY_ADDRESS ) (LogFile.BaseAddress)) + LogFile.BeginRecord; } else if (*lpArgumentString == '#') { RecordNumber = atoi(lpArgumentString + 1); dprintf("Dumping records starting at record #%d\n", RecordNumber); lpArgumentString = NULL; } else if (*lpArgumentString) { Pointer = GetExpression(lpArgumentString); } else { dprintf("Invalid lead character 0x%02X\n", *lpArgumentString); return; } }
//if (!lpArgumentString || *lpArgumentString) {
if (0 == Pointer){ if (GetLogFileAddress("system", &LogFile) == 0) { dprintf("System Logfile not found\n"); return; } Pointer = ((MEMORY_ADDRESS ) (LogFile.BaseAddress)) + LogFile.BeginRecord; }
StartOfFile = (MEMORY_ADDRESS ) LogFile.BaseAddress; EndOfFile = (MEMORY_ADDRESS ) LogFile.BaseAddress + LogFile.ActualMaxFileSize;
dprintf("%p %p %p\n",Pointer,StartOfFile,EndOfFile ); //
// Dump records starting wherever they told us to
//
while (Pointer < EndOfFile && Pointer && !CheckControlC()) { Pointer = DumpRecord(Pointer, RecordNumber, StartOfFile, EndOfFile); }
return; }
//
// Dump a single LogModule structure if it matches MatchName (NULL matches
// all)
//
PLIST_ENTRY DumpLogModule( MEMORY_ADDRESS pLogModule, LPWSTR MatchName ) { LOGMODULE LogModule; WCHAR ModuleName[MAX_NAME / sizeof(WCHAR)];
GET_DATA(pLogModule, &LogModule, sizeof(LogModule)); GET_DATA(LogModule.ModuleName, &ModuleName, MAX_NAME);
if (!MatchName || !_wcsicmp(MatchName, ModuleName)) { dprintf("\tModule Name %S\n", ModuleName); dprintf("\tModule Atom 0x%2x\n", LogModule.ModuleAtom); dprintf("\tPointer to LogFile %p\n", LogModule.LogFile); }
return (LogModule.ModuleList.Flink); }
//
// Dump selected, or all, LogModule structures
//
DECLARE_API(logmodule) { MEMORY_ADDRESS pLogModule = 0; MEMORY_ADDRESS LogModuleAnchor = 0; LPWSTR wArgumentString = NULL; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString;
INIT_API();
UnicodeString.Buffer = NULL;
//
// Evaluate the argument string to get the address of
// the logmodule to dump. If no parm, dump them all.
//
while (isspace(*lpArgumentString)) lpArgumentString++; if (lpArgumentString && *lpArgumentString == '.') { lpArgumentString++; RtlInitAnsiString(&AnsiString, lpArgumentString); RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); } else if (lpArgumentString && *lpArgumentString) { pLogModule = GetExpression(lpArgumentString); DumpLogModule( pLogModule, NULL); return; }
LogModuleAnchor = GetExpression("eventlog!LogModuleHead");
if (LogModuleAnchor) { GET_DATA(LogModuleAnchor, &pLogModule, sizeof(MEMORY_ADDRESS));
while (pLogModule != LogModuleAnchor && !CheckControlC()) { pLogModule = (MEMORY_ADDRESS) DumpLogModule( pLogModule, UnicodeString.Buffer); if (!UnicodeString.Buffer) { dprintf("\n"); } } } else { dprintf("Unable ro resolve %s\n","eventlog!LogModuleHead"); } if (UnicodeString.Buffer) { RtlFreeUnicodeString(&UnicodeString); }
return; }
//
// Dump a single LogFile structure if it matches MatchName (NULL matches
// all)
//
PLIST_ENTRY DumpLogFile( HANDLE hCurrentProcess, MEMORY_ADDRESS pLogFile, LPWSTR MatchName ) { LOGFILE LogFile; LPWSTR UnicodeName;
//
// Get the fixed part of the structure
//
GET_DATA(pLogFile, &LogFile, sizeof(LogFile))
//
// Get the Default module name
//
UnicodeName = GetUnicodeString(LogFile.LogModuleName);
//
// See if we're just looking for a particular one. If we are and
// this isn't it, bail out.
//
if (MatchName && _wcsicmp(MatchName, UnicodeName)) { LocalFree(UnicodeName); return (LogFile.FileList.Flink); }
//
// Otherwise print it out
//
dprintf("%ws", UnicodeName); LocalFree(UnicodeName);
//
// Now the file name of this logfile
//
UnicodeName = GetUnicodeString(LogFile.LogFileName); dprintf(" : %ws\n", UnicodeName); LocalFree(UnicodeName);
if (LogFile.Notifiees.Flink == LogFile.Notifiees.Blink) { dprintf("\tNo active ChangeNotifies on this log\n"); } else { dprintf("\tActive Change Notify! Dump of this list not implemented\n"); }
dprintf("\tReference Count: %d\n\tFlags: ", LogFile.RefCount); if (LogFile.Flags == 0) { dprintf("No flags set "); } else { if (LogFile.Flags & ELF_LOGFILE_HEADER_DIRTY) { dprintf("Dirty "); } if (LogFile.Flags & ELF_LOGFILE_HEADER_WRAP) { dprintf("Wrapped "); } if (LogFile.Flags & ELF_LOGFILE_LOGFULL_WRITTEN) { dprintf("Logfull Written "); } } dprintf("\n");
dprintf("\tMax Files Sizes [Cfg:Curr:Next] 0x%X : 0x%X : 0x%X\n", LogFile.ConfigMaxFileSize, LogFile.ActualMaxFileSize, LogFile.NextClearMaxFileSize);
dprintf("\tRecord Numbers [Oldest:Curr] %d : %d\n", LogFile.OldestRecordNumber, LogFile.CurrentRecordNumber);
dprintf("\tRetention period in days: %d\n", LogFile.Retention / 86400);
dprintf("\tBase Address: 0x%X\n", LogFile.BaseAddress);
dprintf("\tView size: 0x%X\n", LogFile.ViewSize);
dprintf("\tOffset of beginning record: 0x%X\n", LogFile.BeginRecord);
dprintf("\tOffset of ending record: 0x%X\n", LogFile.EndRecord);
return (LogFile.FileList.Flink); }
//
// Dump selected, or all, LogFile structures
//
DECLARE_API(logfile) { MEMORY_ADDRESS pLogFile; MEMORY_ADDRESS LogFileAnchor; LPWSTR wArgumentString = NULL; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; BOOL AllocateString = FALSE;
INIT_API();
UnicodeString.Buffer = NULL;
//
// Evaluate the argument string to get the address of
// the logfile to dump. If no parm, dump them all.
//
while (isspace(*lpArgumentString)) lpArgumentString++;
if (lpArgumentString && *lpArgumentString) { if(*lpArgumentString == '.') { lpArgumentString++; RtlInitAnsiString(&AnsiString, lpArgumentString); RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); } else { pLogFile = GetExpression(lpArgumentString); DumpLogFile(hCurrentProcess, pLogFile, NULL); return; } }
LogFileAnchor = GetExpression("eventlog!LogFilesHead");
GET_DATA(LogFileAnchor, &pLogFile, sizeof(MEMORY_ADDRESS))
while (pLogFile != LogFileAnchor) { pLogFile = (MEMORY_ADDRESS) DumpLogFile(hCurrentProcess, pLogFile, UnicodeString.Buffer); if (!UnicodeString.Buffer) { dprintf("\n"); } }
if (UnicodeString.Buffer) { RtlFreeUnicodeString(&UnicodeString); }
return; }
//
// Dump a request packet structure
//
DECLARE_API(request) { ELF_REQUEST_RECORD Request; MEMORY_ADDRESS Pointer; DWORD RecordSize; WRITE_PKT WritePkt; READ_PKT ReadPkt; CLEAR_PKT ClearPkt; BACKUP_PKT BackupPkt; LPWSTR FileName; CHAR Address[32];
INIT_API();
//
// Evaluate the argument string to get the address of
// the request packet to dump.
//
while (isspace(*lpArgumentString)) lpArgumentString++;
if (lpArgumentString && *lpArgumentString) { Pointer = GetExpression(lpArgumentString); } else { dprintf("Must supply a request packet address\n"); return; }
GET_DATA(Pointer, &Request, sizeof(ELF_REQUEST_RECORD))
switch (Request.Command ) { case ELF_COMMAND_READ: dprintf("\nRead packet\n"); GET_DATA(Request.Pkt.ReadPkt, &ReadPkt, sizeof(READ_PKT)) dprintf("\tLast Seek Position = %d\n", ReadPkt.LastSeekPos); dprintf("\tLast Seek Record = %d\n", ReadPkt.LastSeekRecord); dprintf("\tStart at record number %d\n", ReadPkt.RecordNumber); dprintf("\tRead %d bytes into buffer at 0x%X\n", ReadPkt.BufferSize, ReadPkt.Buffer); if (ReadPkt.Flags & ELF_IREAD_UNICODE) { dprintf("\tReturn in ANSI\n"); } else { dprintf("\tReturn in UNICODE\n"); } dprintf("\tRead flags: "); if (ReadPkt.ReadFlags & EVENTLOG_SEQUENTIAL_READ) { dprintf("Sequential "); } if (ReadPkt.ReadFlags & EVENTLOG_SEEK_READ) { dprintf("Seek "); } if (ReadPkt.ReadFlags & EVENTLOG_FORWARDS_READ) { dprintf("Forward "); } if (ReadPkt.ReadFlags & EVENTLOG_BACKWARDS_READ) { dprintf("Backwards "); } dprintf("\n"); break;
case ELF_COMMAND_WRITE: dprintf("\nWrite packet\n"); if (Request.Flags == ELF_FORCE_OVERWRITE) { dprintf("with ELF_FORCE_OVERWRITE enabled\n"); } else { dprintf("\n"); } GET_DATA(Request.Pkt.WritePkt, &WritePkt, sizeof(WRITE_PKT)) RecordSize = (WritePkt.Datasize); DumpRecord((MEMORY_ADDRESS)WritePkt.Buffer, 0, 0, 0); break;
case ELF_COMMAND_CLEAR: dprintf("\nClear packet\n"); GET_DATA(Request.Pkt.ClearPkt, &ClearPkt, sizeof(CLEAR_PKT)) FileName = GetUnicodeString(ClearPkt.BackupFileName); dprintf("Backup filename = %ws\n", FileName); LocalFree(FileName); break;
case ELF_COMMAND_BACKUP: dprintf("\nBackup packet\n"); GET_DATA(Request.Pkt.BackupPkt, &BackupPkt, sizeof(BACKUP_PKT)) FileName = GetUnicodeString(BackupPkt.BackupFileName); dprintf("Backup filename = %ws\n", FileName); LocalFree(FileName); break;
case ELF_COMMAND_WRITE_QUEUED: dprintf("\nQueued Write packet\n"); if (Request.Flags == ELF_FORCE_OVERWRITE) { dprintf("with ELF_FORCE_OVERWRITE enabled\n"); } else { dprintf("\n"); } dprintf("NtStatus = 0x%X\n", Request.Status); break;
default: dprintf("\nInvalid packet\n"); }
dprintf("\nLogFile for this packet:\n\n"); sprintf(Address,"%p",Request.LogFile); logfile(hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, Address);
dprintf("\nLogModule for this packet:\n\n"); sprintf(Address,"%p",Request.Module); logmodule(hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, Address);
return; }
//
// Online help
//
DECLARE_API(help) { INIT_API(); dprintf("\nEventlog debugger Extensions\n");
if (!lpArgumentString || *lpArgumentString == '\0' || *lpArgumentString == '\n' || *lpArgumentString == '\r') { dprintf("\tlogmodule - dump a logmodule structure\n"); dprintf("\tlogfile - dump a logfile structure\n"); dprintf("\trequest - dump a request record\n"); dprintf("\trecord - dump a eventlog record\n"); dprintf("\n\tEnter help <cmd> for detailed help on a command\n"); } else { if (!_stricmp(lpArgumentString, "logmodule")) { dprintf("\tlogmodule <arg>, where <arg> can be one of:\n"); dprintf("\t\tno argument - dump all logmodule structures\n"); dprintf("\t\taddress - dump the logmodule at specified address\n"); dprintf("\t\t.string - dump the logmodule with name string\n"); } else if (!_stricmp(lpArgumentString, "logfile")) { dprintf("\tlogfile <arg>, where <arg> can be one of:\n"); dprintf("\t\tno argument - dump all logfile structures\n"); dprintf("\t\taddress - dump the logfile at specified address\n"); dprintf("\t\t.string - dump the logfile with name string\n"); } else if (!_stricmp(lpArgumentString, "record")) { dprintf("\trecord <arg>, where <arg> can be one of:\n"); dprintf("\t\tno argument - dump all records in system log\n"); dprintf("\t\taddress - dump records starting at specified address\n"); dprintf("\t\t.string - dump all records in the <string> log\n"); dprintf("\t\t#<nnn> - dumps records starting at nnn in system log\n"); dprintf("\t\t#<nnn> .string - dumps records starting at nnn in <string> log\n"); } else if (!_stricmp(lpArgumentString, "request")) { dprintf("\trequest - dump the request record at specified address\n"); } else { dprintf("\tInvalid command [%s]\n", lpArgumentString); } } }
|