mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
7969ebfbc4
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@6128 21ef857c-d57f-4fe0-8362-d861dc6d29cd
978 lines
32 KiB
C
978 lines
32 KiB
C
/*
|
|
* Process Hacker -
|
|
* module list
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include <phapp.h>
|
|
#include <settings.h>
|
|
#include <extmgri.h>
|
|
#include <phplug.h>
|
|
#include <emenu.h>
|
|
#include <verify.h>
|
|
|
|
BOOLEAN PhpModuleNodeHashtableCompareFunction(
|
|
_In_ PVOID Entry1,
|
|
_In_ PVOID Entry2
|
|
);
|
|
|
|
ULONG PhpModuleNodeHashtableHashFunction(
|
|
_In_ PVOID Entry
|
|
);
|
|
|
|
VOID PhpDestroyModuleNode(
|
|
_In_ PPH_MODULE_NODE ModuleNode
|
|
);
|
|
|
|
VOID PhpRemoveModuleNode(
|
|
_In_ PPH_MODULE_NODE ModuleNode,
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context
|
|
);
|
|
|
|
LONG PhpModuleTreeNewPostSortFunction(
|
|
_In_ LONG Result,
|
|
_In_ PVOID Node1,
|
|
_In_ PVOID Node2,
|
|
_In_ PH_SORT_ORDER SortOrder
|
|
);
|
|
|
|
BOOLEAN NTAPI PhpModuleTreeNewCallback(
|
|
_In_ HWND hwnd,
|
|
_In_ PH_TREENEW_MESSAGE Message,
|
|
_In_opt_ PVOID Parameter1,
|
|
_In_opt_ PVOID Parameter2,
|
|
_In_opt_ PVOID Context
|
|
);
|
|
|
|
VOID PhInitializeModuleList(
|
|
_In_ HWND ParentWindowHandle,
|
|
_In_ HWND TreeNewHandle,
|
|
_Out_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
HWND hwnd;
|
|
|
|
memset(Context, 0, sizeof(PH_MODULE_LIST_CONTEXT));
|
|
Context->EnableStateHighlighting = TRUE;
|
|
|
|
Context->NodeHashtable = PhCreateHashtable(
|
|
sizeof(PPH_MODULE_NODE),
|
|
PhpModuleNodeHashtableCompareFunction,
|
|
PhpModuleNodeHashtableHashFunction,
|
|
100
|
|
);
|
|
Context->NodeList = PhCreateList(100);
|
|
|
|
Context->ParentWindowHandle = ParentWindowHandle;
|
|
Context->TreeNewHandle = TreeNewHandle;
|
|
hwnd = TreeNewHandle;
|
|
PhSetControlTheme(hwnd, L"explorer");
|
|
|
|
TreeNew_SetCallback(hwnd, PhpModuleTreeNewCallback, Context);
|
|
|
|
TreeNew_SetRedraw(hwnd, FALSE);
|
|
|
|
// Default columns
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, -2, 0);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_BASEADDRESS, TRUE, L"Base Address", 80, PH_ALIGN_RIGHT, 0, DT_RIGHT);
|
|
PhAddTreeNewColumnEx(hwnd, PHMOTLC_SIZE, TRUE, L"Size", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_DESCRIPTION, TRUE, L"Description", 160, PH_ALIGN_LEFT, 2, 0);
|
|
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_COMPANYNAME, FALSE, L"Company Name", 180, PH_ALIGN_LEFT, -1, 0);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_FILENAME, FALSE, L"File Name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS);
|
|
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, -1, 0);
|
|
PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADCOUNT, FALSE, L"Load Count", 40, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification Status", 70, PH_ALIGN_LEFT, -1, 0);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified Signer", 100, PH_ALIGN_LEFT, -1, 0);
|
|
PhAddTreeNewColumnEx(hwnd, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE);
|
|
PhAddTreeNewColumnEx(hwnd, PHMOTLC_TIMESTAMP, FALSE, L"Time Stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE);
|
|
PhAddTreeNewColumnEx(hwnd, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE);
|
|
PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADTIME, FALSE, L"Load Time", 100, PH_ALIGN_LEFT, -1, 0, TRUE);
|
|
PhAddTreeNewColumn(hwnd, PHMOTLC_LOADREASON, FALSE, L"Load Reason", 80, PH_ALIGN_LEFT, -1, 0);
|
|
|
|
TreeNew_SetRedraw(hwnd, TRUE);
|
|
|
|
TreeNew_SetTriState(hwnd, TRUE);
|
|
TreeNew_SetSort(hwnd, 0, NoSortOrder);
|
|
|
|
PhCmInitializeManager(&Context->Cm, hwnd, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction);
|
|
}
|
|
|
|
VOID PhDeleteModuleList(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
if (Context->BoldFont)
|
|
DeleteObject(Context->BoldFont);
|
|
|
|
PhCmDeleteManager(&Context->Cm);
|
|
|
|
for (i = 0; i < Context->NodeList->Count; i++)
|
|
PhpDestroyModuleNode(Context->NodeList->Items[i]);
|
|
|
|
PhDereferenceObject(Context->NodeHashtable);
|
|
PhDereferenceObject(Context->NodeList);
|
|
}
|
|
|
|
BOOLEAN PhpModuleNodeHashtableCompareFunction(
|
|
_In_ PVOID Entry1,
|
|
_In_ PVOID Entry2
|
|
)
|
|
{
|
|
PPH_MODULE_NODE moduleNode1 = *(PPH_MODULE_NODE *)Entry1;
|
|
PPH_MODULE_NODE moduleNode2 = *(PPH_MODULE_NODE *)Entry2;
|
|
|
|
return moduleNode1->ModuleItem == moduleNode2->ModuleItem;
|
|
}
|
|
|
|
ULONG PhpModuleNodeHashtableHashFunction(
|
|
_In_ PVOID Entry
|
|
)
|
|
{
|
|
return PhHashIntPtr((ULONG_PTR)(*(PPH_MODULE_NODE *)Entry)->ModuleItem);
|
|
}
|
|
|
|
VOID PhLoadSettingsModuleList(
|
|
_Inout_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
PPH_STRING settings;
|
|
PPH_STRING sortSettings;
|
|
|
|
settings = PhGetStringSetting(L"ModuleTreeListColumns");
|
|
sortSettings = PhGetStringSetting(L"ModuleTreeListSort");
|
|
PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);
|
|
PhDereferenceObject(settings);
|
|
PhDereferenceObject(sortSettings);
|
|
}
|
|
|
|
VOID PhSaveSettingsModuleList(
|
|
_Inout_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
PPH_STRING settings;
|
|
PPH_STRING sortSettings;
|
|
|
|
settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);
|
|
PhSetStringSetting2(L"ModuleTreeListColumns", &settings->sr);
|
|
PhSetStringSetting2(L"ModuleTreeListSort", &sortSettings->sr);
|
|
PhDereferenceObject(settings);
|
|
PhDereferenceObject(sortSettings);
|
|
}
|
|
|
|
PPH_MODULE_NODE PhAddModuleNode(
|
|
_Inout_ PPH_MODULE_LIST_CONTEXT Context,
|
|
_In_ PPH_MODULE_ITEM ModuleItem,
|
|
_In_ ULONG RunId
|
|
)
|
|
{
|
|
PPH_MODULE_NODE moduleNode;
|
|
|
|
moduleNode = PhAllocate(PhEmGetObjectSize(EmModuleNodeType, sizeof(PH_MODULE_NODE)));
|
|
memset(moduleNode, 0, sizeof(PH_MODULE_NODE));
|
|
PhInitializeTreeNewNode(&moduleNode->Node);
|
|
|
|
if (Context->EnableStateHighlighting && RunId != 1)
|
|
{
|
|
PhChangeShStateTn(
|
|
&moduleNode->Node,
|
|
&moduleNode->ShState,
|
|
&Context->NodeStateList,
|
|
NewItemState,
|
|
PhCsColorNew,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
moduleNode->ModuleItem = ModuleItem;
|
|
PhReferenceObject(ModuleItem);
|
|
|
|
memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM);
|
|
moduleNode->Node.TextCache = moduleNode->TextCache;
|
|
moduleNode->Node.TextCacheSize = PHMOTLC_MAXIMUM;
|
|
|
|
PhAddEntryHashtable(Context->NodeHashtable, &moduleNode);
|
|
PhAddItemList(Context->NodeList, moduleNode);
|
|
|
|
PhEmCallObjectOperation(EmModuleNodeType, moduleNode, EmObjectCreate);
|
|
|
|
TreeNew_NodesStructured(Context->TreeNewHandle);
|
|
|
|
return moduleNode;
|
|
}
|
|
|
|
PPH_MODULE_NODE PhFindModuleNode(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context,
|
|
_In_ PPH_MODULE_ITEM ModuleItem
|
|
)
|
|
{
|
|
PH_MODULE_NODE lookupModuleNode;
|
|
PPH_MODULE_NODE lookupModuleNodePtr = &lookupModuleNode;
|
|
PPH_MODULE_NODE *moduleNode;
|
|
|
|
lookupModuleNode.ModuleItem = ModuleItem;
|
|
|
|
moduleNode = (PPH_MODULE_NODE *)PhFindEntryHashtable(
|
|
Context->NodeHashtable,
|
|
&lookupModuleNodePtr
|
|
);
|
|
|
|
if (moduleNode)
|
|
return *moduleNode;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
VOID PhRemoveModuleNode(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context,
|
|
_In_ PPH_MODULE_NODE ModuleNode
|
|
)
|
|
{
|
|
// Remove from the hashtable here to avoid problems in case the key is re-used.
|
|
PhRemoveEntryHashtable(Context->NodeHashtable, &ModuleNode);
|
|
|
|
if (Context->EnableStateHighlighting)
|
|
{
|
|
PhChangeShStateTn(
|
|
&ModuleNode->Node,
|
|
&ModuleNode->ShState,
|
|
&Context->NodeStateList,
|
|
RemovingItemState,
|
|
PhCsColorRemoved,
|
|
Context->TreeNewHandle
|
|
);
|
|
}
|
|
else
|
|
{
|
|
PhpRemoveModuleNode(ModuleNode, Context);
|
|
}
|
|
}
|
|
|
|
VOID PhpDestroyModuleNode(
|
|
_In_ PPH_MODULE_NODE ModuleNode
|
|
)
|
|
{
|
|
PhEmCallObjectOperation(EmModuleNodeType, ModuleNode, EmObjectDelete);
|
|
|
|
if (ModuleNode->TooltipText) PhDereferenceObject(ModuleNode->TooltipText);
|
|
|
|
if (ModuleNode->SizeText) PhDereferenceObject(ModuleNode->SizeText);
|
|
if (ModuleNode->TimeStampText) PhDereferenceObject(ModuleNode->TimeStampText);
|
|
if (ModuleNode->LoadTimeText) PhDereferenceObject(ModuleNode->LoadTimeText);
|
|
|
|
PhDereferenceObject(ModuleNode->ModuleItem);
|
|
|
|
PhFree(ModuleNode);
|
|
}
|
|
|
|
VOID PhpRemoveModuleNode(
|
|
_In_ PPH_MODULE_NODE ModuleNode,
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ModuleNode
|
|
)
|
|
{
|
|
ULONG index;
|
|
|
|
// Remove from list and cleanup.
|
|
|
|
if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != -1)
|
|
PhRemoveItemList(Context->NodeList, index);
|
|
|
|
PhpDestroyModuleNode(ModuleNode);
|
|
|
|
TreeNew_NodesStructured(Context->TreeNewHandle);
|
|
}
|
|
|
|
VOID PhUpdateModuleNode(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context,
|
|
_In_ PPH_MODULE_NODE ModuleNode
|
|
)
|
|
{
|
|
memset(ModuleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM);
|
|
PhClearReference(&ModuleNode->TooltipText);
|
|
|
|
ModuleNode->ValidMask = 0;
|
|
PhInvalidateTreeNewNode(&ModuleNode->Node, TN_CACHE_COLOR);
|
|
TreeNew_NodesStructured(Context->TreeNewHandle);
|
|
}
|
|
|
|
VOID PhTickModuleNodes(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
PH_TICK_SH_STATE_TN(PH_MODULE_NODE, ShState, Context->NodeStateList, PhpRemoveModuleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context);
|
|
}
|
|
|
|
#define SORT_FUNCTION(Column) PhpModuleTreeNewCompare##Column
|
|
|
|
#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpModuleTreeNewCompare##Column( \
|
|
_In_ void *_context, \
|
|
_In_ const void *_elem1, \
|
|
_In_ const void *_elem2 \
|
|
) \
|
|
{ \
|
|
PPH_MODULE_NODE node1 = *(PPH_MODULE_NODE *)_elem1; \
|
|
PPH_MODULE_NODE node2 = *(PPH_MODULE_NODE *)_elem2; \
|
|
PPH_MODULE_ITEM moduleItem1 = node1->ModuleItem; \
|
|
PPH_MODULE_ITEM moduleItem2 = node2->ModuleItem; \
|
|
int sortResult = 0;
|
|
|
|
#define END_SORT_FUNCTION \
|
|
if (sortResult == 0) \
|
|
sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress); \
|
|
\
|
|
return PhModifySort(sortResult, ((PPH_MODULE_LIST_CONTEXT)_context)->TreeNewSortOrder); \
|
|
}
|
|
|
|
LONG PhpModuleTreeNewPostSortFunction(
|
|
_In_ LONG Result,
|
|
_In_ PVOID Node1,
|
|
_In_ PVOID Node2,
|
|
_In_ PH_SORT_ORDER SortOrder
|
|
)
|
|
{
|
|
if (Result == 0)
|
|
Result = uintptrcmp((ULONG_PTR)((PPH_MODULE_NODE)Node1)->ModuleItem->BaseAddress, (ULONG_PTR)((PPH_MODULE_NODE)Node2)->ModuleItem->BaseAddress);
|
|
|
|
return PhModifySort(Result, SortOrder);
|
|
}
|
|
|
|
BEGIN_SORT_FUNCTION(TriState)
|
|
{
|
|
if (moduleItem1->IsFirst)
|
|
{
|
|
sortResult = -1;
|
|
}
|
|
else if (moduleItem2->IsFirst)
|
|
{
|
|
sortResult = 1;
|
|
}
|
|
else
|
|
{
|
|
sortResult = PhCompareString(moduleItem1->Name, moduleItem2->Name, TRUE); // fall back to sorting by name
|
|
}
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(Name)
|
|
{
|
|
sortResult = PhCompareString(moduleItem1->Name, moduleItem2->Name, TRUE);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(BaseAddress)
|
|
{
|
|
sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(Size)
|
|
{
|
|
sortResult = uintcmp(moduleItem1->Size, moduleItem2->Size);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(Description)
|
|
{
|
|
sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.FileDescription, moduleItem2->VersionInfo.FileDescription, TRUE);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(CompanyName)
|
|
{
|
|
sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.CompanyName, moduleItem2->VersionInfo.CompanyName, TRUE);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(Version)
|
|
{
|
|
sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.FileVersion, moduleItem2->VersionInfo.FileVersion, TRUE);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(FileName)
|
|
{
|
|
sortResult = PhCompareStringWithNull(moduleItem1->FileName, moduleItem2->FileName, TRUE);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(Type)
|
|
{
|
|
sortResult = uintcmp(moduleItem1->Type, moduleItem2->Type);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(LoadCount)
|
|
{
|
|
sortResult = uintcmp(moduleItem1->LoadCount, moduleItem2->LoadCount);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(VerificationStatus)
|
|
{
|
|
sortResult = intcmp(moduleItem1->VerifyResult, moduleItem2->VerifyResult);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(VerifiedSigner)
|
|
{
|
|
sortResult = PhCompareStringWithNull(
|
|
moduleItem1->VerifySignerName,
|
|
moduleItem2->VerifySignerName,
|
|
TRUE
|
|
);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(Aslr)
|
|
{
|
|
sortResult = intcmp(
|
|
moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,
|
|
moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
|
);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(TimeStamp)
|
|
{
|
|
sortResult = uintcmp(moduleItem1->ImageTimeDateStamp, moduleItem2->ImageTimeDateStamp);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(CfGuard)
|
|
{
|
|
sortResult = intcmp(
|
|
moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF,
|
|
moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF
|
|
);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(LoadTime)
|
|
{
|
|
sortResult = uint64cmp(moduleItem1->LoadTime.QuadPart, moduleItem2->LoadTime.QuadPart);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BEGIN_SORT_FUNCTION(LoadReason)
|
|
{
|
|
sortResult = uintcmp(moduleItem1->LoadReason, moduleItem2->LoadReason);
|
|
}
|
|
END_SORT_FUNCTION
|
|
|
|
BOOLEAN NTAPI PhpModuleTreeNewCallback(
|
|
_In_ HWND hwnd,
|
|
_In_ PH_TREENEW_MESSAGE Message,
|
|
_In_opt_ PVOID Parameter1,
|
|
_In_opt_ PVOID Parameter2,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_MODULE_LIST_CONTEXT context;
|
|
PPH_MODULE_NODE node;
|
|
|
|
context = Context;
|
|
|
|
if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm))
|
|
return TRUE;
|
|
|
|
switch (Message)
|
|
{
|
|
case TreeNewGetChildren:
|
|
{
|
|
PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
|
|
|
|
if (!getChildren->Node)
|
|
{
|
|
static PVOID sortFunctions[] =
|
|
{
|
|
SORT_FUNCTION(Name),
|
|
SORT_FUNCTION(BaseAddress),
|
|
SORT_FUNCTION(Size),
|
|
SORT_FUNCTION(Description),
|
|
SORT_FUNCTION(CompanyName),
|
|
SORT_FUNCTION(Version),
|
|
SORT_FUNCTION(FileName),
|
|
SORT_FUNCTION(Type),
|
|
SORT_FUNCTION(LoadCount),
|
|
SORT_FUNCTION(VerificationStatus),
|
|
SORT_FUNCTION(VerifiedSigner),
|
|
SORT_FUNCTION(Aslr),
|
|
SORT_FUNCTION(TimeStamp),
|
|
SORT_FUNCTION(CfGuard),
|
|
SORT_FUNCTION(LoadTime),
|
|
SORT_FUNCTION(LoadReason)
|
|
};
|
|
int (__cdecl *sortFunction)(void *, const void *, const void *);
|
|
|
|
if (context->TreeNewSortOrder == NoSortOrder)
|
|
{
|
|
sortFunction = SORT_FUNCTION(TriState);
|
|
}
|
|
else
|
|
{
|
|
if (!PhCmForwardSort(
|
|
(PPH_TREENEW_NODE *)context->NodeList->Items,
|
|
context->NodeList->Count,
|
|
context->TreeNewSortColumn,
|
|
context->TreeNewSortOrder,
|
|
&context->Cm
|
|
))
|
|
{
|
|
if (context->TreeNewSortColumn < PHMOTLC_MAXIMUM)
|
|
sortFunction = sortFunctions[context->TreeNewSortColumn];
|
|
else
|
|
sortFunction = NULL;
|
|
}
|
|
else
|
|
{
|
|
sortFunction = NULL;
|
|
}
|
|
}
|
|
|
|
if (sortFunction)
|
|
{
|
|
qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);
|
|
}
|
|
|
|
getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;
|
|
getChildren->NumberOfChildren = context->NodeList->Count;
|
|
}
|
|
}
|
|
return TRUE;
|
|
case TreeNewIsLeaf:
|
|
{
|
|
PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
|
|
|
|
isLeaf->IsLeaf = TRUE;
|
|
}
|
|
return TRUE;
|
|
case TreeNewGetCellText:
|
|
{
|
|
PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
|
|
PPH_MODULE_ITEM moduleItem;
|
|
|
|
node = (PPH_MODULE_NODE)getCellText->Node;
|
|
moduleItem = node->ModuleItem;
|
|
|
|
switch (getCellText->Id)
|
|
{
|
|
case PHMOTLC_NAME:
|
|
getCellText->Text = moduleItem->Name->sr;
|
|
break;
|
|
case PHMOTLC_BASEADDRESS:
|
|
PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->BaseAddressString);
|
|
break;
|
|
case PHMOTLC_SIZE:
|
|
if (!node->SizeText)
|
|
node->SizeText = PhFormatSize(moduleItem->Size, -1);
|
|
getCellText->Text = PhGetStringRef(node->SizeText);
|
|
break;
|
|
case PHMOTLC_DESCRIPTION:
|
|
getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileDescription);
|
|
break;
|
|
case PHMOTLC_COMPANYNAME:
|
|
getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.CompanyName);
|
|
break;
|
|
case PHMOTLC_VERSION:
|
|
getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileVersion);
|
|
break;
|
|
case PHMOTLC_FILENAME:
|
|
getCellText->Text = PhGetStringRef(moduleItem->FileName);
|
|
break;
|
|
case PHMOTLC_TYPE:
|
|
{
|
|
PWSTR typeString;
|
|
|
|
switch (moduleItem->Type)
|
|
{
|
|
case PH_MODULE_TYPE_MODULE:
|
|
typeString = L"DLL";
|
|
break;
|
|
case PH_MODULE_TYPE_MAPPED_FILE:
|
|
typeString = L"Mapped File";
|
|
break;
|
|
case PH_MODULE_TYPE_MAPPED_IMAGE:
|
|
typeString = L"Mapped Image";
|
|
break;
|
|
case PH_MODULE_TYPE_WOW64_MODULE:
|
|
typeString = L"WOW64 DLL";
|
|
break;
|
|
case PH_MODULE_TYPE_KERNEL_MODULE:
|
|
typeString = L"Kernel Module";
|
|
break;
|
|
default:
|
|
typeString = L"Unknown";
|
|
break;
|
|
}
|
|
|
|
PhInitializeStringRefLongHint(&getCellText->Text, typeString);
|
|
}
|
|
break;
|
|
case PHMOTLC_LOADCOUNT:
|
|
if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE ||
|
|
moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE)
|
|
{
|
|
if (moduleItem->LoadCount != (USHORT)-1)
|
|
{
|
|
PhPrintInt32(node->LoadCountText, moduleItem->LoadCount);
|
|
PhInitializeStringRefLongHint(&getCellText->Text, node->LoadCountText);
|
|
}
|
|
else
|
|
{
|
|
PhInitializeStringRef(&getCellText->Text, L"Static");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PhInitializeEmptyStringRef(&getCellText->Text);
|
|
}
|
|
break;
|
|
case PHMOTLC_VERIFICATIONSTATUS:
|
|
if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE ||
|
|
moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE)
|
|
{
|
|
PhInitializeStringRef(&getCellText->Text,
|
|
moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not Trusted");
|
|
}
|
|
else
|
|
{
|
|
PhInitializeEmptyStringRef(&getCellText->Text);
|
|
}
|
|
break;
|
|
case PHMOTLC_VERIFIEDSIGNER:
|
|
getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName);
|
|
break;
|
|
case PHMOTLC_ASLR:
|
|
if (WindowsVersion >= WINDOWS_VISTA)
|
|
{
|
|
if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
|
|
PhInitializeStringRef(&getCellText->Text, L"ASLR");
|
|
}
|
|
else
|
|
{
|
|
PhInitializeStringRef(&getCellText->Text, L"N/A");
|
|
}
|
|
break;
|
|
case PHMOTLC_TIMESTAMP:
|
|
{
|
|
LARGE_INTEGER time;
|
|
SYSTEMTIME systemTime;
|
|
|
|
if (moduleItem->ImageTimeDateStamp != 0)
|
|
{
|
|
RtlSecondsSince1970ToTime(moduleItem->ImageTimeDateStamp, &time);
|
|
PhLargeIntegerToLocalSystemTime(&systemTime, &time);
|
|
PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime));
|
|
getCellText->Text = node->TimeStampText->sr;
|
|
}
|
|
else
|
|
{
|
|
PhInitializeEmptyStringRef(&getCellText->Text);
|
|
}
|
|
}
|
|
break;
|
|
case PHMOTLC_CFGUARD:
|
|
if (WindowsVersion >= WINDOWS_8_1)
|
|
{
|
|
if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)
|
|
PhInitializeStringRef(&getCellText->Text, L"CF Guard");
|
|
}
|
|
else
|
|
{
|
|
PhInitializeStringRef(&getCellText->Text, L"N/A");
|
|
}
|
|
break;
|
|
case PHMOTLC_LOADTIME:
|
|
{
|
|
SYSTEMTIME systemTime;
|
|
|
|
if (moduleItem->LoadTime.QuadPart != 0)
|
|
{
|
|
PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->LoadTime);
|
|
PhMoveReference(&node->LoadTimeText, PhFormatDateTime(&systemTime));
|
|
getCellText->Text = node->LoadTimeText->sr;
|
|
}
|
|
else
|
|
{
|
|
PhInitializeEmptyStringRef(&getCellText->Text);
|
|
}
|
|
}
|
|
break;
|
|
case PHMOTLC_LOADREASON:
|
|
{
|
|
PWSTR string = L"";
|
|
|
|
if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE)
|
|
{
|
|
switch (moduleItem->LoadReason)
|
|
{
|
|
case LoadReasonStaticDependency:
|
|
string = L"Static Dependency";
|
|
break;
|
|
case LoadReasonStaticForwarderDependency:
|
|
string = L"Static Forwarder Dependency";
|
|
break;
|
|
case LoadReasonDynamicForwarderDependency:
|
|
string = L"Dynamic Forwarder Dependency";
|
|
break;
|
|
case LoadReasonDelayloadDependency:
|
|
string = L"Delay Load Dependency";
|
|
break;
|
|
case LoadReasonDynamicLoad:
|
|
string = L"Dynamic";
|
|
break;
|
|
case LoadReasonAsImageLoad:
|
|
string = L"As Image";
|
|
break;
|
|
case LoadReasonAsDataLoad:
|
|
string = L"As Data";
|
|
break;
|
|
default:
|
|
if (WindowsVersion >= WINDOWS_8)
|
|
string = L"Unknown";
|
|
else
|
|
string = L"N/A";
|
|
break;
|
|
}
|
|
}
|
|
|
|
PhInitializeStringRefLongHint(&getCellText->Text, string);
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
getCellText->Flags = TN_CACHE;
|
|
}
|
|
return TRUE;
|
|
case TreeNewGetNodeColor:
|
|
{
|
|
PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;
|
|
PPH_MODULE_ITEM moduleItem;
|
|
|
|
node = (PPH_MODULE_NODE)getNodeColor->Node;
|
|
moduleItem = node->ModuleItem;
|
|
|
|
if (!moduleItem)
|
|
; // Dummy
|
|
else if (PhCsUseColorDotNet && (moduleItem->Flags & LDRP_COR_IMAGE))
|
|
getNodeColor->BackColor = PhCsColorDotNet;
|
|
else if (PhCsUseColorImmersiveProcesses && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER))
|
|
getNodeColor->BackColor = PhCsColorImmersiveProcesses;
|
|
else if (PhCsUseColorRelocatedModules && (moduleItem->Flags & LDRP_IMAGE_NOT_AT_BASE))
|
|
getNodeColor->BackColor = PhCsColorRelocatedModules;
|
|
|
|
getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;
|
|
}
|
|
return TRUE;
|
|
case TreeNewGetNodeFont:
|
|
{
|
|
PPH_TREENEW_GET_NODE_FONT getNodeFont = Parameter1;
|
|
|
|
node = (PPH_MODULE_NODE)getNodeFont->Node;
|
|
|
|
// Make the executable file module item bold.
|
|
if (node->ModuleItem->IsFirst)
|
|
{
|
|
if (!context->BoldFont)
|
|
context->BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0), FW_BOLD);
|
|
|
|
getNodeFont->Font = context->BoldFont ? context->BoldFont : NULL;
|
|
getNodeFont->Flags = TN_CACHE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case TreeNewGetCellTooltip:
|
|
{
|
|
PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;
|
|
|
|
node = (PPH_MODULE_NODE)getCellTooltip->Node;
|
|
|
|
if (getCellTooltip->Column->Id != 0)
|
|
return FALSE;
|
|
|
|
if (!node->TooltipText)
|
|
{
|
|
node->TooltipText = PhFormatImageVersionInfo(
|
|
node->ModuleItem->FileName,
|
|
&node->ModuleItem->VersionInfo,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
// Make sure we don't try to create the tooltip text again.
|
|
if (!node->TooltipText)
|
|
node->TooltipText = PhReferenceEmptyString();
|
|
}
|
|
|
|
if (!PhIsNullOrEmptyString(node->TooltipText))
|
|
{
|
|
getCellTooltip->Text = node->TooltipText->sr;
|
|
getCellTooltip->Unfolding = FALSE;
|
|
getCellTooltip->Font = NULL; // use default font
|
|
getCellTooltip->MaximumWidth = 550;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
case TreeNewSortChanged:
|
|
{
|
|
TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder);
|
|
// Force a rebuild to sort the items.
|
|
TreeNew_NodesStructured(hwnd);
|
|
}
|
|
return TRUE;
|
|
case TreeNewKeyDown:
|
|
{
|
|
PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
|
|
|
|
switch (keyEvent->VirtualKey)
|
|
{
|
|
case 'C':
|
|
if (GetKeyState(VK_CONTROL) < 0)
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_COPY, 0);
|
|
break;
|
|
case 'A':
|
|
if (GetKeyState(VK_CONTROL) < 0)
|
|
TreeNew_SelectRange(context->TreeNewHandle, 0, -1);
|
|
break;
|
|
case 'M':
|
|
if (GetKeyState(VK_CONTROL) < 0)
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_SEARCHONLINE, 0);
|
|
break;
|
|
case VK_DELETE:
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_UNLOAD, 0);
|
|
break;
|
|
case VK_RETURN:
|
|
if (GetKeyState(VK_CONTROL) >= 0)
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_INSPECT, 0);
|
|
else
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_OPENFILELOCATION, 0);
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
case TreeNewHeaderRightClick:
|
|
{
|
|
PH_TN_COLUMN_MENU_DATA data;
|
|
|
|
data.TreeNewHandle = hwnd;
|
|
data.MouseEvent = Parameter1;
|
|
data.DefaultSortColumn = 0;
|
|
data.DefaultSortOrder = NoSortOrder;
|
|
PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT);
|
|
|
|
data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT,
|
|
PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);
|
|
PhHandleTreeNewColumnMenu(&data);
|
|
PhDeleteTreeNewColumnMenu(&data);
|
|
}
|
|
return TRUE;
|
|
case TreeNewLeftDoubleClick:
|
|
{
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_INSPECT, 0);
|
|
}
|
|
return TRUE;
|
|
case TreeNewContextMenu:
|
|
{
|
|
PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;
|
|
|
|
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu);
|
|
}
|
|
return TRUE;
|
|
case TreeNewGetDialogCode:
|
|
{
|
|
PULONG code = Parameter2;
|
|
|
|
if (PtrToUlong(Parameter1) == VK_RETURN)
|
|
{
|
|
*code = DLGC_WANTMESSAGE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
PPH_MODULE_ITEM PhGetSelectedModuleItem(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = NULL;
|
|
ULONG i;
|
|
|
|
for (i = 0; i < Context->NodeList->Count; i++)
|
|
{
|
|
PPH_MODULE_NODE node = Context->NodeList->Items[i];
|
|
|
|
if (node->Node.Selected)
|
|
{
|
|
moduleItem = node->ModuleItem;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return moduleItem;
|
|
}
|
|
|
|
VOID PhGetSelectedModuleItems(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context,
|
|
_Out_ PPH_MODULE_ITEM **Modules,
|
|
_Out_ PULONG NumberOfModules
|
|
)
|
|
{
|
|
PPH_LIST list;
|
|
ULONG i;
|
|
|
|
list = PhCreateList(2);
|
|
|
|
for (i = 0; i < Context->NodeList->Count; i++)
|
|
{
|
|
PPH_MODULE_NODE node = Context->NodeList->Items[i];
|
|
|
|
if (node->Node.Selected)
|
|
{
|
|
PhAddItemList(list, node->ModuleItem);
|
|
}
|
|
}
|
|
|
|
*Modules = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);
|
|
*NumberOfModules = list->Count;
|
|
|
|
PhDereferenceObject(list);
|
|
}
|
|
|
|
VOID PhDeselectAllModuleNodes(
|
|
_In_ PPH_MODULE_LIST_CONTEXT Context
|
|
)
|
|
{
|
|
TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1);
|
|
}
|