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

1062 lines
23 KiB
C

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
wow64log.c
Abstract:
Main entrypoints for wow64log.dll. To add a data type handler :
1- Define a LOGDATATYPE for the data to log in w64logp.h
2- Implement the data type handler using the standard interface
NTSTATUS
LogDataType(IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn);
3- Insert the handler into LogDataType[] below.
Author:
03-Oct-1999 SamerA
Revision History:
--*/
#include "w64logp.h"
/// Public
//
// Control logging flags
//
UINT_PTR Wow64LogFlags;
HANDLE Wow64LogFileHandle;
/// Private
//
// Hold an array of pointers to each system service DebugThunkInfo
//
PULONG_PTR *LogNtBase;
PULONG_PTR *LogWin32;
PULONG_PTR *LogConsole;
PULONG_PTR *LogBase;
//
// NOTE : The order entries in this table should match the LOGTYPE enum in
// w64logp.h.
//
LOGDATATYPE LogDataType[] =
{
{LogTypeValue}, // TypeHex
{LogTypePULongInOut}, // TypePULongPtrInOut
{LogTypePULongOut}, // TypePULONGOut
{LogTypePULongOut}, // TypePHandleOut
{LogTypeUnicodeString}, // TypeUnicodeStringIn
{LogTypeObjectAttrbiutes}, // TypeObjectAttributesIn
{LogTypeIoStatusBlock}, // TypeIoStatusBlockOut
{LogTypePWStr}, // TypePwstrIn
{LogTypePRectIn}, // TypePRectIn
{LogTypePLargeIntegerIn}, // TypePLargeIntegerIn
};
WOW64LOGAPI
NTSTATUS
Wow64LogInitialize(
VOID)
/*++
Routine Description:
This function is called by wow64.dll to initialize wow64 logging
subsystem.
Arguments:
None
Return Value:
NTSTATUS
--*/
{
ULONG NtBaseTableSize, Win32TableSize, ConsoleTableSize, BaseTableSize;
PULONG_PTR *Win32ThunkDebugInfo;
PULONG_PTR *ConsoleThunkDebugInfo;
UNICODE_STRING Log2Name;
PVOID Log2Handle;
NTSTATUS st;
//
// Initialize the logging file handle
//
Wow64LogFileHandle = INVALID_HANDLE_VALUE;
//
// Initialize the logging flags
//
LogInitializeFlags(&Wow64LogFlags);
WOW64LOGOUTPUT((LF_TRACE, "Wow64LogInitialize - Wow64LogFlags = %I64x\n", Wow64LogFlags));
//
// Load the Win32 logging DLL if available.
//
RtlInitUnicodeString(&Log2Name, L"wow64lg2.dll");
st = LdrLoadDll(NULL, NULL, &Log2Name, &Log2Handle);
if (NT_SUCCESS(st)) {
ANSI_STRING ExportName;
RtlInitAnsiString(&ExportName, "Win32ThunkDebugInfo");
st = LdrGetProcedureAddress(Log2Handle, &ExportName, 0, &(PVOID)Win32ThunkDebugInfo);
if (NT_SUCCESS(st)) {
RtlInitAnsiString(&ExportName, "ConsoleThunkDebugInfo");
st = LdrGetProcedureAddress(Log2Handle, &ExportName, 0, &(PVOID)ConsoleThunkDebugInfo);
}
}
if (!NT_SUCCESS(st)) {
Log2Handle = NULL;
Win32ThunkDebugInfo = NULL;
ConsoleThunkDebugInfo = NULL;
}
//
// Build pointers to the debug thunk info for each
// system service
//
NtBaseTableSize = GetThunkDebugTableSize(
(PTHUNK_DEBUG_INFO)NtThunkDebugInfo);
BaseTableSize = GetThunkDebugTableSize(
(PTHUNK_DEBUG_INFO)BaseThunkDebugInfo);
if (Log2Handle) {
Win32TableSize = GetThunkDebugTableSize(
(PTHUNK_DEBUG_INFO)Win32ThunkDebugInfo);
ConsoleTableSize = GetThunkDebugTableSize(
(PTHUNK_DEBUG_INFO)ConsoleThunkDebugInfo);
} else {
Win32TableSize = 0;
ConsoleTableSize = 0;
}
LogNtBase = (PULONG_PTR *)Wow64AllocateHeap((NtBaseTableSize + Win32TableSize + ConsoleTableSize + BaseTableSize) *
sizeof(PULONG_PTR) );
if (!LogNtBase)
{
WOW64LOGOUTPUT((LF_ERROR, "Wow64LogInitialize - Wow64AllocateHeap failed\n"));
return STATUS_UNSUCCESSFUL;
}
LogWin32 = LogNtBase + NtBaseTableSize;
LogConsole = LogWin32 + Win32TableSize;
LogBase = LogConsole + ConsoleTableSize;
BuildDebugThunkInfo((PTHUNK_DEBUG_INFO)NtThunkDebugInfo, LogNtBase);
BuildDebugThunkInfo((PTHUNK_DEBUG_INFO)BaseThunkDebugInfo, LogBase);
if (Log2Handle) {
BuildDebugThunkInfo((PTHUNK_DEBUG_INFO)Win32ThunkDebugInfo, LogWin32);
BuildDebugThunkInfo((PTHUNK_DEBUG_INFO)ConsoleThunkDebugInfo, LogConsole);
}
return STATUS_SUCCESS;
}
WOW64LOGAPI
NTSTATUS
Wow64LogTerminate(
VOID)
/*++
Routine Description:
This function is called by wow64.dll when the process is exiting.
Arguments:
None
Return Value:
NTSTATUS
--*/
{
IO_STATUS_BLOCK IoStatusBlock;
if (Wow64LogFileHandle != INVALID_HANDLE_VALUE)
{
NtFlushBuffersFile(Wow64LogFileHandle, &IoStatusBlock);
NtClose(Wow64LogFileHandle);
}
return STATUS_SUCCESS;
}
NTSTATUS
LogInitializeFlags(
IN OUT PUINT_PTR Flags)
/*++
Routine Description:
Reads the logging flags from the registry
Arguments:
Flags - Pointer to receive logging flags
Return Value:
NTSTATUS
--*/
{
HANDLE Key;
UNICODE_STRING KeyName, ValueName, ResultValue;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR KeyValueBuffer[ 128 ];
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
ULONG ResultLength, RegFlags;
NTSTATUS NtStatus;
//
// Punch in the default
//
*Flags = LF_DEFAULT;
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
NtStatus = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(NtStatus))
{
RtlInitUnicodeString(&ValueName, L"WOW64LOGFLAGS");
NtStatus = NtQueryValueKey(Key,
&ValueName,
KeyValuePartialInformation,
KeyValueInformation,
sizeof(KeyValueBuffer),
&ResultLength);
if (NT_SUCCESS(NtStatus))
{
if ((KeyValueInformation->Type == REG_DWORD) &&
(KeyValueInformation->DataLength == sizeof(DWORD)))
{
*Flags = *((PULONG)KeyValueInformation->Data);
}
}
}
return NtStatus;
}
ULONG
GetThunkDebugTableSize(
IN PTHUNK_DEBUG_INFO DebugInfoTable)
/*++
Routine Description:
This routine retreives the number of DebugThunkInfo entries
in the passed table.
Arguments:
DebugInfoTable - Pointer to services debug info
Return Value:
Number of entries
--*/
{
ULONG Count = 0;
while (DebugInfoTable && DebugInfoTable->ApiName)
{
Count++;
DebugInfoTable = (PTHUNK_DEBUG_INFO)
&DebugInfoTable->Arg[DebugInfoTable->NumberOfArg];
}
return Count;
}
NTSTATUS
BuildDebugThunkInfo(
IN PTHUNK_DEBUG_INFO DebugInfoTable,
OUT PULONG_PTR *LogTable)
/*++
Routine Description:
This routine fills a service-table-indexed with pointers
to the corresponding DebugThunkInfo
Arguments:
DebugInfoTable - Services debug info
LogTable - Table of pointers to fill
Return Value:
NTSTATUS
--*/
{
ULONG i=0;
while (DebugInfoTable && DebugInfoTable->ApiName)
{
LogTable[i++] = (PULONG_PTR) DebugInfoTable;
DebugInfoTable = (PTHUNK_DEBUG_INFO)
&DebugInfoTable->Arg[DebugInfoTable->NumberOfArg];
}
return STATUS_SUCCESS;
}
NTSTATUS
LogApiHeader(
PTHUNK_DEBUG_INFO ThunkDebugInfo,
PLOGINFO LogInfo,
BOOLEAN ServiceReturn,
ULONG_PTR ReturnResult,
ULONG_PTR ReturnAddress)
/*++
Routine Description:
Log the Thunked API header
Arguments:
ThunkDebugInfo - Pointer to service log info
LogInfo - Logging Info
ServiceReturn - TRUE if called after the thunk API has executed
ReturnResult - Result code returned from the API
ReturnAddress - Return address of for this thunked call
Return Value:
NTSTATUS
--*/
{
if (ServiceReturn)
{
return LogFormat(LogInfo,
"wh%s: Ret=%lx-%lx: ",
ThunkDebugInfo->ApiName,
ReturnResult,
ReturnAddress);
}
return LogFormat(LogInfo,
"%8.8X-wh%s: ",
PtrToUlong(NtCurrentTeb()->ClientId.UniqueThread),
ThunkDebugInfo->ApiName);
}
NTSTATUS
LogApiParameters(
IN OUT PLOGINFO LogInfo,
IN PULONG Stack32,
IN PTHUNK_DEBUG_INFO ThunkDebugInfo,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log the Thunked API Parameters
Arguments:
LogInfo - Output log buffer
Stack32 - Pointer to 32-bit arg stack
ThunkDebugInfo - Pointer to service log info for the API
ServiceReturn - TRUE if called after the Thunk API has executed
Return Value:
NTSTATUS
--*/
{
UINT_PTR i=0;
//
// Loops thru the parameters
//
while (i < ThunkDebugInfo->NumberOfArg)
{
_try
{
LogDataType[ThunkDebugInfo->Arg[i].Type].Handler(
LogInfo,
Stack32[i],
ThunkDebugInfo->Arg[i].Name,
ServiceReturn);
}
_except(EXCEPTION_EXECUTE_HANDLER)
{
//
// Log the bad parameters
//
LogFormat(LogInfo,
"%s=%lx-%ws ",
ThunkDebugInfo->Arg[i].Name,
Stack32[i],
L"(BAD)");
}
i++;
}
return STATUS_SUCCESS;
}
NTSTATUS
LogThunkApi(
IN PTHUNK_LOG_CONTEXT ThunkLogContext,
IN PTHUNK_DEBUG_INFO ThunkDebugInfo,
IN UINT_PTR LogFullInfo)
/*++
Routine Description:
Log the Thunked API
Arguments:
ThunkLogContext - Thunk API log context
ThunkDebugInfo - Pointer to service log info for the API
LogFullInfo - Flag whther to log all the API info or just the name
Return Value:
NTSTATUS
--*/
{
NTSTATUS NtStatus;
CHAR szBuf[ MAX_LOG_BUFFER ];
LOGINFO LogInfo;
PULONG Stack32 = ThunkLogContext->Stack32;
BOOLEAN ServiceReturn = ThunkLogContext->ServiceReturn;
//
// Initialize the log buffer
//
LogInfo.OutputBuffer = szBuf;
LogInfo.BufferSize = MAX_LOG_BUFFER - 1;
//
// Log API header
//
NtStatus = LogApiHeader(ThunkDebugInfo,
&LogInfo,
ServiceReturn,
ThunkLogContext->ReturnResult,
*(Stack32-1));
if (!NT_SUCCESS(NtStatus))
{
return NtStatus;
}
// Log Parameters
if (LogFullInfo)
{
NtStatus = LogApiParameters(&LogInfo,
Stack32,
ThunkDebugInfo,
ServiceReturn);
if (!NT_SUCCESS(NtStatus))
{
return NtStatus;
}
}
//
// Do actual output
//
LogInfo.OutputBuffer[0] = '\0';
LogOut(szBuf, Wow64LogFlags);
LogOut("\r\n", Wow64LogFlags);
return NtStatus;
}
WOW64LOGAPI
NTSTATUS
Wow64LogSystemService(
IN PTHUNK_LOG_CONTEXT ThunkLogContext)
/*++
Routine Description:
Logs information for the specified system service.
Arguments:
LogContext - Thunk API log context
Return Value:
NTSTATUS
--*/
{
NTSTATUS NtStatus;
PTHUNK_DEBUG_INFO ThunkDebugInfo;
ULONG_PTR TableNumber = ThunkLogContext->TableNumber;
ULONG_PTR ServiceNumber = ThunkLogContext->ServiceNumber;
UINT_PTR LogFullInfo;
//
// Use try except !!
//
_try
{
switch(TableNumber)
{
case WHNT32_INDEX:
if (!LF_NTBASE_ENABLED(Wow64LogFlags))
{
return STATUS_SUCCESS;
}
LogFullInfo = (Wow64LogFlags & LF_NTBASE_FULL);
ThunkDebugInfo = (PTHUNK_DEBUG_INFO)LogNtBase[ServiceNumber];
break;
case WHCON_INDEX:
if (!LF_NTCON_ENABLED(Wow64LogFlags) || LogConsole == NULL)
{
return STATUS_SUCCESS;
}
LogFullInfo = (Wow64LogFlags & LF_NTCON_FULL);
ThunkDebugInfo = (PTHUNK_DEBUG_INFO)LogConsole[ServiceNumber];
break;
case WHWIN32_INDEX:
if (!LF_WIN32_ENABLED(Wow64LogFlags) || LogWin32 == NULL)
{
return STATUS_SUCCESS;
}
LogFullInfo = (Wow64LogFlags & LF_WIN32_FULL);
ThunkDebugInfo = (PTHUNK_DEBUG_INFO)LogWin32[ServiceNumber];
break;
case WHBASE_INDEX:
if (!LF_BASE_ENABLED(Wow64LogFlags))
{
return STATUS_SUCCESS;
}
LogFullInfo = (Wow64LogFlags & LF_BASE_FULL);
ThunkDebugInfo = (PTHUNK_DEBUG_INFO)LogBase[ServiceNumber];
break;
default: // invalid service table
WOW64LOGOUTPUT((LF_ERROR, "Wow64LogSystemService: Not supported table number - %lx\n", TableNumber));
return STATUS_UNSUCCESSFUL;
break;
}
NtStatus = LogThunkApi(ThunkLogContext,
ThunkDebugInfo,
LogFullInfo);
}
_except(EXCEPTION_EXECUTE_HANDLER)
{
WOW64LOGOUTPUT((LF_EXCEPTION, "Wow64LogSystemService : Invalid Service ServiceTable = %lx, ServiceNumber = %lx. Status=%lx\n",
TableNumber, ServiceNumber, GetExceptionCode()));
NtStatus = GetExceptionCode();
}
return NtStatus;
}
//////////////////////////////////////////////////////////////////////////
//
// DATA TYPE LOGGING ROUTINES
//
///////////////////////////////////////////////////////////////////////////
NTSTATUS
LogTypeValue(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as ULONG
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
if (ServiceReturn)
{
return STATUS_SUCCESS;
}
return LogFormat(LogInfo,
"%s=%lx ",
FieldName,
(ULONG)Data);
}
NTSTATUS
LogTypeUnicodeString(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as UNICODE_STRING32
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
UNICODE_STRING32 *Name32;
PWCHAR Buffer = L" ";
if (ServiceReturn)
{
return STATUS_SUCCESS;
}
Name32 = (UNICODE_STRING32 *)Data;
if (Data > 0xffff)
{
if (Name32->Buffer)
{
Buffer = (PWCHAR)Name32->Buffer;
}
if (Name32->Length && Name32->Buffer > 0xffff) {
return LogFormat(LogInfo,
"%s=%ws ",
FieldName,
Buffer);
} else {
return LogFormat(LogInfo,
"%s={L=%x,M=%x,B=%x}",
FieldName,
Name32->Length,
Name32->MaximumLength,
Name32->Buffer);
}
}
return LogFormat(LogInfo,
"%s=%x",
FieldName,
Name32);
}
NTSTATUS
LogTypePULongInOut(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as PULONG
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
return LogFormat(LogInfo,
"[%s-%lx]=%lx ",
FieldName,
(ULONG)Data,
((PULONG)Data ? *((PULONG)Data) : 0));
}
NTSTATUS
LogTypePULongOut(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as PULONG (Out field)
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
if (ServiceReturn)
{
return LogFormat(LogInfo,
"[%s-%lx]=%lx ",
FieldName,
(PULONG)Data,
((PULONG)Data ? *(PULONG)Data : 0));
}
return LogFormat(LogInfo,
"%s=%lx ",
FieldName,
(PULONG)Data);
}
NTSTATUS
LogTypeObjectAttrbiutes(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as POBJECT_ATTRIBUTES
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
NT32OBJECT_ATTRIBUTES *ObjA32;
UNICODE_STRING32 *ObjectName = NULL;
PWCHAR Buffer = L"";
if (ServiceReturn)
{
return STATUS_SUCCESS;
}
ObjA32 = (NT32OBJECT_ATTRIBUTES *)Data;
if (ObjA32)
{
ObjectName = (UNICODE_STRING32 *)ObjA32->ObjectName;
if (ObjectName)
{
if (ObjectName->Buffer)
{
Buffer = (PWCHAR)ObjectName->Buffer;
}
}
}
return LogFormat(LogInfo,
"%s=%lx {N=%ws,A=%lx} ",
FieldName,
(PULONG)Data,
Buffer,
(ObjA32 ? ObjA32->Attributes : 0));
}
NTSTATUS
LogTypeIoStatusBlock(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as IO_STATUS_BLOCK
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
if (ServiceReturn)
{
PIO_STATUS_BLOCK32 StatusBlock32 = (PIO_STATUS_BLOCK32)Data;
return LogFormat(LogInfo,
"%s={S=%lx,I=%lx} ",
FieldName,
(PULONG)Data,
(StatusBlock32 ? StatusBlock32->Status : 0),
(StatusBlock32 ? StatusBlock32->Information : 0));
}
return LogFormat(LogInfo,
"%s=%lx ",
FieldName,
(PULONG)Data);
}
NTSTATUS
LogTypePWStr(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as PWSTR
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
ULONG_PTR i;
WCHAR Buffer[ 14 ];
PWSTR String = (PWSTR) Data;
if (ServiceReturn)
{
return STATUS_SUCCESS;
}
//
// Sometime this type is treated as a pointer
// to WCHARs without NULL terminating it, like
// how it's used in NtGdiExtTextOutW, so let's dump
// a minimal string
//
if (Data)
{
i = 0;
while((i < ((sizeof(Buffer) / sizeof(WCHAR)) - 4)) && (String[i]))
{
Buffer[i] = String[i];
i++;
}
if (i == ((sizeof(Buffer) / sizeof(WCHAR)) - 4))
{
Buffer[i++] = L'.';
Buffer[i++] = L'.';
Buffer[i++] = L'.';
}
Buffer[i++] = UNICODE_NULL;
}
return LogFormat(LogInfo,
"%s=%ws ",
FieldName,
(Data > 0xffff) ? Buffer : L"");
}
NTSTATUS
LogTypePRectIn(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as PWSTR
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
if (ServiceReturn)
{
return STATUS_SUCCESS;
}
if (Data)
{
PRECT Rect = (PRECT)Data;
return LogFormat(LogInfo,
"%s={%lx,%lx,%lx,%lx} ",
FieldName,
Rect->left, Rect->top, Rect->right, Rect->bottom);
}
return LogTypeValue(LogInfo,
Data,
FieldName,
ServiceReturn);
}
NTSTATUS
LogTypePLargeIntegerIn(
IN OUT PLOGINFO LogInfo,
IN ULONG_PTR Data,
IN PSZ FieldName,
IN BOOLEAN ServiceReturn)
/*++
Routine Description:
Log Data as PLARGE_INTEGER
Arguments:
LogInfo - Output log buffer
Data - Value to log
FieldName - Descriptive name of value to log
ServiceReturn - TRUE if called after the thunk API has executed
Return Value:
NTSTATUS
--*/
{
if (ServiceReturn)
{
return STATUS_SUCCESS;
}
if (Data)
{
NT32ULARGE_INTEGER *ULargeInt = (NT32ULARGE_INTEGER *)Data;
return LogFormat(LogInfo,
"%s={H=%lx,L=%lx} ",
FieldName,
ULargeInt->HighPart, ULargeInt->LowPart);
}
return LogTypeValue(LogInfo,
Data,
FieldName,
ServiceReturn);
}