mirror of https://github.com/lianthony/NT4.0
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.
1958 lines
45 KiB
1958 lines
45 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbgutil.c
|
|
|
|
Abstract:
|
|
|
|
This file contains supplimental debugging and diagnostic routines for SAM.
|
|
|
|
|
|
Author:
|
|
|
|
Chris Mayhall (ChrisMay) 04-Apr-1996
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
04-Apr-1996 ChrisMay
|
|
Created.
|
|
08-Apr-1996 ChrisMay
|
|
Added enumeration routines.
|
|
15-Apr-1996 ChrisMay
|
|
Added query routines.
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include <samsrvp.h>
|
|
|
|
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define DBG_BUFFER_SIZE 4096
|
|
|
|
|
|
|
|
//
|
|
// Private Helper Routines
|
|
//
|
|
|
|
VOID
|
|
SamIDebugOutput(
|
|
IN LPSTR DebugMessage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine displays a message on the debugger.
|
|
|
|
Parameters:
|
|
|
|
DebugMessage - Pointer to the message string.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
sprintf(Buffer, "%-30s", DebugMessage);
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SamIDebugFileLineOutput(
|
|
IN LPSTR FileName,
|
|
IN ULONG LineNumber
|
|
)
|
|
{
|
|
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
sprintf(Buffer, "[File = %s Line = %lu]\n", FileName, LineNumber);
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
wcstombsp(
|
|
IN LPSTR Destination,
|
|
IN LPWSTR Source,
|
|
IN ULONG Size
|
|
)
|
|
{
|
|
ULONG Index;
|
|
|
|
for (Index = 0; Index < Size; Index++)
|
|
{
|
|
if (Source[Index] != L'\0')
|
|
{
|
|
Destination[Index] = (CHAR)(Source[Index]);
|
|
}
|
|
}
|
|
Destination[Size] = '\0';
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpBinaryData(
|
|
PBYTE pData,
|
|
DWORD cbData
|
|
)
|
|
{
|
|
DWORD i;
|
|
BYTE AsciiLine[16];
|
|
BYTE BinaryLine[16];
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
if (0 == cbData)
|
|
{
|
|
OutputDebugStringA("Zero-Length Data\n");
|
|
return;
|
|
}
|
|
|
|
if (cbData > DBG_BUFFER_SIZE)
|
|
{
|
|
OutputDebugStringA("ShowBinaryData - truncating display to 256 bytes\n");
|
|
cbData = 256;
|
|
}
|
|
|
|
for (; cbData > 0 ;)
|
|
{
|
|
for (i = 0; i < 16 && cbData > 0 ; i++, cbData--)
|
|
{
|
|
BinaryLine[i] = *pData;
|
|
(isprint(*pData)) ? (AsciiLine[i] = *pData) : (AsciiLine[i] = '.');
|
|
pData++;
|
|
}
|
|
|
|
if (i < 15)
|
|
{
|
|
for (; i < 16 ; i++)
|
|
{
|
|
BinaryLine[i] = ' ';
|
|
AsciiLine[i] = ' ';
|
|
}
|
|
}
|
|
|
|
sprintf(Buffer,
|
|
"%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\t",
|
|
BinaryLine[0],
|
|
BinaryLine[1],
|
|
BinaryLine[2],
|
|
BinaryLine[3],
|
|
BinaryLine[4],
|
|
BinaryLine[5],
|
|
BinaryLine[6],
|
|
BinaryLine[7],
|
|
BinaryLine[8],
|
|
BinaryLine[9],
|
|
BinaryLine[10],
|
|
BinaryLine[11],
|
|
BinaryLine[12],
|
|
BinaryLine[13],
|
|
BinaryLine[14],
|
|
BinaryLine[15]);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%c%c%c%c%c%c%c%c - %c%c%c%c%c%c%c%c\n",
|
|
AsciiLine[0],
|
|
AsciiLine[1],
|
|
AsciiLine[2],
|
|
AsciiLine[3],
|
|
AsciiLine[4],
|
|
AsciiLine[5],
|
|
AsciiLine[6],
|
|
AsciiLine[7],
|
|
AsciiLine[8],
|
|
AsciiLine[9],
|
|
AsciiLine[10],
|
|
AsciiLine[11],
|
|
AsciiLine[12],
|
|
AsciiLine[13],
|
|
AsciiLine[14],
|
|
AsciiLine[15]);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Set Value Key Routines
|
|
//
|
|
|
|
VOID
|
|
SamIDumpNtSetValueKey(
|
|
IN PUNICODE_STRING ValueName,
|
|
IN ULONG TitleIndex,
|
|
IN ULONG Type,
|
|
IN PVOID Data,
|
|
IN ULONG DataSize
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
if (NULL != ValueName)
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString,
|
|
ValueName,
|
|
TRUE);
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %s\n",
|
|
"Set Value Key:",
|
|
"ValueName",
|
|
AnsiString.Buffer);
|
|
|
|
RtlFreeAnsiString(&AnsiString);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %s\n",
|
|
"Set Value Key:",
|
|
"ValueName",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"TitleIndex",
|
|
TitleIndex);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"Type",
|
|
Type);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != Data)
|
|
{
|
|
// BUG: Need a display routine for the data.
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"Data",
|
|
"BINARY DATA");
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"Data",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n\n",
|
|
"DataSize",
|
|
DataSize);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SamIDumpRtlpNtSetValueKey(
|
|
IN ULONG Type,
|
|
IN PVOID Data,
|
|
IN ULONG DataSize
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n",
|
|
"Set Value Key:",
|
|
"Type",
|
|
Type);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != Data)
|
|
{
|
|
// BUG: Need a display routine for the data.
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"Data",
|
|
"ARRAY OF ULONG");
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"Data",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n\n",
|
|
"DataSize",
|
|
DataSize);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Query Routines
|
|
//
|
|
|
|
VOID
|
|
SamIDumpNtQueryKey(
|
|
IN KEY_INFORMATION_CLASS KeyInformationClass,
|
|
IN PVOID KeyInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
// This routine dumps the parameters after returning from the NtQueryKey
|
|
// routine. The KeyInformation is a PVOID buffer that is mapped to one of
|
|
// the KeyInformationClass structures. The case-label values correspond
|
|
// to the values in the KEY_INFORMATION_CLASS enum. Note that the Length
|
|
// parameter is used to specify the buffer length. This is done because
|
|
// the data-length member inside each structure seems to always be set to
|
|
// zero--why?
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n",
|
|
"Query Key:",
|
|
"KeyInformationClass",
|
|
KeyInformationClass);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != KeyInformation)
|
|
{
|
|
CHAR BufferTmp[DBG_BUFFER_SIZE];
|
|
PKEY_BASIC_INFORMATION KeyBasicInformation;
|
|
PKEY_FULL_INFORMATION KeyFullInformation;
|
|
PKEY_NODE_INFORMATION KeyNodeInformation;
|
|
|
|
switch(KeyInformationClass)
|
|
{
|
|
case 0: // KeyBasicInformation
|
|
// Basic information's Name member is an array of WCHAR.
|
|
KeyBasicInformation = KeyInformation;
|
|
wcstombsp(BufferTmp,
|
|
KeyBasicInformation->Name,
|
|
wcslen(KeyBasicInformation->Name));
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = 0x%lx:0xlx\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"KeyInformation:",
|
|
"LastWriteTime",
|
|
KeyBasicInformation->LastWriteTime.HighPart,
|
|
KeyBasicInformation->LastWriteTime.LowPart,
|
|
"TitleIndex",
|
|
KeyBasicInformation->TitleIndex,
|
|
"NameLength",
|
|
KeyBasicInformation->NameLength,
|
|
"Name",
|
|
// BufferTmp);
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
// Displaying the data as an LPWSTR doesn't work, so just dump the
|
|
// bytes.
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpBinaryData((PBYTE)KeyBasicInformation->Name,
|
|
// KeyBasicInformation->NameLength);
|
|
Length);
|
|
|
|
break;
|
|
|
|
case 1: // KeyNodeInformation
|
|
// Node information's Name member is an array of WCHAR.
|
|
KeyNodeInformation = KeyInformation;
|
|
wcstombsp(BufferTmp,
|
|
(LPWSTR)KeyNodeInformation->Name,
|
|
wcslen((LPWSTR)KeyNodeInformation->Name));
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = 0x%lx:0x%lx\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"KeyInformation:",
|
|
"LastWriteTime",
|
|
KeyNodeInformation->LastWriteTime.HighPart,
|
|
KeyNodeInformation->LastWriteTime.LowPart,
|
|
"TitleIndex",
|
|
KeyNodeInformation->TitleIndex,
|
|
"ClassOffset",
|
|
KeyNodeInformation->ClassOffset,
|
|
"ClassLength",
|
|
KeyNodeInformation->ClassLength,
|
|
"NameLength",
|
|
KeyNodeInformation->NameLength,
|
|
"Name",
|
|
// BufferTmp);
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
// Displaying the data as an LPWSTR doesn't work, so just dump the
|
|
// bytes.
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpBinaryData((PBYTE)KeyNodeInformation->Name,
|
|
// KeyNodeInformation->NameLength);
|
|
Length);
|
|
|
|
break;
|
|
|
|
case 2: // KeyFullInformation
|
|
|
|
KeyFullInformation = KeyInformation;
|
|
|
|
// Full information's Class member is an array of WCHAR.
|
|
|
|
// wcstombsp(BufferTmp,
|
|
// KeyFullInformation->Class,
|
|
// wcslen(KeyFullInformation->Class));
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = 0x%lx:0x%lx\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"KeyInformation:",
|
|
"LastWriteTime",
|
|
KeyFullInformation->LastWriteTime.HighPart,
|
|
KeyFullInformation->LastWriteTime.LowPart,
|
|
"TitleIndex",
|
|
KeyFullInformation->TitleIndex,
|
|
"ClassOffset",
|
|
KeyFullInformation->ClassOffset,
|
|
"ClassLength",
|
|
KeyFullInformation->ClassLength,
|
|
"SubKeys",
|
|
KeyFullInformation->SubKeys,
|
|
"MaxNameLen",
|
|
KeyFullInformation->MaxNameLen,
|
|
"MaxClassLen",
|
|
KeyFullInformation->MaxClassLen,
|
|
"Values",
|
|
KeyFullInformation->Values,
|
|
"MaxValueNameLen",
|
|
KeyFullInformation->MaxValueNameLen,
|
|
"MaxValueDataLen",
|
|
KeyFullInformation->MaxValueDataLen,
|
|
"Class",
|
|
// BufferTmp);
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
// Displaying the data as an LPWSTR doesn't work, so just dump the
|
|
// bytes.
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpBinaryData((PBYTE)KeyFullInformation->Class,
|
|
// KeyFullInformation->ClassLength);
|
|
Length);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"KeyInformation",
|
|
NULL);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
// OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"Length",
|
|
Length);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != ResultLength)
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n\n",
|
|
"ResultLength",
|
|
ResultLength);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n\n",
|
|
"ResultLength",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SamIDumpNtQueryValueKey(
|
|
IN PUNICODE_STRING ValueName,
|
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
|
IN PVOID KeyValueInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
// This routine dumps the parameters after returning from NtQueryValueKey
|
|
// routine. The KeyValueInformation is a PVOID buffer that is mapped to
|
|
// one of the KeyInformationClass structures. The case-label values corre-
|
|
// spond to the values in the KEY_VALUE_INFORMATION_CLASS enum.
|
|
|
|
if (NULL != ValueName)
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString,
|
|
ValueName,
|
|
TRUE);
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %s\n",
|
|
"Query Value Key:",
|
|
"ValueName",
|
|
AnsiString.Buffer);
|
|
|
|
RtlFreeAnsiString(&AnsiString);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %s\n",
|
|
"Query Value Key:",
|
|
"ValueName",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"KeyValueInformationClass",
|
|
KeyValueInformationClass);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != KeyValueInformation)
|
|
{
|
|
CHAR BufferTmp[DBG_BUFFER_SIZE];
|
|
PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInformation;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueFullInformation;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInformation;
|
|
|
|
switch(KeyValueInformationClass)
|
|
{
|
|
case 0: // KeyValueBasicInformation
|
|
// Basic information's Name member is an array of WCHAR.
|
|
KeyValueBasicInformation = KeyValueInformation;
|
|
wcstombsp(BufferTmp,
|
|
KeyValueBasicInformation->Name,
|
|
wcslen(KeyValueBasicInformation->Name));
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"TitleIndex",
|
|
KeyValueBasicInformation->TitleIndex,
|
|
"Type",
|
|
KeyValueBasicInformation->Type,
|
|
"NameLength",
|
|
KeyValueBasicInformation->NameLength,
|
|
"Name",
|
|
//BufferTmp);
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
// Displaying the data as an LPWSTR doesn't work, so just dump the
|
|
// bytes.
|
|
|
|
OutputDebugStringA(Buffer);
|
|
SampDumpBinaryData((PBYTE)KeyValueBasicInformation->Name,
|
|
KeyValueBasicInformation->NameLength);
|
|
break;
|
|
|
|
case 1: // KeyValueFullInformation
|
|
// Full information's Name member is an array of WCHAR.
|
|
KeyValueFullInformation = KeyValueInformation;
|
|
wcstombsp(BufferTmp,
|
|
KeyValueFullInformation->Name,
|
|
wcslen(KeyValueFullInformation->Name));
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"TitleIndex",
|
|
KeyValueFullInformation->TitleIndex,
|
|
"Type",
|
|
KeyValueFullInformation->Type,
|
|
"DataOffset",
|
|
KeyValueFullInformation->DataOffset,
|
|
"DataLength",
|
|
KeyValueFullInformation->DataLength,
|
|
"NameLength",
|
|
KeyValueFullInformation->NameLength,
|
|
"Name",
|
|
//BufferTmp);
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
// Displaying the data as an LPWSTR doesn't work, so just dump the
|
|
// bytes.
|
|
|
|
OutputDebugStringA(Buffer);
|
|
SampDumpBinaryData((PBYTE)KeyValueFullInformation->Name,
|
|
KeyValueFullInformation->NameLength);
|
|
break;
|
|
|
|
case 2: // KeyValuePartialInformation
|
|
|
|
KeyValuePartialInformation = KeyValueInformation;
|
|
|
|
// Partial information's Data member is an array of UCHAR.
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"TitleIndex",
|
|
KeyValuePartialInformation->TitleIndex,
|
|
"Type",
|
|
KeyValuePartialInformation->Type,
|
|
"DataLength",
|
|
KeyValuePartialInformation->DataLength,
|
|
"Data",
|
|
// KeyValuePartialInformation->Data);
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
// First, dump the buffer as a raw byte stream.
|
|
|
|
SampDumpBinaryData(KeyValuePartialInformation->Data,
|
|
KeyValuePartialInformation->DataLength);
|
|
|
|
// Then, determine object type and dump the data in SAM struct
|
|
// format.
|
|
|
|
switch(KeyValuePartialInformation->Type)
|
|
{
|
|
|
|
case 0: // Server Object
|
|
break;
|
|
|
|
case 1: // Domain Object
|
|
break;
|
|
|
|
case 2: // Group Object
|
|
break;
|
|
|
|
case 3: // Alias Object
|
|
|
|
// Dump the alias object's fixed attributes.
|
|
|
|
// BUG: What about Basic and Full information?
|
|
|
|
// SampDumpPSAMP_V1_FIXED_LENGTH_ALIAS(
|
|
// KeyValuePartialInformation->Data,
|
|
// 0);
|
|
|
|
// Dump the alias object's variable attribute array.
|
|
|
|
//SampDumpAliasVariableAttributeArray(
|
|
// KeyValuePartialInformation->Data);
|
|
|
|
// Dump the alias object's Variable attributes.
|
|
|
|
|
|
break;
|
|
|
|
case 4: // User Object
|
|
break;
|
|
|
|
default: // Unknown Object
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"KeyValueInformation",
|
|
NULL);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
// OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"Length",
|
|
Length);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != ResultLength)
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n\n",
|
|
"ResultLength",
|
|
ResultLength);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n\n",
|
|
"ResultLength",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SamIDumpRtlpNtQueryValueKey(
|
|
IN PULONG KeyValueType,
|
|
IN PVOID KeyValue,
|
|
IN PULONG KeyValueLength,
|
|
IN PLARGE_INTEGER LastWriteTime
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
if (NULL != KeyValueType)
|
|
{
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = 0x%lx\n",
|
|
"Query Value Key:",
|
|
"KeyValueType",
|
|
*KeyValueType);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %s\n",
|
|
"Query Value Key:",
|
|
"KeyValueType",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != KeyValue)
|
|
{
|
|
SampDumpBinaryData((PBYTE)KeyValue, *KeyValueLength);
|
|
OutputDebugStringA("\n");
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"KeyValue",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != KeyValueLength)
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"KeyValueLength",
|
|
*KeyValueLength);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"KeyValueLength",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != LastWriteTime)
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = 0x%lx:0x%lx\n\n",
|
|
"LastWriteTime",
|
|
LastWriteTime->HighPart,
|
|
LastWriteTime->LowPart);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n\n",
|
|
"LastWriteTime",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Enumeration Routines
|
|
//
|
|
|
|
VOID
|
|
SamIDumpNtEnumerateKey(
|
|
IN ULONG Index,
|
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
|
IN PVOID KeyValueInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n",
|
|
"Enumerate Key:",
|
|
"Index",
|
|
Index);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"KeyValueInformationClass",
|
|
KeyValueInformationClass);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != KeyValueInformation)
|
|
{
|
|
CHAR BufferTmp[DBG_BUFFER_SIZE];
|
|
PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInformation;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueFullInformation;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInformation;
|
|
|
|
switch(KeyValueInformationClass)
|
|
{
|
|
case 0: // KeyValueBasicInformation
|
|
// Full information's Name member is an array of WCHAR.
|
|
KeyValueBasicInformation = KeyValueInformation;
|
|
wcstombsp(BufferTmp,
|
|
KeyValueBasicInformation->Name,
|
|
wcslen(KeyValueBasicInformation->Name));
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"TitleIndex",
|
|
KeyValueBasicInformation->TitleIndex,
|
|
"Type",
|
|
KeyValueBasicInformation->Type,
|
|
"NameLength",
|
|
KeyValueBasicInformation->NameLength,
|
|
"Name",
|
|
BufferTmp);
|
|
break;
|
|
|
|
case 1: // KeyValueFullInformation
|
|
// Full information's Name member is an array of WCHAR.
|
|
KeyValueFullInformation = KeyValueInformation;
|
|
wcstombsp(BufferTmp,
|
|
KeyValueFullInformation->Name,
|
|
wcslen(KeyValueFullInformation->Name));
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"TitleIndex",
|
|
KeyValueFullInformation->TitleIndex,
|
|
"Type",
|
|
KeyValueFullInformation->Type,
|
|
"DataOffset",
|
|
KeyValueFullInformation->DataOffset,
|
|
"DataLength",
|
|
KeyValueFullInformation->DataLength,
|
|
"NameLength",
|
|
KeyValueFullInformation->NameLength,
|
|
"Name",
|
|
BufferTmp);
|
|
break;
|
|
|
|
case 2: // KeyValuePartialInformation
|
|
// Partial information's Data member is an array of UCHAR.
|
|
KeyValuePartialInformation = KeyValueInformation;
|
|
|
|
// BUG: Need a display routine for the data.
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %s\n",
|
|
"TitleIndex",
|
|
KeyValuePartialInformation->TitleIndex,
|
|
"Type",
|
|
KeyValuePartialInformation->Type,
|
|
"DataLength",
|
|
KeyValuePartialInformation->DataLength,
|
|
"Data",
|
|
// KeyValuePartialInformation->Data);
|
|
"BINARY DATA FOLLOWS:");
|
|
OutputDebugStringA(Buffer);
|
|
SampDumpBinaryData(KeyValuePartialInformation->Data,
|
|
KeyValuePartialInformation->DataLength);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"KeyValueInformation",
|
|
NULL);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
// OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"Length",
|
|
Length);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
if (NULL != ResultLength)
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n\n",
|
|
"ResultLength",
|
|
ResultLength);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n\n",
|
|
"ResultLength",
|
|
NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SamIDumpRtlpNtEnumerateSubKey(
|
|
IN PUNICODE_STRING SubKeyName,
|
|
IN PSAM_ENUMERATE_HANDLE Index,
|
|
IN LARGE_INTEGER LastWriteTime
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString,
|
|
SubKeyName,
|
|
TRUE);
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %s\n%-30s = %lu\n%-30s = 0x%lx:0x%lx\n\n",
|
|
"Enumerate SubKey:",
|
|
"SubKeyName",
|
|
AnsiString.Buffer,
|
|
"Index",
|
|
*Index,
|
|
"LastWriteTime",
|
|
LastWriteTime.HighPart,
|
|
LastWriteTime.LowPart);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
RtlFreeAnsiString(&AnsiString);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Security Descriptor Component Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpSecurityDescriptorSubAuthority(
|
|
IN UCHAR SubAuthorityCount,
|
|
IN ULONG SubAuthority[]
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
INT Count = (INT)SubAuthorityCount;
|
|
INT Index = 0;
|
|
|
|
for (Index = 0; Index < Count; Index++)
|
|
{
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n",
|
|
"SubAuthority:",
|
|
"SubAuthority Element",
|
|
SubAuthority[Index]);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpSecurityDescriptorOwner(
|
|
IN PISID Owner
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %du\n%-30s = %du\n%-30s = %du%du%du%du%du%du\n",
|
|
"Owner:",
|
|
"Revision",
|
|
Owner->Revision,
|
|
"SubAuthorityCount",
|
|
Owner->SubAuthorityCount,
|
|
"IdentifierAuthority",
|
|
Owner->IdentifierAuthority.Value[0],
|
|
Owner->IdentifierAuthority.Value[1],
|
|
Owner->IdentifierAuthority.Value[2],
|
|
Owner->IdentifierAuthority.Value[3],
|
|
Owner->IdentifierAuthority.Value[4],
|
|
Owner->IdentifierAuthority.Value[5]);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpSecurityDescriptorSubAuthority(Owner->SubAuthorityCount,
|
|
Owner->SubAuthority);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpSecurityDescriptorGroup(
|
|
IN PISID Group
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %du\n%-30s = %du\n%-30s = %du%du%du%du%du%du\n",
|
|
"Group:",
|
|
"Revision",
|
|
Group->Revision,
|
|
"SubAuthorityCount",
|
|
Group->SubAuthorityCount,
|
|
"IdentifierAuthority",
|
|
Group->IdentifierAuthority.Value[0],
|
|
Group->IdentifierAuthority.Value[1],
|
|
Group->IdentifierAuthority.Value[2],
|
|
Group->IdentifierAuthority.Value[3],
|
|
Group->IdentifierAuthority.Value[4],
|
|
Group->IdentifierAuthority.Value[5]);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpSecurityDescriptorSubAuthority(Group->SubAuthorityCount,
|
|
Group->SubAuthority);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// ACL Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpAcl(
|
|
IN PACL Acl
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %du\n%-30s = %du\n%-30s = %du\n%-30s = %du\n%-30s = %du\n",
|
|
"Acl:",
|
|
"AclRevision",
|
|
Acl->AclRevision,
|
|
"Sbz1",
|
|
Acl->Sbz1,
|
|
"ACL Size",
|
|
Acl->AclSize,
|
|
"ACE Count",
|
|
Acl->AceCount,
|
|
"Sbz2",
|
|
Acl->Sbz2);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Security Descriptor Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpSecurityDescriptor(
|
|
IN PISECURITY_DESCRIPTOR SecurityDescriptor
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
if (NULL != SecurityDescriptor)
|
|
{
|
|
// Note that the SECURITY_DESCRIPTOR is intended to be treated as an
|
|
// opaque blob so that future changes are compatible with previous
|
|
// versions.
|
|
|
|
// Revision is actually represented as a UCHAR, but it is displayed as
|
|
// a "du" in this routine.
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %du\n%-30s = %du\n%-30s = %du\n%-30s = 0x%lx\n",
|
|
"SecurityDescriptor:",
|
|
"Revision",
|
|
SecurityDescriptor->Revision,
|
|
"Sbz1",
|
|
SecurityDescriptor->Sbz1,
|
|
"Control",
|
|
SecurityDescriptor->Control);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpSecurityDescriptorOwner(SecurityDescriptor->Owner);
|
|
SampDumpSecurityDescriptorGroup(SecurityDescriptor->Group);
|
|
SampDumpAcl(SecurityDescriptor->Sacl);
|
|
SampDumpAcl(SecurityDescriptor->Dacl);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer, "%-30s = %s\n", "SecurityDescriptor:", NULL);
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Quality Of Service Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpSecurityQualityOfService(
|
|
IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
if (NULL != SecurityQualityOfService)
|
|
{
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n%-30s = %du\n%-30s = %du\n%-30s = %du\n",
|
|
"SecurityQualityOfService:",
|
|
"Length",
|
|
SecurityQualityOfService->Length,
|
|
"ImpersonationLevel",
|
|
SecurityQualityOfService->ImpersonationLevel,
|
|
"ContextTrackingMode",
|
|
SecurityQualityOfService->ContextTrackingMode,
|
|
"EffectiveOnly",
|
|
SecurityQualityOfService->EffectiveOnly);
|
|
}
|
|
else
|
|
{
|
|
sprintf(Buffer, "%-30s = %s\n", "SecurityQualityOfService:", NULL);
|
|
}
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Object Attribute Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpObjectAttributes(
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString,
|
|
ObjectAttributes->ObjectName,
|
|
TRUE);
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n%-30s = 0x%lx\n%-30s = %s\n%-30s = 0x%lx\n",
|
|
"ObjectAttributes:",
|
|
"Length",
|
|
ObjectAttributes->Length,
|
|
"RootDirectory Handle",
|
|
ObjectAttributes->RootDirectory,
|
|
"ObjectName",
|
|
AnsiString.Buffer,
|
|
"Attributes",
|
|
ObjectAttributes->Attributes);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
RtlFreeAnsiString(&AnsiString);
|
|
|
|
SampDumpSecurityDescriptor(ObjectAttributes->SecurityDescriptor);
|
|
SampDumpSecurityQualityOfService(ObjectAttributes->SecurityQualityOfService);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Open Key Routines
|
|
//
|
|
|
|
VOID
|
|
SamIDumpNtOpenKey(
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN ULONG Options
|
|
)
|
|
{
|
|
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = 0x%lx\n%-30s = 0x%lx\n",
|
|
"Open Registry Key:",
|
|
"DesiredAccess",
|
|
DesiredAccess,
|
|
"Options",
|
|
Options);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpObjectAttributes(ObjectAttributes);
|
|
|
|
OutputDebugStringA("\n");
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// V1_0A Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpPSAMP_V1_FIXED_LENGTH_SERVER(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
PSAMP_V1_FIXED_LENGTH_SERVER TempBuffer = NewValue;
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n",
|
|
"SAMP_V1_FIXED_LENGTH_SERVER Buffer:",
|
|
"RevisionLevel",
|
|
TempBuffer->RevisionLevel);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
OutputDebugStringA("\n");
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpPSAMP_V1_0A_FIXED_LENGTH_DOMAIN(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
PSAMP_V1_0A_FIXED_LENGTH_DOMAIN TempBuffer = NewValue;
|
|
|
|
sprintf(Buffer,
|
|
|
|
"%s\n%-30s = %lu\n%-30s = %lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %du\n\
|
|
%-30s = %du\n%-30s = %du\n%-30s = %du\n%-30s = %du\n%-30s = %du\n\n",
|
|
|
|
"SAMP_V1_OA_FIXED_LENGTH_DOMAIN Buffer:",
|
|
|
|
"Revision",
|
|
TempBuffer->Revision,
|
|
|
|
"Unused1",
|
|
TempBuffer->Unused1,
|
|
|
|
"Creation Time",
|
|
TempBuffer->CreationTime.HighPart,
|
|
TempBuffer->CreationTime.LowPart,
|
|
|
|
"Modified Count",
|
|
TempBuffer->ModifiedCount.HighPart,
|
|
TempBuffer->ModifiedCount.LowPart,
|
|
|
|
"MaxPasswordAge",
|
|
TempBuffer->MaxPasswordAge.HighPart,
|
|
TempBuffer->MaxPasswordAge.LowPart,
|
|
|
|
"MinPasswordAge",
|
|
TempBuffer->MinPasswordAge.HighPart,
|
|
TempBuffer->MinPasswordAge.LowPart,
|
|
|
|
"ForceLogoff",
|
|
TempBuffer->ForceLogoff.HighPart,
|
|
TempBuffer->ForceLogoff.LowPart,
|
|
|
|
"LockoutDuration",
|
|
TempBuffer->LockoutDuration.HighPart,
|
|
TempBuffer->LockoutDuration.LowPart,
|
|
|
|
"LockoutObservationWindow",
|
|
TempBuffer->LockoutObservationWindow.HighPart,
|
|
TempBuffer->LockoutObservationWindow.LowPart,
|
|
|
|
"ModifiedCountAtLastPromotion",
|
|
TempBuffer->ModifiedCountAtLastPromotion.HighPart,
|
|
TempBuffer->ModifiedCountAtLastPromotion.LowPart,
|
|
|
|
"NextRid",
|
|
TempBuffer->NextRid,
|
|
|
|
"PasswordProperties",
|
|
TempBuffer->PasswordProperties,
|
|
|
|
"MinPasswordLength",
|
|
TempBuffer->MinPasswordLength,
|
|
|
|
"PasswordHistoryLength",
|
|
TempBuffer->PasswordHistoryLength,
|
|
|
|
"LockoutThreshold",
|
|
TempBuffer->LockoutThreshold,
|
|
|
|
"ServerState",
|
|
TempBuffer->ServerState,
|
|
|
|
"ServerRole",
|
|
TempBuffer->ServerRole,
|
|
|
|
"UasCompatibilityRequired",
|
|
TempBuffer->UasCompatibilityRequired);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Variable Length Attribute Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpSAMP_VARIABLE_LENGTH_ATTRIBUTE(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
BYTE *TempBuffer = NewValue;
|
|
|
|
#if 0
|
|
|
|
// BUGBUG: Incoming buffer is a self-describing binary stream.
|
|
|
|
PSAMP_VARIABLE_LENGTH_ATTRIBUTE TempBuffer = NewValue;
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %l\n%-30s = %lu\n%-30s = %lu\n\n",
|
|
"SAMP_VARIABLE_LENGTH_ATTRIBUTE Buffer:",
|
|
"Offset",
|
|
TempBuffer->Offset,
|
|
"Length",
|
|
TempBuffer->Length,
|
|
"Qualifier",
|
|
TempBuffer->Qualifier);
|
|
|
|
#endif
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n\n",
|
|
"NewValueLength",
|
|
NewValueLength);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Fixed Length Attribute Routines
|
|
//
|
|
|
|
#if 0
|
|
|
|
VOID
|
|
SampDumpPSAMP_V1_FIXED_LENGTH_ALIAS(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
PSAMP_V1_FIXED_LENGTH_ALIAS TempBuffer = NewValue;
|
|
|
|
// BUG: NewValueLength is unnecessary for this fixed length attribute.
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n\n",
|
|
"SAMP_V1_FIXED_LENGTH_ALIAS Buffer:",
|
|
"RelativeId",
|
|
TempBuffer->RelativeId);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
VOID
|
|
SampDumpPSAMP_V1_0A_FIXED_LENGTH_GROUP(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
PSAMP_V1_FIXED_LENGTH_GROUP TempBuffer = NewValue;
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n\n",
|
|
"SAMP_V1_OA_FIXED_LENGTH_GROUP Buffer:",
|
|
"RelativeId",
|
|
TempBuffer->RelativeId,
|
|
"Attributes",
|
|
TempBuffer->Attributes,
|
|
"AdminGroup",
|
|
TempBuffer->AdminGroup);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpPSAMP_V1_0A_FIXED_LENGTH_USER(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
PSAMP_V1_0A_FIXED_LENGTH_USER TempBuffer = NewValue;
|
|
|
|
sprintf(Buffer,
|
|
|
|
"%s\n%-30s = %lu\n%-30s = %lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %l:%lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %du\n%-30s = %du\n\
|
|
%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n\n",
|
|
|
|
"SAMP_V1_OA_FIXED_LENGTH_USER Buffer:",
|
|
|
|
"Revision",
|
|
TempBuffer->Revision,
|
|
|
|
"Unused1",
|
|
TempBuffer->Unused1,
|
|
|
|
"LastLogon",
|
|
TempBuffer->LastLogon.HighPart,
|
|
TempBuffer->LastLogon.LowPart,
|
|
|
|
"LastLogoff",
|
|
TempBuffer->LastLogoff.HighPart,
|
|
TempBuffer->LastLogoff.LowPart,
|
|
|
|
"PasswordLastSet",
|
|
TempBuffer->PasswordLastSet.HighPart,
|
|
TempBuffer->PasswordLastSet.LowPart,
|
|
|
|
"AccountExpires",
|
|
TempBuffer->AccountExpires.HighPart,
|
|
TempBuffer->AccountExpires.LowPart,
|
|
|
|
"LastBadPasswordTime",
|
|
TempBuffer->LastBadPasswordTime.HighPart,
|
|
TempBuffer->LastBadPasswordTime.LowPart,
|
|
|
|
"UserId",
|
|
TempBuffer->UserId,
|
|
|
|
"PrimaryGroupId",
|
|
TempBuffer->PrimaryGroupId,
|
|
|
|
"UserAccountControl",
|
|
TempBuffer->UserAccountControl,
|
|
|
|
"CountryCode",
|
|
TempBuffer->CountryCode,
|
|
|
|
"CodePage",
|
|
TempBuffer->CodePage,
|
|
|
|
"BadPasswordCount",
|
|
TempBuffer->BadPasswordCount,
|
|
|
|
"LogonCount",
|
|
TempBuffer->LogonCount,
|
|
|
|
"AdminCount",
|
|
TempBuffer->AdminCount,
|
|
|
|
"Unused2",
|
|
TempBuffer->Unused2,
|
|
|
|
"OperatorCount",
|
|
TempBuffer->OperatorCount);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpSampFixedBufferAddress(
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength
|
|
)
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = 0x%lx\n%-30s = %lu\n%-30s = %s\n",
|
|
"BufferAddress",
|
|
NewValue,
|
|
"BufferLength",
|
|
NewValueLength,
|
|
"Buffer",
|
|
"BINARY DATA FOLLOWS:");
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpBinaryData((PBYTE)NewValue, NewValueLength);
|
|
OutputDebugStringA("\n");
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpBuffer(
|
|
IN PVOID BufferAddress,
|
|
IN ULONG BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps the address and length of the attribute buffer.
|
|
|
|
Parameters:
|
|
|
|
BufferAddress - self explanatory.
|
|
|
|
BufferLength - self explanatory.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = 0x%lx\n",
|
|
"BufferAddress",
|
|
BufferAddress);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"BufferLength",
|
|
BufferLength);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n\n",
|
|
"Buffer Content",
|
|
BufferAddress);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// RXact Routines
|
|
//
|
|
|
|
VOID
|
|
SampDumpRXactLog(
|
|
IN PRTL_RXACT_LOG TransactionLog
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps a (registry) transaction log structure.
|
|
|
|
Parameters:
|
|
|
|
TransactionLog - Pointer to the transaction log.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = %lu\n%-30s = %lu\n%-30s = %lu\n",
|
|
"Transaction Log:",
|
|
"OperationCount",
|
|
TransactionLog->OperationCount,
|
|
"LogSize",
|
|
TransactionLog->LogSize,
|
|
"LogSizeInUse",
|
|
TransactionLog->LogSizeInUse);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpRXactContext(
|
|
IN PRTL_RXACT_CONTEXT TransactionContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps a (registry) transaction context.
|
|
|
|
Parameters:
|
|
|
|
TransactionContext - Pointer to the transaction context.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%s\n%-30s = 0x%lx\n%-30s = 0x%lx\n%-30s = %d\n",
|
|
"Transaction Context:",
|
|
"RootRegistryKey Handle",
|
|
TransactionContext->RootRegistryKey,
|
|
"RXactKey Handle",
|
|
TransactionContext->RXactKey,
|
|
"HandlesValid",
|
|
TransactionContext->HandlesValid);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
SampDumpRXactLog(TransactionContext->RXactLog);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpRXactOperation(
|
|
IN RTL_RXACT_OPERATION Operation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps an operation value.
|
|
|
|
Parameters:
|
|
|
|
Operation - The operation value.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"Operation",
|
|
Operation);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpSubKeyNameAndKey(
|
|
IN PUNICODE_STRING SubKeyName,
|
|
IN HANDLE KeyHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps the registry root name and root-key handle value.
|
|
|
|
Parameters:
|
|
|
|
SubKeyName - Pointer to a counted string that is the root name.
|
|
|
|
KeyHandle - Handle of the registry's root key.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString, SubKeyName, TRUE);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"SubKeyName",
|
|
AnsiString.Buffer);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
RtlFreeAnsiString(&AnsiString);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = 0x%lx\n",
|
|
"KeyHandle",
|
|
KeyHandle);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpAttributeName(
|
|
IN PUNICODE_STRING AttributeName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps a combined-attribute name.
|
|
|
|
Parameters:
|
|
|
|
AttributeName - Pointer to the string containing the name.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString, AttributeName, TRUE);
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %s\n",
|
|
"AttributeName",
|
|
AnsiString.Buffer);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
|
|
RtlFreeAnsiString(&AnsiString);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SampDumpKeyType(
|
|
IN ULONG RegistryKeyType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps a registry key type.
|
|
|
|
Parameters:
|
|
|
|
RegistryKeyType - self explanatory.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Buffer[DBG_BUFFER_SIZE];
|
|
|
|
sprintf(Buffer,
|
|
"%-30s = %lu\n",
|
|
"RegistryKeyType",
|
|
RegistryKeyType);
|
|
|
|
OutputDebugStringA(Buffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SamIDumpRXact(
|
|
IN PRTL_RXACT_CONTEXT TransactionContext,
|
|
IN RTL_RXACT_OPERATION Operation,
|
|
IN PUNICODE_STRING SubKeyName,
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING AttributeName,
|
|
IN ULONG RegistryKeyType,
|
|
IN PVOID NewValue,
|
|
IN ULONG NewValueLength,
|
|
IN ULONG NewValueType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dumps a (registry) transaction, just before the call to
|
|
RtlAddAttributeActionToRXact.
|
|
|
|
Parameters:
|
|
|
|
(See individual output routines above for the descriptions)
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
SampDumpRXactContext(TransactionContext);
|
|
SampDumpRXactOperation(Operation);
|
|
SampDumpSubKeyNameAndKey(SubKeyName, KeyHandle);
|
|
SampDumpAttributeName(AttributeName);
|
|
SampDumpKeyType(RegistryKeyType);
|
|
|
|
switch(NewValueType)
|
|
{
|
|
case FIXED_LENGTH_SERVER_FLAG:
|
|
SampDumpPSAMP_V1_FIXED_LENGTH_SERVER(NewValue, NewValueLength);
|
|
break;
|
|
|
|
case FIXED_LENGTH_DOMAIN_FLAG:
|
|
SampDumpPSAMP_V1_0A_FIXED_LENGTH_DOMAIN(NewValue, NewValueLength);
|
|
break;
|
|
|
|
case FIXED_LENGTH_ALIAS_FLAG:
|
|
// SampDumpPSAMP_V1_FIXED_LENGTH_ALIAS(NewValue, NewValueLength);
|
|
break;
|
|
|
|
case FIXED_LENGTH_GROUP_FLAG:
|
|
SampDumpPSAMP_V1_0A_FIXED_LENGTH_GROUP(NewValue, NewValueLength);
|
|
break;
|
|
|
|
case FIXED_LENGTH_USER_FLAG:
|
|
SampDumpPSAMP_V1_0A_FIXED_LENGTH_USER(NewValue, NewValueLength);
|
|
break;
|
|
|
|
case VARIABLE_LENGTH_ATTRIBUTE_FLAG:
|
|
SampDumpSAMP_VARIABLE_LENGTH_ATTRIBUTE(NewValue, NewValueLength);
|
|
break;
|
|
|
|
case FixedBufferAddressFlag:
|
|
SampDumpSampFixedBufferAddress(NewValue, NewValueLength);
|
|
break;
|
|
|
|
default:
|
|
SampDumpBuffer(NewValue, NewValueLength);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|