go my file uploader

This commit is contained in:
AirDog46
2025-05-13 19:45:22 +03:00
commit c5fab8aa94
708 changed files with 343216 additions and 0 deletions

68
phlib/apiimport.c Normal file
View File

@@ -0,0 +1,68 @@
/*
* Process Hacker -
* procedure import module
*
* Copyright (C) 2015 wj32
*
* 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 <ph.h>
#include <apiimport.h>
PVOID PhpImportProcedure(
_Inout_ PVOID *Cache,
_Inout_ PBOOLEAN CacheValid,
_In_ PWSTR ModuleName,
_In_ PSTR ProcedureName
)
{
HMODULE module;
PVOID procedure;
if (*CacheValid)
return *Cache;
module = GetModuleHandle(ModuleName);
if (!module)
return NULL;
procedure = GetProcAddress(module, ProcedureName);
*Cache = procedure;
MemoryBarrier();
*CacheValid = TRUE;
return procedure;
}
#define PH_DEFINE_IMPORT(Module, Name) \
_##Name Name##_Import(VOID) \
{ \
static PVOID cache = NULL; \
static BOOLEAN cacheValid = FALSE; \
\
return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \
}
PH_DEFINE_IMPORT(L"comctl32.dll", TaskDialogIndirect);
PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment);
PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager);
PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction);
PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransactionManager);
PH_DEFINE_IMPORT(L"shell32.dll", SHCreateShellItem);
PH_DEFINE_IMPORT(L"shell32.dll", SHOpenFolderAndSelectItems);
PH_DEFINE_IMPORT(L"shell32.dll", SHParseDisplayName);

1081
phlib/avltree.c Normal file

File diff suppressed because it is too large Load Diff

5983
phlib/basesup.c Normal file

File diff suppressed because it is too large Load Diff

22
phlib/circbuf.c Normal file
View File

@@ -0,0 +1,22 @@
#include <phbase.h>
#include <circbuf.h>
#undef T
#define T ULONG
#include "circbuf_i.h"
#undef T
#define T ULONG64
#include "circbuf_i.h"
#undef T
#define T PVOID
#include "circbuf_i.h"
#undef T
#define T SIZE_T
#include "circbuf_i.h"
#undef T
#define T FLOAT
#include "circbuf_i.h"

121
phlib/circbuf_i.h Normal file
View File

@@ -0,0 +1,121 @@
#ifdef T
#include <templ.h>
VOID T___(PhInitializeCircularBuffer, T)(
_Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ ULONG Size
)
{
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
Buffer->Size = PhRoundUpToPowerOfTwo(Size);
Buffer->SizeMinusOne = Buffer->Size - 1;
#else
Buffer->Size = Size;
#endif
Buffer->Count = 0;
Buffer->Index = 0;
Buffer->Data = PhAllocate(sizeof(T) * Buffer->Size);
}
VOID T___(PhDeleteCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer
)
{
PhFree(Buffer->Data);
}
VOID T___(PhResizeCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ ULONG NewSize
)
{
T *newData;
ULONG tailSize;
ULONG headSize;
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
NewSize = PhRoundUpToPowerOfTwo(NewSize);
#endif
// If we're not actually resizing it, return.
if (NewSize == Buffer->Size)
return;
newData = PhAllocate(sizeof(T) * NewSize);
tailSize = (ULONG)(Buffer->Size - Buffer->Index);
headSize = Buffer->Count - tailSize;
if (NewSize > Buffer->Size)
{
// Copy the tail, then the head.
memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);
memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * headSize);
Buffer->Index = 0;
}
else
{
if (tailSize >= NewSize)
{
// Copy only a part of the tail.
memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * NewSize);
Buffer->Index = 0;
}
else
{
// Copy the tail, then only part of the head.
memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);
memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * (NewSize - tailSize));
Buffer->Index = 0;
}
// Since we're making the circular buffer smaller, limit the count.
if (Buffer->Count > NewSize)
Buffer->Count = NewSize;
}
Buffer->Data = newData;
Buffer->Size = NewSize;
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
Buffer->SizeMinusOne = NewSize - 1;
#endif
}
VOID T___(PhClearCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer
)
{
Buffer->Count = 0;
Buffer->Index = 0;
}
VOID T___(PhCopyCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_Out_writes_(Count) T *Destination,
_In_ ULONG Count
)
{
ULONG tailSize;
ULONG headSize;
tailSize = (ULONG)(Buffer->Size - Buffer->Index);
headSize = Buffer->Count - tailSize;
if (Count > Buffer->Count)
Count = Buffer->Count;
if (tailSize >= Count)
{
// Copy only a part of the tail.
memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * Count);
}
else
{
// Copy the tail, then only part of the head.
memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize);
memcpy(&Destination[tailSize], Buffer->Data, sizeof(T) * (Count - tailSize));
}
}
#endif

228
phlib/colorbox.c Normal file
View File

@@ -0,0 +1,228 @@
/*
* Process Hacker -
* color picker
*
* Copyright (C) 2010 wj32
*
* 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 <ph.h>
#include <guisup.h>
#include <colorbox.h>
#include <commdlg.h>
typedef struct _PHP_COLORBOX_CONTEXT
{
COLORREF SelectedColor;
BOOLEAN Hot;
BOOLEAN HasFocus;
} PHP_COLORBOX_CONTEXT, *PPHP_COLORBOX_CONTEXT;
LRESULT CALLBACK PhpColorBoxWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
BOOLEAN PhColorBoxInitialization(
VOID
)
{
WNDCLASSEX c = { sizeof(c) };
c.style = CS_GLOBALCLASS;
c.lpfnWndProc = PhpColorBoxWndProc;
c.cbClsExtra = 0;
c.cbWndExtra = sizeof(PVOID);
c.hInstance = PhLibImageBase;
c.hIcon = NULL;
c.hCursor = LoadCursor(NULL, IDC_ARROW);
c.hbrBackground = NULL;
c.lpszMenuName = NULL;
c.lpszClassName = PH_COLORBOX_CLASSNAME;
c.hIconSm = NULL;
if (!RegisterClassEx(&c))
return FALSE;
return TRUE;
}
VOID PhpCreateColorBoxContext(
_Out_ PPHP_COLORBOX_CONTEXT *Context
)
{
PPHP_COLORBOX_CONTEXT context;
context = PhAllocate(sizeof(PHP_COLORBOX_CONTEXT));
memset(context, 0, sizeof(PHP_COLORBOX_CONTEXT));
*Context = context;
}
VOID PhpFreeColorBoxContext(
_In_ _Post_invalid_ PPHP_COLORBOX_CONTEXT Context
)
{
PhFree(Context);
}
VOID PhpChooseColor(
_In_ HWND hwnd,
_In_ PPHP_COLORBOX_CONTEXT Context
)
{
CHOOSECOLOR chooseColor = { sizeof(chooseColor) };
COLORREF customColors[16] = { 0 };
chooseColor.hwndOwner = hwnd;
chooseColor.rgbResult = Context->SelectedColor;
chooseColor.lpCustColors = customColors;
chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;
if (ChooseColor(&chooseColor))
{
Context->SelectedColor = chooseColor.rgbResult;
InvalidateRect(hwnd, NULL, TRUE);
}
}
LRESULT CALLBACK PhpColorBoxWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PPHP_COLORBOX_CONTEXT context;
context = (PPHP_COLORBOX_CONTEXT)GetWindowLongPtr(hwnd, 0);
if (uMsg == WM_CREATE)
{
PhpCreateColorBoxContext(&context);
SetWindowLongPtr(hwnd, 0, (LONG_PTR)context);
}
if (!context)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_CREATE:
{
// Nothing
}
break;
case WM_DESTROY:
{
PhpFreeColorBoxContext(context);
SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL);
}
break;
case WM_PAINT:
{
PAINTSTRUCT paintStruct;
RECT clientRect;
HDC hdc;
if (hdc = BeginPaint(hwnd, &paintStruct))
{
GetClientRect(hwnd, &clientRect);
// Border color
SetDCPenColor(hdc, RGB(0x44, 0x44, 0x44));
// Fill color
if (!context->Hot && !context->HasFocus)
SetDCBrushColor(hdc, context->SelectedColor);
else
SetDCBrushColor(hdc, PhMakeColorBrighter(context->SelectedColor, 64));
// Draw the rectangle.
SelectObject(hdc, GetStockObject(DC_PEN));
SelectObject(hdc, GetStockObject(DC_BRUSH));
Rectangle(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);
EndPaint(hwnd, &paintStruct);
}
}
return 0;
case WM_ERASEBKGND:
return 1;
case WM_MOUSEMOVE:
{
if (!context->Hot)
{
TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) };
context->Hot = TRUE;
InvalidateRect(hwnd, NULL, TRUE);
trackMouseEvent.dwFlags = TME_LEAVE;
trackMouseEvent.hwndTrack = hwnd;
TrackMouseEvent(&trackMouseEvent);
}
}
break;
case WM_MOUSELEAVE:
{
context->Hot = FALSE;
InvalidateRect(hwnd, NULL, TRUE);
}
break;
case WM_LBUTTONDOWN:
{
PhpChooseColor(hwnd, context);
}
break;
case WM_SETFOCUS:
{
context->HasFocus = TRUE;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_KILLFOCUS:
{
context->HasFocus = FALSE;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_GETDLGCODE:
if (wParam == VK_RETURN)
return DLGC_WANTMESSAGE;
return 0;
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_SPACE:
case VK_RETURN:
PhpChooseColor(hwnd, context);
break;
}
}
break;
case CBCM_SETCOLOR:
context->SelectedColor = (COLORREF)wParam;
return TRUE;
case CBCM_GETCOLOR:
return (LRESULT)context->SelectedColor;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

573
phlib/cpysave.c Normal file
View File

@@ -0,0 +1,573 @@
/*
* Process Hacker -
* copy/save code for listviews and treelists
*
* Copyright (C) 2010-2012 wj32
*
* 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 <ph.h>
#include <guisup.h>
#include <treenew.h>
#include <cpysave.h>
#define TAB_SIZE 8
VOID PhpEscapeStringForCsv(
_Inout_ PPH_STRING_BUILDER StringBuilder,
_In_ PPH_STRING String
)
{
SIZE_T i;
SIZE_T length;
PWCHAR runStart;
SIZE_T runLength;
length = String->Length / sizeof(WCHAR);
runStart = NULL;
for (i = 0; i < length; i++)
{
switch (String->Buffer[i])
{
case '\"':
if (runStart)
{
PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));
runStart = NULL;
}
PhAppendStringBuilder2(StringBuilder, L"\"\"");
break;
default:
if (runStart)
{
runLength++;
}
else
{
runStart = &String->Buffer[i];
runLength = 1;
}
break;
}
}
if (runStart)
PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));
}
/**
* Allocates a text table.
*
* \param Table A variable which receives a pointer to the text table.
* \param Rows The number of rows in the table.
* \param Columns The number of columns in the table.
*/
VOID PhaCreateTextTable(
_Out_ PPH_STRING ***Table,
_In_ ULONG Rows,
_In_ ULONG Columns
)
{
PPH_STRING **table;
ULONG i;
table = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING *) * Rows));
for (i = 0; i < Rows; i++)
{
table[i] = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING) * Columns));
memset(table[i], 0, sizeof(PPH_STRING) * Columns);
}
*Table = table;
}
/**
* Formats a text table to a list of lines.
*
* \param Table A pointer to the text table.
* \param Rows The number of rows in the table.
* \param Columns The number of columns in the table.
* \param Mode The export formatting mode.
*
* \return A list of strings for each line in the output. The list object and
* string objects are not auto-dereferenced.
*/
PPH_LIST PhaFormatTextTable(
_In_ PPH_STRING **Table,
_In_ ULONG Rows,
_In_ ULONG Columns,
_In_ ULONG Mode
)
{
PPH_LIST lines;
// The tab count array contains the number of tabs need to fill the biggest
// row cell in each column.
PULONG tabCount;
ULONG i;
ULONG j;
if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES)
{
// Create the tab count array.
tabCount = PH_AUTO(PhCreateAlloc(sizeof(ULONG) * Columns));
memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values
for (i = 0; i < Rows; i++)
{
for (j = 0; j < Columns; j++)
{
ULONG newCount;
if (Table[i][j])
newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);
else
newCount = 0;
// Replace the existing count if this tab count is bigger.
if (tabCount[j] < newCount)
tabCount[j] = newCount;
}
}
}
// Create the final list of lines by going through each cell and appending
// the proper tab count (if we are using tabs). This will make sure each column
// is properly aligned.
lines = PhCreateList(Rows);
for (i = 0; i < Rows; i++)
{
PH_STRING_BUILDER stringBuilder;
PhInitializeStringBuilder(&stringBuilder, 100);
switch (Mode)
{
case PH_EXPORT_MODE_TABS:
{
for (j = 0; j < Columns; j++)
{
ULONG k;
if (Table[i][j])
{
// Calculate the number of tabs needed.
k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);
PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr);
}
else
{
k = tabCount[j] + 1;
}
PhAppendCharStringBuilder2(&stringBuilder, '\t', k);
}
}
break;
case PH_EXPORT_MODE_SPACES:
{
for (j = 0; j < Columns; j++)
{
ULONG k;
if (Table[i][j])
{
// Calculate the number of spaces needed.
k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR));
PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr);
}
else
{
k = (tabCount[j] + 1) * TAB_SIZE;
}
PhAppendCharStringBuilder2(&stringBuilder, ' ', k);
}
}
break;
case PH_EXPORT_MODE_CSV:
{
for (j = 0; j < Columns; j++)
{
PhAppendCharStringBuilder(&stringBuilder, '\"');
if (Table[i][j])
{
PhpEscapeStringForCsv(&stringBuilder, Table[i][j]);
}
PhAppendCharStringBuilder(&stringBuilder, '\"');
if (j != Columns - 1)
PhAppendCharStringBuilder(&stringBuilder, ',');
}
}
break;
}
PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder));
}
return lines;
}
VOID PhMapDisplayIndexTreeNew(
_In_ HWND TreeNewHandle,
_Out_opt_ PULONG *DisplayToId,
_Out_opt_ PWSTR **DisplayToText,
_Out_ PULONG NumberOfColumns
)
{
PPH_TREENEW_COLUMN fixedColumn;
ULONG numberOfColumns;
PULONG displayToId;
PWSTR *displayToText;
ULONG i;
PH_TREENEW_COLUMN column;
fixedColumn = TreeNew_GetFixedColumn(TreeNewHandle);
numberOfColumns = TreeNew_GetVisibleColumnCount(TreeNewHandle);
displayToId = PhAllocate(numberOfColumns * sizeof(ULONG));
if (fixedColumn)
{
TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns - 1, displayToId + 1);
displayToId[0] = fixedColumn->Id;
}
else
{
TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns, displayToId);
}
if (DisplayToText)
{
displayToText = PhAllocate(numberOfColumns * sizeof(PWSTR));
for (i = 0; i < numberOfColumns; i++)
{
if (TreeNew_GetColumn(TreeNewHandle, displayToId[i], &column))
{
displayToText[i] = column.Text;
}
}
*DisplayToText = displayToText;
}
if (DisplayToId)
*DisplayToId = displayToId;
else
PhFree(displayToId);
*NumberOfColumns = numberOfColumns;
}
PPH_STRING PhGetTreeNewText(
_In_ HWND TreeNewHandle,
_Reserved_ ULONG Reserved
)
{
PH_STRING_BUILDER stringBuilder;
PULONG displayToId;
ULONG rows;
ULONG columns;
ULONG i;
ULONG j;
PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, NULL, &columns);
rows = TreeNew_GetFlatNodeCount(TreeNewHandle);
PhInitializeStringBuilder(&stringBuilder, 0x100);
for (i = 0; i < rows; i++)
{
PH_TREENEW_GET_CELL_TEXT getCellText;
getCellText.Node = TreeNew_GetFlatNode(TreeNewHandle, i);
assert(getCellText.Node);
if (!getCellText.Node->Selected)
continue;
for (j = 0; j < columns; j++)
{
getCellText.Id = displayToId[j];
PhInitializeEmptyStringRef(&getCellText.Text);
TreeNew_GetCellText(TreeNewHandle, &getCellText);
PhAppendStringBuilder(&stringBuilder, &getCellText.Text);
PhAppendStringBuilder2(&stringBuilder, L", ");
}
// Remove the trailing comma and space.
if (stringBuilder.String->Length != 0)
PhRemoveEndStringBuilder(&stringBuilder, 2);
PhAppendStringBuilder2(&stringBuilder, L"\r\n");
}
PhFree(displayToId);
return PhFinalStringBuilderString(&stringBuilder);
}
PPH_LIST PhGetGenericTreeNewLines(
_In_ HWND TreeNewHandle,
_In_ ULONG Mode
)
{
PH_AUTO_POOL autoPool;
PPH_LIST lines;
ULONG rows;
ULONG columns;
ULONG numberOfNodes;
PULONG displayToId;
PWSTR *displayToText;
PPH_STRING **table;
ULONG i;
ULONG j;
PhInitializeAutoPool(&autoPool);
numberOfNodes = TreeNew_GetFlatNodeCount(TreeNewHandle);
rows = numberOfNodes + 1;
PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, &displayToText, &columns);
PhaCreateTextTable(&table, rows, columns);
for (i = 0; i < columns; i++)
table[0][i] = PhaCreateString(displayToText[i]);
for (i = 0; i < numberOfNodes; i++)
{
PPH_TREENEW_NODE node;
node = TreeNew_GetFlatNode(TreeNewHandle, i);
if (node)
{
for (j = 0; j < columns; j++)
{
PH_TREENEW_GET_CELL_TEXT getCellText;
getCellText.Node = node;
getCellText.Id = displayToId[j];
PhInitializeEmptyStringRef(&getCellText.Text);
TreeNew_GetCellText(TreeNewHandle, &getCellText);
table[i + 1][j] = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);
}
}
else
{
for (j = 0; j < columns; j++)
{
table[i + 1][j] = PH_AUTO(PhReferenceEmptyString());
}
}
}
PhFree(displayToText);
PhFree(displayToId);
lines = PhaFormatTextTable(table, rows, columns, Mode);
PhDeleteAutoPool(&autoPool);
return lines;
}
VOID PhaMapDisplayIndexListView(
_In_ HWND ListViewHandle,
_Out_writes_(Count) PULONG DisplayToId,
_Out_writes_opt_(Count) PPH_STRING *DisplayToText,
_In_ ULONG Count,
_Out_ PULONG NumberOfColumns
)
{
LVCOLUMN lvColumn;
ULONG i;
ULONG count;
WCHAR buffer[128];
count = 0;
lvColumn.mask = LVCF_ORDER | LVCF_TEXT;
lvColumn.pszText = buffer;
lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR);
for (i = 0; i < Count; i++)
{
if (ListView_GetColumn(ListViewHandle, i, &lvColumn))
{
ULONG displayIndex;
displayIndex = (ULONG)lvColumn.iOrder;
assert(displayIndex < Count);
DisplayToId[displayIndex] = i;
if (DisplayToText)
DisplayToText[displayIndex] = PhaCreateString(buffer);
count++;
}
else
{
break;
}
}
*NumberOfColumns = count;
}
PPH_STRING PhaGetListViewItemText(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ INT SubItemIndex
)
{
PPH_STRING buffer;
SIZE_T allocatedCount;
SIZE_T count;
LVITEM lvItem;
// Unfortunately LVM_GETITEMTEXT doesn't want to return the actual length of the text.
// Keep doubling the buffer size until we get a return count that is strictly less than
// the amount we allocated.
buffer = NULL;
allocatedCount = 256;
count = allocatedCount;
while (count >= allocatedCount)
{
if (buffer)
PhDereferenceObject(buffer);
allocatedCount *= 2;
buffer = PhCreateStringEx(NULL, allocatedCount * sizeof(WCHAR));
buffer->Buffer[0] = 0;
lvItem.iSubItem = SubItemIndex;
lvItem.cchTextMax = (INT)allocatedCount + 1;
lvItem.pszText = buffer->Buffer;
count = SendMessage(ListViewHandle, LVM_GETITEMTEXT, Index, (LPARAM)&lvItem);
}
PhTrimToNullTerminatorString(buffer);
PH_AUTO(buffer);
return buffer;
}
PPH_STRING PhGetListViewText(
_In_ HWND ListViewHandle
)
{
PH_AUTO_POOL autoPool;
PH_STRING_BUILDER stringBuilder;
ULONG displayToId[100];
ULONG rows;
ULONG columns;
ULONG i;
ULONG j;
PhInitializeAutoPool(&autoPool);
PhaMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns);
rows = ListView_GetItemCount(ListViewHandle);
PhInitializeStringBuilder(&stringBuilder, 0x100);
for (i = 0; i < rows; i++)
{
if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))
continue;
for (j = 0; j < columns; j++)
{
PhAppendStringBuilder(&stringBuilder, &PhaGetListViewItemText(ListViewHandle, i, j)->sr);
PhAppendStringBuilder2(&stringBuilder, L", ");
}
// Remove the trailing comma and space.
if (stringBuilder.String->Length != 0)
PhRemoveEndStringBuilder(&stringBuilder, 2);
PhAppendStringBuilder2(&stringBuilder, L"\r\n");
}
PhDeleteAutoPool(&autoPool);
return PhFinalStringBuilderString(&stringBuilder);
}
PPH_LIST PhGetListViewLines(
_In_ HWND ListViewHandle,
_In_ ULONG Mode
)
{
PH_AUTO_POOL autoPool;
PPH_LIST lines;
ULONG rows;
ULONG columns;
ULONG displayToId[100];
PPH_STRING displayToText[100];
PPH_STRING **table;
ULONG i;
ULONG j;
PhInitializeAutoPool(&autoPool);
rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers
// Create the display index/text to ID map.
PhaMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns);
PhaCreateTextTable(&table, rows, columns);
// Populate the first row with the column headers.
for (i = 0; i < columns; i++)
table[0][i] = displayToText[i];
// Populate the other rows with text.
for (i = 1; i < rows; i++)
{
for (j = 0; j < columns; j++)
{
// Important: use this to bypass extlv's hooking.
// extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT.
table[i][j] = PhaGetListViewItemText(ListViewHandle, i - 1, j);
}
}
lines = PhaFormatTextTable(table, rows, columns, Mode);
PhDeleteAutoPool(&autoPool);
return lines;
}

219
phlib/data.c Normal file
View File

@@ -0,0 +1,219 @@
#include <ph.h>
#include <phdata.h>
// SIDs
SID PhSeNobodySid = { SID_REVISION, 1, SECURITY_NULL_SID_AUTHORITY, { SECURITY_NULL_RID } };
SID PhSeEveryoneSid = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } };
SID PhSeLocalSid = { SID_REVISION, 1, SECURITY_LOCAL_SID_AUTHORITY, { SECURITY_LOCAL_RID } };
SID PhSeCreatorOwnerSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_OWNER_RID } };
SID PhSeCreatorGroupSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_GROUP_RID } };
SID PhSeDialupSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_DIALUP_RID } };
SID PhSeNetworkSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_RID } };
SID PhSeBatchSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_BATCH_RID } };
SID PhSeInteractiveSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_INTERACTIVE_RID } };
SID PhSeServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_SERVICE_RID } };
SID PhSeAnonymousLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_ANONYMOUS_LOGON_RID } };
SID PhSeProxySid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_PROXY_RID } };
SID PhSeAuthenticatedUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_AUTHENTICATED_USER_RID } };
SID PhSeRestrictedCodeSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_RESTRICTED_CODE_RID } };
SID PhSeTerminalServerUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_TERMINAL_SERVER_RID } };
SID PhSeRemoteInteractiveLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_REMOTE_LOGON_RID } };
SID PhSeLocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } };
SID PhSeLocalServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SERVICE_RID } };
SID PhSeNetworkServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } };
// Unicode
PH_STRINGREF PhUnicodeByteOrderMark = PH_STRINGREF_INIT(L"\ufeff");
// Characters
DECLSPEC_SELECTANY
BOOLEAN PhCharIsPrintable[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 - 15 */ // TAB, LF and CR are printable
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ' ' - '/' */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* '0' - '9' */
1, 1, 1, 1, 1, 1, 1, /* ':' - '@' */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'A' - 'Z' */
1, 1, 1, 1, 1, 1, /* '[' - '`' */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'a' - 'z' */
1, 1, 1, 1, 0, /* '{' - 127 */ // DEL is not printable
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 - 143 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 - 159 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 175 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 - 191 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 - 207 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 - 223 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 - 239 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 240 - 255 */
};
DECLSPEC_SELECTANY
ULONG PhCharToInteger[256] =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 15 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 - 31 */
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* ' ' - '/' */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */
52, 53, 54, 55, 56, 57, 58, /* ':' - '@' */
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'A' - 'Z' */
59, 60, 61, 62, 63, 64, /* '[' - '`' */
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'a' - 'z' */
65, 66, 67, 68, -1, /* '{' - 127 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 - 143 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 - 159 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 - 175 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 - 191 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 - 207 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 - 223 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 - 239 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 240 - 255 */
};
DECLSPEC_SELECTANY
CHAR PhIntegerToChar[69] =
"0123456789" /* 0 - 9 */
"abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */
" !\"#$%&'()*+,-./" /* 36 - 51 */
":;<=>?@" /* 52 - 58 */
"[\\]^_`" /* 59 - 64 */
"{|}~" /* 65 - 68 */
;
DECLSPEC_SELECTANY
CHAR PhIntegerToCharUpper[69] =
"0123456789" /* 0 - 9 */
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 10 - 35 */
" !\"#$%&'()*+,-./" /* 36 - 51 */
":;<=>?@" /* 52 - 58 */
"[\\]^_`" /* 59 - 64 */
"{|}~" /* 65 - 68 */
;
// CRC32 (IEEE 802.3)
DECLSPEC_SELECTANY
ULONG PhCrc32Table[256] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
// Enums
DECLSPEC_SELECTANY
WCHAR *PhIoPriorityHintNames[MaxIoPriorityTypes] =
{
L"Very low",
L"Low",
L"Normal",
L"High",
L"Critical"
};
DECLSPEC_SELECTANY
WCHAR *PhPagePriorityNames[MEMORY_PRIORITY_NORMAL + 1] =
{
L"Lowest",
L"Very low",
L"Low",
L"Medium",
L"Below normal",
L"Normal"
};
DECLSPEC_SELECTANY
WCHAR *PhKThreadStateNames[MaximumThreadState] =
{
L"Initialized",
L"Ready",
L"Running",
L"Standby",
L"Terminated",
L"Waiting",
L"Transition",
L"DeferredReady",
L"GateWait",
L"WaitingForProcessInSwap"
};
DECLSPEC_SELECTANY
WCHAR *PhKWaitReasonNames[MaximumWaitReason] =
{
L"Executive",
L"FreePage",
L"PageIn",
L"PoolAllocation",
L"DelayExecution",
L"Suspended",
L"UserRequest",
L"WrExecutive",
L"WrFreePage",
L"WrPageIn",
L"WrPoolAllocation",
L"WrDelayExecution",
L"WrSuspended",
L"WrUserRequest",
L"WrEventPair",
L"WrQueue",
L"WrLpcReceive",
L"WrLpcReply",
L"WrVirtualMemory",
L"WrPageOut",
L"WrRendezvous",
L"WrKeyedEvent",
L"WrTerminated",
L"WrProcessInSwap",
L"WrCpuRateControl",
L"WrCalloutStack",
L"WrKernel",
L"WrResource",
L"WrPushLock",
L"WrMutex",
L"WrQuantumEnd",
L"WrDispatchInt",
L"WrPreempted",
L"WrYieldExecution",
L"WrFastMutex",
L"WrGuardedMutex",
L"WrRundown",
L"WrAlertByThreadId",
L"WrDeferredPreempt"
};

249
phlib/dspick.c Normal file
View File

@@ -0,0 +1,249 @@
/*
* Process Hacker -
* DS object picker wrapper
*
* Copyright (C) 2010 wj32
*
* 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 <ph.h>
#include <guisup.h>
#include <lsasup.h>
#include <dspick.h>
#include <ole2.h>
#define CINTERFACE
#define COBJMACROS
#include <objsel.h>
#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This))
#define IDataObject_Release(This) ((This)->lpVtbl->Release(This))
#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium))
#define IDsObjectPicker_QueryInterface(This, riid, ppvObject) ((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IDsObjectPicker_AddRef(This) ((This)->lpVtbl->AddRef(This))
#define IDsObjectPicker_Release(This) ((This)->lpVtbl->Release(This))
#define IDsObjectPicker_Initialize(This, pInitInfo) ((This)->lpVtbl->Initialize(This, pInitInfo))
#define IDsObjectPicker_InvokeDialog(This, hwndParent, ppdoSelections) ((This)->lpVtbl->InvokeDialog(This, hwndParent, ppdoSelections))
IDsObjectPicker *PhpCreateDsObjectPicker(
VOID
)
{
static CLSID CLSID_DsObjectPicker_I = { 0x17d6ccd8, 0x3b7b, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } };
static IID IID_IDsObjectPicker_I = { 0x0c87e64e, 0x3b7a, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } };
IDsObjectPicker *picker;
if (SUCCEEDED(CoCreateInstance(
&CLSID_DsObjectPicker_I,
NULL,
CLSCTX_INPROC_SERVER,
&IID_IDsObjectPicker_I,
&picker
)))
{
return picker;
}
else
{
return NULL;
}
}
VOID PhFreeDsObjectPickerDialog(
_In_ PVOID PickerDialog
)
{
IDsObjectPicker_Release((IDsObjectPicker *)PickerDialog);
}
PVOID PhCreateDsObjectPickerDialog(
_In_ ULONG Flags
)
{
IDsObjectPicker *picker;
DSOP_INIT_INFO initInfo;
DSOP_SCOPE_INIT_INFO scopeInit[1];
picker = PhpCreateDsObjectPicker();
if (!picker)
return NULL;
memset(scopeInit, 0, sizeof(scopeInit));
scopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
scopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER;
scopeInit[0].flScope =
DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT |
DSOP_SCOPE_FLAG_WANT_SID_PATH |
DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS |
DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
scopeInit[0].FilterFlags.Uplevel.flBothModes =
DSOP_FILTER_INCLUDE_ADVANCED_VIEW |
DSOP_FILTER_USERS |
DSOP_FILTER_BUILTIN_GROUPS |
DSOP_FILTER_WELL_KNOWN_PRINCIPALS;
scopeInit[0].FilterFlags.flDownlevel =
DSOP_DOWNLEVEL_FILTER_USERS |
DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS |
DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS |
DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS;
memset(&initInfo, 0, sizeof(DSOP_INIT_INFO));
initInfo.cbSize = sizeof(DSOP_INIT_INFO);
initInfo.pwzTargetComputer = NULL;
initInfo.cDsScopeInfos = 1;
initInfo.aDsScopeInfos = scopeInit;
initInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;
if (Flags & PH_DSPICK_MULTISELECT)
initInfo.flOptions |= DSOP_FLAG_MULTISELECT;
if (!SUCCEEDED(IDsObjectPicker_Initialize(picker, &initInfo)))
{
IDsObjectPicker_Release(picker);
return NULL;
}
return picker;
}
PDS_SELECTION_LIST PhpGetDsSelectionList(
_In_ IDataObject *Selections
)
{
FORMATETC format;
STGMEDIUM medium;
format.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(L"CFSTR_DSOP_DS_SELECTION_LIST");
format.ptd = NULL;
format.dwAspect = -1;
format.lindex = -1;
format.tymed = TYMED_HGLOBAL;
if (SUCCEEDED(IDataObject_GetData(Selections, &format, &medium)))
{
if (medium.tymed != TYMED_HGLOBAL)
return NULL;
return (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);
}
else
{
return NULL;
}
}
BOOLEAN PhShowDsObjectPickerDialog(
_In_ HWND hWnd,
_In_ PVOID PickerDialog,
_Out_ PPH_DSPICK_OBJECTS *Objects
)
{
IDsObjectPicker *picker;
IDataObject *dataObject;
PDS_SELECTION_LIST selections;
PPH_DSPICK_OBJECTS objects;
ULONG i;
picker = (IDsObjectPicker *)PickerDialog;
if (!SUCCEEDED(IDsObjectPicker_InvokeDialog(picker, hWnd, &dataObject)))
return FALSE;
if (!dataObject)
return FALSE;
selections = PhpGetDsSelectionList(dataObject);
IDataObject_Release(dataObject);
if (!selections)
return FALSE;
objects = PhAllocate(
FIELD_OFFSET(PH_DSPICK_OBJECTS, Objects) +
selections->cItems * sizeof(PH_DSPICK_OBJECT)
);
objects->NumberOfObjects = selections->cItems;
for (i = 0; i < selections->cItems; i++)
{
PDS_SELECTION selection;
PSID sid;
PH_STRINGREF path;
PH_STRINGREF prefix;
selection = &selections->aDsSelection[i];
objects->Objects[i].Name = PhCreateString(selection->pwzName);
objects->Objects[i].Sid = NULL;
if (selection->pwzADsPath && selection->pwzADsPath[0] != 0)
{
PhInitializeStringRef(&path, selection->pwzADsPath);
PhInitializeStringRef(&prefix, L"LDAP://<SID=");
if (PhStartsWithStringRef(&path, &prefix, TRUE))
{
PhSkipStringRef(&path, prefix.Length);
path.Length -= sizeof(WCHAR); // Ignore ">" at end
sid = PhAllocate(path.Length / sizeof(WCHAR) / 2);
if (PhHexStringToBuffer(&path, (PUCHAR)sid))
{
if (RtlValidSid(sid))
objects->Objects[i].Sid = sid;
else
PhFree(sid);
}
else
{
PhFree(sid);
}
}
}
else
{
// Try to get the SID.
PhLookupName(&objects->Objects[i].Name->sr, &objects->Objects[i].Sid, NULL, NULL);
}
}
*Objects = objects;
return TRUE;
}
VOID PhFreeDsObjectPickerObjects(
_In_ PPH_DSPICK_OBJECTS Objects
)
{
ULONG i;
for (i = 0; i < Objects->NumberOfObjects; i++)
{
PhDereferenceObject(Objects->Objects[i].Name);
if (Objects->Objects[i].Sid)
PhFree(Objects->Objects[i].Sid);
}
PhFree(Objects);
}

856
phlib/emenu.c Normal file
View File

@@ -0,0 +1,856 @@
/*
* Process Hacker -
* extended menus
*
* Copyright (C) 2010-2011 wj32
*
* 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 <ph.h>
#include <guisup.h>
#include <emenu.h>
static const PH_FLAG_MAPPING EMenuTypeMappings[] =
{
{ PH_EMENU_MENUBARBREAK, MFT_MENUBARBREAK },
{ PH_EMENU_MENUBREAK, MFT_MENUBREAK },
{ PH_EMENU_RADIOCHECK, MFT_RADIOCHECK }
};
static const PH_FLAG_MAPPING EMenuStateMappings[] =
{
{ PH_EMENU_CHECKED, MFS_CHECKED },
{ PH_EMENU_DEFAULT, MFS_DEFAULT },
{ PH_EMENU_DISABLED, MFS_DISABLED },
{ PH_EMENU_HIGHLIGHT, MFS_HILITE }
};
PPH_EMENU_ITEM PhAllocateEMenuItem(
VOID
)
{
PPH_EMENU_ITEM item;
item = PhAllocate(sizeof(PH_EMENU_ITEM));
memset(item, 0, sizeof(PH_EMENU_ITEM));
return item;
}
/**
* Creates a menu item.
*
* \param Flags A combination of the following:
* \li \c PH_EMENU_DISABLED The menu item is greyed and cannot be selected.
* \li \c PH_EMENU_CHECKED A check mark is displayed.
* \li \c PH_EMENU_HIGHLIGHT The menu item is highlighted.
* \li \c PH_EMENU_MENUBARBREAK Places the menu item in a new column, separated by a vertical line.
* \li \c PH_EMENU_MENUBREAK Places the menu item in a new column, with no vertical line.
* \li \c PH_EMENU_DEFAULT The menu item is displayed as the default item. This causes the text to
* be bolded.
* \li \c PH_EMENU_RADIOCHECK Uses a radio-button mark instead of a check mark.
* \param Id A unique identifier for the menu item.
* \param Text The text displayed for the menu item.
* \param Bitmap A bitmap image for the menu item.
* \param Context A user-defined value.
*/
PPH_EMENU_ITEM PhCreateEMenuItem(
_In_ ULONG Flags,
_In_ ULONG Id,
_In_ PWSTR Text,
_In_opt_ HBITMAP Bitmap,
_In_opt_ PVOID Context
)
{
PPH_EMENU_ITEM item;
item = PhAllocateEMenuItem();
item->Flags = Flags;
item->Id = Id;
item->Text = Text;
item->Bitmap = Bitmap;
item->Context = Context;
return item;
}
/**
* Frees resources used by a menu item and its children.
*
* \param Item The menu item.
*
* \remarks The menu item is NOT automatically removed from its parent. It is safe to call this
* function while enumerating menu items.
*/
VOID PhpDestroyEMenuItem(
_In_ PPH_EMENU_ITEM Item
)
{
if (Item->DeleteFunction)
Item->DeleteFunction(Item);
if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text)
PhFree(Item->Text);
if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap)
DeleteObject(Item->Bitmap);
if (Item->Items)
{
ULONG i;
for (i = 0; i < Item->Items->Count; i++)
{
PhpDestroyEMenuItem(Item->Items->Items[i]);
}
PhDereferenceObject(Item->Items);
}
PhFree(Item);
}
/**
* Frees resources used by a menu item and its children.
*
* \param Item The menu item.
*
* \remarks The menu item is automatically removed from its parent.
*/
VOID PhDestroyEMenuItem(
_In_ PPH_EMENU_ITEM Item
)
{
// Remove the item from its parent, if it has one.
if (Item->Parent)
PhRemoveEMenuItem(NULL, Item, -1);
PhpDestroyEMenuItem(Item);
}
/**
* Finds a child menu item.
*
* \param Item The parent menu item.
* \param Flags A combination of the following:
* \li \c PH_EMENU_FIND_DESCEND Searches recursively within child menu items.
* \li \c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search.
* \li \c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters
* (ampersands).
* \param Text The text of the menu item to find. If NULL, the text is ignored.
* \param Id The identifier of the menu item to find. If 0, the identifier is ignored.
*
* \return The found menu item, or NULL if the menu item could not be found.
*/
PPH_EMENU_ITEM PhFindEMenuItem(
_In_ PPH_EMENU_ITEM Item,
_In_ ULONG Flags,
_In_opt_ PWSTR Text,
_In_opt_ ULONG Id
)
{
return PhFindEMenuItemEx(Item, Flags, Text, Id, NULL, NULL);
}
/**
* Finds a child menu item.
*
* \param Item The parent menu item.
* \param Flags A combination of the following:
* \li \c PH_EMENU_FIND_DESCEND Searches recursively within child menu items.
* \li \c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search.
* \li \c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters
* (ampersands).
* \param Text The text of the menu item to find. If NULL, the text is ignored.
* \param Id The identifier of the menu item to find. If 0, the identifier is ignored.
* \param FoundParent A variable which receives the parent of the found menu item.
* \param FoundIndex A variable which receives the index of the found menu item.
*
* \return The found menu item, or NULL if the menu item could not be found.
*/
PPH_EMENU_ITEM PhFindEMenuItemEx(
_In_ PPH_EMENU_ITEM Item,
_In_ ULONG Flags,
_In_opt_ PWSTR Text,
_In_opt_ ULONG Id,
_Out_opt_ PPH_EMENU_ITEM *FoundParent,
_Out_opt_ PULONG FoundIndex
)
{
PH_STRINGREF searchText;
ULONG i;
PPH_EMENU_ITEM item;
if (!Item->Items)
return NULL;
if (Text && (Flags & PH_EMENU_FIND_LITERAL))
PhInitializeStringRef(&searchText, Text);
for (i = 0; i < Item->Items->Count; i++)
{
item = Item->Items->Items[i];
if (Text)
{
if (Flags & PH_EMENU_FIND_LITERAL)
{
PH_STRINGREF text;
PhInitializeStringRef(&text, item->Text);
if (Flags & PH_EMENU_FIND_STARTSWITH)
{
if (PhStartsWithStringRef(&text, &searchText, TRUE))
goto FoundItemHere;
}
else
{
if (PhEqualStringRef(&text, &searchText, TRUE))
goto FoundItemHere;
}
}
else
{
if (PhCompareUnicodeStringZIgnoreMenuPrefix(Text, item->Text,
TRUE, !!(Flags & PH_EMENU_FIND_STARTSWITH)) == 0)
goto FoundItemHere;
}
}
if (Id && item->Id == Id)
goto FoundItemHere;
if (Flags & PH_EMENU_FIND_DESCEND)
{
PPH_EMENU_ITEM foundItem;
PPH_EMENU_ITEM foundParent;
ULONG foundIndex;
foundItem = PhFindEMenuItemEx(item, Flags, Text, Id, &foundParent, &foundIndex);
if (foundItem)
{
if (FoundParent)
*FoundParent = foundParent;
if (FoundIndex)
*FoundIndex = foundIndex;
return foundItem;
}
}
}
return NULL;
FoundItemHere:
if (FoundParent)
*FoundParent = Item;
if (FoundIndex)
*FoundIndex = i;
return item;
}
/**
* Determines the index of a menu item.
*
* \param Parent The parent menu item.
* \param Item The child menu item.
*
* \return The index of the menu item, or -1 if the menu item was not found in the parent menu item.
*/
ULONG PhIndexOfEMenuItem(
_In_ PPH_EMENU_ITEM Parent,
_In_ PPH_EMENU_ITEM Item
)
{
if (!Parent->Items)
return -1;
return PhFindItemList(Parent->Items, Item);
}
/**
* Inserts a menu item into a parent menu item.
*
* \param Parent The parent menu item.
* \param Item The menu item to insert.
* \param Index The index at which to insert the menu item. If the index is too large, the menu item
* is inserted at the last position.
*/
VOID PhInsertEMenuItem(
_Inout_ PPH_EMENU_ITEM Parent,
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG Index
)
{
// Remove the item from its old parent if it has one.
if (Item->Parent)
PhRemoveEMenuItem(Item->Parent, Item, 0);
if (!Parent->Items)
Parent->Items = PhCreateList(16);
if (Index > Parent->Items->Count)
Index = Parent->Items->Count;
if (Index == -1)
PhAddItemList(Parent->Items, Item);
else
PhInsertItemList(Parent->Items, Index, Item);
Item->Parent = Parent;
}
/**
* Removes a menu item from its parent.
*
* \param Parent The parent menu item. If \a Item is NULL, this parameter must be specified.
* \param Item The child menu item. This may be NULL if \a Index is specified.
* \param Index The index of the menu item to remove. If \a Item is specified, this parameter is
* ignored.
*/
BOOLEAN PhRemoveEMenuItem(
_Inout_opt_ PPH_EMENU_ITEM Parent,
_In_opt_ PPH_EMENU_ITEM Item,
_In_opt_ ULONG Index
)
{
if (Item)
{
if (!Parent)
Parent = Item->Parent;
if (!Parent->Items)
return FALSE;
Index = PhFindItemList(Parent->Items, Item);
if (Index == -1)
return FALSE;
}
else
{
if (!Parent)
return FALSE;
if (!Parent->Items)
return FALSE;
}
Item = Parent->Items->Items[Index];
PhRemoveItemList(Parent->Items, Index);
Item->Parent = NULL;
return TRUE;
}
/**
* Removes all children from a menu item.
*
* \param Parent The parent menu item.
*/
VOID PhRemoveAllEMenuItems(
_Inout_ PPH_EMENU_ITEM Parent
)
{
ULONG i;
if (!Parent->Items)
return;
for (i = 0; i < Parent->Items->Count; i++)
{
PhpDestroyEMenuItem(Parent->Items->Items[i]);
}
PhClearList(Parent->Items);
}
/**
* Creates a root menu.
*/
PPH_EMENU PhCreateEMenu(
VOID
)
{
PPH_EMENU menu;
menu = PhAllocate(sizeof(PH_EMENU));
memset(menu, 0, sizeof(PH_EMENU));
menu->Items = PhCreateList(16);
return menu;
}
/**
* Frees resources used by a root menu and its children.
*
* \param Menu A root menu.
*/
VOID PhDestroyEMenu(
_In_ PPH_EMENU Menu
)
{
ULONG i;
for (i = 0; i < Menu->Items->Count; i++)
{
PhpDestroyEMenuItem(Menu->Items->Items[i]);
}
PhDereferenceObject(Menu->Items);
PhFree(Menu);
}
/**
* Initializes a data structure containing additional information resulting from a call to
* PhEMenuToHMenu().
*/
VOID PhInitializeEMenuData(
_Out_ PPH_EMENU_DATA Data
)
{
Data->IdToItem = PhCreateList(16);
}
/**
* Frees resources used by a data structure initialized by PhInitializeEMenuData().
*/
VOID PhDeleteEMenuData(
_Inout_ PPH_EMENU_DATA Data
)
{
PhDereferenceObject(Data->IdToItem);
}
/**
* Converts an EMENU to a Windows menu object.
*
* \param Menu The menu item to convert.
* \param Flags A combination of the following:
* \li \c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item.
* The resulting mappings are placed in \a Data.
* \param Data Additional data resulting from the conversion. The data structure must be initialized
* by PhInitializeEMenuData() prior to calling this function.
*
* \return A menu handle. The menu object must be destroyed using DestroyMenu() when it is no longer
* needed.
*/
HMENU PhEMenuToHMenu(
_In_ PPH_EMENU_ITEM Menu,
_In_ ULONG Flags,
_Inout_opt_ PPH_EMENU_DATA Data
)
{
HMENU menuHandle;
menuHandle = CreatePopupMenu();
if (!menuHandle)
return NULL;
PhEMenuToHMenu2(menuHandle, Menu, Flags, Data);
if (!(Menu->Flags & PH_EMENU_SEPARATECHECKSPACE))
{
MENUINFO menuInfo;
memset(&menuInfo, 0, sizeof(MENUINFO));
menuInfo.cbSize = sizeof(MENUINFO);
menuInfo.fMask = MIM_STYLE;
menuInfo.dwStyle = MNS_CHECKORBMP;
SetMenuInfo(menuHandle, &menuInfo);
}
return menuHandle;
}
/**
* Converts an EMENU to a Windows menu object.
*
* \param MenuHandle A handle to a Windows menu object.
* \param Menu The menu item to convert. The items are appended to \a MenuHandle.
* \param Flags A combination of the following:
* \li \c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item.
* The resulting mappings are placed in \a Data.
* \param Data Additional data resulting from the conversion. The data structure must be initialized
* by PhInitializeEMenuData() prior to calling this function.
*/
VOID PhEMenuToHMenu2(
_In_ HMENU MenuHandle,
_In_ PPH_EMENU_ITEM Menu,
_In_ ULONG Flags,
_Inout_opt_ PPH_EMENU_DATA Data
)
{
ULONG i;
PPH_EMENU_ITEM item;
MENUITEMINFO menuItemInfo;
for (i = 0; i < Menu->Items->Count; i++)
{
item = Menu->Items->Items[i];
memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));
menuItemInfo.cbSize = sizeof(MENUITEMINFO);
// Type
menuItemInfo.fMask = MIIM_FTYPE | MIIM_STATE;
if (item->Flags & PH_EMENU_SEPARATOR)
{
menuItemInfo.fType = MFT_SEPARATOR;
}
else
{
menuItemInfo.fType = MFT_STRING;
menuItemInfo.fMask |= MIIM_STRING;
menuItemInfo.dwTypeData = item->Text;
}
PhMapFlags1(
&menuItemInfo.fType,
item->Flags,
EMenuTypeMappings,
sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING)
);
// Bitmap
if (item->Bitmap)
{
menuItemInfo.fMask |= MIIM_BITMAP;
menuItemInfo.hbmpItem = item->Bitmap;
}
// Id
if (Flags & PH_EMENU_CONVERT_ID)
{
ULONG id;
if (Data)
{
PhAddItemList(Data->IdToItem, item);
id = Data->IdToItem->Count;
menuItemInfo.fMask |= MIIM_ID;
menuItemInfo.wID = id;
}
}
else
{
if (item->Id)
{
menuItemInfo.fMask |= MIIM_ID;
menuItemInfo.wID = item->Id;
}
}
// State
PhMapFlags1(
&menuItemInfo.fState,
item->Flags,
EMenuStateMappings,
sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING)
);
// Context
menuItemInfo.fMask |= MIIM_DATA;
menuItemInfo.dwItemData = (ULONG_PTR)item;
// Submenu
if (item->Items && item->Items->Count != 0)
{
menuItemInfo.fMask |= MIIM_SUBMENU;
menuItemInfo.hSubMenu = PhEMenuToHMenu(item, Flags, Data);
}
InsertMenuItem(MenuHandle, MAXINT, TRUE, &menuItemInfo);
}
}
/**
* Converts a Windows menu object to an EMENU.
*
* \param MenuItem The menu item in which the converted menu items will be placed.
* \param MenuHandle A menu handle.
*/
VOID PhHMenuToEMenuItem(
_Inout_ PPH_EMENU_ITEM MenuItem,
_In_ HMENU MenuHandle
)
{
ULONG i;
ULONG count;
count = GetMenuItemCount(MenuHandle);
if (count != -1)
{
for (i = 0; i < count; i++)
{
MENUITEMINFO menuItemInfo;
WCHAR buffer[256];
PPH_EMENU_ITEM menuItem;
menuItemInfo.cbSize = sizeof(menuItemInfo);
menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU;
menuItemInfo.cch = sizeof(buffer) / sizeof(WCHAR);
menuItemInfo.dwTypeData = buffer;
if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo))
continue;
menuItem = PhCreateEMenuItem(
PH_EMENU_TEXT_OWNED,
menuItemInfo.wID,
PhDuplicateStringZ(buffer),
NULL,
NULL
);
if (menuItemInfo.fType & MFT_SEPARATOR)
menuItem->Flags |= PH_EMENU_SEPARATOR;
PhMapFlags2(
&menuItem->Flags,
menuItemInfo.fType,
EMenuTypeMappings,
sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING)
);
PhMapFlags2(
&menuItem->Flags,
menuItemInfo.fState,
EMenuStateMappings,
sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING)
);
if (menuItemInfo.hSubMenu)
PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu);
PhInsertEMenuItem(MenuItem, menuItem, -1);
}
}
}
/**
* Loads a menu resource and converts it to an EMENU.
*
* \param MenuItem The menu item in which the converted menu items will be placed.
* \param InstanceHandle The module containing the menu resource.
* \param Resource The resource identifier.
* \param SubMenuIndex The index of the sub menu to use, or -1 to use the root menu.
*/
VOID PhLoadResourceEMenuItem(
_Inout_ PPH_EMENU_ITEM MenuItem,
_In_ HINSTANCE InstanceHandle,
_In_ PWSTR Resource,
_In_ ULONG SubMenuIndex
)
{
HMENU menu;
HMENU realMenu;
menu = LoadMenu(InstanceHandle, Resource);
if (SubMenuIndex != -1)
realMenu = GetSubMenu(menu, SubMenuIndex);
else
realMenu = menu;
PhHMenuToEMenuItem(MenuItem, realMenu);
DestroyMenu(menu);
}
/**
* Displays a menu.
*
* \param Menu A menu.
* \param WindowHandle The window that owns the popup menu.
* \param Flags A combination of the following:
* \li \c PH_EMENU_SHOW_SEND_COMMAND A WM_COMMAND message is sent to the window when the user clicks
* on a menu item.
* \li \c PH_EMENU_SHOW_LEFTRIGHT The user can select menu items with both the left and right mouse
* buttons.
* \param Align The alignment of the menu.
* \param X The horizontal location of the menu.
* \param Y The vertical location of the menu.
*
* \return The selected menu item, or NULL if the menu was cancelled.
*/
PPH_EMENU_ITEM PhShowEMenu(
_In_ PPH_EMENU Menu,
_In_ HWND WindowHandle,
_In_ ULONG Flags,
_In_ ULONG Align,
_In_ ULONG X,
_In_ ULONG Y
)
{
PPH_EMENU_ITEM selectedItem;
ULONG result;
ULONG flags;
PH_EMENU_DATA data;
HMENU popupMenu;
selectedItem = NULL;
flags = TPM_RETURNCMD | TPM_NONOTIFY;
// Flags
if (Flags & PH_EMENU_SHOW_LEFTRIGHT)
flags |= TPM_RIGHTBUTTON;
else
flags |= TPM_LEFTBUTTON;
// Align
if (Align & PH_ALIGN_LEFT)
flags |= TPM_LEFTALIGN;
else if (Align & PH_ALIGN_RIGHT)
flags |= TPM_RIGHTALIGN;
else
flags |= TPM_CENTERALIGN;
if (Align & PH_ALIGN_TOP)
flags |= TPM_TOPALIGN;
else if (Align & PH_ALIGN_BOTTOM)
flags |= TPM_BOTTOMALIGN;
else
flags |= TPM_VCENTERALIGN;
PhInitializeEMenuData(&data);
if (popupMenu = PhEMenuToHMenu(Menu, PH_EMENU_CONVERT_ID, &data))
{
result = TrackPopupMenu(
popupMenu,
flags,
X,
Y,
0,
WindowHandle,
NULL
);
if (result != 0)
{
selectedItem = data.IdToItem->Items[result - 1];
}
DestroyMenu(popupMenu);
}
PhDeleteEMenuData(&data);
if ((Flags & PH_EMENU_SHOW_SEND_COMMAND) && selectedItem && selectedItem->Id != 0)
SendMessage(WindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, 0), 0);
return selectedItem;
}
/**
* Sets the flags of a menu item.
*
* \param Item The parent menu item.
* \param Id The identifier of the child menu item.
* \param Mask The flags to modify.
* \param Value The new value of the flags.
*/
BOOLEAN PhSetFlagsEMenuItem(
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG Id,
_In_ ULONG Mask,
_In_ ULONG Value
)
{
PPH_EMENU_ITEM item;
item = PhFindEMenuItem(Item, PH_EMENU_FIND_DESCEND, NULL, Id);
if (item)
{
item->Flags &= ~Mask;
item->Flags |= Value;
return TRUE;
}
else
{
return FALSE;
}
}
/**
* Sets flags for all children of a menu item.
*
* \param Item The parent menu item.
* \param Mask The flags to modify.
* \param Value The new value of the flags.
*/
VOID PhSetFlagsAllEMenuItems(
_In_ PPH_EMENU_ITEM Item,
_In_ ULONG Mask,
_In_ ULONG Value
)
{
ULONG i;
for (i = 0; i < Item->Items->Count; i++)
{
PPH_EMENU_ITEM item = Item->Items->Items[i];
item->Flags &= ~Mask;
item->Flags |= Value;
}
}
VOID PhModifyEMenuItem(
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG ModifyFlags,
_In_ ULONG OwnedFlags,
_In_opt_ PWSTR Text,
_In_opt_ HBITMAP Bitmap
)
{
if (ModifyFlags & PH_EMENU_MODIFY_TEXT)
{
if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text)
PhFree(Item->Text);
Item->Text = Text;
Item->Flags &= ~PH_EMENU_TEXT_OWNED;
Item->Flags |= OwnedFlags & PH_EMENU_TEXT_OWNED;
}
if (ModifyFlags & PH_EMENU_MODIFY_BITMAP)
{
if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap)
DeleteObject(Item->Bitmap);
Item->Bitmap = Bitmap;
Item->Flags &= ~PH_EMENU_BITMAP_OWNED;
Item->Flags |= OwnedFlags & PH_EMENU_BITMAP_OWNED;
}
}

92
phlib/error.c Normal file
View File

@@ -0,0 +1,92 @@
/*
* Process Hacker -
* error codes
*
* Copyright (C) 2010-2011 wj32
*
* 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 <phbase.h>
/**
* Converts a NTSTATUS value to a Win32 error code.
*
* \remarks This function handles FACILITY_NTWIN32 status values properly, unlike
* RtlNtStatusToDosError.
*/
ULONG PhNtStatusToDosError(
_In_ NTSTATUS Status
)
{
if (NT_NTWIN32(Status)) // RtlNtStatusToDosError doesn't seem to handle these cases correctly
return WIN32_FROM_NTSTATUS(Status);
else
return RtlNtStatusToDosError(Status);
}
/**
* Converts a Win32 error code to a NTSTATUS value.
*
* \remarks Only a small number of cases are currently supported. Other status values are wrapped
* using FACILITY_NTWIN32.
*/
NTSTATUS PhDosErrorToNtStatus(
_In_ ULONG DosError
)
{
switch (DosError)
{
case ERROR_INVALID_FUNCTION: return STATUS_ILLEGAL_FUNCTION;
case ERROR_FILE_NOT_FOUND: return STATUS_NO_SUCH_FILE;
case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
case ERROR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE;
case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED;
case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
case ERROR_NOT_LOCKED: return STATUS_NOT_LOCKED;
case ERROR_MORE_DATA: return STATUS_MORE_ENTRIES;
case ERROR_NOACCESS: return STATUS_ACCESS_VIOLATION;
case ERROR_STACK_OVERFLOW: return STATUS_STACK_OVERFLOW;
case ERROR_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR;
default: return NTSTATUS_FROM_WIN32(DosError);
}
}
/**
* Determines whether a NTSTATUS value indicates that a file cannot be not found.
*/
BOOLEAN PhNtStatusFileNotFound(
_In_ NTSTATUS Status
)
{
switch (Status)
{
case STATUS_NO_SUCH_FILE:
return TRUE;
case STATUS_OBJECT_NAME_INVALID:
return TRUE;
case STATUS_OBJECT_NAME_NOT_FOUND:
return TRUE;
case STATUS_OBJECT_NO_LONGER_EXISTS:
return TRUE;
case STATUS_OBJECT_PATH_INVALID:
return TRUE;
case STATUS_OBJECT_PATH_NOT_FOUND:
return TRUE;
default: return FALSE;
}
}

748
phlib/extlv.c Normal file
View File

@@ -0,0 +1,748 @@
/*
* Process Hacker -
* extended list view
*
* Copyright (C) 2010-2012 wj32
*
* 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/>.
*/
/*
* The extended list view adds some functionality to the default list view control, such as sorting,
* item colors and fonts, better redraw disabling, and the ability to change the cursor. This is
* currently implemented by hooking the window procedure.
*/
#include <ph.h>
#include <guisup.h>
#include <windowsx.h>
#define PH_MAX_COMPARE_FUNCTIONS 16
typedef struct _PH_EXTLV_CONTEXT
{
HWND Handle;
WNDPROC OldWndProc;
PVOID Context;
// Sorting
BOOLEAN TriState;
ULONG SortColumn;
PH_SORT_ORDER SortOrder;
BOOLEAN SortFast;
PPH_COMPARE_FUNCTION TriStateCompareFunction;
PPH_COMPARE_FUNCTION CompareFunctions[PH_MAX_COMPARE_FUNCTIONS];
ULONG FallbackColumns[PH_MAX_COMPARE_FUNCTIONS];
ULONG NumberOfFallbackColumns;
// Color and Font
PPH_EXTLV_GET_ITEM_COLOR ItemColorFunction;
PPH_EXTLV_GET_ITEM_FONT ItemFontFunction;
// Misc.
LONG EnableRedraw;
HCURSOR Cursor;
} PH_EXTLV_CONTEXT, *PPH_EXTLV_CONTEXT;
LRESULT CALLBACK PhpExtendedListViewWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT PhpExtendedListViewCompareFunc(
_In_ LPARAM lParam1,
_In_ LPARAM lParam2,
_In_ LPARAM lParamSort
);
INT PhpExtendedListViewCompareFastFunc(
_In_ LPARAM lParam1,
_In_ LPARAM lParam2,
_In_ LPARAM lParamSort
);
INT PhpCompareListViewItems(
_In_ PPH_EXTLV_CONTEXT Context,
_In_ INT X,
_In_ INT Y,
_In_ PVOID XParam,
_In_ PVOID YParam,
_In_ ULONG Column,
_In_ BOOLEAN EnableDefault
);
INT PhpDefaultCompareListViewItems(
_In_ PPH_EXTLV_CONTEXT Context,
_In_ INT X,
_In_ INT Y,
_In_ ULONG Column
);
static PWSTR PhpMakeExtLvContextAtom(
VOID
)
{
PH_DEFINE_MAKE_ATOM(L"PhLib_ExtLvContext");
}
/**
* Enables extended list view support for a list view control.
*
* \param hWnd A handle to the list view control.
*/
VOID PhSetExtendedListView(
_In_ HWND hWnd
)
{
WNDPROC oldWndProc;
PPH_EXTLV_CONTEXT context;
oldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PhpExtendedListViewWndProc);
context = PhAllocate(sizeof(PH_EXTLV_CONTEXT));
context->Handle = hWnd;
context->OldWndProc = oldWndProc;
context->Context = NULL;
context->TriState = FALSE;
context->SortColumn = 0;
context->SortOrder = AscendingSortOrder;
context->SortFast = FALSE;
context->TriStateCompareFunction = NULL;
memset(context->CompareFunctions, 0, sizeof(context->CompareFunctions));
context->NumberOfFallbackColumns = 0;
context->ItemColorFunction = NULL;
context->ItemFontFunction = NULL;
context->EnableRedraw = 1;
context->Cursor = NULL;
SetProp(hWnd, PhpMakeExtLvContextAtom(), (HANDLE)context);
ExtendedListView_Init(hWnd);
}
LRESULT CALLBACK PhpExtendedListViewWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PPH_EXTLV_CONTEXT context;
WNDPROC oldWndProc;
context = (PPH_EXTLV_CONTEXT)GetProp(hwnd, PhpMakeExtLvContextAtom());
oldWndProc = context->OldWndProc;
switch (uMsg)
{
case WM_DESTROY:
{
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
PhFree(context);
RemoveProp(hwnd, PhpMakeExtLvContextAtom());
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case HDN_ITEMCLICK:
{
HWND headerHandle;
headerHandle = (HWND)CallWindowProc(context->OldWndProc, hwnd, LVM_GETHEADER, 0, 0);
if (header->hwndFrom == headerHandle)
{
LPNMHEADER header2 = (LPNMHEADER)header;
if (header2->iItem == context->SortColumn)
{
if (context->TriState)
{
if (context->SortOrder == AscendingSortOrder)
context->SortOrder = DescendingSortOrder;
else if (context->SortOrder == DescendingSortOrder)
context->SortOrder = NoSortOrder;
else
context->SortOrder = AscendingSortOrder;
}
else
{
if (context->SortOrder == AscendingSortOrder)
context->SortOrder = DescendingSortOrder;
else
context->SortOrder = AscendingSortOrder;
}
}
else
{
context->SortColumn = header2->iItem;
context->SortOrder = AscendingSortOrder;
}
PhSetHeaderSortIcon(headerHandle, context->SortColumn, context->SortOrder);
ExtendedListView_SortItems(hwnd);
}
}
break;
}
}
break;
case WM_REFLECT + WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case NM_CUSTOMDRAW:
{
if (header->hwndFrom == hwnd)
{
LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW)header;
switch (customDraw->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT:
{
BOOLEAN colorChanged = FALSE;
HFONT newFont = NULL;
if (context->ItemColorFunction)
{
customDraw->clrTextBk = context->ItemColorFunction(
(INT)customDraw->nmcd.dwItemSpec,
(PVOID)customDraw->nmcd.lItemlParam,
context->Context
);
colorChanged = TRUE;
}
if (context->ItemFontFunction)
{
newFont = context->ItemFontFunction(
(INT)customDraw->nmcd.dwItemSpec,
(PVOID)customDraw->nmcd.lItemlParam,
context->Context
);
}
if (newFont)
SelectObject(customDraw->nmcd.hdc, newFont);
if (colorChanged)
{
if (PhGetColorBrightness(customDraw->clrTextBk) > 100) // slightly less than half
customDraw->clrText = RGB(0x00, 0x00, 0x00);
else
customDraw->clrText = RGB(0xff, 0xff, 0xff);
}
if (!newFont)
return CDRF_DODEFAULT;
else
return CDRF_NEWFONT;
}
break;
}
}
}
break;
}
}
break;
case WM_SETCURSOR:
{
if (context->Cursor)
{
SetCursor(context->Cursor);
return TRUE;
}
}
break;
case WM_UPDATEUISTATE:
{
// Disable focus rectangles by setting or masking out the flag where appropriate.
switch (LOWORD(wParam))
{
case UIS_SET:
wParam |= UISF_HIDEFOCUS << 16;
break;
case UIS_CLEAR:
case UIS_INITIALIZE:
wParam &= ~(UISF_HIDEFOCUS << 16);
break;
}
}
break;
case ELVM_ADDFALLBACKCOLUMN:
{
if (context->NumberOfFallbackColumns < PH_MAX_COMPARE_FUNCTIONS)
context->FallbackColumns[context->NumberOfFallbackColumns++] = (ULONG)wParam;
else
return FALSE;
}
return TRUE;
case ELVM_ADDFALLBACKCOLUMNS:
{
ULONG numberOfColumns = (ULONG)wParam;
PULONG columns = (PULONG)lParam;
if (context->NumberOfFallbackColumns + numberOfColumns <= PH_MAX_COMPARE_FUNCTIONS)
{
memcpy(
&context->FallbackColumns[context->NumberOfFallbackColumns],
columns,
numberOfColumns * sizeof(ULONG)
);
context->NumberOfFallbackColumns += numberOfColumns;
}
else
{
return FALSE;
}
}
return TRUE;
case ELVM_INIT:
{
PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder);
// HACK to fix tooltips showing behind Always On Top windows.
SetWindowPos(ListView_GetToolTips(hwnd), HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
// Make sure focus rectangles are disabled.
SendMessage(hwnd, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);
}
return TRUE;
case ELVM_SETCOLUMNWIDTH:
{
ULONG column = (ULONG)wParam;
LONG width = (LONG)lParam;
if (width == ELVSCW_AUTOSIZE_REMAININGSPACE)
{
RECT clientRect;
LONG availableWidth;
ULONG i;
LVCOLUMN lvColumn;
GetClientRect(hwnd, &clientRect);
availableWidth = clientRect.right;
i = 0;
lvColumn.mask = LVCF_WIDTH;
while (TRUE)
{
if (i != column)
{
if (CallWindowProc(oldWndProc, hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn))
{
availableWidth -= lvColumn.cx;
}
else
{
break;
}
}
i++;
}
if (availableWidth >= 40)
return CallWindowProc(oldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth);
}
return CallWindowProc(oldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, width);
}
break;
case ELVM_SETCOMPAREFUNCTION:
{
ULONG column = (ULONG)wParam;
PPH_COMPARE_FUNCTION compareFunction = (PPH_COMPARE_FUNCTION)lParam;
if (column >= PH_MAX_COMPARE_FUNCTIONS)
return FALSE;
context->CompareFunctions[column] = compareFunction;
}
return TRUE;
case ELVM_SETCONTEXT:
{
context->Context = (PVOID)lParam;
}
return TRUE;
case ELVM_SETCURSOR:
{
context->Cursor = (HCURSOR)lParam;
}
return TRUE;
case ELVM_SETITEMCOLORFUNCTION:
{
context->ItemColorFunction = (PPH_EXTLV_GET_ITEM_COLOR)lParam;
}
return TRUE;
case ELVM_SETITEMFONTFUNCTION:
{
context->ItemFontFunction = (PPH_EXTLV_GET_ITEM_FONT)lParam;
}
return TRUE;
case ELVM_SETREDRAW:
{
if (wParam)
context->EnableRedraw++;
else
context->EnableRedraw--;
if (context->EnableRedraw == 1)
{
SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
InvalidateRect(hwnd, NULL, FALSE);
}
else if (context->EnableRedraw == 0)
{
SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
}
}
return TRUE;
case ELVM_SETSORT:
{
context->SortColumn = (ULONG)wParam;
context->SortOrder = (PH_SORT_ORDER)lParam;
PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder);
}
return TRUE;
case ELVM_SETSORTFAST:
{
context->SortFast = !!wParam;
}
return TRUE;
case ELVM_SETTRISTATE:
{
context->TriState = !!wParam;
}
return TRUE;
case ELVM_SETTRISTATECOMPAREFUNCTION:
{
context->TriStateCompareFunction = (PPH_COMPARE_FUNCTION)lParam;
}
return TRUE;
case ELVM_SORTITEMS:
{
if (context->SortFast)
{
// This sort method is faster than the normal sort because our comparison function
// doesn't have to call the list view window procedure to get the item lParam
// values. The disadvantage of this method is that default sorting is not available
// - if a column doesn't have a comparison function, it doesn't get sorted at all.
ListView_SortItems(
hwnd,
PhpExtendedListViewCompareFastFunc,
(LPARAM)context
);
}
else
{
ListView_SortItemsEx(
hwnd,
PhpExtendedListViewCompareFunc,
(LPARAM)context
);
}
}
return TRUE;
}
return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
}
/**
* Visually indicates the sort order of a header control item.
*
* \param hwnd A handle to the header control.
* \param Index The index of the item.
* \param Order The sort order of the item.
*/
VOID PhSetHeaderSortIcon(
_In_ HWND hwnd,
_In_ INT Index,
_In_ PH_SORT_ORDER Order
)
{
ULONG count;
ULONG i;
count = Header_GetItemCount(hwnd);
if (count == -1)
return;
for (i = 0; i < count; i++)
{
HDITEM item;
item.mask = HDI_FORMAT;
Header_GetItem(hwnd, i, &item);
if (Order != NoSortOrder && i == Index)
{
if (Order == AscendingSortOrder)
{
item.fmt &= ~HDF_SORTDOWN;
item.fmt |= HDF_SORTUP;
}
else if (Order == DescendingSortOrder)
{
item.fmt &= ~HDF_SORTUP;
item.fmt |= HDF_SORTDOWN;
}
}
else
{
item.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
}
Header_SetItem(hwnd, i, &item);
}
}
static INT PhpExtendedListViewCompareFunc(
_In_ LPARAM lParam1,
_In_ LPARAM lParam2,
_In_ LPARAM lParamSort
)
{
PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort;
INT result;
INT x = (INT)lParam1;
INT y = (INT)lParam2;
ULONG i;
PULONG fallbackColumns;
LVITEM xItem;
LVITEM yItem;
// Get the param values.
xItem.mask = LVIF_PARAM | LVIF_STATE;
xItem.iItem = x;
xItem.iSubItem = 0;
yItem.mask = LVIF_PARAM | LVIF_STATE;
yItem.iItem = y;
yItem.iSubItem = 0;
// Don't use SendMessage/ListView_* because it will call our new window procedure, which will
// use GetProp. This calls NtUserGetProp, and obviously having a system call in a comparison
// function is very, very bad for performance.
if (!CallWindowProc(context->OldWndProc, context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem))
return 0;
if (!CallWindowProc(context->OldWndProc, context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem))
return 0;
// First, do tri-state sorting.
if (
context->TriState &&
context->SortOrder == NoSortOrder &&
context->TriStateCompareFunction
)
{
result = context->TriStateCompareFunction(
(PVOID)xItem.lParam,
(PVOID)yItem.lParam,
context->Context
);
if (result != 0)
return result;
}
// Compare using the user-selected column and move on to the fallback columns if necessary.
result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, context->SortColumn, TRUE);
if (result != 0)
return result;
fallbackColumns = context->FallbackColumns;
for (i = context->NumberOfFallbackColumns; i != 0; i--)
{
ULONG fallbackColumn = *fallbackColumns++;
if (fallbackColumn == context->SortColumn)
continue;
result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, fallbackColumn, TRUE);
if (result != 0)
return result;
}
return 0;
}
static INT PhpExtendedListViewCompareFastFunc(
_In_ LPARAM lParam1,
_In_ LPARAM lParam2,
_In_ LPARAM lParamSort
)
{
PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort;
INT result;
ULONG i;
PULONG fallbackColumns;
if (!lParam1 || !lParam2)
return 0;
// First, do tri-state sorting.
if (
context->TriState &&
context->SortOrder == NoSortOrder &&
context->TriStateCompareFunction
)
{
result = context->TriStateCompareFunction(
(PVOID)lParam1,
(PVOID)lParam2,
context->Context
);
if (result != 0)
return result;
}
// Compare using the user-selected column and move on to the fallback columns if necessary.
result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, context->SortColumn, FALSE);
if (result != 0)
return result;
fallbackColumns = context->FallbackColumns;
for (i = context->NumberOfFallbackColumns; i != 0; i--)
{
ULONG fallbackColumn = *fallbackColumns++;
if (fallbackColumn == context->SortColumn)
continue;
result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, fallbackColumn, FALSE);
if (result != 0)
return result;
}
return 0;
}
static FORCEINLINE INT PhpCompareListViewItems(
_In_ PPH_EXTLV_CONTEXT Context,
_In_ INT X,
_In_ INT Y,
_In_ PVOID XParam,
_In_ PVOID YParam,
_In_ ULONG Column,
_In_ BOOLEAN EnableDefault
)
{
INT result = 0;
if (
Column < PH_MAX_COMPARE_FUNCTIONS &&
Context->CompareFunctions[Column]
)
{
result = PhModifySort(
Context->CompareFunctions[Column](XParam, YParam, Context->Context),
Context->SortOrder
);
if (result != 0)
return result;
}
if (EnableDefault)
{
return PhModifySort(
PhpDefaultCompareListViewItems(Context, X, Y, Column),
Context->SortOrder
);
}
else
{
return 0;
}
}
static INT PhpDefaultCompareListViewItems(
_In_ PPH_EXTLV_CONTEXT Context,
_In_ INT X,
_In_ INT Y,
_In_ ULONG Column
)
{
WCHAR xText[261];
WCHAR yText[261];
LVITEM item;
// Get the X item text.
item.mask = LVIF_TEXT;
item.iItem = X;
item.iSubItem = Column;
item.pszText = xText;
item.cchTextMax = 260;
xText[0] = 0;
CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item);
// Get the Y item text.
item.iItem = Y;
item.pszText = yText;
item.cchTextMax = 260;
yText[0] = 0;
CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item);
// Compare them.
#if 1
return PhCompareStringZNatural(xText, yText, TRUE);
#else
return _wcsicmp(xText, yText);
#endif
}

384
phlib/fastlock.c Normal file
View File

@@ -0,0 +1,384 @@
/*
* Process Hacker -
* fast resource lock
*
* Copyright (C) 2009-2010 wj32
*
* 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 <phbase.h>
#include <fastlock.h>
// FastLock is a port of FastResourceLock from PH 1.x.
//
// The code contains no comments because it is a direct port. Please see FastResourceLock.cs in PH
// 1.x for details.
// The fast lock is around 7% faster than the critical section when there is no contention, when
// used solely for mutual exclusion. It is also much smaller than the critical section.
#define PH_LOCK_OWNED 0x1
#define PH_LOCK_EXCLUSIVE_WAKING 0x2
#define PH_LOCK_SHARED_OWNERS_SHIFT 2
#define PH_LOCK_SHARED_OWNERS_MASK 0x3ff
#define PH_LOCK_SHARED_OWNERS_INC 0x4
#define PH_LOCK_SHARED_WAITERS_SHIFT 12
#define PH_LOCK_SHARED_WAITERS_MASK 0x3ff
#define PH_LOCK_SHARED_WAITERS_INC 0x1000
#define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22
#define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3ff
#define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000
#define PH_LOCK_EXCLUSIVE_MASK \
(PH_LOCK_EXCLUSIVE_WAKING | \
(PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT))
VOID PhInitializeFastLock(
_Out_ PPH_FAST_LOCK FastLock
)
{
FastLock->Value = 0;
FastLock->ExclusiveWakeEvent = NULL;
FastLock->SharedWakeEvent = NULL;
}
VOID PhDeleteFastLock(
_Inout_ PPH_FAST_LOCK FastLock
)
{
if (FastLock->ExclusiveWakeEvent)
{
NtClose(FastLock->ExclusiveWakeEvent);
FastLock->ExclusiveWakeEvent = NULL;
}
if (FastLock->SharedWakeEvent)
{
NtClose(FastLock->SharedWakeEvent);
FastLock->SharedWakeEvent = NULL;
}
}
FORCEINLINE VOID PhpEnsureEventCreated(
_Inout_ PHANDLE Handle
)
{
HANDLE handle;
if (*Handle != NULL)
return;
NtCreateSemaphore(&handle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG);
if (_InterlockedCompareExchangePointer(
Handle,
handle,
NULL
) != NULL)
{
NtClose(handle);
}
}
FORCEINLINE ULONG PhpGetSpinCount(
VOID
)
{
if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1)
return 4000;
else
return 0;
}
_May_raise_
_Acquires_exclusive_lock_(*FastLock)
VOID FASTCALL PhfAcquireFastLockExclusive(
_Inout_ PPH_FAST_LOCK FastLock
)
{
ULONG value;
ULONG i = 0;
ULONG spinCount;
spinCount = PhpGetSpinCount();
while (TRUE)
{
value = FastLock->Value;
if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)))
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_OWNED,
value
) == value)
break;
}
else if (i >= spinCount)
{
PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent);
if (_InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_EXCLUSIVE_WAITERS_INC,
value
) == value)
{
if (NtWaitForSingleObject(
FastLock->ExclusiveWakeEvent,
FALSE,
NULL
) != STATUS_WAIT_0)
PhRaiseStatus(STATUS_UNSUCCESSFUL);
do
{
value = FastLock->Value;
} while (_InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_OWNED - PH_LOCK_EXCLUSIVE_WAKING,
value
) != value);
break;
}
}
i++;
YieldProcessor();
}
}
_May_raise_
_Acquires_shared_lock_(*FastLock)
VOID FASTCALL PhfAcquireFastLockShared(
_Inout_ PPH_FAST_LOCK FastLock
)
{
ULONG value;
ULONG i = 0;
ULONG spinCount;
spinCount = PhpGetSpinCount();
while (TRUE)
{
value = FastLock->Value;
if (!(value & (
PH_LOCK_OWNED |
(PH_LOCK_SHARED_OWNERS_MASK << PH_LOCK_SHARED_OWNERS_SHIFT) |
PH_LOCK_EXCLUSIVE_MASK
)))
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,
value
) == value)
break;
}
else if (
(value & PH_LOCK_OWNED) &&
((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 0 &&
!(value & PH_LOCK_EXCLUSIVE_MASK)
)
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_SHARED_OWNERS_INC,
value
) == value)
break;
}
else if (i >= spinCount)
{
PhpEnsureEventCreated(&FastLock->SharedWakeEvent);
if (_InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_SHARED_WAITERS_INC,
value
) == value)
{
if (NtWaitForSingleObject(
FastLock->SharedWakeEvent,
FALSE,
NULL
) != STATUS_WAIT_0)
PhRaiseStatus(STATUS_UNSUCCESSFUL);
continue;
}
}
i++;
YieldProcessor();
}
}
_Releases_exclusive_lock_(*FastLock)
VOID FASTCALL PhfReleaseFastLockExclusive(
_Inout_ PPH_FAST_LOCK FastLock
)
{
ULONG value;
while (TRUE)
{
value = FastLock->Value;
if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK)
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_EXCLUSIVE_WAITERS_INC,
value
) == value)
{
NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);
break;
}
}
else
{
ULONG sharedWaiters;
sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK;
if (_InterlockedCompareExchange(
&FastLock->Value,
value & ~(PH_LOCK_OWNED | (PH_LOCK_SHARED_WAITERS_MASK << PH_LOCK_SHARED_WAITERS_SHIFT)),
value
) == value)
{
if (sharedWaiters)
NtReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0);
break;
}
}
YieldProcessor();
}
}
_Releases_shared_lock_(*FastLock)
VOID FASTCALL PhfReleaseFastLockShared(
_Inout_ PPH_FAST_LOCK FastLock
)
{
ULONG value;
while (TRUE)
{
value = FastLock->Value;
if (((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 1)
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value - PH_LOCK_SHARED_OWNERS_INC,
value
) == value)
break;
}
else if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK)
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING -
PH_LOCK_SHARED_OWNERS_INC - PH_LOCK_EXCLUSIVE_WAITERS_INC,
value
) == value)
{
NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);
break;
}
}
else
{
if (_InterlockedCompareExchange(
&FastLock->Value,
value - PH_LOCK_OWNED - PH_LOCK_SHARED_OWNERS_INC,
value
) == value)
break;
}
YieldProcessor();
}
}
_When_(return != 0, _Acquires_exclusive_lock_(*FastLock))
BOOLEAN FASTCALL PhfTryAcquireFastLockExclusive(
_Inout_ PPH_FAST_LOCK FastLock
)
{
ULONG value;
value = FastLock->Value;
if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))
return FALSE;
return _InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_OWNED,
value
) == value;
}
_When_(return != 0, _Acquires_shared_lock_(*FastLock))
BOOLEAN FASTCALL PhfTryAcquireFastLockShared(
_Inout_ PPH_FAST_LOCK FastLock
)
{
ULONG value;
value = FastLock->Value;
if (value & PH_LOCK_EXCLUSIVE_MASK)
return FALSE;
if (!(value & PH_LOCK_OWNED))
{
return _InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,
value
) == value;
}
else if ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK)
{
return _InterlockedCompareExchange(
&FastLock->Value,
value + PH_LOCK_SHARED_OWNERS_INC,
value
) == value;
}
else
{
return FALSE;
}
}

1510
phlib/filepool.c Normal file

File diff suppressed because it is too large Load Diff

876
phlib/filestream.c Normal file
View File

@@ -0,0 +1,876 @@
/*
* Process Hacker -
* file stream object
*
* Copyright (C) 2010-2011 wj32
*
* 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 <ph.h>
#include <filestream.h>
#include <filestreamp.h>
PPH_OBJECT_TYPE PhFileStreamType;
BOOLEAN PhFileStreamInitialization(
VOID
)
{
PH_OBJECT_TYPE_PARAMETERS parameters;
parameters.FreeListSize = sizeof(PH_FILE_STREAM);
parameters.FreeListCount = 16;
PhFileStreamType = PhCreateObjectTypeEx(L"FileStream", PH_OBJECT_TYPE_USE_FREE_LIST, PhpFileStreamDeleteProcedure, &parameters);
return TRUE;
}
NTSTATUS PhCreateFileStream(
_Out_ PPH_FILE_STREAM *FileStream,
_In_ PWSTR FileName,
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG Flags
)
{
NTSTATUS status;
PPH_FILE_STREAM fileStream;
HANDLE fileHandle;
ULONG createOptions;
if (Flags & PH_FILE_STREAM_ASYNCHRONOUS)
createOptions = FILE_NON_DIRECTORY_FILE;
else
createOptions = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT;
if (!NT_SUCCESS(status = PhCreateFileWin32(
&fileHandle,
FileName,
DesiredAccess,
0,
ShareAccess,
CreateDisposition,
createOptions
)))
return status;
if (!NT_SUCCESS(status = PhCreateFileStream2(
&fileStream,
fileHandle,
Flags,
PAGE_SIZE
)))
{
NtClose(fileHandle);
return status;
}
if (Flags & PH_FILE_STREAM_APPEND)
{
LARGE_INTEGER zero;
zero.QuadPart = 0;
if (!NT_SUCCESS(PhSeekFileStream(
fileStream,
&zero,
SeekEnd
)))
{
PhDereferenceObject(fileStream);
return status;
}
}
*FileStream = fileStream;
return status;
}
NTSTATUS PhCreateFileStream2(
_Out_ PPH_FILE_STREAM *FileStream,
_In_ HANDLE FileHandle,
_In_ ULONG Flags,
_In_ ULONG BufferLength
)
{
PPH_FILE_STREAM fileStream;
fileStream = PhCreateObject(sizeof(PH_FILE_STREAM), PhFileStreamType);
fileStream->FileHandle = FileHandle;
fileStream->Flags = Flags;
fileStream->Position.QuadPart = 0;
if (!(Flags & PH_FILE_STREAM_UNBUFFERED))
{
fileStream->Buffer = NULL;
fileStream->BufferLength = BufferLength;
}
else
{
fileStream->Buffer = NULL;
fileStream->BufferLength = 0;
}
fileStream->ReadPosition = 0;
fileStream->ReadLength = 0;
fileStream->WritePosition = 0;
*FileStream = fileStream;
return STATUS_SUCCESS;
}
VOID NTAPI PhpFileStreamDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
)
{
PPH_FILE_STREAM fileStream = (PPH_FILE_STREAM)Object;
PhFlushFileStream(fileStream, FALSE);
if (!(fileStream->Flags & PH_FILE_STREAM_HANDLE_UNOWNED))
NtClose(fileStream->FileHandle);
if (fileStream->Buffer)
PhFreePage(fileStream->Buffer);
}
/**
* Verifies that a file stream's position matches the position held by the file object.
*/
VOID PhVerifyFileStream(
_In_ PPH_FILE_STREAM FileStream
)
{
NTSTATUS status;
// If the file object is asynchronous, the file object doesn't maintain its position.
if (!(FileStream->Flags & (
PH_FILE_STREAM_OWN_POSITION |
PH_FILE_STREAM_ASYNCHRONOUS
)))
{
FILE_POSITION_INFORMATION positionInfo;
IO_STATUS_BLOCK isb;
if (!NT_SUCCESS(status = NtQueryInformationFile(
FileStream->FileHandle,
&isb,
&positionInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
)))
PhRaiseStatus(status);
if (FileStream->Position.QuadPart != positionInfo.CurrentByteOffset.QuadPart)
PhRaiseStatus(STATUS_INTERNAL_ERROR);
}
}
NTSTATUS PhpAllocateBufferFileStream(
_Inout_ PPH_FILE_STREAM FileStream
)
{
FileStream->Buffer = PhAllocatePage(FileStream->BufferLength, NULL);
if (FileStream->Buffer)
return STATUS_SUCCESS;
else
return STATUS_NO_MEMORY;
}
NTSTATUS PhpReadFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG ReadLength
)
{
NTSTATUS status;
IO_STATUS_BLOCK isb;
PLARGE_INTEGER position;
position = NULL;
if (FileStream->Flags & PH_FILE_STREAM_OWN_POSITION)
position = &FileStream->Position;
status = NtReadFile(
FileStream->FileHandle,
NULL,
NULL,
NULL,
&isb,
Buffer,
Length,
position,
NULL
);
if (status == STATUS_PENDING)
{
// Wait for the operation to finish. This probably means we got called on an asynchronous
// file object.
status = NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);
if (NT_SUCCESS(status))
status = isb.Status;
}
if (NT_SUCCESS(status))
{
FileStream->Position.QuadPart += isb.Information;
if (ReadLength)
*ReadLength = (ULONG)isb.Information;
}
return status;
}
NTSTATUS PhReadFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG ReadLength
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG availableLength;
ULONG readLength;
if (FileStream->Flags & PH_FILE_STREAM_UNBUFFERED)
{
return PhpReadFileStream(
FileStream,
Buffer,
Length,
ReadLength
);
}
// How much do we have available to copy out of the buffer?
availableLength = FileStream->ReadLength - FileStream->ReadPosition;
if (availableLength == 0)
{
// Make sure buffered writes are flushed.
if (FileStream->WritePosition != 0)
{
if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))
return status;
}
// If this read is too big, pass it through.
if (Length >= FileStream->BufferLength)
{
// These are now invalid.
FileStream->ReadPosition = 0;
FileStream->ReadLength = 0;
return PhpReadFileStream(
FileStream,
Buffer,
Length,
ReadLength
);
}
if (!FileStream->Buffer)
{
if (!NT_SUCCESS(status = PhpAllocateBufferFileStream(FileStream)))
return status;
}
// Read as much as we can into our buffer.
if (!NT_SUCCESS(status = PhpReadFileStream(
FileStream,
FileStream->Buffer,
FileStream->BufferLength,
&readLength
)))
return status;
if (readLength == 0)
{
// No data read.
if (ReadLength)
*ReadLength = readLength;
return status;
}
FileStream->ReadPosition = 0;
FileStream->ReadLength = readLength;
}
else
{
readLength = availableLength;
}
if (readLength > Length)
readLength = Length;
// Try to satisfy the request from the buffer.
memcpy(
Buffer,
(PCHAR)FileStream->Buffer + FileStream->ReadPosition,
readLength
);
FileStream->ReadPosition += readLength;
// If we didn't completely satisfy the request, read some more.
if (
readLength < Length &&
// Don't try to read more if the buffer wasn't even filled up last time. (No more to read.)
FileStream->ReadLength == FileStream->BufferLength
)
{
ULONG readLength2;
if (NT_SUCCESS(status = PhpReadFileStream(
FileStream,
(PCHAR)Buffer + readLength,
Length - readLength,
&readLength2
)))
{
readLength += readLength2;
// These are now invalid.
FileStream->ReadPosition = 0;
FileStream->ReadLength = 0;
}
}
if (NT_SUCCESS(status))
{
if (ReadLength)
*ReadLength = readLength;
}
return status;
}
NTSTATUS PhpWriteFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length
)
{
NTSTATUS status;
IO_STATUS_BLOCK isb;
PLARGE_INTEGER position;
position = NULL;
if (FileStream->Flags & PH_FILE_STREAM_OWN_POSITION)
position = &FileStream->Position;
status = NtWriteFile(
FileStream->FileHandle,
NULL,
NULL,
NULL,
&isb,
Buffer,
Length,
position,
NULL
);
if (status == STATUS_PENDING)
{
// Wait for the operation to finish. This probably means we got called on an asynchronous
// file object.
status = NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);
if (NT_SUCCESS(status))
status = isb.Status;
}
if (NT_SUCCESS(status))
{
FileStream->Position.QuadPart += isb.Information;
FileStream->Flags |= PH_FILE_STREAM_WRITTEN;
}
return status;
}
NTSTATUS PhWriteFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG availableLength;
ULONG writtenLength;
if (FileStream->Flags & PH_FILE_STREAM_UNBUFFERED)
{
return PhpWriteFileStream(
FileStream,
Buffer,
Length
);
}
if (FileStream->WritePosition == 0)
{
// Make sure buffered reads are flushed.
if (!NT_SUCCESS(status = PhpFlushReadFileStream(FileStream)))
return status;
}
if (FileStream->WritePosition != 0)
{
availableLength = FileStream->BufferLength - FileStream->WritePosition;
// Try to satisfy the request by copying the data to the buffer.
if (availableLength != 0)
{
writtenLength = availableLength;
if (writtenLength > Length)
writtenLength = Length;
memcpy(
(PCHAR)FileStream->Buffer + FileStream->WritePosition,
Buffer,
writtenLength
);
FileStream->WritePosition += writtenLength;
if (writtenLength == Length)
{
// The request has been completely satisfied.
return status;
}
Buffer = (PCHAR)Buffer + writtenLength;
Length -= writtenLength;
}
// If we didn't completely satisfy the request, it's because the buffer is full. Flush it.
if (!NT_SUCCESS(status = PhpWriteFileStream(
FileStream,
FileStream->Buffer,
FileStream->WritePosition
)))
return status;
FileStream->WritePosition = 0;
}
// If the write is too big, pass it through.
if (Length >= FileStream->BufferLength)
{
if (!NT_SUCCESS(status = PhpWriteFileStream(
FileStream,
Buffer,
Length
)))
return status;
}
else if (Length != 0)
{
if (!FileStream->Buffer)
{
if (!NT_SUCCESS(status = PhpAllocateBufferFileStream(FileStream)))
return status;
}
// Completely satisfy the request by copying the data to the buffer.
memcpy(
FileStream->Buffer,
Buffer,
Length
);
FileStream->WritePosition = Length;
}
return status;
}
NTSTATUS PhpFlushReadFileStream(
_Inout_ PPH_FILE_STREAM FileStream
)
{
NTSTATUS status = STATUS_SUCCESS;
if (FileStream->ReadLength - FileStream->ReadPosition != 0)
{
LARGE_INTEGER offset;
// We have some buffered read data, so our position is too far ahead. We need to move it
// back to the first unused byte.
offset.QuadPart = -(LONG)(FileStream->ReadLength - FileStream->ReadPosition);
if (!NT_SUCCESS(status = PhpSeekFileStream(
FileStream,
&offset,
SeekCurrent
)))
return status;
}
FileStream->ReadPosition = 0;
FileStream->ReadLength = 0;
return status;
}
NTSTATUS PhpFlushWriteFileStream(
_Inout_ PPH_FILE_STREAM FileStream
)
{
NTSTATUS status = STATUS_SUCCESS;
if (!NT_SUCCESS(status = PhpWriteFileStream(
FileStream,
FileStream->Buffer,
FileStream->WritePosition
)))
return status;
FileStream->WritePosition = 0;
return status;
}
/**
* Flushes the file stream.
*
* \param FileStream A file stream object.
* \param Full TRUE to flush the file object through the operating system, otherwise FALSE to only
* ensure the buffer is flushed to the operating system.
*/
NTSTATUS PhFlushFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ BOOLEAN Full
)
{
NTSTATUS status = STATUS_SUCCESS;
if (FileStream->WritePosition != 0)
{
if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))
return status;
}
if (FileStream->ReadPosition != 0)
{
if (!NT_SUCCESS(status = PhpFlushReadFileStream(FileStream)))
return status;
}
if (Full && (FileStream->Flags & PH_FILE_STREAM_WRITTEN))
{
IO_STATUS_BLOCK isb;
if (!NT_SUCCESS(status = NtFlushBuffersFile(
FileStream->FileHandle,
&isb
)))
return status;
}
return status;
}
VOID PhGetPositionFileStream(
_In_ PPH_FILE_STREAM FileStream,
_Out_ PLARGE_INTEGER Position
)
{
Position->QuadPart =
FileStream->Position.QuadPart +
(FileStream->ReadPosition - FileStream->ReadLength) +
FileStream->WritePosition;
}
NTSTATUS PhpSeekFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Offset,
_In_ PH_SEEK_ORIGIN Origin
)
{
NTSTATUS status = STATUS_SUCCESS;
switch (Origin)
{
case SeekStart:
{
FileStream->Position = *Offset;
}
break;
case SeekCurrent:
{
FileStream->Position.QuadPart += Offset->QuadPart;
}
break;
case SeekEnd:
{
if (!NT_SUCCESS(status = PhGetFileSize(
FileStream->FileHandle,
&FileStream->Position
)))
return status;
FileStream->Position.QuadPart += Offset->QuadPart;
}
break;
}
if (!(FileStream->Flags & PH_FILE_STREAM_OWN_POSITION))
{
FILE_POSITION_INFORMATION positionInfo;
IO_STATUS_BLOCK isb;
positionInfo.CurrentByteOffset = FileStream->Position;
if (!NT_SUCCESS(status = NtSetInformationFile(
FileStream->FileHandle,
&isb,
&positionInfo,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation
)))
return status;
}
return status;
}
NTSTATUS PhSeekFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Offset,
_In_ PH_SEEK_ORIGIN Origin
)
{
NTSTATUS status = STATUS_SUCCESS;
LARGE_INTEGER offset;
offset = *Offset;
if (FileStream->WritePosition != 0)
{
if (!NT_SUCCESS(status = PhpFlushWriteFileStream(FileStream)))
return status;
}
else if (FileStream->ReadPosition != 0)
{
if (Origin == SeekCurrent)
{
// We have buffered read data, which means our position is too far ahead. Subtract this
// difference from the offset (which will affect the position accordingly).
offset.QuadPart -= FileStream->ReadLength - FileStream->ReadPosition;
}
// TODO: Try to keep some of the read buffer.
FileStream->ReadPosition = 0;
FileStream->ReadLength = 0;
}
if (!NT_SUCCESS(status = PhpSeekFileStream(
FileStream,
&offset,
Origin
)))
return status;
return status;
}
NTSTATUS PhLockFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Position,
_In_ PLARGE_INTEGER Length,
_In_ BOOLEAN Wait,
_In_ BOOLEAN Shared
)
{
NTSTATUS status;
IO_STATUS_BLOCK isb;
status = NtLockFile(
FileStream->FileHandle,
NULL,
NULL,
NULL,
&isb,
Position,
Length,
0,
!Wait,
!Shared
);
if (status == STATUS_PENDING)
{
// Wait for the operation to finish. This probably means we got called on an asynchronous
// file object.
NtWaitForSingleObject(FileStream->FileHandle, FALSE, NULL);
status = isb.Status;
}
return status;
}
NTSTATUS PhUnlockFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Position,
_In_ PLARGE_INTEGER Length
)
{
IO_STATUS_BLOCK isb;
return NtUnlockFile(
FileStream->FileHandle,
&isb,
Position,
Length,
0
);
}
NTSTATUS PhWriteStringAsUtf8FileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PPH_STRINGREF String
)
{
return PhWriteStringAsUtf8FileStreamEx(FileStream, String->Buffer, String->Length);
}
NTSTATUS PhWriteStringAsUtf8FileStream2(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PWSTR String
)
{
PH_STRINGREF string;
PhInitializeStringRef(&string, String);
return PhWriteStringAsUtf8FileStream(FileStream, &string);
}
NTSTATUS PhWriteStringAsUtf8FileStreamEx(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PWSTR Buffer,
_In_ SIZE_T Length
)
{
NTSTATUS status = STATUS_SUCCESS;
PH_STRINGREF block;
SIZE_T inPlaceUtf8Size;
PCHAR inPlaceUtf8 = NULL;
PPH_BYTES utf8 = NULL;
if (Length > PAGE_SIZE)
{
// In UTF-8, the maximum number of bytes per code point is 4.
inPlaceUtf8Size = PAGE_SIZE / sizeof(WCHAR) * 4;
inPlaceUtf8 = PhAllocatePage(inPlaceUtf8Size, NULL);
}
while (Length != 0)
{
block.Buffer = Buffer;
block.Length = PAGE_SIZE;
if (block.Length > Length)
block.Length = Length;
if (inPlaceUtf8)
{
SIZE_T bytesInUtf8String;
if (!PhConvertUtf16ToUtf8Buffer(
inPlaceUtf8,
inPlaceUtf8Size,
&bytesInUtf8String,
block.Buffer,
block.Length
))
{
status = STATUS_INVALID_PARAMETER;
goto CleanupExit;
}
status = PhWriteFileStream(FileStream, inPlaceUtf8, (ULONG)bytesInUtf8String);
}
else
{
utf8 = PhConvertUtf16ToUtf8Ex(block.Buffer, block.Length);
if (!utf8)
{
status = STATUS_INVALID_PARAMETER;
goto CleanupExit;
}
status = PhWriteFileStream(FileStream, utf8->Buffer, (ULONG)utf8->Length);
PhDereferenceObject(utf8);
}
if (!NT_SUCCESS(status))
goto CleanupExit;
Buffer += block.Length / sizeof(WCHAR);
Length -= block.Length;
}
CleanupExit:
if (inPlaceUtf8)
PhFreePage(inPlaceUtf8);
return status;
}
NTSTATUS PhWriteStringFormatAsUtf8FileStream_V(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ _Printf_format_string_ PWSTR Format,
_In_ va_list ArgPtr
)
{
NTSTATUS status;
PPH_STRING string;
string = PhFormatString_V(Format, ArgPtr);
status = PhWriteStringAsUtf8FileStream(FileStream, &string->sr);
PhDereferenceObject(string);
return status;
}
NTSTATUS PhWriteStringFormatAsUtf8FileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ _Printf_format_string_ PWSTR Format,
...
)
{
va_list argptr;
va_start(argptr, Format);
return PhWriteStringFormatAsUtf8FileStream_V(FileStream, Format, argptr);
}

276
phlib/format.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* Process Hacker -
* string formatting
*
* Copyright (C) 2010-2015 wj32
*
* 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/>.
*/
/*
* This module provides a high-performance string formatting mechanism. Instead of using format
* strings, the user supplies an array of structures. This system is 2-5 times faster than
* printf-based functions.
*
* This file contains the public interfaces, while including the real formatting code from
* elsewhere. There are currently two functions: PhFormat, which returns a string object containing
* the formatted string, and PhFormatToBuffer, which writes the formatted string to a buffer. The
* latter is a bit faster due to the lack of resizing logic.
*/
#include <phbase.h>
#include <locale.h>
extern ULONG PhMaxSizeUnit;
#define SMALL_BUFFER_LENGTH (PH_OBJECT_SMALL_OBJECT_SIZE - FIELD_OFFSET(PH_STRING, Data) - sizeof(WCHAR))
#define BUFFER_SIZE 512
#define PHP_FORMAT_NEGATIVE 0x1
#define PHP_FORMAT_POSITIVE 0x2
#define PHP_FORMAT_PAD 0x4
// Internal CRT routine needed for floating-point conversion
errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,
int format, int precision, int caps, _locale_t plocinfo);
// Keep in sync with PhSizeUnitNames
static PH_STRINGREF PhpSizeUnitNamesCounted[7] =
{
PH_STRINGREF_INIT(L"B"),
PH_STRINGREF_INIT(L"kB"),
PH_STRINGREF_INIT(L"MB"),
PH_STRINGREF_INIT(L"GB"),
PH_STRINGREF_INIT(L"TB"),
PH_STRINGREF_INIT(L"PB"),
PH_STRINGREF_INIT(L"EB")
};
static PH_INITONCE PhpFormatInitOnce = PH_INITONCE_INIT;
static WCHAR PhpFormatDecimalSeparator = '.';
static WCHAR PhpFormatThousandSeparator = ',';
static _locale_t PhpFormatUserLocale = NULL;
#if (_MSC_VER >= 1900)
// See Source\10.0.10150.0\ucrt\convert\cvt.cpp in SDK v10.
errno_t __cdecl __acrt_fp_format(
double const* const value,
char* const result_buffer,
size_t const result_buffer_count,
char* const scratch_buffer,
size_t const scratch_buffer_count,
int const format,
int const precision,
UINT64 const options,
_locale_t const locale
);
static errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes,
int format, int precision, int caps, _locale_t plocinfo)
{
char scratch_buffer[_CVTBUFSIZE + 1];
if (caps & 1)
format -= 32; // Make uppercase
return __acrt_fp_format(arg, buffer, sizeInBytes, scratch_buffer, sizeof(scratch_buffer),
format, precision, 0, plocinfo);
}
#endif
// From Source\10.0.10150.0\ucrt\inc\corecrt_internal_stdio_output.h in SDK v10.
VOID PhpCropZeros(
_Inout_ PCHAR Buffer,
_In_ _locale_t Locale
)
{
CHAR decimalSeparator = (CHAR)PhpFormatDecimalSeparator;
while (*Buffer && *Buffer != decimalSeparator)
++Buffer;
if (*Buffer++)
{
while (*Buffer && *Buffer != 'e' && *Buffer != 'E')
++Buffer;
PCHAR stop = Buffer--;
while (*Buffer == '0')
--Buffer;
if (*Buffer == decimalSeparator)
--Buffer;
while ((*++Buffer = *stop++) != '\0')
NOTHING;
}
}
PPH_STRING PhpResizeFormatBuffer(
_In_ PPH_STRING String,
_Inout_ PSIZE_T AllocatedLength,
_In_ SIZE_T UsedLength,
_In_ SIZE_T NeededLength
)
{
PPH_STRING newString;
SIZE_T allocatedLength;
allocatedLength = *AllocatedLength;
allocatedLength *= 2;
if (allocatedLength < UsedLength + NeededLength)
allocatedLength = UsedLength + NeededLength;
newString = PhCreateStringEx(NULL, allocatedLength);
memcpy(newString->Buffer, String->Buffer, UsedLength);
PhDereferenceObject(String);
*AllocatedLength = allocatedLength;
return newString;
}
/**
* Creates a formatted string.
*
* \param Format An array of format structures.
* \param Count The number of structures supplied in \a Format.
* \param InitialCapacity The number of bytes to reserve initially for the string. If 0 is
* specified, a default value is used.
*/
PPH_STRING PhFormat(
_In_reads_(Count) PPH_FORMAT Format,
_In_ ULONG Count,
_In_opt_ SIZE_T InitialCapacity
)
{
PPH_STRING string;
SIZE_T allocatedLength;
PWSTR buffer;
SIZE_T usedLength;
// Set up the buffer.
// If the specified initial capacity is too small (or zero), use the largest buffer size which
// will still be eligible for allocation from the small object free list.
if (InitialCapacity < SMALL_BUFFER_LENGTH)
InitialCapacity = SMALL_BUFFER_LENGTH;
string = PhCreateStringEx(NULL, InitialCapacity);
allocatedLength = InitialCapacity;
buffer = string->Buffer;
usedLength = 0;
#undef ENSURE_BUFFER
#undef OK_BUFFER
#undef ADVANCE_BUFFER
#define ENSURE_BUFFER(NeededLength) \
do { \
if (allocatedLength < usedLength + (NeededLength)) \
{ \
string = PhpResizeFormatBuffer(string, &allocatedLength, usedLength, (NeededLength)); \
buffer = string->Buffer + usedLength / sizeof(WCHAR); \
} \
} while (0)
#define OK_BUFFER (TRUE)
#define ADVANCE_BUFFER(Length) \
do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0)
#include "format_i.h"
string->Length = usedLength;
// Null-terminate the string.
string->Buffer[usedLength / sizeof(WCHAR)] = 0;
return string;
}
/**
* Writes a formatted string to a buffer.
*
* \param Format An array of format structures.
* \param Count The number of structures supplied in \a Format.
* \param Buffer A buffer. If NULL, no data is written.
* \param BufferLength The number of bytes available in \a Buffer, including space for the null
* terminator.
* \param ReturnLength The number of bytes required to hold the string, including the null
* terminator.
*
* \return TRUE if the buffer was large enough and the string was written (i.e. \a BufferLength >=
* \a ReturnLength), otherwise FALSE. In either case, the required number of bytes is stored in
* \a ReturnLength.
*
* \remarks If the function fails but \a BufferLength != 0, a single null byte is written to the
* start of \a Buffer.
*/
BOOLEAN PhFormatToBuffer(
_In_reads_(Count) PPH_FORMAT Format,
_In_ ULONG Count,
_Out_writes_bytes_opt_(BufferLength) PWSTR Buffer,
_In_opt_ SIZE_T BufferLength,
_Out_opt_ PSIZE_T ReturnLength
)
{
PWSTR buffer;
SIZE_T usedLength;
BOOLEAN overrun;
buffer = Buffer;
usedLength = 0;
overrun = FALSE;
// Make sure we don't try to write anything if we don't have a buffer.
if (!Buffer)
overrun = TRUE;
#undef ENSURE_BUFFER
#undef OK_BUFFER
#undef ADVANCE_BUFFER
#define ENSURE_BUFFER(NeededLength) \
do { \
if (!overrun && (BufferLength < usedLength + (NeededLength))) \
overrun = TRUE; \
} while (0)
#define OK_BUFFER (!overrun)
#define ADVANCE_BUFFER(Length) \
do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0)
#include "format_i.h"
// Write the null-terminator.
ENSURE_BUFFER(sizeof(WCHAR));
if (OK_BUFFER)
*buffer = 0;
else if (Buffer && BufferLength != 0) // try to null-terminate even if this function fails
*Buffer = 0;
ADVANCE_BUFFER(sizeof(WCHAR));
if (ReturnLength)
*ReturnLength = usedLength;
return OK_BUFFER;
}

568
phlib/format_i.h Normal file
View File

@@ -0,0 +1,568 @@
/*
* This file contains the actual formatting code used by various public interface functions.
*
* There are three macros defined by the parent function which control how this code writes the
* formatted string:
* * ENSURE_BUFFER - This macro is passed the number of bytes required whenever characters need to
* be written to the buffer. The macro can resize the buffer if needed.
* * OK_BUFFER - This macro returns TRUE if it is OK to write to the buffer, otherwise FALSE when
* the buffer is too large, is not specified, or some other error has occurred.
* * ADVANCE_BUFFER - This macro is passed the number of bytes written to the buffer and should
* increment the "buffer" pointer and "usedLength" counter.
* In addition to these macros, the "buffer" and "usedLength" variables are assumed to be present.
*
* The below code defines many macros; this is so that composite formatting types can be constructed
* (e.g. the "size" type).
*/
{
if (PhBeginInitOnce(&PhpFormatInitOnce))
{
WCHAR localeBuffer[4];
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, localeBuffer, 4) &&
(localeBuffer[0] != 0 && localeBuffer[1] == 0))
{
PhpFormatDecimalSeparator = localeBuffer[0];
}
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, localeBuffer, 4) &&
(localeBuffer[0] != 0 && localeBuffer[1] == 0))
{
PhpFormatThousandSeparator = localeBuffer[0];
}
if (PhpFormatDecimalSeparator != '.')
PhpFormatUserLocale = _create_locale(LC_ALL, "");
PhEndInitOnce(&PhpFormatInitOnce);
}
while (Count--)
{
PPH_FORMAT format;
SIZE_T partLength;
WCHAR tempBuffer[BUFFER_SIZE];
ULONG flags;
ULONG int32;
ULONG64 int64;
format = Format++;
// Save the currently used length so we can compute the part length later.
partLength = usedLength;
flags = 0;
switch (format->Type & FormatTypeMask)
{
// Characters and Strings
case CharFormatType:
ENSURE_BUFFER(sizeof(WCHAR));
if (OK_BUFFER)
*buffer = format->u.Char;
ADVANCE_BUFFER(sizeof(WCHAR));
break;
case StringFormatType:
ENSURE_BUFFER(format->u.String.Length);
if (OK_BUFFER)
memcpy(buffer, format->u.String.Buffer, format->u.String.Length);
ADVANCE_BUFFER(format->u.String.Length);
break;
case StringZFormatType:
{
SIZE_T count;
count = PhCountStringZ(format->u.StringZ);
ENSURE_BUFFER(count * sizeof(WCHAR));
if (OK_BUFFER)
memcpy(buffer, format->u.StringZ, count * sizeof(WCHAR));
ADVANCE_BUFFER(count * sizeof(WCHAR));
}
break;
case MultiByteStringFormatType:
case MultiByteStringZFormatType:
{
ULONG bytesInUnicodeString;
PSTR multiByteBuffer;
SIZE_T multiByteLength;
if (format->Type == MultiByteStringFormatType)
{
multiByteBuffer = format->u.MultiByteString.Buffer;
multiByteLength = format->u.MultiByteString.Length;
}
else
{
multiByteBuffer = format->u.MultiByteStringZ;
multiByteLength = strlen(multiByteBuffer);
}
if (NT_SUCCESS(RtlMultiByteToUnicodeSize(
&bytesInUnicodeString,
multiByteBuffer,
(ULONG)multiByteLength
)))
{
ENSURE_BUFFER(bytesInUnicodeString);
if (!OK_BUFFER || NT_SUCCESS(RtlMultiByteToUnicodeN(
buffer,
bytesInUnicodeString,
NULL,
multiByteBuffer,
(ULONG)multiByteLength
)))
{
ADVANCE_BUFFER(bytesInUnicodeString);
}
}
}
break;
// Integers
#define PROCESS_DIGIT(Input) \
do { \
r = (ULONG)(Input % radix); \
Input /= radix; \
*temp-- = integerToChar[r]; \
tempCount++; \
} while (0)
#define COMMON_INTEGER_FORMAT(Input, Format) \
do { \
ULONG radix; \
PCHAR integerToChar; \
PWSTR temp; \
ULONG tempCount; \
ULONG r; \
ULONG preCount; \
ULONG padCount; \
\
radix = 10; \
if (((Format)->Type & FormatUseRadix) && (Format)->Radix >= 2 && (Format)->Radix <= 69) \
radix = (Format)->Radix; \
integerToChar = PhIntegerToChar; \
if ((Format)->Type & FormatUpperCase) \
integerToChar = PhIntegerToCharUpper; \
temp = tempBuffer + BUFFER_SIZE - 1; \
tempCount = 0; \
\
if (Input != 0) \
{ \
if ((Format)->Type & FormatGroupDigits) \
{ \
ULONG needsSep = 0; \
\
do \
{ \
PROCESS_DIGIT(Input); \
\
if (++needsSep == 3 && Input != 0) /* get rid of trailing separator */ \
{ \
*temp-- = PhpFormatThousandSeparator; \
tempCount++; \
needsSep = 0; \
} \
} while (Input != 0); \
} \
else \
{ \
do \
{ \
PROCESS_DIGIT(Input); \
} while (Input != 0); \
} \
} \
else \
{ \
*temp-- = '0'; \
tempCount++; \
} \
\
preCount = 0; \
\
if (flags & PHP_FORMAT_NEGATIVE) \
preCount++; \
else if ((Format)->Type & FormatPrefixSign) \
preCount++; \
\
if (((Format)->Type & FormatPadZeros) && !((Format)->Type & FormatGroupDigits)) \
{ \
if (preCount + tempCount < (Format)->Width) \
{ \
flags |= PHP_FORMAT_PAD; \
padCount = (Format)->Width - (preCount + tempCount); \
preCount += padCount; \
} \
} \
\
temp++; \
ENSURE_BUFFER((preCount + tempCount) * sizeof(WCHAR)); \
if (OK_BUFFER) \
{ \
if (flags & PHP_FORMAT_NEGATIVE) \
*buffer++ = '-'; \
else if ((Format)->Type & FormatPrefixSign) \
*buffer++ = '+'; \
\
if (flags & PHP_FORMAT_PAD) \
{ \
wmemset(buffer, '0', padCount); \
buffer += padCount; \
} \
\
memcpy(buffer, temp, tempCount * sizeof(WCHAR)); \
buffer += tempCount; \
} \
usedLength += (preCount + tempCount) * sizeof(WCHAR); \
} while (0)
#ifndef _WIN64
case IntPtrFormatType:
int32 = format->u.IntPtr;
goto CommonMaybeNegativeInt32Format;
#endif
case Int32FormatType:
int32 = format->u.Int32;
#ifndef _WIN64
CommonMaybeNegativeInt32Format:
#endif
if ((LONG)int32 < 0)
{
int32 = -(LONG)int32;
flags |= PHP_FORMAT_NEGATIVE;
}
goto CommonInt32Format;
#ifndef _WIN64
case UIntPtrFormatType:
int32 = format->u.UIntPtr;
goto CommonInt32Format;
#endif
case UInt32FormatType:
int32 = format->u.UInt32;
CommonInt32Format:
COMMON_INTEGER_FORMAT(int32, format);
break;
#ifdef _WIN64
case IntPtrFormatType:
int64 = format->u.IntPtr;
goto CommonMaybeNegativeInt64Format;
#endif
case Int64FormatType:
int64 = format->u.Int64;
#ifdef _WIN64
CommonMaybeNegativeInt64Format:
#endif
if ((LONG64)int64 < 0)
{
int64 = -(LONG64)int64;
flags |= PHP_FORMAT_NEGATIVE;
}
goto CommonInt64Format;
#ifdef _WIN64
case UIntPtrFormatType:
int64 = format->u.UIntPtr;
goto CommonInt64Format;
#endif
case UInt64FormatType:
int64 = format->u.UInt64;
CommonInt64Format:
COMMON_INTEGER_FORMAT(int64, format);
break;
// Floating point numbers
#define COMMON_DOUBLE_FORMAT(Format) \
do { \
ULONG precision; \
DOUBLE value; \
CHAR c; \
PSTR temp; \
ULONG length; \
\
if ((Format)->Type & FormatUsePrecision) \
{ \
precision = (Format)->Precision; \
\
if (precision > BUFFER_SIZE - 1 - _CVTBUFSIZE) \
precision = BUFFER_SIZE - 1 - _CVTBUFSIZE; \
} \
else \
{ \
precision = 6; \
} \
\
c = 'f'; \
\
if ((Format)->Type & FormatStandardForm) \
c = 'e'; \
else if ((Format)->Type & FormatHexadecimalForm) \
c = 'a'; \
\
/* Use MS CRT routines to do the work. */ \
\
value = (Format)->u.Double; \
temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \
_cfltcvt_l( \
&value, \
temp, \
sizeof(tempBuffer) - 1, \
c, \
precision, \
!!((Format)->Type & FormatUpperCase), \
PhpFormatUserLocale \
); \
\
/* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \
/* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \
if ((Format)->Type & FormatCropZeros) \
PhpCropZeros(temp, PhpFormatUserLocale); \
\
length = (ULONG)strlen(temp); \
\
if (temp[0] == '-') \
{ \
flags |= PHP_FORMAT_NEGATIVE; \
temp++; \
length--; \
} \
else if ((Format)->Type & FormatPrefixSign) \
{ \
flags |= PHP_FORMAT_POSITIVE; \
} \
\
if (((Format)->Type & FormatGroupDigits) && !((Format)->Type & (FormatStandardForm | FormatHexadecimalForm))) \
{ \
PSTR whole; \
PSTR decimalPoint; \
ULONG wholeCount; \
ULONG sepsCount; \
ULONG ensureLength; \
ULONG copyCount; \
ULONG needsSep; \
\
/* Find the first non-digit character and assume that is the */ \
/* decimal point (or the end of the string). */ \
\
whole = temp; \
decimalPoint = temp; \
\
while ((UCHAR)(*decimalPoint - '0') < 10) \
decimalPoint++; \
\
/* Copy the characters to the output buffer, and at the same time */ \
/* insert the separators. */ \
\
wholeCount = (ULONG)(decimalPoint - temp); \
\
if (wholeCount != 0) \
sepsCount = (wholeCount + 2) / 3 - 1; \
else \
sepsCount = 0; \
\
ensureLength = (length + sepsCount) * sizeof(WCHAR); \
if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \
ensureLength += sizeof(WCHAR); \
ENSURE_BUFFER(ensureLength); \
\
copyCount = wholeCount; \
needsSep = (wholeCount + 2) % 3; \
\
if (OK_BUFFER) \
{ \
if (flags & PHP_FORMAT_NEGATIVE) \
*buffer++ = '-'; \
else if (flags & PHP_FORMAT_POSITIVE) \
*buffer++ = '+'; \
\
while (copyCount--) \
{ \
*buffer++ = *whole++; \
\
if (needsSep-- == 0 && copyCount != 0) /* get rid of trailing separator */ \
{ \
*buffer++ = PhpFormatThousandSeparator; \
needsSep = 2; \
} \
} \
} \
\
if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \
usedLength += sizeof(WCHAR); \
usedLength += (wholeCount + sepsCount) * sizeof(WCHAR); \
\
/* Copy the rest. */ \
\
copyCount = length - wholeCount; \
\
if (OK_BUFFER) \
{ \
PhZeroExtendToUtf16Buffer(decimalPoint, copyCount, buffer); \
ADVANCE_BUFFER(copyCount * sizeof(WCHAR)); \
} \
} \
else \
{ \
SIZE_T preLength; \
SIZE_T padLength; \
\
/* Take care of the sign and zero padding. */ \
preLength = 0; \
\
if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \
preLength++; \
\
if ((Format)->Type & FormatPadZeros) \
{ \
if (preLength + length < (Format)->Width) \
{ \
flags |= PHP_FORMAT_PAD; \
padLength = (Format)->Width - (preLength + length); \
preLength += padLength; \
} \
} \
/* We don't need to group digits, so directly copy the characters */ \
/* to the output buffer. */ \
\
ENSURE_BUFFER((preLength + length) * sizeof(WCHAR)); \
\
if (OK_BUFFER) \
{ \
if (flags & PHP_FORMAT_NEGATIVE) \
*buffer++ = '-'; \
else if (flags & PHP_FORMAT_POSITIVE) \
*buffer++ = '+'; \
\
if (flags & PHP_FORMAT_PAD) \
{ \
wmemset(buffer, '0', padLength); \
buffer += padLength; \
} \
} \
\
usedLength += preLength * sizeof(WCHAR); \
\
if (OK_BUFFER) \
{ \
PhZeroExtendToUtf16Buffer((PSTR)temp, length, buffer); \
ADVANCE_BUFFER(length * sizeof(WCHAR)); \
} \
} \
} while (0)
case DoubleFormatType:
flags = 0;
COMMON_DOUBLE_FORMAT(format);
break;
// Additional types
case SizeFormatType:
{
ULONG i = 0;
ULONG maxSizeUnit;
DOUBLE s;
PH_FORMAT doubleFormat;
s = (DOUBLE)format->u.Size;
if (format->u.Size == 0)
{
ENSURE_BUFFER(sizeof(WCHAR));
if (OK_BUFFER)
*buffer = '0';
ADVANCE_BUFFER(sizeof(WCHAR));
goto ContinueLoop;
}
if (format->Type & FormatUseRadix)
maxSizeUnit = format->Radix;
else
maxSizeUnit = PhMaxSizeUnit;
while (
s >= 1000 &&
i < sizeof(PhpSizeUnitNamesCounted) / sizeof(PH_STRINGREF) &&
i < maxSizeUnit
)
{
s /= 1024;
i++;
}
// Format the number, then append the unit name.
doubleFormat.Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | FormatGroupDigits;
doubleFormat.Precision = (format->Type & FormatUsePrecision) ? format->Precision : 2;
doubleFormat.Width = 0; // stupid compiler
doubleFormat.u.Double = s;
flags = 0;
COMMON_DOUBLE_FORMAT(&doubleFormat);
ENSURE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length);
if (OK_BUFFER)
{
*buffer = ' ';
memcpy(buffer + 1, PhpSizeUnitNamesCounted[i].Buffer, PhpSizeUnitNamesCounted[i].Length);
}
ADVANCE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length);
}
break;
}
ContinueLoop:
partLength = usedLength - partLength;
if (format->Type & (FormatLeftAlign | FormatRightAlign))
{
SIZE_T newLength;
SIZE_T addLength;
newLength = format->Width * sizeof(WCHAR);
// We only pad and never truncate.
if (partLength < newLength)
{
addLength = newLength - partLength;
ENSURE_BUFFER(addLength);
if (OK_BUFFER)
{
WCHAR pad;
if (format->Type & FormatUsePad)
pad = format->Pad;
else
pad = ' ';
if (format->Type & FormatLeftAlign)
{
// Left alignment is easy; we just fill the remaining space with the pad
// character.
wmemset(buffer, pad, addLength / sizeof(WCHAR));
}
else
{
PWSTR start;
// Right alignment is much slower and involves moving the text forward, then
// filling in the space before it.
start = buffer - partLength / sizeof(WCHAR);
memmove(start + addLength / sizeof(WCHAR), start, partLength);
wmemset(start, pad, addLength / sizeof(WCHAR));
}
}
ADVANCE_BUFFER(addLength);
}
}
}
}

238
phlib/global.c Normal file
View File

@@ -0,0 +1,238 @@
/*
* Process Hacker -
* global variables and initialization functions
*
* Copyright (C) 2010-2013 wj32
*
* 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 <ph.h>
#include <phintrnl.h>
#include <filestream.h>
#include <symprv.h>
BOOLEAN PhInitializeSystem(
_In_ ULONG Flags
);
VOID PhInitializeSystemInformation(
VOID
);
VOID PhInitializeWindowsVersion(
VOID
);
PHLIBAPI PVOID PhLibImageBase;
PHLIBAPI PWSTR PhApplicationName = L"Application";
PHLIBAPI ULONG PhGlobalDpi = 96;
PHLIBAPI PVOID PhHeapHandle;
PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion;
PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation;
PHLIBAPI ULONG WindowsVersion;
PHLIBAPI ACCESS_MASK ProcessQueryAccess;
PHLIBAPI ACCESS_MASK ProcessAllAccess;
PHLIBAPI ACCESS_MASK ThreadQueryAccess;
PHLIBAPI ACCESS_MASK ThreadSetAccess;
PHLIBAPI ACCESS_MASK ThreadAllAccess;
// Internal data
#ifdef DEBUG
PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock;
#endif
NTSTATUS PhInitializePhLib(
VOID
)
{
return PhInitializePhLibEx(
0xffffffff, // all possible features
0,
0
);
}
NTSTATUS PhInitializePhLibEx(
_In_ ULONG Flags,
_In_opt_ SIZE_T HeapReserveSize,
_In_opt_ SIZE_T HeapCommitSize
)
{
PhHeapHandle = RtlCreateHeap(
HEAP_GROWABLE | HEAP_CLASS_1,
NULL,
HeapReserveSize ? HeapReserveSize : 2 * 1024 * 1024, // 2 MB
HeapCommitSize ? HeapCommitSize : 1024 * 1024, // 1 MB
NULL,
NULL
);
if (!PhHeapHandle)
return STATUS_INSUFFICIENT_RESOURCES;
PhLibImageBase = NtCurrentPeb()->ImageBaseAddress;
PhInitializeWindowsVersion();
PhInitializeSystemInformation();
if (!PhQueuedLockInitialization())
return STATUS_UNSUCCESSFUL;
if (!NT_SUCCESS(PhRefInitialization()))
return STATUS_UNSUCCESSFUL;
if (!PhBaseInitialization())
return STATUS_UNSUCCESSFUL;
if (!PhInitializeSystem(Flags))
return STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
#ifndef _WIN64
BOOLEAN PhIsExecutingInWow64(
VOID
)
{
static BOOLEAN valid = FALSE;
static BOOLEAN isWow64;
if (!valid)
{
PhGetProcessIsWow64(NtCurrentProcess(), &isWow64);
MemoryBarrier();
valid = TRUE;
}
return isWow64;
}
#endif
static BOOLEAN PhInitializeSystem(
_In_ ULONG Flags
)
{
if (Flags & PHLIB_INIT_MODULE_FILE_STREAM)
{
if (!PhFileStreamInitialization())
return FALSE;
}
if (Flags & PHLIB_INIT_MODULE_SYMBOL_PROVIDER)
{
if (!PhSymbolProviderInitialization())
return FALSE;
}
return TRUE;
}
static VOID PhInitializeSystemInformation(
VOID
)
{
NtQuerySystemInformation(
SystemBasicInformation,
&PhSystemBasicInformation,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL
);
}
static VOID PhInitializeWindowsVersion(
VOID
)
{
RTL_OSVERSIONINFOEXW versionInfo;
ULONG majorVersion;
ULONG minorVersion;
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
{
WindowsVersion = WINDOWS_NEW;
return;
}
memcpy(&PhOsVersion, &versionInfo, sizeof(RTL_OSVERSIONINFOEXW));
majorVersion = versionInfo.dwMajorVersion;
minorVersion = versionInfo.dwMinorVersion;
if (majorVersion == 5 && minorVersion < 1 || majorVersion < 5)
{
WindowsVersion = WINDOWS_ANCIENT;
}
/* Windows XP */
else if (majorVersion == 5 && minorVersion == 1)
{
WindowsVersion = WINDOWS_XP;
}
/* Windows Server 2003 */
else if (majorVersion == 5 && minorVersion == 2)
{
WindowsVersion = WINDOWS_SERVER_2003;
}
/* Windows Vista, Windows Server 2008 */
else if (majorVersion == 6 && minorVersion == 0)
{
WindowsVersion = WINDOWS_VISTA;
}
/* Windows 7, Windows Server 2008 R2 */
else if (majorVersion == 6 && minorVersion == 1)
{
WindowsVersion = WINDOWS_7;
}
/* Windows 8 */
else if (majorVersion == 6 && minorVersion == 2)
{
WindowsVersion = WINDOWS_8;
}
/* Windows 8.1 */
else if (majorVersion == 6 && minorVersion == 3)
{
WindowsVersion = WINDOWS_8_1;
}
/* Windows 10 */
else if (majorVersion == 10 && minorVersion == 0)
{
WindowsVersion = WINDOWS_10;
}
else if (majorVersion == 10 && minorVersion > 0 || majorVersion > 10)
{
WindowsVersion = WINDOWS_NEW;
}
if (WINDOWS_HAS_LIMITED_ACCESS)
{
ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION;
ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff;
ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION;
ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION;
ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;
}
else
{
ProcessQueryAccess = PROCESS_QUERY_INFORMATION;
ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;
ThreadQueryAccess = THREAD_QUERY_INFORMATION;
ThreadSetAccess = THREAD_SET_INFORMATION;
ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff;
}
}

1332
phlib/graph.c Normal file

File diff suppressed because it is too large Load Diff

1372
phlib/guisup.c Normal file

File diff suppressed because it is too large Load Diff

1097
phlib/handle.c Normal file

File diff suppressed because it is too large Load Diff

1865
phlib/hexedit.c Normal file

File diff suppressed because it is too large Load Diff

1763
phlib/hndlinfo.c Normal file

File diff suppressed because it is too large Load Diff

237
phlib/icotobmp.c Normal file
View File

@@ -0,0 +1,237 @@
#include <ph.h>
#include <guisup.h>
#include <uxtheme.h>
// code from http://msdn.microsoft.com/en-us/library/bb757020.aspx
typedef HPAINTBUFFER (*_BeginBufferedPaint)(
_In_ HDC hdcTarget,
_In_ const RECT *prcTarget,
_In_ BP_BUFFERFORMAT dwFormat,
_In_ BP_PAINTPARAMS *pPaintParams,
_Out_ HDC *phdc
);
typedef HRESULT (*_EndBufferedPaint)(
_In_ HPAINTBUFFER hBufferedPaint,
_In_ BOOL fUpdateTarget
);
typedef HRESULT (*_GetBufferedPaintBits)(
_In_ HPAINTBUFFER hBufferedPaint,
_Out_ RGBQUAD **ppbBuffer,
_Out_ int *pcxRow
);
static BOOLEAN ImportsInitialized = FALSE;
static _BeginBufferedPaint BeginBufferedPaint_I = NULL;
static _EndBufferedPaint EndBufferedPaint_I = NULL;
static _GetBufferedPaintBits GetBufferedPaintBits_I = NULL;
static HBITMAP PhpCreateBitmap32(
_In_ HDC hdc,
_In_ ULONG Width,
_In_ ULONG Height,
_Outptr_opt_ PVOID *Bits
)
{
BITMAPINFO bitmapInfo;
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biWidth = Width;
bitmapInfo.bmiHeader.biHeight = Height;
bitmapInfo.bmiHeader.biBitCount = 32;
return CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0);
}
static BOOLEAN PhpHasAlpha(
_In_ PULONG Argb,
_In_ ULONG Width,
_In_ ULONG Height,
_In_ ULONG RowWidth
)
{
ULONG delta;
ULONG x;
ULONG y;
delta = RowWidth - Width;
for (y = Width; y; y--)
{
for (x = Height; x; x--)
{
if (*Argb++ & 0xff000000)
return TRUE;
}
Argb += delta;
}
return FALSE;
}
static VOID PhpConvertToPArgb32(
_In_ HDC hdc,
_Inout_ PULONG Argb,
_In_ HBITMAP Bitmap,
_In_ ULONG Width,
_In_ ULONG Height,
_In_ ULONG RowWidth
)
{
BITMAPINFO bitmapInfo;
PVOID bits;
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biWidth = Width;
bitmapInfo.bmiHeader.biHeight = Height;
bitmapInfo.bmiHeader.biBitCount = 32;
bits = PhAllocate(Width * sizeof(ULONG) * Height);
if (GetDIBits(hdc, Bitmap, 0, Height, bits, &bitmapInfo, DIB_RGB_COLORS) == Height)
{
PULONG argbMask;
ULONG delta;
ULONG x;
ULONG y;
argbMask = (PULONG)bits;
delta = RowWidth - Width;
for (y = Height; y; y--)
{
for (x = Width; x; x--)
{
if (*argbMask++)
{
*Argb++ = 0; // transparent
}
else
{
*Argb++ |= 0xff000000; // opaque
}
}
Argb += delta;
}
}
PhFree(bits);
}
static VOID PhpConvertToPArgb32IfNeeded(
_In_ HPAINTBUFFER PaintBuffer,
_In_ HDC hdc,
_In_ HICON Icon,
_In_ ULONG Width,
_In_ ULONG Height
)
{
RGBQUAD *quad;
ULONG rowWidth;
if (SUCCEEDED(GetBufferedPaintBits_I(PaintBuffer, &quad, &rowWidth)))
{
PULONG argb = (PULONG)quad;
if (!PhpHasAlpha(argb, Width, Height, rowWidth))
{
ICONINFO iconInfo;
if (GetIconInfo(Icon, &iconInfo))
{
if (iconInfo.hbmMask)
{
PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth);
}
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
}
}
}
}
HBITMAP PhIconToBitmap(
_In_ HICON Icon,
_In_ ULONG Width,
_In_ ULONG Height
)
{
HBITMAP bitmap;
RECT iconRectangle;
HDC screenHdc;
HDC hdc;
HBITMAP oldBitmap;
BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
BP_PAINTPARAMS paintParams = { sizeof(paintParams) };
HDC bufferHdc;
HPAINTBUFFER paintBuffer;
iconRectangle.left = 0;
iconRectangle.top = 0;
iconRectangle.right = Width;
iconRectangle.bottom = Height;
if (!ImportsInitialized)
{
HMODULE uxtheme;
uxtheme = GetModuleHandle(L"uxtheme.dll");
BeginBufferedPaint_I = PhGetProcedureAddress(uxtheme, "BeginBufferedPaint", 0);
EndBufferedPaint_I = PhGetProcedureAddress(uxtheme, "EndBufferedPaint", 0);
GetBufferedPaintBits_I = PhGetProcedureAddress(uxtheme, "GetBufferedPaintBits", 0);
ImportsInitialized = TRUE;
}
if (!BeginBufferedPaint_I || !EndBufferedPaint_I || !GetBufferedPaintBits_I)
{
// Probably XP.
screenHdc = GetDC(NULL);
hdc = CreateCompatibleDC(screenHdc);
bitmap = CreateCompatibleBitmap(screenHdc, Width, Height);
ReleaseDC(NULL, screenHdc);
oldBitmap = SelectObject(hdc, bitmap);
FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1));
DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);
SelectObject(hdc, oldBitmap);
DeleteDC(hdc);
return bitmap;
}
screenHdc = GetDC(NULL);
hdc = CreateCompatibleDC(screenHdc);
bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL);
ReleaseDC(NULL, screenHdc);
oldBitmap = SelectObject(hdc, bitmap);
paintParams.dwFlags = BPPF_ERASE;
paintParams.pBlendFunction = &blendFunction;
paintBuffer = BeginBufferedPaint_I(hdc, &iconRectangle, BPBF_DIB, &paintParams, &bufferHdc);
DrawIconEx(bufferHdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);
// If the icon did not have an alpha channel, we need to convert the buffer to PARGB.
PhpConvertToPArgb32IfNeeded(paintBuffer, hdc, Icon, Width, Height);
// This will write the buffer contents to the destination bitmap.
EndBufferedPaint_I(paintBuffer, TRUE);
SelectObject(hdc, oldBitmap);
DeleteDC(hdc);
return bitmap;
}

86
phlib/include/apiimport.h Normal file
View File

@@ -0,0 +1,86 @@
#ifndef _PH_APIIMPORT_H
#define _PH_APIIMPORT_H
// comctl32
typedef HRESULT (WINAPI *_TaskDialogIndirect)(
_In_ const struct _TASKDIALOGCONFIG *pTaskConfig,
_In_ int *pnButton,
_In_ int *pnRadioButton,
_In_ BOOL *pfVerificationFlagChecked
);
// ntdll
typedef NTSTATUS (NTAPI *_NtQueryInformationEnlistment)(
_In_ HANDLE EnlistmentHandle,
_In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass,
_Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation,
_In_ ULONG EnlistmentInformationLength,
_Out_opt_ PULONG ReturnLength
);
typedef NTSTATUS (NTAPI *_NtQueryInformationResourceManager)(
_In_ HANDLE ResourceManagerHandle,
_In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,
_Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation,
_In_ ULONG ResourceManagerInformationLength,
_Out_opt_ PULONG ReturnLength
);
typedef NTSTATUS (NTAPI *_NtQueryInformationTransaction)(
_In_ HANDLE TransactionHandle,
_In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,
_Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation,
_In_ ULONG TransactionInformationLength,
_Out_opt_ PULONG ReturnLength
);
typedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)(
_In_ HANDLE TransactionManagerHandle,
_In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,
_Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation,
_In_ ULONG TransactionManagerInformationLength,
_Out_opt_ PULONG ReturnLength
);
// shell32
#if defined(_M_IX86)
#define __unaligned
#endif
typedef HRESULT (WINAPI *_SHCreateShellItem)(
_In_opt_ const struct _ITEMIDLIST __unaligned *pidlParent,
_In_opt_ struct IShellFolder *psfParent,
_In_ const struct _ITEMIDLIST __unaligned *pidl,
_Out_ struct IShellItem **ppsi
);
typedef HRESULT (WINAPI *_SHOpenFolderAndSelectItems)(
_In_ const struct _ITEMIDLIST __unaligned *pidlFolder,
_In_ UINT cidl,
_In_reads_opt_(cidl) const struct _ITEMIDLIST __unaligned **apidl,
_In_ DWORD dwFlags
);
typedef HRESULT (WINAPI *_SHParseDisplayName)(
_In_ LPCWSTR pszName,
_In_opt_ struct IBindCtx *pbc,
_Out_ const struct _ITEMIDLIST __unaligned **ppidl,
_In_ ULONG sfgaoIn,
_Out_ ULONG *psfgaoOut
);
#define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID)
PH_DECLARE_IMPORT(TaskDialogIndirect);
PH_DECLARE_IMPORT(NtQueryInformationEnlistment);
PH_DECLARE_IMPORT(NtQueryInformationResourceManager);
PH_DECLARE_IMPORT(NtQueryInformationTransaction);
PH_DECLARE_IMPORT(NtQueryInformationTransactionManager);
PH_DECLARE_IMPORT(SHCreateShellItem);
PH_DECLARE_IMPORT(SHOpenFolderAndSelectItems);
PH_DECLARE_IMPORT(SHParseDisplayName);
#endif

26
phlib/include/circbuf.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef _PH_CIRCBUF_H
#define _PH_CIRCBUF_H
#define PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
#undef T
#define T ULONG
#include "circbuf_h.h"
#undef T
#define T ULONG64
#include "circbuf_h.h"
#undef T
#define T PVOID
#include "circbuf_h.h"
#undef T
#define T SIZE_T
#include "circbuf_h.h"
#undef T
#define T FLOAT
#include "circbuf_h.h"
#endif

140
phlib/include/circbuf_h.h Normal file
View File

@@ -0,0 +1,140 @@
#ifdef T
#include <templ.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct T___(_PH_CIRCULAR_BUFFER, T)
{
ULONG Size;
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
ULONG SizeMinusOne;
#endif
ULONG Count;
LONG Index;
T *Data;
} T___(PH_CIRCULAR_BUFFER, T), *T___(PPH_CIRCULAR_BUFFER, T);
PHLIBAPI
VOID
NTAPI
T___(PhInitializeCircularBuffer, T)(
_Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ ULONG Size
);
PHLIBAPI
VOID
NTAPI
T___(PhDeleteCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer
);
PHLIBAPI
VOID
NTAPI
T___(PhResizeCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ ULONG NewSize
);
PHLIBAPI
VOID
NTAPI
T___(PhClearCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer
);
PHLIBAPI
VOID
NTAPI
T___(PhCopyCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_Out_writes_(Count) T *Destination,
_In_ ULONG Count
);
FORCEINLINE T T___(PhGetItemCircularBuffer, T)(
_In_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ LONG Index
)
{
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
return Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne];
#else
ULONG size;
size = Buffer->Size;
// Modulo is dividend-based.
return Buffer->Data[(((Buffer->Index + Index) % size) + size) % size];
#endif
}
FORCEINLINE VOID T___(PhSetItemCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ LONG Index,
_In_ T Value
)
{
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne] = Value;
#else
ULONG size;
size = Buffer->Size;
Buffer->Data[(((Buffer->Index + Index) % size) + size) % size] = Value;
#endif
}
FORCEINLINE VOID T___(PhAddItemCircularBuffer, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ T Value
)
{
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
Buffer->Data[Buffer->Index = ((Buffer->Index - 1) & Buffer->SizeMinusOne)] = Value;
#else
ULONG size;
size = Buffer->Size;
Buffer->Data[Buffer->Index = (((Buffer->Index - 1) % size) + size) % size] = Value;
#endif
if (Buffer->Count < Buffer->Size)
Buffer->Count++;
}
FORCEINLINE T T___(PhAddItemCircularBuffer2, T)(
_Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer,
_In_ T Value
)
{
LONG index;
T oldValue;
#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE
index = ((Buffer->Index - 1) & Buffer->SizeMinusOne);
#else
ULONG size;
size = Buffer->Size;
index = (((Buffer->Index - 1) % size) + size) % size;
#endif
Buffer->Index = index;
oldValue = Buffer->Data[index];
Buffer->Data[index] = Value;
if (Buffer->Count < Buffer->Size)
Buffer->Count++;
return oldValue;
}
#ifdef __cplusplus
}
#endif
#endif

30
phlib/include/colorbox.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef _PH_COLORBOX_H
#define _PH_COLORBOX_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_COLORBOX_CLASSNAME L"PhColorBox"
PHLIBAPI
BOOLEAN
NTAPI
PhColorBoxInitialization(
VOID
);
#define CBCM_SETCOLOR (WM_APP + 1501)
#define CBCM_GETCOLOR (WM_APP + 1502)
#define ColorBox_SetColor(hWnd, Color) \
SendMessage((hWnd), CBCM_SETCOLOR, (WPARAM)(Color), 0)
#define ColorBox_GetColor(hWnd) \
((COLORREF)SendMessage((hWnd), CBCM_GETCOLOR, 0, 0))
#ifdef __cplusplus
}
#endif
#endif

78
phlib/include/cpysave.h Normal file
View File

@@ -0,0 +1,78 @@
#ifndef _PH_CPYSAVE_H
#define _PH_CPYSAVE_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_EXPORT_MODE_TABS 0
#define PH_EXPORT_MODE_SPACES 1
#define PH_EXPORT_MODE_CSV 2
PHLIBAPI
VOID PhaCreateTextTable(
_Out_ PPH_STRING ***Table,
_In_ ULONG Rows,
_In_ ULONG Columns
);
PHLIBAPI
PPH_LIST PhaFormatTextTable(
_In_ PPH_STRING **Table,
_In_ ULONG Rows,
_In_ ULONG Columns,
_In_ ULONG Mode
);
PHLIBAPI
VOID PhMapDisplayIndexTreeNew(
_In_ HWND TreeNewHandle,
_Out_opt_ PULONG *DisplayToId,
_Out_opt_ PWSTR **DisplayToText,
_Out_ PULONG NumberOfColumns
);
PHLIBAPI
PPH_STRING PhGetTreeNewText(
_In_ HWND TreeNewHandle,
_Reserved_ ULONG Reserved
);
PHLIBAPI
PPH_LIST PhGetGenericTreeNewLines(
_In_ HWND TreeNewHandle,
_In_ ULONG Mode
);
PHLIBAPI
VOID PhaMapDisplayIndexListView(
_In_ HWND ListViewHandle,
_Out_writes_(Count) PULONG DisplayToId,
_Out_writes_opt_(Count) PPH_STRING *DisplayToText,
_In_ ULONG Count,
_Out_ PULONG NumberOfColumns
);
PHLIBAPI
PPH_STRING PhaGetListViewItemText(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ INT SubItemIndex
);
PHLIBAPI
PPH_STRING PhGetListViewText(
_In_ HWND ListViewHandle
);
PHLIBAPI
PPH_LIST PhGetListViewLines(
_In_ HWND ListViewHandle,
_In_ ULONG Mode
);
#ifdef __cplusplus
}
#endif
#endif

35
phlib/include/dltmgr.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef _PH_DLTMGR_H
#define _PH_DLTMGR_H
typedef struct _PH_SINGLE_DELTA
{
FLOAT Value;
FLOAT Delta;
} PH_SINGLE_DELTA, *PPH_SINGLE_DELTA;
typedef struct _PH_UINT32_DELTA
{
ULONG Value;
ULONG Delta;
} PH_UINT32_DELTA, *PPH_UINT32_DELTA;
typedef struct _PH_UINT64_DELTA
{
ULONG64 Value;
ULONG64 Delta;
} PH_UINT64_DELTA, *PPH_UINT64_DELTA;
typedef struct _PH_UINTPTR_DELTA
{
ULONG_PTR Value;
ULONG_PTR Delta;
} PH_UINTPTR_DELTA, *PPH_UINTPTR_DELTA;
#define PhInitializeDelta(DltMgr) \
((DltMgr)->Value = 0, (DltMgr)->Delta = 0)
#define PhUpdateDelta(DltMgr, NewValue) \
((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \
(DltMgr)->Value = (NewValue), (DltMgr)->Delta)
#endif

48
phlib/include/dspick.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef _PH_DSPICK_H
#define _PH_DSPICK_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_DSPICK_MULTISELECT 0x1
typedef struct _PH_DSPICK_OBJECT
{
PPH_STRING Name;
PSID Sid;
} PH_DSPICK_OBJECT, *PPH_DSPICK_OBJECT;
typedef struct _PH_DSPICK_OBJECTS
{
ULONG NumberOfObjects;
PH_DSPICK_OBJECT Objects[1];
} PH_DSPICK_OBJECTS, *PPH_DSPICK_OBJECTS;
PHLIBAPI
VOID PhFreeDsObjectPickerDialog(
_In_ PVOID PickerDialog
);
PHLIBAPI
PVOID PhCreateDsObjectPickerDialog(
_In_ ULONG Flags
);
PHLIBAPI
BOOLEAN PhShowDsObjectPickerDialog(
_In_ HWND hWnd,
_In_ PVOID PickerDialog,
_Out_ PPH_DSPICK_OBJECTS *Objects
);
PHLIBAPI
VOID PhFreeDsObjectPickerObjects(
_In_ PPH_DSPICK_OBJECTS Objects
);
#ifdef __cplusplus
}
#endif
#endif

219
phlib/include/emenu.h Normal file
View File

@@ -0,0 +1,219 @@
#ifndef _PH_EMENU_H
#define _PH_EMENU_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_EMENU_DISABLED 0x1
#define PH_EMENU_CHECKED 0x2
#define PH_EMENU_HIGHLIGHT 0x4
#define PH_EMENU_MENUBARBREAK 0x8
#define PH_EMENU_MENUBREAK 0x10
#define PH_EMENU_DEFAULT 0x20
#define PH_EMENU_MOUSESELECT 0x40
#define PH_EMENU_RADIOCHECK 0x80
#define PH_EMENU_SEPARATECHECKSPACE 0x100000
#define PH_EMENU_SEPARATOR 0x200000
#define PH_EMENU_TEXT_OWNED 0x80000000
#define PH_EMENU_BITMAP_OWNED 0x40000000
struct _PH_EMENU_ITEM;
typedef VOID (NTAPI *PPH_EMENU_ITEM_DELETE_FUNCTION)(
_In_ struct _PH_EMENU_ITEM *Item
);
typedef struct _PH_EMENU_ITEM
{
ULONG Flags;
ULONG Id;
PWSTR Text;
HBITMAP Bitmap;
PVOID Parameter;
PVOID Context;
PPH_EMENU_ITEM_DELETE_FUNCTION DeleteFunction;
PVOID Reserved;
struct _PH_EMENU_ITEM *Parent;
PPH_LIST Items;
} PH_EMENU_ITEM, *PPH_EMENU_ITEM;
typedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU;
PHLIBAPI
PPH_EMENU_ITEM PhCreateEMenuItem(
_In_ ULONG Flags,
_In_ ULONG Id,
_In_ PWSTR Text,
_In_opt_ HBITMAP Bitmap,
_In_opt_ PVOID Context
);
PHLIBAPI
VOID PhDestroyEMenuItem(
_In_ PPH_EMENU_ITEM Item
);
#define PH_EMENU_FIND_DESCEND 0x1
#define PH_EMENU_FIND_STARTSWITH 0x2
#define PH_EMENU_FIND_LITERAL 0x4
PHLIBAPI
PPH_EMENU_ITEM PhFindEMenuItem(
_In_ PPH_EMENU_ITEM Item,
_In_ ULONG Flags,
_In_opt_ PWSTR Text,
_In_opt_ ULONG Id
);
PHLIBAPI
PPH_EMENU_ITEM PhFindEMenuItemEx(
_In_ PPH_EMENU_ITEM Item,
_In_ ULONG Flags,
_In_opt_ PWSTR Text,
_In_opt_ ULONG Id,
_Out_opt_ PPH_EMENU_ITEM *FoundParent,
_Out_opt_ PULONG FoundIndex
);
PHLIBAPI
ULONG PhIndexOfEMenuItem(
_In_ PPH_EMENU_ITEM Parent,
_In_ PPH_EMENU_ITEM Item
);
PHLIBAPI
VOID PhInsertEMenuItem(
_Inout_ PPH_EMENU_ITEM Parent,
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG Index
);
PHLIBAPI
BOOLEAN PhRemoveEMenuItem(
_Inout_opt_ PPH_EMENU_ITEM Parent,
_In_opt_ PPH_EMENU_ITEM Item,
_In_opt_ ULONG Index
);
PHLIBAPI
VOID PhRemoveAllEMenuItems(
_Inout_ PPH_EMENU_ITEM Parent
);
PHLIBAPI
PPH_EMENU PhCreateEMenu(
VOID
);
PHLIBAPI
VOID PhDestroyEMenu(
_In_ PPH_EMENU Menu
);
#define PH_EMENU_CONVERT_ID 0x1
typedef struct _PH_EMENU_DATA
{
PPH_LIST IdToItem;
} PH_EMENU_DATA, *PPH_EMENU_DATA;
PHLIBAPI
VOID PhInitializeEMenuData(
_Out_ PPH_EMENU_DATA Data
);
PHLIBAPI
VOID PhDeleteEMenuData(
_Inout_ PPH_EMENU_DATA Data
);
PHLIBAPI
HMENU PhEMenuToHMenu(
_In_ PPH_EMENU_ITEM Menu,
_In_ ULONG Flags,
_Inout_opt_ PPH_EMENU_DATA Data
);
PHLIBAPI
VOID PhEMenuToHMenu2(
_In_ HMENU MenuHandle,
_In_ PPH_EMENU_ITEM Menu,
_In_ ULONG Flags,
_Inout_opt_ PPH_EMENU_DATA Data
);
PHLIBAPI
VOID PhHMenuToEMenuItem(
_Inout_ PPH_EMENU_ITEM MenuItem,
_In_ HMENU MenuHandle
);
PHLIBAPI
VOID PhLoadResourceEMenuItem(
_Inout_ PPH_EMENU_ITEM MenuItem,
_In_ HINSTANCE InstanceHandle,
_In_ PWSTR Resource,
_In_ ULONG SubMenuIndex
);
#define PH_EMENU_SHOW_SEND_COMMAND 0x1
#define PH_EMENU_SHOW_LEFTRIGHT 0x2
PHLIBAPI
PPH_EMENU_ITEM PhShowEMenu(
_In_ PPH_EMENU Menu,
_In_ HWND WindowHandle,
_In_ ULONG Flags,
_In_ ULONG Align,
_In_ ULONG X,
_In_ ULONG Y
);
// Convenience functions
PHLIBAPI
BOOLEAN PhSetFlagsEMenuItem(
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG Id,
_In_ ULONG Mask,
_In_ ULONG Value
);
FORCEINLINE BOOLEAN PhEnableEMenuItem(
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG Id,
_In_ BOOLEAN Enable
)
{
return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED);
}
PHLIBAPI
VOID PhSetFlagsAllEMenuItems(
_In_ PPH_EMENU_ITEM Item,
_In_ ULONG Mask,
_In_ ULONG Value
);
#define PH_EMENU_MODIFY_TEXT 0x1
#define PH_EMENU_MODIFY_BITMAP 0x2
PHLIBAPI
VOID PhModifyEMenuItem(
_Inout_ PPH_EMENU_ITEM Item,
_In_ ULONG ModifyFlags,
_In_ ULONG OwnedFlags,
_In_opt_ PWSTR Text,
_In_opt_ HBITMAP Bitmap
);
#ifdef __cplusplus
}
#endif
#endif

93
phlib/include/fastlock.h Normal file
View File

@@ -0,0 +1,93 @@
#ifndef _PH_FASTLOCK_H
#define _PH_FASTLOCK_H
// FastLock is a port of FastResourceLock from PH 1.x.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _PH_FAST_LOCK
{
ULONG Value;
HANDLE ExclusiveWakeEvent;
HANDLE SharedWakeEvent;
} PH_FAST_LOCK, *PPH_FAST_LOCK;
#define PH_FAST_LOCK_INIT { 0, NULL, NULL }
PHLIBAPI
VOID
NTAPI
PhInitializeFastLock(
_Out_ PPH_FAST_LOCK FastLock
);
PHLIBAPI
VOID
NTAPI
PhDeleteFastLock(
_Inout_ PPH_FAST_LOCK FastLock
);
#define PhAcquireFastLockExclusive PhfAcquireFastLockExclusive
_May_raise_
_Acquires_exclusive_lock_(*FastLock)
PHLIBAPI
VOID
FASTCALL
PhfAcquireFastLockExclusive(
_Inout_ PPH_FAST_LOCK FastLock
);
#define PhAcquireFastLockShared PhfAcquireFastLockShared
_May_raise_
_Acquires_shared_lock_(*FastLock)
PHLIBAPI
VOID
FASTCALL
PhfAcquireFastLockShared(
_Inout_ PPH_FAST_LOCK FastLock
);
#define PhReleaseFastLockExclusive PhfReleaseFastLockExclusive
_Releases_exclusive_lock_(*FastLock)
PHLIBAPI
VOID
FASTCALL
PhfReleaseFastLockExclusive(
_Inout_ PPH_FAST_LOCK FastLock
);
#define PhReleaseFastLockShared PhfReleaseFastLockShared
_Releases_shared_lock_(*FastLock)
PHLIBAPI
VOID
FASTCALL
PhfReleaseFastLockShared(
_Inout_ PPH_FAST_LOCK FastLock
);
#define PhTryAcquireFastLockExclusive PhfTryAcquireFastLockExclusive
_When_(return != 0, _Acquires_exclusive_lock_(*FastLock))
PHLIBAPI
BOOLEAN
FASTCALL
PhfTryAcquireFastLockExclusive(
_Inout_ PPH_FAST_LOCK FastLock
);
#define PhTryAcquireFastLockShared PhfTryAcquireFastLockShared
_When_(return != 0, _Acquires_shared_lock_(*FastLock))
PHLIBAPI
BOOLEAN
FASTCALL
PhfTryAcquireFastLockShared(
_Inout_ PPH_FAST_LOCK FastLock
);
#ifdef __cplusplus
}
#endif
#endif

196
phlib/include/filepool.h Normal file
View File

@@ -0,0 +1,196 @@
#ifndef _PH_FILEPOOL_H
#define _PH_FILEPOOL_H
#ifdef __cplusplus
extern "C" {
#endif
// On-disk structures
// Each file has at least one segment. Each segment has a number of blocks, which are allocated from
// a bitmap. The segment header is always in the first block of each segment, except for the first
// segment. In the first segment, the file header is in the first few blocks, followed by the
// segment header.
//
// The segments are placed in a particular free list depending on how many blocks they have free;
// this allows allocators to simply skip the segments which don't have enough segments free, and
// allocate new segments if necessary. The free list does not however guarantee that a particular
// segment has a particular number of contiguous blocks free; low performance can still occur when
// there is fragmentation.
/** The number of 32-bit integers used for each allocation bitmap. */
#define PH_FP_BITMAP_SIZE 64
/** The power-of-two index of the bitmap size. */
#define PH_FP_BITMAP_SIZE_SHIFT 6
/** The number of blocks that are available in each segment. */
#define PH_FP_BLOCK_COUNT (PH_FP_BITMAP_SIZE * 32)
/** The power-of-two index of the block count. */
#define PH_FP_BLOCK_COUNT_SHIFT (PH_FP_BITMAP_SIZE_SHIFT + 5)
/** The number of free lists for segments. */
#define PH_FP_FREE_LIST_COUNT 8
// Block flags
/** The block is the beginning of a large allocation (one that spans several segments). */
#define PH_FP_BLOCK_LARGE_ALLOCATION 0x1
typedef struct _PH_FP_BLOCK_HEADER
{
ULONG Flags; // PH_FP_BLOCK_*
/** The number of blocks in the entire logical block, or the number
* of segments in a large allocation. */
ULONG Span;
ULONGLONG Body;
} PH_FP_BLOCK_HEADER, *PPH_FP_BLOCK_HEADER;
typedef struct _PH_FP_SEGMENT_HEADER
{
ULONG Bitmap[PH_FP_BITMAP_SIZE];
ULONG FreeBlocks;
ULONG FreeFlink;
ULONG FreeBlink;
ULONG Reserved[13];
} PH_FP_SEGMENT_HEADER, *PPH_FP_SEGMENT_HEADER;
#define PH_FP_MAGIC ('loPF')
typedef struct _PH_FP_FILE_HEADER
{
ULONG Magic;
ULONG SegmentShift;
ULONG SegmentCount;
ULONGLONG UserContext;
ULONG FreeLists[PH_FP_FREE_LIST_COUNT];
} PH_FP_FILE_HEADER, *PPH_FP_FILE_HEADER;
// Runtime
typedef struct _PH_FILE_POOL_PARAMETERS
{
// File options
/**
* The base-2 logarithm of the size of each segment. This value must be between 16 and 28,
* inclusive.
*/
ULONG SegmentShift;
// Runtime options
/** The maximum number of inactive segments to keep mapped. */
ULONG MaximumInactiveViews;
} PH_FILE_POOL_PARAMETERS, *PPH_FILE_POOL_PARAMETERS;
typedef struct _PH_FILE_POOL
{
HANDLE FileHandle;
HANDLE SectionHandle;
BOOLEAN ReadOnly;
PH_FREE_LIST ViewFreeList;
PLIST_ENTRY *ByIndexBuckets;
ULONG ByIndexSize;
PH_AVL_TREE ByBaseSet;
ULONG MaximumInactiveViews;
ULONG NumberOfInactiveViews;
LIST_ENTRY InactiveViewsListHead;
PPH_FP_BLOCK_HEADER FirstBlockOfFirstSegment;
PPH_FP_FILE_HEADER Header;
ULONG SegmentShift; // The power-of-two size of each segment
ULONG SegmentSize; // The size of each segment
ULONG BlockShift; // The power-of-two size of each block in each segment
ULONG BlockSize; // The size of each block in each segment
ULONG FileHeaderBlockSpan; // The number of blocks needed to store a file header
ULONG SegmentHeaderBlockSpan; // The number of blocks needed to store a segment header
} PH_FILE_POOL, *PPH_FILE_POOL;
PHLIBAPI
NTSTATUS PhCreateFilePool(
_Out_ PPH_FILE_POOL *Pool,
_In_ HANDLE FileHandle,
_In_ BOOLEAN ReadOnly,
_In_opt_ PPH_FILE_POOL_PARAMETERS Parameters
);
PHLIBAPI
NTSTATUS PhCreateFilePool2(
_Out_ PPH_FILE_POOL *Pool,
_In_ PWSTR FileName,
_In_ BOOLEAN ReadOnly,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_opt_ PPH_FILE_POOL_PARAMETERS Parameters
);
PHLIBAPI
VOID PhDestroyFilePool(
_In_ _Post_invalid_ PPH_FILE_POOL Pool
);
PHLIBAPI
PVOID PhAllocateFilePool(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG Size,
_Out_opt_ PULONG Rva
);
PHLIBAPI
VOID PhFreeFilePool(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Block
);
PHLIBAPI
BOOLEAN PhFreeFilePoolByRva(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG Rva
);
PHLIBAPI
VOID PhReferenceFilePool(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Address
);
PHLIBAPI
VOID PhDereferenceFilePool(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Address
);
PHLIBAPI
PVOID PhReferenceFilePoolByRva(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG Rva
);
PHLIBAPI
BOOLEAN PhDereferenceFilePoolByRva(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG Rva
);
PHLIBAPI
ULONG PhEncodeRvaFilePool(
_In_ PPH_FILE_POOL Pool,
_In_ PVOID Address
);
PHLIBAPI
VOID PhGetUserContextFilePool(
_In_ PPH_FILE_POOL Pool,
_Out_ PULONGLONG Context
);
PHLIBAPI
VOID PhSetUserContextFilePool(
_Inout_ PPH_FILE_POOL Pool,
_In_ PULONGLONG Context
);
#ifdef __cplusplus
}
#endif
#endif

204
phlib/include/filepoolp.h Normal file
View File

@@ -0,0 +1,204 @@
#ifndef _PH_FILEPOOLP_H
#define _PH_FILEPOOLP_H
typedef struct _PH_FILE_POOL_VIEW
{
LIST_ENTRY ByIndexListEntry;
PH_AVL_LINKS ByBaseLinks;
LIST_ENTRY InactiveViewsListEntry;
ULONG RefCount;
ULONG SegmentIndex;
PVOID Base;
} PH_FILE_POOL_VIEW, *PPH_FILE_POOL_VIEW;
NTSTATUS PhpValidateFilePoolParameters(
_Inout_ PPH_FILE_POOL_PARAMETERS Parameters
);
VOID PhpSetDefaultFilePoolParameters(
_Out_ PPH_FILE_POOL_PARAMETERS Parameters
);
// Range mapping
NTSTATUS PhFppExtendRange(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG NewSize
);
NTSTATUS PhFppMapRange(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG Offset,
_In_ ULONG Size,
_Out_ PVOID *Base
);
NTSTATUS PhFppUnmapRange(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Base
);
// Segments
VOID PhFppInitializeSegment(
_Inout_ PPH_FILE_POOL Pool,
_Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader,
_In_ ULONG AdditionalBlocksUsed
);
PPH_FP_BLOCK_HEADER PhFppAllocateSegment(
_Inout_ PPH_FILE_POOL Pool,
_Out_ PULONG NewSegmentIndex
);
PPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment(
_Inout_ PPH_FILE_POOL Pool,
_In_ PPH_FP_BLOCK_HEADER FirstBlock
);
// Views
VOID PhFppAddViewByIndex(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
VOID PhFppRemoveViewByIndex(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
PPH_FILE_POOL_VIEW PhFppFindViewByIndex(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG SegmentIndex
);
LONG NTAPI PhpFilePoolViewByBaseCompareFunction(
_In_ PPH_AVL_LINKS Links1,
_In_ PPH_AVL_LINKS Links2
);
VOID PhFppAddViewByBase(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
VOID PhFppRemoveViewByBase(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
PPH_FILE_POOL_VIEW PhFppFindViewByBase(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Base
);
PPH_FILE_POOL_VIEW PhFppCreateView(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG SegmentIndex
);
VOID PhFppDestroyView(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
VOID PhFppActivateView(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
VOID PhFppDeactivateView(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
VOID PhFppReferenceView(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
VOID PhFppDereferenceView(
_Inout_ PPH_FILE_POOL Pool,
_Inout_ PPH_FILE_POOL_VIEW View
);
PPH_FP_BLOCK_HEADER PhFppReferenceSegment(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG SegmentIndex
);
VOID PhFppDereferenceSegment(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG SegmentIndex
);
VOID PhFppReferenceSegmentByBase(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Base
);
VOID PhFppDereferenceSegmentByBase(
_Inout_ PPH_FILE_POOL Pool,
_In_ PVOID Base
);
// Bitmap allocation
PPH_FP_BLOCK_HEADER PhFppAllocateBlocks(
_Inout_ PPH_FILE_POOL Pool,
_In_ PPH_FP_BLOCK_HEADER FirstBlock,
_Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,
_In_ ULONG NumberOfBlocks
);
VOID PhFppFreeBlocks(
_Inout_ PPH_FILE_POOL Pool,
_In_ PPH_FP_BLOCK_HEADER FirstBlock,
_Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader,
_In_ PPH_FP_BLOCK_HEADER BlockHeader
);
// Free list
ULONG PhFppComputeFreeListIndex(
_In_ PPH_FILE_POOL Pool,
_In_ ULONG NumberOfBlocks
);
BOOLEAN PhFppInsertFreeList(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG FreeListIndex,
_In_ ULONG SegmentIndex,
_In_ PPH_FP_SEGMENT_HEADER SegmentHeader
);
BOOLEAN PhFppRemoveFreeList(
_Inout_ PPH_FILE_POOL Pool,
_In_ ULONG FreeListIndex,
_In_ ULONG SegmentIndex,
_In_ PPH_FP_SEGMENT_HEADER SegmentHeader
);
// Misc.
PPH_FP_BLOCK_HEADER PhFppGetHeaderBlock(
_In_ PPH_FILE_POOL Pool,
_In_ PVOID Block
);
ULONG PhFppEncodeRva(
_In_ PPH_FILE_POOL Pool,
_In_ ULONG SegmentIndex,
_In_ PPH_FP_BLOCK_HEADER FirstBlock,
_In_ PVOID Address
);
ULONG PhFppDecodeRva(
_In_ PPH_FILE_POOL Pool,
_In_ ULONG Rva,
_Out_ PULONG SegmentIndex
);
#endif

204
phlib/include/filestream.h Normal file
View File

@@ -0,0 +1,204 @@
#ifndef _PH_FILESTREAM_H
#define _PH_FILESTREAM_H
#ifdef __cplusplus
extern "C" {
#endif
// Core flags (PhCreateFileStream2)
/** Indicates that the file stream object should not close the file handle upon deletion. */
#define PH_FILE_STREAM_HANDLE_UNOWNED 0x1
/**
* Indicates that the file stream object should not buffer I/O operations. Note that this does not
* prevent the operating system from buffering I/O.
*/
#define PH_FILE_STREAM_UNBUFFERED 0x2
/**
* Indicates that the file handle supports asynchronous operations. The file handle must not have
* been opened with FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT.
*/
#define PH_FILE_STREAM_ASYNCHRONOUS 0x4
/**
* Indicates that the file stream object should maintain the file position and not use the file
* object's own file position.
*/
#define PH_FILE_STREAM_OWN_POSITION 0x8
// Higher-level flags (PhCreateFileStream)
#define PH_FILE_STREAM_APPEND 0x00010000
// Internal flags
/** Indicates that at least one write has been issued to the file handle. */
#define PH_FILE_STREAM_WRITTEN 0x80000000
// Seek
typedef enum _PH_SEEK_ORIGIN
{
SeekStart,
SeekCurrent,
SeekEnd
} PH_SEEK_ORIGIN;
typedef struct _PH_FILE_STREAM
{
HANDLE FileHandle;
ULONG Flags;
LARGE_INTEGER Position; // file object position, *not* the actual position
PVOID Buffer;
ULONG BufferLength;
ULONG ReadPosition; // read position in buffer
ULONG ReadLength; // how much available to read from buffer
ULONG WritePosition; // write position in buffer
} PH_FILE_STREAM, *PPH_FILE_STREAM;
extern PPH_OBJECT_TYPE PhFileStreamType;
BOOLEAN
NTAPI
PhFileStreamInitialization(
VOID
);
PHLIBAPI
NTSTATUS
NTAPI
PhCreateFileStream(
_Out_ PPH_FILE_STREAM *FileStream,
_In_ PWSTR FileName,
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG ShareMode,
_In_ ULONG CreateDisposition,
_In_ ULONG Flags
);
PHLIBAPI
NTSTATUS
NTAPI
PhCreateFileStream2(
_Out_ PPH_FILE_STREAM *FileStream,
_In_ HANDLE FileHandle,
_In_ ULONG Flags,
_In_ ULONG BufferLength
);
PHLIBAPI
VOID
NTAPI
PhVerifyFileStream(
_In_ PPH_FILE_STREAM FileStream
);
PHLIBAPI
NTSTATUS
NTAPI
PhReadFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG ReadLength
);
PHLIBAPI
NTSTATUS
NTAPI
PhWriteFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length
);
PHLIBAPI
NTSTATUS
NTAPI
PhFlushFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ BOOLEAN Full
);
PHLIBAPI
VOID
NTAPI
PhGetPositionFileStream(
_In_ PPH_FILE_STREAM FileStream,
_Out_ PLARGE_INTEGER Position
);
PHLIBAPI
NTSTATUS
NTAPI
PhSeekFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Offset,
_In_ PH_SEEK_ORIGIN Origin
);
PHLIBAPI
NTSTATUS
NTAPI
PhLockFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Position,
_In_ PLARGE_INTEGER Length,
_In_ BOOLEAN Wait,
_In_ BOOLEAN Shared
);
PHLIBAPI
NTSTATUS
NTAPI
PhUnlockFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Position,
_In_ PLARGE_INTEGER Length
);
PHLIBAPI
NTSTATUS
NTAPI
PhWriteStringAsUtf8FileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PPH_STRINGREF String
);
PHLIBAPI
NTSTATUS
NTAPI
PhWriteStringAsUtf8FileStream2(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PWSTR String
);
PHLIBAPI
NTSTATUS
NTAPI
PhWriteStringAsUtf8FileStreamEx(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PWSTR Buffer,
_In_ SIZE_T Length
);
PHLIBAPI
NTSTATUS
NTAPI
PhWriteStringFormatAsUtf8FileStream_V(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ _Printf_format_string_ PWSTR Format,
_In_ va_list ArgPtr
);
PHLIBAPI
NTSTATUS
NTAPI
PhWriteStringFormatAsUtf8FileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ _Printf_format_string_ PWSTR Format,
...
);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,40 @@
#ifndef _PH_FILESTREAMP_H
#define _PH_FILESTREAMP_H
VOID NTAPI PhpFileStreamDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
);
NTSTATUS PhpAllocateBufferFileStream(
_Inout_ PPH_FILE_STREAM FileStream
);
NTSTATUS PhpReadFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG ReadLength
);
NTSTATUS PhpWriteFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length
);
NTSTATUS PhpFlushReadFileStream(
_Inout_ PPH_FILE_STREAM FileStream
);
NTSTATUS PhpFlushWriteFileStream(
_Inout_ PPH_FILE_STREAM FileStream
);
NTSTATUS PhpSeekFileStream(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ PLARGE_INTEGER Offset,
_In_ PH_SEEK_ORIGIN Origin
);
#endif

255
phlib/include/graph.h Normal file
View File

@@ -0,0 +1,255 @@
#ifndef _PH_GRAPH_H
#define _PH_GRAPH_H
#ifdef __cplusplus
extern "C" {
#endif
// Graph drawing
extern RECT PhNormalGraphTextMargin;
extern RECT PhNormalGraphTextPadding;
#define PH_GRAPH_USE_GRID_X 0x1
#define PH_GRAPH_USE_GRID_Y 0x2
#define PH_GRAPH_LOGARITHMIC_GRID_Y 0x4
#define PH_GRAPH_USE_LINE_2 0x10
#define PH_GRAPH_OVERLAY_LINE_2 0x20
#define PH_GRAPH_LABEL_MAX_Y 0x1000
typedef PPH_STRING (NTAPI *PPH_GRAPH_LABEL_Y_FUNCTION)(
_In_ struct _PH_GRAPH_DRAW_INFO *DrawInfo,
_In_ ULONG DataIndex,
_In_ FLOAT Value,
_In_ FLOAT Parameter
);
typedef struct _PH_GRAPH_DRAW_INFO
{
// Basic
ULONG Width;
ULONG Height;
ULONG Flags;
ULONG Step;
COLORREF BackColor;
// Data/lines
ULONG LineDataCount;
PFLOAT LineData1;
PFLOAT LineData2;
COLORREF LineColor1;
COLORREF LineColor2;
COLORREF LineBackColor1;
COLORREF LineBackColor2;
// Grid
COLORREF GridColor;
ULONG GridWidth;
FLOAT GridHeight;
ULONG GridXOffset;
ULONG GridYThreshold;
FLOAT GridBase; // Base for logarithmic grid
// y-axis label
PPH_GRAPH_LABEL_Y_FUNCTION LabelYFunction;
FLOAT LabelYFunctionParameter;
HFONT LabelYFont;
COLORREF LabelYColor;
ULONG LabelMaxYIndexLimit;
// Text
PH_STRINGREF Text;
RECT TextRect;
RECT TextBoxRect;
HFONT TextFont;
COLORREF TextColor;
COLORREF TextBoxColor;
} PH_GRAPH_DRAW_INFO, *PPH_GRAPH_DRAW_INFO;
// Graph control
#define PH_GRAPH_CLASSNAME L"PhGraph"
PHLIBAPI
BOOLEAN PhGraphControlInitialization(
VOID
);
PHLIBAPI
VOID PhDrawGraphDirect(
_In_ HDC hdc,
_In_ PVOID Bits,
_In_ PPH_GRAPH_DRAW_INFO DrawInfo
);
PHLIBAPI
VOID PhSetGraphText(
_In_ HDC hdc,
_Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,
_In_ PPH_STRINGREF Text,
_In_ PRECT Margin,
_In_ PRECT Padding,
_In_ ULONG Align
);
// Configuration
typedef struct _PH_GRAPH_OPTIONS
{
COLORREF FadeOutBackColor;
ULONG FadeOutWidth;
HCURSOR DefaultCursor;
} PH_GRAPH_OPTIONS, *PPH_GRAPH_OPTIONS;
// Styles
#define GC_STYLE_FADEOUT 0x1
#define GC_STYLE_DRAW_PANEL 0x2
// Messages
#define GCM_GETDRAWINFO (WM_USER + 1301)
#define GCM_SETDRAWINFO (WM_USER + 1302)
#define GCM_DRAW (WM_USER + 1303)
#define GCM_MOVEGRID (WM_USER + 1304)
#define GCM_GETBUFFEREDCONTEXT (WM_USER + 1305)
#define GCM_SETTOOLTIP (WM_USER + 1306)
#define GCM_UPDATETOOLTIP (WM_USER + 1307)
#define GCM_GETOPTIONS (WM_USER + 1308)
#define GCM_SETOPTIONS (WM_USER + 1309)
#define Graph_GetDrawInfo(hWnd, DrawInfo) \
SendMessage((hWnd), GCM_GETDRAWINFO, 0, (LPARAM)(DrawInfo))
#define Graph_SetDrawInfo(hWnd, DrawInfo) \
SendMessage((hWnd), GCM_SETDRAWINFO, 0, (LPARAM)(DrawInfo))
#define Graph_Draw(hWnd) \
SendMessage((hWnd), GCM_DRAW, 0, 0)
#define Graph_MoveGrid(hWnd, Increment) \
SendMessage((hWnd), GCM_MOVEGRID, (WPARAM)(Increment), 0)
#define Graph_GetBufferedContext(hWnd) \
((HDC)SendMessage((hWnd), GCM_GETBUFFEREDCONTEXT, 0, 0))
#define Graph_SetTooltip(hWnd, Enable) \
((HDC)SendMessage((hWnd), GCM_SETTOOLTIP, (WPARAM)(Enable), 0))
#define Graph_UpdateTooltip(hWnd) \
((HDC)SendMessage((hWnd), GCM_UPDATETOOLTIP, 0, 0))
#define Graph_GetOptions(hWnd, Options) \
SendMessage((hWnd), GCM_GETOPTIONS, 0, (LPARAM)(Options))
#define Graph_SetOptions(hWnd, Options) \
SendMessage((hWnd), GCM_SETOPTIONS, 0, (LPARAM)(Options))
// Notifications
#define GCN_GETDRAWINFO (WM_USER + 1351)
#define GCN_GETTOOLTIPTEXT (WM_USER + 1352)
#define GCN_MOUSEEVENT (WM_USER + 1353)
#define GCN_DRAWPANEL (WM_USER + 1354)
typedef struct _PH_GRAPH_GETDRAWINFO
{
NMHDR Header;
PPH_GRAPH_DRAW_INFO DrawInfo;
} PH_GRAPH_GETDRAWINFO, *PPH_GRAPH_GETDRAWINFO;
typedef struct _PH_GRAPH_GETTOOLTIPTEXT
{
NMHDR Header;
ULONG Index;
ULONG TotalCount;
PH_STRINGREF Text; // must be null-terminated
} PH_GRAPH_GETTOOLTIPTEXT, *PPH_GRAPH_GETTOOLTIPTEXT;
typedef struct _PH_GRAPH_MOUSEEVENT
{
NMHDR Header;
ULONG Index;
ULONG TotalCount;
ULONG Message;
ULONG Keys;
POINT Point;
} PH_GRAPH_MOUSEEVENT, *PPH_GRAPH_MOUSEEVENT;
typedef struct _PH_GRAPH_DRAWPANEL
{
NMHDR Header;
HDC hdc;
RECT Rect;
} PH_GRAPH_DRAWPANEL, *PPH_GRAPH_DRAWPANEL;
// Graph buffer management
#define PH_GRAPH_DATA_COUNT(Width, Step) (((Width) + (Step) - 1) / (Step) + 1) // round up in division
typedef struct _PH_GRAPH_BUFFERS
{
PFLOAT Data1; // invalidate by setting Valid to FALSE
PFLOAT Data2; // invalidate by setting Valid to FALSE
ULONG AllocatedCount;
BOOLEAN Valid; // indicates the data is valid
} PH_GRAPH_BUFFERS, *PPH_GRAPH_BUFFERS;
PHLIBAPI
VOID PhInitializeGraphBuffers(
_Out_ PPH_GRAPH_BUFFERS Buffers
);
PHLIBAPI
VOID PhDeleteGraphBuffers(
_Inout_ PPH_GRAPH_BUFFERS Buffers
);
PHLIBAPI
VOID PhGetDrawInfoGraphBuffers(
_Inout_ PPH_GRAPH_BUFFERS Buffers,
_Inout_ PPH_GRAPH_DRAW_INFO DrawInfo,
_In_ ULONG DataCount
);
// Graph control state
// The basic buffer management structure was moved out of this section because
// the text management is not needed for most cases.
typedef struct _PH_GRAPH_STATE
{
// Union for compatibility
union
{
struct
{
PFLOAT Data1; // invalidate by setting Valid to FALSE
PFLOAT Data2; // invalidate by setting Valid to FALSE
ULONG AllocatedCount;
BOOLEAN Valid; // indicates the data is valid
};
PH_GRAPH_BUFFERS Buffers;
};
PPH_STRING Text;
PPH_STRING TooltipText; // invalidate by setting TooltipIndex to -1
ULONG TooltipIndex; // indicates the tooltip text is valid for this index
} PH_GRAPH_STATE, *PPH_GRAPH_STATE;
PHLIBAPI
VOID PhInitializeGraphState(
_Out_ PPH_GRAPH_STATE State
);
PHLIBAPI
VOID PhDeleteGraphState(
_Inout_ PPH_GRAPH_STATE State
);
PHLIBAPI
VOID PhGraphStateGetDrawInfo(
_Inout_ PPH_GRAPH_STATE State,
_In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo,
_In_ ULONG DataCount
);
#ifdef __cplusplus
}
#endif
#endif

723
phlib/include/guisup.h Normal file
View File

@@ -0,0 +1,723 @@
#ifndef _PH_PHGUI_H
#define _PH_PHGUI_H
#pragma once
#include <commctrl.h>
#ifdef __cplusplus
extern "C" {
#endif
// guisup
typedef BOOL (WINAPI *_ChangeWindowMessageFilter)(
_In_ UINT message,
_In_ DWORD dwFlag
);
typedef BOOL (WINAPI *_IsImmersiveProcess)(
_In_ HANDLE hProcess
);
#define RFF_NOBROWSE 0x0001
#define RFF_NODEFAULT 0x0002
#define RFF_CALCDIRECTORY 0x0004
#define RFF_NOLABEL 0x0008
#define RFF_NOSEPARATEMEM 0x0020
#define RFN_VALIDATE (-510)
typedef struct _NMRUNFILEDLGW
{
NMHDR hdr;
LPCWSTR lpszFile;
LPCWSTR lpszDirectory;
UINT nShow;
} NMRUNFILEDLGW, *LPNMRUNFILEDLGW, *PNMRUNFILEDLGW;
typedef NMRUNFILEDLGW NMRUNFILEDLG;
typedef PNMRUNFILEDLGW PNMRUNFILEDLG;
typedef LPNMRUNFILEDLGW LPNMRUNFILEDLG;
#define RF_OK 0x0000
#define RF_CANCEL 0x0001
#define RF_RETRY 0x0002
typedef HANDLE HTHEME;
typedef BOOL (WINAPI *_RunFileDlg)(
_In_ HWND hwndOwner,
_In_opt_ HICON hIcon,
_In_opt_ LPCWSTR lpszDirectory,
_In_opt_ LPCWSTR lpszTitle,
_In_opt_ LPCWSTR lpszDescription,
_In_ ULONG uFlags
);
typedef HRESULT (WINAPI *_SHAutoComplete)(
_In_ HWND hwndEdit,
_In_ DWORD dwFlags
);
extern _ChangeWindowMessageFilter ChangeWindowMessageFilter_I;
extern _IsImmersiveProcess IsImmersiveProcess_I;
extern _RunFileDlg RunFileDlg;
extern _SHAutoComplete SHAutoComplete_I;
PHLIBAPI
VOID PhGuiSupportInitialization(
VOID
);
PHLIBAPI
VOID PhSetControlTheme(
_In_ HWND Handle,
_In_ PWSTR Theme
);
FORCEINLINE VOID PhSetWindowStyle(
_In_ HWND Handle,
_In_ LONG_PTR Mask,
_In_ LONG_PTR Value
)
{
LONG_PTR style;
style = GetWindowLongPtr(Handle, GWL_STYLE);
style = (style & ~Mask) | (Value & Mask);
SetWindowLongPtr(Handle, GWL_STYLE, style);
}
FORCEINLINE VOID PhSetWindowExStyle(
_In_ HWND Handle,
_In_ LONG_PTR Mask,
_In_ LONG_PTR Value
)
{
LONG_PTR style;
style = GetWindowLongPtr(Handle, GWL_EXSTYLE);
style = (style & ~Mask) | (Value & Mask);
SetWindowLongPtr(Handle, GWL_EXSTYLE, style);
}
#ifndef WM_REFLECT
#define WM_REFLECT 0x2000
#endif
#define REFLECT_MESSAGE(hwnd, msg, wParam, lParam) \
{ \
LRESULT result_ = PhReflectMessage(hwnd, msg, wParam, lParam); \
\
if (result_) \
return result_; \
}
#define REFLECT_MESSAGE_DLG(hwndDlg, hwnd, msg, wParam, lParam) \
{ \
LRESULT result_ = PhReflectMessage(hwnd, msg, wParam, lParam); \
\
if (result_) \
{ \
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result_); \
return TRUE; \
} \
}
FORCEINLINE LRESULT PhReflectMessage(
_In_ HWND Handle,
_In_ UINT Message,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (Message == WM_NOTIFY)
{
LPNMHDR header = (LPNMHDR)lParam;
if (header->hwndFrom == Handle)
return SendMessage(Handle, WM_REFLECT + Message, wParam, lParam);
}
return 0;
}
#define PH_DEFINE_MAKE_ATOM(AtomName) \
do { \
static UNICODE_STRING atomName = RTL_CONSTANT_STRING(AtomName); \
static PH_INITONCE initOnce = PH_INITONCE_INIT; \
static RTL_ATOM atom = 0; \
\
if (PhBeginInitOnce(&initOnce)) \
{ \
NtAddAtom(atomName.Buffer, atomName.Length, &atom); \
PhEndInitOnce(&initOnce); \
} \
\
if (atom) \
return (PWSTR)(ULONG_PTR)atom; \
else \
return atomName.Buffer; \
} while (0)
FORCEINLINE VOID PhSetListViewStyle(
_In_ HWND Handle,
_In_ BOOLEAN AllowDragDrop,
_In_ BOOLEAN ShowLabelTips
)
{
ULONG style;
style = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;
if (AllowDragDrop)
style |= LVS_EX_HEADERDRAGDROP;
if (ShowLabelTips)
style |= LVS_EX_LABELTIP;
ListView_SetExtendedListViewStyleEx(
Handle,
style,
-1
);
}
PHLIBAPI
INT PhAddListViewColumn(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ INT DisplayIndex,
_In_ INT SubItemIndex,
_In_ INT Format,
_In_ INT Width,
_In_ PWSTR Text
);
PHLIBAPI
INT PhAddListViewItem(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ PWSTR Text,
_In_opt_ PVOID Param
);
PHLIBAPI
INT PhFindListViewItemByFlags(
_In_ HWND ListViewHandle,
_In_ INT StartIndex,
_In_ ULONG Flags
);
PHLIBAPI
INT PhFindListViewItemByParam(
_In_ HWND ListViewHandle,
_In_ INT StartIndex,
_In_opt_ PVOID Param
);
PHLIBAPI
LOGICAL PhGetListViewItemImageIndex(
_In_ HWND ListViewHandle,
_In_ INT Index,
_Out_ PINT ImageIndex
);
PHLIBAPI
LOGICAL PhGetListViewItemParam(
_In_ HWND ListViewHandle,
_In_ INT Index,
_Out_ PVOID *Param
);
PHLIBAPI
VOID PhRemoveListViewItem(
_In_ HWND ListViewHandle,
_In_ INT Index
);
PHLIBAPI
VOID PhSetListViewItemImageIndex(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ INT ImageIndex
);
PHLIBAPI
VOID PhSetListViewSubItem(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ INT SubItemIndex,
_In_ PWSTR Text
);
PHLIBAPI
BOOLEAN PhLoadListViewColumnSettings(
_In_ HWND ListViewHandle,
_In_ PPH_STRING Settings
);
PHLIBAPI
PPH_STRING PhSaveListViewColumnSettings(
_In_ HWND ListViewHandle
);
PHLIBAPI
INT PhAddTabControlTab(
_In_ HWND TabControlHandle,
_In_ INT Index,
_In_ PWSTR Text
);
#define PhaGetDlgItemText(hwndDlg, id) \
PH_AUTO_T(PH_STRING, PhGetWindowText(GetDlgItem(hwndDlg, id)))
PHLIBAPI
PPH_STRING PhGetWindowText(
_In_ HWND hwnd
);
#define PH_GET_WINDOW_TEXT_INTERNAL 0x1
#define PH_GET_WINDOW_TEXT_LENGTH_ONLY 0x2
PHLIBAPI
ULONG PhGetWindowTextEx(
_In_ HWND hwnd,
_In_ ULONG Flags,
_Out_opt_ PPH_STRING *Text
);
PHLIBAPI
VOID PhAddComboBoxStrings(
_In_ HWND hWnd,
_In_ PWSTR *Strings,
_In_ ULONG NumberOfStrings
);
PHLIBAPI
PPH_STRING PhGetComboBoxString(
_In_ HWND hwnd,
_In_ INT Index
);
PHLIBAPI
INT PhSelectComboBoxString(
_In_ HWND hwnd,
_In_ PWSTR String,
_In_ BOOLEAN Partial
);
PHLIBAPI
PPH_STRING PhGetListBoxString(
_In_ HWND hwnd,
_In_ INT Index
);
PHLIBAPI
VOID PhSetStateAllListViewItems(
_In_ HWND hWnd,
_In_ ULONG State,
_In_ ULONG Mask
);
PHLIBAPI
PVOID PhGetSelectedListViewItemParam(
_In_ HWND hWnd
);
PHLIBAPI
VOID PhGetSelectedListViewItemParams(
_In_ HWND hWnd,
_Out_ PVOID **Items,
_Out_ PULONG NumberOfItems
);
PHLIBAPI
VOID PhSetImageListBitmap(
_In_ HIMAGELIST ImageList,
_In_ INT Index,
_In_ HINSTANCE InstanceHandle,
_In_ LPCWSTR BitmapName
);
#define PH_LOAD_ICON_SHARED 0x1
#define PH_LOAD_ICON_SIZE_SMALL 0x2
#define PH_LOAD_ICON_SIZE_LARGE 0x4
#define PH_LOAD_ICON_STRICT 0x8
PHLIBAPI
HICON PhLoadIcon(
_In_opt_ HINSTANCE InstanceHandle,
_In_ PWSTR Name,
_In_ ULONG Flags,
_In_opt_ ULONG Width,
_In_opt_ ULONG Height
);
PHLIBAPI
VOID PhGetStockApplicationIcon(
_Out_opt_ HICON *SmallIcon,
_Out_opt_ HICON *LargeIcon
);
PHLIBAPI
HICON PhGetFileShellIcon(
_In_opt_ PWSTR FileName,
_In_opt_ PWSTR DefaultExtension,
_In_ BOOLEAN LargeIcon
);
PHLIBAPI
VOID PhSetClipboardString(
_In_ HWND hWnd,
_In_ PPH_STRINGREF String
);
typedef struct _DLGTEMPLATEEX
{
WORD dlgVer;
WORD signature;
DWORD helpID;
DWORD exStyle;
DWORD style;
WORD cDlgItems;
short x;
short y;
short cx;
short cy;
} DLGTEMPLATEEX, *PDLGTEMPLATEEX;
PHLIBAPI
HWND PhCreateDialogFromTemplate(
_In_ HWND Parent,
_In_ ULONG Style,
_In_ PVOID Instance,
_In_ PWSTR Template,
_In_ DLGPROC DialogProc,
_In_ PVOID Parameter
);
PHLIBAPI
BOOLEAN PhModalPropertySheet(
_Inout_ PROPSHEETHEADER *Header
);
#define PH_ANCHOR_LEFT 0x1
#define PH_ANCHOR_TOP 0x2
#define PH_ANCHOR_RIGHT 0x4
#define PH_ANCHOR_BOTTOM 0x8
#define PH_ANCHOR_ALL 0xf
// This interface is horrible and should be rewritten, but it works for now.
#define PH_LAYOUT_FORCE_INVALIDATE 0x1000 // invalidate the control when it is resized
#define PH_LAYOUT_TAB_CONTROL 0x2000 // this is a dummy item, a hack for the tab control
#define PH_LAYOUT_IMMEDIATE_RESIZE 0x4000 // needed for the tab control hack
#define PH_LAYOUT_DUMMY_MASK (PH_LAYOUT_TAB_CONTROL) // items that don't have a window handle, or don't actually get their window resized
typedef struct _PH_LAYOUT_ITEM
{
HWND Handle;
struct _PH_LAYOUT_ITEM *ParentItem; // for rectangle calculation
struct _PH_LAYOUT_ITEM *LayoutParentItem; // for actual resizing
ULONG LayoutNumber;
ULONG NumberOfChildren;
HDWP DeferHandle;
RECT Rect;
RECT OrigRect;
RECT Margin;
ULONG Anchor;
} PH_LAYOUT_ITEM, *PPH_LAYOUT_ITEM;
typedef struct _PH_LAYOUT_MANAGER
{
PPH_LIST List;
PH_LAYOUT_ITEM RootItem;
ULONG LayoutNumber;
} PH_LAYOUT_MANAGER, *PPH_LAYOUT_MANAGER;
PHLIBAPI
VOID PhInitializeLayoutManager(
_Out_ PPH_LAYOUT_MANAGER Manager,
_In_ HWND RootWindowHandle
);
PHLIBAPI
VOID PhDeleteLayoutManager(
_Inout_ PPH_LAYOUT_MANAGER Manager
);
PHLIBAPI
PPH_LAYOUT_ITEM PhAddLayoutItem(
_Inout_ PPH_LAYOUT_MANAGER Manager,
_In_ HWND Handle,
_In_opt_ PPH_LAYOUT_ITEM ParentItem,
_In_ ULONG Anchor
);
PHLIBAPI
PPH_LAYOUT_ITEM PhAddLayoutItemEx(
_Inout_ PPH_LAYOUT_MANAGER Manager,
_In_ HWND Handle,
_In_opt_ PPH_LAYOUT_ITEM ParentItem,
_In_ ULONG Anchor,
_In_ RECT Margin
);
PHLIBAPI
VOID PhLayoutManagerLayout(
_Inout_ PPH_LAYOUT_MANAGER Manager
);
FORCEINLINE VOID PhResizingMinimumSize(
_Inout_ PRECT Rect,
_In_ WPARAM Edge,
_In_ LONG MinimumWidth,
_In_ LONG MinimumHeight
)
{
if (Edge == WMSZ_BOTTOMRIGHT || Edge == WMSZ_RIGHT || Edge == WMSZ_TOPRIGHT)
{
if (Rect->right - Rect->left < MinimumWidth)
Rect->right = Rect->left + MinimumWidth;
}
else if (Edge == WMSZ_BOTTOMLEFT || Edge == WMSZ_LEFT || Edge == WMSZ_TOPLEFT)
{
if (Rect->right - Rect->left < MinimumWidth)
Rect->left = Rect->right - MinimumWidth;
}
if (Edge == WMSZ_BOTTOMRIGHT || Edge == WMSZ_BOTTOM || Edge == WMSZ_BOTTOMLEFT)
{
if (Rect->bottom - Rect->top < MinimumHeight)
Rect->bottom = Rect->top + MinimumHeight;
}
else if (Edge == WMSZ_TOPRIGHT || Edge == WMSZ_TOP || Edge == WMSZ_TOPLEFT)
{
if (Rect->bottom - Rect->top < MinimumHeight)
Rect->top = Rect->bottom - MinimumHeight;
}
}
FORCEINLINE VOID PhCopyControlRectangle(
_In_ HWND ParentWindowHandle,
_In_ HWND FromControlHandle,
_In_ HWND ToControlHandle
)
{
RECT windowRect;
GetWindowRect(FromControlHandle, &windowRect);
MapWindowPoints(NULL, ParentWindowHandle, (POINT *)&windowRect, 2);
MoveWindow(ToControlHandle, windowRect.left, windowRect.top,
windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE);
}
// icotobmp
PHLIBAPI
HBITMAP
NTAPI
PhIconToBitmap(
_In_ HICON Icon,
_In_ ULONG Width,
_In_ ULONG Height
);
// extlv
#define PH_ALIGN_CENTER 0x0
#define PH_ALIGN_LEFT 0x1
#define PH_ALIGN_RIGHT 0x2
#define PH_ALIGN_TOP 0x4
#define PH_ALIGN_BOTTOM 0x8
typedef enum _PH_ITEM_STATE
{
// The item is normal. Use the ItemColorFunction to determine the color of the item.
NormalItemState = 0,
// The item is new. On the next tick, change the state to NormalItemState. When an item is in
// this state, highlight it in NewColor.
NewItemState,
// The item is being removed. On the next tick, delete the item. When an item is in this state,
// highlight it in RemovingColor.
RemovingItemState
} PH_ITEM_STATE;
typedef COLORREF (NTAPI *PPH_EXTLV_GET_ITEM_COLOR)(
_In_ INT Index,
_In_ PVOID Param,
_In_opt_ PVOID Context
);
typedef HFONT (NTAPI *PPH_EXTLV_GET_ITEM_FONT)(
_In_ INT Index,
_In_ PVOID Param,
_In_opt_ PVOID Context
);
PHLIBAPI
VOID
NTAPI
PhSetExtendedListView(
_In_ HWND hWnd
);
PHLIBAPI
VOID
NTAPI
PhSetHeaderSortIcon(
_In_ HWND hwnd,
_In_ INT Index,
_In_ PH_SORT_ORDER Order
);
// next 1122
#define ELVM_ADDFALLBACKCOLUMN (WM_APP + 1106)
#define ELVM_ADDFALLBACKCOLUMNS (WM_APP + 1109)
#define ELVM_RESERVED5 (WM_APP + 1120)
#define ELVM_INIT (WM_APP + 1102)
#define ELVM_SETCOLUMNWIDTH (WM_APP + 1121)
#define ELVM_SETCOMPAREFUNCTION (WM_APP + 1104)
#define ELVM_SETCONTEXT (WM_APP + 1103)
#define ELVM_SETCURSOR (WM_APP + 1114)
#define ELVM_RESERVED4 (WM_APP + 1118)
#define ELVM_SETITEMCOLORFUNCTION (WM_APP + 1111)
#define ELVM_SETITEMFONTFUNCTION (WM_APP + 1117)
#define ELVM_RESERVED1 (WM_APP + 1112)
#define ELVM_SETREDRAW (WM_APP + 1116)
#define ELVM_RESERVED2 (WM_APP + 1113)
#define ELVM_SETSORT (WM_APP + 1108)
#define ELVM_SETSORTFAST (WM_APP + 1119)
#define ELVM_RESERVED0 (WM_APP + 1110)
#define ELVM_SETTRISTATE (WM_APP + 1107)
#define ELVM_SETTRISTATECOMPAREFUNCTION (WM_APP + 1105)
#define ELVM_SORTITEMS (WM_APP + 1101)
#define ELVM_RESERVED3 (WM_APP + 1115)
#define ExtendedListView_AddFallbackColumn(hWnd, Column) \
SendMessage((hWnd), ELVM_ADDFALLBACKCOLUMN, (WPARAM)(Column), 0)
#define ExtendedListView_AddFallbackColumns(hWnd, NumberOfColumns, Columns) \
SendMessage((hWnd), ELVM_ADDFALLBACKCOLUMNS, (WPARAM)(NumberOfColumns), (LPARAM)(Columns))
#define ExtendedListView_Init(hWnd) \
SendMessage((hWnd), ELVM_INIT, 0, 0)
#define ExtendedListView_SetColumnWidth(hWnd, Column, Width) \
SendMessage((hWnd), ELVM_SETCOLUMNWIDTH, (WPARAM)(Column), (LPARAM)(Width))
#define ExtendedListView_SetCompareFunction(hWnd, Column, CompareFunction) \
SendMessage((hWnd), ELVM_SETCOMPAREFUNCTION, (WPARAM)(Column), (LPARAM)(CompareFunction))
#define ExtendedListView_SetContext(hWnd, Context) \
SendMessage((hWnd), ELVM_SETCONTEXT, 0, (LPARAM)(Context))
#define ExtendedListView_SetCursor(hWnd, Cursor) \
SendMessage((hWnd), ELVM_SETCURSOR, 0, (LPARAM)(Cursor))
#define ExtendedListView_SetItemColorFunction(hWnd, ItemColorFunction) \
SendMessage((hWnd), ELVM_SETITEMCOLORFUNCTION, 0, (LPARAM)(ItemColorFunction))
#define ExtendedListView_SetItemFontFunction(hWnd, ItemFontFunction) \
SendMessage((hWnd), ELVM_SETITEMFONTFUNCTION, 0, (LPARAM)(ItemFontFunction))
#define ExtendedListView_SetRedraw(hWnd, Redraw) \
SendMessage((hWnd), ELVM_SETREDRAW, (WPARAM)(Redraw), 0)
#define ExtendedListView_SetSort(hWnd, Column, Order) \
SendMessage((hWnd), ELVM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))
#define ExtendedListView_SetSortFast(hWnd, Fast) \
SendMessage((hWnd), ELVM_SETSORTFAST, (WPARAM)(Fast), 0)
#define ExtendedListView_SetTriState(hWnd, TriState) \
SendMessage((hWnd), ELVM_SETTRISTATE, (WPARAM)(TriState), 0)
#define ExtendedListView_SetTriStateCompareFunction(hWnd, CompareFunction) \
SendMessage((hWnd), ELVM_SETTRISTATECOMPAREFUNCTION, 0, (LPARAM)(CompareFunction))
#define ExtendedListView_SortItems(hWnd) \
SendMessage((hWnd), ELVM_SORTITEMS, 0, 0)
#define ELVSCW_AUTOSIZE (-1)
#define ELVSCW_AUTOSIZE_USEHEADER (-2)
#define ELVSCW_AUTOSIZE_REMAININGSPACE (-3)
/**
* Gets the brightness of a color.
*
* \param Color The color.
*
* \return A value ranging from 0 to 255, indicating the brightness of the color.
*/
FORCEINLINE
ULONG
PhGetColorBrightness(
_In_ COLORREF Color
)
{
ULONG r = Color & 0xff;
ULONG g = (Color >> 8) & 0xff;
ULONG b = (Color >> 16) & 0xff;
ULONG min;
ULONG max;
min = r;
if (g < min) min = g;
if (b < min) min = b;
max = r;
if (g > max) max = g;
if (b > max) max = b;
return (min + max) / 2;
}
FORCEINLINE
COLORREF
PhHalveColorBrightness(
_In_ COLORREF Color
)
{
/*return RGB(
(UCHAR)Color / 2,
(UCHAR)(Color >> 8) / 2,
(UCHAR)(Color >> 16) / 2
);*/
// Since all targets are little-endian, we can use the following method.
*((PUCHAR)&Color) /= 2;
*((PUCHAR)&Color + 1) /= 2;
*((PUCHAR)&Color + 2) /= 2;
return Color;
}
FORCEINLINE
COLORREF
PhMakeColorBrighter(
_In_ COLORREF Color,
_In_ UCHAR Increment
)
{
UCHAR r;
UCHAR g;
UCHAR b;
r = (UCHAR)Color;
g = (UCHAR)(Color >> 8);
b = (UCHAR)(Color >> 16);
if (r <= 255 - Increment)
r += Increment;
else
r = 255;
if (g <= 255 - Increment)
g += Increment;
else
g = 255;
if (b <= 255 - Increment)
b += Increment;
else
b = 255;
return RGB(r, g, b);
}
#ifdef __cplusplus
}
#endif
#endif

43
phlib/include/guisupp.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef _PH_GUISUPP_H
#define _PH_GUISUPP_H
typedef HRESULT (WINAPI *_LoadIconMetric)(
_In_ HINSTANCE hinst,
_In_ PCWSTR pszName,
_In_ int lims,
_Out_ HICON *phico
);
typedef HRESULT (WINAPI *_LoadIconWithScaleDown)(
_In_ HINSTANCE hinst,
_In_ PCWSTR pszName,
_In_ int cx,
_In_ int cy,
_Out_ HICON *phico
);
typedef struct _PHP_ICON_ENTRY
{
HINSTANCE InstanceHandle;
PWSTR Name;
ULONG Width;
ULONG Height;
HICON Icon;
} PHP_ICON_ENTRY, *PPHP_ICON_ENTRY;
#define PHP_ICON_ENTRY_SIZE_SMALL (-1)
#define PHP_ICON_ENTRY_SIZE_LARGE (-2)
FORCEINLINE ULONG PhpGetIconEntrySize(
_In_ ULONG InputSize,
_In_ ULONG Flags
)
{
if (Flags & PH_LOAD_ICON_SIZE_SMALL)
return PHP_ICON_ENTRY_SIZE_SMALL;
if (Flags & PH_LOAD_ICON_SIZE_LARGE)
return PHP_ICON_ENTRY_SIZE_LARGE;
return InputSize;
}
#endif

167
phlib/include/handle.h Normal file
View File

@@ -0,0 +1,167 @@
#ifndef _PH_HANDLE_H
#define _PH_HANDLE_H
#ifdef __cplusplus
extern "C" {
#endif
struct _PH_HANDLE_TABLE;
typedef struct _PH_HANDLE_TABLE *PPH_HANDLE_TABLE;
typedef struct _PH_HANDLE_TABLE_ENTRY
{
union
{
PVOID Object;
ULONG_PTR Value;
struct
{
/** The type of the entry; 1 if the entry is free, otherwise 0 if the entry is in use. */
ULONG_PTR Type : 1;
/**
* Whether the entry is not locked; 1 if the entry is not locked, otherwise 0 if the
* entry is locked.
*/
ULONG_PTR Locked : 1;
ULONG_PTR Value : sizeof(ULONG_PTR) * 8 - 2;
} TypeAndValue;
};
union
{
ACCESS_MASK GrantedAccess;
ULONG NextFreeValue;
ULONG_PTR Value2;
};
} PH_HANDLE_TABLE_ENTRY, *PPH_HANDLE_TABLE_ENTRY;
#define PH_HANDLE_TABLE_SAFE
#define PH_HANDLE_TABLE_FREE_COUNT 64
#define PH_HANDLE_TABLE_STRICT_FIFO 0x1
#define PH_HANDLE_TABLE_VALID_FLAGS 0x1
PHLIBAPI
PPH_HANDLE_TABLE
NTAPI
PhCreateHandleTable(
VOID
);
PHLIBAPI
VOID
NTAPI
PhDestroyHandleTable(
_In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable
);
PHLIBAPI
BOOLEAN
NTAPI
PhLockHandleTableEntry(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry
);
PHLIBAPI
VOID
NTAPI
PhUnlockHandleTableEntry(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry
);
PHLIBAPI
HANDLE
NTAPI
PhCreateHandle(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry
);
PHLIBAPI
BOOLEAN
NTAPI
PhDestroyHandle(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ HANDLE Handle,
_In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry
);
PHLIBAPI
PPH_HANDLE_TABLE_ENTRY
NTAPI
PhLookupHandleTableEntry(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ HANDLE Handle
);
typedef BOOLEAN (NTAPI *PPH_ENUM_HANDLE_TABLE_CALLBACK)(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ HANDLE Handle,
_In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry,
_In_opt_ PVOID Context
);
PHLIBAPI
VOID
NTAPI
PhEnumHandleTable(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,
_In_opt_ PVOID Context
);
PHLIBAPI
VOID
NTAPI
PhSweepHandleTable(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback,
_In_opt_ PVOID Context
);
typedef enum _PH_HANDLE_TABLE_INFORMATION_CLASS
{
HandleTableBasicInformation,
HandleTableFlagsInformation,
MaxHandleTableInfoClass
} PH_HANDLE_TABLE_INFORMATION_CLASS;
typedef struct _PH_HANDLE_TABLE_BASIC_INFORMATION
{
ULONG Count;
ULONG Flags;
ULONG TableLevel;
} PH_HANDLE_TABLE_BASIC_INFORMATION, *PPH_HANDLE_TABLE_BASIC_INFORMATION;
typedef struct _PH_HANDLE_TABLE_FLAGS_INFORMATION
{
ULONG Flags;
} PH_HANDLE_TABLE_FLAGS_INFORMATION, *PPH_HANDLE_TABLE_FLAGS_INFORMATION;
PHLIBAPI
NTSTATUS
NTAPI
PhQueryInformationHandleTable(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,
_Out_writes_bytes_opt_(BufferLength) PVOID Buffer,
_In_ ULONG BufferLength,
_Out_opt_ PULONG ReturnLength
);
PHLIBAPI
NTSTATUS
NTAPI
PhSetInformationHandleTable(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,
_In_reads_bytes_(BufferLength) PVOID Buffer,
_In_ ULONG BufferLength
);
#ifdef __cplusplus
}
#endif
#endif

147
phlib/include/handlep.h Normal file
View File

@@ -0,0 +1,147 @@
#ifndef _PH_HANDLEP_H
#define _PH_HANDLEP_H
#define PH_HANDLE_TABLE_ENTRY_TYPE 0x1
#define PH_HANDLE_TABLE_ENTRY_IN_USE 0x0
#define PH_HANDLE_TABLE_ENTRY_FREE 0x1
// Locked actually means Not Locked. This means that an in use, locked handle table entry can be
// used as-is.
#define PH_HANDLE_TABLE_ENTRY_LOCKED 0x2
#define PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT 1
// There is initially one handle table level, with 256 entries. When the handle table is expanded,
// the table is replaced with a level 1 table, which contains 256 pointers to level 0 tables (the
// first entry already points to the initial level 0 table). Similarly, when the handle table is
// expanded a second time, the table is replaced with a level 2 table, which contains 256 pointers
// to level 1 tables.
//
// This provides a maximum of 16,777,216 handles.
#define PH_HANDLE_TABLE_LEVEL_ENTRIES 256
#define PH_HANDLE_TABLE_LEVEL_MASK 0x3
#define PH_HANDLE_TABLE_LOCKS 8
#define PH_HANDLE_TABLE_LOCK_INDEX(HandleValue) ((HandleValue) % PH_HANDLE_TABLE_LOCKS)
typedef struct _PH_HANDLE_TABLE
{
PH_QUEUED_LOCK Lock;
PH_WAKE_EVENT HandleWakeEvent;
ULONG Count;
ULONG_PTR TableValue;
ULONG FreeValue;
ULONG NextValue;
ULONG FreeValueAlt;
ULONG Flags;
PH_QUEUED_LOCK Locks[PH_HANDLE_TABLE_LOCKS];
} PH_HANDLE_TABLE, *PPH_HANDLE_TABLE;
FORCEINLINE VOID PhpLockHandleTableShared(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ ULONG Index
)
{
PhAcquireQueuedLockShared(&HandleTable->Locks[Index]);
}
FORCEINLINE VOID PhpUnlockHandleTableShared(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ ULONG Index
)
{
PhReleaseQueuedLockShared(&HandleTable->Locks[Index]);
}
// Handle values work by specifying indicies into each
// level.
//
// Bits 0-7: level 0
// Bits 8-15: level 1
// Bits 16-23: level 2
// Bits 24-31: reserved
#define PH_HANDLE_VALUE_INVALID ((ULONG)-1)
#define PH_HANDLE_VALUE_SHIFT 2
#define PH_HANDLE_VALUE_BIAS 4
#define PH_HANDLE_VALUE_LEVEL0(HandleValue) ((HandleValue) & 0xff)
#define PH_HANDLE_VALUE_LEVEL1_U(HandleValue) ((HandleValue) >> 8)
#define PH_HANDLE_VALUE_LEVEL1(HandleValue) (PH_HANDLE_VALUE_LEVEL1_U(HandleValue) & 0xff)
#define PH_HANDLE_VALUE_LEVEL2_U(HandleValue) ((HandleValue) >> 16)
#define PH_HANDLE_VALUE_LEVEL2(HandleValue) (PH_HANDLE_VALUE_LEVEL2_U(HandleValue) & 0xff)
#define PH_HANDLE_VALUE_IS_INVALID(HandleValue) (((HandleValue) >> 24) != 0)
FORCEINLINE HANDLE PhpEncodeHandle(
_In_ ULONG HandleValue
)
{
return UlongToHandle(((HandleValue << PH_HANDLE_VALUE_SHIFT) + PH_HANDLE_VALUE_BIAS));
}
FORCEINLINE ULONG PhpDecodeHandle(
_In_ HANDLE Handle
)
{
return (HandleToUlong(Handle) - PH_HANDLE_VALUE_BIAS) >> PH_HANDLE_VALUE_SHIFT;
}
VOID PhpBlockOnLockedHandleTableEntry(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry
);
PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_Out_ PULONG HandleValue
);
VOID PhpFreeHandleTableEntry(
_Inout_ PPH_HANDLE_TABLE HandleTable,
_In_ ULONG HandleValue,
_Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry
);
BOOLEAN PhpAllocateMoreHandleTableEntries(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ BOOLEAN Initialize
);
PPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ ULONG HandleValue
);
ULONG PhpMoveFreeHandleTableEntries(
_Inout_ PPH_HANDLE_TABLE HandleTable
);
PPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0(
_In_ PPH_HANDLE_TABLE HandleTable,
_In_ BOOLEAN Initialize
);
VOID PhpFreeHandleTableLevel0(
_In_ PPH_HANDLE_TABLE_ENTRY Table
);
PPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1(
_In_ PPH_HANDLE_TABLE HandleTable
);
VOID PhpFreeHandleTableLevel1(
_In_ PPH_HANDLE_TABLE_ENTRY *Table
);
PPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2(
_In_ PPH_HANDLE_TABLE HandleTable
);
VOID PhpFreeHandleTableLevel2(
_In_ PPH_HANDLE_TABLE_ENTRY **Table
);
#endif

49
phlib/include/hexedit.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef _PH_HEXEDIT_H
#define _PH_HEXEDIT_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_HEXEDIT_CLASSNAME L"PhHexEdit"
#define EDIT_NONE 0
#define EDIT_ASCII 1
#define EDIT_HIGH 2
#define EDIT_LOW 3
PHLIBAPI
BOOLEAN PhHexEditInitialization(
VOID
);
#define HEM_SETBUFFER (WM_USER + 1)
#define HEM_SETDATA (WM_USER + 2)
#define HEM_GETBUFFER (WM_USER + 3)
#define HEM_SETSEL (WM_USER + 4)
#define HEM_SETEDITMODE (WM_USER + 5)
#define HEM_SETBYTESPERROW (WM_USER + 6)
#define HexEdit_SetBuffer(hWnd, Buffer, Length) \
SendMessage((hWnd), HEM_SETBUFFER, (WPARAM)(Length), (LPARAM)(Buffer))
#define HexEdit_SetData(hWnd, Buffer, Length) \
SendMessage((hWnd), HEM_SETDATA, (WPARAM)(Length), (LPARAM)(Buffer))
#define HexEdit_GetBuffer(hWnd, Length) \
((PUCHAR)SendMessage((hWnd), HEM_GETBUFFER, (WPARAM)(Length), 0))
#define HexEdit_SetSel(hWnd, Start, End) \
SendMessage((hWnd), HEM_SETSEL, (WPARAM)(Start), (LPARAM)(End))
#define HexEdit_SetEditMode(hWnd, Mode) \
SendMessage((hWnd), HEM_SETEDITMODE, (WPARAM)(Mode), 0)
#define HexEdit_SetBytesPerRow(hWnd, BytesPerRow) \
SendMessage((hWnd), HEM_SETBYTESPERROW, (WPARAM)(BytesPerRow), 0)
#ifdef __cplusplus
}
#endif
#endif

201
phlib/include/hexeditp.h Normal file
View File

@@ -0,0 +1,201 @@
#ifndef _PH_HEXEDITP_H
#define _PH_HEXEDITP_H
typedef struct _PHP_HEXEDIT_CONTEXT
{
PUCHAR Data;
LONG Length;
BOOLEAN UserBuffer;
LONG TopIndex; // index of first visible byte on screen
LONG CurrentAddress;
LONG CurrentMode;
LONG SelStart;
LONG SelEnd;
LONG BytesPerRow;
LONG LinesPerPage;
BOOLEAN ShowAddress;
BOOLEAN ShowAscii;
BOOLEAN ShowHex;
BOOLEAN AddressIsWide;
BOOLEAN AllowLengthChange;
BOOLEAN NoAddressChange;
BOOLEAN HalfPage;
HFONT Font;
LONG LineHeight;
LONG NullWidth;
PWCHAR CharBuffer;
ULONG CharBufferLength;
BOOLEAN Update;
LONG HexOffset;
LONG AsciiOffset;
LONG AddressOffset;
BOOLEAN HasCapture;
POINT EditPosition;
} PHP_HEXEDIT_CONTEXT, *PPHP_HEXEDIT_CONTEXT;
#define IS_PRINTABLE(Byte) ((ULONG)((Byte) - ' ') <= (ULONG)('~' - ' '))
#define TO_HEX(Buffer, Byte) \
{ \
*(Buffer)++ = PhIntegerToChar[(Byte) >> 4]; \
*(Buffer)++ = PhIntegerToChar[(Byte) & 0xf]; \
}
#define REDRAW_WINDOW(hwnd) \
RedrawWindow((hwnd), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE)
VOID PhpCreateHexEditContext(
_Out_ PPHP_HEXEDIT_CONTEXT *Context
);
VOID PhpFreeHexEditContext(
_In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context
);
LRESULT CALLBACK PhpHexEditWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID PhpHexEditUpdateMetrics(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ BOOLEAN UpdateLineHeight,
_In_opt_ HDC hdc
);
VOID PhpHexEditOnPaint(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ PAINTSTRUCT *PaintStruct,
_In_ HDC hdc
);
VOID PhpHexEditUpdateScrollbars(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
FORCEINLINE BOOLEAN PhpHexEditHasSelected(
_In_ PPHP_HEXEDIT_CONTEXT Context
)
{
return Context->SelStart != -1;
}
VOID PhpHexEditCreateAddressCaret(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditCreateEditCaret(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditRepositionCaret(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG Position
);
VOID PhpHexEditCalculatePosition(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG X,
_In_ LONG Y,
_Out_ POINT *Point
);
VOID PhpHexEditMove(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG X,
_In_ LONG Y
);
VOID PhpHexEditSetSel(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG S,
_In_ LONG E
);
VOID PhpHexEditScrollTo(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG Position
);
VOID PhpHexEditClearEdit(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditCopyEdit(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditCutEdit(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditPasteEdit(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditSelectAll(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditUndoEdit(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditNormalizeSel(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context
);
VOID PhpHexEditSelDelete(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG S,
_In_ LONG E
);
VOID PhpHexEditSelInsert(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ LONG S,
_In_ LONG L
);
VOID PhpHexEditSetBuffer(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ PUCHAR Data,
_In_ ULONG Length
);
VOID PhpHexEditSetData(
_In_ HWND hwnd,
_In_ PPHP_HEXEDIT_CONTEXT Context,
_In_ PUCHAR Data,
_In_ ULONG Length
);
#endif

138
phlib/include/hndlinfo.h Normal file
View File

@@ -0,0 +1,138 @@
#ifndef _PH_HNDLINFO_H
#define _PH_HNDLINFO_H
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_OBJECT_TYPE_NUMBER 257
typedef PPH_STRING (NTAPI *PPH_GET_CLIENT_ID_NAME)(
_In_ PCLIENT_ID ClientId
);
PHLIBAPI
PPH_GET_CLIENT_ID_NAME
NTAPI
PhSetHandleClientIdFunction(
_In_ PPH_GET_CLIENT_ID_NAME GetClientIdName
);
PHLIBAPI
PPH_STRING
NTAPI
PhFormatNativeKeyName(
_In_ PPH_STRING Name
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetSectionFileName(
_In_ HANDLE SectionHandle,
_Out_ PPH_STRING *FileName
);
PHLIBAPI
_Callback_ PPH_STRING
NTAPI
PhStdGetClientIdName(
_In_ PCLIENT_ID ClientId
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetHandleInformation(
_In_ HANDLE ProcessHandle,
_In_ HANDLE Handle,
_In_ ULONG ObjectTypeNumber,
_Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,
_Out_opt_ PPH_STRING *TypeName,
_Out_opt_ PPH_STRING *ObjectName,
_Out_opt_ PPH_STRING *BestObjectName
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetHandleInformationEx(
_In_ HANDLE ProcessHandle,
_In_ HANDLE Handle,
_In_ ULONG ObjectTypeNumber,
_Reserved_ ULONG Flags,
_Out_opt_ PNTSTATUS SubStatus,
_Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,
_Out_opt_ PPH_STRING *TypeName,
_Out_opt_ PPH_STRING *ObjectName,
_Out_opt_ PPH_STRING *BestObjectName,
_Reserved_ PVOID *ExtraInformation
);
#define PH_FIRST_OBJECT_TYPE(ObjectTypes) \
(POBJECT_TYPE_INFORMATION)((PCHAR)(ObjectTypes) + ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR))
#define PH_NEXT_OBJECT_TYPE(ObjectType) \
(POBJECT_TYPE_INFORMATION)((PCHAR)(ObjectType) + sizeof(OBJECT_TYPE_INFORMATION) + \
ALIGN_UP(ObjectType->TypeName.MaximumLength, ULONG_PTR))
PHLIBAPI
NTSTATUS
NTAPI
PhEnumObjectTypes(
_Out_ POBJECT_TYPES_INFORMATION *ObjectTypes
);
PHLIBAPI
ULONG
NTAPI
PhGetObjectTypeNumber(
_In_ PUNICODE_STRING TypeName
);
PHLIBAPI
NTSTATUS
NTAPI
PhCallWithTimeout(
_In_ PUSER_THREAD_START_ROUTINE Routine,
_In_opt_ PVOID Context,
_In_opt_ PLARGE_INTEGER AcquireTimeout,
_In_ PLARGE_INTEGER CallTimeout
);
PHLIBAPI
NTSTATUS
NTAPI
PhCallNtQueryObjectWithTimeout(
_In_ HANDLE Handle,
_In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,
_Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,
_In_ ULONG ObjectInformationLength,
_Out_opt_ PULONG ReturnLength
);
PHLIBAPI
NTSTATUS
NTAPI
PhCallNtQuerySecurityObjectWithTimeout(
_In_ HANDLE Handle,
_In_ SECURITY_INFORMATION SecurityInformation,
_Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,
_In_ ULONG Length,
_Out_ PULONG LengthNeeded
);
PHLIBAPI
NTSTATUS
NTAPI
PhCallNtSetSecurityObjectWithTimeout(
_In_ HANDLE Handle,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
);
#ifdef __cplusplus
}
#endif
#endif

242
phlib/include/kphapi.h Normal file
View File

@@ -0,0 +1,242 @@
#ifndef _KPHAPI_H
#define _KPHAPI_H
// This file contains KProcessHacker definitions shared across kernel-mode and user-mode.
// Process information
typedef enum _KPH_PROCESS_INFORMATION_CLASS
{
KphProcessReserved1 = 1,
KphProcessReserved2 = 2,
KphProcessReserved3 = 3,
MaxKphProcessInfoClass
} KPH_PROCESS_INFORMATION_CLASS;
// Thread information
typedef enum _KPH_THREAD_INFORMATION_CLASS
{
KphThreadReserved1 = 1,
KphThreadReserved2 = 2,
KphThreadReserved3 = 3,
MaxKphThreadInfoClass
} KPH_THREAD_INFORMATION_CLASS;
// Process handle information
typedef struct _KPH_PROCESS_HANDLE
{
HANDLE Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
USHORT ObjectTypeIndex;
USHORT Reserved1;
ULONG HandleAttributes;
ULONG Reserved2;
} KPH_PROCESS_HANDLE, *PKPH_PROCESS_HANDLE;
typedef struct _KPH_PROCESS_HANDLE_INFORMATION
{
ULONG HandleCount;
KPH_PROCESS_HANDLE Handles[1];
} KPH_PROCESS_HANDLE_INFORMATION, *PKPH_PROCESS_HANDLE_INFORMATION;
// Object information
typedef enum _KPH_OBJECT_INFORMATION_CLASS
{
KphObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION
KphObjectNameInformation, // q: OBJECT_NAME_INFORMATION
KphObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION
KphObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION
KphObjectProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION
KphObjectThreadBasicInformation, // q: THREAD_BASIC_INFORMATION
KphObjectEtwRegBasicInformation, // q: ETWREG_BASIC_INFORMATION
KphObjectFileObjectInformation, // q: KPH_FILE_OBJECT_INFORMATION
KphObjectFileObjectDriver, // q: KPH_FILE_OBJECT_DRIVER
MaxKphObjectInfoClass
} KPH_OBJECT_INFORMATION_CLASS;
typedef struct _KPH_FILE_OBJECT_INFORMATION
{
BOOLEAN LockOperation;
BOOLEAN DeletePending;
BOOLEAN ReadAccess;
BOOLEAN WriteAccess;
BOOLEAN DeleteAccess;
BOOLEAN SharedRead;
BOOLEAN SharedWrite;
BOOLEAN SharedDelete;
LARGE_INTEGER CurrentByteOffset;
ULONG Flags;
} KPH_FILE_OBJECT_INFORMATION, *PKPH_FILE_OBJECT_INFORMATION;
typedef struct _KPH_FILE_OBJECT_DRIVER
{
HANDLE DriverHandle;
} KPH_FILE_OBJECT_DRIVER, *PKPH_FILE_OBJECT_DRIVER;
// Driver information
typedef enum _DRIVER_INFORMATION_CLASS
{
DriverBasicInformation,
DriverNameInformation,
DriverServiceKeyNameInformation,
MaxDriverInfoClass
} DRIVER_INFORMATION_CLASS;
typedef struct _DRIVER_BASIC_INFORMATION
{
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
} DRIVER_BASIC_INFORMATION, *PDRIVER_BASIC_INFORMATION;
typedef struct _DRIVER_NAME_INFORMATION
{
UNICODE_STRING DriverName;
} DRIVER_NAME_INFORMATION, *PDRIVER_NAME_INFORMATION;
typedef struct _DRIVER_SERVICE_KEY_NAME_INFORMATION
{
UNICODE_STRING ServiceKeyName;
} DRIVER_SERVICE_KEY_NAME_INFORMATION, *PDRIVER_SERVICE_KEY_NAME_INFORMATION;
// ETW registration object information
typedef struct _ETWREG_BASIC_INFORMATION
{
GUID Guid;
ULONG_PTR SessionId;
} ETWREG_BASIC_INFORMATION, *PETWREG_BASIC_INFORMATION;
// Device
#define KPH_DEVICE_SHORT_NAME L"KProcessHacker3"
#define KPH_DEVICE_TYPE 0x9999
#define KPH_DEVICE_NAME (L"\\Device\\" KPH_DEVICE_SHORT_NAME)
// Parameters
typedef enum _KPH_SECURITY_LEVEL
{
KphSecurityNone = 0, // all clients are allowed
KphSecurityPrivilegeCheck = 1, // require SeDebugPrivilege
KphSecuritySignatureCheck = 2, // require trusted signature
KphSecuritySignatureAndPrivilegeCheck = 3, // require trusted signature and SeDebugPrivilege
KphMaxSecurityLevel
} KPH_SECURITY_LEVEL, *PKPH_SECURITY_LEVEL;
typedef struct _KPH_DYN_STRUCT_DATA
{
SHORT EgeGuid;
SHORT EpObjectTable;
SHORT Reserved0;
SHORT Reserved1;
SHORT Reserved2;
SHORT EreGuidEntry;
SHORT HtHandleContentionEvent;
SHORT OtName;
SHORT OtIndex;
SHORT ObDecodeShift;
SHORT ObAttributesShift;
} KPH_DYN_STRUCT_DATA, *PKPH_DYN_STRUCT_DATA;
typedef struct _KPH_DYN_PACKAGE
{
USHORT MajorVersion;
USHORT MinorVersion;
USHORT ServicePackMajor; // -1 to ignore
USHORT BuildNumber; // -1 to ignore
ULONG ResultingNtVersion; // PHNT_*
KPH_DYN_STRUCT_DATA StructData;
} KPH_DYN_PACKAGE, *PKPH_DYN_PACKAGE;
#define KPH_DYN_CONFIGURATION_VERSION 3
#define KPH_DYN_MAXIMUM_PACKAGES 64
typedef struct _KPH_DYN_CONFIGURATION
{
ULONG Version;
ULONG NumberOfPackages;
KPH_DYN_PACKAGE Packages[1];
} KPH_DYN_CONFIGURATION, *PKPH_DYN_CONFIGURATION;
// Verification
#ifdef __BCRYPT_H__
#define KPH_SIGN_ALGORITHM BCRYPT_ECDSA_P256_ALGORITHM
#define KPH_SIGN_ALGORITHM_BITS 256
#define KPH_HASH_ALGORITHM BCRYPT_SHA256_ALGORITHM
#define KPH_BLOB_PUBLIC BCRYPT_ECCPUBLIC_BLOB
#endif
#define KPH_SIGNATURE_MAX_SIZE (128 * 1024) // 128 kB
typedef ULONG KPH_KEY, *PKPH_KEY;
typedef enum _KPH_KEY_LEVEL
{
KphKeyLevel1 = 1,
KphKeyLevel2 = 2
} KPH_KEY_LEVEL;
#define KPH_KEY_BACKOFF_TIME ((LONGLONG)(100 * 1000 * 10)) // 100ms
#define KPH_PROCESS_READ_ACCESS \
(PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ)
#define KPH_THREAD_READ_ACCESS \
(THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT)
#define KPH_TOKEN_READ_ACCESS \
(TOKEN_QUERY | TOKEN_QUERY_SOURCE)
// Features
// No features defined.
// Control codes
#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_NEITHER, FILE_ANY_ACCESS)
// General
#define KPH_GETFEATURES KPH_CTL_CODE(0)
#define KPH_VERIFYCLIENT KPH_CTL_CODE(1)
#define KPH_RETRIEVEKEY KPH_CTL_CODE(2) // User-mode only
// Processes
#define KPH_OPENPROCESS KPH_CTL_CODE(50) // L1/L2 protected API
#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) // L1/L2 protected API
#define KPH_OPENPROCESSJOB KPH_CTL_CODE(52)
#define KPH_RESERVED53 KPH_CTL_CODE(53)
#define KPH_RESERVED54 KPH_CTL_CODE(54)
#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) // L2 protected API
#define KPH_RESERVED56 KPH_CTL_CODE(56)
#define KPH_RESERVED57 KPH_CTL_CODE(57)
#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) // L2 protected API
#define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(59)
#define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(60)
// Threads
#define KPH_OPENTHREAD KPH_CTL_CODE(100) // L1/L2 protected API
#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(101)
#define KPH_RESERVED102 KPH_CTL_CODE(102)
#define KPH_RESERVED103 KPH_CTL_CODE(103)
#define KPH_RESERVED104 KPH_CTL_CODE(104)
#define KPH_RESERVED105 KPH_CTL_CODE(105)
#define KPH_CAPTURESTACKBACKTRACETHREAD KPH_CTL_CODE(106)
#define KPH_QUERYINFORMATIONTHREAD KPH_CTL_CODE(107)
#define KPH_SETINFORMATIONTHREAD KPH_CTL_CODE(108)
// Handles
#define KPH_ENUMERATEPROCESSHANDLES KPH_CTL_CODE(150)
#define KPH_QUERYINFORMATIONOBJECT KPH_CTL_CODE(151)
#define KPH_SETINFORMATIONOBJECT KPH_CTL_CODE(152)
#define KPH_RESERVED153 KPH_CTL_CODE(153)
// Misc.
#define KPH_OPENDRIVER KPH_CTL_CODE(200)
#define KPH_QUERYINFORMATIONDRIVER KPH_CTL_CODE(201)
#endif

300
phlib/include/kphuser.h Normal file
View File

@@ -0,0 +1,300 @@
#ifndef _PH_KPHUSER_H
#define _PH_KPHUSER_H
#include <kphapi.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _KPH_PARAMETERS
{
KPH_SECURITY_LEVEL SecurityLevel;
BOOLEAN CreateDynamicConfiguration;
} KPH_PARAMETERS, *PKPH_PARAMETERS;
PHLIBAPI
NTSTATUS
NTAPI
KphConnect(
_In_opt_ PWSTR DeviceName
);
PHLIBAPI
NTSTATUS
NTAPI
KphConnect2(
_In_opt_ PWSTR DeviceName,
_In_ PWSTR FileName
);
PHLIBAPI
NTSTATUS
NTAPI
KphConnect2Ex(
_In_opt_ PWSTR DeviceName,
_In_ PWSTR FileName,
_In_opt_ PKPH_PARAMETERS Parameters
);
PHLIBAPI
NTSTATUS
NTAPI
KphDisconnect(
VOID
);
PHLIBAPI
BOOLEAN
NTAPI
KphIsConnected(
VOID
);
PHLIBAPI
BOOLEAN
NTAPI
KphIsVerified(
VOID
);
PHLIBAPI
NTSTATUS
NTAPI
KphSetParameters(
_In_opt_ PWSTR DeviceName,
_In_ PKPH_PARAMETERS Parameters
);
PHLIBAPI
NTSTATUS
NTAPI
KphInstall(
_In_opt_ PWSTR DeviceName,
_In_ PWSTR FileName
);
PHLIBAPI
NTSTATUS
NTAPI
KphInstallEx(
_In_opt_ PWSTR DeviceName,
_In_ PWSTR FileName,
_In_opt_ PKPH_PARAMETERS Parameters
);
PHLIBAPI
NTSTATUS
NTAPI
KphUninstall(
_In_opt_ PWSTR DeviceName
);
PHLIBAPI
NTSTATUS
NTAPI
KphGetFeatures(
_Out_ PULONG Features
);
PHLIBAPI
NTSTATUS
NTAPI
KphVerifyClient(
_In_reads_bytes_(SignatureSize) PUCHAR Signature,
_In_ ULONG SignatureSize
);
PHLIBAPI
NTSTATUS
NTAPI
KphOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ PCLIENT_ID ClientId
);
PHLIBAPI
NTSTATUS
NTAPI
KphOpenProcessToken(
_In_ HANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_Out_ PHANDLE TokenHandle
);
PHLIBAPI
NTSTATUS
NTAPI
KphOpenProcessJob(
_In_ HANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_Out_ PHANDLE JobHandle
);
PHLIBAPI
NTSTATUS
NTAPI
KphTerminateProcess(
_In_ HANDLE ProcessHandle,
_In_ NTSTATUS ExitStatus
);
PHLIBAPI
NTSTATUS
NTAPI
KphReadVirtualMemoryUnsafe(
_In_opt_ HANDLE ProcessHandle,
_In_ PVOID BaseAddress,
_Out_writes_bytes_(BufferSize) PVOID Buffer,
_In_ SIZE_T BufferSize,
_Out_opt_ PSIZE_T NumberOfBytesRead
);
PHLIBAPI
NTSTATUS
NTAPI
KphQueryInformationProcess(
_In_ HANDLE ProcessHandle,
_In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
_Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphSetInformationProcess(
_In_ HANDLE ProcessHandle,
_In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
_In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphOpenThread(
_Out_ PHANDLE ThreadHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ PCLIENT_ID ClientId
);
PHLIBAPI
NTSTATUS
NTAPI
KphOpenThreadProcess(
_In_ HANDLE ThreadHandle,
_In_ ACCESS_MASK DesiredAccess,
_Out_ PHANDLE ProcessHandle
);
PHLIBAPI
NTSTATUS
NTAPI
KphCaptureStackBackTraceThread(
_In_ HANDLE ThreadHandle,
_In_ ULONG FramesToSkip,
_In_ ULONG FramesToCapture,
_Out_writes_(FramesToCapture) PVOID *BackTrace,
_Out_opt_ PULONG CapturedFrames,
_Out_opt_ PULONG BackTraceHash
);
PHLIBAPI
NTSTATUS
NTAPI
KphQueryInformationThread(
_In_ HANDLE ThreadHandle,
_In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
_Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,
_In_ ULONG ThreadInformationLength,
_Out_opt_ PULONG ReturnLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphSetInformationThread(
_In_ HANDLE ThreadHandle,
_In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
_In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,
_In_ ULONG ThreadInformationLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphEnumerateProcessHandles(
_In_ HANDLE ProcessHandle,
_Out_writes_bytes_(BufferLength) PVOID Buffer,
_In_opt_ ULONG BufferLength,
_Out_opt_ PULONG ReturnLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphEnumerateProcessHandles2(
_In_ HANDLE ProcessHandle,
_Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles
);
PHLIBAPI
NTSTATUS
NTAPI
KphQueryInformationObject(
_In_ HANDLE ProcessHandle,
_In_ HANDLE Handle,
_In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
_Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation,
_In_ ULONG ObjectInformationLength,
_Out_opt_ PULONG ReturnLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphSetInformationObject(
_In_ HANDLE ProcessHandle,
_In_ HANDLE Handle,
_In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
_In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,
_In_ ULONG ObjectInformationLength
);
PHLIBAPI
NTSTATUS
NTAPI
KphOpenDriver(
_Out_ PHANDLE DriverHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes
);
PHLIBAPI
NTSTATUS
NTAPI
KphQueryInformationDriver(
_In_ HANDLE DriverHandle,
_In_ DRIVER_INFORMATION_CLASS DriverInformationClass,
_Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation,
_In_ ULONG DriverInformationLength,
_Out_opt_ PULONG ReturnLength
);
// kphdata
PHLIBAPI
NTSTATUS
NTAPI
KphInitializeDynamicPackage(
_Out_ PKPH_DYN_PACKAGE Package
);
#ifdef __cplusplus
}
#endif
#endif

127
phlib/include/kphuserp.h Normal file
View File

@@ -0,0 +1,127 @@
#ifndef _PH_KPHUSERP_H
#define _PH_KPHUSERP_H
typedef NTSTATUS (NTAPI *PKPHP_WITH_KEY_CONTINUATION)(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
NTSTATUS KphpDeviceIoControl(
_In_ ULONG KphControlCode,
_In_ PVOID InBuffer,
_In_ ULONG InBufferLength
);
typedef struct _KPHP_RETRIEVE_KEY_CONTEXT
{
IO_STATUS_BLOCK Iosb;
PKPHP_WITH_KEY_CONTINUATION Continuation;
PVOID Context;
NTSTATUS Status;
} KPHP_RETRIEVE_KEY_CONTEXT, *PKPHP_RETRIEVE_KEY_CONTEXT;
VOID KphpWithKeyApcRoutine(
_In_ PVOID ApcContext,
_In_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ ULONG Reserved
);
NTSTATUS KphpWithKey(
_In_ KPH_KEY_LEVEL KeyLevel,
_In_ PKPHP_WITH_KEY_CONTINUATION Continuation,
_In_ PVOID Context
);
// Get L1 key
typedef struct _KPHP_GET_L1_KEY_CONTEXT
{
PKPH_KEY Key;
} KPHP_GET_L1_KEY_CONTEXT, *PKPHP_GET_L1_KEY_CONTEXT;
NTSTATUS KphpGetL1KeyContinuation(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
NTSTATUS KphpGetL1Key(
_Out_ PKPH_KEY Key
);
// Open process
typedef struct _KPH_OPEN_PROCESS_INPUT
{
PHANDLE ProcessHandle;
ACCESS_MASK DesiredAccess;
PCLIENT_ID ClientId;
KPH_KEY Key;
} KPH_OPEN_PROCESS_INPUT, *PKPH_OPEN_PROCESS_INPUT;
NTSTATUS KphpOpenProcessContinuation(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
// Open process token
typedef struct _KPH_OPEN_PROCESS_TOKEN_INPUT
{
HANDLE ProcessHandle;
ACCESS_MASK DesiredAccess;
PHANDLE TokenHandle;
KPH_KEY Key;
} KPH_OPEN_PROCESS_TOKEN_INPUT, *PKPH_OPEN_PROCESS_TOKEN_INPUT;
NTSTATUS KphpOpenProcessTokenContinuation(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
// Terminate process
typedef struct _KPH_TERMINATE_PROCESS_INPUT
{
HANDLE ProcessHandle;
NTSTATUS ExitStatus;
KPH_KEY Key;
} KPH_TERMINATE_PROCESS_INPUT, *PKPH_TERMINATE_PROCESS_INPUT;
NTSTATUS KphpTerminateProcessContinuation(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
// Read virtual memory, unsafe
typedef struct _KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT
{
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
SIZE_T BufferSize;
PSIZE_T NumberOfBytesRead;
KPH_KEY Key;
} KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT, *PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT;
NTSTATUS KphpReadVirtualMemoryUnsafeContinuation(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
// Open thread
typedef struct _KPH_OPEN_THREAD_INPUT
{
PHANDLE ThreadHandle;
ACCESS_MASK DesiredAccess;
PCLIENT_ID ClientId;
KPH_KEY Key;
} KPH_OPEN_THREAD_INPUT, *PKPH_OPEN_THREAD_INPUT;
NTSTATUS KphpOpenThreadContinuation(
_In_ KPH_KEY Key,
_In_ PVOID Context
);
#endif

88
phlib/include/lsasup.h Normal file
View File

@@ -0,0 +1,88 @@
#ifndef _PH_LSASUP_H
#define _PH_LSASUP_H
#ifdef __cplusplus
extern "C" {
#endif
PHLIBAPI
NTSTATUS
NTAPI
PhOpenLsaPolicy(
_Out_ PLSA_HANDLE PolicyHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ PUNICODE_STRING SystemName
);
PHLIBAPI
LSA_HANDLE
NTAPI
PhGetLookupPolicyHandle(
VOID
);
PHLIBAPI
BOOLEAN
NTAPI
PhLookupPrivilegeName(
_In_ PLUID PrivilegeValue,
_Out_ PPH_STRING *PrivilegeName
);
PHLIBAPI
BOOLEAN
NTAPI
PhLookupPrivilegeDisplayName(
_In_ PPH_STRINGREF PrivilegeName,
_Out_ PPH_STRING *PrivilegeDisplayName
);
PHLIBAPI
BOOLEAN
NTAPI
PhLookupPrivilegeValue(
_In_ PPH_STRINGREF PrivilegeName,
_Out_ PLUID PrivilegeValue
);
PHLIBAPI
NTSTATUS
NTAPI
PhLookupSid(
_In_ PSID Sid,
_Out_opt_ PPH_STRING *Name,
_Out_opt_ PPH_STRING *DomainName,
_Out_opt_ PSID_NAME_USE NameUse
);
PHLIBAPI
NTSTATUS
NTAPI
PhLookupName(
_In_ PPH_STRINGREF Name,
_Out_opt_ PSID *Sid,
_Out_opt_ PPH_STRING *DomainName,
_Out_opt_ PSID_NAME_USE NameUse
);
PHLIBAPI
PPH_STRING
NTAPI
PhGetSidFullName(
_In_ PSID Sid,
_In_ BOOLEAN IncludeDomain,
_Out_opt_ PSID_NAME_USE NameUse
);
PHLIBAPI
PPH_STRING
NTAPI
PhSidToStringSid(
_In_ PSID Sid
);
#ifdef __cplusplus
}
#endif
#endif

388
phlib/include/mapimg.h Normal file
View File

@@ -0,0 +1,388 @@
#ifndef _PH_MAPIMG_H
#define _PH_MAPIMG_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _PH_MAPPED_IMAGE
{
PVOID ViewBase;
SIZE_T Size;
PIMAGE_NT_HEADERS NtHeaders;
ULONG NumberOfSections;
PIMAGE_SECTION_HEADER Sections;
USHORT Magic;
} PH_MAPPED_IMAGE, *PPH_MAPPED_IMAGE;
PHLIBAPI
NTSTATUS
NTAPI
PhInitializeMappedImage(
_Out_ PPH_MAPPED_IMAGE MappedImage,
_In_ PVOID ViewBase,
_In_ SIZE_T Size
);
PHLIBAPI
NTSTATUS
NTAPI
PhLoadMappedImage(
_In_opt_ PWSTR FileName,
_In_opt_ HANDLE FileHandle,
_In_ BOOLEAN ReadOnly,
_Out_ PPH_MAPPED_IMAGE MappedImage
);
PHLIBAPI
NTSTATUS
NTAPI
PhUnloadMappedImage(
_Inout_ PPH_MAPPED_IMAGE MappedImage
);
PHLIBAPI
NTSTATUS
NTAPI
PhMapViewOfEntireFile(
_In_opt_ PWSTR FileName,
_In_opt_ HANDLE FileHandle,
_In_ BOOLEAN ReadOnly,
_Out_ PVOID *ViewBase,
_Out_ PSIZE_T Size
);
PHLIBAPI
PIMAGE_SECTION_HEADER
NTAPI
PhMappedImageRvaToSection(
_In_ PPH_MAPPED_IMAGE MappedImage,
_In_ ULONG Rva
);
PHLIBAPI
PVOID
NTAPI
PhMappedImageRvaToVa(
_In_ PPH_MAPPED_IMAGE MappedImage,
_In_ ULONG Rva,
_Out_opt_ PIMAGE_SECTION_HEADER *Section
);
PHLIBAPI
BOOLEAN
NTAPI
PhGetMappedImageSectionName(
_In_ PIMAGE_SECTION_HEADER Section,
_Out_writes_opt_z_(Count) PSTR Buffer,
_In_ ULONG Count,
_Out_opt_ PULONG ReturnCount
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageDataEntry(
_In_ PPH_MAPPED_IMAGE MappedImage,
_In_ ULONG Index,
_Out_ PIMAGE_DATA_DIRECTORY *Entry
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageLoadConfig32(
_In_ PPH_MAPPED_IMAGE MappedImage,
_Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageLoadConfig64(
_In_ PPH_MAPPED_IMAGE MappedImage,
_Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig
);
typedef struct _PH_REMOTE_MAPPED_IMAGE
{
PVOID ViewBase;
PIMAGE_NT_HEADERS NtHeaders;
ULONG NumberOfSections;
PIMAGE_SECTION_HEADER Sections;
USHORT Magic;
} PH_REMOTE_MAPPED_IMAGE, *PPH_REMOTE_MAPPED_IMAGE;
NTSTATUS
NTAPI
PhLoadRemoteMappedImage(
_In_ HANDLE ProcessHandle,
_In_ PVOID ViewBase,
_Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage
);
NTSTATUS
NTAPI
PhUnloadRemoteMappedImage(
_Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage
);
typedef struct _PH_MAPPED_IMAGE_EXPORTS
{
PPH_MAPPED_IMAGE MappedImage;
ULONG NumberOfEntries;
PIMAGE_DATA_DIRECTORY DataDirectory;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PULONG AddressTable;
PULONG NamePointerTable;
PUSHORT OrdinalTable;
} PH_MAPPED_IMAGE_EXPORTS, *PPH_MAPPED_IMAGE_EXPORTS;
typedef struct _PH_MAPPED_IMAGE_EXPORT_ENTRY
{
USHORT Ordinal;
PSTR Name;
} PH_MAPPED_IMAGE_EXPORT_ENTRY, *PPH_MAPPED_IMAGE_EXPORT_ENTRY;
typedef struct _PH_MAPPED_IMAGE_EXPORT_FUNCTION
{
PVOID Function;
PSTR ForwardedName;
} PH_MAPPED_IMAGE_EXPORT_FUNCTION, *PPH_MAPPED_IMAGE_EXPORT_FUNCTION;
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageExports(
_Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,
_In_ PPH_MAPPED_IMAGE MappedImage
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageExportEntry(
_In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
_In_ ULONG Index,
_Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageExportFunction(
_In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
_In_opt_ PSTR Name,
_In_opt_ USHORT Ordinal,
_Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageExportFunctionRemote(
_In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
_In_opt_ PSTR Name,
_In_opt_ USHORT Ordinal,
_In_ PVOID RemoteBase,
_Out_ PVOID *Function
);
#define PH_MAPPED_IMAGE_DELAY_IMPORTS 0x1
typedef struct _PH_MAPPED_IMAGE_IMPORTS
{
PPH_MAPPED_IMAGE MappedImage;
ULONG Flags;
ULONG NumberOfDlls;
union
{
PIMAGE_IMPORT_DESCRIPTOR DescriptorTable;
PVOID DelayDescriptorTable;
};
} PH_MAPPED_IMAGE_IMPORTS, *PPH_MAPPED_IMAGE_IMPORTS;
typedef struct _PH_MAPPED_IMAGE_IMPORT_DLL
{
PPH_MAPPED_IMAGE MappedImage;
ULONG Flags;
PSTR Name;
ULONG NumberOfEntries;
union
{
PIMAGE_IMPORT_DESCRIPTOR Descriptor;
PVOID DelayDescriptor;
};
PVOID *LookupTable;
} PH_MAPPED_IMAGE_IMPORT_DLL, *PPH_MAPPED_IMAGE_IMPORT_DLL;
typedef struct _PH_MAPPED_IMAGE_IMPORT_ENTRY
{
PSTR Name;
union
{
USHORT Ordinal;
USHORT NameHint;
};
} PH_MAPPED_IMAGE_IMPORT_ENTRY, *PPH_MAPPED_IMAGE_IMPORT_ENTRY;
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageImports(
_Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,
_In_ PPH_MAPPED_IMAGE MappedImage
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageImportDll(
_In_ PPH_MAPPED_IMAGE_IMPORTS Imports,
_In_ ULONG Index,
_Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageImportEntry(
_In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,
_In_ ULONG Index,
_Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedImageDelayImports(
_Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,
_In_ PPH_MAPPED_IMAGE MappedImage
);
USHORT
NTAPI
PhCheckSum(
_In_ ULONG Sum,
_In_reads_(Count) PUSHORT Buffer,
_In_ ULONG Count
);
PHLIBAPI
ULONG
NTAPI
PhCheckSumMappedImage(
_In_ PPH_MAPPED_IMAGE MappedImage
);
// maplib
struct _PH_MAPPED_ARCHIVE;
typedef struct _PH_MAPPED_ARCHIVE *PPH_MAPPED_ARCHIVE;
typedef enum _PH_MAPPED_ARCHIVE_MEMBER_TYPE
{
NormalArchiveMemberType,
LinkerArchiveMemberType,
LongnamesArchiveMemberType
} PH_MAPPED_ARCHIVE_MEMBER_TYPE;
typedef struct _PH_MAPPED_ARCHIVE_MEMBER
{
PPH_MAPPED_ARCHIVE MappedArchive;
PH_MAPPED_ARCHIVE_MEMBER_TYPE Type;
PSTR Name;
ULONG Size;
PVOID Data;
PIMAGE_ARCHIVE_MEMBER_HEADER Header;
CHAR NameBuffer[20];
} PH_MAPPED_ARCHIVE_MEMBER, *PPH_MAPPED_ARCHIVE_MEMBER;
typedef struct _PH_MAPPED_ARCHIVE
{
PVOID ViewBase;
SIZE_T Size;
PH_MAPPED_ARCHIVE_MEMBER FirstLinkerMember;
PH_MAPPED_ARCHIVE_MEMBER SecondLinkerMember;
PH_MAPPED_ARCHIVE_MEMBER LongnamesMember;
BOOLEAN HasLongnamesMember;
PPH_MAPPED_ARCHIVE_MEMBER FirstStandardMember;
PPH_MAPPED_ARCHIVE_MEMBER LastStandardMember;
} PH_MAPPED_ARCHIVE, *PPH_MAPPED_ARCHIVE;
typedef struct _PH_MAPPED_ARCHIVE_IMPORT_ENTRY
{
PSTR Name;
PSTR DllName;
union
{
USHORT Ordinal;
USHORT NameHint;
};
BYTE Type;
BYTE NameType;
USHORT Machine;
} PH_MAPPED_ARCHIVE_IMPORT_ENTRY, *PPH_MAPPED_ARCHIVE_IMPORT_ENTRY;
PHLIBAPI
NTSTATUS
NTAPI
PhInitializeMappedArchive(
_Out_ PPH_MAPPED_ARCHIVE MappedArchive,
_In_ PVOID ViewBase,
_In_ SIZE_T Size
);
PHLIBAPI
NTSTATUS
NTAPI
PhLoadMappedArchive(
_In_opt_ PWSTR FileName,
_In_opt_ HANDLE FileHandle,
_In_ BOOLEAN ReadOnly,
_Out_ PPH_MAPPED_ARCHIVE MappedArchive
);
PHLIBAPI
NTSTATUS
NTAPI
PhUnloadMappedArchive(
_Inout_ PPH_MAPPED_ARCHIVE MappedArchive
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetNextMappedArchiveMember(
_In_ PPH_MAPPED_ARCHIVE_MEMBER Member,
_Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember
);
PHLIBAPI
BOOLEAN
NTAPI
PhIsMappedArchiveMemberShortFormat(
_In_ PPH_MAPPED_ARCHIVE_MEMBER Member
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetMappedArchiveImportEntry(
_In_ PPH_MAPPED_ARCHIVE_MEMBER Member,
_Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry
);
#ifdef __cplusplus
}
#endif
#endif

11
phlib/include/ph.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _PH_PH_H
#define _PH_PH_H
#pragma once
#include <phbase.h>
#include <phnative.h>
#include <phnativeinl.h>
#include <phutil.h>
#endif

45
phlib/include/phbase.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef _PH_PHBASE_H
#define _PH_PHBASE_H
#pragma once
#ifndef PHLIB_NO_DEFAULT_LIB
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "version.lib")
#endif
// nonstandard extension used : nameless struct/union
#pragma warning(disable: 4201)
// nonstandard extension used : bit field types other than int
#pragma warning(disable: 4214)
// 'function': attributes not present on previous declaration
#pragma warning(disable: 4985)
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#if !defined(_PHLIB_)
#define PHLIBAPI __declspec(dllimport)
#else
#define PHLIBAPI
#endif
#include <phnt_windows.h>
#include <phnt.h>
#include <phsup.h>
#include <ref.h>
#include <queuedlock.h>
#include <stdlib.h>
#include <phconfig.h>
#include <phbasesup.h>
#include <phdata.h>
#endif

3740
phlib/include/phbasesup.h Normal file

File diff suppressed because it is too large Load Diff

109
phlib/include/phconfig.h Normal file
View File

@@ -0,0 +1,109 @@
#ifndef _PH_PHCONFIG_H
#define _PH_PHCONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#define _User_set_
PHLIBAPI extern _User_set_ PVOID PhLibImageBase;
PHLIBAPI extern _User_set_ PWSTR PhApplicationName;
PHLIBAPI extern _User_set_ ULONG PhGlobalDpi;
PHLIBAPI extern PVOID PhHeapHandle;
PHLIBAPI extern RTL_OSVERSIONINFOEXW PhOsVersion;
PHLIBAPI extern SYSTEM_BASIC_INFORMATION PhSystemBasicInformation;
PHLIBAPI extern ULONG WindowsVersion;
PHLIBAPI extern ACCESS_MASK ProcessQueryAccess;
PHLIBAPI extern ACCESS_MASK ProcessAllAccess;
PHLIBAPI extern ACCESS_MASK ThreadQueryAccess;
PHLIBAPI extern ACCESS_MASK ThreadSetAccess;
PHLIBAPI extern ACCESS_MASK ThreadAllAccess;
#define WINDOWS_ANCIENT 0
#define WINDOWS_XP 51
#define WINDOWS_SERVER_2003 52
#define WINDOWS_VISTA 60
#define WINDOWS_7 61
#define WINDOWS_8 62
#define WINDOWS_8_1 63
#define WINDOWS_10 100
#define WINDOWS_NEW MAXLONG
#define WINDOWS_HAS_CONSOLE_HOST (WindowsVersion >= WINDOWS_7)
#define WINDOWS_HAS_CYCLE_TIME (WindowsVersion >= WINDOWS_VISTA)
#define WINDOWS_HAS_IFILEDIALOG (WindowsVersion >= WINDOWS_VISTA)
#define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (WindowsVersion >= WINDOWS_VISTA)
#define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8)
#define WINDOWS_HAS_LIMITED_ACCESS (WindowsVersion >= WINDOWS_VISTA)
#define WINDOWS_HAS_SERVICE_TAGS (WindowsVersion >= WINDOWS_VISTA)
#define WINDOWS_HAS_UAC (WindowsVersion >= WINDOWS_VISTA)
// Debugging
#ifdef DEBUG
#define dprintf(format, ...) DbgPrint(format, __VA_ARGS__)
#else
#define dprintf(format, ...)
#endif
// global
// Initialization flags
// Features
// Imports
#define PHLIB_INIT_MODULE_RESERVED1 0x1
#define PHLIB_INIT_MODULE_RESERVED2 0x2
/** Needed to use work queues. */
#define PHLIB_INIT_MODULE_RESERVED3 0x4
#define PHLIB_INIT_MODULE_RESERVED4 0x8
/** Needed to use file streams. */
#define PHLIB_INIT_MODULE_FILE_STREAM 0x10
/** Needed to use symbol providers. */
#define PHLIB_INIT_MODULE_SYMBOL_PROVIDER 0x20
#define PHLIB_INIT_MODULE_RESERVED5 0x40
PHLIBAPI
NTSTATUS
NTAPI
PhInitializePhLib(
VOID
);
PHLIBAPI
NTSTATUS
NTAPI
PhInitializePhLibEx(
_In_ ULONG Flags,
_In_opt_ SIZE_T HeapReserveSize,
_In_opt_ SIZE_T HeapCommitSize
);
#ifdef _WIN64
FORCEINLINE
BOOLEAN
PhIsExecutingInWow64(
VOID
)
{
return FALSE;
}
#else
PHLIBAPI
BOOLEAN
NTAPI
PhIsExecutingInWow64(
VOID
);
#endif
#ifdef __cplusplus
}
#endif
#endif

60
phlib/include/phdata.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef _PH_PHDATA_H
#define _PH_PHDATA_H
#ifdef __cplusplus
extern "C" {
#endif
// SIDs
extern SID PhSeNobodySid;
extern SID PhSeEveryoneSid;
extern SID PhSeLocalSid;
extern SID PhSeCreatorOwnerSid;
extern SID PhSeCreatorGroupSid;
extern SID PhSeDialupSid;
extern SID PhSeNetworkSid;
extern SID PhSeBatchSid;
extern SID PhSeInteractiveSid;
extern SID PhSeServiceSid;
extern SID PhSeAnonymousLogonSid;
extern SID PhSeProxySid;
extern SID PhSeAuthenticatedUserSid;
extern SID PhSeRestrictedCodeSid;
extern SID PhSeTerminalServerUserSid;
extern SID PhSeRemoteInteractiveLogonSid;
extern SID PhSeLocalSystemSid;
extern SID PhSeLocalServiceSid;
extern SID PhSeNetworkServiceSid;
// Unicode
extern PH_STRINGREF PhUnicodeByteOrderMark;
// Characters
extern BOOLEAN PhCharIsPrintable[256];
extern ULONG PhCharToInteger[256];
extern CHAR PhIntegerToChar[69];
extern CHAR PhIntegerToCharUpper[69];
// CRC32
extern ULONG PhCrc32Table[256];
// Enums
extern WCHAR *PhIoPriorityHintNames[MaxIoPriorityTypes];
extern WCHAR *PhPagePriorityNames[MEMORY_PRIORITY_NORMAL + 1];
extern WCHAR *PhKThreadStateNames[MaximumThreadState];
extern WCHAR *PhKWaitReasonNames[MaximumWaitReason];
#ifdef __cplusplus
}
#endif
#endif

49
phlib/include/phintrnl.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef _PH_PHINTRNL_H
#define _PH_PHINTRNL_H
typedef struct _PHLIB_STATISTICS_BLOCK
{
// basesup
ULONG BaseThreadsCreated;
ULONG BaseThreadsCreateFailed;
ULONG BaseStringBuildersCreated;
ULONG BaseStringBuildersResized;
// ref
ULONG RefObjectsCreated;
ULONG RefObjectsDestroyed;
ULONG RefObjectsAllocated;
ULONG RefObjectsFreed;
ULONG RefObjectsAllocatedFromSmallFreeList;
ULONG RefObjectsFreedToSmallFreeList;
ULONG RefObjectsAllocatedFromTypeFreeList;
ULONG RefObjectsFreedToTypeFreeList;
ULONG RefObjectsDeleteDeferred;
ULONG RefAutoPoolsCreated;
ULONG RefAutoPoolsDestroyed;
ULONG RefAutoPoolsDynamicAllocated;
ULONG RefAutoPoolsDynamicResized;
// queuedlock
ULONG QlBlockSpins;
ULONG QlBlockWaits;
ULONG QlAcquireExclusiveBlocks;
ULONG QlAcquireSharedBlocks;
// workqueue
ULONG WqWorkQueueThreadsCreated;
ULONG WqWorkQueueThreadsCreateFailed;
ULONG WqWorkItemsQueued;
} PHLIB_STATISTICS_BLOCK;
#ifdef DEBUG
extern PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock;
#endif
#ifdef DEBUG
#define PHLIB_INC_STATISTIC(Name) (_InterlockedIncrement(&PhLibStatisticsBlock.Name))
#else
#define PHLIB_INC_STATISTIC(Name)
#endif
#endif

1042
phlib/include/phnative.h Normal file

File diff suppressed because it is too large Load Diff

968
phlib/include/phnativeinl.h Normal file
View File

@@ -0,0 +1,968 @@
#ifndef _PH_PHNATINL_H
#define _PH_PHNATINL_H
#pragma once
// This file contains inlined native API wrapper functions. These functions were previously
// exported, but are now inlined because they are extremely simple wrappers around equivalent native
// API functions.
/**
* Gets basic information for a process.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param BasicInformation A variable which receives the information.
*/
FORCEINLINE
NTSTATUS
PhGetProcessBasicInformation(
_In_ HANDLE ProcessHandle,
_Out_ PPROCESS_BASIC_INFORMATION BasicInformation
)
{
return NtQueryInformationProcess(
ProcessHandle,
ProcessBasicInformation,
BasicInformation,
sizeof(PROCESS_BASIC_INFORMATION),
NULL
);
}
/**
* Gets extended basic information for a process.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param ExtendedBasicInformation A variable which receives the information.
*/
FORCEINLINE
NTSTATUS
PhGetProcessExtendedBasicInformation(
_In_ HANDLE ProcessHandle,
_Out_ PPROCESS_EXTENDED_BASIC_INFORMATION ExtendedBasicInformation
)
{
ExtendedBasicInformation->Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION);
return NtQueryInformationProcess(
ProcessHandle,
ProcessBasicInformation,
ExtendedBasicInformation,
sizeof(PROCESS_EXTENDED_BASIC_INFORMATION),
NULL
);
}
/**
* Gets time information for a process.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param Times A variable which receives the information.
*/
FORCEINLINE
NTSTATUS
PhGetProcessTimes(
_In_ HANDLE ProcessHandle,
_Out_ PKERNEL_USER_TIMES Times
)
{
return NtQueryInformationProcess(
ProcessHandle,
ProcessTimes,
Times,
sizeof(KERNEL_USER_TIMES),
NULL
);
}
/**
* Gets a process' session ID.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param SessionId A variable which receives the process' session ID.
*/
FORCEINLINE
NTSTATUS
PhGetProcessSessionId(
_In_ HANDLE ProcessHandle,
_Out_ PULONG SessionId
)
{
NTSTATUS status;
PROCESS_SESSION_INFORMATION sessionInfo;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessSessionInformation,
&sessionInfo,
sizeof(PROCESS_SESSION_INFORMATION),
NULL
);
if (NT_SUCCESS(status))
{
*SessionId = sessionInfo.SessionId;
}
return status;
}
/**
* Gets whether a process is running under 32-bit emulation.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param IsWow64 A variable which receives a boolean indicating whether the process is 32-bit.
*/
FORCEINLINE
NTSTATUS
PhGetProcessIsWow64(
_In_ HANDLE ProcessHandle,
_Out_ PBOOLEAN IsWow64
)
{
NTSTATUS status;
ULONG_PTR wow64;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessWow64Information,
&wow64,
sizeof(ULONG_PTR),
NULL
);
if (NT_SUCCESS(status))
{
*IsWow64 = !!wow64;
}
return status;
}
/**
* Gets a process' WOW64 PEB address.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param Peb32 A variable which receives the base address of the process' WOW64 PEB. If the process
* is 64-bit, the variable receives NULL.
*/
FORCEINLINE
NTSTATUS
PhGetProcessPeb32(
_In_ HANDLE ProcessHandle,
_Out_ PVOID *Peb32
)
{
NTSTATUS status;
ULONG_PTR wow64;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessWow64Information,
&wow64,
sizeof(ULONG_PTR),
NULL
);
if (NT_SUCCESS(status))
{
*Peb32 = (PVOID)wow64;
}
return status;
}
/**
* Gets whether a process is being debugged.
*
* \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION
* access.
* \param IsBeingDebugged A variable which receives a boolean indicating whether the process is
* being debugged.
*/
FORCEINLINE
NTSTATUS
PhGetProcessIsBeingDebugged(
_In_ HANDLE ProcessHandle,
_Out_ PBOOLEAN IsBeingDebugged
)
{
NTSTATUS status;
PVOID debugPort;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessDebugPort,
&debugPort,
sizeof(PVOID),
NULL
);
if (NT_SUCCESS(status))
{
*IsBeingDebugged = !!debugPort;
}
return status;
}
/**
* Gets a handle to a process' debug object.
*
* \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION
* access.
* \param DebugObjectHandle A variable which receives a handle to the debug object associated with
* the process. You must close the handle when you no longer need it.
*
* \retval STATUS_PORT_NOT_SET The process is not being debugged and has no associated debug object.
*/
FORCEINLINE
NTSTATUS
PhGetProcessDebugObject(
_In_ HANDLE ProcessHandle,
_Out_ PHANDLE DebugObjectHandle
)
{
return NtQueryInformationProcess(
ProcessHandle,
ProcessDebugObjectHandle,
DebugObjectHandle,
sizeof(HANDLE),
NULL
);
}
/**
* Gets a process' no-execute status.
*
* \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION
* access.
* \param ExecuteFlags A variable which receives the no-execute flags.
*/
FORCEINLINE
NTSTATUS
PhGetProcessExecuteFlags(
_In_ HANDLE ProcessHandle,
_Out_ PULONG ExecuteFlags
)
{
return NtQueryInformationProcess(
ProcessHandle,
ProcessExecuteFlags,
ExecuteFlags,
sizeof(ULONG),
NULL
);
}
/**
* Gets a process' I/O priority.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param IoPriority A variable which receives the I/O priority of the process.
*/
FORCEINLINE
NTSTATUS
PhGetProcessIoPriority(
_In_ HANDLE ProcessHandle,
_Out_ IO_PRIORITY_HINT *IoPriority
)
{
return NtQueryInformationProcess(
ProcessHandle,
ProcessIoPriority,
IoPriority,
sizeof(IO_PRIORITY_HINT),
NULL
);
}
/**
* Gets a process' page priority.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param PagePriority A variable which receives the page priority of the process.
*/
FORCEINLINE
NTSTATUS
PhGetProcessPagePriority(
_In_ HANDLE ProcessHandle,
_Out_ PULONG PagePriority
)
{
NTSTATUS status;
PAGE_PRIORITY_INFORMATION pagePriorityInfo;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessPagePriority,
&pagePriorityInfo,
sizeof(PAGE_PRIORITY_INFORMATION),
NULL
);
if (NT_SUCCESS(status))
{
*PagePriority = pagePriorityInfo.PagePriority;
}
return status;
}
/**
* Gets a process' cycle count.
*
* \param ProcessHandle A handle to a process. The handle must have
* PROCESS_QUERY_LIMITED_INFORMATION access.
* \param CycleTime A variable which receives the 64-bit cycle time.
*/
FORCEINLINE
NTSTATUS
PhGetProcessCycleTime(
_In_ HANDLE ProcessHandle,
_Out_ PULONG64 CycleTime
)
{
NTSTATUS status;
PROCESS_CYCLE_TIME_INFORMATION cycleTimeInfo;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessCycleTime,
&cycleTimeInfo,
sizeof(PROCESS_CYCLE_TIME_INFORMATION),
NULL
);
if (!NT_SUCCESS(status))
return status;
*CycleTime = cycleTimeInfo.AccumulatedCycles;
return status;
}
FORCEINLINE
NTSTATUS
PhGetProcessConsoleHostProcessId(
_In_ HANDLE ProcessHandle,
_Out_ PHANDLE ConsoleHostProcessId
)
{
NTSTATUS status;
ULONG_PTR consoleHostProcess;
status = NtQueryInformationProcess(
ProcessHandle,
ProcessConsoleHostProcess,
&consoleHostProcess,
sizeof(ULONG_PTR),
NULL
);
if (!NT_SUCCESS(status))
return status;
*ConsoleHostProcessId = (HANDLE)consoleHostProcess;
return status;
}
/**
* Sets a process' affinity mask.
*
* \param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.
* \param AffinityMask The new affinity mask.
*/
FORCEINLINE
NTSTATUS
PhSetProcessAffinityMask(
_In_ HANDLE ProcessHandle,
_In_ ULONG_PTR AffinityMask
)
{
return NtSetInformationProcess(
ProcessHandle,
ProcessAffinityMask,
&AffinityMask,
sizeof(ULONG_PTR)
);
}
/**
* Sets a process' I/O priority.
*
* \param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access.
* \param IoPriority The new I/O priority.
*/
FORCEINLINE
NTSTATUS
PhSetProcessIoPriority(
_In_ HANDLE ProcessHandle,
_In_ IO_PRIORITY_HINT IoPriority
)
{
return NtSetInformationProcess(
ProcessHandle,
ProcessIoPriority,
&IoPriority,
sizeof(IO_PRIORITY_HINT)
);
}
/**
* Gets basic information for a thread.
*
* \param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION
* access.
* \param BasicInformation A variable which receives the information.
*/
FORCEINLINE
NTSTATUS
PhGetThreadBasicInformation(
_In_ HANDLE ThreadHandle,
_Out_ PTHREAD_BASIC_INFORMATION BasicInformation
)
{
return NtQueryInformationThread(
ThreadHandle,
ThreadBasicInformation,
BasicInformation,
sizeof(THREAD_BASIC_INFORMATION),
NULL
);
}
/**
* Gets a thread's I/O priority.
*
* \param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION
* access.
* \param IoPriority A variable which receives the I/O priority of the thread.
*/
FORCEINLINE
NTSTATUS
PhGetThreadIoPriority(
_In_ HANDLE ThreadHandle,
_Out_ IO_PRIORITY_HINT *IoPriority
)
{
return NtQueryInformationThread(
ThreadHandle,
ThreadIoPriority,
IoPriority,
sizeof(IO_PRIORITY_HINT),
NULL
);
}
/**
* Gets a thread's page priority.
*
* \param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION
* access.
* \param PagePriority A variable which receives the page priority of the thread.
*/
FORCEINLINE
NTSTATUS
PhGetThreadPagePriority(
_In_ HANDLE ThreadHandle,
_Out_ PULONG PagePriority
)
{
NTSTATUS status;
PAGE_PRIORITY_INFORMATION pagePriorityInfo;
status = NtQueryInformationThread(
ThreadHandle,
ThreadPagePriority,
&pagePriorityInfo,
sizeof(PAGE_PRIORITY_INFORMATION),
NULL
);
if (NT_SUCCESS(status))
{
*PagePriority = pagePriorityInfo.PagePriority;
}
return status;
}
/**
* Gets a thread's cycle count.
*
* \param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION
* access.
* \param CycleTime A variable which receives the 64-bit cycle time.
*/
FORCEINLINE
NTSTATUS
PhGetThreadCycleTime(
_In_ HANDLE ThreadHandle,
_Out_ PULONG64 CycleTime
)
{
NTSTATUS status;
THREAD_CYCLE_TIME_INFORMATION cycleTimeInfo;
status = NtQueryInformationThread(
ThreadHandle,
ThreadCycleTime,
&cycleTimeInfo,
sizeof(THREAD_CYCLE_TIME_INFORMATION),
NULL
);
if (!NT_SUCCESS(status))
return status;
*CycleTime = cycleTimeInfo.AccumulatedCycles;
return status;
}
/**
* Sets a thread's affinity mask.
*
* \param ThreadHandle A handle to a thread. The handle must have THREAD_SET_LIMITED_INFORMATION
* access.
* \param AffinityMask The new affinity mask.
*/
FORCEINLINE
NTSTATUS
PhSetThreadAffinityMask(
_In_ HANDLE ThreadHandle,
_In_ ULONG_PTR AffinityMask
)
{
return NtSetInformationThread(
ThreadHandle,
ThreadAffinityMask,
&AffinityMask,
sizeof(ULONG_PTR)
);
}
/**
* Sets a thread's I/O priority.
*
* \param ThreadHandle A handle to a thread. The handle must have THREAD_SET_LIMITED_INFORMATION
* access.
* \param IoPriority The new I/O priority.
*/
FORCEINLINE
NTSTATUS
PhSetThreadIoPriority(
_In_ HANDLE ThreadHandle,
_In_ IO_PRIORITY_HINT IoPriority
)
{
return NtSetInformationThread(
ThreadHandle,
ThreadIoPriority,
&IoPriority,
sizeof(IO_PRIORITY_HINT)
);
}
FORCEINLINE
NTSTATUS
PhGetJobBasicAndIoAccounting(
_In_ HANDLE JobHandle,
_Out_ PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION BasicAndIoAccounting
)
{
return NtQueryInformationJobObject(
JobHandle,
JobObjectBasicAndIoAccountingInformation,
BasicAndIoAccounting,
sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetJobBasicLimits(
_In_ HANDLE JobHandle,
_Out_ PJOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimits
)
{
return NtQueryInformationJobObject(
JobHandle,
JobObjectBasicLimitInformation,
BasicLimits,
sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetJobExtendedLimits(
_In_ HANDLE JobHandle,
_Out_ PJOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimits
)
{
return NtQueryInformationJobObject(
JobHandle,
JobObjectExtendedLimitInformation,
ExtendedLimits,
sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetJobBasicUiRestrictions(
_In_ HANDLE JobHandle,
_Out_ PJOBOBJECT_BASIC_UI_RESTRICTIONS BasicUiRestrictions
)
{
return NtQueryInformationJobObject(
JobHandle,
JobObjectBasicUIRestrictions,
BasicUiRestrictions,
sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS),
NULL
);
}
/**
* Gets a token's session ID.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param SessionId A variable which receives the session ID.
*/
FORCEINLINE
NTSTATUS
PhGetTokenSessionId(
_In_ HANDLE TokenHandle,
_Out_ PULONG SessionId
)
{
ULONG returnLength;
return NtQueryInformationToken(
TokenHandle,
TokenSessionId,
SessionId,
sizeof(ULONG),
&returnLength
);
}
/**
* Gets a token's elevation type.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param ElevationType A variable which receives the elevation type.
*/
FORCEINLINE
NTSTATUS
PhGetTokenElevationType(
_In_ HANDLE TokenHandle,
_Out_ PTOKEN_ELEVATION_TYPE ElevationType
)
{
ULONG returnLength;
return NtQueryInformationToken(
TokenHandle,
TokenElevationType,
ElevationType,
sizeof(TOKEN_ELEVATION_TYPE),
&returnLength
);
}
/**
* Gets whether a token is elevated.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param Elevated A variable which receives a boolean indicating whether the token is elevated.
*/
FORCEINLINE
NTSTATUS
PhGetTokenIsElevated(
_In_ HANDLE TokenHandle,
_Out_ PBOOLEAN Elevated
)
{
NTSTATUS status;
TOKEN_ELEVATION elevation;
ULONG returnLength;
status = NtQueryInformationToken(
TokenHandle,
TokenElevation,
&elevation,
sizeof(TOKEN_ELEVATION),
&returnLength
);
if (NT_SUCCESS(status))
{
*Elevated = !!elevation.TokenIsElevated;
}
return status;
}
/**
* Gets a token's statistics.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param Statistics A variable which receives the token's statistics.
*/
FORCEINLINE
NTSTATUS
PhGetTokenStatistics(
_In_ HANDLE TokenHandle,
_Out_ PTOKEN_STATISTICS Statistics
)
{
ULONG returnLength;
return NtQueryInformationToken(
TokenHandle,
TokenStatistics,
Statistics,
sizeof(TOKEN_STATISTICS),
&returnLength
);
}
/**
* Gets a token's source.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY_SOURCE access.
* \param Source A variable which receives the token's source.
*/
FORCEINLINE
NTSTATUS
PhGetTokenSource(
_In_ HANDLE TokenHandle,
_Out_ PTOKEN_SOURCE Source
)
{
ULONG returnLength;
return NtQueryInformationToken(
TokenHandle,
TokenSource,
Source,
sizeof(TOKEN_SOURCE),
&returnLength
);
}
/**
* Gets a handle to a token's linked token.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param LinkedTokenHandle A variable which receives a handle to the linked token. You must close
* the handle using NtClose() when you no longer need it.
*/
FORCEINLINE
NTSTATUS
PhGetTokenLinkedToken(
_In_ HANDLE TokenHandle,
_Out_ PHANDLE LinkedTokenHandle
)
{
NTSTATUS status;
ULONG returnLength;
TOKEN_LINKED_TOKEN linkedToken;
status = NtQueryInformationToken(
TokenHandle,
TokenLinkedToken,
&linkedToken,
sizeof(TOKEN_LINKED_TOKEN),
&returnLength
);
if (!NT_SUCCESS(status))
return status;
*LinkedTokenHandle = linkedToken.LinkedToken;
return status;
}
/**
* Gets whether virtualization is allowed for a token.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param IsVirtualizationAllowed A variable which receives a boolean indicating whether
* virtualization is allowed for the token.
*/
FORCEINLINE
NTSTATUS
PhGetTokenIsVirtualizationAllowed(
_In_ HANDLE TokenHandle,
_Out_ PBOOLEAN IsVirtualizationAllowed
)
{
NTSTATUS status;
ULONG returnLength;
ULONG virtualizationAllowed;
status = NtQueryInformationToken(
TokenHandle,
TokenVirtualizationAllowed,
&virtualizationAllowed,
sizeof(ULONG),
&returnLength
);
if (!NT_SUCCESS(status))
return status;
*IsVirtualizationAllowed = !!virtualizationAllowed;
return status;
}
/**
* Gets whether virtualization is enabled for a token.
*
* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access.
* \param IsVirtualizationEnabled A variable which receives a boolean indicating whether
* virtualization is enabled for the token.
*/
FORCEINLINE
NTSTATUS
PhGetTokenIsVirtualizationEnabled(
_In_ HANDLE TokenHandle,
_Out_ PBOOLEAN IsVirtualizationEnabled
)
{
NTSTATUS status;
ULONG returnLength;
ULONG virtualizationEnabled;
status = NtQueryInformationToken(
TokenHandle,
TokenVirtualizationEnabled,
&virtualizationEnabled,
sizeof(ULONG),
&returnLength
);
if (!NT_SUCCESS(status))
return status;
*IsVirtualizationEnabled = !!virtualizationEnabled;
return status;
}
FORCEINLINE
NTSTATUS
PhGetEventBasicInformation(
_In_ HANDLE EventHandle,
_Out_ PEVENT_BASIC_INFORMATION BasicInformation
)
{
return NtQueryEvent(
EventHandle,
EventBasicInformation,
BasicInformation,
sizeof(EVENT_BASIC_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetMutantBasicInformation(
_In_ HANDLE MutantHandle,
_Out_ PMUTANT_BASIC_INFORMATION BasicInformation
)
{
return NtQueryMutant(
MutantHandle,
MutantBasicInformation,
BasicInformation,
sizeof(MUTANT_BASIC_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetMutantOwnerInformation(
_In_ HANDLE MutantHandle,
_Out_ PMUTANT_OWNER_INFORMATION OwnerInformation
)
{
return NtQueryMutant(
MutantHandle,
MutantOwnerInformation,
OwnerInformation,
sizeof(MUTANT_OWNER_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetSectionBasicInformation(
_In_ HANDLE SectionHandle,
_Out_ PSECTION_BASIC_INFORMATION BasicInformation
)
{
return NtQuerySection(
SectionHandle,
SectionBasicInformation,
BasicInformation,
sizeof(SECTION_BASIC_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetSemaphoreBasicInformation(
_In_ HANDLE SemaphoreHandle,
_Out_ PSEMAPHORE_BASIC_INFORMATION BasicInformation
)
{
return NtQuerySemaphore(
SemaphoreHandle,
SemaphoreBasicInformation,
BasicInformation,
sizeof(SEMAPHORE_BASIC_INFORMATION),
NULL
);
}
FORCEINLINE
NTSTATUS
PhGetTimerBasicInformation(
_In_ HANDLE TimerHandle,
_Out_ PTIMER_BASIC_INFORMATION BasicInformation
)
{
return NtQueryTimer(
TimerHandle,
TimerBasicInformation,
BasicInformation,
sizeof(TIMER_BASIC_INFORMATION),
NULL
);
}
#endif

139
phlib/include/phnet.h Normal file
View File

@@ -0,0 +1,139 @@
#ifndef _PH_PHNET_H
#define _PH_PHNET_H
#include <inaddr.h>
#include <in6addr.h>
#define PH_IPV4_NETWORK_TYPE 0x1
#define PH_IPV6_NETWORK_TYPE 0x2
#define PH_NETWORK_TYPE_MASK 0x3
#define PH_TCP_PROTOCOL_TYPE 0x10
#define PH_UDP_PROTOCOL_TYPE 0x20
#define PH_PROTOCOL_TYPE_MASK 0x30
#define PH_NO_NETWORK_PROTOCOL 0x0
#define PH_TCP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE)
#define PH_TCP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE)
#define PH_UDP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE)
#define PH_UDP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE)
typedef struct _PH_IP_ADDRESS
{
ULONG Type;
union
{
ULONG Ipv4;
struct in_addr InAddr;
UCHAR Ipv6[16];
struct in6_addr In6Addr;
};
} PH_IP_ADDRESS, *PPH_IP_ADDRESS;
FORCEINLINE BOOLEAN PhEqualIpAddress(
_In_ PPH_IP_ADDRESS Address1,
_In_ PPH_IP_ADDRESS Address2
)
{
if ((Address1->Type | Address2->Type) == 0) // don't check addresses if both are invalid
return TRUE;
if (Address1->Type != Address2->Type)
return FALSE;
if (Address1->Type == PH_IPV4_NETWORK_TYPE)
{
return Address1->Ipv4 == Address2->Ipv4;
}
else
{
#ifdef _WIN64
return
*(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) &&
*(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8);
#else
return
*(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) &&
*(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) &&
*(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) &&
*(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12);
#endif
}
}
FORCEINLINE ULONG PhHashIpAddress(
_In_ PPH_IP_ADDRESS Address
)
{
ULONG hash = 0;
if (Address->Type == 0)
return 0;
hash = Address->Type | (Address->Type << 16);
if (Address->Type == PH_IPV4_NETWORK_TYPE)
{
hash ^= Address->Ipv4;
}
else
{
hash += *(PULONG)(Address->Ipv6);
hash ^= *(PULONG)(Address->Ipv6 + 4);
hash += *(PULONG)(Address->Ipv6 + 8);
hash ^= *(PULONG)(Address->Ipv6 + 12);
}
return hash;
}
FORCEINLINE BOOLEAN PhIsNullIpAddress(
_In_ PPH_IP_ADDRESS Address
)
{
if (Address->Type == 0)
{
return TRUE;
}
else if (Address->Type == PH_IPV4_NETWORK_TYPE)
{
return Address->Ipv4 == 0;
}
else if (Address->Type == PH_IPV6_NETWORK_TYPE)
{
#ifdef _WIN64
return (*(PULONG64)(Address->Ipv6) | *(PULONG64)(Address->Ipv6 + 8)) == 0;
#else
return (*(PULONG)(Address->Ipv6) | *(PULONG)(Address->Ipv6 + 4) |
*(PULONG)(Address->Ipv6 + 8) | *(PULONG)(Address->Ipv6 + 12)) == 0;
#endif
}
else
{
return TRUE;
}
}
typedef struct _PH_IP_ENDPOINT
{
PH_IP_ADDRESS Address;
ULONG Port;
} PH_IP_ENDPOINT, *PPH_IP_ENDPOINT;
FORCEINLINE BOOLEAN PhEqualIpEndpoint(
_In_ PPH_IP_ENDPOINT Endpoint1,
_In_ PPH_IP_ENDPOINT Endpoint2
)
{
return
PhEqualIpAddress(&Endpoint1->Address, &Endpoint2->Address) &&
Endpoint1->Port == Endpoint2->Port;
}
FORCEINLINE ULONG PhHashIpEndpoint(
_In_ PPH_IP_ENDPOINT Endpoint
)
{
return PhHashIpAddress(&Endpoint->Address) ^ Endpoint->Port;
}
#endif

546
phlib/include/phsup.h Normal file
View File

@@ -0,0 +1,546 @@
#ifndef _PH_PHSUP_H
#define _PH_PHSUP_H
// This header file provides some useful definitions specific to phlib.
#include <intrin.h>
#include <wchar.h>
#include <assert.h>
#include <stdio.h>
// Memory
#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))
#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))
#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1))
#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align))
#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type))
#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type))
#define PAGE_SIZE 0x1000
#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024)
// Exceptions
#define PhRaiseStatus(Status) RtlRaiseStatus(Status)
#define SIMPLE_EXCEPTION_FILTER(Condition) \
((Condition) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
// Compiler
#ifdef DEBUG
#define ASSUME_ASSERT(Expression) assert(Expression)
#define ASSUME_NO_DEFAULT assert(FALSE)
#else
#define ASSUME_ASSERT(Expression) __assume(Expression)
#define ASSUME_NO_DEFAULT __assume(FALSE)
#endif
// Time
#define PH_TICKS_PER_NS ((LONG64)1 * 10)
#define PH_TICKS_PER_MS (PH_TICKS_PER_NS * 1000)
#define PH_TICKS_PER_SEC (PH_TICKS_PER_MS * 1000)
#define PH_TICKS_PER_MIN (PH_TICKS_PER_SEC * 60)
#define PH_TICKS_PER_HOUR (PH_TICKS_PER_MIN * 60)
#define PH_TICKS_PER_DAY (PH_TICKS_PER_HOUR * 24)
#define PH_TICKS_PARTIAL_MS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MS) % 1000)
#define PH_TICKS_PARTIAL_SEC(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_SEC) % 60)
#define PH_TICKS_PARTIAL_MIN(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MIN) % 60)
#define PH_TICKS_PARTIAL_HOURS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_HOUR) % 24)
#define PH_TICKS_PARTIAL_DAYS(Ticks) ((ULONG64)(Ticks) / PH_TICKS_PER_DAY)
#define PH_TIMEOUT_MS PH_TICKS_PER_MS
#define PH_TIMEOUT_SEC PH_TICKS_PER_SEC
// Annotations
/**
* Indicates that a function assumes the specified number of references are available for the
* object.
*
* \remarks Usually functions reference objects if they store them for later usage; this annotation
* specifies that the caller must supply these extra references itself. In effect these references
* are "transferred" to the function and must not be used. E.g. if you create an object and
* immediately call a function with _Assume_refs_(1), you may no longer use the object since that
* one reference you held is no longer yours.
*/
#define _Assume_refs_(count)
#define _Callback_
/**
* Indicates that a function may raise a software exception.
*
* \remarks Do not use this annotation for temporary usages of exceptions, e.g. unimplemented
* functions.
*/
#define _May_raise_
/**
* Indicates that a function requires the specified value to be aligned at the specified number of
* bytes.
*/
#define _Needs_align_(align)
// Casts
// Zero extension and sign extension macros
#define C_1uTo2(x) ((unsigned short)(unsigned char)(x))
#define C_1sTo2(x) ((unsigned short)(signed char)(x))
#define C_1uTo4(x) ((unsigned int)(unsigned char)(x))
#define C_1sTo4(x) ((unsigned int)(signed char)(x))
#define C_2uTo4(x) ((unsigned int)(unsigned short)(x))
#define C_2sTo4(x) ((unsigned int)(signed short)(x))
#define C_4uTo8(x) ((unsigned __int64)(unsigned int)(x))
#define C_4sTo8(x) ((unsigned __int64)(signed int)(x))
// Sorting
typedef enum _PH_SORT_ORDER
{
NoSortOrder = 0,
AscendingSortOrder,
DescendingSortOrder
} PH_SORT_ORDER, *PPH_SORT_ORDER;
FORCEINLINE LONG PhModifySort(
_In_ LONG Result,
_In_ PH_SORT_ORDER Order
)
{
if (Order == AscendingSortOrder)
return Result;
else if (Order == DescendingSortOrder)
return -Result;
else
return Result;
}
#define PH_BUILTIN_COMPARE(value1, value2) \
if (value1 > value2) \
return 1; \
else if (value1 < value2) \
return -1; \
\
return 0
FORCEINLINE int charcmp(
_In_ signed char value1,
_In_ signed char value2
)
{
return C_1sTo4(value1 - value2);
}
FORCEINLINE int ucharcmp(
_In_ unsigned char value1,
_In_ unsigned char value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int shortcmp(
_In_ signed short value1,
_In_ signed short value2
)
{
return C_2sTo4(value1 - value2);
}
FORCEINLINE int ushortcmp(
_In_ unsigned short value1,
_In_ unsigned short value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int intcmp(
_In_ int value1,
_In_ int value2
)
{
return value1 - value2;
}
FORCEINLINE int uintcmp(
_In_ unsigned int value1,
_In_ unsigned int value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int int64cmp(
_In_ __int64 value1,
_In_ __int64 value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int uint64cmp(
_In_ unsigned __int64 value1,
_In_ unsigned __int64 value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int intptrcmp(
_In_ LONG_PTR value1,
_In_ LONG_PTR value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int uintptrcmp(
_In_ ULONG_PTR value1,
_In_ ULONG_PTR value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int singlecmp(
_In_ float value1,
_In_ float value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int doublecmp(
_In_ double value1,
_In_ double value2
)
{
PH_BUILTIN_COMPARE(value1, value2);
}
FORCEINLINE int wcsicmp2(
_In_opt_ PWSTR Value1,
_In_opt_ PWSTR Value2
)
{
if (Value1 && Value2)
return _wcsicmp(Value1, Value2);
else if (!Value1)
return !Value2 ? 0 : -1;
else
return 1;
}
typedef int (__cdecl *PC_COMPARE_FUNCTION)(void *, const void *, const void *);
// Synchronization
#ifndef _WIN64
#ifndef _InterlockedCompareExchangePointer
void *_InterlockedCompareExchangePointer(
void *volatile *Destination,
void *Exchange,
void *Comparand
);
#endif
#if (_MSC_VER < 1900)
#ifndef _InterlockedExchangePointer
FORCEINLINE void *_InterlockedExchangePointer(
void *volatile *Destination,
void *Exchange
)
{
return (PVOID)_InterlockedExchange(
(PLONG_PTR)Destination,
(LONG_PTR)Exchange
);
}
#endif
#endif
#endif
FORCEINLINE LONG_PTR _InterlockedExchangeAddPointer(
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend,
_In_ LONG_PTR Value
)
{
#ifdef _WIN64
return (LONG_PTR)_InterlockedExchangeAdd64((PLONG64)Addend, (LONG64)Value);
#else
return (LONG_PTR)_InterlockedExchangeAdd((PLONG)Addend, (LONG)Value);
#endif
}
FORCEINLINE LONG_PTR _InterlockedIncrementPointer(
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend
)
{
#ifdef _WIN64
return (LONG_PTR)_InterlockedIncrement64((PLONG64)Addend);
#else
return (LONG_PTR)_InterlockedIncrement((PLONG)Addend);
#endif
}
FORCEINLINE LONG_PTR _InterlockedDecrementPointer(
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend
)
{
#ifdef _WIN64
return (LONG_PTR)_InterlockedDecrement64((PLONG64)Addend);
#else
return (LONG_PTR)_InterlockedDecrement((PLONG)Addend);
#endif
}
FORCEINLINE BOOLEAN _InterlockedBitTestAndResetPointer(
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,
_In_ LONG_PTR Bit
)
{
#ifdef _WIN64
return _interlockedbittestandreset64((PLONG64)Base, (LONG64)Bit);
#else
return _interlockedbittestandreset((PLONG)Base, (LONG)Bit);
#endif
}
FORCEINLINE BOOLEAN _InterlockedBitTestAndSetPointer(
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,
_In_ LONG_PTR Bit
)
{
#ifdef _WIN64
return _interlockedbittestandset64((PLONG64)Base, (LONG64)Bit);
#else
return _interlockedbittestandset((PLONG)Base, (LONG)Bit);
#endif
}
FORCEINLINE BOOLEAN _InterlockedIncrementNoZero(
_Inout_ _Interlocked_operand_ LONG volatile *Addend
)
{
LONG value;
LONG newValue;
value = *Addend;
while (TRUE)
{
if (value == 0)
return FALSE;
if ((newValue = _InterlockedCompareExchange(
Addend,
value + 1,
value
)) == value)
{
return TRUE;
}
value = newValue;
}
}
FORCEINLINE BOOLEAN _InterlockedIncrementPositive(
_Inout_ _Interlocked_operand_ LONG volatile *Addend
)
{
LONG value;
LONG newValue;
value = *Addend;
while (TRUE)
{
if (value <= 0)
return FALSE;
if ((newValue = _InterlockedCompareExchange(
Addend,
value + 1,
value
)) == value)
{
return TRUE;
}
value = newValue;
}
}
// Strings
#define PH_INT32_STR_LEN 12
#define PH_INT32_STR_LEN_1 (PH_INT32_STR_LEN + 1)
#define PH_INT64_STR_LEN 50
#define PH_INT64_STR_LEN_1 (PH_INT64_STR_LEN + 1)
#define PH_PTR_STR_LEN 24
#define PH_PTR_STR_LEN_1 (PH_PTR_STR_LEN + 1)
FORCEINLINE VOID PhPrintInt32(
_Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination,
_In_ LONG Int32
)
{
_ltow(Int32, Destination, 10);
}
FORCEINLINE VOID PhPrintUInt32(
_Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination,
_In_ ULONG UInt32
)
{
_ultow(UInt32, Destination, 10);
}
FORCEINLINE VOID PhPrintInt64(
_Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination,
_In_ LONG64 Int64
)
{
_i64tow(Int64, Destination, 10);
}
FORCEINLINE VOID PhPrintUInt64(
_Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination,
_In_ ULONG64 UInt64
)
{
_ui64tow(UInt64, Destination, 10);
}
FORCEINLINE VOID PhPrintPointer(
_Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination,
_In_ PVOID Pointer
)
{
Destination[0] = '0';
Destination[1] = 'x';
#ifdef _WIN64
_ui64tow((ULONG64)Pointer, &Destination[2], 16);
#else
_ultow((ULONG)Pointer, &Destination[2], 16);
#endif
}
// Misc.
FORCEINLINE ULONG PhCountBits(
_In_ ULONG Value
)
{
ULONG count = 0;
while (Value)
{
count++;
Value &= Value - 1;
}
return count;
}
FORCEINLINE ULONG PhRoundNumber(
_In_ ULONG Value,
_In_ ULONG Granularity
)
{
return (Value + Granularity / 2) / Granularity * Granularity;
}
FORCEINLINE ULONG PhMultiplyDivide(
_In_ ULONG Number,
_In_ ULONG Numerator,
_In_ ULONG Denominator
)
{
return (ULONG)(((ULONG64)Number * (ULONG64)Numerator + Denominator / 2) / (ULONG64)Denominator);
}
FORCEINLINE LONG PhMultiplyDivideSigned(
_In_ LONG Number,
_In_ ULONG Numerator,
_In_ ULONG Denominator
)
{
if (Number >= 0)
return PhMultiplyDivide(Number, Numerator, Denominator);
else
return -(LONG)PhMultiplyDivide(-Number, Numerator, Denominator);
}
FORCEINLINE VOID PhProbeAddress(
_In_ PVOID UserAddress,
_In_ SIZE_T UserLength,
_In_ PVOID BufferAddress,
_In_ SIZE_T BufferLength,
_In_ ULONG Alignment
)
{
if (UserLength != 0)
{
if (((ULONG_PTR)UserAddress & (Alignment - 1)) != 0)
PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
if (
((ULONG_PTR)UserAddress + UserLength < (ULONG_PTR)UserAddress) ||
((ULONG_PTR)UserAddress < (ULONG_PTR)BufferAddress) ||
((ULONG_PTR)UserAddress + UserLength > (ULONG_PTR)BufferAddress + BufferLength)
)
PhRaiseStatus(STATUS_ACCESS_VIOLATION);
}
}
FORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds(
_Out_ PLARGE_INTEGER Timeout,
_In_ ULONG Milliseconds
)
{
if (Milliseconds == INFINITE)
return NULL;
Timeout->QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS);
return Timeout;
}
FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus()
{
ULONG win32Result;
// This is needed because NTSTATUS_FROM_WIN32 uses the argument multiple times.
win32Result = GetLastError();
return NTSTATUS_FROM_WIN32(win32Result);
}
FORCEINLINE PVOID PhGetModuleProcAddress(
_In_ PWSTR ModuleName,
_In_ PSTR ProcName
)
{
HMODULE module;
module = GetModuleHandle(ModuleName);
if (module)
return GetProcAddress(module, ProcName);
else
return NULL;
}
#endif

1049
phlib/include/phutil.h Normal file

File diff suppressed because it is too large Load Diff

139
phlib/include/provider.h Normal file
View File

@@ -0,0 +1,139 @@
#ifndef _PH_PROVIDER_H
#define _PH_PROVIDER_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(DEBUG)
extern PPH_LIST PhDbgProviderList;
extern PH_QUEUED_LOCK PhDbgProviderListLock;
#endif
typedef enum _PH_PROVIDER_THREAD_STATE
{
ProviderThreadRunning,
ProviderThreadStopped,
ProviderThreadStopping
} PH_PROVIDER_THREAD_STATE;
typedef VOID (NTAPI *PPH_PROVIDER_FUNCTION)(
_In_ PVOID Object
);
struct _PH_PROVIDER_THREAD;
typedef struct _PH_PROVIDER_THREAD *PPH_PROVIDER_THREAD;
typedef struct _PH_PROVIDER_REGISTRATION
{
LIST_ENTRY ListEntry;
PPH_PROVIDER_THREAD ProviderThread;
PPH_PROVIDER_FUNCTION Function;
PVOID Object;
ULONG RunId;
BOOLEAN Enabled;
BOOLEAN Unregistering;
BOOLEAN Boosting;
} PH_PROVIDER_REGISTRATION, *PPH_PROVIDER_REGISTRATION;
typedef struct _PH_PROVIDER_THREAD
{
HANDLE ThreadHandle;
HANDLE TimerHandle;
ULONG Interval;
PH_PROVIDER_THREAD_STATE State;
PH_QUEUED_LOCK Lock;
LIST_ENTRY ListHead;
ULONG BoostCount;
} PH_PROVIDER_THREAD, *PPH_PROVIDER_THREAD;
PHLIBAPI
VOID
NTAPI
PhInitializeProviderThread(
_Out_ PPH_PROVIDER_THREAD ProviderThread,
_In_ ULONG Interval
);
PHLIBAPI
VOID
NTAPI
PhDeleteProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread
);
PHLIBAPI
VOID
NTAPI
PhStartProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread
);
PHLIBAPI
VOID
NTAPI
PhStopProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread
);
PHLIBAPI
VOID
NTAPI
PhSetIntervalProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread,
_In_ ULONG Interval
);
PHLIBAPI
VOID
NTAPI
PhRegisterProvider(
_Inout_ PPH_PROVIDER_THREAD ProviderThread,
_In_ PPH_PROVIDER_FUNCTION Function,
_In_opt_ PVOID Object,
_Out_ PPH_PROVIDER_REGISTRATION Registration
);
PHLIBAPI
VOID
NTAPI
PhUnregisterProvider(
_Inout_ PPH_PROVIDER_REGISTRATION Registration
);
PHLIBAPI
BOOLEAN
NTAPI
PhBoostProvider(
_Inout_ PPH_PROVIDER_REGISTRATION Registration,
_Out_opt_ PULONG FutureRunId
);
PHLIBAPI
ULONG
NTAPI
PhGetRunIdProvider(
_In_ PPH_PROVIDER_REGISTRATION Registration
);
PHLIBAPI
BOOLEAN
NTAPI
PhGetEnabledProvider(
_In_ PPH_PROVIDER_REGISTRATION Registration
);
PHLIBAPI
VOID
NTAPI
PhSetEnabledProvider(
_Inout_ PPH_PROVIDER_REGISTRATION Registration,
_In_ BOOLEAN Enabled
);
#ifdef __cplusplus
}
#endif
#endif

349
phlib/include/queuedlock.h Normal file
View File

@@ -0,0 +1,349 @@
#ifndef _PH_QUEUEDLOCK_H
#define _PH_QUEUEDLOCK_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1)
#define PH_QUEUED_LOCK_OWNED_SHIFT 0
#define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2)
// Valid only if Waiters = 0
#define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4)
#define PH_QUEUED_LOCK_SHARED_SHIFT 2
// Valid only if Waiters = 1
#define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4)
#define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)
#define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf)
#define PhGetQueuedLockSharedOwners(Value) \
((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT)
#define PhGetQueuedLockWaitBlock(Value) \
((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS))
typedef struct _PH_QUEUED_LOCK
{
ULONG_PTR Value;
} PH_QUEUED_LOCK, *PPH_QUEUED_LOCK;
#define PH_QUEUED_LOCK_INIT { 0 }
#define PH_QUEUED_WAITER_EXCLUSIVE 0x1
#define PH_QUEUED_WAITER_SPINNING 0x2
#define PH_QUEUED_WAITER_SPINNING_SHIFT 1
typedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK
{
/** A pointer to the next wait block, i.e. the wait block pushed onto the list before this one. */
struct _PH_QUEUED_WAIT_BLOCK *Next;
/**
* A pointer to the previous wait block, i.e. the wait block pushed onto the list after this
* one.
*/
struct _PH_QUEUED_WAIT_BLOCK *Previous;
/** A pointer to the last wait block, i.e. the first waiter pushed onto the list. */
struct _PH_QUEUED_WAIT_BLOCK *Last;
ULONG SharedOwners;
ULONG Flags;
} PH_QUEUED_WAIT_BLOCK, *PPH_QUEUED_WAIT_BLOCK;
BOOLEAN PhQueuedLockInitialization(
VOID
);
// Queued lock
FORCEINLINE
VOID
PhInitializeQueuedLock(
_Out_ PPH_QUEUED_LOCK QueuedLock
)
{
QueuedLock->Value = 0;
}
PHLIBAPI
VOID
FASTCALL
PhfAcquireQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
);
_Acquires_exclusive_lock_(*QueuedLock)
FORCEINLINE
VOID
PhAcquireQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
if (_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
{
// Owned bit was already set. Slow path.
PhfAcquireQueuedLockExclusive(QueuedLock);
}
}
PHLIBAPI
VOID
FASTCALL
PhfAcquireQueuedLockShared(
_Inout_ PPH_QUEUED_LOCK QueuedLock
);
_Acquires_shared_lock_(*QueuedLock)
FORCEINLINE
VOID
PhAcquireQueuedLockShared(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&QueuedLock->Value,
(PVOID)(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC),
(PVOID)0
) != 0)
{
PhfAcquireQueuedLockShared(QueuedLock);
}
}
_When_(return != 0, _Acquires_exclusive_lock_(*QueuedLock))
FORCEINLINE
BOOLEAN
PhTryAcquireQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
{
return TRUE;
}
else
{
return FALSE;
}
}
PHLIBAPI
VOID
FASTCALL
PhfReleaseQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
);
PHLIBAPI
VOID
FASTCALL
PhfWakeForReleaseQueuedLock(
_Inout_ PPH_QUEUED_LOCK QueuedLock,
_In_ ULONG_PTR Value
);
_Releases_exclusive_lock_(*QueuedLock)
FORCEINLINE
VOID
PhReleaseQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
ULONG_PTR value;
value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED);
if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) == PH_QUEUED_LOCK_WAITERS)
{
PhfWakeForReleaseQueuedLock(QueuedLock, value - PH_QUEUED_LOCK_OWNED);
}
}
PHLIBAPI
VOID
FASTCALL
PhfReleaseQueuedLockShared(
_Inout_ PPH_QUEUED_LOCK QueuedLock
);
_Releases_shared_lock_(*QueuedLock)
FORCEINLINE
VOID
PhReleaseQueuedLockShared(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
ULONG_PTR value;
value = PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC;
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&QueuedLock->Value,
(PVOID)0,
(PVOID)value
) != value)
{
PhfReleaseQueuedLockShared(QueuedLock);
}
}
FORCEINLINE
VOID
PhAcquireReleaseQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
BOOLEAN owned;
MemoryBarrier();
owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);
MemoryBarrier();
if (owned)
{
PhAcquireQueuedLockExclusive(QueuedLock);
PhReleaseQueuedLockExclusive(QueuedLock);
}
}
FORCEINLINE
BOOLEAN
PhTryAcquireReleaseQueuedLockExclusive(
_Inout_ PPH_QUEUED_LOCK QueuedLock
)
{
BOOLEAN owned;
// Need two memory barriers because we don't want the compiler re-ordering the following check
// in either direction.
MemoryBarrier();
owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);
MemoryBarrier();
return owned;
}
// Condition variable
typedef struct _PH_QUEUED_LOCK PH_CONDITION, *PPH_CONDITION;
#define PH_CONDITION_INIT PH_QUEUED_LOCK_INIT
FORCEINLINE
VOID
PhInitializeCondition(
_Out_ PPH_CONDITION Condition
)
{
PhInitializeQueuedLock(Condition);
}
#define PhPulseCondition PhfPulseCondition
PHLIBAPI
VOID
FASTCALL
PhfPulseCondition(
_Inout_ PPH_CONDITION Condition
);
#define PhPulseAllCondition PhfPulseAllCondition
PHLIBAPI
VOID
FASTCALL
PhfPulseAllCondition(
_Inout_ PPH_CONDITION Condition
);
#define PhWaitForCondition PhfWaitForCondition
PHLIBAPI
VOID
FASTCALL
PhfWaitForCondition(
_Inout_ PPH_CONDITION Condition,
_Inout_ PPH_QUEUED_LOCK Lock,
_In_opt_ PLARGE_INTEGER Timeout
);
#define PH_CONDITION_WAIT_QUEUED_LOCK 0x1
#define PH_CONDITION_WAIT_CRITICAL_SECTION 0x2
#define PH_CONDITION_WAIT_FAST_LOCK 0x4
#define PH_CONDITION_WAIT_LOCK_TYPE_MASK 0xfff
#define PH_CONDITION_WAIT_SHARED 0x1000
#define PH_CONDITION_WAIT_SPIN 0x2000
#define PhWaitForConditionEx PhfWaitForConditionEx
PHLIBAPI
VOID
FASTCALL
PhfWaitForConditionEx(
_Inout_ PPH_CONDITION Condition,
_Inout_ PVOID Lock,
_In_ ULONG Flags,
_In_opt_ PLARGE_INTEGER Timeout
);
// Wake event
typedef struct _PH_QUEUED_LOCK PH_WAKE_EVENT, *PPH_WAKE_EVENT;
#define PH_WAKE_EVENT_INIT PH_QUEUED_LOCK_INIT
FORCEINLINE
VOID
PhInitializeWakeEvent(
_Out_ PPH_WAKE_EVENT WakeEvent
)
{
PhInitializeQueuedLock(WakeEvent);
}
#define PhQueueWakeEvent PhfQueueWakeEvent
PHLIBAPI
VOID
FASTCALL
PhfQueueWakeEvent(
_Inout_ PPH_WAKE_EVENT WakeEvent,
_Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock
);
PHLIBAPI
VOID
FASTCALL
PhfSetWakeEvent(
_Inout_ PPH_WAKE_EVENT WakeEvent,
_Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock
);
FORCEINLINE
VOID
PhSetWakeEvent(
_Inout_ PPH_WAKE_EVENT WakeEvent,
_Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock
)
{
// The wake event is similar to a synchronization event in that it does not have thread-safe
// pulsing; we can simply skip the function call if there's nothing to wake. However, if we're
// cancelling a wait (WaitBlock != NULL) we need to make the call.
if (WakeEvent->Value || WaitBlock)
PhfSetWakeEvent(WakeEvent, WaitBlock);
}
#define PhWaitForWakeEvent PhfWaitForWakeEvent
PHLIBAPI
NTSTATUS
FASTCALL
PhfWaitForWakeEvent(
_Inout_ PPH_WAKE_EVENT WakeEvent,
_Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,
_In_ BOOLEAN Spin,
_In_opt_ PLARGE_INTEGER Timeout
);
#ifdef __cplusplus
}
#endif
#endif

309
phlib/include/ref.h Normal file
View File

@@ -0,0 +1,309 @@
/*
* Process Hacker -
* internal object manager
*
* Copyright (C) 2009-2016 wj32
*
* 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/>.
*/
#ifndef _PH_REF_H
#define _PH_REF_H
#ifdef __cplusplus
extern "C" {
#endif
// Configuration
#define PH_OBJECT_SMALL_OBJECT_SIZE 48
#define PH_OBJECT_SMALL_OBJECT_COUNT 512
// Object type flags
#define PH_OBJECT_TYPE_USE_FREE_LIST 0x00000001
#define PH_OBJECT_TYPE_VALID_FLAGS 0x00000001
// Object type callbacks
/**
* The delete procedure for an object type, called when an object of the type is being freed.
*
* \param Object A pointer to the object being freed.
* \param Flags Reserved.
*/
typedef VOID (NTAPI *PPH_TYPE_DELETE_PROCEDURE)(
_In_ PVOID Object,
_In_ ULONG Flags
);
struct _PH_OBJECT_TYPE;
typedef struct _PH_OBJECT_TYPE *PPH_OBJECT_TYPE;
struct _PH_QUEUED_LOCK;
typedef struct _PH_QUEUED_LOCK PH_QUEUED_LOCK, *PPH_QUEUED_LOCK;
#ifdef DEBUG
typedef VOID (NTAPI *PPH_CREATE_OBJECT_HOOK)(
_In_ PVOID Object,
_In_ SIZE_T Size,
_In_ ULONG Flags,
_In_ PPH_OBJECT_TYPE ObjectType
);
#endif
typedef struct _PH_OBJECT_TYPE_PARAMETERS
{
SIZE_T FreeListSize;
ULONG FreeListCount;
} PH_OBJECT_TYPE_PARAMETERS, *PPH_OBJECT_TYPE_PARAMETERS;
typedef struct _PH_OBJECT_TYPE_INFORMATION
{
PWSTR Name;
ULONG NumberOfObjects;
USHORT Flags;
UCHAR TypeIndex;
UCHAR Reserved;
} PH_OBJECT_TYPE_INFORMATION, *PPH_OBJECT_TYPE_INFORMATION;
extern PPH_OBJECT_TYPE PhObjectTypeObject;
extern PPH_OBJECT_TYPE PhAllocType;
#ifdef DEBUG
extern LIST_ENTRY PhDbgObjectListHead;
extern PH_QUEUED_LOCK PhDbgObjectListLock;
extern PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook;
#endif
NTSTATUS PhRefInitialization(
VOID
);
_May_raise_
PHLIBAPI
PVOID
NTAPI
PhCreateObject(
_In_ SIZE_T ObjectSize,
_In_ PPH_OBJECT_TYPE ObjectType
);
PHLIBAPI
PVOID
NTAPI
PhReferenceObject(
_In_ PVOID Object
);
_May_raise_
PHLIBAPI
PVOID
NTAPI
PhReferenceObjectEx(
_In_ PVOID Object,
_In_ LONG RefCount
);
PHLIBAPI
PVOID
NTAPI
PhReferenceObjectSafe(
_In_ PVOID Object
);
PHLIBAPI
VOID
NTAPI
PhDereferenceObject(
_In_ PVOID Object
);
PHLIBAPI
VOID
NTAPI
PhDereferenceObjectDeferDelete(
_In_ PVOID Object
);
_May_raise_
PHLIBAPI
VOID
NTAPI
PhDereferenceObjectEx(
_In_ PVOID Object,
_In_ LONG RefCount,
_In_ BOOLEAN DeferDelete
);
PHLIBAPI
PPH_OBJECT_TYPE
NTAPI
PhGetObjectType(
_In_ PVOID Object
);
PHLIBAPI
PPH_OBJECT_TYPE
NTAPI
PhCreateObjectType(
_In_ PWSTR Name,
_In_ ULONG Flags,
_In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure
);
PHLIBAPI
PPH_OBJECT_TYPE
NTAPI
PhCreateObjectTypeEx(
_In_ PWSTR Name,
_In_ ULONG Flags,
_In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure,
_In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters
);
PHLIBAPI
VOID
NTAPI
PhGetObjectTypeInformation(
_In_ PPH_OBJECT_TYPE ObjectType,
_Out_ PPH_OBJECT_TYPE_INFORMATION Information
);
PHLIBAPI
PVOID
NTAPI
PhCreateAlloc(
_In_ SIZE_T Size
);
// Object reference functions
FORCEINLINE
VOID
PhSwapReference(
_Inout_ PVOID *ObjectReference,
_In_opt_ PVOID NewObject
)
{
PVOID oldObject;
oldObject = *ObjectReference;
*ObjectReference = NewObject;
if (NewObject) PhReferenceObject(NewObject);
if (oldObject) PhDereferenceObject(oldObject);
}
FORCEINLINE
VOID
PhMoveReference(
_Inout_ PVOID *ObjectReference,
_In_opt_ _Assume_refs_(1) PVOID NewObject
)
{
PVOID oldObject;
oldObject = *ObjectReference;
*ObjectReference = NewObject;
if (oldObject) PhDereferenceObject(oldObject);
}
FORCEINLINE
VOID
PhSetReference(
_Out_ PVOID *ObjectReference,
_In_opt_ PVOID NewObject
)
{
*ObjectReference = NewObject;
if (NewObject) PhReferenceObject(NewObject);
}
FORCEINLINE
VOID
PhClearReference(
_Inout_ PVOID *ObjectReference
)
{
PhMoveReference(ObjectReference, NULL);
}
// Auto-dereference pool
/** The size of the static array in an auto-release pool. */
#define PH_AUTO_POOL_STATIC_SIZE 64
/** The maximum size of the dynamic array for it to be kept after the auto-release pool is drained. */
#define PH_AUTO_POOL_DYNAMIC_BIG_SIZE 256
/**
* An auto-dereference pool can be used for semi-automatic reference counting. Batches of objects
* are dereferenced at a certain time.
*
* This object is not thread-safe and cannot be used across thread boundaries. Always store them as
* local variables.
*/
typedef struct _PH_AUTO_POOL
{
ULONG StaticCount;
PVOID StaticObjects[PH_AUTO_POOL_STATIC_SIZE];
ULONG DynamicCount;
ULONG DynamicAllocated;
PVOID *DynamicObjects;
struct _PH_AUTO_POOL *NextPool;
} PH_AUTO_POOL, *PPH_AUTO_POOL;
PHLIBAPI
VOID
NTAPI
PhInitializeAutoPool(
_Out_ PPH_AUTO_POOL AutoPool
);
_May_raise_
PHLIBAPI
VOID
NTAPI
PhDeleteAutoPool(
_Inout_ PPH_AUTO_POOL AutoPool
);
PHLIBAPI
VOID
NTAPI
PhDrainAutoPool(
_In_ PPH_AUTO_POOL AutoPool
);
_May_raise_
PHLIBAPI
PVOID
NTAPI
PhAutoDereferenceObject(
_In_opt_ PVOID Object
);
#define PH_AUTO PhAutoDereferenceObject
#define PH_AUTO_T(Type, Object) ((Type *)PH_AUTO(Object))
#ifdef __cplusplus
}
#endif
#endif

175
phlib/include/refp.h Normal file
View File

@@ -0,0 +1,175 @@
/*
* Process Hacker -
* internal object manager
*
* Copyright (C) 2009-2016 wj32
*
* 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/>.
*/
#ifndef _PH_REFP_H
#define _PH_REFP_H
#define PH_OBJECT_TYPE_TABLE_SIZE 256
/** The object was allocated from the small free list. */
#define PH_OBJECT_FROM_SMALL_FREE_LIST 0x1
/** The object was allocated from the type free list. */
#define PH_OBJECT_FROM_TYPE_FREE_LIST 0x2
/**
* The object header contains object manager information including the reference count of an object
* and its type.
*/
typedef struct _PH_OBJECT_HEADER
{
union
{
struct
{
USHORT TypeIndex;
UCHAR Flags;
UCHAR Reserved1;
#ifdef _WIN64
ULONG Reserved2;
#endif
union
{
LONG RefCount;
struct
{
LONG SavedTypeIndex : 16;
LONG SavedFlags : 8;
LONG Reserved : 7;
LONG DeferDelete : 1; // MUST be the high bit, so that RefCount < 0 when deferring delete
};
};
#ifdef _WIN64
ULONG Reserved3;
#endif
};
SLIST_ENTRY DeferDeleteListEntry;
};
#ifdef DEBUG
PVOID StackBackTrace[16];
LIST_ENTRY ObjectListEntry;
#endif
/**
* The body of the object. For use by the \ref PhObjectToObjectHeader and
* \ref PhObjectHeaderToObject macros.
*/
QUAD_PTR Body;
} PH_OBJECT_HEADER, *PPH_OBJECT_HEADER;
#ifndef DEBUG
#ifdef _WIN64
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved2) == 0x4);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x8);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved3) == 0xc);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x10);
#else
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x4);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0);
C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x8);
#endif
#endif
/**
* Gets a pointer to the object header for an object.
*
* \param Object A pointer to an object.
*
* \return A pointer to the object header of the object.
*/
#define PhObjectToObjectHeader(Object) ((PPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)(Object), PH_OBJECT_HEADER, Body))
/**
* Gets a pointer to an object from an object header.
*
* \param ObjectHeader A pointer to an object header.
*
* \return A pointer to an object.
*/
#define PhObjectHeaderToObject(ObjectHeader) ((PVOID)&((PPH_OBJECT_HEADER)(ObjectHeader))->Body)
/**
* Calculates the total size to allocate for an object.
*
* \param Size The size of the object to allocate.
*
* \return The new size, including space for the object header.
*/
#define PhAddObjectHeaderSize(Size) ((Size) + FIELD_OFFSET(PH_OBJECT_HEADER, Body))
/** An object type specifies a kind of object and its delete procedure. */
typedef struct _PH_OBJECT_TYPE
{
/** The flags that were used to create the object type. */
USHORT Flags;
UCHAR TypeIndex;
UCHAR Reserved;
/** The total number of objects of this type that are alive. */
ULONG NumberOfObjects;
/** An optional procedure called when objects of this type are freed. */
PPH_TYPE_DELETE_PROCEDURE DeleteProcedure;
/** The name of the type. */
PWSTR Name;
/** A free list to use when allocating for this type. */
PH_FREE_LIST FreeList;
} PH_OBJECT_TYPE, *PPH_OBJECT_TYPE;
/**
* Increments a reference count, but will never increment from a nonpositive value to 1.
*
* \param RefCount A pointer to a reference count.
*/
FORCEINLINE
BOOLEAN
PhpInterlockedIncrementSafe(
_Inout_ PLONG RefCount
)
{
/* Here we will attempt to increment the reference count, making sure that it is positive. */
return _InterlockedIncrementPositive(RefCount);
}
PPH_OBJECT_HEADER PhpAllocateObject(
_In_ PPH_OBJECT_TYPE ObjectType,
_In_ SIZE_T ObjectSize
);
VOID PhpFreeObject(
_In_ PPH_OBJECT_HEADER ObjectHeader
);
VOID PhpDeferDeleteObject(
_In_ PPH_OBJECT_HEADER ObjectHeader
);
NTSTATUS PhpDeferDeleteObjectRoutine(
_In_ PVOID Parameter
);
#endif

163
phlib/include/secedit.h Normal file
View File

@@ -0,0 +1,163 @@
#ifndef _PH_SECEDIT_H
#define _PH_SECEDIT_H
#ifdef __cplusplus
extern "C" {
#endif
// secedit
typedef struct _PH_ACCESS_ENTRY
{
PWSTR Name;
ACCESS_MASK Access;
BOOLEAN General;
BOOLEAN Specific;
PWSTR ShortName;
} PH_ACCESS_ENTRY, *PPH_ACCESS_ENTRY;
PHLIBAPI
HPROPSHEETPAGE
NTAPI
PhCreateSecurityPage(
_In_ PWSTR ObjectName,
_In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,
_In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,
_In_opt_ PVOID Context,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
);
PHLIBAPI
VOID
NTAPI
PhEditSecurity(
_In_ HWND hWnd,
_In_ PWSTR ObjectName,
_In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,
_In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,
_In_opt_ PVOID Context,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
);
typedef struct _PH_STD_OBJECT_SECURITY
{
PPH_OPEN_OBJECT OpenObject;
PWSTR ObjectType;
PVOID Context;
} PH_STD_OBJECT_SECURITY, *PPH_STD_OBJECT_SECURITY;
FORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity(
_In_ SECURITY_INFORMATION SecurityInformation
)
{
ACCESS_MASK access = 0;
if (
(SecurityInformation & OWNER_SECURITY_INFORMATION) ||
(SecurityInformation & GROUP_SECURITY_INFORMATION) ||
(SecurityInformation & DACL_SECURITY_INFORMATION)
)
{
access |= READ_CONTROL;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
access |= ACCESS_SYSTEM_SECURITY;
}
return access;
}
FORCEINLINE ACCESS_MASK PhGetAccessForSetSecurity(
_In_ SECURITY_INFORMATION SecurityInformation
)
{
ACCESS_MASK access = 0;
if (
(SecurityInformation & OWNER_SECURITY_INFORMATION) ||
(SecurityInformation & GROUP_SECURITY_INFORMATION)
)
{
access |= WRITE_OWNER;
}
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
access |= WRITE_DAC;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
access |= ACCESS_SYSTEM_SECURITY;
}
return access;
}
PHLIBAPI
_Callback_ NTSTATUS
NTAPI
PhStdGetObjectSecurity(
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_opt_ PVOID Context
);
PHLIBAPI
_Callback_ NTSTATUS
NTAPI
PhStdSetObjectSecurity(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_opt_ PVOID Context
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetSeObjectSecurity(
_In_ HANDLE Handle,
_In_ ULONG ObjectType,
_In_ SECURITY_INFORMATION SecurityInformation,
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor
);
PHLIBAPI
NTSTATUS
NTAPI
PhSetSeObjectSecurity(
_In_ HANDLE Handle,
_In_ ULONG ObjectType,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
);
// secdata
PHLIBAPI
BOOLEAN
NTAPI
PhGetAccessEntries(
_In_ PWSTR Type,
_Out_ PPH_ACCESS_ENTRY *AccessEntries,
_Out_ PULONG NumberOfAccessEntries
);
PHLIBAPI
PPH_STRING
NTAPI
PhGetAccessString(
_In_ ACCESS_MASK Access,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
);
#ifdef __cplusplus
}
#endif
#endif

100
phlib/include/seceditp.h Normal file
View File

@@ -0,0 +1,100 @@
#ifndef _PH_SECEDITP_H
#define _PH_SECEDITP_H
#include <aclui.h>
#include <aclapi.h>
typedef struct
{
ISecurityInformationVtbl *VTable;
ULONG RefCount;
PPH_STRING ObjectName;
PPH_GET_OBJECT_SECURITY GetObjectSecurity;
PPH_SET_OBJECT_SECURITY SetObjectSecurity;
PVOID Context;
PSI_ACCESS AccessEntries;
ULONG NumberOfAccessEntries;
} PhSecurityInformation;
ISecurityInformation *PhSecurityInformation_Create(
_In_ PWSTR ObjectName,
_In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,
_In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,
_In_opt_ PVOID Context,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface(
_In_ ISecurityInformation *This,
_In_ REFIID Riid,
_Out_ PVOID *Object
);
ULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef(
_In_ ISecurityInformation *This
);
ULONG STDMETHODCALLTYPE PhSecurityInformation_Release(
_In_ ISecurityInformation *This
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation(
_In_ ISecurityInformation *This,
_Out_ PSI_OBJECT_INFO ObjectInfo
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity(
_In_ ISecurityInformation *This,
_In_ SECURITY_INFORMATION RequestedInformation,
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,
_In_ BOOL Default
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity(
_In_ ISecurityInformation *This,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights(
_In_ ISecurityInformation *This,
_In_ const GUID *ObjectType,
_In_ ULONG Flags,
_Out_ PSI_ACCESS *Access,
_Out_ PULONG Accesses,
_Out_ PULONG DefaultAccess
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric(
_In_ ISecurityInformation *This,
_In_ const GUID *ObjectType,
_In_ PUCHAR AceFlags,
_Inout_ PACCESS_MASK Mask
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes(
_In_ ISecurityInformation *This,
_Out_ PSI_INHERIT_TYPE *InheritTypes,
_Out_ PULONG InheritTypesCount
);
HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback(
_In_ ISecurityInformation *This,
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ SI_PAGE_TYPE uPage
);
typedef HPROPSHEETPAGE (WINAPI *_CreateSecurityPage)(
_In_ LPSECURITYINFO psi
);
typedef BOOL (WINAPI *_EditSecurity)(
_In_ HWND hwndOwner,
_In_ LPSECURITYINFO psi
);
#endif

146
phlib/include/svcsup.h Normal file
View File

@@ -0,0 +1,146 @@
#ifndef _PH_SVCSUP_H
#define _PH_SVCSUP_H
#ifdef __cplusplus
extern "C" {
#endif
extern WCHAR *PhServiceTypeStrings[10];
extern WCHAR *PhServiceStartTypeStrings[5];
extern WCHAR *PhServiceErrorControlStrings[4];
PHLIBAPI
PVOID
NTAPI
PhEnumServices(
_In_ SC_HANDLE ScManagerHandle,
_In_opt_ ULONG Type,
_In_opt_ ULONG State,
_Out_ PULONG Count
);
PHLIBAPI
SC_HANDLE
NTAPI
PhOpenService(
_In_ PWSTR ServiceName,
_In_ ACCESS_MASK DesiredAccess
);
PHLIBAPI
PVOID
NTAPI
PhGetServiceConfig(
_In_ SC_HANDLE ServiceHandle
);
PHLIBAPI
PVOID
NTAPI
PhQueryServiceVariableSize(
_In_ SC_HANDLE ServiceHandle,
_In_ ULONG InfoLevel
);
PHLIBAPI
PPH_STRING
NTAPI
PhGetServiceDescription(
_In_ SC_HANDLE ServiceHandle
);
PHLIBAPI
BOOLEAN
NTAPI
PhGetServiceDelayedAutoStart(
_In_ SC_HANDLE ServiceHandle,
_Out_ PBOOLEAN DelayedAutoStart
);
PHLIBAPI
BOOLEAN
NTAPI
PhSetServiceDelayedAutoStart(
_In_ SC_HANDLE ServiceHandle,
_In_ BOOLEAN DelayedAutoStart
);
PHLIBAPI
PWSTR
NTAPI
PhGetServiceStateString(
_In_ ULONG ServiceState
);
PHLIBAPI
PWSTR
NTAPI
PhGetServiceTypeString(
_In_ ULONG ServiceType
);
PHLIBAPI
ULONG
NTAPI
PhGetServiceTypeInteger(
_In_ PWSTR ServiceType
);
PHLIBAPI
PWSTR
NTAPI
PhGetServiceStartTypeString(
_In_ ULONG ServiceStartType
);
PHLIBAPI
ULONG
NTAPI
PhGetServiceStartTypeInteger(
_In_ PWSTR ServiceStartType
);
PHLIBAPI
PWSTR
NTAPI
PhGetServiceErrorControlString(
_In_ ULONG ServiceErrorControl
);
PHLIBAPI
ULONG
NTAPI
PhGetServiceErrorControlInteger(
_In_ PWSTR ServiceErrorControl
);
PHLIBAPI
PPH_STRING
NTAPI
PhGetServiceNameFromTag(
_In_ HANDLE ProcessId,
_In_ PVOID ServiceTag
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetThreadServiceTag(
_In_ HANDLE ThreadHandle,
_In_opt_ HANDLE ProcessHandle,
_Out_ PVOID *ServiceTag
);
PHLIBAPI
NTSTATUS
NTAPI
PhGetServiceDllParameter(
_In_ PPH_STRINGREF ServiceName,
_Out_ PPH_STRING *ServiceDll
);
#ifdef __cplusplus
}
#endif
#endif

303
phlib/include/symprv.h Normal file
View File

@@ -0,0 +1,303 @@
#ifndef _PH_SYMPRV_H
#define _PH_SYMPRV_H
#ifdef __cplusplus
extern "C" {
#endif
extern PPH_OBJECT_TYPE PhSymbolProviderType;
extern PH_CALLBACK PhSymInitCallback;
#define PH_MAX_SYMBOL_NAME_LEN 128
typedef struct _PH_SYMBOL_PROVIDER
{
LIST_ENTRY ModulesListHead;
PH_QUEUED_LOCK ModulesListLock;
HANDLE ProcessHandle;
BOOLEAN IsRealHandle;
BOOLEAN IsRegistered;
PH_INITONCE InitOnce;
PH_AVL_TREE ModulesSet;
PH_CALLBACK EventCallback;
} PH_SYMBOL_PROVIDER, *PPH_SYMBOL_PROVIDER;
typedef enum _PH_SYMBOL_RESOLVE_LEVEL
{
PhsrlFunction,
PhsrlModule,
PhsrlAddress,
PhsrlInvalid
} PH_SYMBOL_RESOLVE_LEVEL, *PPH_SYMBOL_RESOLVE_LEVEL;
typedef struct _PH_SYMBOL_INFORMATION
{
ULONG64 Address;
ULONG64 ModuleBase;
ULONG Index;
ULONG Size;
} PH_SYMBOL_INFORMATION, *PPH_SYMBOL_INFORMATION;
typedef struct _PH_SYMBOL_LINE_INFORMATION
{
ULONG LineNumber;
ULONG64 Address;
} PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION;
typedef enum _PH_SYMBOL_EVENT_TYPE
{
SymbolDeferredSymbolLoadStart = 1,
SymbolDeferredSymbolLoadComplete = 2,
SymbolDeferredSymbolLoadFailure = 3,
SymbolSymbolsUnloaded = 4,
SymbolDeferredSymbolLoadCancel = 7
} PH_SYMBOL_EVENT_TYPE;
typedef struct _PH_SYMBOL_EVENT_DATA
{
PPH_SYMBOL_PROVIDER SymbolProvider;
PH_SYMBOL_EVENT_TYPE Type;
ULONG64 BaseAddress;
ULONG CheckSum;
ULONG TimeStamp;
PPH_STRING FileName;
} PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA;
PHLIBAPI
BOOLEAN
NTAPI
PhSymbolProviderInitialization(
VOID
);
PHLIBAPI
VOID
NTAPI
PhSymbolProviderCompleteInitialization(
_In_opt_ PVOID DbgHelpBase
);
PHLIBAPI
PPH_SYMBOL_PROVIDER
NTAPI
PhCreateSymbolProvider(
_In_opt_ HANDLE ProcessId
);
PHLIBAPI
BOOLEAN
NTAPI
PhGetLineFromAddress(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ ULONG64 Address,
_Out_ PPH_STRING *FileName,
_Out_opt_ PULONG Displacement,
_Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information
);
PHLIBAPI
ULONG64
NTAPI
PhGetModuleFromAddress(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ ULONG64 Address,
_Out_opt_ PPH_STRING *FileName
);
PHLIBAPI
PPH_STRING
NTAPI
PhGetSymbolFromAddress(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ ULONG64 Address,
_Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel,
_Out_opt_ PPH_STRING *FileName,
_Out_opt_ PPH_STRING *SymbolName,
_Out_opt_ PULONG64 Displacement
);
PHLIBAPI
BOOLEAN
NTAPI
PhGetSymbolFromName(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ PWSTR Name,
_Out_ PPH_SYMBOL_INFORMATION Information
);
PHLIBAPI
BOOLEAN
NTAPI
PhLoadModuleSymbolProvider(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ PWSTR FileName,
_In_ ULONG64 BaseAddress,
_In_ ULONG Size
);
PHLIBAPI
VOID
NTAPI
PhSetOptionsSymbolProvider(
_In_ ULONG Mask,
_In_ ULONG Value
);
PHLIBAPI
VOID
NTAPI
PhSetSearchPathSymbolProvider(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ PWSTR Path
);
#ifdef _WIN64
PHLIBAPI
NTSTATUS
NTAPI
PhAccessOutOfProcessFunctionEntry(
_In_ HANDLE ProcessHandle,
_In_ ULONG64 ControlPc,
_Out_ PRUNTIME_FUNCTION Function
);
#endif
PHLIBAPI
ULONG64
__stdcall
PhGetModuleBase64(
_In_ HANDLE hProcess,
_In_ DWORD64 dwAddr
);
PHLIBAPI
PVOID
__stdcall
PhFunctionTableAccess64(
_In_ HANDLE hProcess,
_In_ DWORD64 AddrBase
);
#ifndef _DBGHELP_
// Some of the types used below are defined in dbghelp.h.
typedef struct _tagSTACKFRAME64 *LPSTACKFRAME64;
typedef struct _tagADDRESS64 *LPADDRESS64;
typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
_In_ HANDLE hProcess,
_In_ DWORD64 qwBaseAddress,
_Out_writes_bytes_(nSize) PVOID lpBuffer,
_In_ DWORD nSize,
_Out_ LPDWORD lpNumberOfBytesRead
);
typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
_In_ HANDLE ahProcess,
_In_ DWORD64 AddrBase
);
typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(
_In_ HANDLE hProcess,
_In_ DWORD64 Address
);
typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
_In_ HANDLE hProcess,
_In_ HANDLE hThread,
_In_ LPADDRESS64 lpaddr
);
typedef enum _MINIDUMP_TYPE MINIDUMP_TYPE;
typedef struct _MINIDUMP_EXCEPTION_INFORMATION *PMINIDUMP_EXCEPTION_INFORMATION;
typedef struct _MINIDUMP_USER_STREAM_INFORMATION *PMINIDUMP_USER_STREAM_INFORMATION;
typedef struct _MINIDUMP_CALLBACK_INFORMATION *PMINIDUMP_CALLBACK_INFORMATION;
#endif
PHLIBAPI
BOOLEAN
NTAPI
PhStackWalk(
_In_ ULONG MachineType,
_In_ HANDLE ProcessHandle,
_In_ HANDLE ThreadHandle,
_Inout_ LPSTACKFRAME64 StackFrame,
_Inout_ PVOID ContextRecord,
_In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
_In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
_In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
_In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
PHLIBAPI
BOOLEAN
NTAPI
PhWriteMiniDumpProcess(
_In_ HANDLE ProcessHandle,
_In_ HANDLE ProcessId,
_In_ HANDLE FileHandle,
_In_ MINIDUMP_TYPE DumpType,
_In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
_In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
_In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
// High-level stack walking
#define PH_THREAD_STACK_FRAME_I386 0x1
#define PH_THREAD_STACK_FRAME_AMD64 0x2
#define PH_THREAD_STACK_FRAME_KERNEL 0x4
#define PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT 0x100
/** Contains information about a thread stack frame. */
typedef struct _PH_THREAD_STACK_FRAME
{
PVOID PcAddress;
PVOID ReturnAddress;
PVOID FrameAddress;
PVOID StackAddress;
PVOID BStoreAddress;
PVOID Params[4];
ULONG Flags;
} PH_THREAD_STACK_FRAME, *PPH_THREAD_STACK_FRAME;
#define PH_WALK_I386_STACK 0x1
#define PH_WALK_AMD64_STACK 0x2
#define PH_WALK_KERNEL_STACK 0x10
/**
* A callback function passed to PhWalkThreadStack() and called for each stack frame.
*
* \param StackFrame A structure providing information about the stack frame.
* \param Context A user-defined value passed to PhWalkThreadStack().
*
* \return TRUE to continue the stack walk, FALSE to stop.
*/
typedef BOOLEAN (NTAPI *PPH_WALK_THREAD_STACK_CALLBACK)(
_In_ PPH_THREAD_STACK_FRAME StackFrame,
_In_opt_ PVOID Context
);
PHLIBAPI
NTSTATUS
NTAPI
PhWalkThreadStack(
_In_ HANDLE ThreadHandle,
_In_opt_ HANDLE ProcessHandle,
_In_opt_ PCLIENT_ID ClientId,
_In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ ULONG Flags,
_In_ PPH_WALK_THREAD_STACK_CALLBACK Callback,
_In_opt_ PVOID Context
);
#ifdef __cplusplus
}
#endif
#endif

170
phlib/include/symprvp.h Normal file
View File

@@ -0,0 +1,170 @@
#ifndef _PH_SYMPRVP_H
#define _PH_SYMPRVP_H
typedef BOOL (WINAPI *_SymInitialize)(
_In_ HANDLE hProcess,
_In_opt_ PCSTR UserSearchPath,
_In_ BOOL fInvadeProcess
);
typedef BOOL (WINAPI *_SymCleanup)(
_In_ HANDLE hProcess
);
typedef BOOL (WINAPI *_SymEnumSymbols)(
_In_ HANDLE hProcess,
_In_ ULONG64 BaseOfDll,
_In_opt_ PCSTR Mask,
_In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
_In_opt_ const PVOID UserContext
);
typedef BOOL (WINAPI *_SymEnumSymbolsW)(
_In_ HANDLE hProcess,
_In_ ULONG64 BaseOfDll,
_In_opt_ PCWSTR Mask,
_In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
_In_opt_ const PVOID UserContext
);
typedef BOOL (WINAPI *_SymFromAddr)(
_In_ HANDLE hProcess,
_In_ DWORD64 Address,
_Out_opt_ PDWORD64 Displacement,
_Inout_ PSYMBOL_INFO Symbol
);
typedef BOOL (WINAPI *_SymFromAddrW)(
_In_ HANDLE hProcess,
_In_ DWORD64 Address,
_Out_opt_ PDWORD64 Displacement,
_Inout_ PSYMBOL_INFOW Symbol
);
typedef BOOL (WINAPI *_SymFromName)(
_In_ HANDLE hProcess,
_In_ PCSTR Name,
_Inout_ PSYMBOL_INFO Symbol
);
typedef BOOL (WINAPI *_SymFromNameW)(
_In_ HANDLE hProcess,
_In_ PCWSTR Name,
_Inout_ PSYMBOL_INFOW Symbol
);
typedef BOOL (WINAPI *_SymGetLineFromAddr64)(
_In_ HANDLE hProcess,
_In_ DWORD64 dwAddr,
_Out_ PDWORD pdwDisplacement,
_Out_ PIMAGEHLP_LINE64 Line
);
typedef BOOL (WINAPI *_SymGetLineFromAddrW64)(
_In_ HANDLE hProcess,
_In_ DWORD64 dwAddr,
_Out_ PDWORD pdwDisplacement,
_Out_ PIMAGEHLP_LINEW64 Line
);
typedef DWORD64 (WINAPI *_SymLoadModule64)(
_In_ HANDLE hProcess,
_In_opt_ HANDLE hFile,
_In_opt_ PCSTR ImageName,
_In_opt_ PCSTR ModuleName,
_In_ DWORD64 BaseOfDll,
_In_ DWORD SizeOfDll
);
typedef DWORD64 (WINAPI *_SymLoadModuleExW)(
_In_ HANDLE hProcess,
_In_ HANDLE hFile,
_In_ PCWSTR ImageName,
_In_ PCWSTR ModuleName,
_In_ DWORD64 BaseOfDll,
_In_ DWORD DllSize,
_In_ PMODLOAD_DATA Data,
_In_ DWORD Flags
);
typedef DWORD (WINAPI *_SymGetOptions)();
typedef DWORD (WINAPI *_SymSetOptions)(
_In_ DWORD SymOptions
);
typedef BOOL (WINAPI *_SymGetSearchPath)(
_In_ HANDLE hProcess,
_Out_ PSTR SearchPath,
_In_ DWORD SearchPathLength
);
typedef BOOL (WINAPI *_SymGetSearchPathW)(
_In_ HANDLE hProcess,
_Out_ PWSTR SearchPath,
_In_ DWORD SearchPathLength
);
typedef BOOL (WINAPI *_SymSetSearchPath)(
_In_ HANDLE hProcess,
_In_opt_ PCSTR SearchPath
);
typedef BOOL (WINAPI *_SymSetSearchPathW)(
_In_ HANDLE hProcess,
_In_opt_ PCWSTR SearchPath
);
typedef BOOL (WINAPI *_SymUnloadModule64)(
_In_ HANDLE hProcess,
_In_ DWORD64 BaseOfDll
);
typedef PVOID (WINAPI *_SymFunctionTableAccess64)(
_In_ HANDLE hProcess,
_In_ DWORD64 AddrBase
);
typedef DWORD64 (WINAPI *_SymGetModuleBase64)(
_In_ HANDLE hProcess,
_In_ DWORD64 dwAddr
);
typedef BOOL (WINAPI *_SymRegisterCallbackW64)(
_In_ HANDLE hProcess,
_In_ PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
_In_ ULONG64 UserContext
);
typedef BOOL (WINAPI *_StackWalk64)(
_In_ DWORD MachineType,
_In_ HANDLE hProcess,
_In_ HANDLE hThread,
_Inout_ LPSTACKFRAME64 StackFrame,
_Inout_ PVOID ContextRecord,
_In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
_In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
_In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
_In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
typedef BOOL (WINAPI *_MiniDumpWriteDump)(
_In_ HANDLE hProcess,
_In_ DWORD ProcessId,
_In_ HANDLE hFile,
_In_ MINIDUMP_TYPE DumpType,
_In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
_In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
_In_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
typedef UINT_PTR (CALLBACK *_SymbolServerGetOptions)(
VOID
);
typedef BOOL (CALLBACK *_SymbolServerSetOptions)(
_In_ UINT_PTR options,
_In_ ULONG64 data
);
#endif

7
phlib/include/templ.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef _PH_TEMPL_H
#define _PH_TEMPL_H
#define TEMPLATE_(f,T) f##_##T
#define T___(f,T) TEMPLATE_(f,T)
#endif

672
phlib/include/treenew.h Normal file
View File

@@ -0,0 +1,672 @@
#ifndef _PH_TREENEW_H
#define _PH_TREENEW_H
#ifdef __cplusplus
extern "C" {
#endif
#define PH_TREENEW_CLASSNAME L"PhTreeNew"
#define PH_TREENEW_SEARCH_TIMEOUT 1000
#define PH_TREENEW_SEARCH_MAXIMUM_LENGTH 1023
typedef struct _PH_TREENEW_COLUMN
{
union
{
ULONG Flags;
struct
{
ULONG Visible : 1;
ULONG CustomDraw : 1;
ULONG Fixed : 1; // Whether this is the fixed column
ULONG SortDescending : 1; // Sort descending on initial click rather than ascending
ULONG DpiScaleOnAdd : 1; // Whether to DPI scale the width (only when adding)
ULONG SpareFlags : 27;
};
};
ULONG Id;
PVOID Context;
PWSTR Text;
LONG Width;
ULONG Alignment;
ULONG DisplayIndex; // -1 for fixed column or invalid
ULONG TextFlags;
struct
{
LONG ViewIndex; // Actual index in header control
LONG ViewX; // 0 for the fixed column, and an offset from the divider for normal columns
} s;
} PH_TREENEW_COLUMN, *PPH_TREENEW_COLUMN;
typedef struct _PH_TREENEW_NODE
{
union
{
ULONG Flags;
struct
{
ULONG Visible : 1;
ULONG Selected : 1;
ULONG Expanded : 1;
ULONG UseAutoForeColor : 1;
ULONG UseTempBackColor : 1;
ULONG Unselectable : 1;
ULONG SpareFlags : 26;
};
};
COLORREF BackColor;
COLORREF ForeColor;
COLORREF TempBackColor;
HFONT Font;
HICON Icon;
PPH_STRINGREF TextCache;
ULONG TextCacheSize;
ULONG Index; // Index within the flat list
ULONG Level; // 0 for root, 1, 2, ...
struct
{
union
{
ULONG Flags2;
struct
{
ULONG IsLeaf : 1;
ULONG CachedColorValid : 1;
ULONG CachedFontValid : 1;
ULONG CachedIconValid : 1;
ULONG PlusMinusHot : 1;
ULONG SpareFlags2 : 27;
};
};
// Temp. drawing data
COLORREF DrawBackColor;
COLORREF DrawForeColor;
} s;
} PH_TREENEW_NODE, *PPH_TREENEW_NODE;
// Styles
#define TN_STYLE_ICONS 0x1
#define TN_STYLE_DOUBLE_BUFFERED 0x2
#define TN_STYLE_NO_DIVIDER 0x4
#define TN_STYLE_ANIMATE_DIVIDER 0x8
#define TN_STYLE_NO_COLUMN_SORT 0x10
#define TN_STYLE_NO_COLUMN_REORDER 0x20
#define TN_STYLE_THIN_ROWS 0x40
#define TN_STYLE_NO_COLUMN_HEADER 0x80
// Extended flags
#define TN_FLAG_ITEM_DRAG_SELECT 0x1
#define TN_FLAG_NO_UNFOLDING_TOOLTIPS 0x2
// Callback flags
#define TN_CACHE 0x1
#define TN_AUTO_FORECOLOR 0x1000
// Column change flags
#define TN_COLUMN_CONTEXT 0x1
#define TN_COLUMN_TEXT 0x2
#define TN_COLUMN_WIDTH 0x4
#define TN_COLUMN_ALIGNMENT 0x8
#define TN_COLUMN_DISPLAYINDEX 0x10
#define TN_COLUMN_TEXTFLAGS 0x20
#define TN_COLUMN_FLAG_VISIBLE 0x100000
#define TN_COLUMN_FLAG_CUSTOMDRAW 0x200000
#define TN_COLUMN_FLAG_FIXED 0x400000
#define TN_COLUMN_FLAG_SORTDESCENDING 0x800000
#define TN_COLUMN_FLAG_NODPISCALEONADD 0x1000000
#define TN_COLUMN_FLAGS 0xfff00000
// Cache flags
#define TN_CACHE_COLOR 0x1
#define TN_CACHE_FONT 0x2
#define TN_CACHE_ICON 0x4
// Cell part input flags
#define TN_MEASURE_TEXT 0x1
// Cell part flags
#define TN_PART_CELL 0x1
#define TN_PART_PLUSMINUS 0x2
#define TN_PART_ICON 0x4
#define TN_PART_CONTENT 0x8
#define TN_PART_TEXT 0x10
// Hit test input flags
#define TN_TEST_COLUMN 0x1
#define TN_TEST_SUBITEM 0x2 // requires TN_TEST_COLUMN
// Hit test flags
#define TN_HIT_LEFT 0x1
#define TN_HIT_RIGHT 0x2
#define TN_HIT_ABOVE 0x4
#define TN_HIT_BELOW 0x8
#define TN_HIT_ITEM 0x10
#define TN_HIT_ITEM_PLUSMINUS 0x20 // requires TN_TEST_SUBITEM
#define TN_HIT_ITEM_ICON 0x40 // requires TN_TEST_SUBITEM
#define TN_HIT_ITEM_CONTENT 0x80 // requires TN_TEST_SUBITEM
#define TN_HIT_DIVIDER 0x100
// Selection flags
#define TN_SELECT_DESELECT 0x1
#define TN_SELECT_TOGGLE 0x2
#define TN_SELECT_RESET 0x4
// Auto-size flags
#define TN_AUTOSIZE_REMAINING_SPACE 0x1
typedef struct _PH_TREENEW_CELL_PARTS
{
ULONG Flags;
RECT RowRect;
RECT CellRect; // TN_PART_CELL
RECT PlusMinusRect; // TN_PART_PLUSMINUS
RECT IconRect; // TN_PART_ICON
RECT ContentRect; // TN_PART_CONTENT
RECT TextRect; // TN_PART_TEXT
PH_STRINGREF Text; // TN_PART_TEXT
HFONT Font; // TN_PART_TEXT
} PH_TREENEW_CELL_PARTS, *PPH_TREENEW_CELL_PARTS;
typedef struct _PH_TREENEW_HIT_TEST
{
POINT Point;
ULONG InFlags;
ULONG Flags;
PPH_TREENEW_NODE Node;
PPH_TREENEW_COLUMN Column; // requires TN_TEST_COLUMN
} PH_TREENEW_HIT_TEST, *PPH_TREENEW_HIT_TEST;
typedef enum _PH_TREENEW_MESSAGE
{
TreeNewGetChildren, // PPH_TREENEW_GET_CHILDREN Parameter1
TreeNewIsLeaf, // PPH_TREENEW_IS_LEAF Parameter1
TreeNewGetCellText, // PPH_TREENEW_GET_CELL_TEXT Parameter1
TreeNewGetNodeColor, // PPH_TREENEW_GET_NODE_COLOR Parameter1
TreeNewGetNodeFont, // PPH_TREENEW_GET_NODE_FONT Parameter1
TreeNewGetNodeIcon, // PPH_TREENEW_GET_NODE_ICON Parameter1
TreeNewGetCellTooltip, // PPH_TREENEW_GET_CELL_TOOLTIP Parameter1
TreeNewCustomDraw, // PPH_TREENEW_CUSTOM_DRAW Parameter1
// Notifications
TreeNewNodeExpanding, // PPH_TREENEW_NODE Parameter1, PPH_TREENEW_NODE_EVENT Parameter2
TreeNewNodeSelecting, // PPH_TREENEW_NODE Parameter1
TreeNewSortChanged,
TreeNewSelectionChanged,
TreeNewKeyDown, // PPH_TREENEW_KEY_EVENT Parameter1
TreeNewLeftClick, // PPH_TREENEW_MOUSE_EVENT Parameter1
TreeNewRightClick, // PPH_TREENEW_MOUSE_EVENT Parameter1
TreeNewLeftDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1
TreeNewRightDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1
TreeNewContextMenu, // PPH_TREENEW_CONTEXT_MENU Parameter1
TreeNewHeaderRightClick, // PPH_TREENEW_HEADER_MOUSE_EVENT Parameter1
TreeNewIncrementalSearch, // PPH_TREENEW_SEARCH_EVENT Parameter1
TreeNewColumnResized, // PPH_TREENEW_COLUMN Parameter1
TreeNewColumnReordered,
TreeNewDestroying,
TreeNewGetDialogCode, // ULONG Parameter1, PULONG Parameter2
MaxTreeNewMessage
} PH_TREENEW_MESSAGE;
typedef BOOLEAN (NTAPI *PPH_TREENEW_CALLBACK)(
_In_ HWND hwnd,
_In_ PH_TREENEW_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2,
_In_opt_ PVOID Context
);
typedef struct _PH_TREENEW_GET_CHILDREN
{
ULONG Flags;
PPH_TREENEW_NODE Node;
ULONG NumberOfChildren;
PPH_TREENEW_NODE *Children; // can be NULL if no children
} PH_TREENEW_GET_CHILDREN, *PPH_TREENEW_GET_CHILDREN;
typedef struct _PH_TREENEW_IS_LEAF
{
ULONG Flags;
PPH_TREENEW_NODE Node;
BOOLEAN IsLeaf;
} PH_TREENEW_IS_LEAF, *PPH_TREENEW_IS_LEAF;
typedef struct _PH_TREENEW_GET_CELL_TEXT
{
ULONG Flags;
PPH_TREENEW_NODE Node;
ULONG Id;
PH_STRINGREF Text;
} PH_TREENEW_GET_CELL_TEXT, *PPH_TREENEW_GET_CELL_TEXT;
typedef struct _PH_TREENEW_GET_NODE_COLOR
{
ULONG Flags;
PPH_TREENEW_NODE Node;
COLORREF BackColor;
COLORREF ForeColor;
} PH_TREENEW_GET_NODE_COLOR, *PPH_TREENEW_GET_NODE_COLOR;
typedef struct _PH_TREENEW_GET_NODE_FONT
{
ULONG Flags;
PPH_TREENEW_NODE Node;
HFONT Font;
} PH_TREENEW_GET_NODE_FONT, *PPH_TREENEW_GET_NODE_FONT;
typedef struct _PH_TREENEW_GET_NODE_ICON
{
ULONG Flags;
PPH_TREENEW_NODE Node;
HICON Icon;
} PH_TREENEW_GET_NODE_ICON, *PPH_TREENEW_GET_NODE_ICON;
typedef struct _PH_TREENEW_GET_CELL_TOOLTIP
{
ULONG Flags;
PPH_TREENEW_NODE Node;
PPH_TREENEW_COLUMN Column;
BOOLEAN Unfolding;
PH_STRINGREF Text;
HFONT Font;
ULONG MaximumWidth;
} PH_TREENEW_GET_CELL_TOOLTIP, *PPH_TREENEW_GET_CELL_TOOLTIP;
typedef struct _PH_TREENEW_CUSTOM_DRAW
{
PPH_TREENEW_NODE Node;
PPH_TREENEW_COLUMN Column;
HDC Dc;
RECT CellRect;
RECT TextRect;
} PH_TREENEW_CUSTOM_DRAW, *PPH_TREENEW_CUSTOM_DRAW;
typedef struct _PH_TREENEW_MOUSE_EVENT
{
POINT Location;
PPH_TREENEW_NODE Node;
PPH_TREENEW_COLUMN Column;
ULONG KeyFlags;
} PH_TREENEW_MOUSE_EVENT, *PPH_TREENEW_MOUSE_EVENT;
typedef struct _PH_TREENEW_KEY_EVENT
{
BOOLEAN Handled;
ULONG VirtualKey;
ULONG Data;
} PH_TREENEW_KEY_EVENT, *PPH_TREENEW_KEY_EVENT;
typedef struct _PH_TREENEW_NODE_EVENT
{
BOOLEAN Handled;
ULONG Flags;
PVOID Reserved1;
PVOID Reserved2;
} PH_TREENEW_NODE_EVENT, *PPH_TREENEW_NODE_EVENT;
typedef struct _PH_TREENEW_CONTEXT_MENU
{
POINT Location;
POINT ClientLocation;
PPH_TREENEW_NODE Node;
PPH_TREENEW_COLUMN Column;
BOOLEAN KeyboardInvoked;
} PH_TREENEW_CONTEXT_MENU, *PPH_TREENEW_CONTEXT_MENU;
typedef struct _PH_TREENEW_HEADER_MOUSE_EVENT
{
POINT ScreenLocation;
POINT Location;
POINT HeaderLocation;
PPH_TREENEW_COLUMN Column;
} PH_TREENEW_HEADER_MOUSE_EVENT, *PPH_TREENEW_HEADER_MOUSE_EVENT;
typedef struct _PH_TREENEW_SEARCH_EVENT
{
LONG FoundIndex;
LONG StartIndex;
PH_STRINGREF String;
} PH_TREENEW_SEARCH_EVENT, *PPH_TREENEW_SEARCH_EVENT;
#define TNM_FIRST (WM_USER + 1)
#define TNM_SETCALLBACK (WM_USER + 1)
#define TNM_NODESADDED (WM_USER + 2) // unimplemented
#define TNM_NODESREMOVED (WM_USER + 3) // unimplemented
#define TNM_NODESSTRUCTURED (WM_USER + 4)
#define TNM_ADDCOLUMN (WM_USER + 5)
#define TNM_REMOVECOLUMN (WM_USER + 6)
#define TNM_GETCOLUMN (WM_USER + 7)
#define TNM_SETCOLUMN (WM_USER + 8)
#define TNM_GETCOLUMNORDERARRAY (WM_USER + 9)
#define TNM_SETCOLUMNORDERARRAY (WM_USER + 10)
#define TNM_SETCURSOR (WM_USER + 11)
#define TNM_GETSORT (WM_USER + 12)
#define TNM_SETSORT (WM_USER + 13)
#define TNM_SETTRISTATE (WM_USER + 14)
#define TNM_ENSUREVISIBLE (WM_USER + 15)
#define TNM_SCROLL (WM_USER + 16)
#define TNM_GETFLATNODECOUNT (WM_USER + 17)
#define TNM_GETFLATNODE (WM_USER + 18)
#define TNM_GETCELLTEXT (WM_USER + 19)
#define TNM_SETNODEEXPANDED (WM_USER + 20)
#define TNM_GETMAXID (WM_USER + 21)
#define TNM_SETMAXID (WM_USER + 22)
#define TNM_INVALIDATENODE (WM_USER + 23)
#define TNM_INVALIDATENODES (WM_USER + 24)
#define TNM_GETFIXEDHEADER (WM_USER + 25)
#define TNM_GETHEADER (WM_USER + 26)
#define TNM_GETTOOLTIPS (WM_USER + 27)
#define TNM_SELECTRANGE (WM_USER + 28)
#define TNM_DESELECTRANGE (WM_USER + 29)
#define TNM_GETCOLUMNCOUNT (WM_USER + 30)
#define TNM_SETREDRAW (WM_USER + 31)
#define TNM_GETVIEWPARTS (WM_USER + 32)
#define TNM_GETFIXEDCOLUMN (WM_USER + 33)
#define TNM_GETFIRSTCOLUMN (WM_USER + 34)
#define TNM_SETFOCUSNODE (WM_USER + 35)
#define TNM_SETMARKNODE (WM_USER + 36)
#define TNM_SETHOTNODE (WM_USER + 37)
#define TNM_SETEXTENDEDFLAGS (WM_USER + 38)
#define TNM_GETCALLBACK (WM_USER + 39)
#define TNM_HITTEST (WM_USER + 40)
#define TNM_GETVISIBLECOLUMNCOUNT (WM_USER + 41)
#define TNM_AUTOSIZECOLUMN (WM_USER + 42)
#define TNM_SETEMPTYTEXT (WM_USER + 43)
#define TNM_SETROWHEIGHT (WM_USER + 44)
#define TNM_ISFLATNODEVALID (WM_USER + 45)
#define TNM_LAST (WM_USER + 45)
#define TreeNew_SetCallback(hWnd, Callback, Context) \
SendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))
#define TreeNew_NodesStructured(hWnd) \
SendMessage((hWnd), TNM_NODESSTRUCTURED, 0, 0)
#define TreeNew_AddColumn(hWnd, Column) \
SendMessage((hWnd), TNM_ADDCOLUMN, 0, (LPARAM)(Column))
#define TreeNew_RemoveColumn(hWnd, Id) \
SendMessage((hWnd), TNM_REMOVECOLUMN, (WPARAM)(Id), 0)
#define TreeNew_GetColumn(hWnd, Id, Column) \
SendMessage((hWnd), TNM_GETCOLUMN, (WPARAM)(Id), (LPARAM)(Column))
#define TreeNew_SetColumn(hWnd, Mask, Column) \
SendMessage((hWnd), TNM_SETCOLUMN, (WPARAM)(Mask), (LPARAM)(Column))
#define TreeNew_GetColumnOrderArray(hWnd, Count, Array) \
SendMessage((hWnd), TNM_GETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))
#define TreeNew_SetColumnOrderArray(hWnd, Count, Array) \
SendMessage((hWnd), TNM_SETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array))
#define TreeNew_SetCursor(hWnd, Cursor) \
SendMessage((hWnd), TNM_SETCURSOR, 0, (LPARAM)(Cursor))
#define TreeNew_GetSort(hWnd, Column, Order) \
SendMessage((hWnd), TNM_GETSORT, (WPARAM)(Column), (LPARAM)(Order))
#define TreeNew_SetSort(hWnd, Column, Order) \
SendMessage((hWnd), TNM_SETSORT, (WPARAM)(Column), (LPARAM)(Order))
#define TreeNew_SetTriState(hWnd, TriState) \
SendMessage((hWnd), TNM_SETTRISTATE, (WPARAM)(TriState), 0)
#define TreeNew_EnsureVisible(hWnd, Node) \
SendMessage((hWnd), TNM_ENSUREVISIBLE, 0, (LPARAM)(Node))
#define TreeNew_Scroll(hWnd, DeltaRows, DeltaX) \
SendMessage((hWnd), TNM_SCROLL, (WPARAM)(DeltaRows), (LPARAM)(DeltaX))
#define TreeNew_GetFlatNodeCount(hWnd) \
((ULONG)SendMessage((hWnd), TNM_GETFLATNODECOUNT, 0, 0))
#define TreeNew_GetFlatNode(hWnd, Index) \
((PPH_TREENEW_NODE)SendMessage((hWnd), TNM_GETFLATNODE, (WPARAM)(Index), 0))
#define TreeNew_GetCellText(hWnd, GetCellText) \
SendMessage((hWnd), TNM_GETCELLTEXT, 0, (LPARAM)(GetCellText))
#define TreeNew_SetNodeExpanded(hWnd, Node, Expanded) \
SendMessage((hWnd), TNM_SETNODEEXPANDED, (WPARAM)(Expanded), (LPARAM)(Node))
#define TreeNew_GetMaxId(hWnd) \
((ULONG)SendMessage((hWnd), TNM_GETMAXID, 0, 0))
#define TreeNew_SetMaxId(hWnd, MaxId) \
SendMessage((hWnd), TNM_SETMAXID, (WPARAM)(MaxId), 0)
#define TreeNew_InvalidateNode(hWnd, Node) \
SendMessage((hWnd), TNM_INVALIDATENODE, 0, (LPARAM)(Node))
#define TreeNew_InvalidateNodes(hWnd, Start, End) \
SendMessage((hWnd), TNM_INVALIDATENODES, (WPARAM)(Start), (LPARAM)(End))
#define TreeNew_GetFixedHeader(hWnd) \
((HWND)SendMessage((hWnd), TNM_GETFIXEDHEADER, 0, 0))
#define TreeNew_GetHeader(hWnd) \
((HWND)SendMessage((hWnd), TNM_GETHEADER, 0, 0))
#define TreeNew_GetTooltips(hWnd) \
((HWND)SendMessage((hWnd), TNM_GETTOOLTIPS, 0, 0))
#define TreeNew_SelectRange(hWnd, Start, End) \
SendMessage((hWnd), TNM_SELECTRANGE, (WPARAM)(Start), (LPARAM)(End))
#define TreeNew_DeselectRange(hWnd, Start, End) \
SendMessage((hWnd), TNM_DESELECTRANGE, (WPARAM)(Start), (LPARAM)(End))
#define TreeNew_GetColumnCount(hWnd) \
((ULONG)SendMessage((hWnd), TNM_GETCOLUMNCOUNT, 0, 0))
#define TreeNew_SetRedraw(hWnd, Redraw) \
((LONG)SendMessage((hWnd), TNM_SETREDRAW, (WPARAM)(Redraw), 0))
#define TreeNew_GetViewParts(hWnd, Parts) \
SendMessage((hWnd), TNM_GETVIEWPARTS, 0, (LPARAM)(Parts))
#define TreeNew_GetFixedColumn(hWnd) \
((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIXEDCOLUMN, 0, 0))
#define TreeNew_GetFirstColumn(hWnd) \
((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIRSTCOLUMN, 0, 0))
#define TreeNew_SetFocusNode(hWnd, Node) \
SendMessage((hWnd), TNM_SETFOCUSNODE, 0, (LPARAM)(Node))
#define TreeNew_SetMarkNode(hWnd, Node) \
SendMessage((hWnd), TNM_SETMARKNODE, 0, (LPARAM)(Node))
#define TreeNew_SetHotNode(hWnd, Node) \
SendMessage((hWnd), TNM_SETHOTNODE, 0, (LPARAM)(Node))
#define TreeNew_SetExtendedFlags(hWnd, Mask, Value) \
SendMessage((hWnd), TNM_SETEXTENDEDFLAGS, (WPARAM)(Mask), (LPARAM)(Value))
#define TreeNew_GetCallback(hWnd, Callback, Context) \
SendMessage((hWnd), TNM_GETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback))
#define TreeNew_HitTest(hWnd, HitTest) \
SendMessage((hWnd), TNM_HITTEST, 0, (LPARAM)(HitTest))
#define TreeNew_GetVisibleColumnCount(hWnd) \
((ULONG)SendMessage((hWnd), TNM_GETVISIBLECOLUMNCOUNT, 0, 0))
#define TreeNew_AutoSizeColumn(hWnd, Id, Flags) \
SendMessage((hWnd), TNM_AUTOSIZECOLUMN, (WPARAM)(Id), (LPARAM)(Flags))
#define TreeNew_SetEmptyText(hWnd, Text, Flags) \
SendMessage((hWnd), TNM_SETEMPTYTEXT, (WPARAM)(Flags), (LPARAM)(Text))
#define TreeNew_SetRowHeight(hWnd, RowHeight) \
SendMessage((hWnd), TNM_SETROWHEIGHT, (WPARAM)(RowHeight), 0)
#define TreeNew_IsFlatNodeValid(hWnd) \
((BOOLEAN)SendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0))
typedef struct _PH_TREENEW_VIEW_PARTS
{
RECT ClientRect;
LONG HeaderHeight;
LONG RowHeight;
ULONG VScrollWidth;
ULONG HScrollHeight;
LONG VScrollPosition;
LONG HScrollPosition;
LONG FixedWidth;
LONG NormalLeft;
LONG NormalWidth;
} PH_TREENEW_VIEW_PARTS, *PPH_TREENEW_VIEW_PARTS;
PHLIBAPI
BOOLEAN PhTreeNewInitialization(
VOID
);
FORCEINLINE VOID PhInitializeTreeNewNode(
_In_ PPH_TREENEW_NODE Node
)
{
memset(Node, 0, sizeof(PH_TREENEW_NODE));
Node->Visible = TRUE;
Node->Expanded = TRUE;
}
FORCEINLINE VOID PhInvalidateTreeNewNode(
_Inout_ PPH_TREENEW_NODE Node,
_In_ ULONG Flags
)
{
if (Flags & TN_CACHE_COLOR)
Node->s.CachedColorValid = FALSE;
if (Flags & TN_CACHE_FONT)
Node->s.CachedFontValid = FALSE;
if (Flags & TN_CACHE_ICON)
Node->s.CachedIconValid = FALSE;
}
FORCEINLINE BOOLEAN PhAddTreeNewColumn(
_In_ HWND hwnd,
_In_ ULONG Id,
_In_ BOOLEAN Visible,
_In_ PWSTR Text,
_In_ ULONG Width,
_In_ ULONG Alignment,
_In_ ULONG DisplayIndex,
_In_ ULONG TextFlags
)
{
PH_TREENEW_COLUMN column;
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
column.Id = Id;
column.Visible = Visible;
column.Text = Text;
column.Width = Width;
column.Alignment = Alignment;
column.DisplayIndex = DisplayIndex;
column.TextFlags = TextFlags;
column.DpiScaleOnAdd = TRUE;
if (DisplayIndex == -2)
column.Fixed = TRUE;
return !!TreeNew_AddColumn(hwnd, &column);
}
FORCEINLINE BOOLEAN PhAddTreeNewColumnEx(
_In_ HWND hwnd,
_In_ ULONG Id,
_In_ BOOLEAN Visible,
_In_ PWSTR Text,
_In_ ULONG Width,
_In_ ULONG Alignment,
_In_ ULONG DisplayIndex,
_In_ ULONG TextFlags,
_In_ BOOLEAN SortDescending
)
{
PH_TREENEW_COLUMN column;
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
column.Id = Id;
column.Visible = Visible;
column.Text = Text;
column.Width = Width;
column.Alignment = Alignment;
column.DisplayIndex = DisplayIndex;
column.TextFlags = TextFlags;
column.DpiScaleOnAdd = TRUE;
if (DisplayIndex == -2)
column.Fixed = TRUE;
if (SortDescending)
column.SortDescending = TRUE;
return !!TreeNew_AddColumn(hwnd, &column);
}
FORCEINLINE BOOLEAN PhAddTreeNewColumnEx2(
_In_ HWND hwnd,
_In_ ULONG Id,
_In_ BOOLEAN Visible,
_In_ PWSTR Text,
_In_ ULONG Width,
_In_ ULONG Alignment,
_In_ ULONG DisplayIndex,
_In_ ULONG TextFlags,
_In_ ULONG ExtraFlags
)
{
PH_TREENEW_COLUMN column;
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
column.Id = Id;
column.Visible = Visible;
column.Text = Text;
column.Width = Width;
column.Alignment = Alignment;
column.DisplayIndex = DisplayIndex;
column.TextFlags = TextFlags;
if (DisplayIndex == -2)
column.Fixed = TRUE;
if (ExtraFlags & TN_COLUMN_FLAG_CUSTOMDRAW)
column.CustomDraw = TRUE;
if (ExtraFlags & TN_COLUMN_FLAG_SORTDESCENDING)
column.SortDescending = TRUE;
if (!(ExtraFlags & TN_COLUMN_FLAG_NODPISCALEONADD))
column.DpiScaleOnAdd = TRUE;
return !!TreeNew_AddColumn(hwnd, &column);
}
#ifdef __cplusplus
}
#endif
#endif

802
phlib/include/treenewp.h Normal file
View File

@@ -0,0 +1,802 @@
#ifndef _PH_TREENEWP_H
#define _PH_TREENEWP_H
// Important notes about pointers:
//
// All memory allocation for nodes and strings is handled by the user. This usually means there is a
// very limited time during which they can be safely accessed.
//
// Node pointers are valid through the duration of message processing, and also up to the next
// restructure operation, either user- or control- initiated. This means that state such as the
// focused node, hot node and mark node must be carefully preserved through restructuring. If
// restructuring is suspended by a set-redraw call, all nodes must be considered invalid and no user
// input can be handled.
//
// Strings are valid only through the duration of message processing.
typedef struct _PH_TREENEW_CONTEXT
{
HWND Handle;
PVOID InstanceHandle;
HWND FixedHeaderHandle;
HWND HeaderHandle;
HWND VScrollHandle;
HWND HScrollHandle;
HWND FillerBoxHandle;
HWND TooltipsHandle;
union
{
struct
{
ULONG FontOwned : 1;
ULONG Tracking : 1; // tracking for fixed divider
ULONG VScrollVisible : 1;
ULONG HScrollVisible : 1;
ULONG FixedColumnVisible : 1;
ULONG FixedDividerVisible : 1;
ULONG AnimateDivider : 1;
ULONG AnimateDividerFadingIn : 1;
ULONG AnimateDividerFadingOut : 1;
ULONG CanAnyExpand : 1;
ULONG TriState : 1;
ULONG HasFocus : 1;
ULONG ThemeInitialized : 1; // delay load theme data
ULONG ThemeActive : 1;
ULONG ThemeHasItemBackground : 1;
ULONG ThemeHasGlyph : 1;
ULONG ThemeHasHotGlyph : 1;
ULONG FocusNodeFound : 1; // used to preserve the focused node across restructuring
ULONG SearchFailed : 1; // used to prevent multiple beeps
ULONG SearchSingleCharMode : 1; // LV style single-character search
ULONG TooltipUnfolding : 1; // whether the current tooltip is unfolding
ULONG DoubleBuffered : 1;
ULONG SuspendUpdateStructure : 1;
ULONG SuspendUpdateLayout : 1;
ULONG SuspendUpdateMoveMouse : 1;
ULONG DragSelectionActive : 1;
ULONG SelectionRectangleAlpha : 1; // use alpha blending for the selection rectangle
ULONG CustomRowHeight : 1;
ULONG Spare : 4;
};
ULONG Flags;
};
ULONG Style;
ULONG ExtendedStyle;
ULONG ExtendedFlags;
HFONT Font;
HCURSOR Cursor;
HCURSOR DividerCursor;
RECT ClientRect;
LONG HeaderHeight;
LONG RowHeight;
ULONG VScrollWidth;
ULONG HScrollHeight;
LONG VScrollPosition;
LONG HScrollPosition;
LONG FixedWidth; // width of the fixed part of the tree list
LONG FixedWidthMinimum;
LONG NormalLeft; // FixedWidth + 1 if there is a fixed column, otherwise 0
PPH_TREENEW_NODE FocusNode;
ULONG HotNodeIndex;
ULONG MarkNodeIndex; // selection mark
ULONG MouseDownLast;
POINT MouseDownLocation;
PPH_TREENEW_CALLBACK Callback;
PVOID CallbackContext;
PPH_TREENEW_COLUMN *Columns; // columns, indexed by ID
ULONG NextId;
ULONG AllocatedColumns;
ULONG NumberOfColumns; // just a statistic; do not use for actual logic
PPH_TREENEW_COLUMN *ColumnsByDisplay; // columns, indexed by display order (excluding the fixed column)
ULONG AllocatedColumnsByDisplay;
ULONG NumberOfColumnsByDisplay; // the number of visible columns (excluding the fixed column)
LONG TotalViewX; // total width of normal columns
PPH_TREENEW_COLUMN FixedColumn;
PPH_TREENEW_COLUMN FirstColumn; // first column, by display order (including the fixed column)
PPH_TREENEW_COLUMN LastColumn; // last column, by display order (including the fixed column)
PPH_TREENEW_COLUMN ResizingColumn;
LONG OldColumnWidth;
LONG TrackStartX;
LONG TrackOldFixedWidth;
ULONG DividerHot; // 0 for un-hot, 100 for completely hot
PPH_LIST FlatList;
ULONG SortColumn; // ID of the column to sort by
PH_SORT_ORDER SortOrder;
FLOAT VScrollRemainder;
FLOAT HScrollRemainder;
LONG SearchMessageTime;
PWSTR SearchString;
ULONG SearchStringCount;
ULONG AllocatedSearchString;
ULONG TooltipIndex;
ULONG TooltipId;
PPH_STRING TooltipText;
RECT TooltipRect; // text rectangle of an unfolding tooltip
HFONT TooltipFont;
HFONT NewTooltipFont;
ULONG TooltipColumnId;
WNDPROC FixedHeaderOldWndProc;
WNDPROC HeaderOldWndProc;
TEXTMETRIC TextMetrics;
HTHEME ThemeData;
LONG SystemBorderX;
LONG SystemBorderY;
LONG SystemEdgeX;
LONG SystemEdgeY;
HDC BufferedContext;
HBITMAP BufferedOldBitmap;
HBITMAP BufferedBitmap;
RECT BufferedContextRect;
LONG SystemDragX;
LONG SystemDragY;
RECT DragRect;
LONG EnableRedraw;
HRGN SuspendUpdateRegion;
PH_STRINGREF EmptyText;
} PH_TREENEW_CONTEXT, *PPH_TREENEW_CONTEXT;
LRESULT CALLBACK PhTnpWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
BOOLEAN NTAPI PhTnpNullCallback(
_In_ HWND hwnd,
_In_ PH_TREENEW_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2,
_In_opt_ PVOID Context
);
VOID PhTnpCreateTreeNewContext(
_Out_ PPH_TREENEW_CONTEXT *Context
);
VOID PhTnpDestroyTreeNewContext(
_In_ PPH_TREENEW_CONTEXT Context
);
// Event handlers
BOOLEAN PhTnpOnCreate(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ CREATESTRUCT *CreateStruct
);
VOID PhTnpOnSize(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpOnSetFont(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_opt_ HFONT Font,
_In_ LOGICAL Redraw
);
VOID PhTnpOnStyleChanged(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG Type,
_In_ STYLESTRUCT *StyleStruct
);
VOID PhTnpOnSettingChange(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpOnThemeChanged(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context
);
ULONG PhTnpOnGetDlgCode(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG VirtualKey,
_In_opt_ PMSG Message
);
VOID PhTnpOnPaint(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpOnPrintClient(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc,
_In_ ULONG Flags
);
BOOLEAN PhTnpOnNcPaint(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_opt_ HRGN UpdateRegion
);
BOOLEAN PhTnpOnSetCursor(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HWND CursorWindowHandle
);
VOID PhTnpOnTimer(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Id
);
VOID PhTnpOnMouseMove(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG VirtualKeys,
_In_ LONG CursorX,
_In_ LONG CursorY
);
VOID PhTnpOnMouseLeave(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpOnXxxButtonXxx(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Message,
_In_ ULONG VirtualKeys,
_In_ LONG CursorX,
_In_ LONG CursorY
);
VOID PhTnpOnCaptureChanged(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpOnKeyDown(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG VirtualKey,
_In_ ULONG Data
);
VOID PhTnpOnChar(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Character,
_In_ ULONG Data
);
VOID PhTnpOnMouseWheel(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG Distance,
_In_ ULONG VirtualKeys,
_In_ LONG CursorX,
_In_ LONG CursorY
);
VOID PhTnpOnMouseHWheel(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG Distance,
_In_ ULONG VirtualKeys,
_In_ LONG CursorX,
_In_ LONG CursorY
);
VOID PhTnpOnContextMenu(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG CursorScreenX,
_In_ LONG CursorScreenY
);
VOID PhTnpOnVScroll(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Request,
_In_ USHORT Position
);
VOID PhTnpOnHScroll(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Request,
_In_ USHORT Position
);
BOOLEAN PhTnpOnNotify(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ NMHDR *Header,
_Out_ LRESULT *Result
);
ULONG_PTR PhTnpOnUserMessage(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Message,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam
);
// Misc.
VOID PhTnpSetFont(
_In_ PPH_TREENEW_CONTEXT Context,
_In_opt_ HFONT Font,
_In_ BOOLEAN Redraw
);
VOID PhTnpUpdateSystemMetrics(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpUpdateTextMetrics(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpUpdateThemeData(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpInitializeThemeData(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpCancelTrack(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpLayout(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpLayoutHeader(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpSetFixedWidth(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG FixedWidth
);
VOID PhTnpSetRedraw(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ BOOLEAN Redraw
);
VOID PhTnpSendMouseEvent(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PH_TREENEW_MESSAGE Message,
_In_ LONG CursorX,
_In_ LONG CursorY,
_In_ PPH_TREENEW_NODE Node,
_In_ PPH_TREENEW_COLUMN Column,
_In_ ULONG VirtualKeys
);
// Columns
PPH_TREENEW_COLUMN PhTnpLookupColumnById(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Id
);
BOOLEAN PhTnpAddColumn(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_COLUMN Column
);
BOOLEAN PhTnpRemoveColumn(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Id
);
BOOLEAN PhTnpCopyColumn(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Id,
_Out_ PPH_TREENEW_COLUMN Column
);
BOOLEAN PhTnpChangeColumn(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Mask,
_In_ ULONG Id,
_In_ PPH_TREENEW_COLUMN Column
);
VOID PhTnpExpandAllocatedColumns(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpUpdateColumnMaps(
_In_ PPH_TREENEW_CONTEXT Context
);
// Columns (header control)
LONG PhTnpInsertColumnHeader(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_COLUMN Column
);
VOID PhTnpChangeColumnHeader(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Mask,
_In_ PPH_TREENEW_COLUMN Column
);
VOID PhTnpDeleteColumnHeader(
_In_ PPH_TREENEW_CONTEXT Context,
_Inout_ PPH_TREENEW_COLUMN Column
);
VOID PhTnpUpdateColumnHeaders(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpProcessResizeColumn(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_COLUMN Column,
_In_ LONG Delta
);
VOID PhTnpProcessSortColumn(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_COLUMN NewColumn
);
BOOLEAN PhTnpSetColumnHeaderSortIcon(
_In_ PPH_TREENEW_CONTEXT Context,
_In_opt_ PPH_TREENEW_COLUMN SortColumnPointer
);
VOID PhTnpAutoSizeColumnHeader(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HWND HeaderHandle,
_In_ PPH_TREENEW_COLUMN Column,
_In_ ULONG Flags
);
// Nodes
BOOLEAN PhTnpGetNodeChildren(
_In_ PPH_TREENEW_CONTEXT Context,
_In_opt_ PPH_TREENEW_NODE Node,
_Out_ PPH_TREENEW_NODE **Children,
_Out_ PULONG NumberOfChildren
);
BOOLEAN PhTnpIsNodeLeaf(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_NODE Node
);
BOOLEAN PhTnpGetCellText(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_NODE Node,
_In_ ULONG Id,
_Out_ PPH_STRINGREF Text
);
VOID PhTnpRestructureNodes(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpInsertNodeChildren(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_NODE Node,
_In_ ULONG Level
);
VOID PhTnpSetExpandedNode(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_NODE Node,
_In_ BOOLEAN Expanded
);
BOOLEAN PhTnpGetCellParts(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Index,
_In_opt_ PPH_TREENEW_COLUMN Column,
_In_ ULONG Flags,
_Out_ PPH_TREENEW_CELL_PARTS Parts
);
BOOLEAN PhTnpGetRowRects(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Start,
_In_ ULONG End,
_In_ BOOLEAN Clip,
_Out_ PRECT Rect
);
VOID PhTnpHitTest(
_In_ PPH_TREENEW_CONTEXT Context,
_Inout_ PPH_TREENEW_HIT_TEST HitTest
);
VOID PhTnpSelectRange(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Start,
_In_ ULONG End,
_In_ ULONG Flags,
_Out_opt_ PULONG ChangedStart,
_Out_opt_ PULONG ChangedEnd
);
VOID PhTnpSetHotNode(
_In_ PPH_TREENEW_CONTEXT Context,
_In_opt_ PPH_TREENEW_NODE NewHotNode,
_In_ BOOLEAN NewPlusMinusHot
);
VOID PhTnpProcessSelectNode(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPH_TREENEW_NODE Node,
_In_ LOGICAL ControlKey,
_In_ LOGICAL ShiftKey,
_In_ LOGICAL RightButton
);
BOOLEAN PhTnpEnsureVisibleNode(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Index
);
// Mouse
VOID PhTnpProcessMoveMouse(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG CursorX,
_In_ LONG CursorY
);
VOID PhTnpProcessMouseVWheel(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG Distance
);
VOID PhTnpProcessMouseHWheel(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG Distance
);
// Keyboard
BOOLEAN PhTnpProcessFocusKey(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG VirtualKey
);
BOOLEAN PhTnpProcessNodeKey(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG VirtualKey
);
VOID PhTnpProcessSearchKey(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG Character
);
BOOLEAN PhTnpDefaultIncrementalSearch(
_In_ PPH_TREENEW_CONTEXT Context,
_Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent,
_In_ BOOLEAN Partial,
_In_ BOOLEAN Wrap
);
// Scrolling
VOID PhTnpUpdateScrollBars(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpScroll(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG DeltaRows,
_In_ LONG DeltaX
);
VOID PhTnpProcessScroll(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG DeltaRows,
_In_ LONG DeltaX
);
BOOLEAN PhTnpCanScroll(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ BOOLEAN Horizontal,
_In_ BOOLEAN Positive
);
// Drawing
VOID PhTnpPaint(
_In_ HWND hwnd,
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc,
_In_ PRECT PaintRect
);
VOID PhTnpPrepareRowForDraw(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc,
_Inout_ PPH_TREENEW_NODE Node
);
VOID PhTnpDrawCell(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc,
_In_ PRECT CellRect,
_In_ PPH_TREENEW_NODE Node,
_In_ PPH_TREENEW_COLUMN Column,
_In_ LONG RowIndex,
_In_ LONG ColumnIndex
);
VOID PhTnpDrawDivider(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc
);
VOID PhTnpDrawPlusMinusGlyph(
_In_ HDC hdc,
_In_ PRECT Rect,
_In_ BOOLEAN Plus
);
VOID PhTnpDrawSelectionRectangle(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc,
_In_ PRECT Rect
);
VOID PhTnpDrawThemedBorder(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ HDC hdc
);
// Tooltips
VOID PhTnpInitializeTooltips(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpGetTooltipText(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ PPOINT Point,
_Out_ PWSTR *Text
);
BOOLEAN PhTnpPrepareTooltipShow(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpPrepareTooltipPop(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpPopTooltip(
_In_ PPH_TREENEW_CONTEXT Context
);
PPH_TREENEW_COLUMN PhTnpHitTestHeader(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ BOOLEAN Fixed,
_In_ PPOINT Point,
_Out_opt_ PRECT ItemRect
);
VOID PhTnpGetHeaderTooltipText(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ BOOLEAN Fixed,
_In_ PPOINT Point,
_Out_ PWSTR *Text
);
PWSTR PhTnpMakeContextAtom(
VOID
);
LRESULT CALLBACK PhTnpHeaderHookWndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// Drag selection
BOOLEAN PhTnpDetectDrag(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG CursorX,
_In_ LONG CursorY,
_In_ BOOLEAN DispatchMessages,
_Out_opt_ PULONG CancelledByMessage
);
VOID PhTnpDragSelect(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ LONG CursorX,
_In_ LONG CursorY
);
VOID PhTnpProcessDragSelect(
_In_ PPH_TREENEW_CONTEXT Context,
_In_ ULONG VirtualKeys,
_In_ PRECT OldRect,
_In_ PRECT NewRect,
_In_ PRECT TotalRect
);
// Double buffering
VOID PhTnpCreateBufferedContext(
_In_ PPH_TREENEW_CONTEXT Context
);
VOID PhTnpDestroyBufferedContext(
_In_ PPH_TREENEW_CONTEXT Context
);
// Support functions
VOID PhTnpGetMessagePos(
_In_ HWND hwnd,
_Out_ PPOINT ClientPoint
);
// Macros
#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented
#define TNP_CELL_LEFT_MARGIN 6
#define TNP_CELL_RIGHT_MARGIN 6
#define TNP_ICON_RIGHT_PADDING 4
#define TNP_TIMER_NULL 1
#define TNP_TIMER_ANIMATE_DIVIDER 2
#define TNP_TOOLTIPS_ITEM 0
#define TNP_TOOLTIPS_FIXED_HEADER 1
#define TNP_TOOLTIPS_HEADER 2
#define TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH 550
#define TNP_ANIMATE_DIVIDER_INTERVAL 10
#define TNP_ANIMATE_DIVIDER_INCREMENT 17
#define TNP_ANIMATE_DIVIDER_DECREMENT 2
#define TNP_HIT_TEST_FIXED_DIVIDER(X, Context) \
((Context)->FixedDividerVisible && (X) >= (Context)->FixedWidth - 8 && (X) < (Context)->FixedWidth + 8)
#define TNP_HIT_TEST_PLUS_MINUS_GLYPH(X, NodeLevel) \
(((X) >= TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth)) && ((X) < TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth) + SmallIconWidth))
#endif

77
phlib/include/verify.h Normal file
View File

@@ -0,0 +1,77 @@
#ifndef _PH_VERIFY_H
#define _PH_VERIFY_H
#include <wintrust.h>
#include <softpub.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PH_VERIFY_DEFAULT_SIZE_LIMIT (32 * 1024 * 1024)
typedef enum _VERIFY_RESULT
{
VrUnknown = 0,
VrNoSignature,
VrTrusted,
VrExpired,
VrRevoked,
VrDistrust,
VrSecuritySettings,
VrBadSignature
} VERIFY_RESULT, *PVERIFY_RESULT;
#define PH_VERIFY_PREVENT_NETWORK_ACCESS 0x1
#define PH_VERIFY_VIEW_PROPERTIES 0x2
typedef struct _PH_VERIFY_FILE_INFO
{
PWSTR FileName;
ULONG Flags; // PH_VERIFY_*
ULONG FileSizeLimitForHash; // 0 for PH_VERIFY_DEFAULT_SIZE_LIMIT, -1 for unlimited
ULONG NumberOfCatalogFileNames;
PWSTR *CatalogFileNames;
HWND hWnd; // for PH_VERIFY_VIEW_PROPERTIES
} PH_VERIFY_FILE_INFO, *PPH_VERIFY_FILE_INFO;
PHLIBAPI
VERIFY_RESULT
NTAPI
PhVerifyFile(
_In_ PWSTR FileName,
_Out_opt_ PPH_STRING *SignerName
);
PHLIBAPI
NTSTATUS
NTAPI
PhVerifyFileEx(
_In_ PPH_VERIFY_FILE_INFO Information,
_Out_ VERIFY_RESULT *VerifyResult,
_Out_opt_ PCERT_CONTEXT **Signatures,
_Out_opt_ PULONG NumberOfSignatures
);
PHLIBAPI
VOID
NTAPI
PhFreeVerifySignatures(
_In_ PCERT_CONTEXT *Signatures,
_In_ ULONG NumberOfSignatures
);
PHLIBAPI
PPH_STRING
NTAPI
PhGetSignerNameFromCertificate(
_In_ PCERT_CONTEXT Certificate
);
#ifdef __cplusplus
}
#endif
#endif

118
phlib/include/verifyp.h Normal file
View File

@@ -0,0 +1,118 @@
#ifndef _PH_VERIFYP_H
#define _PH_VERIFYP_H
#include <commdlg.h>
typedef struct _CATALOG_INFO
{
DWORD cbStruct;
WCHAR wszCatalogFile[MAX_PATH];
} CATALOG_INFO, *PCATALOG_INFO;
typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT {
DWORD dwSize;
HWND hwndParent;
DWORD dwFlags;
LPCTSTR szTitle;
CMSG_SIGNER_INFO *pSignerInfo;
HCRYPTMSG hMsg;
LPCSTR pszOID;
DWORD_PTR dwReserved;
DWORD cStores;
HCERTSTORE *rghStores;
DWORD cPropSheetPages;
LPCPROPSHEETPAGE rgPropSheetPages;
} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT;
typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)(
HANDLE hFile,
DWORD *pcbHash,
BYTE *pbHash,
DWORD dwFlags
);
typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle2)(
HCATADMIN hCatAdmin,
HANDLE hFile,
DWORD *pcbHash,
BYTE *pbHash,
DWORD dwFlags
);
typedef BOOL (WINAPI *_CryptCATAdminAcquireContext)(
HANDLE *phCatAdmin,
GUID *pgSubsystem,
DWORD dwFlags
);
typedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)(
HCATADMIN *phCatAdmin,
const GUID *pgSubsystem,
PCWSTR pwszHashAlgorithm,
PCCERT_STRONG_SIGN_PARA pStrongHashPolicy,
DWORD dwFlags
);
typedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)(
HANDLE hCatAdmin,
BYTE *pbHash,
DWORD cbHash,
DWORD dwFlags,
HANDLE *phPrevCatInfo
);
typedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)(
HANDLE hCatInfo,
CATALOG_INFO *psCatInfo,
DWORD dwFlags
);
typedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)(
HANDLE hCatAdmin,
HANDLE hCatInfo,
DWORD dwFlags
);
typedef BOOL (WINAPI *_CryptCATAdminReleaseContext)(
HANDLE hCatAdmin,
DWORD dwFlags
);
typedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)(
HANDLE hStateData
);
typedef PCRYPT_PROVIDER_SGNR (WINAPI *_WTHelperGetProvSignerFromChain)(
CRYPT_PROVIDER_DATA *pProvData,
DWORD idxSigner,
BOOL fCounterSigner,
DWORD idxCounterSigner
);
typedef LONG (WINAPI *_WinVerifyTrust)(
HWND hWnd,
GUID *pgActionID,
LPVOID pWVTData
);
typedef DWORD (WINAPI *_CertNameToStr)(
DWORD dwCertEncodingType,
PCERT_NAME_BLOB pName,
DWORD dwStrType,
LPTSTR psz,
DWORD csz
);
typedef PCCERT_CONTEXT (WINAPI *_CertDuplicateCertificateContext)(
_In_ PCCERT_CONTEXT pCertContext
);
typedef BOOL (WINAPI *_CertFreeCertificateContext)(
_In_ PCCERT_CONTEXT pCertContext
);
typedef BOOL (WINAPI *_CryptUIDlgViewSignerInfo)(
_In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi
);
#endif

108
phlib/include/workqueue.h Normal file
View File

@@ -0,0 +1,108 @@
#ifndef _PH_WORKQUEUE_H
#define _PH_WORKQUEUE_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(DEBUG)
extern PPH_LIST PhDbgWorkQueueList;
extern PH_QUEUED_LOCK PhDbgWorkQueueListLock;
#endif
typedef struct _PH_WORK_QUEUE
{
PH_RUNDOWN_PROTECT RundownProtect;
BOOLEAN Terminating;
LIST_ENTRY QueueListHead;
PH_QUEUED_LOCK QueueLock;
PH_CONDITION QueueEmptyCondition;
ULONG MaximumThreads;
ULONG MinimumThreads;
ULONG NoWorkTimeout;
PH_QUEUED_LOCK StateLock;
HANDLE SemaphoreHandle;
ULONG CurrentThreads;
ULONG BusyCount;
} PH_WORK_QUEUE, *PPH_WORK_QUEUE;
typedef VOID (NTAPI *PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION)(
_In_ PUSER_THREAD_START_ROUTINE Function,
_In_ PVOID Context
);
typedef struct _PH_WORK_QUEUE_ENVIRONMENT
{
LONG BasePriority : 6; // Base priority increment
ULONG IoPriority : 3; // I/O priority hint
ULONG PagePriority : 3; // Page/memory priority
ULONG ForceUpdate : 1; // Always set priorities regardless of cached values
ULONG SpareBits : 19;
} PH_WORK_QUEUE_ENVIRONMENT, *PPH_WORK_QUEUE_ENVIRONMENT;
PHLIBAPI
VOID
NTAPI
PhInitializeWorkQueue(
_Out_ PPH_WORK_QUEUE WorkQueue,
_In_ ULONG MinimumThreads,
_In_ ULONG MaximumThreads,
_In_ ULONG NoWorkTimeout
);
PHLIBAPI
VOID
NTAPI
PhDeleteWorkQueue(
_Inout_ PPH_WORK_QUEUE WorkQueue
);
PHLIBAPI
VOID
NTAPI
PhWaitForWorkQueue(
_Inout_ PPH_WORK_QUEUE WorkQueue
);
PHLIBAPI
VOID
NTAPI
PhQueueItemWorkQueue(
_Inout_ PPH_WORK_QUEUE WorkQueue,
_In_ PUSER_THREAD_START_ROUTINE Function,
_In_opt_ PVOID Context
);
PHLIBAPI
VOID
NTAPI
PhQueueItemWorkQueueEx(
_Inout_ PPH_WORK_QUEUE WorkQueue,
_In_ PUSER_THREAD_START_ROUTINE Function,
_In_opt_ PVOID Context,
_In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,
_In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment
);
PHLIBAPI
VOID
NTAPI
PhInitializeWorkQueueEnvironment(
_Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment
);
PHLIBAPI
PPH_WORK_QUEUE
NTAPI
PhGetGlobalWorkQueue(
VOID
);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,49 @@
#ifndef _PH_WORKQUEUEP_H
#define _PH_WORKQUEUEP_H
typedef struct _PH_WORK_QUEUE_ITEM
{
LIST_ENTRY ListEntry;
PUSER_THREAD_START_ROUTINE Function;
PVOID Context;
PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction;
PH_WORK_QUEUE_ENVIRONMENT Environment;
} PH_WORK_QUEUE_ITEM, *PPH_WORK_QUEUE_ITEM;
VOID PhpGetDefaultWorkQueueEnvironment(
_Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment
);
VOID PhpUpdateWorkQueueEnvironment(
_Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment,
_In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment
);
PPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem(
_In_ PUSER_THREAD_START_ROUTINE Function,
_In_opt_ PVOID Context,
_In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction,
_In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment
);
VOID PhpDestroyWorkQueueItem(
_In_ PPH_WORK_QUEUE_ITEM WorkQueueItem
);
VOID PhpExecuteWorkQueueItem(
_Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem
);
HANDLE PhpGetSemaphoreWorkQueue(
_Inout_ PPH_WORK_QUEUE WorkQueue
);
BOOLEAN PhpCreateWorkQueueThread(
_Inout_ PPH_WORK_QUEUE WorkQueue
);
NTSTATUS PhpWorkQueueThreadStart(
_In_ PVOID Parameter
);
#endif

1102
phlib/kph.c Normal file

File diff suppressed because it is too large Load Diff

276
phlib/kphdata.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* Process Hacker -
* KProcessHacker dynamic data definitions
*
* Copyright (C) 2011-2016 wj32
*
* 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 <ph.h>
#include <kphuser.h>
#ifdef _WIN64
ULONG KphpGetKernelRevisionNumber(
VOID
)
{
ULONG result;
PPH_STRING kernelFileName;
PVOID versionInfo;
VS_FIXEDFILEINFO *rootBlock;
ULONG rootBlockLength;
result = 0;
kernelFileName = PhGetKernelFileName();
PhMoveReference(&kernelFileName, PhGetFileName(kernelFileName));
versionInfo = PhGetFileVersionInfo(kernelFileName->Buffer);
PhDereferenceObject(kernelFileName);
if (versionInfo && VerQueryValue(versionInfo, L"\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0)
result = rootBlock->dwFileVersionLS & 0xffff;
PhFree(versionInfo);
return result;
}
NTSTATUS KphInitializeDynamicPackage(
_Out_ PKPH_DYN_PACKAGE Package
)
{
ULONG majorVersion, minorVersion, servicePack, buildNumber;
majorVersion = PhOsVersion.dwMajorVersion;
minorVersion = PhOsVersion.dwMinorVersion;
servicePack = PhOsVersion.wServicePackMajor;
buildNumber = PhOsVersion.dwBuildNumber;
memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA));
Package->MajorVersion = (USHORT)majorVersion;
Package->MinorVersion = (USHORT)minorVersion;
Package->ServicePackMajor = (USHORT)servicePack;
Package->BuildNumber = -1;
// Windows 7, Windows Server 2008 R2
if (majorVersion == 6 && minorVersion == 1)
{
Package->ResultingNtVersion = PHNT_WIN7;
if (servicePack == 0)
{
}
else if (servicePack == 1)
{
}
else
{
return STATUS_NOT_SUPPORTED;
}
Package->StructData.EgeGuid = 0x14;
Package->StructData.EpObjectTable = 0x200;
Package->StructData.EreGuidEntry = 0x10;
Package->StructData.OtName = 0x10;
Package->StructData.OtIndex = 0x28; // now only a UCHAR, not a ULONG
}
// Windows 8, Windows Server 2012
else if (majorVersion == 6 && minorVersion == 2 && buildNumber == 9200)
{
Package->BuildNumber = 9200;
Package->ResultingNtVersion = PHNT_WIN8;
Package->StructData.EgeGuid = 0x14;
Package->StructData.EpObjectTable = 0x408;
Package->StructData.EreGuidEntry = 0x10;
Package->StructData.HtHandleContentionEvent = 0x30;
Package->StructData.OtName = 0x10;
Package->StructData.OtIndex = 0x28;
Package->StructData.ObDecodeShift = 19;
Package->StructData.ObAttributesShift = 20;
}
// Windows 8.1, Windows Server 2012 R2
else if (majorVersion == 6 && minorVersion == 3 && buildNumber == 9600)
{
ULONG revisionNumber = KphpGetKernelRevisionNumber();
Package->BuildNumber = 9600;
Package->ResultingNtVersion = PHNT_WINBLUE;
Package->StructData.EgeGuid = 0x18;
Package->StructData.EpObjectTable = 0x408;
Package->StructData.EreGuidEntry = revisionNumber >= 17736 ? 0x20 : 0x10;
Package->StructData.HtHandleContentionEvent = 0x30;
Package->StructData.OtName = 0x10;
Package->StructData.OtIndex = 0x28;
Package->StructData.ObDecodeShift = 16;
Package->StructData.ObAttributesShift = 17;
}
// Windows 10
else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240)
{
Package->BuildNumber = 10240;
Package->ResultingNtVersion = PHNT_THRESHOLD;
Package->StructData.EgeGuid = 0x18;
Package->StructData.EpObjectTable = 0x418;
Package->StructData.EreGuidEntry = 0x20;
Package->StructData.HtHandleContentionEvent = 0x30;
Package->StructData.OtName = 0x10;
Package->StructData.OtIndex = 0x28;
Package->StructData.ObDecodeShift = 16;
Package->StructData.ObAttributesShift = 17;
}
else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586)
{
Package->BuildNumber = 10586;
Package->ResultingNtVersion = PHNT_THRESHOLD2;
Package->StructData.EgeGuid = 0x18;
Package->StructData.EpObjectTable = 0x418;
Package->StructData.EreGuidEntry = 0x20;
Package->StructData.HtHandleContentionEvent = 0x30;
Package->StructData.OtName = 0x10;
Package->StructData.OtIndex = 0x28;
Package->StructData.ObDecodeShift = 16;
Package->StructData.ObAttributesShift = 17;
}
else
{
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
#else
NTSTATUS KphInitializeDynamicPackage(
_Out_ PKPH_DYN_PACKAGE Package
)
{
ULONG majorVersion, minorVersion, servicePack, buildNumber;
majorVersion = PhOsVersion.dwMajorVersion;
minorVersion = PhOsVersion.dwMinorVersion;
servicePack = PhOsVersion.wServicePackMajor;
buildNumber = PhOsVersion.dwBuildNumber;
memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA));
Package->MajorVersion = (USHORT)majorVersion;
Package->MinorVersion = (USHORT)minorVersion;
Package->ServicePackMajor = (USHORT)servicePack;
Package->BuildNumber = -1;
// Windows 7, Windows Server 2008 R2
if (majorVersion == 6 && minorVersion == 1)
{
Package->ResultingNtVersion = PHNT_WIN7;
if (servicePack == 0)
{
NOTHING;
}
else if (servicePack == 1)
{
NOTHING;
}
else
{
return STATUS_NOT_SUPPORTED;
}
Package->StructData.EgeGuid = 0xc;
Package->StructData.EpObjectTable = 0xf4;
Package->StructData.EreGuidEntry = 0x8;
Package->StructData.OtName = 0x8;
Package->StructData.OtIndex = 0x14; // now only a UCHAR, not a ULONG
}
// Windows 8, Windows Server 2012
else if (majorVersion == 6 && minorVersion == 2)
{
Package->ResultingNtVersion = PHNT_WIN8;
if (servicePack == 0)
{
NOTHING;
}
else
{
return STATUS_NOT_SUPPORTED;
}
Package->StructData.EgeGuid = 0xc;
Package->StructData.EpObjectTable = 0x150;
Package->StructData.EreGuidEntry = 0x8;
Package->StructData.OtName = 0x8;
Package->StructData.OtIndex = 0x14;
}
// Windows 8.1, Windows Server 2012 R2
else if (majorVersion == 6 && minorVersion == 3)
{
Package->ResultingNtVersion = PHNT_WINBLUE;
if (servicePack == 0)
{
NOTHING;
}
else
{
return STATUS_NOT_SUPPORTED;
}
Package->StructData.EgeGuid = 0xc;
Package->StructData.EpObjectTable = 0x150;
Package->StructData.EreGuidEntry = 0x8;
Package->StructData.OtName = 0x8;
Package->StructData.OtIndex = 0x14;
}
// Windows 10
else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240)
{
Package->BuildNumber = 10240;
Package->ResultingNtVersion = PHNT_THRESHOLD;
Package->StructData.EgeGuid = 0xc;
Package->StructData.EpObjectTable = 0x154;
Package->StructData.EreGuidEntry = 0x10;
Package->StructData.OtName = 0x8;
Package->StructData.OtIndex = 0x14;
}
else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586)
{
Package->BuildNumber = 10586;
Package->ResultingNtVersion = PHNT_THRESHOLD2;
Package->StructData.EgeGuid = 0xc;
Package->StructData.EpObjectTable = 0x154;
Package->StructData.EreGuidEntry = 0x10;
Package->StructData.OtName = 0x8;
Package->StructData.OtIndex = 0x14;
}
else
{
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
#endif

480
phlib/lsasup.c Normal file
View File

@@ -0,0 +1,480 @@
/*
* Process Hacker -
* LSA support functions
*
* Copyright (C) 2010-2011 wj32
*
* 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/>.
*/
/*
* These are functions which communicate with LSA or are support functions. They replace certain
* Win32 security-related functions such as LookupAccountName, LookupAccountSid and
* LookupPrivilege*, which are badly designed. (LSA already allocates the return values for the
* caller, yet the Win32 functions insist on their callers providing their own buffers.)
*/
#include <ph.h>
#include <lsasup.h>
static LSA_HANDLE PhLookupPolicyHandle = NULL;
NTSTATUS PhOpenLsaPolicy(
_Out_ PLSA_HANDLE PolicyHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ PUNICODE_STRING SystemName
)
{
OBJECT_ATTRIBUTES oa = { 0 };
return LsaOpenPolicy(
SystemName,
&oa,
DesiredAccess,
PolicyHandle
);
}
/**
* Retrieves a handle to the local LSA policy with POLICY_LOOKUP_NAMES access.
*
* \remarks Do not close the handle; it is cached.
*/
LSA_HANDLE PhGetLookupPolicyHandle(
VOID
)
{
LSA_HANDLE lookupPolicyHandle;
LSA_HANDLE newLookupPolicyHandle;
lookupPolicyHandle = PhLookupPolicyHandle;
// If there is no cached handle, open one.
if (!lookupPolicyHandle)
{
if (NT_SUCCESS(PhOpenLsaPolicy(
&newLookupPolicyHandle,
POLICY_LOOKUP_NAMES,
NULL
)))
{
// We succeeded in opening a policy handle, and since we did not have a cached handle
// before, we will now store it.
lookupPolicyHandle = _InterlockedCompareExchangePointer(
&PhLookupPolicyHandle,
newLookupPolicyHandle,
NULL
);
if (!lookupPolicyHandle)
{
// Success. Use our handle.
lookupPolicyHandle = newLookupPolicyHandle;
}
else
{
// Someone already placed a handle in the cache. Close our handle and use their
// handle.
LsaClose(newLookupPolicyHandle);
}
}
}
return lookupPolicyHandle;
}
/**
* Gets the name of a privilege from its LUID.
*
* \param PrivilegeValue The LUID of a privilege.
* \param PrivilegeName A variable which receives a pointer to a string containing the privilege
* name. You must free the string using PhDereferenceObject() when you no longer need it.
*/
BOOLEAN PhLookupPrivilegeName(
_In_ PLUID PrivilegeValue,
_Out_ PPH_STRING *PrivilegeName
)
{
NTSTATUS status;
PUNICODE_STRING name;
status = LsaLookupPrivilegeName(
PhGetLookupPolicyHandle(),
PrivilegeValue,
&name
);
if (!NT_SUCCESS(status))
return FALSE;
*PrivilegeName = PhCreateStringFromUnicodeString(name);
LsaFreeMemory(name);
return TRUE;
}
/**
* Gets the display name of a privilege from its name.
*
* \param PrivilegeName The name of a privilege.
* \param PrivilegeDisplayName A variable which receives a pointer to a string containing the
* privilege's display name. You must free the string using PhDereferenceObject() when you no longer
* need it.
*/
BOOLEAN PhLookupPrivilegeDisplayName(
_In_ PPH_STRINGREF PrivilegeName,
_Out_ PPH_STRING *PrivilegeDisplayName
)
{
NTSTATUS status;
UNICODE_STRING privilegeName;
PUNICODE_STRING displayName;
SHORT language;
if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))
return FALSE;
status = LsaLookupPrivilegeDisplayName(
PhGetLookupPolicyHandle(),
&privilegeName,
&displayName,
&language
);
if (!NT_SUCCESS(status))
return FALSE;
*PrivilegeDisplayName = PhCreateStringFromUnicodeString(displayName);
LsaFreeMemory(displayName);
return TRUE;
}
/**
* Gets the LUID of a privilege from its name.
*
* \param PrivilegeName The name of a privilege.
* \param PrivilegeValue A variable which receives the LUID of the privilege.
*/
BOOLEAN PhLookupPrivilegeValue(
_In_ PPH_STRINGREF PrivilegeName,
_Out_ PLUID PrivilegeValue
)
{
UNICODE_STRING privilegeName;
if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))
return FALSE;
return NT_SUCCESS(LsaLookupPrivilegeValue(
PhGetLookupPolicyHandle(),
&privilegeName,
PrivilegeValue
));
}
/**
* Gets information about a SID.
*
* \param Sid A SID to query.
* \param Name A variable which receives a pointer to a string containing the SID's name. You must
* free the string using PhDereferenceObject() when you no longer need it.
* \param DomainName A variable which receives a pointer to a string containing the SID's domain
* name. You must free the string using PhDereferenceObject() when you no longer need it.
* \param NameUse A variable which receives the SID's usage.
*/
NTSTATUS PhLookupSid(
_In_ PSID Sid,
_Out_opt_ PPH_STRING *Name,
_Out_opt_ PPH_STRING *DomainName,
_Out_opt_ PSID_NAME_USE NameUse
)
{
NTSTATUS status;
LSA_HANDLE policyHandle;
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
PLSA_TRANSLATED_NAME names;
policyHandle = PhGetLookupPolicyHandle();
referencedDomains = NULL;
names = NULL;
if (NT_SUCCESS(status = LsaLookupSids(
policyHandle,
1,
&Sid,
&referencedDomains,
&names
)))
{
if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
{
if (Name)
{
*Name = PhCreateStringFromUnicodeString(&names[0].Name);
}
if (DomainName)
{
if (names[0].DomainIndex >= 0)
{
PLSA_TRUST_INFORMATION trustInfo;
trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
*DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);
}
else
{
*DomainName = PhReferenceEmptyString();
}
}
if (NameUse)
{
*NameUse = names[0].Use;
}
}
else
{
status = STATUS_NONE_MAPPED;
}
}
// LsaLookupSids allocates memory even if it returns STATUS_NONE_MAPPED.
if (referencedDomains)
LsaFreeMemory(referencedDomains);
if (names)
LsaFreeMemory(names);
return status;
}
/**
* Gets information about a name.
*
* \param Name A name to query.
* \param Sid A variable which receives a pointer to a SID. You must free the SID using PhFree()
* when you no longer need it.
* \param DomainName A variable which receives a pointer to a string containing the SID's domain
* name. You must free the string using PhDereferenceObject() when you no longer need it.
* \param NameUse A variable which receives the SID's usage.
*/
NTSTATUS PhLookupName(
_In_ PPH_STRINGREF Name,
_Out_opt_ PSID *Sid,
_Out_opt_ PPH_STRING *DomainName,
_Out_opt_ PSID_NAME_USE NameUse
)
{
NTSTATUS status;
LSA_HANDLE policyHandle;
UNICODE_STRING name;
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
PLSA_TRANSLATED_SID2 sids;
if (!PhStringRefToUnicodeString(Name, &name))
return STATUS_NAME_TOO_LONG;
policyHandle = PhGetLookupPolicyHandle();
referencedDomains = NULL;
sids = NULL;
if (NT_SUCCESS(status = LsaLookupNames2(
policyHandle,
0,
1,
&name,
&referencedDomains,
&sids
)))
{
if (sids[0].Use != SidTypeInvalid && sids[0].Use != SidTypeUnknown)
{
if (Sid)
{
PSID sid;
ULONG sidLength;
sidLength = RtlLengthSid(sids[0].Sid);
sid = PhAllocate(sidLength);
memcpy(sid, sids[0].Sid, sidLength);
*Sid = sid;
}
if (DomainName)
{
if (sids[0].DomainIndex >= 0)
{
PLSA_TRUST_INFORMATION trustInfo;
trustInfo = &referencedDomains->Domains[sids[0].DomainIndex];
*DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);
}
else
{
*DomainName = PhReferenceEmptyString();
}
}
if (NameUse)
{
*NameUse = sids[0].Use;
}
}
else
{
status = STATUS_NONE_MAPPED;
}
}
// LsaLookupNames2 allocates memory even if it returns STATUS_NONE_MAPPED.
if (referencedDomains)
LsaFreeMemory(referencedDomains);
if (sids)
LsaFreeMemory(sids);
return status;
}
/**
* Gets the name of a SID.
*
* \param Sid A SID to query.
* \param IncludeDomain TRUE to include the domain name, otherwise FALSE.
* \param NameUse A variable which receives the SID's usage.
*
* \return A pointer to a string containing the name of the SID in the following format:
* domain\\name. You must free the string using PhDereferenceObject() when you no longer need it. If
* an error occurs, the function returns NULL.
*/
PPH_STRING PhGetSidFullName(
_In_ PSID Sid,
_In_ BOOLEAN IncludeDomain,
_Out_opt_ PSID_NAME_USE NameUse
)
{
NTSTATUS status;
PPH_STRING fullName;
LSA_HANDLE policyHandle;
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
PLSA_TRANSLATED_NAME names;
policyHandle = PhGetLookupPolicyHandle();
referencedDomains = NULL;
names = NULL;
if (NT_SUCCESS(status = LsaLookupSids(
policyHandle,
1,
&Sid,
&referencedDomains,
&names
)))
{
if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
{
PWSTR domainNameBuffer;
ULONG domainNameLength;
if (IncludeDomain && names[0].DomainIndex >= 0)
{
PLSA_TRUST_INFORMATION trustInfo;
trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
domainNameBuffer = trustInfo->Name.Buffer;
domainNameLength = trustInfo->Name.Length;
}
else
{
domainNameBuffer = NULL;
domainNameLength = 0;
}
if (domainNameBuffer && domainNameLength != 0)
{
fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(WCHAR) + names[0].Name.Length);
memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength);
fullName->Buffer[domainNameLength / sizeof(WCHAR)] = '\\';
memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length);
}
else
{
fullName = PhCreateStringFromUnicodeString(&names[0].Name);
}
if (NameUse)
{
*NameUse = names[0].Use;
}
}
else
{
fullName = NULL;
}
}
else
{
fullName = NULL;
}
if (referencedDomains)
LsaFreeMemory(referencedDomains);
if (names)
LsaFreeMemory(names);
return fullName;
}
/**
* Gets a SDDL string representation of a SID.
*
* \param Sid A SID to query.
*
* \return A pointer to a string containing the SDDL representation of the SID. You must free the
* string using PhDereferenceObject() when you no longer need it. If an error occurs, the function
* returns NULL.
*/
PPH_STRING PhSidToStringSid(
_In_ PSID Sid
)
{
PPH_STRING string;
UNICODE_STRING us;
string = PhCreateStringEx(NULL, MAX_UNICODE_STACK_BUFFER_LENGTH * sizeof(WCHAR));
PhStringRefToUnicodeString(&string->sr, &us);
if (NT_SUCCESS(RtlConvertSidToUnicodeString(
&us,
Sid,
FALSE
)))
{
string->Length = us.Length;
string->Buffer[us.Length / sizeof(WCHAR)] = 0;
return string;
}
else
{
return NULL;
}
}

1218
phlib/mapimg.c Normal file

File diff suppressed because it is too large Load Diff

402
phlib/maplib.c Normal file
View File

@@ -0,0 +1,402 @@
/*
* Process Hacker -
* mapped library
*
* Copyright (C) 2010 wj32
*
* 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/>.
*/
/*
* This file contains functions to load and retrieve information for library/archive files (lib).
* The file format for archive files is explained in the PE/COFF specification located at:
*
* http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
*/
#include <ph.h>
#include <mapimg.h>
VOID PhpMappedArchiveProbe(
_In_ PPH_MAPPED_ARCHIVE MappedArchive,
_In_ PVOID Address,
_In_ SIZE_T Length
);
NTSTATUS PhpGetMappedArchiveMemberFromHeader(
_In_ PPH_MAPPED_ARCHIVE MappedArchive,
_In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header,
_Out_ PPH_MAPPED_ARCHIVE_MEMBER Member
);
NTSTATUS PhInitializeMappedArchive(
_Out_ PPH_MAPPED_ARCHIVE MappedArchive,
_In_ PVOID ViewBase,
_In_ SIZE_T Size
)
{
NTSTATUS status;
PCHAR start;
start = (PCHAR)ViewBase;
memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE));
MappedArchive->ViewBase = ViewBase;
MappedArchive->Size = Size;
__try
{
// Verify the file signature.
PhpMappedArchiveProbe(MappedArchive, start, IMAGE_ARCHIVE_START_SIZE);
if (memcmp(start, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE) != 0)
PhRaiseStatus(STATUS_INVALID_IMAGE_FORMAT);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
// Get the members.
// Note: the names are checked.
// First linker member
status = PhpGetMappedArchiveMemberFromHeader(
MappedArchive,
(PIMAGE_ARCHIVE_MEMBER_HEADER)(start + IMAGE_ARCHIVE_START_SIZE),
&MappedArchive->FirstLinkerMember
);
if (!NT_SUCCESS(status))
return status;
if (MappedArchive->FirstLinkerMember.Type != LinkerArchiveMemberType)
return STATUS_INVALID_PARAMETER;
MappedArchive->FirstStandardMember = &MappedArchive->FirstLinkerMember;
// Second linker member
status = PhGetNextMappedArchiveMember(
&MappedArchive->FirstLinkerMember,
&MappedArchive->SecondLinkerMember
);
if (!NT_SUCCESS(status))
return status;
if (MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType)
return STATUS_INVALID_PARAMETER;
// Longnames member
// This member doesn't seem to be mandatory, contrary to the specification.
// So we'll check if it's actually a longnames member, and if not, ignore it.
status = PhGetNextMappedArchiveMember(
&MappedArchive->SecondLinkerMember,
&MappedArchive->LongnamesMember
);
if (
NT_SUCCESS(status) &&
MappedArchive->LongnamesMember.Type == LongnamesArchiveMemberType
)
{
MappedArchive->HasLongnamesMember = TRUE;
MappedArchive->LastStandardMember = &MappedArchive->LongnamesMember;
}
else
{
MappedArchive->LastStandardMember = &MappedArchive->SecondLinkerMember;
}
return STATUS_SUCCESS;
}
NTSTATUS PhLoadMappedArchive(
_In_opt_ PWSTR FileName,
_In_opt_ HANDLE FileHandle,
_In_ BOOLEAN ReadOnly,
_Out_ PPH_MAPPED_ARCHIVE MappedArchive
)
{
NTSTATUS status;
status = PhMapViewOfEntireFile(
FileName,
FileHandle,
ReadOnly,
&MappedArchive->ViewBase,
&MappedArchive->Size
);
if (NT_SUCCESS(status))
{
status = PhInitializeMappedArchive(
MappedArchive,
MappedArchive->ViewBase,
MappedArchive->Size
);
if (!NT_SUCCESS(status))
{
NtUnmapViewOfSection(NtCurrentProcess(), MappedArchive->ViewBase);
}
}
return status;
}
NTSTATUS PhUnloadMappedArchive(
_Inout_ PPH_MAPPED_ARCHIVE MappedArchive
)
{
return NtUnmapViewOfSection(
NtCurrentProcess(),
MappedArchive->ViewBase
);
}
VOID PhpMappedArchiveProbe(
_In_ PPH_MAPPED_ARCHIVE MappedArchive,
_In_ PVOID Address,
_In_ SIZE_T Length
)
{
PhProbeAddress(Address, Length, MappedArchive->ViewBase, MappedArchive->Size, 1);
}
/**
* Gets the next archive member.
*
* \param Member An archive member structure.
* \param NextMember A variable which receives a structure describing the next archive member. This
* pointer may be the same as the pointer specified in \a Member.
*/
NTSTATUS PhGetNextMappedArchiveMember(
_In_ PPH_MAPPED_ARCHIVE_MEMBER Member,
_Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember
)
{
PIMAGE_ARCHIVE_MEMBER_HEADER nextHeader;
nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(
Member->Data,
Member->Size
);
// 2 byte alignment.
if ((ULONG_PTR)nextHeader & 0x1)
nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(nextHeader, 1);
return PhpGetMappedArchiveMemberFromHeader(
Member->MappedArchive,
nextHeader,
NextMember
);
}
NTSTATUS PhpGetMappedArchiveMemberFromHeader(
_In_ PPH_MAPPED_ARCHIVE MappedArchive,
_In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header,
_Out_ PPH_MAPPED_ARCHIVE_MEMBER Member
)
{
WCHAR integerString[11];
ULONG64 size;
PH_STRINGREF string;
PWSTR digit;
PSTR slash;
if ((ULONG_PTR)Header >= (ULONG_PTR)MappedArchive->ViewBase + MappedArchive->Size)
return STATUS_NO_MORE_ENTRIES;
__try
{
PhpMappedArchiveProbe(MappedArchive, Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
Member->MappedArchive = MappedArchive;
Member->Header = Header;
Member->Data = PTR_ADD_OFFSET(Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
Member->Type = NormalArchiveMemberType;
// Read the size string, terminate it after the last digit and parse it.
if (!PhCopyStringZFromBytes(Header->Size, 10, integerString, 11, NULL))
return STATUS_INVALID_PARAMETER;
string.Buffer = integerString;
string.Length = 0;
digit = string.Buffer;
while (iswdigit(*digit++))
string.Length += sizeof(WCHAR);
if (!PhStringToInteger64(&string, 10, &size))
return STATUS_INVALID_PARAMETER;
Member->Size = (ULONG)size;
__try
{
PhpMappedArchiveProbe(MappedArchive, Member->Data, Member->Size);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
// Parse the name.
if (!PhCopyBytesZ(Header->Name, 16, Member->NameBuffer, 20, NULL))
return STATUS_INVALID_PARAMETER;
Member->Name = Member->NameBuffer;
slash = strchr(Member->NameBuffer, '/');
if (!slash)
return STATUS_INVALID_PARAMETER;
// Special names:
// * If the slash is the first character, then this is a linker member.
// * If there is a slash after the slash which is a first character, then this is the longnames
// member.
// * If there are digits after the slash, then the real name is stored in the longnames member.
if (slash == Member->NameBuffer)
{
if (Member->NameBuffer[1] == '/')
{
// Longnames member. Set the name to "/".
Member->NameBuffer[0] = '/';
Member->NameBuffer[1] = 0;
Member->Type = LongnamesArchiveMemberType;
}
else
{
// Linker member. Set the name to "".
Member->NameBuffer[0] = 0;
Member->Type = LinkerArchiveMemberType;
}
}
else
{
if (isdigit(slash[1]))
{
PSTR digita;
ULONG64 offset64;
ULONG offset;
// The name is stored in the longnames member.
// Note: we make sure we have the longnames member first.
if (!MappedArchive->LongnamesMember.Header)
return STATUS_INVALID_PARAMETER;
// Find the last digit and null terminate the string there.
digita = slash + 2;
while (isdigit(*digita))
digita++;
*digita = 0;
// Parse the offset and make sure it lies within the longnames member.
if (!PhCopyStringZFromBytes(slash + 1, -1, integerString, 11, NULL))
return STATUS_INVALID_PARAMETER;
PhInitializeStringRefLongHint(&string, integerString);
if (!PhStringToInteger64(&string, 10, &offset64))
return STATUS_INVALID_PARAMETER;
offset = (ULONG)offset64;
if (offset >= MappedArchive->LongnamesMember.Size)
return STATUS_INVALID_PARAMETER;
// TODO: Probe the name.
Member->Name = (PSTR)PTR_ADD_OFFSET(MappedArchive->LongnamesMember.Data, offset);
}
else
{
// Null terminate the string.
slash[0] = 0;
}
}
return STATUS_SUCCESS;
}
BOOLEAN PhIsMappedArchiveMemberShortFormat(
_In_ PPH_MAPPED_ARCHIVE_MEMBER Member
)
{
PIMAGE_FILE_HEADER header;
header = (PIMAGE_FILE_HEADER)Member->Data;
return header->Machine != IMAGE_FILE_MACHINE_UNKNOWN;
}
NTSTATUS PhGetMappedArchiveImportEntry(
_In_ PPH_MAPPED_ARCHIVE_MEMBER Member,
_Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry
)
{
IMPORT_OBJECT_HEADER *importHeader;
importHeader = (IMPORT_OBJECT_HEADER *)Member->Data;
if (Member->Type != NormalArchiveMemberType)
return STATUS_INVALID_PARAMETER;
if (
importHeader->Sig1 != IMAGE_FILE_MACHINE_UNKNOWN ||
importHeader->Sig2 != IMPORT_OBJECT_HDR_SIG2
)
return STATUS_INVALID_PARAMETER;
Entry->Type = (BYTE)importHeader->Type;
Entry->NameType = (BYTE)importHeader->NameType;
Entry->Machine = importHeader->Machine;
// TODO: Probe the name.
Entry->Name = (PSTR)PTR_ADD_OFFSET(importHeader, sizeof(IMPORT_OBJECT_HEADER));
Entry->DllName = (PSTR)PTR_ADD_OFFSET(Entry->Name, strlen(Entry->Name) + 1);
// Ordinal/NameHint are union'ed, so these statements are exactly the same.
// It's there in case this changes in the future.
if (Entry->NameType == IMPORT_OBJECT_ORDINAL)
{
Entry->Ordinal = importHeader->Ordinal;
}
else
{
Entry->NameHint = importHeader->Hint;
}
return STATUS_SUCCESS;
}

225
phlib/md5.c Normal file
View File

@@ -0,0 +1,225 @@
/*
* MD5 hash implementation and interface functions
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* This code was modified for Process Hacker. */
#include <phbase.h>
#include "md5.h"
void MD5Transform(ULONG buf[4], ULONG in[16]);
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
VOID MD5Init(
_Out_ MD5_CTX *Context
)
{
Context->buf[0] = 0x67452301;
Context->buf[1] = 0xefcdab89;
Context->buf[2] = 0x98badcfe;
Context->buf[3] = 0x10325476;
Context->i[0] = 0;
Context->i[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
VOID MD5Update(
_Inout_ MD5_CTX *Context,
_In_reads_bytes_(Length) UCHAR *Input,
_In_ ULONG Length
)
{
ULONG t;
/* Update bitcount */
t = Context->i[0];
if ((Context->i[0] = t + ((ULONG) Length << 3)) < t)
Context->i[1]++; /* Carry from low to high */
Context->i[1] += Length >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) Context->in + t;
t = 64 - t;
if (Length < t) {
memcpy(p, Input, Length);
return;
}
memcpy(p, Input, t);
MD5Transform(Context->buf, (ULONG *) Context->in);
Input += t;
Length -= t;
}
/* Process data in 64-byte chunks */
while (Length >= 64) {
memcpy(Context->in, Input, 64);
MD5Transform(Context->buf, (ULONG *) Context->in);
Input += 64;
Length -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(Context->in, Input, Length);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
VOID MD5Final(
_Inout_ MD5_CTX *Context
)
{
unsigned int count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (Context->i[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = Context->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
MD5Transform(Context->buf, (ULONG *) Context->in);
/* Now fill the next block with 56 bytes */
memset(Context->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
/* Append length in bits and transform */
((ULONG *) Context->in)[14] = Context->i[0];
((ULONG *) Context->in)[15] = Context->i[1];
MD5Transform(Context->buf, (ULONG *) Context->in);
memcpy(Context->digest, Context->buf, 16);
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = _rotl(w, s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
void MD5Transform(ULONG buf[4], ULONG in[16])
{
register ULONG a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

26
phlib/md5.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef _MD5_H
#define _MD5_H
typedef struct
{
ULONG i[2];
ULONG buf[4];
UCHAR in[64];
UCHAR digest[16];
} MD5_CTX;
VOID MD5Init(
_Out_ MD5_CTX *Context
);
VOID MD5Update(
_Inout_ MD5_CTX *Context,
_In_reads_bytes_(Length) UCHAR *Input,
_In_ ULONG Length
);
VOID MD5Final(
_Inout_ MD5_CTX *Context
);
#endif

6460
phlib/native.c Normal file

File diff suppressed because it is too large Load Diff

247
phlib/phlib.vcxproj Normal file
View File

@@ -0,0 +1,247 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{477D0215-F252-41A1-874B-F27E3EA1ED17}</ProjectGuid>
<RootNamespace>phlib</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\phnt\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>DEBUG;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<TreatWarningAsError>true</TreatWarningAsError>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\phnt\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>DEBUG;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<TreatWarningAsError>true</TreatWarningAsError>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\phnt\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<TreatWarningAsError>true</TreatWarningAsError>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\phnt\include;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<TreatWarningAsError>true</TreatWarningAsError>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="apiimport.c" />
<ClCompile Include="avltree.c" />
<ClCompile Include="basesup.c" />
<ClCompile Include="circbuf.c" />
<ClCompile Include="colorbox.c" />
<ClCompile Include="cpysave.c" />
<ClCompile Include="data.c" />
<ClCompile Include="dspick.c" />
<ClCompile Include="emenu.c" />
<ClCompile Include="error.c" />
<ClCompile Include="extlv.c" />
<ClCompile Include="fastlock.c" />
<ClCompile Include="filepool.c" />
<ClCompile Include="format.c" />
<ClCompile Include="global.c" />
<ClCompile Include="graph.c" />
<ClCompile Include="guisup.c" />
<ClCompile Include="handle.c" />
<ClCompile Include="hexedit.c" />
<ClCompile Include="hndlinfo.c" />
<ClCompile Include="icotobmp.c" />
<ClCompile Include="filestream.c" />
<ClCompile Include="kph.c" />
<ClCompile Include="kphdata.c" />
<ClCompile Include="lsasup.c" />
<ClCompile Include="mapimg.c" />
<ClCompile Include="maplib.c" />
<ClCompile Include="md5.c" />
<ClCompile Include="native.c" />
<ClCompile Include="provider.c" />
<ClCompile Include="queuedlock.c" />
<ClCompile Include="ref.c" />
<ClCompile Include="secdata.c" />
<ClCompile Include="secedit.c" />
<ClCompile Include="sha.c" />
<ClCompile Include="util.c" />
<ClCompile Include="svcsup.c" />
<ClCompile Include="symprv.c" />
<ClCompile Include="sync.c" />
<ClCompile Include="treenew.c" />
<ClCompile Include="verify.c" />
<ClCompile Include="workqueue.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\apiimport.h" />
<ClInclude Include="include\cpysave.h" />
<ClInclude Include="include\filepool.h" />
<ClInclude Include="include\filepoolp.h" />
<ClInclude Include="include\filestream.h" />
<ClInclude Include="include\handle.h" />
<ClInclude Include="include\hndlinfo.h" />
<ClInclude Include="include\kphapi.h" />
<ClInclude Include="include\kphuserp.h" />
<ClInclude Include="include\lsasup.h" />
<ClInclude Include="include\mapimg.h" />
<ClInclude Include="include\phbasesup.h" />
<ClInclude Include="include\phconfig.h" />
<ClInclude Include="include\phdata.h" />
<ClInclude Include="include\phintrnl.h" />
<ClInclude Include="include\phnative.h" />
<ClInclude Include="include\phnativeinl.h" />
<ClInclude Include="include\circbuf.h" />
<ClInclude Include="include\circbuf_h.h" />
<ClInclude Include="circbuf_i.h" />
<ClInclude Include="include\colorbox.h" />
<ClInclude Include="include\phutil.h" />
<ClInclude Include="include\provider.h" />
<ClInclude Include="include\secedit.h" />
<ClInclude Include="include\svcsup.h" />
<ClInclude Include="include\symprvp.h" />
<ClInclude Include="include\treenew.h" />
<ClInclude Include="include\treenewp.h" />
<ClInclude Include="include\verify.h" />
<ClInclude Include="include\dltmgr.h" />
<ClInclude Include="include\dspick.h" />
<ClInclude Include="include\emenu.h" />
<ClInclude Include="include\fastlock.h" />
<ClInclude Include="format_i.h" />
<ClInclude Include="include\graph.h" />
<ClInclude Include="include\guisupp.h" />
<ClInclude Include="include\handlep.h" />
<ClInclude Include="include\hexedit.h" />
<ClInclude Include="include\hexeditp.h" />
<ClInclude Include="include\filestreamp.h" />
<ClInclude Include="include\kphuser.h" />
<ClInclude Include="md5.h" />
<ClInclude Include="include\ph.h" />
<ClInclude Include="include\phbase.h" />
<ClInclude Include="include\guisup.h" />
<ClInclude Include="include\phnet.h" />
<ClInclude Include="include\phsup.h" />
<ClInclude Include="include\queuedlock.h" />
<ClInclude Include="include\ref.h" />
<ClInclude Include="include\refp.h" />
<ClInclude Include="include\seceditp.h" />
<ClInclude Include="sha.h" />
<ClInclude Include="include\symprv.h" />
<ClInclude Include="include\templ.h" />
<ClInclude Include="include\verifyp.h" />
<ClInclude Include="include\workqueue.h" />
<ClInclude Include="include\workqueuep.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

314
phlib/phlib.vcxproj.filters Normal file
View File

@@ -0,0 +1,314 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="basesup.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="circbuf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="colorbox.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="data.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dspick.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="emenu.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="error.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="extlv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fastlock.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="format.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="global.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="graph.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="guisup.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="handle.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hexedit.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hndlinfo.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="icotobmp.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kph.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapimg.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="maplib.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="md5.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="native.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="provider.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="queuedlock.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ref.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="secdata.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="secedit.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sha.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="svcsup.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="symprv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sync.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="verify.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="workqueue.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cpysave.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="filepool.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="treenew.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kphdata.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="apiimport.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="avltree.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="filestream.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="lsasup.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="util.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\circbuf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\circbuf_h.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="circbuf_i.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\colorbox.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\dltmgr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\dspick.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\emenu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\fastlock.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="format_i.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\graph.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\guisupp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\handlep.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\hexedit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\hexeditp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\ph.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phbase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phnet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phsup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\queuedlock.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\ref.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\refp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\seceditp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\symprv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\templ.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\verifyp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phintrnl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\kphapi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\kphuser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\cpysave.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\filepool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\filepoolp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\treenew.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\treenewp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\verify.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\secedit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\symprvp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\apiimport.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\handle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\workqueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\mapimg.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\workqueuep.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\filestreamp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\filestream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\hndlinfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\provider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phdata.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phconfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phbasesup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\lsasup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phnativeinl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phnative.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\svcsup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\phutil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="md5.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sha.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\guisup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\kphuserp.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

470
phlib/provider.c Normal file
View File

@@ -0,0 +1,470 @@
/*
* Process Hacker -
* provider system
*
* Copyright (C) 2009-2016 wj32
*
* 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/>.
*/
/*
* Provider objects allow a function to be executed periodically. This is managed by a
* synchronization timer object which is signaled periodically. The use of a timer object as opposed
* to a simple sleep call means that the length of time a provider function takes to execute has no
* effect on the interval between runs.
*
* In contrast to callback objects, the context passed to provider functions must be
* reference-counted objects. This means that it is not guaranteed that the function will not be in
* execution after the unregister operation is complete. However, the since the context object is
* reference-counted, there are no safety issues.
*
* Providers can be boosted, which causes them to be run immediately ignoring the interval. This is
* separate to the periodic runs, and does not cause the next periodic run to be missed. Providers,
* even when boosted, always run on the same provider thread. The other option would be to have the
* boosting thread run the provider function directly, which would involve unnecessary blocking and
* synchronization.
*/
#include <ph.h>
#include <provider.h>
#ifdef DEBUG
PPH_LIST PhDbgProviderList;
PH_QUEUED_LOCK PhDbgProviderListLock = PH_QUEUED_LOCK_INIT;
#endif
/**
* Initializes a provider thread.
*
* \param ProviderThread A pointer to a provider thread object.
* \param Interval The interval between each run, in milliseconds.
*/
VOID PhInitializeProviderThread(
_Out_ PPH_PROVIDER_THREAD ProviderThread,
_In_ ULONG Interval
)
{
ProviderThread->ThreadHandle = NULL;
ProviderThread->TimerHandle = NULL;
ProviderThread->Interval = Interval;
ProviderThread->State = ProviderThreadStopped;
PhInitializeQueuedLock(&ProviderThread->Lock);
InitializeListHead(&ProviderThread->ListHead);
ProviderThread->BoostCount = 0;
#ifdef DEBUG
PhAcquireQueuedLockExclusive(&PhDbgProviderListLock);
if (!PhDbgProviderList)
PhDbgProviderList = PhCreateList(4);
PhAddItemList(PhDbgProviderList, ProviderThread);
PhReleaseQueuedLockExclusive(&PhDbgProviderListLock);
#endif
}
/**
* Frees resources used by a provider thread.
*
* \param ProviderThread A pointer to a provider thread object.
*/
VOID PhDeleteProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread
)
{
#ifdef DEBUG
ULONG index;
#endif
// Nothing
#ifdef DEBUG
PhAcquireQueuedLockExclusive(&PhDbgProviderListLock);
if ((index = PhFindItemList(PhDbgProviderList, ProviderThread)) != -1)
PhRemoveItemList(PhDbgProviderList, index);
PhReleaseQueuedLockExclusive(&PhDbgProviderListLock);
#endif
}
NTSTATUS NTAPI PhpProviderThreadStart(
_In_ PVOID Parameter
)
{
PH_AUTO_POOL autoPool;
PPH_PROVIDER_THREAD providerThread = (PPH_PROVIDER_THREAD)Parameter;
NTSTATUS status = STATUS_SUCCESS;
PLIST_ENTRY listEntry;
PPH_PROVIDER_REGISTRATION registration;
PPH_PROVIDER_FUNCTION providerFunction;
PVOID object;
LIST_ENTRY tempListHead;
PhInitializeAutoPool(&autoPool);
while (providerThread->State != ProviderThreadStopping)
{
// Keep removing and executing providers from the list until there are no more. Each removed
// provider will be placed on the temporary list. After this is done, all providers on the
// temporary list will be re-added to the list again.
//
// The key to this working safely with the other functions (boost, register, unregister) is
// that at all times when the mutex is not acquired every single provider must be in a list
// (main list or the temp list).
InitializeListHead(&tempListHead);
PhAcquireQueuedLockExclusive(&providerThread->Lock);
// Main loop.
// We check the status variable for STATUS_ALERTED, which means that someone is requesting
// that a provider be boosted. Note that if they alert this thread while we are not waiting
// on the timer, when we do perform the wait it will return immediately with STATUS_ALERTED.
while (TRUE)
{
if (status == STATUS_ALERTED)
{
// Check if we have any more providers to boost. Note that this always works because
// boosted providers are always in front of normal providers. Therefore we will
// never mistakenly boost normal providers.
if (providerThread->BoostCount == 0)
break;
}
listEntry = RemoveHeadList(&providerThread->ListHead);
if (listEntry == &providerThread->ListHead)
break;
registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry);
// Add the provider to the temp list.
InsertTailList(&tempListHead, listEntry);
if (status != STATUS_ALERTED)
{
if (!registration->Enabled || registration->Unregistering)
continue;
}
else
{
// If we're boosting providers, we don't care if they are enabled or not. However,
// we have to make sure any providers which are being unregistered get a chance to
// fix the boost count.
if (registration->Unregistering)
{
PhReleaseQueuedLockExclusive(&providerThread->Lock);
PhAcquireQueuedLockExclusive(&providerThread->Lock);
continue;
}
}
if (status == STATUS_ALERTED)
{
assert(registration->Boosting);
registration->Boosting = FALSE;
providerThread->BoostCount--;
}
providerFunction = registration->Function;
object = registration->Object;
if (object)
PhReferenceObject(object);
registration->RunId++;
PhReleaseQueuedLockExclusive(&providerThread->Lock);
providerFunction(object);
PhDrainAutoPool(&autoPool);
PhAcquireQueuedLockExclusive(&providerThread->Lock);
if (object)
PhDereferenceObject(object);
}
// Re-add the items in the temp list to the main list.
while ((listEntry = RemoveHeadList(&tempListHead)) != &tempListHead)
{
registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry);
// We must insert boosted providers at the front of the list in order to maintain the
// condition that boosted providers are always in front of normal providers. This occurs
// when the timer is signaled just before a boosting provider alerts our thread.
if (!registration->Boosting)
InsertTailList(&providerThread->ListHead, listEntry);
else
InsertHeadList(&providerThread->ListHead, listEntry);
}
PhReleaseQueuedLockExclusive(&providerThread->Lock);
// Perform an alertable wait so we can be woken up by someone telling us to boost providers,
// or to terminate.
status = NtWaitForSingleObject(
providerThread->TimerHandle,
TRUE,
NULL
);
}
PhDeleteAutoPool(&autoPool);
return STATUS_SUCCESS;
}
/**
* Starts a provider thread.
*
* \param ProviderThread A pointer to a provider thread object.
*/
VOID PhStartProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread
)
{
if (ProviderThread->State != ProviderThreadStopped)
return;
// Create and set the timer.
NtCreateTimer(&ProviderThread->TimerHandle, TIMER_ALL_ACCESS, NULL, SynchronizationTimer);
PhSetIntervalProviderThread(ProviderThread, ProviderThread->Interval);
// Create and start the thread.
ProviderThread->ThreadHandle = PhCreateThread(
0,
PhpProviderThreadStart,
ProviderThread
);
ProviderThread->State = ProviderThreadRunning;
}
/**
* Stops a provider thread.
*
* \param ProviderThread A pointer to a provider thread object.
*/
VOID PhStopProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread
)
{
if (ProviderThread->State != ProviderThreadRunning)
return;
// Signal to the thread that we are shutting down, and wait for it to exit.
ProviderThread->State = ProviderThreadStopping;
NtAlertThread(ProviderThread->ThreadHandle); // wake it up
NtWaitForSingleObject(ProviderThread->ThreadHandle, FALSE, NULL);
// Free resources.
NtClose(ProviderThread->ThreadHandle);
NtClose(ProviderThread->TimerHandle);
ProviderThread->ThreadHandle = NULL;
ProviderThread->TimerHandle = NULL;
ProviderThread->State = ProviderThreadStopped;
}
/**
* Sets the run interval for a provider thread.
*
* \param ProviderThread A pointer to a provider thread object.
* \param Interval The interval between each run, in milliseconds.
*/
VOID PhSetIntervalProviderThread(
_Inout_ PPH_PROVIDER_THREAD ProviderThread,
_In_ ULONG Interval
)
{
ProviderThread->Interval = Interval;
if (ProviderThread->TimerHandle)
{
LARGE_INTEGER interval;
interval.QuadPart = -(LONGLONG)Interval * PH_TIMEOUT_MS;
NtSetTimer(ProviderThread->TimerHandle, &interval, NULL, NULL, FALSE, Interval, NULL);
}
}
/**
* Registers a provider with a provider thread.
*
* \param ProviderThread A pointer to a provider thread object.
* \param Function The provider function.
* \param Object A pointer to an object to pass to the provider function. The object must be managed
* by the reference-counting system.
* \param Registration A variable which receives registration information for the provider.
*
* \remarks The provider is initially disabled. Call PhSetEnabledProvider() to enable it.
*/
VOID PhRegisterProvider(
_Inout_ PPH_PROVIDER_THREAD ProviderThread,
_In_ PPH_PROVIDER_FUNCTION Function,
_In_opt_ PVOID Object,
_Out_ PPH_PROVIDER_REGISTRATION Registration
)
{
Registration->ProviderThread = ProviderThread;
Registration->Function = Function;
Registration->Object = Object;
Registration->RunId = 0;
Registration->Enabled = FALSE;
Registration->Unregistering = FALSE;
Registration->Boosting = FALSE;
if (Object)
PhReferenceObject(Object);
PhAcquireQueuedLockExclusive(&ProviderThread->Lock);
InsertTailList(&ProviderThread->ListHead, &Registration->ListEntry);
PhReleaseQueuedLockExclusive(&ProviderThread->Lock);
}
/**
* Unregisters a provider.
*
* \param Registration A pointer to the registration object for a provider.
*
* \remarks The provider function may still be in execution once this function returns.
*/
VOID PhUnregisterProvider(
_Inout_ PPH_PROVIDER_REGISTRATION Registration
)
{
PPH_PROVIDER_THREAD providerThread;
providerThread = Registration->ProviderThread;
Registration->Unregistering = TRUE;
// There are two possibilities for removal:
// 1. The provider is removed while the thread is not in the main loop. This is the normal case.
// 2. The provider is removed while the thread is in the main loop. In that case the provider
// will be removed from the temp list and so it won't be re-added to the main list.
PhAcquireQueuedLockExclusive(&providerThread->Lock);
RemoveEntryList(&Registration->ListEntry);
// Fix the boost count.
if (Registration->Boosting)
providerThread->BoostCount--;
// The user-supplied object must be dereferenced
// while the mutex is held.
if (Registration->Object)
PhDereferenceObject(Registration->Object);
PhReleaseQueuedLockExclusive(&providerThread->Lock);
}
/**
* Causes a provider to be queued for immediate execution.
*
* \param Registration A pointer to the registration object for a provider.
* \param FutureRunId A variable which receives the run ID of the future run.
*
* \return TRUE if the operation was successful; FALSE if the provider is being unregistered, the
* provider is already being boosted, or the provider thread is not running.
*
* \remarks Boosted providers will be run immediately, ignoring the run interval. Boosting will not
* however affect the normal runs.
*/
BOOLEAN PhBoostProvider(
_Inout_ PPH_PROVIDER_REGISTRATION Registration,
_Out_opt_ PULONG FutureRunId
)
{
PPH_PROVIDER_THREAD providerThread;
ULONG futureRunId;
if (Registration->Unregistering)
return FALSE;
providerThread = Registration->ProviderThread;
// Simply move to the provider to the front of the list. This works even if the provider is
// currently in the temp list.
PhAcquireQueuedLockExclusive(&providerThread->Lock);
// Abort if the provider is already being boosted or the provider thread is stopping/stopped.
if (Registration->Boosting || providerThread->State != ProviderThreadRunning)
{
PhReleaseQueuedLockExclusive(&providerThread->Lock);
return FALSE;
}
RemoveEntryList(&Registration->ListEntry);
InsertHeadList(&providerThread->ListHead, &Registration->ListEntry);
Registration->Boosting = TRUE;
providerThread->BoostCount++;
futureRunId = Registration->RunId + 1;
PhReleaseQueuedLockExclusive(&providerThread->Lock);
// Wake up the thread.
NtAlertThread(providerThread->ThreadHandle);
if (FutureRunId)
*FutureRunId = futureRunId;
return TRUE;
}
/**
* Gets the current run ID of a provider.
*
* \param Registration A pointer to the registration object for a provider.
*/
ULONG PhGetRunIdProvider(
_In_ PPH_PROVIDER_REGISTRATION Registration
)
{
return Registration->RunId;
}
/**
* Gets whether a provider is enabled.
*
* \param Registration A pointer to the registration object for a provider.
*/
BOOLEAN PhGetEnabledProvider(
_In_ PPH_PROVIDER_REGISTRATION Registration
)
{
return Registration->Enabled;
}
/**
* Sets whether a provider is enabled.
*
* \param Registration A pointer to the registration object for a provider.
* \param Enabled TRUE if the provider is enabled, otherwise FALSE.
*/
VOID PhSetEnabledProvider(
_Inout_ PPH_PROVIDER_REGISTRATION Registration,
_In_ BOOLEAN Enabled
)
{
Registration->Enabled = Enabled;
}

1201
phlib/queuedlock.c Normal file

File diff suppressed because it is too large Load Diff

753
phlib/ref.c Normal file
View File

@@ -0,0 +1,753 @@
/*
* Process Hacker -
* object manager
*
* Copyright (C) 2009-2016 wj32
*
* 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 <phbase.h>
#include <phintrnl.h>
#include <workqueue.h>
#include <refp.h>
PPH_OBJECT_TYPE PhObjectTypeObject = NULL;
SLIST_HEADER PhObjectDeferDeleteListHead;
PH_FREE_LIST PhObjectSmallFreeList;
PPH_OBJECT_TYPE PhAllocType = NULL;
ULONG PhObjectTypeCount = 0;
PPH_OBJECT_TYPE PhObjectTypeTable[PH_OBJECT_TYPE_TABLE_SIZE];
static ULONG PhpAutoPoolTlsIndex;
#ifdef DEBUG
LIST_ENTRY PhDbgObjectListHead;
PH_QUEUED_LOCK PhDbgObjectListLock = PH_QUEUED_LOCK_INIT;
PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook = NULL;
#endif
#define REF_STAT_UP(Name) PHLIB_INC_STATISTIC(Name)
/**
* Initializes the object manager module.
*/
NTSTATUS PhRefInitialization(
VOID
)
{
PH_OBJECT_TYPE dummyObjectType;
#ifdef DEBUG
InitializeListHead(&PhDbgObjectListHead);
#endif
RtlInitializeSListHead(&PhObjectDeferDeleteListHead);
PhInitializeFreeList(
&PhObjectSmallFreeList,
PhAddObjectHeaderSize(PH_OBJECT_SMALL_OBJECT_SIZE),
PH_OBJECT_SMALL_OBJECT_COUNT
);
// Create the fundamental object type.
memset(&dummyObjectType, 0, sizeof(PH_OBJECT_TYPE));
PhObjectTypeObject = &dummyObjectType; // PhCreateObject expects an object type.
PhObjectTypeTable[0] = &dummyObjectType; // PhCreateObject also expects PhObjectTypeTable[0] to be filled in.
PhObjectTypeObject = PhCreateObjectType(L"Type", 0, NULL);
// Now that the fundamental object type exists, fix it up.
PhObjectToObjectHeader(PhObjectTypeObject)->TypeIndex = PhObjectTypeObject->TypeIndex;
PhObjectTypeObject->NumberOfObjects = 1;
// Create the allocated memory object type.
PhAllocType = PhCreateObjectType(L"Alloc", 0, NULL);
// Reserve a slot for the auto pool.
PhpAutoPoolTlsIndex = TlsAlloc();
if (PhpAutoPoolTlsIndex == TLS_OUT_OF_INDEXES)
return STATUS_INSUFFICIENT_RESOURCES;
return STATUS_SUCCESS;
}
/**
* Allocates a object.
*
* \param ObjectSize The size of the object.
* \param ObjectType The type of the object.
*
* \return A pointer to the newly allocated object.
*/
_May_raise_ PVOID PhCreateObject(
_In_ SIZE_T ObjectSize,
_In_ PPH_OBJECT_TYPE ObjectType
)
{
NTSTATUS status = STATUS_SUCCESS;
PPH_OBJECT_HEADER objectHeader;
// Allocate storage for the object. Note that this includes the object header followed by the
// object body.
objectHeader = PhpAllocateObject(ObjectType, ObjectSize);
// Object type statistics.
_InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects);
// Initialize the object header.
objectHeader->RefCount = 1;
objectHeader->TypeIndex = ObjectType->TypeIndex;
// objectHeader->Flags is set by PhpAllocateObject.
REF_STAT_UP(RefObjectsCreated);
#ifdef DEBUG
{
USHORT capturedFrames;
capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL);
memset(
&objectHeader->StackBackTrace[capturedFrames],
0,
sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID)
);
}
PhAcquireQueuedLockExclusive(&PhDbgObjectListLock);
InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry);
PhReleaseQueuedLockExclusive(&PhDbgObjectListLock);
{
PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook;
dbgCreateObjectHook = PhDbgCreateObjectHook;
if (dbgCreateObjectHook)
{
dbgCreateObjectHook(
PhObjectHeaderToObject(objectHeader),
ObjectSize,
0,
ObjectType
);
}
}
#endif
return PhObjectHeaderToObject(objectHeader);
}
/**
* References the specified object.
*
* \param Object A pointer to the object to reference.
*
* \return The object.
*/
PVOID PhReferenceObject(
_In_ PVOID Object
)
{
PPH_OBJECT_HEADER objectHeader;
objectHeader = PhObjectToObjectHeader(Object);
// Increment the reference count.
_InterlockedIncrement(&objectHeader->RefCount);
return Object;
}
/**
* References the specified object.
*
* \param Object A pointer to the object to reference.
* \param RefCount The number of references to add.
*
* \return The object.
*/
_May_raise_ PVOID PhReferenceObjectEx(
_In_ PVOID Object,
_In_ LONG RefCount
)
{
PPH_OBJECT_HEADER objectHeader;
LONG oldRefCount;
assert(!(RefCount < 0));
objectHeader = PhObjectToObjectHeader(Object);
// Increase the reference count.
oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, RefCount);
return Object;
}
/**
* Attempts to reference an object and fails if it is being destroyed.
*
* \param Object The object to reference if it is not being deleted.
*
* \return The object itself if the object was referenced, NULL if it was being deleted and was not
* referenced.
*
* \remarks This function is useful if a reference to an object is held, protected by a mutex, and
* the delete procedure of the object's type attempts to acquire the mutex. If this function is
* called while the mutex is owned, you can avoid referencing an object that is being destroyed.
*/
PVOID PhReferenceObjectSafe(
_In_ PVOID Object
)
{
PPH_OBJECT_HEADER objectHeader;
objectHeader = PhObjectToObjectHeader(Object);
// Increase the reference count only if it positive already (atomically).
if (PhpInterlockedIncrementSafe(&objectHeader->RefCount))
return Object;
else
return NULL;
}
/**
* Dereferences the specified object.
* The object will be freed if its reference count reaches 0.
*
* \param Object A pointer to the object to dereference.
*/
VOID PhDereferenceObject(
_In_ PVOID Object
)
{
PPH_OBJECT_HEADER objectHeader;
LONG newRefCount;
objectHeader = PhObjectToObjectHeader(Object);
// Decrement the reference count.
newRefCount = _InterlockedDecrement(&objectHeader->RefCount);
ASSUME_ASSERT(newRefCount >= 0);
// Free the object if it has 0 references.
if (newRefCount == 0)
{
PhpFreeObject(objectHeader);
}
}
/**
* Dereferences the specified object.
* The object will be freed in a worker thread if its reference count reaches 0.
*
* \param Object A pointer to the object to dereference.
*/
VOID PhDereferenceObjectDeferDelete(
_In_ PVOID Object
)
{
PhDereferenceObjectEx(Object, 1, TRUE);
}
/**
* Dereferences the specified object.
* The object will be freed if its reference count reaches 0.
*
* \param Object A pointer to the object to dereference.
* \param RefCount The number of references to remove.
* \param DeferDelete Whether to defer deletion of the object.
*/
_May_raise_ VOID PhDereferenceObjectEx(
_In_ PVOID Object,
_In_ LONG RefCount,
_In_ BOOLEAN DeferDelete
)
{
PPH_OBJECT_HEADER objectHeader;
LONG oldRefCount;
LONG newRefCount;
assert(!(RefCount < 0));
objectHeader = PhObjectToObjectHeader(Object);
// Decrease the reference count.
oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount);
newRefCount = oldRefCount - RefCount;
// Free the object if it has 0 references.
if (newRefCount == 0)
{
if (DeferDelete)
{
PhpDeferDeleteObject(objectHeader);
}
else
{
// Free the object.
PhpFreeObject(objectHeader);
}
}
else if (newRefCount < 0)
{
PhRaiseStatus(STATUS_INVALID_PARAMETER);
}
}
/**
* Gets an object's type.
*
* \param Object A pointer to an object.
*
* \return A pointer to a type object.
*/
PPH_OBJECT_TYPE PhGetObjectType(
_In_ PVOID Object
)
{
return PhObjectTypeTable[PhObjectToObjectHeader(Object)->TypeIndex];
}
/**
* Creates an object type.
*
* \param Name The name of the type.
* \param Flags A combination of flags affecting the behaviour of the object type.
* \param DeleteProcedure A callback function that is executed when an object of this type is about
* to be freed (i.e. when its reference count is 0).
*
* \return A pointer to the newly created object type.
*
* \remarks Do not reference or dereference the object type once it is created.
*/
PPH_OBJECT_TYPE PhCreateObjectType(
_In_ PWSTR Name,
_In_ ULONG Flags,
_In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure
)
{
return PhCreateObjectTypeEx(
Name,
Flags,
DeleteProcedure,
NULL
);
}
/**
* Creates an object type.
*
* \param Name The name of the type.
* \param Flags A combination of flags affecting the behaviour of the object type.
* \param DeleteProcedure A callback function that is executed when an object of this type is about
* to be freed (i.e. when its reference count is 0).
* \param Parameters A structure containing additional parameters for the object type.
*
* \return A pointer to the newly created object type.
*
* \remarks Do not reference or dereference the object type once it is created.
*/
PPH_OBJECT_TYPE PhCreateObjectTypeEx(
_In_ PWSTR Name,
_In_ ULONG Flags,
_In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure,
_In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters
)
{
NTSTATUS status = STATUS_SUCCESS;
PPH_OBJECT_TYPE objectType;
// Check the flags.
if ((Flags & PH_OBJECT_TYPE_VALID_FLAGS) != Flags) /* Valid flag mask */
PhRaiseStatus(STATUS_INVALID_PARAMETER_3);
if ((Flags & PH_OBJECT_TYPE_USE_FREE_LIST) && !Parameters)
PhRaiseStatus(STATUS_INVALID_PARAMETER_MIX);
// Create the type object.
objectType = PhCreateObject(sizeof(PH_OBJECT_TYPE), PhObjectTypeObject);
// Initialize the type object.
objectType->Flags = (USHORT)Flags;
objectType->TypeIndex = (USHORT)_InterlockedIncrement(&PhObjectTypeCount) - 1;
objectType->NumberOfObjects = 0;
objectType->DeleteProcedure = DeleteProcedure;
objectType->Name = Name;
if (objectType->TypeIndex < PH_OBJECT_TYPE_TABLE_SIZE)
PhObjectTypeTable[objectType->TypeIndex] = objectType;
else
PhRaiseStatus(STATUS_UNSUCCESSFUL);
if (Parameters)
{
if (Flags & PH_OBJECT_TYPE_USE_FREE_LIST)
{
PhInitializeFreeList(
&objectType->FreeList,
PhAddObjectHeaderSize(Parameters->FreeListSize),
Parameters->FreeListCount
);
}
}
return objectType;
}
/**
* Gets information about an object type.
*
* \param ObjectType A pointer to an object type.
* \param Information A variable which receives information about the object type.
*/
VOID PhGetObjectTypeInformation(
_In_ PPH_OBJECT_TYPE ObjectType,
_Out_ PPH_OBJECT_TYPE_INFORMATION Information
)
{
Information->Name = ObjectType->Name;
Information->NumberOfObjects = ObjectType->NumberOfObjects;
Information->Flags = ObjectType->Flags;
Information->TypeIndex = ObjectType->TypeIndex;
}
/**
* Allocates storage for an object.
*
* \param ObjectType The type of the object.
* \param ObjectSize The size of the object, excluding the header.
*/
PPH_OBJECT_HEADER PhpAllocateObject(
_In_ PPH_OBJECT_TYPE ObjectType,
_In_ SIZE_T ObjectSize
)
{
PPH_OBJECT_HEADER objectHeader;
if (ObjectType->Flags & PH_OBJECT_TYPE_USE_FREE_LIST)
{
assert(ObjectType->FreeList.Size == PhAddObjectHeaderSize(ObjectSize));
objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList);
objectHeader->Flags = PH_OBJECT_FROM_TYPE_FREE_LIST;
REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList);
}
else if (ObjectSize <= PH_OBJECT_SMALL_OBJECT_SIZE)
{
objectHeader = PhAllocateFromFreeList(&PhObjectSmallFreeList);
objectHeader->Flags = PH_OBJECT_FROM_SMALL_FREE_LIST;
REF_STAT_UP(RefObjectsAllocatedFromSmallFreeList);
}
else
{
objectHeader = PhAllocate(PhAddObjectHeaderSize(ObjectSize));
objectHeader->Flags = 0;
REF_STAT_UP(RefObjectsAllocated);
}
return objectHeader;
}
/**
* Calls the delete procedure for an object and frees its allocated storage.
*
* \param ObjectHeader A pointer to the object header of an allocated object.
*/
VOID PhpFreeObject(
_In_ PPH_OBJECT_HEADER ObjectHeader
)
{
PPH_OBJECT_TYPE objectType;
objectType = PhObjectTypeTable[ObjectHeader->TypeIndex];
// Object type statistics.
_InterlockedDecrement(&objectType->NumberOfObjects);
#ifdef DEBUG
PhAcquireQueuedLockExclusive(&PhDbgObjectListLock);
RemoveEntryList(&ObjectHeader->ObjectListEntry);
PhReleaseQueuedLockExclusive(&PhDbgObjectListLock);
#endif
REF_STAT_UP(RefObjectsDestroyed);
// Call the delete procedure if we have one.
if (objectType->DeleteProcedure)
{
objectType->DeleteProcedure(PhObjectHeaderToObject(ObjectHeader), 0);
}
if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST)
{
PhFreeToFreeList(&objectType->FreeList, ObjectHeader);
REF_STAT_UP(RefObjectsFreedToTypeFreeList);
}
else if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST)
{
PhFreeToFreeList(&PhObjectSmallFreeList, ObjectHeader);
REF_STAT_UP(RefObjectsFreedToSmallFreeList);
}
else
{
PhFree(ObjectHeader);
REF_STAT_UP(RefObjectsFreed);
}
}
/**
* Queues an object for deletion.
*
* \param ObjectHeader A pointer to the object header of the object to delete.
*/
VOID PhpDeferDeleteObject(
_In_ PPH_OBJECT_HEADER ObjectHeader
)
{
PSLIST_ENTRY oldFirstEntry;
// Save TypeIndex and Flags since they get overwritten when we push the object onto the defer
// delete list.
ObjectHeader->DeferDelete = 1;
MemoryBarrier();
ObjectHeader->SavedTypeIndex = ObjectHeader->TypeIndex;
ObjectHeader->SavedFlags = ObjectHeader->Flags;
oldFirstEntry = RtlFirstEntrySList(&PhObjectDeferDeleteListHead);
RtlInterlockedPushEntrySList(&PhObjectDeferDeleteListHead, &ObjectHeader->DeferDeleteListEntry);
REF_STAT_UP(RefObjectsDeleteDeferred);
// Was the to-free list empty before? If so, we need to queue a work item.
if (!oldFirstEntry)
{
PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpDeferDeleteObjectRoutine, NULL);
}
}
/**
* Removes and frees objects from the to-free list.
*/
NTSTATUS PhpDeferDeleteObjectRoutine(
_In_ PVOID Parameter
)
{
PSLIST_ENTRY listEntry;
PPH_OBJECT_HEADER objectHeader;
// Clear the list and obtain the first object to free.
listEntry = RtlInterlockedFlushSList(&PhObjectDeferDeleteListHead);
while (listEntry)
{
objectHeader = CONTAINING_RECORD(listEntry, PH_OBJECT_HEADER, DeferDeleteListEntry);
listEntry = listEntry->Next;
// Restore TypeIndex and Flags.
objectHeader->TypeIndex = (USHORT)objectHeader->SavedTypeIndex;
objectHeader->Flags = (UCHAR)objectHeader->SavedFlags;
PhpFreeObject(objectHeader);
}
return STATUS_SUCCESS;
}
/**
* Creates a reference-counted memory block.
*
* \param Size The number of bytes to allocate.
*
* \return A pointer to the memory block.
*/
PVOID PhCreateAlloc(
_In_ SIZE_T Size
)
{
return PhCreateObject(Size, PhAllocType);
}
/**
* Gets the current auto-dereference pool for the current thread.
*/
FORCEINLINE PPH_AUTO_POOL PhpGetCurrentAutoPool(
VOID
)
{
return (PPH_AUTO_POOL)TlsGetValue(PhpAutoPoolTlsIndex);
}
/**
* Sets the current auto-dereference pool for the current thread.
*/
_May_raise_ FORCEINLINE VOID PhpSetCurrentAutoPool(
_In_ PPH_AUTO_POOL AutoPool
)
{
if (!TlsSetValue(PhpAutoPoolTlsIndex, AutoPool))
PhRaiseStatus(STATUS_UNSUCCESSFUL);
#ifdef DEBUG
{
PPHP_BASE_THREAD_DBG dbg;
dbg = (PPHP_BASE_THREAD_DBG)TlsGetValue(PhDbgThreadDbgTlsIndex);
if (dbg)
{
dbg->CurrentAutoPool = AutoPool;
}
}
#endif
}
/**
* Initializes an auto-dereference pool and sets it as the current pool for the current thread. You
* must call PhDeleteAutoPool() before storage for the auto-dereference pool is freed.
*
* \remarks Always store auto-dereference pools in local variables, and do not share the pool with
* any other functions.
*/
VOID PhInitializeAutoPool(
_Out_ PPH_AUTO_POOL AutoPool
)
{
AutoPool->StaticCount = 0;
AutoPool->DynamicCount = 0;
AutoPool->DynamicAllocated = 0;
AutoPool->DynamicObjects = NULL;
// Add the pool to the stack.
AutoPool->NextPool = PhpGetCurrentAutoPool();
PhpSetCurrentAutoPool(AutoPool);
REF_STAT_UP(RefAutoPoolsCreated);
}
/**
* Deletes an auto-dereference pool. The function will dereference any objects currently in the
* pool. If a pool other than the current pool is passed to the function, an exception is raised.
*
* \param AutoPool The auto-dereference pool to delete.
*/
_May_raise_ VOID PhDeleteAutoPool(
_Inout_ PPH_AUTO_POOL AutoPool
)
{
PhDrainAutoPool(AutoPool);
if (PhpGetCurrentAutoPool() != AutoPool)
PhRaiseStatus(STATUS_UNSUCCESSFUL);
// Remove the pool from the stack.
PhpSetCurrentAutoPool(AutoPool->NextPool);
// Free the dynamic array if it hasn't been freed yet.
if (AutoPool->DynamicObjects)
PhFree(AutoPool->DynamicObjects);
REF_STAT_UP(RefAutoPoolsDestroyed);
}
/**
* Dereferences and removes all objects in an auto-release pool.
*
* \param AutoPool The auto-release pool to drain.
*/
VOID PhDrainAutoPool(
_In_ PPH_AUTO_POOL AutoPool
)
{
ULONG i;
for (i = 0; i < AutoPool->StaticCount; i++)
PhDereferenceObject(AutoPool->StaticObjects[i]);
AutoPool->StaticCount = 0;
if (AutoPool->DynamicObjects)
{
for (i = 0; i < AutoPool->DynamicCount; i++)
{
PhDereferenceObject(AutoPool->DynamicObjects[i]);
}
AutoPool->DynamicCount = 0;
if (AutoPool->DynamicAllocated > PH_AUTO_POOL_DYNAMIC_BIG_SIZE)
{
AutoPool->DynamicAllocated = 0;
PhFree(AutoPool->DynamicObjects);
AutoPool->DynamicObjects = NULL;
}
}
}
/**
* Adds an object to the current auto-dereference pool for the current thread. If the current thread
* does not have an auto-dereference pool, the function raises an exception.
*
* \param Object A pointer to an object. The object will be dereferenced when the current
* auto-dereference pool is drained or freed.
*/
_May_raise_ PVOID PhAutoDereferenceObject(
_In_opt_ PVOID Object
)
{
PPH_AUTO_POOL autoPool = PhpGetCurrentAutoPool();
#ifdef DEBUG
// If we don't have an auto-dereference pool, we don't want to leak the object (unlike what
// Apple does with NSAutoreleasePool).
if (!autoPool)
PhRaiseStatus(STATUS_UNSUCCESSFUL);
#endif
if (!Object)
return NULL;
// See if we can use the static array.
if (autoPool->StaticCount < PH_AUTO_POOL_STATIC_SIZE)
{
autoPool->StaticObjects[autoPool->StaticCount++] = Object;
return Object;
}
// Use the dynamic array.
// Allocate the array if we haven't already.
if (!autoPool->DynamicObjects)
{
autoPool->DynamicAllocated = 64;
autoPool->DynamicObjects = PhAllocate(
sizeof(PVOID) * autoPool->DynamicAllocated
);
REF_STAT_UP(RefAutoPoolsDynamicAllocated);
}
// See if we need to resize the array.
if (autoPool->DynamicCount == autoPool->DynamicAllocated)
{
autoPool->DynamicAllocated *= 2;
autoPool->DynamicObjects = PhReAllocate(
autoPool->DynamicObjects,
sizeof(PVOID) * autoPool->DynamicAllocated
);
REF_STAT_UP(RefAutoPoolsDynamicResized);
}
autoPool->DynamicObjects[autoPool->DynamicCount++] = Object;
return Object;
}

786
phlib/secdata.c Normal file
View File

@@ -0,0 +1,786 @@
/*
* Process Hacker -
* object security data
*
* Copyright (C) 2010-2016 wj32
*
* 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 <ph.h>
#include <guisup.h>
#include <secedit.h>
#include <wmistr.h>
#define ACCESS_ENTRIES(Type) static PH_ACCESS_ENTRY Ph##Type##AccessEntries[] =
#define ACCESS_ENTRY(Type, HasSynchronize) \
{ L#Type, Ph##Type##AccessEntries, sizeof(Ph##Type##AccessEntries), HasSynchronize }
typedef struct _PH_SPECIFIC_TYPE
{
PWSTR Type;
PPH_ACCESS_ENTRY AccessEntries;
ULONG SizeOfAccessEntries;
BOOLEAN HasSynchronize;
} PH_SPECIFIC_TYPE, *PPH_SPECIFIC_TYPE;
ACCESS_ENTRIES(Standard)
{
{ L"Synchronize", SYNCHRONIZE, FALSE, TRUE },
{ L"Delete", DELETE, FALSE, TRUE },
{ L"Read permissions", READ_CONTROL, FALSE, TRUE, L"Read control" },
{ L"Change permissions", WRITE_DAC, FALSE, TRUE, L"Write DAC" },
{ L"Take ownership", WRITE_OWNER, FALSE, TRUE, L"Write owner" }
};
ACCESS_ENTRIES(AlpcPort)
{
{ L"Full control", PORT_ALL_ACCESS, TRUE, TRUE },
{ L"Connect", PORT_CONNECT, TRUE, TRUE }
};
ACCESS_ENTRIES(DebugObject)
{
{ L"Full control", DEBUG_ALL_ACCESS, TRUE, TRUE },
{ L"Read events", DEBUG_READ_EVENT, TRUE, TRUE },
{ L"Assign processes", DEBUG_PROCESS_ASSIGN, TRUE, TRUE },
{ L"Query information", DEBUG_QUERY_INFORMATION, TRUE, TRUE },
{ L"Set information", DEBUG_SET_INFORMATION, TRUE, TRUE }
};
ACCESS_ENTRIES(Desktop)
{
{ L"Full control", DESKTOP_ALL_ACCESS, TRUE, TRUE },
{ L"Read", DESKTOP_GENERIC_READ, TRUE, FALSE },
{ L"Write", DESKTOP_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", DESKTOP_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Enumerate", DESKTOP_ENUMERATE, FALSE, TRUE },
{ L"Read objects", DESKTOP_READOBJECTS, FALSE, TRUE },
{ L"Playback journals", DESKTOP_JOURNALPLAYBACK, FALSE, TRUE },
{ L"Write objects", DESKTOP_WRITEOBJECTS, FALSE, TRUE },
{ L"Create windows", DESKTOP_CREATEWINDOW, FALSE, TRUE },
{ L"Create menus", DESKTOP_CREATEMENU, FALSE, TRUE },
{ L"Create window hooks", DESKTOP_HOOKCONTROL, FALSE, TRUE },
{ L"Record journals", DESKTOP_JOURNALRECORD, FALSE, TRUE },
{ L"Switch desktop", DESKTOP_SWITCHDESKTOP, FALSE, TRUE }
};
ACCESS_ENTRIES(Directory)
{
{ L"Full control", DIRECTORY_ALL_ACCESS, TRUE, TRUE },
{ L"Query", DIRECTORY_QUERY, TRUE, TRUE},
{ L"Traverse", DIRECTORY_TRAVERSE, TRUE, TRUE},
{ L"Create objects", DIRECTORY_CREATE_OBJECT, TRUE, TRUE},
{ L"Create subdirectories", DIRECTORY_CREATE_SUBDIRECTORY, TRUE, TRUE}
};
ACCESS_ENTRIES(Event)
{
{ L"Full control", EVENT_ALL_ACCESS, TRUE, TRUE },
{ L"Query", EVENT_QUERY_STATE, TRUE, TRUE },
{ L"Modify", EVENT_MODIFY_STATE, TRUE, TRUE }
};
ACCESS_ENTRIES(EventPair)
{
{ L"Full control", EVENT_PAIR_ALL_ACCESS, TRUE, TRUE }
};
ACCESS_ENTRIES(File)
{
{ L"Full control", FILE_ALL_ACCESS, TRUE, TRUE },
{ L"Read & execute", FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Read", FILE_GENERIC_READ, TRUE, FALSE },
{ L"Write", FILE_GENERIC_WRITE, TRUE, FALSE },
{ L"Traverse folder / execute file", FILE_EXECUTE, FALSE, TRUE, L"Execute" },
{ L"List folder / read data", FILE_READ_DATA, FALSE, TRUE, L"Read data" },
{ L"Read attributes", FILE_READ_ATTRIBUTES, FALSE, TRUE },
{ L"Read extended attributes", FILE_READ_EA, FALSE, TRUE, L"Read EA" },
{ L"Create files / write data", FILE_WRITE_DATA, FALSE, TRUE, L"Write data" },
{ L"Create folders / append data", FILE_APPEND_DATA, FALSE, TRUE, L"Append data" },
{ L"Write attributes", FILE_WRITE_ATTRIBUTES, FALSE, TRUE },
{ L"Write extended attributes", FILE_WRITE_EA, FALSE, TRUE, L"Write EA" },
{ L"Delete subfolders and files", FILE_DELETE_CHILD, FALSE, TRUE, L"Delete child" }
};
ACCESS_ENTRIES(FilterConnectionPort)
{
{ L"Full control", FLT_PORT_ALL_ACCESS, TRUE, TRUE },
{ L"Connect", FLT_PORT_CONNECT, TRUE, TRUE }
};
ACCESS_ENTRIES(IoCompletion)
{
{ L"Full control", IO_COMPLETION_ALL_ACCESS, TRUE, TRUE },
{ L"Query", IO_COMPLETION_QUERY_STATE, TRUE, TRUE },
{ L"Modify", IO_COMPLETION_MODIFY_STATE, TRUE, TRUE }
};
ACCESS_ENTRIES(Job)
{
{ L"Full control", JOB_OBJECT_ALL_ACCESS, TRUE, TRUE },
{ L"Query", JOB_OBJECT_QUERY, TRUE, TRUE },
{ L"Assign processes", JOB_OBJECT_ASSIGN_PROCESS, TRUE, TRUE },
{ L"Set attributes", JOB_OBJECT_SET_ATTRIBUTES, TRUE, TRUE },
{ L"Set security attributes", JOB_OBJECT_SET_SECURITY_ATTRIBUTES, TRUE, TRUE },
{ L"Terminate", JOB_OBJECT_TERMINATE, TRUE, TRUE }
};
ACCESS_ENTRIES(Key)
{
{ L"Full control", KEY_ALL_ACCESS, TRUE, TRUE },
{ L"Read", KEY_READ, TRUE, FALSE },
{ L"Write", KEY_WRITE, TRUE, FALSE },
{ L"Execute", KEY_EXECUTE, TRUE, FALSE },
{ L"Enumerate subkeys", KEY_ENUMERATE_SUB_KEYS, FALSE, TRUE },
{ L"Query values", KEY_QUERY_VALUE, FALSE, TRUE },
{ L"Notify", KEY_NOTIFY, FALSE, TRUE },
{ L"Set values", KEY_SET_VALUE, FALSE, TRUE },
{ L"Create subkeys", KEY_CREATE_SUB_KEY, FALSE, TRUE },
{ L"Create links", KEY_CREATE_LINK, FALSE, TRUE }
};
ACCESS_ENTRIES(KeyedEvent)
{
{ L"Full control", KEYEDEVENT_ALL_ACCESS, TRUE, TRUE },
{ L"Wait", KEYEDEVENT_WAIT, TRUE, TRUE },
{ L"Wake", KEYEDEVENT_WAKE, TRUE, TRUE }
};
ACCESS_ENTRIES(LsaAccount)
{
{ L"Full control", ACCOUNT_ALL_ACCESS, TRUE, TRUE },
{ L"Read", ACCOUNT_READ, TRUE, FALSE },
{ L"Write", ACCOUNT_WRITE, TRUE, FALSE },
{ L"Execute", ACCOUNT_EXECUTE, TRUE, FALSE },
{ L"View", ACCOUNT_VIEW, FALSE, TRUE },
{ L"Adjust privileges", ACCOUNT_ADJUST_PRIVILEGES, FALSE, TRUE },
{ L"Adjust quotas", ACCOUNT_ADJUST_QUOTAS, FALSE, TRUE },
{ L"Adjust system access", ACCOUNT_ADJUST_SYSTEM_ACCESS, FALSE, TRUE }
};
ACCESS_ENTRIES(LsaPolicy)
{
{ L"Full control", POLICY_ALL_ACCESS | POLICY_NOTIFICATION, TRUE, TRUE },
{ L"Read", POLICY_READ, TRUE, FALSE },
{ L"Write", POLICY_WRITE, TRUE, FALSE },
{ L"Execute", POLICY_EXECUTE | POLICY_NOTIFICATION, TRUE, FALSE },
{ L"View local information", POLICY_VIEW_LOCAL_INFORMATION, FALSE, TRUE },
{ L"View audit information", POLICY_VIEW_AUDIT_INFORMATION, FALSE, TRUE },
{ L"Get private information", POLICY_GET_PRIVATE_INFORMATION, FALSE, TRUE },
{ L"Administer trust", POLICY_TRUST_ADMIN, FALSE, TRUE },
{ L"Create account", POLICY_CREATE_ACCOUNT, FALSE, TRUE },
{ L"Create secret", POLICY_CREATE_SECRET, FALSE, TRUE },
{ L"Create privilege", POLICY_CREATE_PRIVILEGE, FALSE, TRUE },
{ L"Set default quota limits", POLICY_SET_DEFAULT_QUOTA_LIMITS, FALSE, TRUE },
{ L"Set audit requirements", POLICY_SET_AUDIT_REQUIREMENTS, FALSE, TRUE },
{ L"Administer audit log", POLICY_AUDIT_LOG_ADMIN, FALSE, TRUE },
{ L"Administer server", POLICY_SERVER_ADMIN, FALSE, TRUE },
{ L"Lookup names", POLICY_LOOKUP_NAMES, FALSE, TRUE },
{ L"Get notifications", POLICY_NOTIFICATION, FALSE, TRUE }
};
ACCESS_ENTRIES(LsaSecret)
{
{ L"Full control", SECRET_ALL_ACCESS, TRUE, TRUE },
{ L"Read", SECRET_READ, TRUE, FALSE },
{ L"Write", SECRET_WRITE, TRUE, FALSE },
{ L"Execute", SECRET_EXECUTE, TRUE, FALSE },
{ L"Set value", SECRET_SET_VALUE, FALSE, TRUE },
{ L"Query value", SECRET_QUERY_VALUE, FALSE, TRUE }
};
ACCESS_ENTRIES(LsaTrusted)
{
{ L"Full control", TRUSTED_ALL_ACCESS, TRUE, TRUE },
{ L"Read", TRUSTED_READ, TRUE, FALSE },
{ L"Write", TRUSTED_WRITE, TRUE, FALSE },
{ L"Execute", TRUSTED_EXECUTE, TRUE, FALSE },
{ L"Query domain name", TRUSTED_QUERY_DOMAIN_NAME, FALSE, TRUE },
{ L"Query controllers", TRUSTED_QUERY_CONTROLLERS, FALSE, TRUE },
{ L"Set controllers", TRUSTED_SET_CONTROLLERS, FALSE, TRUE },
{ L"Query POSIX", TRUSTED_QUERY_POSIX, FALSE, TRUE },
{ L"Set POSIX", TRUSTED_SET_POSIX, FALSE, TRUE },
{ L"Query authentication", TRUSTED_QUERY_AUTH, FALSE, TRUE },
{ L"Set authentication", TRUSTED_SET_AUTH, FALSE, TRUE }
};
ACCESS_ENTRIES(Mutant)
{
{ L"Full control", MUTANT_ALL_ACCESS, TRUE, TRUE },
{ L"Query", MUTANT_QUERY_STATE, TRUE, TRUE }
};
ACCESS_ENTRIES(Partition)
{
{ L"Full control", MEMORY_PARTITION_ALL_ACCESS, TRUE, TRUE },
{ L"Query", MEMORY_PARTITION_QUERY_ACCESS, TRUE, TRUE },
{ L"Modify", MEMORY_PARTITION_MODIFY_ACCESS, TRUE, TRUE }
};
ACCESS_ENTRIES(Process)
{
{ L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, TRUE, TRUE },
{ L"Query information", PROCESS_QUERY_INFORMATION, TRUE, TRUE },
{ L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE },
{ L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE },
{ L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE },
{ L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE },
{ L"Create processes", PROCESS_CREATE_PROCESS, TRUE, TRUE },
{ L"Modify memory", PROCESS_VM_OPERATION, TRUE, TRUE, L"VM operation" },
{ L"Read memory", PROCESS_VM_READ, TRUE, TRUE, L"VM read" },
{ L"Write memory", PROCESS_VM_WRITE, TRUE, TRUE, L"VM write" },
{ L"Duplicate handles", PROCESS_DUP_HANDLE, TRUE, TRUE },
{ L"Suspend / resume / set port", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" },
{ L"Terminate", PROCESS_TERMINATE, TRUE, TRUE }
};
ACCESS_ENTRIES(Process60)
{
{ L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // PROCESS_ALL_ACCESS
{ L"Query limited information", PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE },
{ L"Query information", PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE },
{ L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE },
{ L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE },
{ L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE },
{ L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE },
{ L"Create processes", PROCESS_CREATE_PROCESS, TRUE, TRUE },
{ L"Modify memory", PROCESS_VM_OPERATION, TRUE, TRUE, L"VM operation" },
{ L"Read memory", PROCESS_VM_READ, TRUE, TRUE, L"VM read" },
{ L"Write memory", PROCESS_VM_WRITE, TRUE, TRUE, L"VM write" },
{ L"Duplicate handles", PROCESS_DUP_HANDLE, TRUE, TRUE },
{ L"Suspend / resume / set port", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" },
{ L"Terminate", PROCESS_TERMINATE, TRUE, TRUE }
};
ACCESS_ENTRIES(Profile)
{
{ L"Full control", PROFILE_ALL_ACCESS, TRUE, TRUE },
{ L"Control", PROFILE_CONTROL, TRUE, TRUE }
};
ACCESS_ENTRIES(SamAlias)
{
{ L"Full control", ALIAS_ALL_ACCESS, TRUE, TRUE },
{ L"Read", ALIAS_READ, TRUE, FALSE },
{ L"Write", ALIAS_WRITE, TRUE, FALSE },
{ L"Execute", ALIAS_EXECUTE, TRUE, FALSE },
{ L"Read information", ALIAS_READ_INFORMATION, FALSE, TRUE },
{ L"Write account", ALIAS_WRITE_ACCOUNT, FALSE, TRUE },
{ L"Add member", ALIAS_ADD_MEMBER, FALSE, TRUE },
{ L"Remove member", ALIAS_REMOVE_MEMBER, FALSE, TRUE },
{ L"List members", ALIAS_LIST_MEMBERS, FALSE, TRUE }
};
ACCESS_ENTRIES(SamDomain)
{
{ L"Full control", DOMAIN_ALL_ACCESS, TRUE, TRUE },
{ L"Read", DOMAIN_READ, TRUE, FALSE },
{ L"Write", DOMAIN_WRITE, TRUE, FALSE },
{ L"Execute", DOMAIN_EXECUTE, TRUE, FALSE },
{ L"Read password parameters", DOMAIN_READ_PASSWORD_PARAMETERS, FALSE, TRUE },
{ L"Write password parameters", DOMAIN_WRITE_PASSWORD_PARAMS, FALSE, TRUE },
{ L"Read other parameters", DOMAIN_READ_OTHER_PARAMETERS, FALSE, TRUE },
{ L"Write other parameters", DOMAIN_WRITE_OTHER_PARAMETERS, FALSE, TRUE },
{ L"Create user", DOMAIN_CREATE_USER, FALSE, TRUE },
{ L"Create group", DOMAIN_CREATE_GROUP, FALSE, TRUE },
{ L"Create alias", DOMAIN_CREATE_ALIAS, FALSE, TRUE },
{ L"Get alias membership", DOMAIN_GET_ALIAS_MEMBERSHIP, FALSE, TRUE },
{ L"List accounts", DOMAIN_LIST_ACCOUNTS, FALSE, TRUE },
{ L"Lookup", DOMAIN_LOOKUP, FALSE, TRUE },
{ L"Administer server", DOMAIN_ADMINISTER_SERVER, FALSE, TRUE }
};
ACCESS_ENTRIES(SamGroup)
{
{ L"Full control", GROUP_ALL_ACCESS, TRUE, TRUE },
{ L"Read", GROUP_READ, TRUE, FALSE },
{ L"Write", GROUP_WRITE, TRUE, FALSE },
{ L"Execute", GROUP_EXECUTE, TRUE, FALSE },
{ L"Read information", GROUP_READ_INFORMATION, FALSE, TRUE },
{ L"Write account", GROUP_WRITE_ACCOUNT, FALSE, TRUE },
{ L"Add member", GROUP_ADD_MEMBER, FALSE, TRUE },
{ L"Remove member", GROUP_REMOVE_MEMBER, FALSE, TRUE },
{ L"List members", GROUP_LIST_MEMBERS, FALSE, TRUE }
};
ACCESS_ENTRIES(SamServer)
{
{ L"Full control", SAM_SERVER_ALL_ACCESS, TRUE, TRUE },
{ L"Read", SAM_SERVER_READ, TRUE, FALSE },
{ L"Write", SAM_SERVER_WRITE, TRUE, FALSE },
{ L"Execute", SAM_SERVER_EXECUTE, TRUE, FALSE },
{ L"Connect", SAM_SERVER_CONNECT, FALSE, TRUE },
{ L"Shutdown", SAM_SERVER_SHUTDOWN, FALSE, TRUE },
{ L"Initialize", SAM_SERVER_INITIALIZE, FALSE, TRUE },
{ L"Create domain", SAM_SERVER_CREATE_DOMAIN, FALSE, TRUE },
{ L"Enumerate domains", SAM_SERVER_ENUMERATE_DOMAINS, FALSE, TRUE },
{ L"Lookup domain", SAM_SERVER_LOOKUP_DOMAIN, FALSE, TRUE }
};
ACCESS_ENTRIES(SamUser)
{
{ L"Full control", USER_ALL_ACCESS, TRUE, TRUE },
{ L"Read", USER_READ, TRUE, FALSE },
{ L"Write", USER_WRITE, TRUE, FALSE },
{ L"Execute", USER_EXECUTE, TRUE, FALSE },
{ L"Read general", USER_READ_GENERAL, FALSE, TRUE },
{ L"Read preferences", USER_READ_PREFERENCES, FALSE, TRUE },
{ L"Write preferences", USER_WRITE_PREFERENCES, FALSE, TRUE },
{ L"Read logon", USER_READ_LOGON, FALSE, TRUE },
{ L"Read account", USER_READ_ACCOUNT, FALSE, TRUE },
{ L"Write account", USER_WRITE_ACCOUNT, FALSE, TRUE },
{ L"Change password", USER_CHANGE_PASSWORD, FALSE, TRUE },
{ L"Force password change", USER_FORCE_PASSWORD_CHANGE, FALSE, TRUE },
{ L"List groups", USER_LIST_GROUPS, FALSE, TRUE },
{ L"Read group information", USER_READ_GROUP_INFORMATION, FALSE, TRUE },
{ L"Write group information", USER_WRITE_GROUP_INFORMATION, FALSE, TRUE }
};
ACCESS_ENTRIES(Section)
{
{ L"Full control", SECTION_ALL_ACCESS, TRUE, TRUE },
{ L"Query", SECTION_QUERY, TRUE, TRUE },
{ L"Map for read", SECTION_MAP_READ, TRUE, TRUE, L"Map read" },
{ L"Map for write", SECTION_MAP_WRITE, TRUE, TRUE, L"Map write" },
{ L"Map for execute", SECTION_MAP_EXECUTE, TRUE, TRUE, L"Map execute" },
{ L"Map for execute (explicit)", SECTION_MAP_EXECUTE_EXPLICIT, TRUE, TRUE, L"Map execute explicit" },
{ L"Extend size", SECTION_EXTEND_SIZE, TRUE, TRUE }
};
ACCESS_ENTRIES(Semaphore)
{
{ L"Full control", SEMAPHORE_ALL_ACCESS, TRUE, TRUE },
{ L"Query", SEMAPHORE_QUERY_STATE, TRUE, TRUE },
{ L"Modify", SEMAPHORE_MODIFY_STATE, TRUE, TRUE }
};
ACCESS_ENTRIES(Service)
{
{ L"Full control", SERVICE_ALL_ACCESS, TRUE, TRUE },
{ L"Query status", SERVICE_QUERY_STATUS, TRUE, TRUE },
{ L"Query configuration", SERVICE_QUERY_CONFIG, TRUE, TRUE },
{ L"Modify configuration", SERVICE_CHANGE_CONFIG, TRUE, TRUE },
{ L"Enumerate dependents", SERVICE_ENUMERATE_DEPENDENTS, TRUE, TRUE },
{ L"Start", SERVICE_START, TRUE, TRUE },
{ L"Stop", SERVICE_STOP, TRUE, TRUE },
{ L"Pause / continue", SERVICE_PAUSE_CONTINUE, TRUE, TRUE, L"Pause/continue" },
{ L"Interrogate", SERVICE_INTERROGATE, TRUE, TRUE },
{ L"User-defined control", SERVICE_USER_DEFINED_CONTROL, TRUE, TRUE }
};
ACCESS_ENTRIES(Session)
{
{ L"Full control", SESSION_ALL_ACCESS, TRUE, TRUE },
{ L"Query", SESSION_QUERY_ACCESS, TRUE, TRUE },
{ L"Modify", SESSION_MODIFY_ACCESS, TRUE, TRUE }
};
ACCESS_ENTRIES(SymbolicLink)
{
{ L"Full control", SYMBOLIC_LINK_ALL_ACCESS, TRUE, TRUE },
{ L"Query", SYMBOLIC_LINK_QUERY, TRUE, TRUE }
};
ACCESS_ENTRIES(Thread)
{
{ L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff, TRUE, TRUE },
{ L"Query information", THREAD_QUERY_INFORMATION, TRUE, TRUE },
{ L"Set information", THREAD_SET_INFORMATION, TRUE, TRUE },
{ L"Get context", THREAD_GET_CONTEXT, TRUE, TRUE },
{ L"Set context", THREAD_SET_CONTEXT, TRUE, TRUE },
{ L"Set token", THREAD_SET_THREAD_TOKEN, TRUE, TRUE },
{ L"Alert", THREAD_ALERT, TRUE, TRUE },
{ L"Impersonate", THREAD_IMPERSONATE, TRUE, TRUE },
{ L"Direct impersonate", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE },
{ L"Suspend / resume", THREAD_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" },
{ L"Terminate", THREAD_TERMINATE, TRUE, TRUE },
};
ACCESS_ENTRIES(Thread60)
{
{ L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // THREAD_ALL_ACCESS
{ L"Query limited information", THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE },
{ L"Query information", THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE },
{ L"Set limited information", THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE },
{ L"Set information", THREAD_SET_INFORMATION | THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE },
{ L"Get context", THREAD_GET_CONTEXT, TRUE, TRUE },
{ L"Set context", THREAD_SET_CONTEXT, TRUE, TRUE },
{ L"Set token", THREAD_SET_THREAD_TOKEN, TRUE, TRUE },
{ L"Alert", THREAD_ALERT, TRUE, TRUE },
{ L"Impersonate", THREAD_IMPERSONATE, TRUE, TRUE },
{ L"Direct impersonate", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE },
{ L"Suspend / resume", THREAD_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" },
{ L"Terminate", THREAD_TERMINATE, TRUE, TRUE },
};
ACCESS_ENTRIES(Timer)
{
{ L"Full control", TIMER_ALL_ACCESS, TRUE, TRUE },
{ L"Query", TIMER_QUERY_STATE, TRUE, TRUE },
{ L"Modify", TIMER_MODIFY_STATE, TRUE, TRUE }
};
ACCESS_ENTRIES(TmEn)
{
{ L"Full control", ENLISTMENT_ALL_ACCESS, TRUE, TRUE },
{ L"Read", ENLISTMENT_GENERIC_READ, TRUE, FALSE },
{ L"Write", ENLISTMENT_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", ENLISTMENT_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Query information", ENLISTMENT_QUERY_INFORMATION, FALSE, TRUE },
{ L"Set information", ENLISTMENT_SET_INFORMATION, FALSE, TRUE },
{ L"Recover", ENLISTMENT_RECOVER, FALSE, TRUE },
{ L"Subordinate rights", ENLISTMENT_SUBORDINATE_RIGHTS, FALSE, TRUE },
{ L"Superior rights", ENLISTMENT_SUPERIOR_RIGHTS, FALSE, TRUE }
};
ACCESS_ENTRIES(TmRm)
{
{ L"Full control", RESOURCEMANAGER_ALL_ACCESS, TRUE, TRUE },
{ L"Read", RESOURCEMANAGER_GENERIC_READ, TRUE, FALSE },
{ L"Write", RESOURCEMANAGER_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", RESOURCEMANAGER_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Query information", RESOURCEMANAGER_QUERY_INFORMATION, FALSE, TRUE },
{ L"Set information", RESOURCEMANAGER_SET_INFORMATION, FALSE, TRUE },
{ L"Get notifications", RESOURCEMANAGER_GET_NOTIFICATION, FALSE, TRUE },
{ L"Enlist", RESOURCEMANAGER_ENLIST, FALSE, TRUE },
{ L"Recover", RESOURCEMANAGER_RECOVER, FALSE, TRUE },
{ L"Register protocols", RESOURCEMANAGER_REGISTER_PROTOCOL, FALSE, TRUE },
{ L"Complete propagation", RESOURCEMANAGER_COMPLETE_PROPAGATION, FALSE, TRUE }
};
ACCESS_ENTRIES(TmTm)
{
{ L"Full control", TRANSACTIONMANAGER_ALL_ACCESS, TRUE, TRUE },
{ L"Read", TRANSACTIONMANAGER_GENERIC_READ, TRUE, FALSE },
{ L"Write", TRANSACTIONMANAGER_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", TRANSACTIONMANAGER_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Query information", TRANSACTIONMANAGER_QUERY_INFORMATION, FALSE, TRUE },
{ L"Set information", TRANSACTIONMANAGER_SET_INFORMATION, FALSE, TRUE },
{ L"Recover", TRANSACTIONMANAGER_RECOVER, FALSE, TRUE },
{ L"Rename", TRANSACTIONMANAGER_RENAME, FALSE, TRUE },
{ L"Create resource manager", TRANSACTIONMANAGER_CREATE_RM, FALSE, TRUE },
{ L"Bind transactions", TRANSACTIONMANAGER_BIND_TRANSACTION, FALSE, TRUE }
};
ACCESS_ENTRIES(TmTx)
{
{ L"Full control", TRANSACTION_ALL_ACCESS, TRUE, TRUE },
{ L"Read", TRANSACTION_GENERIC_READ, TRUE, FALSE },
{ L"Write", TRANSACTION_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", TRANSACTION_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Query information", TRANSACTION_QUERY_INFORMATION, FALSE, TRUE },
{ L"Set information", TRANSACTION_SET_INFORMATION, FALSE, TRUE },
{ L"Enlist", TRANSACTION_ENLIST, FALSE, TRUE },
{ L"Commit", TRANSACTION_COMMIT, FALSE, TRUE },
{ L"Rollback", TRANSACTION_ROLLBACK, FALSE, TRUE },
{ L"Propagate", TRANSACTION_PROPAGATE, FALSE, TRUE }
};
ACCESS_ENTRIES(Token)
{
{ L"Full control", TOKEN_ALL_ACCESS, TRUE, TRUE },
{ L"Read", TOKEN_READ, TRUE, FALSE },
{ L"Write", TOKEN_WRITE, TRUE, FALSE },
{ L"Execute", TOKEN_EXECUTE, TRUE, FALSE },
{ L"Adjust privileges", TOKEN_ADJUST_PRIVILEGES, FALSE, TRUE },
{ L"Adjust groups", TOKEN_ADJUST_GROUPS, FALSE, TRUE },
{ L"Adjust defaults", TOKEN_ADJUST_DEFAULT, FALSE, TRUE },
{ L"Adjust session ID", TOKEN_ADJUST_SESSIONID, FALSE, TRUE },
{ L"Assign as primary token", TOKEN_ASSIGN_PRIMARY, FALSE, TRUE, L"Assign primary" },
{ L"Duplicate", TOKEN_DUPLICATE, FALSE, TRUE },
{ L"Impersonate", TOKEN_IMPERSONATE, FALSE, TRUE },
{ L"Query", TOKEN_QUERY, FALSE, TRUE },
{ L"Query source", TOKEN_QUERY_SOURCE, FALSE, TRUE }
};
ACCESS_ENTRIES(TpWorkerFactory)
{
{ L"Full control", WORKER_FACTORY_ALL_ACCESS, TRUE, TRUE },
{ L"Release worker", WORKER_FACTORY_RELEASE_WORKER, FALSE, TRUE },
{ L"Ready worker", WORKER_FACTORY_READY_WORKER, FALSE, TRUE },
{ L"Wait", WORKER_FACTORY_WAIT, FALSE, TRUE },
{ L"Set information", WORKER_FACTORY_SET_INFORMATION, FALSE, TRUE },
{ L"Query information", WORKER_FACTORY_QUERY_INFORMATION, FALSE, TRUE },
{ L"Shutdown", WORKER_FACTORY_SHUTDOWN, FALSE, TRUE }
};
ACCESS_ENTRIES(Type)
{
{ L"Full control", OBJECT_TYPE_ALL_ACCESS, TRUE, TRUE },
{ L"Create", OBJECT_TYPE_CREATE, TRUE, TRUE }
};
ACCESS_ENTRIES(WindowStation)
{
{ L"Full control", WINSTA_ALL_ACCESS | STANDARD_RIGHTS_REQUIRED, TRUE, TRUE },
{ L"Read", WINSTA_GENERIC_READ, TRUE, FALSE },
{ L"Write", WINSTA_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", WINSTA_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Enumerate", WINSTA_ENUMERATE, FALSE, TRUE },
{ L"Enumerate desktops", WINSTA_ENUMDESKTOPS, FALSE, TRUE },
{ L"Read attributes", WINSTA_READATTRIBUTES, FALSE, TRUE },
{ L"Read screen", WINSTA_READSCREEN, FALSE, TRUE },
{ L"Access clipboard", WINSTA_ACCESSCLIPBOARD, FALSE, TRUE },
{ L"Access global atoms", WINSTA_ACCESSGLOBALATOMS, FALSE, TRUE },
{ L"Create desktop", WINSTA_CREATEDESKTOP, FALSE, TRUE },
{ L"Write attributes", WINSTA_WRITEATTRIBUTES, FALSE, TRUE },
{ L"Exit windows", WINSTA_EXITWINDOWS, FALSE, TRUE }
};
ACCESS_ENTRIES(WmiGuid)
{
{ L"Full control", WMIGUID_ALL_ACCESS, TRUE, TRUE },
{ L"Read", WMIGUID_GENERIC_READ, TRUE, FALSE },
{ L"Write", WMIGUID_GENERIC_WRITE, TRUE, FALSE },
{ L"Execute", WMIGUID_GENERIC_EXECUTE, TRUE, FALSE },
{ L"Query information", WMIGUID_QUERY, FALSE, TRUE },
{ L"Set information", WMIGUID_SET, FALSE, TRUE },
{ L"Get notifications", WMIGUID_NOTIFICATION, FALSE, TRUE },
{ L"Read description", WMIGUID_READ_DESCRIPTION, FALSE, TRUE },
{ L"Execute", WMIGUID_EXECUTE, FALSE, TRUE },
{ L"Create real-time logs", TRACELOG_CREATE_REALTIME, FALSE, TRUE, L"Create real-time" },
{ L"Create on disk logs", TRACELOG_CREATE_ONDISK, FALSE, TRUE, L"Create on disk" },
{ L"Enable provider GUIDs", TRACELOG_GUID_ENABLE, FALSE, TRUE, L"Enable GUIDs" },
{ L"Access kernel logger", TRACELOG_ACCESS_KERNEL_LOGGER, FALSE, TRUE },
{ L"Log events", TRACELOG_LOG_EVENT, FALSE, TRUE },
{ L"Access real-time events", TRACELOG_ACCESS_REALTIME, FALSE, TRUE, L"Access real-time" },
{ L"Register provider GUIDs", TRACELOG_REGISTER_GUIDS, FALSE, TRUE, L"Register GUIDs" }
};
static PH_SPECIFIC_TYPE PhSpecificTypes[] =
{
ACCESS_ENTRY(AlpcPort, TRUE),
ACCESS_ENTRY(DebugObject, TRUE),
ACCESS_ENTRY(Desktop, FALSE),
ACCESS_ENTRY(Directory, FALSE),
ACCESS_ENTRY(Event, TRUE),
ACCESS_ENTRY(EventPair, TRUE),
ACCESS_ENTRY(File, TRUE),
ACCESS_ENTRY(FilterConnectionPort, FALSE),
ACCESS_ENTRY(IoCompletion, TRUE),
ACCESS_ENTRY(Job, TRUE),
ACCESS_ENTRY(Key, FALSE),
ACCESS_ENTRY(KeyedEvent, FALSE),
ACCESS_ENTRY(LsaAccount, FALSE),
ACCESS_ENTRY(LsaPolicy, FALSE),
ACCESS_ENTRY(LsaSecret, FALSE),
ACCESS_ENTRY(LsaTrusted, FALSE),
ACCESS_ENTRY(Mutant, TRUE),
ACCESS_ENTRY(Partition, TRUE),
ACCESS_ENTRY(Process, TRUE),
ACCESS_ENTRY(Process60, TRUE),
ACCESS_ENTRY(Profile, FALSE),
ACCESS_ENTRY(SamAlias, FALSE),
ACCESS_ENTRY(SamDomain, FALSE),
ACCESS_ENTRY(SamGroup, FALSE),
ACCESS_ENTRY(SamServer, FALSE),
ACCESS_ENTRY(SamUser, FALSE),
ACCESS_ENTRY(Section, FALSE),
ACCESS_ENTRY(Semaphore, TRUE),
ACCESS_ENTRY(Service, FALSE),
ACCESS_ENTRY(Session, FALSE),
ACCESS_ENTRY(SymbolicLink, FALSE),
ACCESS_ENTRY(Thread, TRUE),
ACCESS_ENTRY(Thread60, TRUE),
ACCESS_ENTRY(Timer, TRUE),
ACCESS_ENTRY(TmEn, FALSE),
ACCESS_ENTRY(TmRm, FALSE),
ACCESS_ENTRY(TmTm, FALSE),
ACCESS_ENTRY(TmTx, FALSE),
ACCESS_ENTRY(Token, FALSE),
ACCESS_ENTRY(TpWorkerFactory, FALSE),
ACCESS_ENTRY(Type, FALSE),
ACCESS_ENTRY(WindowStation, FALSE),
ACCESS_ENTRY(WmiGuid, TRUE)
};
/**
* Gets access entries for an object type.
*
* \param Type The name of the object type.
* \param AccessEntries A variable which receives an array of access entry structures. You must free
* the buffer with PhFree() when you no longer need it.
* \param NumberOfAccessEntries A variable which receives the number of access entry structures
* returned in
* \a AccessEntries.
*/
BOOLEAN PhGetAccessEntries(
_In_ PWSTR Type,
_Out_ PPH_ACCESS_ENTRY *AccessEntries,
_Out_ PULONG NumberOfAccessEntries
)
{
ULONG i;
PPH_SPECIFIC_TYPE specificType = NULL;
PPH_ACCESS_ENTRY accessEntries;
if (PhEqualStringZ(Type, L"ALPC Port", TRUE))
{
Type = L"AlpcPort";
}
else if (PhEqualStringZ(Type, L"Port", TRUE))
{
Type = L"AlpcPort";
}
else if (PhEqualStringZ(Type, L"WaitablePort", TRUE))
{
Type = L"AlpcPort";
}
else if (PhEqualStringZ(Type, L"Process", TRUE))
{
if (WindowsVersion >= WINDOWS_VISTA)
Type = L"Process60";
}
else if (PhEqualStringZ(Type, L"Thread", TRUE))
{
if (WindowsVersion >= WINDOWS_VISTA)
Type = L"Thread60";
}
// Find the specific type.
for (i = 0; i < sizeof(PhSpecificTypes) / sizeof(PH_SPECIFIC_TYPE); i++)
{
if (PhEqualStringZ(PhSpecificTypes[i].Type, Type, TRUE))
{
specificType = &PhSpecificTypes[i];
break;
}
}
if (specificType)
{
ULONG sizeOfEntries;
// Copy the specific access entries and append the standard access entries.
if (specificType->HasSynchronize)
sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries);
else
sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY);
accessEntries = PhAllocate(sizeOfEntries);
memcpy(accessEntries, specificType->AccessEntries, specificType->SizeOfAccessEntries);
if (specificType->HasSynchronize)
{
memcpy(
PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries),
PhStandardAccessEntries,
sizeof(PhStandardAccessEntries)
);
}
else
{
memcpy(
PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries),
&PhStandardAccessEntries[1],
sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY)
);
}
*AccessEntries = accessEntries;
*NumberOfAccessEntries = sizeOfEntries / sizeof(PH_ACCESS_ENTRY);
}
else
{
accessEntries = PhAllocate(sizeof(PhStandardAccessEntries));
memcpy(accessEntries, PhStandardAccessEntries, sizeof(PhStandardAccessEntries));
*AccessEntries = accessEntries;
*NumberOfAccessEntries = sizeof(PhStandardAccessEntries) / sizeof(PH_ACCESS_ENTRY);
}
return TRUE;
}
static int __cdecl PhpAccessEntryCompare(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_ACCESS_ENTRY entry1 = (PPH_ACCESS_ENTRY)elem1;
PPH_ACCESS_ENTRY entry2 = (PPH_ACCESS_ENTRY)elem2;
return intcmp(PhCountBits(entry2->Access), PhCountBits(entry1->Access));
}
/**
* Creates a string representation of an access mask.
*
* \param Access The access mask.
* \param AccessEntries An array of access entry structures. You can call PhGetAccessEntries() to
* retrieve the access entry structures for a standard object type.
* \param NumberOfAccessEntries The number of elements in \a AccessEntries.
*
* \return The string representation of \a Access.
*/
PPH_STRING PhGetAccessString(
_In_ ACCESS_MASK Access,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
)
{
PH_STRING_BUILDER stringBuilder;
PPH_ACCESS_ENTRY accessEntries;
PBOOLEAN matched;
ULONG i;
ULONG j;
PhInitializeStringBuilder(&stringBuilder, 32);
// Sort the access entries according to how many access rights they include.
accessEntries = PhAllocateCopy(AccessEntries, NumberOfAccessEntries * sizeof(PH_ACCESS_ENTRY));
qsort(accessEntries, NumberOfAccessEntries, sizeof(PH_ACCESS_ENTRY), PhpAccessEntryCompare);
matched = PhAllocate(NumberOfAccessEntries * sizeof(BOOLEAN));
memset(matched, 0, NumberOfAccessEntries * sizeof(BOOLEAN));
for (i = 0; i < NumberOfAccessEntries; i++)
{
// We make sure we haven't matched this access entry yet. This ensures that we won't get
// duplicates, e.g. FILE_GENERIC_READ includes FILE_READ_DATA, and we don't want to display
// both to the user.
if (
!matched[i] &&
((Access & accessEntries[i].Access) == accessEntries[i].Access)
)
{
if (accessEntries[i].ShortName)
PhAppendStringBuilder2(&stringBuilder, accessEntries[i].ShortName);
else
PhAppendStringBuilder2(&stringBuilder, accessEntries[i].Name);
PhAppendStringBuilder2(&stringBuilder, L", ");
// Disable equal or more specific entries.
for (j = i; j < NumberOfAccessEntries; j++)
{
if ((accessEntries[i].Access | accessEntries[j].Access) == accessEntries[i].Access)
matched[j] = TRUE;
}
}
}
// Remove the trailing ", ".
if (PhEndsWithString2(stringBuilder.String, L", ", FALSE))
PhRemoveEndStringBuilder(&stringBuilder, 2);
PhFree(matched);
PhFree(accessEntries);
return PhFinalStringBuilderString(&stringBuilder);
}

593
phlib/secedit.c Normal file
View File

@@ -0,0 +1,593 @@
/*
* Process Hacker -
* object security editor
*
* Copyright (C) 2010 wj32
*
* 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 <ph.h>
#include <guisup.h>
#include <secedit.h>
#include <seceditp.h>
#include <hndlinfo.h>
static ISecurityInformationVtbl PhSecurityInformation_VTable =
{
PhSecurityInformation_QueryInterface,
PhSecurityInformation_AddRef,
PhSecurityInformation_Release,
PhSecurityInformation_GetObjectInformation,
PhSecurityInformation_GetSecurity,
PhSecurityInformation_SetSecurity,
PhSecurityInformation_GetAccessRights,
PhSecurityInformation_MapGeneric,
PhSecurityInformation_GetInheritTypes,
PhSecurityInformation_PropertySheetPageCallback
};
static PH_INITONCE SecurityEditorInitOnce = PH_INITONCE_INIT;
static _CreateSecurityPage CreateSecurityPage_I;
static _EditSecurity EditSecurity_I;
FORCEINLINE VOID PhpSecurityEditorInitialization(
VOID
)
{
if (PhBeginInitOnce(&SecurityEditorInitOnce))
{
HMODULE aclui;
aclui = LoadLibrary(L"aclui.dll");
CreateSecurityPage_I = (PVOID)GetProcAddress(aclui, "CreateSecurityPage");
EditSecurity_I = (PVOID)GetProcAddress(aclui, "EditSecurity");
PhEndInitOnce(&SecurityEditorInitOnce);
}
}
/**
* Creates a security editor page.
*
* \param ObjectName The name of the object.
* \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the
* object.
* \param SetObjectSecurity A callback function executed to modify the security descriptor of the
* object.
* \param Context A user-defined value to pass to the callback functions.
* \param AccessEntries An array of access mask descriptors.
* \param NumberOfAccessEntries The number of elements in \a AccessEntries.
*/
HPROPSHEETPAGE PhCreateSecurityPage(
_In_ PWSTR ObjectName,
_In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,
_In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,
_In_opt_ PVOID Context,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
)
{
ISecurityInformation *info;
HPROPSHEETPAGE page;
PhpSecurityEditorInitialization();
if (!CreateSecurityPage_I)
return NULL;
info = PhSecurityInformation_Create(
ObjectName,
GetObjectSecurity,
SetObjectSecurity,
Context,
AccessEntries,
NumberOfAccessEntries
);
page = CreateSecurityPage_I(info);
PhSecurityInformation_Release(info);
return page;
}
/**
* Displays a security editor dialog.
*
* \param hWnd The parent window of the dialog.
* \param ObjectName The name of the object.
* \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the
* object.
* \param SetObjectSecurity A callback function executed to modify the security descriptor of the
* object.
* \param Context A user-defined value to pass to the callback functions.
* \param AccessEntries An array of access mask descriptors.
* \param NumberOfAccessEntries The number of elements in \a AccessEntries.
*/
VOID PhEditSecurity(
_In_ HWND hWnd,
_In_ PWSTR ObjectName,
_In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,
_In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,
_In_opt_ PVOID Context,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
)
{
ISecurityInformation *info;
PhpSecurityEditorInitialization();
if (!EditSecurity_I)
return;
info = PhSecurityInformation_Create(
ObjectName,
GetObjectSecurity,
SetObjectSecurity,
Context,
AccessEntries,
NumberOfAccessEntries
);
EditSecurity_I(hWnd, info);
PhSecurityInformation_Release(info);
}
ISecurityInformation *PhSecurityInformation_Create(
_In_ PWSTR ObjectName,
_In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity,
_In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity,
_In_opt_ PVOID Context,
_In_ PPH_ACCESS_ENTRY AccessEntries,
_In_ ULONG NumberOfAccessEntries
)
{
PhSecurityInformation *info;
ULONG i;
info = PhAllocate(sizeof(PhSecurityInformation));
info->VTable = &PhSecurityInformation_VTable;
info->RefCount = 1;
info->ObjectName = PhCreateString(ObjectName);
info->GetObjectSecurity = GetObjectSecurity;
info->SetObjectSecurity = SetObjectSecurity;
info->Context = Context;
info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * NumberOfAccessEntries);
info->NumberOfAccessEntries = NumberOfAccessEntries;
for (i = 0; i < NumberOfAccessEntries; i++)
{
memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS));
info->AccessEntries[i].pszName = AccessEntries[i].Name;
info->AccessEntries[i].mask = AccessEntries[i].Access;
if (AccessEntries[i].General)
info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL;
if (AccessEntries[i].Specific)
info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC;
}
return (ISecurityInformation *)info;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface(
_In_ ISecurityInformation *This,
_In_ REFIID Riid,
_Out_ PVOID *Object
)
{
if (
IsEqualIID(Riid, &IID_IUnknown) ||
IsEqualIID(Riid, &IID_ISecurityInformation)
)
{
PhSecurityInformation_AddRef(This);
*Object = This;
return S_OK;
}
*Object = NULL;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef(
_In_ ISecurityInformation *This
)
{
PhSecurityInformation *this = (PhSecurityInformation *)This;
this->RefCount++;
return this->RefCount;
}
ULONG STDMETHODCALLTYPE PhSecurityInformation_Release(
_In_ ISecurityInformation *This
)
{
PhSecurityInformation *this = (PhSecurityInformation *)This;
this->RefCount--;
if (this->RefCount == 0)
{
if (this->ObjectName) PhDereferenceObject(this->ObjectName);
PhFree(this->AccessEntries);
PhFree(this);
return 0;
}
return this->RefCount;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation(
_In_ ISecurityInformation *This,
_Out_ PSI_OBJECT_INFO ObjectInfo
)
{
PhSecurityInformation *this = (PhSecurityInformation *)This;
memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO));
ObjectInfo->dwFlags =
SI_EDIT_AUDITS |
SI_EDIT_OWNER |
SI_EDIT_PERMS |
SI_ADVANCED |
SI_NO_ACL_PROTECT |
SI_NO_TREE_APPLY;
ObjectInfo->hInstance = NULL;
ObjectInfo->pszObjectName = this->ObjectName->Buffer;
return S_OK;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity(
_In_ ISecurityInformation *This,
_In_ SECURITY_INFORMATION RequestedInformation,
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,
_In_ BOOL Default
)
{
PhSecurityInformation *this = (PhSecurityInformation *)This;
NTSTATUS status;
PSECURITY_DESCRIPTOR securityDescriptor;
ULONG sdLength;
PSECURITY_DESCRIPTOR newSd;
status = this->GetObjectSecurity(
&securityDescriptor,
RequestedInformation,
this->Context
);
if (!NT_SUCCESS(status))
return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));
sdLength = RtlLengthSecurityDescriptor(securityDescriptor);
newSd = LocalAlloc(0, sdLength);
memcpy(newSd, securityDescriptor, sdLength);
PhFree(securityDescriptor);
*SecurityDescriptor = newSd;
return S_OK;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity(
_In_ ISecurityInformation *This,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
)
{
PhSecurityInformation *this = (PhSecurityInformation *)This;
NTSTATUS status;
status = this->SetObjectSecurity(
SecurityDescriptor,
SecurityInformation,
this->Context
);
if (!NT_SUCCESS(status))
return HRESULT_FROM_WIN32(PhNtStatusToDosError(status));
return S_OK;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights(
_In_ ISecurityInformation *This,
_In_ const GUID *ObjectType,
_In_ ULONG Flags,
_Out_ PSI_ACCESS *Access,
_Out_ PULONG Accesses,
_Out_ PULONG DefaultAccess
)
{
PhSecurityInformation *this = (PhSecurityInformation *)This;
*Access = this->AccessEntries;
*Accesses = this->NumberOfAccessEntries;
*DefaultAccess = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric(
_In_ ISecurityInformation *This,
_In_ const GUID *ObjectType,
_In_ PUCHAR AceFlags,
_Inout_ PACCESS_MASK Mask
)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes(
_In_ ISecurityInformation *This,
_Out_ PSI_INHERIT_TYPE *InheritTypes,
_Out_ PULONG InheritTypesCount
)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback(
_In_ ISecurityInformation *This,
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ SI_PAGE_TYPE uPage
)
{
return E_NOTIMPL;
}
NTSTATUS PhpGetObjectSecurityWithTimeout(
_In_ HANDLE Handle,
_In_ SECURITY_INFORMATION SecurityInformation,
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor
)
{
NTSTATUS status;
ULONG bufferSize;
PVOID buffer;
bufferSize = 0x100;
buffer = PhAllocate(bufferSize);
// This is required (especially for File objects) because some drivers don't seem to handle
// QuerySecurity properly.
memset(buffer, 0, bufferSize);
status = PhCallNtQuerySecurityObjectWithTimeout(
Handle,
SecurityInformation,
buffer,
bufferSize,
&bufferSize
);
if (status == STATUS_BUFFER_TOO_SMALL)
{
PhFree(buffer);
buffer = PhAllocate(bufferSize);
memset(buffer, 0, bufferSize);
status = PhCallNtQuerySecurityObjectWithTimeout(
Handle,
SecurityInformation,
buffer,
bufferSize,
&bufferSize
);
}
if (!NT_SUCCESS(status))
{
PhFree(buffer);
return status;
}
*SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer;
return status;
}
/**
* Retrieves the security descriptor of an object.
*
* \param SecurityDescriptor A variable which receives a pointer to the security descriptor of the
* object. The security descriptor must be freed using PhFree() when no longer needed.
* \param SecurityInformation The security information to retrieve.
* \param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object.
*
* \remarks This function may be used for the \a GetObjectSecurity callback in
* PhCreateSecurityPage() or PhEditSecurity().
*/
_Callback_ NTSTATUS PhStdGetObjectSecurity(
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_opt_ PVOID Context
)
{
NTSTATUS status;
PPH_STD_OBJECT_SECURITY stdObjectSecurity;
HANDLE handle;
stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context;
status = stdObjectSecurity->OpenObject(
&handle,
PhGetAccessForGetSecurity(SecurityInformation),
stdObjectSecurity->Context
);
if (!NT_SUCCESS(status))
return status;
if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE))
{
status = PhGetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor);
CloseServiceHandle(handle);
}
else if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"File", TRUE))
{
status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor);
NtClose(handle);
}
else
{
status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);
NtClose(handle);
}
return status;
}
/**
* Modifies the security descriptor of an object.
*
* \param SecurityDescriptor A security descriptor containing security information to set.
* \param SecurityInformation The security information to retrieve.
* \param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object.
*
* \remarks This function may be used for the \a SetObjectSecurity callback in
* PhCreateSecurityPage() or PhEditSecurity().
*/
_Callback_ NTSTATUS PhStdSetObjectSecurity(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_opt_ PVOID Context
)
{
NTSTATUS status;
PPH_STD_OBJECT_SECURITY stdObjectSecurity;
HANDLE handle;
stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context;
status = stdObjectSecurity->OpenObject(
&handle,
PhGetAccessForSetSecurity(SecurityInformation),
stdObjectSecurity->Context
);
if (!NT_SUCCESS(status))
return status;
if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE))
{
status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor);
CloseServiceHandle(handle);
}
else
{
status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor);
NtClose(handle);
}
return status;
}
NTSTATUS PhGetSeObjectSecurity(
_In_ HANDLE Handle,
_In_ ULONG ObjectType,
_In_ SECURITY_INFORMATION SecurityInformation,
_Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor
)
{
ULONG win32Result;
PSECURITY_DESCRIPTOR securityDescriptor;
win32Result = GetSecurityInfo(
Handle,
ObjectType,
SecurityInformation,
NULL,
NULL,
NULL,
NULL,
&securityDescriptor
);
if (win32Result != ERROR_SUCCESS)
return NTSTATUS_FROM_WIN32(win32Result);
*SecurityDescriptor = PhAllocateCopy(securityDescriptor, RtlLengthSecurityDescriptor(securityDescriptor));
LocalFree(securityDescriptor);
return STATUS_SUCCESS;
}
NTSTATUS PhSetSeObjectSecurity(
_In_ HANDLE Handle,
_In_ ULONG ObjectType,
_In_ SECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
)
{
ULONG win32Result;
SECURITY_INFORMATION securityInformation = 0;
BOOLEAN present;
BOOLEAN defaulted;
PSID owner = NULL;
PSID group = NULL;
PACL dacl = NULL;
PACL sacl = NULL;
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
if (NT_SUCCESS(RtlGetOwnerSecurityDescriptor(SecurityDescriptor, &owner, &defaulted)))
securityInformation |= OWNER_SECURITY_INFORMATION;
}
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
{
if (NT_SUCCESS(RtlGetGroupSecurityDescriptor(SecurityDescriptor, &group, &defaulted)))
securityInformation |= GROUP_SECURITY_INFORMATION;
}
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
if (NT_SUCCESS(RtlGetDaclSecurityDescriptor(SecurityDescriptor, &present, &dacl, &defaulted)) && present)
securityInformation |= DACL_SECURITY_INFORMATION;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
if (NT_SUCCESS(RtlGetSaclSecurityDescriptor(SecurityDescriptor, &present, &sacl, &defaulted)) && present)
securityInformation |= SACL_SECURITY_INFORMATION;
}
win32Result = SetSecurityInfo(
Handle,
ObjectType,
SecurityInformation,
owner,
group,
dacl,
sacl
);
if (win32Result != ERROR_SUCCESS)
return NTSTATUS_FROM_WIN32(win32Result);
return STATUS_SUCCESS;
}

172
phlib/sha.c Normal file
View File

@@ -0,0 +1,172 @@
/*
* Copyright 2004 Filip Navara
* Based on public domain SHA code by Steve Reid <steve@edmweb.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* This code was modified for Process Hacker. */
#include <phbase.h>
#include "sha.h"
/* SHA1 Helper Macros */
//#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
#define rol(value, bits) (_rotl((value), (bits)))
#define DWORD2BE(x) (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000);
#define blk0(i) (Block[i] = (rol(Block[i],24)&0xFF00FF00)|(rol(Block[i],8)&0x00FF00FF))
#define blk1(i) (Block[i&15] = rol(Block[(i+13)&15]^Block[(i+8)&15]^Block[(i+2)&15]^Block[i&15],1))
#define f1(x,y,z) (z^(x&(y^z)))
#define f2(x,y,z) (x^y^z)
#define f3(x,y,z) ((x&y)|(z&(x|y)))
#define f4(x,y,z) (x^y^z)
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
static void SHATransform(ULONG State[5], UCHAR Buffer[64])
{
ULONG a, b, c, d, e;
ULONG *Block;
Block = (ULONG*)Buffer;
/* Copy Context->State[] to working variables */
a = State[0];
b = State[1];
c = State[2];
d = State[3];
e = State[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working variables back into Context->State[] */
State[0] += a;
State[1] += b;
State[2] += c;
State[3] += d;
State[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
}
VOID A_SHAInit(
_Out_ A_SHA_CTX *Context
)
{
/* SHA1 initialization constants */
Context->state[0] = 0x67452301;
Context->state[1] = 0xEFCDAB89;
Context->state[2] = 0x98BADCFE;
Context->state[3] = 0x10325476;
Context->state[4] = 0xC3D2E1F0;
Context->count[0] = 0;
Context->count[1] = 0;
}
VOID A_SHAUpdate(
_Inout_ A_SHA_CTX *Context,
_In_reads_bytes_(Length) UCHAR *Input,
_In_ ULONG Length
)
{
ULONG InputContentSize;
InputContentSize = Context->count[1] & 63;
Context->count[1] += Length;
if (Context->count[1] < Length)
Context->count[0]++;
Context->count[0] += (Length >> 29);
if (InputContentSize + Length < 64)
{
RtlCopyMemory(&Context->buffer[InputContentSize], Input,
Length);
}
else
{
while (InputContentSize + Length >= 64)
{
RtlCopyMemory(Context->buffer + InputContentSize, Input,
64 - InputContentSize);
Input += 64 - InputContentSize;
Length -= 64 - InputContentSize;
SHATransform(Context->state, Context->buffer);
InputContentSize = 0;
}
RtlCopyMemory(Context->buffer + InputContentSize, Input, Length);
}
}
VOID A_SHAFinal(
_Inout_ A_SHA_CTX *Context,
_Out_writes_bytes_(20) UCHAR *Hash
)
{
INT Pad, Index;
UCHAR Buffer[72];
ULONG *Count;
ULONG BufferContentSize, LengthHi, LengthLo;
ULONG *Result;
BufferContentSize = Context->count[1] & 63;
if (BufferContentSize >= 56)
Pad = 56 + 64 - BufferContentSize;
else
Pad = 56 - BufferContentSize;
LengthHi = (Context->count[0] << 3) | (Context->count[1] >> (32 - 3));
LengthLo = (Context->count[1] << 3);
RtlZeroMemory(Buffer + 1, Pad - 1);
Buffer[0] = 0x80;
Count = (ULONG*)(Buffer + Pad);
Count[0] = DWORD2BE(LengthHi);
Count[1] = DWORD2BE(LengthLo);
A_SHAUpdate(Context, Buffer, Pad + 8);
Result = (ULONG *)Hash;
for (Index = 0; Index < 5; Index++)
Result[Index] = DWORD2BE(Context->state[Index]);
A_SHAInit(Context);
}

28
phlib/sha.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _SHA_H
#define _SHA_H
typedef struct
{
ULONG flag;
UCHAR hash[20];
ULONG state[5];
ULONG count[2];
UCHAR buffer[64];
} A_SHA_CTX;
VOID A_SHAInit(
_Out_ A_SHA_CTX *Context
);
VOID A_SHAUpdate(
_Inout_ A_SHA_CTX *Context,
_In_reads_bytes_(Length) UCHAR *Input,
_In_ ULONG Length
);
VOID A_SHAFinal(
_Inout_ A_SHA_CTX *Context,
_Out_writes_bytes_(20) UCHAR *Hash
);
#endif

530
phlib/svcsup.c Normal file
View File

@@ -0,0 +1,530 @@
/*
* Process Hacker -
* service support functions
*
* Copyright (C) 2010-2012 wj32
*
* 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 <ph.h>
#include <svcsup.h>
#include <subprocesstag.h>
#define SIP(String, Integer) { (String), (PVOID)(Integer) }
static PH_KEY_VALUE_PAIR PhpServiceStatePairs[] =
{
SIP(L"Stopped", SERVICE_STOPPED),
SIP(L"Start pending", SERVICE_START_PENDING),
SIP(L"Stop pending", SERVICE_STOP_PENDING),
SIP(L"Running", SERVICE_RUNNING),
SIP(L"Continue pending", SERVICE_CONTINUE_PENDING),
SIP(L"Pause pending", SERVICE_PAUSE_PENDING),
SIP(L"Paused", SERVICE_PAUSED)
};
static PH_KEY_VALUE_PAIR PhpServiceTypePairs[] =
{
SIP(L"Driver", SERVICE_KERNEL_DRIVER),
SIP(L"FS driver", SERVICE_FILE_SYSTEM_DRIVER),
SIP(L"Own process", SERVICE_WIN32_OWN_PROCESS),
SIP(L"Share process", SERVICE_WIN32_SHARE_PROCESS),
SIP(L"Own interactive process", SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS),
SIP(L"Share interactive process", SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS),
SIP(L"User own process", SERVICE_USER_OWN_PROCESS),
SIP(L"User own process (instance)", SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE),
SIP(L"User share process", SERVICE_USER_SHARE_PROCESS),
SIP(L"User share process (instance)", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE),
};
static PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] =
{
SIP(L"Disabled", SERVICE_DISABLED),
SIP(L"Boot start", SERVICE_BOOT_START),
SIP(L"System start", SERVICE_SYSTEM_START),
SIP(L"Auto start", SERVICE_AUTO_START),
SIP(L"Demand start", SERVICE_DEMAND_START)
};
static PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] =
{
SIP(L"Ignore", SERVICE_ERROR_IGNORE),
SIP(L"Normal", SERVICE_ERROR_NORMAL),
SIP(L"Severe", SERVICE_ERROR_SEVERE),
SIP(L"Critical", SERVICE_ERROR_CRITICAL)
};
WCHAR *PhServiceTypeStrings[10] = { L"Driver", L"FS driver", L"Own process", L"Share process",
L"Own interactive process", L"Share interactive process", L"User own process", L"User own process (instance)",
L"User share process", L"User share process (instance)" };
WCHAR *PhServiceStartTypeStrings[5] = { L"Disabled", L"Boot start", L"System start",
L"Auto start", L"Demand start" };
WCHAR *PhServiceErrorControlStrings[4] = { L"Ignore", L"Normal", L"Severe", L"Critical" };
PVOID PhEnumServices(
_In_ SC_HANDLE ScManagerHandle,
_In_opt_ ULONG Type,
_In_opt_ ULONG State,
_Out_ PULONG Count
)
{
static ULONG initialBufferSize = 0x8000;
LOGICAL result;
PVOID buffer;
ULONG bufferSize;
ULONG returnLength;
ULONG servicesReturned;
if (!Type)
Type = WindowsVersion >= WINDOWS_10 ? SERVICE_TYPE_ALL : (SERVICE_DRIVER | SERVICE_WIN32);
if (!State)
State = SERVICE_STATE_ALL;
bufferSize = initialBufferSize;
buffer = PhAllocate(bufferSize);
if (!(result = EnumServicesStatusEx(
ScManagerHandle,
SC_ENUM_PROCESS_INFO,
Type,
State,
buffer,
bufferSize,
&returnLength,
&servicesReturned,
NULL,
NULL
)))
{
if (GetLastError() == ERROR_MORE_DATA)
{
PhFree(buffer);
bufferSize += returnLength;
buffer = PhAllocate(bufferSize);
result = EnumServicesStatusEx(
ScManagerHandle,
SC_ENUM_PROCESS_INFO,
Type,
State,
buffer,
bufferSize,
&returnLength,
&servicesReturned,
NULL,
NULL
);
}
if (!result)
{
PhFree(buffer);
return NULL;
}
}
if (bufferSize <= 0x20000) initialBufferSize = bufferSize;
*Count = servicesReturned;
return buffer;
}
SC_HANDLE PhOpenService(
_In_ PWSTR ServiceName,
_In_ ACCESS_MASK DesiredAccess
)
{
SC_HANDLE scManagerHandle;
SC_HANDLE serviceHandle;
scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!scManagerHandle)
return NULL;
serviceHandle = OpenService(scManagerHandle, ServiceName, DesiredAccess);
CloseServiceHandle(scManagerHandle);
return serviceHandle;
}
PVOID PhGetServiceConfig(
_In_ SC_HANDLE ServiceHandle
)
{
PVOID buffer;
ULONG bufferSize = 0x200;
buffer = PhAllocate(bufferSize);
if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))
{
PhFree(buffer);
buffer = PhAllocate(bufferSize);
if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))
{
PhFree(buffer);
return NULL;
}
}
return buffer;
}
PVOID PhQueryServiceVariableSize(
_In_ SC_HANDLE ServiceHandle,
_In_ ULONG InfoLevel
)
{
PVOID buffer;
ULONG bufferSize = 0x100;
buffer = PhAllocate(bufferSize);
if (!QueryServiceConfig2(
ServiceHandle,
InfoLevel,
(BYTE *)buffer,
bufferSize,
&bufferSize
))
{
PhFree(buffer);
buffer = PhAllocate(bufferSize);
if (!QueryServiceConfig2(
ServiceHandle,
InfoLevel,
(BYTE *)buffer,
bufferSize,
&bufferSize
))
{
PhFree(buffer);
return NULL;
}
}
return buffer;
}
PPH_STRING PhGetServiceDescription(
_In_ SC_HANDLE ServiceHandle
)
{
PPH_STRING description = NULL;
LPSERVICE_DESCRIPTION serviceDescription;
serviceDescription = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION);
if (serviceDescription)
{
if (serviceDescription->lpDescription)
description = PhCreateString(serviceDescription->lpDescription);
PhFree(serviceDescription);
return description;
}
else
{
return NULL;
}
}
BOOLEAN PhGetServiceDelayedAutoStart(
_In_ SC_HANDLE ServiceHandle,
_Out_ PBOOLEAN DelayedAutoStart
)
{
SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
ULONG returnLength;
if (QueryServiceConfig2(
ServiceHandle,
SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
(BYTE *)&delayedAutoStartInfo,
sizeof(SERVICE_DELAYED_AUTO_START_INFO),
&returnLength
))
{
*DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart;
return TRUE;
}
else
{
return FALSE;
}
}
BOOLEAN PhSetServiceDelayedAutoStart(
_In_ SC_HANDLE ServiceHandle,
_In_ BOOLEAN DelayedAutoStart
)
{
SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart;
return !!ChangeServiceConfig2(
ServiceHandle,
SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
&delayedAutoStartInfo
);
}
PWSTR PhGetServiceStateString(
_In_ ULONG ServiceState
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
PhpServiceStatePairs,
sizeof(PhpServiceStatePairs),
ServiceState,
&string
))
return string;
else
return L"Unknown";
}
PWSTR PhGetServiceTypeString(
_In_ ULONG ServiceType
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
PhpServiceTypePairs,
sizeof(PhpServiceTypePairs),
ServiceType,
&string
))
return string;
else
return L"Unknown";
}
ULONG PhGetServiceTypeInteger(
_In_ PWSTR ServiceType
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
PhpServiceTypePairs,
sizeof(PhpServiceTypePairs),
ServiceType,
&integer
))
return integer;
else
return -1;
}
PWSTR PhGetServiceStartTypeString(
_In_ ULONG ServiceStartType
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
PhpServiceStartTypePairs,
sizeof(PhpServiceStartTypePairs),
ServiceStartType,
&string
))
return string;
else
return L"Unknown";
}
ULONG PhGetServiceStartTypeInteger(
_In_ PWSTR ServiceStartType
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
PhpServiceStartTypePairs,
sizeof(PhpServiceStartTypePairs),
ServiceStartType,
&integer
))
return integer;
else
return -1;
}
PWSTR PhGetServiceErrorControlString(
_In_ ULONG ServiceErrorControl
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
PhpServiceErrorControlPairs,
sizeof(PhpServiceErrorControlPairs),
ServiceErrorControl,
&string
))
return string;
else
return L"Unknown";
}
ULONG PhGetServiceErrorControlInteger(
_In_ PWSTR ServiceErrorControl
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
PhpServiceErrorControlPairs,
sizeof(PhpServiceErrorControlPairs),
ServiceErrorControl,
&integer
))
return integer;
else
return -1;
}
PPH_STRING PhGetServiceNameFromTag(
_In_ HANDLE ProcessId,
_In_ PVOID ServiceTag
)
{
static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL;
PPH_STRING serviceName = NULL;
TAG_INFO_NAME_FROM_TAG nameFromTag;
if (!I_QueryTagInformation)
{
I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation");
if (!I_QueryTagInformation)
return NULL;
}
memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG));
nameFromTag.InParams.dwPid = HandleToUlong(ProcessId);
nameFromTag.InParams.dwTag = PtrToUlong(ServiceTag);
I_QueryTagInformation(NULL, eTagInfoLevelNameFromTag, &nameFromTag);
if (nameFromTag.OutParams.pszName)
{
serviceName = PhCreateString(nameFromTag.OutParams.pszName);
LocalFree(nameFromTag.OutParams.pszName);
}
return serviceName;
}
NTSTATUS PhGetThreadServiceTag(
_In_ HANDLE ThreadHandle,
_In_opt_ HANDLE ProcessHandle,
_Out_ PVOID *ServiceTag
)
{
NTSTATUS status;
THREAD_BASIC_INFORMATION basicInfo;
BOOLEAN openedProcessHandle = FALSE;
if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))
return status;
if (!ProcessHandle)
{
if (!NT_SUCCESS(status = PhOpenThreadProcess(
ThreadHandle,
PROCESS_VM_READ,
&ProcessHandle
)))
return status;
openedProcessHandle = TRUE;
}
status = NtReadVirtualMemory(
ProcessHandle,
PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)),
ServiceTag,
sizeof(PVOID),
NULL
);
if (openedProcessHandle)
NtClose(ProcessHandle);
return status;
}
NTSTATUS PhGetServiceDllParameter(
_In_ PPH_STRINGREF ServiceName,
_Out_ PPH_STRING *ServiceDll
)
{
static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\");
static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters");
NTSTATUS status;
HANDLE keyHandle;
PPH_STRING keyName;
keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, &parameters);
if (NT_SUCCESS(status = PhOpenKey(
&keyHandle,
KEY_READ,
PH_KEY_LOCAL_MACHINE,
&keyName->sr,
0
)))
{
PPH_STRING serviceDllString;
if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll"))
{
PPH_STRING expandedString;
if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr))
{
*ServiceDll = expandedString;
PhDereferenceObject(serviceDllString);
}
else
{
*ServiceDll = serviceDllString;
}
}
else
{
status = STATUS_NOT_FOUND;
}
NtClose(keyHandle);
}
PhDereferenceObject(keyName);
return status;
}

1762
phlib/symprv.c Normal file

File diff suppressed because it is too large Load Diff

496
phlib/sync.c Normal file
View File

@@ -0,0 +1,496 @@
/*
* Process Hacker -
* misc. synchronization utilities
*
* Copyright (C) 2010-2015 wj32
*
* 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/>.
*/
/*
* This file contains code for several synchronization objects.
*
* Event. This is a lightweight notification event object that does not create a kernel event object
* until needed. Additionally the kernel event object is automatically freed when no longer needed.
* Note that PhfResetEvent is NOT thread-safe.
*
* Barrier. This is a non-traditional implementation of a barrier, built on the wake event object. I
* have identified three types of participants in this process:
* 1. The slaves, who wait for the master to release them. This is the main mechanism through which
* the threads are synchronized.
* 2. The master, who is the last thread to wait on the barrier. This thread triggers the waking
* process, and waits until all slaves have woken.
* 3. The observers, who are simply threads which were slaves before, were woken, and have tried to
* wait on the barrier again before all other slaves have woken.
*
* Rundown protection. This object allows a thread to wait until all other threads have finished
* using a particular resource before freeing the resource.
*
* Init-once. This is a lightweight one-time initialization mechanism which uses the event object
* for any required blocking. The overhead is very small - only a single inlined comparison.
*/
#include <phbase.h>
/**
* Initializes an event object.
*
* \param Event A pointer to an event object.
*/
VOID FASTCALL PhfInitializeEvent(
_Out_ PPH_EVENT Event
)
{
Event->Value = PH_EVENT_REFCOUNT_INC;
Event->EventHandle = NULL;
}
/**
* Dereferences the event object used by an event.
*
* \param Event A pointer to an event object.
* \param EventHandle The current value of the event object.
*/
FORCEINLINE VOID PhpDereferenceEvent(
_Inout_ PPH_EVENT Event,
_In_opt_ HANDLE EventHandle
)
{
ULONG_PTR value;
value = _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, -PH_EVENT_REFCOUNT_INC);
// See if the reference count has become 0.
if (((value >> PH_EVENT_REFCOUNT_SHIFT) & PH_EVENT_REFCOUNT_MASK) - 1 == 0)
{
if (EventHandle)
{
NtClose(EventHandle);
Event->EventHandle = NULL;
}
}
}
/**
* References the event object used by an event.
*
* \param Event A pointer to an event object.
*/
FORCEINLINE VOID PhpReferenceEvent(
_Inout_ PPH_EVENT Event
)
{
_InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, PH_EVENT_REFCOUNT_INC);
}
/**
* Sets an event object. Any threads waiting on the event will be released.
*
* \param Event A pointer to an event object.
*/
VOID FASTCALL PhfSetEvent(
_Inout_ PPH_EVENT Event
)
{
HANDLE eventHandle;
// Only proceed if the event isn't set already.
if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&Event->Value, PH_EVENT_SET_SHIFT))
{
eventHandle = Event->EventHandle;
if (eventHandle)
{
NtSetEvent(eventHandle, NULL);
}
PhpDereferenceEvent(Event, eventHandle);
}
}
/**
* Waits for an event object to be set.
*
* \param Event A pointer to an event object.
* \param Timeout The timeout value.
*
* \return TRUE if the event object was set before the timeout period expired, otherwise FALSE.
*
* \remarks To test the event, use PhTestEvent() instead of using a timeout of zero.
*/
BOOLEAN FASTCALL PhfWaitForEvent(
_Inout_ PPH_EVENT Event,
_In_opt_ PLARGE_INTEGER Timeout
)
{
BOOLEAN result;
ULONG_PTR value;
HANDLE eventHandle;
value = Event->Value;
// Shortcut: if the event is set, return immediately.
if (value & PH_EVENT_SET)
return TRUE;
// Shortcut: if the timeout is 0, return immediately if the event isn't set.
if (Timeout && Timeout->QuadPart == 0)
return FALSE;
// Prevent the event from being invalidated.
PhpReferenceEvent(Event);
eventHandle = Event->EventHandle;
if (!eventHandle)
{
NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
assert(eventHandle);
// Try to set the event handle to our event.
if (_InterlockedCompareExchangePointer(
&Event->EventHandle,
eventHandle,
NULL
) != NULL)
{
// Someone else set the event before we did.
NtClose(eventHandle);
eventHandle = Event->EventHandle;
}
}
// Essential: check the event one last time to see if it is set.
if (!(Event->Value & PH_EVENT_SET))
{
result = NtWaitForSingleObject(eventHandle, FALSE, Timeout) == STATUS_WAIT_0;
}
else
{
result = TRUE;
}
PhpDereferenceEvent(Event, eventHandle);
return result;
}
/**
* Resets an event's state.
*
* \param Event A pointer to an event object.
*
* \remarks This function is not thread-safe. Make sure no other threads are using the event when
* you call this function.
*/
VOID FASTCALL PhfResetEvent(
_Inout_ PPH_EVENT Event
)
{
assert(!Event->EventHandle);
if (PhTestEvent(Event))
Event->Value = PH_EVENT_REFCOUNT_INC;
}
VOID FASTCALL PhfInitializeBarrier(
_Out_ PPH_BARRIER Barrier,
_In_ ULONG_PTR Target
)
{
Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT;
PhInitializeWakeEvent(&Barrier->WakeEvent);
}
FORCEINLINE VOID PhpBlockOnBarrier(
_Inout_ PPH_BARRIER Barrier,
_In_ ULONG Role,
_In_ BOOLEAN Spin
)
{
PH_QUEUED_WAIT_BLOCK waitBlock;
ULONG_PTR cancel;
PhQueueWakeEvent(&Barrier->WakeEvent, &waitBlock);
cancel = 0;
switch (Role)
{
case PH_BARRIER_MASTER:
cancel = ((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) == 1;
break;
case PH_BARRIER_SLAVE:
cancel = Barrier->Value & PH_BARRIER_WAKING;
break;
case PH_BARRIER_OBSERVER:
cancel = !(Barrier->Value & PH_BARRIER_WAKING);
break;
default:
ASSUME_NO_DEFAULT;
}
if (cancel)
{
PhSetWakeEvent(&Barrier->WakeEvent, &waitBlock);
return;
}
PhWaitForWakeEvent(&Barrier->WakeEvent, &waitBlock, Spin, NULL);
}
/**
* Waits until all threads are blocking on the barrier, and resets the state of the barrier.
*
* \param Barrier A barrier.
* \param Spin TRUE to spin on the barrier before blocking, FALSE to block immediately.
*
* \return TRUE for an unspecified thread after each phase, and FALSE for all other threads.
*
* \remarks By checking the return value of the function, in each phase an action can be performed
* exactly once. This could, for example, involve merging the results of calculations.
*/
BOOLEAN FASTCALL PhfWaitForBarrier(
_Inout_ PPH_BARRIER Barrier,
_In_ BOOLEAN Spin
)
{
ULONG_PTR value;
ULONG_PTR newValue;
ULONG_PTR count;
ULONG_PTR target;
value = Barrier->Value;
while (TRUE)
{
if (!(value & PH_BARRIER_WAKING))
{
count = (value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK;
target = (value >> PH_BARRIER_TARGET_SHIFT) & PH_BARRIER_TARGET_MASK;
assert(count != target);
count++;
if (count != target)
newValue = value + PH_BARRIER_COUNT_INC;
else
newValue = value + PH_BARRIER_COUNT_INC + PH_BARRIER_WAKING;
if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&Barrier->Value,
(PVOID)newValue,
(PVOID)value
)) == value)
{
if (count != target)
{
// Wait for the master signal (the last thread to reach the barrier).
// Once we get it, decrement the count to allow the master to continue.
do
{
PhpBlockOnBarrier(Barrier, PH_BARRIER_SLAVE, Spin);
} while (!(Barrier->Value & PH_BARRIER_WAKING));
value = _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -PH_BARRIER_COUNT_INC);
if (((value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) - 1 == 1)
{
PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for the master
}
return FALSE;
}
else
{
// We're the last one to reach the barrier, so we become the master.
// Wake the slaves and wait for them to decrease the count to 1. This is so that
// we know the slaves have woken and we don't clear the waking bit before they
// wake.
PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for slaves
do
{
PhpBlockOnBarrier(Barrier, PH_BARRIER_MASTER, Spin);
} while (((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) != 1);
_InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -(PH_BARRIER_WAKING + PH_BARRIER_COUNT_INC));
PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for observers
return TRUE;
}
}
}
else
{
// We're too early; other threads are still waking. Wait for them to finish.
PhpBlockOnBarrier(Barrier, PH_BARRIER_OBSERVER, Spin);
newValue = Barrier->Value;
}
value = newValue;
}
}
VOID FASTCALL PhfInitializeRundownProtection(
_Out_ PPH_RUNDOWN_PROTECT Protection
)
{
Protection->Value = 0;
}
BOOLEAN FASTCALL PhfAcquireRundownProtection(
_Inout_ PPH_RUNDOWN_PROTECT Protection
)
{
ULONG_PTR value;
// Increment the reference count only if rundown has not started.
while (TRUE)
{
value = Protection->Value;
if (value & PH_RUNDOWN_ACTIVE)
return FALSE;
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&Protection->Value,
(PVOID)(value + PH_RUNDOWN_REF_INC),
(PVOID)value
) == value)
return TRUE;
}
}
VOID FASTCALL PhfReleaseRundownProtection(
_Inout_ PPH_RUNDOWN_PROTECT Protection
)
{
ULONG_PTR value;
while (TRUE)
{
value = Protection->Value;
if (value & PH_RUNDOWN_ACTIVE)
{
PPH_RUNDOWN_WAIT_BLOCK waitBlock;
// Since rundown is active, the reference count has been moved to the waiter's wait
// block. If we are the last user, we must wake up the waiter.
waitBlock = (PPH_RUNDOWN_WAIT_BLOCK)(value & ~PH_RUNDOWN_ACTIVE);
if (_InterlockedDecrementPointer(&waitBlock->Count) == 0)
{
PhSetEvent(&waitBlock->WakeEvent);
}
break;
}
else
{
// Decrement the reference count normally.
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&Protection->Value,
(PVOID)(value - PH_RUNDOWN_REF_INC),
(PVOID)value
) == value)
break;
}
}
}
VOID FASTCALL PhfWaitForRundownProtection(
_Inout_ PPH_RUNDOWN_PROTECT Protection
)
{
ULONG_PTR value;
ULONG_PTR count;
PH_RUNDOWN_WAIT_BLOCK waitBlock;
BOOLEAN waitBlockInitialized;
// Fast path. If the reference count is 0 or rundown has already been completed, return.
value = (ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&Protection->Value,
(PVOID)PH_RUNDOWN_ACTIVE,
(PVOID)0
);
if (value == 0 || value == PH_RUNDOWN_ACTIVE)
return;
waitBlockInitialized = FALSE;
while (TRUE)
{
value = Protection->Value;
count = value >> PH_RUNDOWN_REF_SHIFT;
// Initialize the wait block if necessary.
if (count != 0 && !waitBlockInitialized)
{
PhInitializeEvent(&waitBlock.WakeEvent);
waitBlockInitialized = TRUE;
}
// Save the existing reference count.
waitBlock.Count = count;
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
(PVOID *)&Protection->Value,
(PVOID)((ULONG_PTR)&waitBlock | PH_RUNDOWN_ACTIVE),
(PVOID)value
) == value)
{
if (count != 0)
PhWaitForEvent(&waitBlock.WakeEvent, NULL);
break;
}
}
}
VOID FASTCALL PhfInitializeInitOnce(
_Out_ PPH_INITONCE InitOnce
)
{
PhInitializeEvent(&InitOnce->Event);
}
BOOLEAN FASTCALL PhfBeginInitOnce(
_Inout_ PPH_INITONCE InitOnce
)
{
if (!_InterlockedBitTestAndSetPointer(&InitOnce->Event.Value, PH_INITONCE_INITIALIZING_SHIFT))
return TRUE;
PhWaitForEvent(&InitOnce->Event, NULL);
return FALSE;
}
VOID FASTCALL PhfEndInitOnce(
_Inout_ PPH_INITONCE InitOnce
)
{
PhSetEvent(&InitOnce->Event);
}

6662
phlib/treenew.c Normal file

File diff suppressed because it is too large Load Diff

4970
phlib/util.c Normal file

File diff suppressed because it is too large Load Diff

671
phlib/verify.c Normal file
View File

@@ -0,0 +1,671 @@
/*
* Process Hacker -
* image verification
*
* Copyright (C) 2009-2013 wj32
*
* 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 <ph.h>
#include <verify.h>
#include <verifyp.h>
_CryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle;
_CryptCATAdminCalcHashFromFileHandle2 CryptCATAdminCalcHashFromFileHandle2;
_CryptCATAdminAcquireContext CryptCATAdminAcquireContext;
_CryptCATAdminAcquireContext2 CryptCATAdminAcquireContext2;
_CryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash;
_CryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext;
_CryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext;
_CryptCATAdminReleaseContext CryptCATAdminReleaseContext;
_WTHelperProvDataFromStateData WTHelperProvDataFromStateData_I;
_WTHelperGetProvSignerFromChain WTHelperGetProvSignerFromChain_I;
_WinVerifyTrust WinVerifyTrust_I;
_CertNameToStr CertNameToStr_I;
_CertDuplicateCertificateContext CertDuplicateCertificateContext_I;
_CertFreeCertificateContext CertFreeCertificateContext_I;
static PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT;
static GUID WinTrustActionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
static GUID DriverActionVerify = DRIVER_ACTION_VERIFY;
static VOID PhpVerifyInitialization(
VOID
)
{
HMODULE wintrust;
HMODULE crypt32;
wintrust = LoadLibrary(L"wintrust.dll");
crypt32 = LoadLibrary(L"crypt32.dll");
CryptCATAdminCalcHashFromFileHandle = (PVOID)GetProcAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle");
CryptCATAdminCalcHashFromFileHandle2 = (PVOID)GetProcAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2");
CryptCATAdminAcquireContext = (PVOID)GetProcAddress(wintrust, "CryptCATAdminAcquireContext");
CryptCATAdminAcquireContext2 = (PVOID)GetProcAddress(wintrust, "CryptCATAdminAcquireContext2");
CryptCATAdminEnumCatalogFromHash = (PVOID)GetProcAddress(wintrust, "CryptCATAdminEnumCatalogFromHash");
CryptCATCatalogInfoFromContext = (PVOID)GetProcAddress(wintrust, "CryptCATCatalogInfoFromContext");
CryptCATAdminReleaseCatalogContext = (PVOID)GetProcAddress(wintrust, "CryptCATAdminReleaseCatalogContext");
CryptCATAdminReleaseContext = (PVOID)GetProcAddress(wintrust, "CryptCATAdminReleaseContext");
WTHelperProvDataFromStateData_I = (PVOID)GetProcAddress(wintrust, "WTHelperProvDataFromStateData");
WTHelperGetProvSignerFromChain_I = (PVOID)GetProcAddress(wintrust, "WTHelperGetProvSignerFromChain");
WinVerifyTrust_I = (PVOID)GetProcAddress(wintrust, "WinVerifyTrust");
CertNameToStr_I = (PVOID)GetProcAddress(crypt32, "CertNameToStrW");
CertDuplicateCertificateContext_I = (PVOID)GetProcAddress(crypt32, "CertDuplicateCertificateContext");
CertFreeCertificateContext_I = (PVOID)GetProcAddress(crypt32, "CertFreeCertificateContext");
}
VERIFY_RESULT PhpStatusToVerifyResult(
_In_ LONG Status
)
{
switch (Status)
{
case 0:
return VrTrusted;
case TRUST_E_NOSIGNATURE:
return VrNoSignature;
case CERT_E_EXPIRED:
return VrExpired;
case CERT_E_REVOKED:
return VrRevoked;
case TRUST_E_EXPLICIT_DISTRUST:
return VrDistrust;
case CRYPT_E_SECURITY_SETTINGS:
return VrSecuritySettings;
case TRUST_E_BAD_DIGEST:
return VrBadSignature;
default:
return VrSecuritySettings;
}
}
BOOLEAN PhpGetSignaturesFromStateData(
_In_ HANDLE StateData,
_Out_ PCERT_CONTEXT **Signatures,
_Out_ PULONG NumberOfSignatures
)
{
PCRYPT_PROVIDER_DATA provData;
PCRYPT_PROVIDER_SGNR sgnr;
PCERT_CONTEXT *signatures;
ULONG i;
ULONG numberOfSignatures;
ULONG index;
provData = WTHelperProvDataFromStateData_I(StateData);
if (!provData)
{
*Signatures = NULL;
*NumberOfSignatures = 0;
return FALSE;
}
i = 0;
numberOfSignatures = 0;
while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0))
{
if (sgnr->csCertChain != 0)
numberOfSignatures++;
i++;
}
if (numberOfSignatures != 0)
{
signatures = PhAllocate(numberOfSignatures * sizeof(PCERT_CONTEXT));
i = 0;
index = 0;
while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0))
{
if (sgnr->csCertChain != 0)
signatures[index++] = (PCERT_CONTEXT)CertDuplicateCertificateContext_I(sgnr->pasCertChain[0].pCert);
i++;
}
}
else
{
signatures = NULL;
}
*Signatures = signatures;
*NumberOfSignatures = numberOfSignatures;
return TRUE;
}
VOID PhpViewSignerInfo(
_In_ PPH_VERIFY_FILE_INFO Information,
_In_ HANDLE StateData
)
{
static PH_INITONCE initOnce = PH_INITONCE_INIT;
static _CryptUIDlgViewSignerInfo cryptUIDlgViewSignerInfo;
if (PhBeginInitOnce(&initOnce))
{
HMODULE cryptui = LoadLibrary(L"cryptui.dll");
cryptUIDlgViewSignerInfo = (PVOID)GetProcAddress(cryptui, "CryptUIDlgViewSignerInfoW");
PhEndInitOnce(&initOnce);
}
if (cryptUIDlgViewSignerInfo)
{
CRYPTUI_VIEWSIGNERINFO_STRUCT viewSignerInfo = { sizeof(CRYPTUI_VIEWSIGNERINFO_STRUCT) };
PCRYPT_PROVIDER_DATA provData;
PCRYPT_PROVIDER_SGNR sgnr;
if (!(provData = WTHelperProvDataFromStateData_I(StateData)))
return;
if (!(sgnr = WTHelperGetProvSignerFromChain_I(provData, 0, FALSE, 0)))
return;
viewSignerInfo.hwndParent = Information->hWnd;
viewSignerInfo.pSignerInfo = sgnr->psSigner;
viewSignerInfo.hMsg = provData->hMsg;
viewSignerInfo.pszOID = szOID_PKIX_KP_CODE_SIGNING;
cryptUIDlgViewSignerInfo(&viewSignerInfo);
}
}
VERIFY_RESULT PhpVerifyFile(
_In_ PPH_VERIFY_FILE_INFO Information,
_In_ HANDLE FileHandle,
_In_ ULONG UnionChoice,
_In_ PVOID UnionData,
_In_ PGUID ActionId,
_In_opt_ PVOID PolicyCallbackData,
_Out_ PCERT_CONTEXT **Signatures,
_Out_ PULONG NumberOfSignatures
)
{
LONG status;
WINTRUST_DATA trustData = { 0 };
trustData.cbStruct = sizeof(WINTRUST_DATA);
trustData.pPolicyCallbackData = PolicyCallbackData;
trustData.dwUIChoice = WTD_UI_NONE;
trustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
trustData.dwUnionChoice = UnionChoice;
trustData.dwStateAction = WTD_STATEACTION_VERIFY;
trustData.dwProvFlags = WTD_SAFER_FLAG;
trustData.pFile = UnionData;
if (UnionChoice == WTD_CHOICE_CATALOG)
trustData.pCatalog = UnionData;
if (Information->Flags & PH_VERIFY_PREVENT_NETWORK_ACCESS)
{
trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
if (WindowsVersion >= WINDOWS_VISTA)
trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;
else
trustData.dwProvFlags |= WTD_REVOCATION_CHECK_NONE;
}
status = WinVerifyTrust_I(NULL, ActionId, &trustData);
PhpGetSignaturesFromStateData(trustData.hWVTStateData, Signatures, NumberOfSignatures);
if (status == 0 && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES))
PhpViewSignerInfo(Information, trustData.hWVTStateData);
// Close the state data.
trustData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust_I(NULL, ActionId, &trustData);
return PhpStatusToVerifyResult(status);
}
BOOLEAN PhpCalculateFileHash(
_In_ HANDLE FileHandle,
_In_ PWSTR HashAlgorithm,
_Out_ PUCHAR *FileHash,
_Out_ PULONG FileHashLength,
_Out_ HANDLE *CatAdminHandle
)
{
HANDLE catAdminHandle;
PUCHAR fileHash;
ULONG fileHashLength;
if (CryptCATAdminAcquireContext2)
{
if (!CryptCATAdminAcquireContext2(&catAdminHandle, &DriverActionVerify, HashAlgorithm, NULL, 0))
return FALSE;
}
else
{
if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0))
return FALSE;
}
fileHashLength = 32;
fileHash = PhAllocate(fileHashLength);
if (CryptCATAdminCalcHashFromFileHandle2)
{
if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0))
{
PhFree(fileHash);
fileHash = PhAllocate(fileHashLength);
if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0))
{
CryptCATAdminReleaseContext(catAdminHandle, 0);
PhFree(fileHash);
return FALSE;
}
}
}
else
{
if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0))
{
PhFree(fileHash);
fileHash = PhAllocate(fileHashLength);
if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0))
{
CryptCATAdminReleaseContext(catAdminHandle, 0);
PhFree(fileHash);
return FALSE;
}
}
}
*FileHash = fileHash;
*FileHashLength = fileHashLength;
*CatAdminHandle = catAdminHandle;
return TRUE;
}
VERIFY_RESULT PhpVerifyFileFromCatalog(
_In_ PPH_VERIFY_FILE_INFO Information,
_In_ HANDLE FileHandle,
_In_opt_ PWSTR HashAlgorithm,
_Out_ PCERT_CONTEXT **Signatures,
_Out_ PULONG NumberOfSignatures
)
{
VERIFY_RESULT verifyResult = VrNoSignature;
PCERT_CONTEXT *signatures;
ULONG numberOfSignatures;
WINTRUST_CATALOG_INFO catalogInfo = { 0 };
LARGE_INTEGER fileSize;
ULONG fileSizeLimit;
PUCHAR fileHash;
ULONG fileHashLength;
PPH_STRING fileHashTag;
HANDLE catAdminHandle;
HANDLE catInfoHandle;
ULONG i;
*Signatures = NULL;
*NumberOfSignatures = 0;
if (!NT_SUCCESS(PhGetFileSize(FileHandle, &fileSize)))
return VrNoSignature;
signatures = NULL;
numberOfSignatures = 0;
if (Information->FileSizeLimitForHash != -1)
{
fileSizeLimit = PH_VERIFY_DEFAULT_SIZE_LIMIT;
if (Information->FileSizeLimitForHash != 0)
fileSizeLimit = Information->FileSizeLimitForHash;
if (fileSize.QuadPart > fileSizeLimit)
return VrNoSignature;
}
if (PhpCalculateFileHash(FileHandle, HashAlgorithm, &fileHash, &fileHashLength, &catAdminHandle))
{
fileHashTag = PhBufferToHexStringEx(fileHash, fileHashLength, TRUE);
// Search the system catalogs.
catInfoHandle = CryptCATAdminEnumCatalogFromHash(
catAdminHandle,
fileHash,
fileHashLength,
0,
NULL
);
if (catInfoHandle)
{
CATALOG_INFO ci = { 0 };
DRIVER_VER_INFO verInfo = { 0 };
if (CryptCATCatalogInfoFromContext(catInfoHandle, &ci, 0))
{
// Disable OS version checking by passing in a DRIVER_VER_INFO structure.
verInfo.cbStruct = sizeof(DRIVER_VER_INFO);
catalogInfo.cbStruct = sizeof(catalogInfo);
catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile;
catalogInfo.pcwszMemberFilePath = Information->FileName;
catalogInfo.pcwszMemberTag = fileHashTag->Buffer;
catalogInfo.pbCalculatedFileHash = fileHash;
catalogInfo.cbCalculatedFileHash = fileHashLength;
catalogInfo.hCatAdmin = catAdminHandle;
verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures);
if (verInfo.pcSignerCertContext)
CertFreeCertificateContext_I(verInfo.pcSignerCertContext);
}
CryptCATAdminReleaseCatalogContext(catAdminHandle, catInfoHandle, 0);
}
else
{
// Search any user-supplied catalogs.
for (i = 0; i < Information->NumberOfCatalogFileNames; i++)
{
PhFreeVerifySignatures(signatures, numberOfSignatures);
catalogInfo.cbStruct = sizeof(catalogInfo);
catalogInfo.pcwszCatalogFilePath = Information->CatalogFileNames[i];
catalogInfo.pcwszMemberFilePath = Information->FileName;
catalogInfo.pcwszMemberTag = fileHashTag->Buffer;
catalogInfo.pbCalculatedFileHash = fileHash;
catalogInfo.cbCalculatedFileHash = fileHashLength;
catalogInfo.hCatAdmin = catAdminHandle;
verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures);
if (verifyResult == VrTrusted)
break;
}
}
PhDereferenceObject(fileHashTag);
PhFree(fileHash);
CryptCATAdminReleaseContext(catAdminHandle, 0);
}
*Signatures = signatures;
*NumberOfSignatures = numberOfSignatures;
return verifyResult;
}
NTSTATUS PhVerifyFileEx(
_In_ PPH_VERIFY_FILE_INFO Information,
_Out_ VERIFY_RESULT *VerifyResult,
_Out_opt_ PCERT_CONTEXT **Signatures,
_Out_opt_ PULONG NumberOfSignatures
)
{
NTSTATUS status;
HANDLE fileHandle;
VERIFY_RESULT verifyResult;
PCERT_CONTEXT *signatures;
ULONG numberOfSignatures;
WINTRUST_FILE_INFO fileInfo = { 0 };
if (PhBeginInitOnce(&PhpVerifyInitOnce))
{
PhpVerifyInitialization();
PhEndInitOnce(&PhpVerifyInitOnce);
}
// Make sure we have successfully imported the required functions.
if (
!CryptCATAdminCalcHashFromFileHandle ||
!CryptCATAdminAcquireContext ||
!CryptCATAdminEnumCatalogFromHash ||
!CryptCATCatalogInfoFromContext ||
!CryptCATAdminReleaseCatalogContext ||
!CryptCATAdminReleaseContext ||
!WinVerifyTrust_I ||
!WTHelperProvDataFromStateData_I ||
!WTHelperGetProvSignerFromChain_I ||
!CertNameToStr_I ||
!CertDuplicateCertificateContext_I ||
!CertFreeCertificateContext_I
)
return STATUS_NOT_SUPPORTED;
if (!NT_SUCCESS(status = PhCreateFileWin32(
&fileHandle,
Information->FileName,
FILE_GENERIC_READ,
0,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
)))
return status;
fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
fileInfo.pcwszFilePath = Information->FileName;
fileInfo.hFile = fileHandle;
verifyResult = PhpVerifyFile(Information, fileHandle, WTD_CHOICE_FILE, &fileInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures);
if (verifyResult == VrNoSignature)
{
if (CryptCATAdminAcquireContext2 && CryptCATAdminCalcHashFromFileHandle2)
{
PhFreeVerifySignatures(signatures, numberOfSignatures);
verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, BCRYPT_SHA256_ALGORITHM, &signatures, &numberOfSignatures);
}
if (verifyResult != VrTrusted)
{
PhFreeVerifySignatures(signatures, numberOfSignatures);
verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, NULL, &signatures, &numberOfSignatures);
}
}
*VerifyResult = verifyResult;
if (Signatures)
*Signatures = signatures;
else
PhFreeVerifySignatures(signatures, numberOfSignatures);
if (NumberOfSignatures)
*NumberOfSignatures = numberOfSignatures;
NtClose(fileHandle);
return STATUS_SUCCESS;
}
VOID PhFreeVerifySignatures(
_In_ PCERT_CONTEXT *Signatures,
_In_ ULONG NumberOfSignatures
)
{
ULONG i;
if (Signatures)
{
for (i = 0; i < NumberOfSignatures; i++)
CertFreeCertificateContext_I(Signatures[i]);
PhFree(Signatures);
}
}
PPH_STRING PhpGetCertNameString(
_In_ PCERT_NAME_BLOB Blob
)
{
PPH_STRING string;
ULONG bufferSize;
// CertNameToStr doesn't give us the correct buffer size unless we don't provide a buffer at
// all.
bufferSize = CertNameToStr_I(
X509_ASN_ENCODING,
Blob,
CERT_X500_NAME_STR,
NULL,
0
);
string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR));
CertNameToStr_I(
X509_ASN_ENCODING,
Blob,
CERT_X500_NAME_STR,
string->Buffer,
bufferSize
);
PhTrimToNullTerminatorString(string);
return string;
}
PPH_STRING PhpGetX500Value(
_In_ PPH_STRINGREF String,
_In_ PPH_STRINGREF KeyName
)
{
WCHAR keyNamePlusEqualsBuffer[10];
PH_STRINGREF keyNamePlusEquals;
SIZE_T keyNameLength;
PH_STRINGREF firstPart;
PH_STRINGREF remainingPart;
keyNameLength = KeyName->Length / sizeof(WCHAR);
assert(!(keyNameLength > sizeof(keyNamePlusEquals) / sizeof(WCHAR) - 1));
keyNamePlusEquals.Buffer = keyNamePlusEqualsBuffer;
keyNamePlusEquals.Length = (keyNameLength + 1) * sizeof(WCHAR);
memcpy(keyNamePlusEquals.Buffer, KeyName->Buffer, KeyName->Length);
keyNamePlusEquals.Buffer[keyNameLength] = '=';
// Find "Key=".
if (!PhSplitStringRefAtString(String, &keyNamePlusEquals, FALSE, &firstPart, &remainingPart))
return NULL;
if (remainingPart.Length == 0)
return NULL;
// Is the value quoted? If so, return the part inside the quotes.
if (remainingPart.Buffer[0] == '"')
{
PhSkipStringRef(&remainingPart, sizeof(WCHAR));
if (!PhSplitStringRefAtChar(&remainingPart, '"', &firstPart, &remainingPart))
return NULL;
return PhCreateString2(&firstPart);
}
else
{
PhSplitStringRefAtChar(&remainingPart, ',', &firstPart, &remainingPart);
return PhCreateString2(&firstPart);
}
}
PPH_STRING PhGetSignerNameFromCertificate(
_In_ PCERT_CONTEXT Certificate
)
{
PCERT_INFO certInfo;
PH_STRINGREF keyName;
PPH_STRING name;
PPH_STRING value;
// Cert context -> Cert info
certInfo = Certificate->pCertInfo;
if (!certInfo)
return NULL;
// Cert info subject -> Subject X.500 string
name = PhpGetCertNameString(&certInfo->Subject);
// Subject X.500 string -> CN or OU value
PhInitializeStringRef(&keyName, L"CN");
value = PhpGetX500Value(&name->sr, &keyName);
if (!value)
{
PhInitializeStringRef(&keyName, L"OU");
value = PhpGetX500Value(&name->sr, &keyName);
}
PhDereferenceObject(name);
return value;
}
/**
* Verifies a file's digital signature.
*
* \param FileName A file name.
* \param SignerName A variable which receives a pointer to a string containing the signer name. You
* must free the string using PhDereferenceObject() when you no longer need it. Note that the signer
* name may be NULL if it is not valid.
*
* \return A VERIFY_RESULT value.
*/
VERIFY_RESULT PhVerifyFile(
_In_ PWSTR FileName,
_Out_opt_ PPH_STRING *SignerName
)
{
PH_VERIFY_FILE_INFO info = { 0 };
VERIFY_RESULT verifyResult;
PCERT_CONTEXT *signatures;
ULONG numberOfSignatures;
info.FileName = FileName;
info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS;
if (NT_SUCCESS(PhVerifyFileEx(&info, &verifyResult, &signatures, &numberOfSignatures)))
{
if (SignerName)
{
*SignerName = NULL;
if (numberOfSignatures != 0)
*SignerName = PhGetSignerNameFromCertificate(signatures[0]);
}
PhFreeVerifySignatures(signatures, numberOfSignatures);
return verifyResult;
}
else
{
if (SignerName)
*SignerName = NULL;
return VrNoSignature;
}
}

Some files were not shown because too many files have changed in this diff Show More