2025-05-13 19:49:49 +03:00

330 lines
9.6 KiB
C

/*
* Process Hacker Extra Plugins -
* Pool Table Plugin
*
* Copyright (C) 2016 dmex
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
PPH_STRING TrimString(
_In_ PPH_STRING String
)
{
static PH_STRINGREF whitespace = PH_STRINGREF_INIT(L" \t");
PH_STRINGREF sr = String->sr;
PhTrimStringRef(&sr, &whitespace, 0);
return PhCreateString2(&sr);
}
PPH_STRING FindPoolTagFilePath(
VOID
)
{
static struct
{
ULONG Folder;
PWSTR AppendPath;
} locations[] =
{
#ifdef _WIN64
{ CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\triage\\pooltag.txt" },
{ CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\triage\\pooltag.txt" },
{ CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\triage\\pooltag.txt" },
{ CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\triage\\pooltag.txt" }
#else
{ CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\triage\\pooltag.txt" },
{ CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\triage\\pooltag.txt" },
{ CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\triage\\pooltag.txt" },
{ CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\triage\\pooltag.txt" }
#endif
};
PPH_STRING path;
ULONG i;
for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++)
{
path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath);
if (path)
{
if (RtlDoesFileExists_U(path->Buffer))
return path;
PhDereferenceObject(path);
}
}
return NULL;
}
BOOLEAN PmPoolTagListHashtableEqualFunction(
_In_ PVOID Entry1,
_In_ PVOID Entry2
)
{
PPOOL_TAG_LIST_ENTRY poolTagNode1 = *(PPOOL_TAG_LIST_ENTRY *)Entry1;
PPOOL_TAG_LIST_ENTRY poolTagNode2 = *(PPOOL_TAG_LIST_ENTRY *)Entry2;
return poolTagNode1->TagUlong == poolTagNode2->TagUlong;
}
ULONG PmPoolTagListHashtableHashFunction(
_In_ PVOID Entry
)
{
return (*(PPOOL_TAG_LIST_ENTRY*)Entry)->TagUlong;
}
PPOOL_TAG_LIST_ENTRY FindPoolTagListEntry(
_In_ PPOOLTAG_CONTEXT Context,
_In_ ULONG PoolTag
)
{
POOL_TAG_LIST_ENTRY lookupWindowNode;
PPOOL_TAG_LIST_ENTRY lookupWindowNodePtr = &lookupWindowNode;
PPOOL_TAG_LIST_ENTRY *windowNode;
lookupWindowNode.TagUlong = PoolTag;
windowNode = (PPOOL_TAG_LIST_ENTRY*)PhFindEntryHashtable(
Context->PoolTagDbHashtable,
&lookupWindowNodePtr
);
if (windowNode)
return *windowNode;
else
return NULL;
}
VOID LoadPoolTagDatabase(
_In_ PPOOLTAG_CONTEXT Context
)
{
static PH_STRINGREF skipPoolTagFileHeader = PH_STRINGREF_INIT(L"\r\n\r\n");
static PH_STRINGREF skipPoolTagFileLine = PH_STRINGREF_INIT(L"\r\n");
PPH_STRING poolTagFilePath;
HANDLE fileHandle = NULL;
LARGE_INTEGER fileSize;
ULONG stringBufferLength;
PSTR stringBuffer;
PPH_STRING utf16StringBuffer = NULL;
IO_STATUS_BLOCK isb;
Context->PoolTagDbList = PhCreateList(100);
Context->PoolTagDbHashtable = PhCreateHashtable(
sizeof(PPOOL_TAG_LIST_ENTRY),
PmPoolTagListHashtableEqualFunction,
PmPoolTagListHashtableHashFunction,
100
);
if (poolTagFilePath = FindPoolTagFilePath())
{
if (!NT_SUCCESS(PhCreateFileWin32(
&fileHandle,
poolTagFilePath->Buffer,
FILE_GENERIC_READ,
0,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
)))
{
PhDereferenceObject(poolTagFilePath);
return;
}
if (!NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)))
{
NtClose(fileHandle);
PhDereferenceObject(poolTagFilePath);
return;
}
if (fileSize.QuadPart == 0)
{
NtClose(fileHandle);
PhDereferenceObject(poolTagFilePath);
return;
}
stringBufferLength = (ULONG)fileSize.QuadPart + 1;
stringBuffer = PhAllocate(stringBufferLength);
memset(stringBuffer, 0, stringBufferLength);
if (NT_SUCCESS(NtReadFile(
fileHandle,
NULL,
NULL,
NULL,
&isb,
stringBuffer,
(ULONG)fileSize.QuadPart,
NULL,
NULL
)))
{
utf16StringBuffer = PhZeroExtendToUtf16(stringBuffer);
}
PhFree(stringBuffer);
NtClose(fileHandle);
PhDereferenceObject(poolTagFilePath);
}
else
{
HRSRC resourceHandle;
// Find the resource
if (resourceHandle = FindResource(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDR_TXT_POOLTAGS),
L"TXT")
)
{
ULONG resourceLength;
HGLOBAL resourceBuffer;
PSTR utf16Buffer;
// Get the resource length
resourceLength = SizeofResource(PluginInstance->DllBase, resourceHandle);
// Load the resource
if (resourceBuffer = LoadResource(PluginInstance->DllBase, resourceHandle))
{
utf16Buffer = (PSTR)LockResource(resourceBuffer);
utf16StringBuffer = PhZeroExtendToUtf16Ex(utf16Buffer, resourceLength);
}
FreeResource(resourceBuffer);
}
}
if (utf16StringBuffer)
{
PH_STRINGREF firstPart;
PH_STRINGREF remainingPart;
PH_STRINGREF poolTagPart;
PH_STRINGREF binaryNamePart;
PH_STRINGREF descriptionPart;
remainingPart = utf16StringBuffer->sr;
PhSplitStringRefAtString(&remainingPart, &skipPoolTagFileHeader, TRUE, &firstPart, &remainingPart);
while (remainingPart.Length != 0)
{
PhSplitStringRefAtString(&remainingPart, &skipPoolTagFileLine, TRUE, &firstPart, &remainingPart);
if (firstPart.Length != 0)
{
PPOOL_TAG_LIST_ENTRY entry;
PPH_STRING poolTagString;
PPH_STRING poolTag;
PPH_STRING binaryName;
PPH_STRING description;
if (!PhSplitStringRefAtChar(&firstPart, '-', &poolTagPart, &firstPart))
continue;
if (!PhSplitStringRefAtChar(&firstPart, '-', &binaryNamePart, &firstPart))
continue;
// Note: Some entries don't have descriptions
PhSplitStringRefAtChar(&firstPart, '-', &descriptionPart, &firstPart);
poolTag = PhCreateString2(&poolTagPart);
binaryName = PhCreateString2(&binaryNamePart);
description = PhCreateString2(&descriptionPart);
entry = PhAllocate(sizeof(POOL_TAG_LIST_ENTRY));
memset(entry, 0, sizeof(POOL_TAG_LIST_ENTRY));
// Strip leading/trailing space characters.
poolTagString = TrimString(poolTag);
entry->BinaryNameString = TrimString(binaryName);
entry->DescriptionString = TrimString(description);
// Convert the poolTagString to ULONG
PhConvertUtf16ToUtf8Buffer(
entry->Tag,
sizeof(entry->Tag),
NULL,
poolTagString->Buffer,
poolTagString->Length
);
PhAddEntryHashtable(Context->PoolTagDbHashtable, &entry);
PhAddItemList(Context->PoolTagDbList, entry);
PhDereferenceObject(description);
PhDereferenceObject(binaryName);
PhDereferenceObject(poolTag);
PhDereferenceObject(poolTagString);
}
}
PhDereferenceObject(utf16StringBuffer);
}
}
VOID FreePoolTagDatabase(
_In_ PPOOLTAG_CONTEXT Context
)
{
for (ULONG i = 0; i < Context->PoolTagDbList->Count; i++)
{
PPOOL_TAG_LIST_ENTRY entry = Context->PoolTagDbList->Items[i];
PhDereferenceObject(entry->DescriptionString);
PhDereferenceObject(entry->BinaryNameString);
PhFree(entry);
}
PhClearHashtable(Context->PoolTagDbHashtable);
PhClearList(Context->PoolTagDbList);
}
VOID UpdatePoolTagBinaryName(
_In_ PPOOLTAG_CONTEXT Context,
_In_ PPOOL_ITEM PoolEntry,
_In_ ULONG TagUlong
)
{
PPOOL_TAG_LIST_ENTRY client;
if (client = FindPoolTagListEntry(Context, TagUlong))
{
PoolEntry->BinaryNameString = client->BinaryNameString;
PoolEntry->DescriptionString = client->DescriptionString;
if (PhStartsWithString2(PoolEntry->BinaryNameString, L"nt!", FALSE))
{
PoolEntry->Type = TPOOLTAG_TREE_ITEM_TYPE_OBJECT;
}
//if (PhEndsWithString2(PoolEntry->BinaryNameString, L".sys", FALSE))
//PoolEntry->Type = TPOOLTAG_TREE_ITEM_TYPE_DRIVER;
}
}