mirror of
https://github.com/hfiref0x/WinObjEx64
synced 2026-06-08 14:40:58 +00:00
61848a3234
+ Centralize and modernize plugin subsystem definitions and fix related bugs, remove duplicate definitions. + Internal rearrangement.
404 lines
9.5 KiB
C
404 lines
9.5 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2020 - 2026
|
|
*
|
|
* TITLE: MAIN.C
|
|
*
|
|
* VERSION: 1.23
|
|
*
|
|
* DATE: 07 Mar 2026
|
|
*
|
|
* WinObjEx64 ImageScope plugin.
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include "global.h"
|
|
|
|
#define IMAGESCOPE_PLUGIN_MAJOR_VERSION 1
|
|
#define IMAGESCOPE_PLUGIN_MINOR_VERSION 2
|
|
|
|
//
|
|
// Dll instance.
|
|
//
|
|
HINSTANCE g_thisDll = NULL;
|
|
|
|
volatile DWORD g_pluginState = PLUGIN_RUNNING;
|
|
|
|
//
|
|
// Plugin entry.
|
|
//
|
|
WINOBJEX_PLUGIN* g_plugin = NULL;
|
|
volatile LONG g_refCount = 0;
|
|
|
|
/*
|
|
* PmpCopyObjectData
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Create copies of object directory and name.
|
|
*
|
|
*/
|
|
BOOL PmpCopyObjectData(
|
|
_In_ WINOBJEX_PARAM_OBJECT* Source,
|
|
_In_ WINOBJEX_PARAM_OBJECT* Dest
|
|
)
|
|
{
|
|
HANDLE HeapHandle = NtCurrentPeb()->ProcessHeap;
|
|
|
|
return supDuplicateUnicodeString(HeapHandle, &Dest->Directory, &Source->Directory) &&
|
|
supDuplicateUnicodeString(HeapHandle, &Dest->Name, &Source->Name);
|
|
}
|
|
|
|
/*
|
|
* PluginFreeGlobalResources
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Plugin resources deallocation routine.
|
|
*
|
|
*/
|
|
VOID PluginFreeGlobalResources(
|
|
_In_ GUI_CONTEXT* Context
|
|
)
|
|
{
|
|
if (Context->SectionAddress) {
|
|
NtUnmapViewOfSection(NtCurrentProcess(), Context->SectionAddress);
|
|
Context->SectionAddress = NULL;
|
|
}
|
|
|
|
supFreeDuplicatedUnicodeString(NtCurrentPeb()->ProcessHeap,
|
|
&Context->ParamBlock.Object.Directory, TRUE);
|
|
|
|
supFreeDuplicatedUnicodeString(NtCurrentPeb()->ProcessHeap,
|
|
&Context->ParamBlock.Object.Name, TRUE);
|
|
}
|
|
|
|
/*
|
|
* PluginThread
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Plugin payload thread.
|
|
*
|
|
*/
|
|
DWORD WINAPI PluginThread(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
ULONG uResult = 0;
|
|
GUI_CONTEXT* context = (GUI_CONTEXT*)Parameter;
|
|
|
|
if (context == NULL)
|
|
return (DWORD)-1;
|
|
|
|
InterlockedIncrement(&g_refCount);
|
|
|
|
__try {
|
|
if (g_plugin == NULL || g_plugin->GuiInitCallback == NULL) { // this is required callback
|
|
kdDebugPrint("Gui init callback required\r\n");
|
|
__leave;
|
|
}
|
|
|
|
if (!g_plugin->GuiInitCallback(g_plugin,
|
|
g_thisDll,
|
|
(WNDPROC)MainWindowProc,
|
|
NULL))
|
|
{
|
|
kdDebugPrint("Gui init callback failure\r\n");
|
|
__leave;
|
|
}
|
|
|
|
uResult = (ULONG)RunUI(context);
|
|
}
|
|
__finally {
|
|
InterlockedDecrement(&g_refCount);
|
|
PluginFreeGlobalResources(context);
|
|
supHeapFree(context);
|
|
}
|
|
|
|
ExitThread(uResult);
|
|
}
|
|
|
|
/*
|
|
* StartPlugin
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Run actual plugin code in dedicated thread.
|
|
*
|
|
*/
|
|
NTSTATUS CALLBACK StartPlugin(
|
|
_In_ PWINOBJEX_PARAM_BLOCK ParamBlock
|
|
)
|
|
{
|
|
BOOL deallocateContext = FALSE;
|
|
DWORD threadId;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
WINOBJEX_PLUGIN_STATE state = PluginInitialization;
|
|
HANDLE workerThread, sectionHandle = NULL;
|
|
GUI_CONTEXT* Context;
|
|
|
|
WCHAR szError[100];
|
|
|
|
Context = (GUI_CONTEXT*)supHeapAlloc(sizeof(GUI_CONTEXT));
|
|
if (Context == NULL)
|
|
return STATUS_MEMORY_NOT_ALLOCATED;
|
|
|
|
__try {
|
|
RtlCopyMemory(
|
|
&Context->ParamBlock,
|
|
ParamBlock,
|
|
sizeof(WINOBJEX_PARAM_BLOCK));
|
|
|
|
RtlZeroMemory(
|
|
&Context->ParamBlock.Object,
|
|
sizeof(WINOBJEX_PARAM_OBJECT));
|
|
|
|
if (!PmpCopyObjectData(
|
|
&ParamBlock->Object,
|
|
&Context->ParamBlock.Object))
|
|
{
|
|
deallocateContext = TRUE;
|
|
status = STATUS_MEMORY_NOT_ALLOCATED;
|
|
__leave;
|
|
}
|
|
|
|
if (Context->ParamBlock.OpenNamedObjectByType == NULL) {
|
|
deallocateContext = TRUE;
|
|
status = STATUS_INVALID_PARAMETER;
|
|
__leave;
|
|
}
|
|
|
|
status = Context->ParamBlock.OpenNamedObjectByType(
|
|
§ionHandle,
|
|
PluginObjectTypeSection,
|
|
&Context->ParamBlock.Object.Directory,
|
|
&Context->ParamBlock.Object.Name,
|
|
SECTION_QUERY | SECTION_MAP_READ);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
StringCbPrintf(szError, sizeof(szError), TEXT("Could not open section, 0x%08X"), (ULONG)status);
|
|
|
|
MessageBox(
|
|
ParamBlock->ParentWindow,
|
|
szError,
|
|
T_PLUGIN_NAME,
|
|
MB_ICONERROR);
|
|
|
|
deallocateContext = TRUE;
|
|
status = STATUS_SUCCESS;
|
|
__leave;
|
|
}
|
|
|
|
// Map section
|
|
status = supMapSection(
|
|
sectionHandle,
|
|
&Context->SectionAddress,
|
|
&Context->SectionViewSize);
|
|
|
|
NtClose(sectionHandle);
|
|
sectionHandle = NULL;
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (status == STATUS_NOT_SUPPORTED) {
|
|
MessageBox(ParamBlock->ParentWindow,
|
|
TEXT("This section does not represent mapped image, unable to continue."),
|
|
T_PLUGIN_NAME,
|
|
MB_ICONINFORMATION);
|
|
}
|
|
else {
|
|
StringCbPrintf(szError, sizeof(szError), TEXT("Could not map section, 0x%08X"), (ULONG)status);
|
|
MessageBox(ParamBlock->ParentWindow, szError,
|
|
T_PLUGIN_NAME,
|
|
MB_ICONERROR);
|
|
}
|
|
|
|
// Stop plugin if we cannot open section, but do not fail with error as we already displayed it.
|
|
state = PluginStopped;
|
|
deallocateContext = TRUE;
|
|
status = STATUS_SUCCESS;
|
|
__leave;
|
|
}
|
|
|
|
workerThread = CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)PluginThread,
|
|
(PVOID)Context,
|
|
0,
|
|
&threadId);
|
|
|
|
if (workerThread) {
|
|
status = STATUS_SUCCESS;
|
|
CloseHandle(workerThread);
|
|
workerThread = NULL;
|
|
state = PluginRunning;
|
|
}
|
|
else {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
state = PluginError;
|
|
deallocateContext = TRUE;
|
|
}
|
|
}
|
|
__finally {
|
|
if (sectionHandle) {
|
|
NtClose(sectionHandle);
|
|
}
|
|
|
|
if (deallocateContext && Context) {
|
|
supHeapFree(Context);
|
|
}
|
|
|
|
if (g_plugin && g_plugin->StateChangeCallback)
|
|
g_plugin->StateChangeCallback(g_plugin, state, NULL);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* StopPlugin
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Stop plugin execution.
|
|
*
|
|
*/
|
|
void CALLBACK StopPlugin(
|
|
VOID
|
|
)
|
|
{
|
|
// Signal stop
|
|
InterlockedExchange((PLONG)&g_pluginState, PLUGIN_STOP);
|
|
|
|
// Wait for all references to be released
|
|
while (InterlockedCompareExchange(&g_refCount, 0, 0) > 0)
|
|
Sleep(50);
|
|
|
|
if (g_plugin && g_plugin->GuiShutdownCallback)
|
|
g_plugin->GuiShutdownCallback(g_plugin, g_thisDll, NULL);
|
|
|
|
}
|
|
|
|
/*
|
|
* PluginInit
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Initialize plugin information for WinObjEx64.
|
|
*
|
|
*/
|
|
BOOLEAN CALLBACK PluginInit(
|
|
_Inout_ PWINOBJEX_PLUGIN PluginData
|
|
)
|
|
{
|
|
// Don't initialize twice
|
|
if (g_plugin) {
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
|
|
if (PluginData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (PluginData->cbSize < sizeof(WINOBJEX_PLUGIN)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (PluginData->AbiVersion != WINOBJEX_PLUGIN_ABI_VERSION) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Set plugin name to be displayed in WinObjEx64 UI.
|
|
//
|
|
StringCbCopy(PluginData->Name, sizeof(PluginData->Name), TEXT("ImageScope"));
|
|
|
|
//
|
|
// Set authors.
|
|
//
|
|
StringCbCopy(PluginData->Authors, sizeof(PluginData->Authors), TEXT("UG North"));
|
|
|
|
//
|
|
// Set plugin description.
|
|
//
|
|
StringCbCopy(PluginData->Description, sizeof(PluginData->Description),
|
|
TEXT("Display additional information for sections created from PE files."));
|
|
|
|
//
|
|
// Set required plugin system version.
|
|
//
|
|
PluginData->RequiredPluginSystemVersion = WOBJ_PLUGIN_SYSTEM_VERSION;
|
|
|
|
//
|
|
// Setup start/stop plugin callbacks.
|
|
//
|
|
PluginData->StartPlugin = (pfnStartPlugin)&StartPlugin;
|
|
PluginData->StopPlugin = (pfnStopPlugin)&StopPlugin;
|
|
|
|
//
|
|
// Setup capabilities.
|
|
//
|
|
PluginData->Capabilities.u1.NeedAdmin = FALSE;
|
|
PluginData->Capabilities.u1.SupportWine = TRUE;
|
|
PluginData->Capabilities.u1.NeedDriver = FALSE;
|
|
PluginData->Capabilities.u1.SupportMultipleInstances = TRUE;
|
|
|
|
PluginData->MajorVersion = IMAGESCOPE_PLUGIN_MAJOR_VERSION;
|
|
PluginData->MinorVersion = IMAGESCOPE_PLUGIN_MINOR_VERSION;
|
|
|
|
//
|
|
// Set plugin type.
|
|
//
|
|
PluginData->Type = ContextPlugin;
|
|
|
|
//
|
|
// Set supported object type(s).
|
|
//
|
|
RtlFillMemory(
|
|
PluginData->SupportedObjectsIds,
|
|
sizeof(PluginData->SupportedObjectsIds),
|
|
PluginObjectTypeNone);
|
|
|
|
PluginData->SupportedObjectsIds[0] = (UCHAR)PluginObjectTypeSection;
|
|
|
|
g_plugin = PluginData;
|
|
|
|
return TRUE;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
DbgPrint("PluginInit exception thrown %lx\r\n", GetExceptionCode());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DllMain
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Dll entry point.
|
|
*
|
|
*/
|
|
BOOL WINAPI DllMain(
|
|
_In_ HINSTANCE hinstDLL,
|
|
_In_ DWORD fdwReason,
|
|
_In_ LPVOID lpvReserved
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpvReserved);
|
|
|
|
if (fdwReason == DLL_PROCESS_ATTACH) {
|
|
g_thisDll = hinstDLL;
|
|
DisableThreadLibraryCalls(hinstDLL);
|
|
}
|
|
return TRUE;
|
|
}
|