windows-nt/Source/XPSP1/NT/base/eventlog/ntsdexts/elfexts.c
2020-09-26 16:20:57 +08:00

768 lines
21 KiB
C

/*++
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);
}
}
}