|
|
/*++
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
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 <elf.h>
#include <elfdef.h>
#include <elfcommn.h>
#include <elfproto.h>
#include <svcsp.h>
#include <elfextrn.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 \ );
PNTSD_OUTPUT_ROUTINE lpOutputRoutine; PNTSD_GET_EXPRESSION lpGetExpressionRoutine; PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
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; }
LPWSTR GetUnicodeString( PUNICODE_STRING pUnicodeString ) { DWORD Pointer; UNICODE_STRING UnicodeString;
GET_DATA(pUnicodeString, &UnicodeString, sizeof(UNICODE_STRING)) Pointer = (DWORD) UnicodeString.Buffer; UnicodeString.Buffer = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, UnicodeString.Length + sizeof(WCHAR)); GET_DATA(Pointer, UnicodeString.Buffer, UnicodeString.Length)
return(UnicodeString.Buffer); }
DWORD GetLogFileAddress( LPSTR LogFileName, PLOGFILE LogFile ) { ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; DWORD Pointer; DWORD LogFileAnchor; LPWSTR ModuleName;
//
// Convert the string to UNICODE
//
RtlInitAnsiString(&AnsiString, LogFileName); RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
//
// Walk the logfile list looking for a match
//
LogFileAnchor = (lpGetExpressionRoutine)("LogFilesHead");
GET_DATA(LogFileAnchor, &Pointer, sizeof(DWORD))
while (Pointer != LogFileAnchor) { GET_DATA(Pointer, LogFile, sizeof(LOGFILE)) ModuleName = GetUnicodeString(LogFile->LogModuleName); if (!_wcsicmp(ModuleName, UnicodeString.Buffer)) { break; } LocalFree(ModuleName); Pointer = (DWORD) LogFile->FileList.Flink; }
RtlFreeUnicodeString(&UnicodeString);
if (Pointer == LogFileAnchor) { return(0); } else { LocalFree(ModuleName); return(Pointer); } }
//
// Dump an individual record
//
DWORD DumpRecord( DWORD Record, DWORD RecordNumber, DWORD StartOfFile, DWORD EndOfFile ) { DWORD BufferLen; PCHAR TimeBuffer; PEVENTLOGRECORD EventLogRecord; LPWSTR Module; LPWSTR Computer; DWORD FirstPiece = 0;
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) { printf("\nRecord %d is %d [0x%X] bytes long starting at 0x%X\n", EventLogRecord->RecordNumber, EventLogRecord->Length, EventLogRecord->Length, Record); Module = (LPWSTR)(EventLogRecord+1); Computer = (LPWSTR)((PBYTE) Module + ((wcslen(Module) + 1) * sizeof(WCHAR))); printf("\tGenerated by %ws from system %ws\n", Module, Computer);
TimeBuffer = ctime((time_t *)&(EventLogRecord->TimeGenerated)); if (TimeBuffer) { printf("\tGenerated at %s", TimeBuffer); } else { printf("\tGenerated time field is blank\n"); } TimeBuffer = ctime((time_t *)&(EventLogRecord->TimeWritten)); if (TimeBuffer) { printf("\tWritten at %s", TimeBuffer); } else { printf("\tTime written field is blank\n"); }
printf("\tEvent Id = %d\n", EventLogRecord->EventID); printf("\tEventType = "); switch (EventLogRecord->EventType) { case EVENTLOG_SUCCESS: printf("Success\n"); break; case EVENTLOG_ERROR_TYPE: printf("Error\n"); break; case EVENTLOG_WARNING_TYPE: printf("Warning\n"); break; case EVENTLOG_INFORMATION_TYPE: printf("Information\n"); break; case EVENTLOG_AUDIT_SUCCESS: printf("Audit Success\n"); break; case EVENTLOG_AUDIT_FAILURE: printf("Audit Failure\n"); break; default: printf("Invalid value 0x%X\n", EventLogRecord->EventType); } printf("\t%d strings at offset 0x%X\n", EventLogRecord->NumStrings, EventLogRecord->StringOffset); printf("\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
//
VOID record( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { DWORD Pointer; LOGFILE LogFile; DWORD StartOfFile; DWORD EndOfFile = 0; DWORD RecordNumber = 0;
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
//
// Evaluate the argument string to get the address of
// the record to dump.
//
if (lpArgumentString && *lpArgumentString) { if (*lpArgumentString == '.') { if (GetLogFileAddress(lpArgumentString+1, &LogFile) == 0) { printf("Logfile %s not found\n", lpArgumentString+1); return; } Pointer = ((DWORD) (LogFile.BaseAddress)) + LogFile.BeginRecord; } else if (*lpArgumentString == '#') { RecordNumber = atoi(lpArgumentString + 1); printf("Dumping records starting at record #%d\n", RecordNumber); lpArgumentString = NULL; } else if (*lpArgumentString) { Pointer = (lpGetExpressionRoutine)(lpArgumentString); } else { printf("Invalid lead character 0x%02X\n", *lpArgumentString); return; } }
if (!lpArgumentString || *lpArgumentString) { if (GetLogFileAddress("system", &LogFile) == 0) { printf("System Logfile not found\n"); return; } Pointer = ((DWORD) (LogFile.BaseAddress)) + LogFile.BeginRecord; }
StartOfFile = (DWORD) LogFile.BaseAddress; EndOfFile = (DWORD) LogFile.BaseAddress + LogFile.ActualMaxFileSize;
//
// Dump records starting wherever they told us to
//
while (Pointer < EndOfFile && Pointer && !(lpCheckControlCRoutine)()) { Pointer = DumpRecord(Pointer, RecordNumber, StartOfFile, EndOfFile); }
return; }
//
// Dump a single LogModule structure if it matches MatchName (NULL matches
// all)
//
PLIST_ENTRY DumpLogModule( HANDLE hCurrentProcess, DWORD 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)) { printf("\tModule Name %ws\n", ModuleName); printf("\tModule Atom 0x%X\n", LogModule.ModuleAtom); printf("\tPointer to LogFile 0x%X\n", LogModule.LogFile); }
return (LogModule.ModuleList.Flink); }
//
// Dump selected, or all, LogModule structures
//
VOID logmodule( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { DWORD pLogModule; DWORD LogModuleAnchor; LPWSTR wArgumentString = NULL; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString;
InitFunctionPointers(hCurrentProcess, lpExtensionApis); UnicodeString.Buffer = NULL;
//
// Evaluate the argument string to get the address of
// the logmodule to dump. If no parm, dump them all.
//
if (lpArgumentString && *lpArgumentString == '.') { lpArgumentString++; RtlInitAnsiString(&AnsiString, lpArgumentString); RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); } else if (lpArgumentString && *lpArgumentString) { pLogModule = (lpGetExpressionRoutine)(lpArgumentString); DumpLogModule(hCurrentProcess, pLogModule, NULL); return; }
LogModuleAnchor = (lpGetExpressionRoutine)("LogModuleHead");
GET_DATA(LogModuleAnchor, &pLogModule, sizeof(DWORD))
while (pLogModule != LogModuleAnchor && !(lpCheckControlCRoutine)()) { pLogModule = (DWORD) DumpLogModule(hCurrentProcess, pLogModule, UnicodeString.Buffer); if (!UnicodeString.Buffer) { printf("\n"); } } if (UnicodeString.Buffer) { RtlFreeUnicodeString(&UnicodeString); }
return; }
//
// Dump a single LogFile structure if it matches MatchName (NULL matches
// all)
//
PLIST_ENTRY DumpLogFile( HANDLE hCurrentProcess, DWORD 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
//
printf("%ws", UnicodeName); LocalFree(UnicodeName);
//
// Now the file name of this logfile
//
UnicodeName = GetUnicodeString(LogFile.LogFileName); printf(" : %ws\n", UnicodeName); LocalFree(UnicodeName);
if (LogFile.Notifiees.Flink == LogFile.Notifiees.Blink) { printf("\tNo active ChangeNotifies on this log\n"); } else { printf("\tActive Change Notify! Dump of this list not implemented\n"); }
printf("\tReference Count: %d\n\tFlags: ", LogFile.RefCount); if (LogFile.Flags == 0) { printf("No flags set "); } else { if (LogFile.Flags & ELF_LOGFILE_HEADER_DIRTY) { printf("Dirty "); } if (LogFile.Flags & ELF_LOGFILE_HEADER_WRAP) { printf("Wrapped "); } if (LogFile.Flags & ELF_LOGFILE_LOGFULL_WRITTEN) { printf("Logfull Written "); } } printf("\n");
printf("\tMax Files Sizes [Cfg:Curr:Next] 0x%X : 0x%X : 0x%X\n", LogFile.ConfigMaxFileSize, LogFile.ActualMaxFileSize, LogFile.NextClearMaxFileSize);
printf("\tRecord Numbers [Oldest:Curr] %d : %d\n", LogFile.OldestRecordNumber, LogFile.CurrentRecordNumber);
printf("\tRetention period in days: %d\n", LogFile.Retention / 86400);
printf("\tBase Address: 0x%X\n", LogFile.BaseAddress);
printf("\tView size: 0x%X\n", LogFile.ViewSize);
printf("\tOffset of beginning record: 0x%X\n", LogFile.BeginRecord);
printf("\tOffset of ending record: 0x%X\n", LogFile.EndRecord);
return (LogFile.FileList.Flink); }
//
// Dump selected, or all, LogFile structures
//
VOID logfile( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { DWORD pLogFile; DWORD LogFileAnchor; LPWSTR wArgumentString = NULL; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; BOOL AllocateString = FALSE;
InitFunctionPointers(hCurrentProcess, lpExtensionApis); UnicodeString.Buffer = NULL;
//
// Evaluate the argument string to get the address of
// the logfile to dump. If no parm, dump them all.
//
if (lpArgumentString && *lpArgumentString) { if(*lpArgumentString == '.') { lpArgumentString++; RtlInitAnsiString(&AnsiString, lpArgumentString); RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); } else { pLogFile = (lpGetExpressionRoutine)(lpArgumentString); DumpLogFile(hCurrentProcess, pLogFile, NULL); return; } }
LogFileAnchor = (lpGetExpressionRoutine)("LogFilesHead");
GET_DATA(LogFileAnchor, &pLogFile, sizeof(DWORD))
while (pLogFile != LogFileAnchor) { pLogFile = (DWORD) DumpLogFile(hCurrentProcess, pLogFile, UnicodeString.Buffer); if (!UnicodeString.Buffer) { printf("\n"); } }
if (UnicodeString.Buffer) { RtlFreeUnicodeString(&UnicodeString); }
return; }
//
// Dump a request packet structure
//
VOID request( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { ELF_REQUEST_RECORD Request; DWORD Pointer; DWORD RecordSize; WRITE_PKT WritePkt; READ_PKT ReadPkt; CLEAR_PKT ClearPkt; BACKUP_PKT BackupPkt; LPWSTR FileName; CHAR Address[18];
InitFunctionPointers(hCurrentProcess, lpExtensionApis);
//
// Evaluate the argument string to get the address of
// the request packet to dump.
//
if (lpArgumentString && *lpArgumentString) { Pointer = (lpGetExpressionRoutine)(lpArgumentString); } else { printf("Must supply a request packet address\n"); return; }
GET_DATA(Pointer, &Request, sizeof(ELF_REQUEST_RECORD))
switch (Request.Command ) { case ELF_COMMAND_READ: printf("\nRead packet\n"); GET_DATA(Request.Pkt.ReadPkt, &ReadPkt, sizeof(READ_PKT)) printf("\tLast Seek Position = %d\n", ReadPkt.LastSeekPos); printf("\tLast Seek Record = %d\n", ReadPkt.LastSeekRecord); printf("\tStart at record number %d\n", ReadPkt.RecordNumber); printf("\tRead %d bytes into buffer at 0x%X\n", ReadPkt.BufferSize, ReadPkt.Buffer); if (ReadPkt.Flags & ELF_IREAD_UNICODE) { printf("\tReturn in ANSI\n"); } else { printf("\tReturn in UNICODE\n"); } printf("\tRead flags: "); if (ReadPkt.ReadFlags & EVENTLOG_SEQUENTIAL_READ) { printf("Sequential "); } if (ReadPkt.ReadFlags & EVENTLOG_SEEK_READ) { printf("Seek "); } if (ReadPkt.ReadFlags & EVENTLOG_FORWARDS_READ) { printf("Forward "); } if (ReadPkt.ReadFlags & EVENTLOG_BACKWARDS_READ) { printf("Backwards "); } printf("\n"); break;
case ELF_COMMAND_WRITE: printf("\nWrite packet\n"); if (Request.Flags == ELF_FORCE_OVERWRITE) { printf("with ELF_FORCE_OVERWRITE enabled\n"); } else { printf("\n"); } GET_DATA(Request.Pkt.WritePkt, &WritePkt, sizeof(WRITE_PKT)) RecordSize = (WritePkt.Datasize); DumpRecord((DWORD)WritePkt.Buffer, 0, 0, 0); break;
case ELF_COMMAND_CLEAR: printf("\nClear packet\n"); GET_DATA(Request.Pkt.ClearPkt, &ClearPkt, sizeof(CLEAR_PKT)) FileName = GetUnicodeString(ClearPkt.BackupFileName); printf("Backup filename = %ws\n", FileName); LocalFree(FileName); break;
case ELF_COMMAND_BACKUP: printf("\nBackup packet\n"); GET_DATA(Request.Pkt.BackupPkt, &BackupPkt, sizeof(BACKUP_PKT)) FileName = GetUnicodeString(BackupPkt.BackupFileName); printf("Backup filename = %ws\n", FileName); LocalFree(FileName); break;
case ELF_COMMAND_WRITE_QUEUED: printf("\nQueued Write packet\n"); if (Request.Flags == ELF_FORCE_OVERWRITE) { printf("with ELF_FORCE_OVERWRITE enabled\n"); } else { printf("\n"); } printf("NtStatus = 0x%X\n", Request.Status); break;
default: printf("\nInvalid packet\n"); }
printf("\nLogFile for this packet:\n\n"); _itoa((DWORD) Request.LogFile, Address, 16); logfile(hCurrentProcess, hCurrentThread, dwCurrentPc, lpExtensionApis, Address);
printf("\nLogModule for this packet:\n\n"); _itoa((DWORD)Request.Module, Address, 16); logmodule(hCurrentProcess, hCurrentThread, dwCurrentPc, lpExtensionApis, Address);
return; }
//
// Online help
//
VOID help( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { InitFunctionPointers(hCurrentProcess, lpExtensionApis);
printf("\nEventlog NTSD Extensions\n");
if (!lpArgumentString || *lpArgumentString == '\0' || *lpArgumentString == '\n' || *lpArgumentString == '\r') { printf("\tlogmodule - dump a logmodule structure\n"); printf("\tlogfile - dump a logfile structure\n"); printf("\trequest - dump a request record\n"); printf("\trecord - dump a eventlog record\n"); printf("\n\tEnter help <cmd> for detailed help on a command\n"); } else { if (!_stricmp(lpArgumentString, "logmodule")) { printf("\tlogmodule <arg>, where <arg> can be one of:\n"); printf("\t\tno argument - dump all logmodule structures\n"); printf("\t\taddress - dump the logmodule at specified address\n"); printf("\t\t.string - dump the logmodule with name string\n"); } else if (!_stricmp(lpArgumentString, "logfile")) { printf("\tlogfile <arg>, where <arg> can be one of:\n"); printf("\t\tno argument - dump all logfile structures\n"); printf("\t\taddress - dump the logfile at specified address\n"); printf("\t\t.string - dump the logfile with name string\n"); } else if (!_stricmp(lpArgumentString, "record")) { printf("\trecord <arg>, where <arg> can be one of:\n"); printf("\t\tno argument - dump all records in system log\n"); printf("\t\taddress - dump records starting at specified address\n"); printf("\t\t.string - dump all records in the <string> log\n"); printf("\t\t#<nnn> - dumps records starting at nnn in system log\n"); printf("\t\t#<nnn> .string - dumps records starting at nnn in <string> log\n"); } else if (!_stricmp(lpArgumentString, "request")) { printf("\trequest - dump the request record at specified address\n"); } else { printf("\tInvalid command [%s]\n", lpArgumentString); } } }
|