1004 lines
36 KiB
C
1004 lines
36 KiB
C
/*
|
|
* Process Hacker -
|
|
* PE viewer
|
|
*
|
|
* 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 <peview.h>
|
|
#include <workqueue.h>
|
|
#include <mapimg.h>
|
|
#include <cpysave.h>
|
|
#include <verify.h>
|
|
#include <shlobj.h>
|
|
#include <uxtheme.h>
|
|
#include <shellapi.h>
|
|
|
|
#define PVM_CHECKSUM_DONE (WM_APP + 1)
|
|
#define PVM_VERIFY_DONE (WM_APP + 2)
|
|
|
|
INT_PTR CALLBACK PvpPeGeneralDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK PvpPeImportsDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK PvpPeExportsDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK PvpPeLoadConfigDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK PvpPeClrDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
PH_MAPPED_IMAGE PvMappedImage;
|
|
PIMAGE_COR20_HEADER PvImageCor20Header;
|
|
|
|
HICON PvImageLargeIcon;
|
|
PH_IMAGE_VERSION_INFO PvImageVersionInfo;
|
|
VERIFY_RESULT PvImageVerifyResult;
|
|
PPH_STRING PvImageSignerName;
|
|
|
|
VOID PvPeProperties(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
|
|
PROPSHEETPAGE propSheetPage;
|
|
HPROPSHEETPAGE pages[5];
|
|
PH_MAPPED_IMAGE_IMPORTS imports;
|
|
PH_MAPPED_IMAGE_EXPORTS exports;
|
|
PIMAGE_DATA_DIRECTORY entry;
|
|
|
|
status = PhLoadMappedImage(PvFileName->Buffer, NULL, TRUE, &PvMappedImage);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
PhShowStatus(NULL, L"Unable to load the PE file", status, 0);
|
|
return;
|
|
}
|
|
|
|
propSheetHeader.dwFlags =
|
|
PSH_NOAPPLYNOW |
|
|
PSH_NOCONTEXTHELP |
|
|
PSH_PROPTITLE;
|
|
propSheetHeader.hwndParent = NULL;
|
|
propSheetHeader.pszCaption = PvFileName->Buffer;
|
|
propSheetHeader.nPages = 0;
|
|
propSheetHeader.nStartPage = 0;
|
|
propSheetHeader.phpage = pages;
|
|
|
|
// General page
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PEGENERAL);
|
|
propSheetPage.pfnDlgProc = PvpPeGeneralDlgProc;
|
|
pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
|
|
|
|
// Imports page
|
|
if ((NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0) ||
|
|
(NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0))
|
|
{
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PEIMPORTS);
|
|
propSheetPage.pfnDlgProc = PvpPeImportsDlgProc;
|
|
pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
|
|
}
|
|
|
|
// Exports page
|
|
if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage)) && exports.NumberOfEntries != 0)
|
|
{
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PEEXPORTS);
|
|
propSheetPage.pfnDlgProc = PvpPeExportsDlgProc;
|
|
pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
|
|
}
|
|
|
|
// Load Config page
|
|
if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry)) && entry->VirtualAddress)
|
|
{
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PELOADCONFIG);
|
|
propSheetPage.pfnDlgProc = PvpPeLoadConfigDlgProc;
|
|
pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
|
|
}
|
|
|
|
// CLR page
|
|
if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &entry)) &&
|
|
entry->VirtualAddress &&
|
|
(PvImageCor20Header = PhMappedImageRvaToVa(&PvMappedImage, entry->VirtualAddress, NULL)))
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
|
|
__try
|
|
{
|
|
PhProbeAddress(PvImageCor20Header, sizeof(IMAGE_COR20_HEADER),
|
|
PvMappedImage.ViewBase, PvMappedImage.Size, 4);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PECLR);
|
|
propSheetPage.pfnDlgProc = PvpPeClrDlgProc;
|
|
pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
|
|
}
|
|
}
|
|
|
|
PropertySheet(&propSheetHeader);
|
|
|
|
PhUnloadMappedImage(&PvMappedImage);
|
|
}
|
|
|
|
static NTSTATUS CheckSumImageThreadStart(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
HWND windowHandle;
|
|
ULONG checkSum;
|
|
|
|
windowHandle = Parameter;
|
|
checkSum = PhCheckSumMappedImage(&PvMappedImage);
|
|
|
|
PostMessage(
|
|
windowHandle,
|
|
PVM_CHECKSUM_DONE,
|
|
checkSum,
|
|
0
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VERIFY_RESULT PvpVerifyFileWithAdditionalCatalog(
|
|
_In_ PPH_STRING FileName,
|
|
_In_ ULONG Flags,
|
|
_In_opt_ HWND hWnd,
|
|
_Out_opt_ PPH_STRING *SignerName
|
|
)
|
|
{
|
|
static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat");
|
|
|
|
VERIFY_RESULT result;
|
|
PH_VERIFY_FILE_INFO info;
|
|
PPH_STRING windowsAppsPath;
|
|
PPH_STRING additionalCatalogFileName = NULL;
|
|
PCERT_CONTEXT *signatures;
|
|
ULONG numberOfSignatures;
|
|
|
|
memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));
|
|
info.FileName = FileName->Buffer;
|
|
info.Flags = Flags;
|
|
info.hWnd = hWnd;
|
|
|
|
windowsAppsPath = PhGetKnownLocation(CSIDL_PROGRAM_FILES, L"\\WindowsApps\\");
|
|
|
|
if (windowsAppsPath)
|
|
{
|
|
if (PhStartsWithStringRef(&FileName->sr, &windowsAppsPath->sr, TRUE))
|
|
{
|
|
PH_STRINGREF remainingFileName;
|
|
ULONG_PTR indexOfBackslash;
|
|
PH_STRINGREF baseFileName;
|
|
|
|
remainingFileName = FileName->sr;
|
|
PhSkipStringRef(&remainingFileName, windowsAppsPath->Length);
|
|
indexOfBackslash = PhFindCharInStringRef(&remainingFileName, '\\', FALSE);
|
|
|
|
if (indexOfBackslash != -1)
|
|
{
|
|
baseFileName.Buffer = FileName->Buffer;
|
|
baseFileName.Length = windowsAppsPath->Length + indexOfBackslash * sizeof(WCHAR);
|
|
additionalCatalogFileName = PhConcatStringRef2(&baseFileName, &codeIntegrityFileName);
|
|
}
|
|
}
|
|
|
|
PhDereferenceObject(windowsAppsPath);
|
|
}
|
|
|
|
if (additionalCatalogFileName)
|
|
{
|
|
info.NumberOfCatalogFileNames = 1;
|
|
info.CatalogFileNames = &additionalCatalogFileName->Buffer;
|
|
}
|
|
|
|
if (!NT_SUCCESS(PhVerifyFileEx(&info, &result, &signatures, &numberOfSignatures)))
|
|
{
|
|
result = VrNoSignature;
|
|
signatures = NULL;
|
|
numberOfSignatures = 0;
|
|
}
|
|
|
|
if (additionalCatalogFileName)
|
|
PhDereferenceObject(additionalCatalogFileName);
|
|
|
|
if (SignerName)
|
|
{
|
|
if (numberOfSignatures != 0)
|
|
*SignerName = PhGetSignerNameFromCertificate(signatures[0]);
|
|
else
|
|
*SignerName = NULL;
|
|
}
|
|
|
|
PhFreeVerifySignatures(signatures, numberOfSignatures);
|
|
|
|
return result;
|
|
}
|
|
|
|
static NTSTATUS VerifyImageThreadStart(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
HWND windowHandle;
|
|
|
|
windowHandle = Parameter;
|
|
PvImageVerifyResult = PvpVerifyFileWithAdditionalCatalog(PvFileName, PH_VERIFY_PREVENT_NETWORK_ACCESS, NULL, &PvImageSignerName);
|
|
PostMessage(windowHandle, PVM_VERIFY_DONE, 0, 0);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
FORCEINLINE PWSTR PvpGetStringOrNa(
|
|
_In_ PPH_STRING String
|
|
)
|
|
{
|
|
if (String)
|
|
return String->Buffer;
|
|
else
|
|
return L"N/A";
|
|
}
|
|
|
|
INT_PTR CALLBACK PvpPeGeneralDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND lvHandle;
|
|
ULONG i;
|
|
PPH_STRING string;
|
|
PWSTR type;
|
|
PH_STRING_BUILDER stringBuilder;
|
|
|
|
PhCenterWindow(GetParent(hwndDlg), NULL);
|
|
|
|
// File version information
|
|
|
|
{
|
|
PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer);
|
|
|
|
if (ExtractIconEx(
|
|
PvFileName->Buffer,
|
|
0,
|
|
&PvImageLargeIcon,
|
|
NULL,
|
|
1
|
|
) == 0)
|
|
{
|
|
PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE);
|
|
}
|
|
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)PvImageLargeIcon, 0);
|
|
|
|
SetDlgItemText(hwndDlg, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription));
|
|
string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName));
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
SetDlgItemText(hwndDlg, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion));
|
|
|
|
PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), VerifyImageThreadStart, hwndDlg);
|
|
}
|
|
|
|
// PE properties
|
|
|
|
switch (PvMappedImage.NtHeaders->FileHeader.Machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
type = L"i386";
|
|
break;
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
type = L"AMD64";
|
|
break;
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
type = L"IA64";
|
|
break;
|
|
case IMAGE_FILE_MACHINE_ARMNT:
|
|
type = L"ARM Thumb-2";
|
|
break;
|
|
default:
|
|
type = L"Unknown";
|
|
break;
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_TARGETMACHINE, type);
|
|
|
|
{
|
|
LARGE_INTEGER time;
|
|
SYSTEMTIME systemTime;
|
|
|
|
RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time);
|
|
PhLargeIntegerToLocalSystemTime(&systemTime, &time);
|
|
|
|
string = PhFormatDateTime(&systemTime);
|
|
SetDlgItemText(hwndDlg, IDC_TIMESTAMP, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
|
|
if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
|
{
|
|
string = PhFormatString(L"0x%Ix", PvMappedImage.NtHeaders->OptionalHeader.ImageBase);
|
|
}
|
|
else
|
|
{
|
|
string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase);
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
|
|
string = PhFormatString(L"0x%Ix (verifying...)", PvMappedImage.NtHeaders->OptionalHeader.CheckSum); // same for 32-bit and 64-bit images
|
|
SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
|
|
PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), CheckSumImageThreadStart, hwndDlg);
|
|
|
|
switch (PvMappedImage.NtHeaders->OptionalHeader.Subsystem)
|
|
{
|
|
case IMAGE_SUBSYSTEM_NATIVE:
|
|
type = L"Native";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_GUI:
|
|
type = L"Windows GUI";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_CUI:
|
|
type = L"Windows CUI";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_OS2_CUI:
|
|
type = L"OS/2 CUI";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_POSIX_CUI:
|
|
type = L"POSIX CUI";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
|
|
type = L"Windows CE CUI";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_EFI_APPLICATION:
|
|
type = L"EFI Application";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
|
|
type = L"EFI Boot Service Driver";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
|
|
type = L"EFI Runtime Driver";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_EFI_ROM:
|
|
type = L"EFI ROM";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_XBOX:
|
|
type = L"Xbox";
|
|
break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
|
|
type = L"Windows Boot Application";
|
|
break;
|
|
default:
|
|
type = L"Unknown";
|
|
break;
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_SUBSYSTEM, type);
|
|
|
|
string = PhFormatString(
|
|
L"%u.%u",
|
|
PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, // same for 32-bit and 64-bit images
|
|
PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion
|
|
);
|
|
SetDlgItemText(hwndDlg, IDC_SUBSYSTEMVERSION, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
|
|
PhInitializeStringBuilder(&stringBuilder, 10);
|
|
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Executable, ");
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
|
|
PhAppendStringBuilder2(&stringBuilder, L"DLL, ");
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Large address aware, ");
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Removable run from swap, ");
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Net run from swap, ");
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_SYSTEM)
|
|
PhAppendStringBuilder2(&stringBuilder, L"System, ");
|
|
if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Uni-processor only, ");
|
|
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA)
|
|
PhAppendStringBuilder2(&stringBuilder, L"High entropy VA, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Dynamic base, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Force integrity check, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT)
|
|
PhAppendStringBuilder2(&stringBuilder, L"NX compatible, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION)
|
|
PhAppendStringBuilder2(&stringBuilder, L"No isolation, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH)
|
|
PhAppendStringBuilder2(&stringBuilder, L"No SEH, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Do not bind, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)
|
|
PhAppendStringBuilder2(&stringBuilder, L"AppContainer, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER)
|
|
PhAppendStringBuilder2(&stringBuilder, L"WDM driver, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Control Flow Guard, ");
|
|
if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Terminal server aware, ");
|
|
|
|
if (PhEndsWithString2(stringBuilder.String, L", ", FALSE))
|
|
PhRemoveEndStringBuilder(&stringBuilder, 2);
|
|
|
|
SetDlgItemText(hwndDlg, IDC_CHARACTERISTICS, stringBuilder.String->Buffer);
|
|
PhDeleteStringBuilder(&stringBuilder);
|
|
|
|
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
PhSetListViewStyle(lvHandle, FALSE, TRUE);
|
|
PhSetControlTheme(lvHandle, L"explorer");
|
|
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name");
|
|
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA");
|
|
PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size");
|
|
|
|
for (i = 0; i < PvMappedImage.NumberOfSections; i++)
|
|
{
|
|
INT lvItemIndex;
|
|
WCHAR sectionName[9];
|
|
WCHAR pointer[PH_PTR_STR_LEN_1];
|
|
|
|
if (PhCopyStringZFromBytes(PvMappedImage.Sections[i].Name,
|
|
IMAGE_SIZEOF_SHORT_NAME, sectionName, 9, NULL))
|
|
{
|
|
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL);
|
|
|
|
PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].VirtualAddress));
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer);
|
|
|
|
PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].SizeOfRawData));
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case PVM_CHECKSUM_DONE:
|
|
{
|
|
PPH_STRING string;
|
|
ULONG headerCheckSum;
|
|
ULONG realCheckSum;
|
|
|
|
headerCheckSum = PvMappedImage.NtHeaders->OptionalHeader.CheckSum; // same for 32-bit and 64-bit images
|
|
realCheckSum = (ULONG)wParam;
|
|
|
|
if (headerCheckSum == 0)
|
|
{
|
|
// Some executables, like .NET ones, don't have a check sum.
|
|
string = PhFormatString(L"0x0 (real 0x%Ix)", realCheckSum);
|
|
SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
else if (headerCheckSum == realCheckSum)
|
|
{
|
|
string = PhFormatString(L"0x%Ix (correct)", headerCheckSum);
|
|
SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
else
|
|
{
|
|
string = PhFormatString(L"0x%Ix (incorrect, real 0x%Ix)", headerCheckSum, realCheckSum);
|
|
SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
}
|
|
break;
|
|
case PVM_VERIFY_DONE:
|
|
{
|
|
PPH_STRING string;
|
|
|
|
if (PvImageVerifyResult == VrTrusted)
|
|
{
|
|
if (PvImageSignerName)
|
|
{
|
|
string = PhFormatString(L"<a>(Verified) %s</a>", PvImageSignerName->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW);
|
|
}
|
|
else
|
|
{
|
|
string = PhConcatStrings2(L"(Verified) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName));
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
}
|
|
else if (PvImageVerifyResult != VrUnknown)
|
|
{
|
|
string = PhConcatStrings2(L"(UNVERIFIED) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName));
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName));
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case NM_CLICK:
|
|
{
|
|
switch (header->idFrom)
|
|
{
|
|
case IDC_COMPANYNAME_LINK:
|
|
{
|
|
PvpVerifyFileWithAdditionalCatalog(PvFileName, PH_VERIFY_VIEW_PROPERTIES, hwndDlg, NULL);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID PvpProcessImports(
|
|
_In_ HWND ListViewHandle,
|
|
_In_ PPH_MAPPED_IMAGE_IMPORTS Imports,
|
|
_In_ BOOLEAN DelayImports
|
|
)
|
|
{
|
|
PH_MAPPED_IMAGE_IMPORT_DLL importDll;
|
|
PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
for (i = 0; i < Imports->NumberOfDlls; i++)
|
|
{
|
|
if (NT_SUCCESS(PhGetMappedImageImportDll(Imports, i, &importDll)))
|
|
{
|
|
for (j = 0; j < importDll.NumberOfEntries; j++)
|
|
{
|
|
if (NT_SUCCESS(PhGetMappedImageImportEntry(&importDll, j, &importEntry)))
|
|
{
|
|
INT lvItemIndex;
|
|
PPH_STRING name;
|
|
WCHAR number[PH_INT32_STR_LEN_1];
|
|
|
|
if (!DelayImports)
|
|
name = PhZeroExtendToUtf16(importDll.Name);
|
|
else
|
|
name = PhFormatString(L"%S (Delay)", importDll.Name);
|
|
|
|
lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, name->Buffer, NULL);
|
|
PhDereferenceObject(name);
|
|
|
|
if (importEntry.Name)
|
|
{
|
|
name = PhZeroExtendToUtf16(importEntry.Name);
|
|
PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer);
|
|
PhDereferenceObject(name);
|
|
|
|
PhPrintUInt32(number, importEntry.NameHint);
|
|
PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, number);
|
|
}
|
|
else
|
|
{
|
|
name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal);
|
|
PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer);
|
|
PhDereferenceObject(name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK PvpPeImportsDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
ULONG fallbackColumns[] = { 0, 1, 2 };
|
|
HWND lvHandle;
|
|
PH_MAPPED_IMAGE_IMPORTS imports;
|
|
|
|
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
PhSetListViewStyle(lvHandle, FALSE, TRUE);
|
|
PhSetControlTheme(lvHandle, L"explorer");
|
|
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 130, L"DLL");
|
|
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 210, L"Name");
|
|
PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Hint");
|
|
PhSetExtendedListView(lvHandle);
|
|
ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns);
|
|
|
|
if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage)))
|
|
{
|
|
PvpProcessImports(lvHandle, &imports, FALSE);
|
|
}
|
|
|
|
if (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage)))
|
|
{
|
|
PvpProcessImports(lvHandle, &imports, TRUE);
|
|
}
|
|
|
|
ExtendedListView_SortItems(lvHandle);
|
|
|
|
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
INT_PTR CALLBACK PvpPeExportsDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND lvHandle;
|
|
PH_MAPPED_IMAGE_EXPORTS exports;
|
|
PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry;
|
|
PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction;
|
|
ULONG i;
|
|
|
|
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
PhSetListViewStyle(lvHandle, FALSE, TRUE);
|
|
PhSetControlTheme(lvHandle, L"explorer");
|
|
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name");
|
|
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 50, L"Ordinal");
|
|
PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 120, L"VA");
|
|
PhSetExtendedListView(lvHandle);
|
|
|
|
if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage)))
|
|
{
|
|
for (i = 0; i < exports.NumberOfEntries; i++)
|
|
{
|
|
if (
|
|
NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)) &&
|
|
NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction))
|
|
)
|
|
{
|
|
INT lvItemIndex;
|
|
PPH_STRING name;
|
|
WCHAR number[PH_INT32_STR_LEN_1];
|
|
WCHAR pointer[PH_PTR_STR_LEN_1];
|
|
|
|
if (exportEntry.Name)
|
|
{
|
|
name = PhZeroExtendToUtf16(exportEntry.Name);
|
|
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL);
|
|
PhDereferenceObject(name);
|
|
}
|
|
else
|
|
{
|
|
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL);
|
|
}
|
|
|
|
PhPrintUInt32(number, exportEntry.Ordinal);
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number);
|
|
|
|
if (!exportFunction.ForwardedName)
|
|
{
|
|
if ((ULONG_PTR)exportFunction.Function >= (ULONG_PTR)PvMappedImage.ViewBase)
|
|
PhPrintPointer(pointer, PTR_SUB_OFFSET(exportFunction.Function, PvMappedImage.ViewBase));
|
|
else
|
|
PhPrintPointer(pointer, exportFunction.Function);
|
|
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer);
|
|
}
|
|
else
|
|
{
|
|
name = PhZeroExtendToUtf16(exportFunction.ForwardedName);
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer);
|
|
PhDereferenceObject(name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExtendedListView_SortItems(lvHandle);
|
|
|
|
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
INT_PTR CALLBACK PvpPeLoadConfigDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
PH_AUTO_POOL autoPool;
|
|
HWND lvHandle;
|
|
PIMAGE_LOAD_CONFIG_DIRECTORY32 config32;
|
|
PIMAGE_LOAD_CONFIG_DIRECTORY64 config64;
|
|
PPH_STRING string;
|
|
|
|
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
PhSetListViewStyle(lvHandle, FALSE, TRUE);
|
|
PhSetControlTheme(lvHandle, L"explorer");
|
|
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name");
|
|
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value");
|
|
|
|
#define ADD_VALUE(Name, Value) \
|
|
do { \
|
|
INT lvItemIndex; \
|
|
\
|
|
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \
|
|
} while (0)
|
|
|
|
#define ADD_VALUES(Config) \
|
|
do { \
|
|
{ \
|
|
LARGE_INTEGER time; \
|
|
SYSTEMTIME systemTime; \
|
|
\
|
|
RtlSecondsSince1970ToTime((Config)->TimeDateStamp, &time); \
|
|
PhLargeIntegerToLocalSystemTime(&systemTime, &time); \
|
|
\
|
|
string = PhFormatDateTime(&systemTime); \
|
|
ADD_VALUE(L"Time stamp", string->Buffer); \
|
|
PhDereferenceObject(string); \
|
|
} \
|
|
\
|
|
ADD_VALUE(L"Version", PhaFormatString(L"%u.%u", (Config)->MajorVersion, (Config)->MinorVersion)->Buffer); \
|
|
ADD_VALUE(L"Global flags to clear", PhaFormatString(L"0x%x", (Config)->GlobalFlagsClear)->Buffer); \
|
|
ADD_VALUE(L"Global flags to set", PhaFormatString(L"0x%x", (Config)->GlobalFlagsSet)->Buffer); \
|
|
ADD_VALUE(L"Critical section default timeout", PhaFormatUInt64((Config)->CriticalSectionDefaultTimeout, TRUE)->Buffer); \
|
|
ADD_VALUE(L"De-commit free block threshold", PhaFormatUInt64((Config)->DeCommitFreeBlockThreshold, TRUE)->Buffer); \
|
|
ADD_VALUE(L"De-commit total free threshold", PhaFormatUInt64((Config)->DeCommitTotalFreeThreshold, TRUE)->Buffer); \
|
|
ADD_VALUE(L"LOCK prefix table", PhaFormatString(L"0x%Ix", (Config)->LockPrefixTable)->Buffer); \
|
|
ADD_VALUE(L"Maximum allocation size", PhaFormatString(L"0x%Ix", (Config)->MaximumAllocationSize)->Buffer); \
|
|
ADD_VALUE(L"Virtual memory threshold", PhaFormatString(L"0x%Ix", (Config)->VirtualMemoryThreshold)->Buffer); \
|
|
ADD_VALUE(L"Process affinity mask", PhaFormatString(L"0x%Ix", (Config)->ProcessAffinityMask)->Buffer); \
|
|
ADD_VALUE(L"Process heap flags", PhaFormatString(L"0x%Ix", (Config)->ProcessHeapFlags)->Buffer); \
|
|
ADD_VALUE(L"CSD version", PhaFormatString(L"%u", (Config)->CSDVersion)->Buffer); \
|
|
ADD_VALUE(L"Edit list", PhaFormatString(L"0x%Ix", (Config)->EditList)->Buffer); \
|
|
ADD_VALUE(L"Security cookie", PhaFormatString(L"0x%Ix", (Config)->SecurityCookie)->Buffer); \
|
|
ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \
|
|
ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \
|
|
} while (0)
|
|
|
|
PhInitializeAutoPool(&autoPool);
|
|
|
|
if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
|
{
|
|
if (NT_SUCCESS(PhGetMappedImageLoadConfig32(&PvMappedImage, &config32)))
|
|
{
|
|
ADD_VALUES(config32);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NT_SUCCESS(PhGetMappedImageLoadConfig64(&PvMappedImage, &config64)))
|
|
{
|
|
ADD_VALUES(config64);
|
|
}
|
|
}
|
|
|
|
PhDeleteAutoPool(&autoPool);
|
|
|
|
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
INT_PTR CALLBACK PvpPeClrDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
PH_STRING_BUILDER stringBuilder;
|
|
PPH_STRING string;
|
|
PVOID metaData;
|
|
ULONG versionStringLength;
|
|
|
|
string = PhFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion,
|
|
PvImageCor20Header->MinorRuntimeVersion);
|
|
SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
|
|
PhInitializeStringBuilder(&stringBuilder, 256);
|
|
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY)
|
|
PhAppendStringBuilder2(&stringBuilder, L"IL only, ");
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED)
|
|
PhAppendStringBuilder2(&stringBuilder, L"32-bit only, ");
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED)
|
|
PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, ");
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY)
|
|
PhAppendStringBuilder2(&stringBuilder, L"IL library, ");
|
|
|
|
if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0)
|
|
{
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, ");
|
|
else
|
|
PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, ");
|
|
}
|
|
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, ");
|
|
if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA)
|
|
PhAppendStringBuilder2(&stringBuilder, L"Track debug data, ");
|
|
|
|
if (PhEndsWithString2(stringBuilder.String, L", ", FALSE))
|
|
PhRemoveEndStringBuilder(&stringBuilder, 2);
|
|
|
|
SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer);
|
|
PhDeleteStringBuilder(&stringBuilder);
|
|
|
|
metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL);
|
|
|
|
if (metaData)
|
|
{
|
|
__try
|
|
{
|
|
PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
metaData = NULL;
|
|
}
|
|
}
|
|
|
|
versionStringLength = 0;
|
|
|
|
if (metaData)
|
|
{
|
|
// Skip 12 bytes.
|
|
// First 4 bytes contains the length of the version string.
|
|
// The version string follows.
|
|
versionStringLength = *(PULONG)((PCHAR)metaData + 12);
|
|
|
|
// Make sure the length is valid.
|
|
if (versionStringLength >= 0x100)
|
|
versionStringLength = 0;
|
|
}
|
|
|
|
if (versionStringLength != 0)
|
|
{
|
|
string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength);
|
|
SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer);
|
|
PhDereferenceObject(string);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A");
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case PSN_QUERYINITIALFOCUS:
|
|
{
|
|
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION));
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|