From fdce5bda3202a863564a55ebec02b4d1a49ebb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=84=9C=EC=9E=AC=EC=99=84?= Date: Mon, 13 Nov 2023 19:37:59 +0900 Subject: [PATCH] =?UTF-8?q?#2=20:=20=EB=8C=80=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Protector/AntiDebug.cpp | 10 +- Protector/AntiLibrary.cpp | 184 ++- Protector/AntiProcess.cpp | 156 ++ Protector/AntiProcess.hpp | 256 ++++ .../{CodeIntegrity.cpp => CodeIntegrity.hpp} | 14 +- Protector/Core.cpp | 95 ++ Protector/Protector.vcxproj | 4 + Protector/Protector.vcxproj.filters | 14 +- Protector/Utils.cpp | 1295 +++++++++++++++++ Protector/Utils.hpp | 34 + 10 files changed, 2050 insertions(+), 12 deletions(-) create mode 100644 Protector/AntiProcess.hpp rename Protector/{CodeIntegrity.cpp => CodeIntegrity.hpp} (75%) create mode 100644 Protector/Utils.cpp create mode 100644 Protector/Utils.hpp diff --git a/Protector/AntiDebug.cpp b/Protector/AntiDebug.cpp index 00be212..eb40798 100644 --- a/Protector/AntiDebug.cpp +++ b/Protector/AntiDebug.cpp @@ -37,16 +37,16 @@ inline bool HypervisorDebugTriggered() return false; } -inline bool AntiDebugTriggered() +inline DWORD AntiDebugTriggered() { if (BasicDebugTriggered()) - return true; + return 1; if (HWBPDebugTriggered()) - return true; + return 2; if (HypervisorDebugTriggered()) - return true; + return 3; - return false; + return 0; } \ No newline at end of file diff --git a/Protector/AntiLibrary.cpp b/Protector/AntiLibrary.cpp index de7c5a8..87383e7 100644 --- a/Protector/AntiLibrary.cpp +++ b/Protector/AntiLibrary.cpp @@ -1,7 +1,151 @@ #include - +#include +#include +#include "Utils.hpp" #pragma comment(linker, "/INCLUDE:_tls_used") //Use TLS +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; + BOOLEAN ShutdownInProgress; + HANDLE ShutdownThreadId; +} PEB_LDR_DATA, * PPEB_LDR_DATA; +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, * PUNICODE_STRING; +typedef const UNICODE_STRING* PCUNICODE_STRING; +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + union + { + LIST_ENTRY InInitializationOrderLinks; + LIST_ENTRY InProgressLinks; + }; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + union + { + UCHAR FlagGroup[4]; + ULONG Flags; + struct + { + ULONG PackagedBinary : 1; + ULONG MarkedForRemoval : 1; + ULONG ImageDll : 1; + ULONG LoadNotificationsSent : 1; + ULONG TelemetryEntryProcessed : 1; + ULONG ProcessStaticImport : 1; + ULONG InLegacyLists : 1; + ULONG InIndexes : 1; + ULONG ShimDll : 1; + ULONG InExceptionTable : 1; + ULONG ReservedFlags1 : 2; + ULONG LoadInProgress : 1; + ULONG LoadConfigProcessed : 1; + ULONG EntryProcessed : 1; + ULONG ProtectDelayLoad : 1; + ULONG ReservedFlags3 : 2; + ULONG DontCallForThreads : 1; + ULONG ProcessAttachCalled : 1; + ULONG ProcessAttachFailed : 1; + ULONG CorDeferredValidate : 1; + ULONG CorImage : 1; + ULONG DontRelocate : 1; + ULONG CorILOnly : 1; + ULONG ReservedFlags5 : 3; + ULONG Redirected : 1; + ULONG ReservedFlags6 : 2; + ULONG CompatDatabaseProcessed : 1; + } s; + } u; + USHORT ObsoleteLoadCount; + USHORT TlsIndex; + LIST_ENTRY HashLinks; + ULONG TimeDateStamp; +} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; +typedef struct _PEB +{ + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + union + { + BOOLEAN BitField; + struct + { + BOOLEAN ImageUsesLargePages : 1; + BOOLEAN IsProtectedProcess : 1; + BOOLEAN IsImageDynamicallyRelocated : 1; + BOOLEAN SkipPatchingUser32Forwarders : 1; + BOOLEAN IsPackagedProcess : 1; + BOOLEAN IsAppContainer : 1; + BOOLEAN IsProtectedProcessLight : 1; + BOOLEAN IsLongPathAwareProcess : 1; + } s1; + } u1; + + HANDLE Mutant; + + PVOID ImageBaseAddress; + PPEB_LDR_DATA Ldr; + PVOID ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PRTL_CRITICAL_SECTION FastPebLock; + PVOID AtlThunkSListPtr; + PVOID IFEOKey; + union + { + ULONG CrossProcessFlags; + struct + { + ULONG ProcessInJob : 1; + ULONG ProcessInitializing : 1; + ULONG ProcessUsingVEH : 1; + ULONG ProcessUsingVCH : 1; + ULONG ProcessUsingFTH : 1; + ULONG ProcessPreviouslyThrottled : 1; + ULONG ProcessCurrentlyThrottled : 1; + ULONG ReservedBits0 : 25; + } s2; + } u2; + union + { + PVOID KernelCallbackTable; + PVOID UserSharedInfoPtr; + } u3; + ULONG SystemReserved[1]; + ULONG AtlThunkSListPtr32; + PVOID ApiSetMap; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[2]; + + PVOID ReadOnlySharedMemoryBase; + PVOID SharedData; // HotpatchInformation + PVOID* ReadOnlyStaticServerData; + + PVOID AnsiCodePageData; // PCPTABLEINFO + PVOID OemCodePageData; // PCPTABLEINFO + PVOID UnicodeCaseTableData; // PNLSTABLEINFO + + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; +} PEB, * PPEB; void NTAPI TlsCallback(PVOID DllHandle, DWORD dwReason, PVOID Reserved) { if (dwReason == DLL_PROCESS_ATTACH) @@ -9,10 +153,46 @@ void NTAPI TlsCallback(PVOID DllHandle, DWORD dwReason, PVOID Reserved) //Check if debugger is present if (IsDebuggerPresent()) ExitProcess(0); + printf("Checking library %p\n", DllHandle); } } #pragma data_seg(".CRT$XLX") PIMAGE_TLS_CALLBACK p_thread_callback[] = { TlsCallback, 0 }; #pragma data_seg() -//TODO: PEB LDR -> Sign \ No newline at end of file +__forceinline void CheckLibrary() +{ + //get peb +#ifdef _WIN64 + PPEB peb = (PPEB)__readgsqword(0x60); +#else + PPEB peb = (PPEB)__readfsdword(0x30); +#endif + //get ldr + PPEB_LDR_DATA ldr = peb->Ldr; + + //loop through modules + auto head = &ldr->InLoadOrderModuleList; + for (auto curr = head->Flink; curr != head; curr = curr->Flink) + { + //get module + auto mod = CONTAINING_RECORD(curr, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + + //get module name + auto path = malloc(mod->FullDllName.Length + sizeof(wchar_t)); + memcpy(path, mod->FullDllName.Buffer, mod->FullDllName.Length); + ((wchar_t*)path)[mod->FullDllName.Length / sizeof(wchar_t)] = 0; + + std::wstring catalogFile; + std::string signType; + std::list SignChain; + if (!CheckFileDigitalSignature((LPCWSTR)path, NULL, catalogFile, signType, SignChain)) + { + printf("Failed to check digital signature of %ws\n", path); + continue; + } + printf("file: %ws\n", path); + PrintSignatureInfo(signType, catalogFile, SignChain); + } + system("pause"); +} \ No newline at end of file diff --git a/Protector/AntiProcess.cpp b/Protector/AntiProcess.cpp index e69de29..ef9d513 100644 --- a/Protector/AntiProcess.cpp +++ b/Protector/AntiProcess.cpp @@ -0,0 +1,156 @@ +#include "AntiProcess.hpp" +#include +#include +#include +#include "Utils.hpp" +typedef NTSTATUS(NTAPI* t_NtQuerySystemInformation)(_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _Out_opt_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength); +typedef NTSTATUS(NTAPI* t_NtQueryObject)(_In_opt_ HANDLE Handle, _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, _Out_opt_ PVOID ObjectInformation, _In_ ULONG ObjectInformationLength, _Out_opt_ PULONG ReturnLength); +typedef NTSTATUS(NTAPI* t_NtQueryInformationProcess)(_In_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass, _Out_ PVOID ProcessInformation, _In_ ULONG ProcessInformationLength, _Out_opt_ PULONG ReturnLength); +#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 + +t_NtQuerySystemInformation NtQuerySystemInformation = (t_NtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation"); +t_NtQueryObject NtQueryObject = (t_NtQueryObject)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryObject"); + +const wchar_t* BlacklistedWindowName[] = { + L"OllyDbg", + L"IDA Pro", + L"Cheat Engine", + L"Process Hacker", + L"Process Explorer", + L"Process Monitor" +}; +const wchar_t* BlacklistedProcessName[] = { + L"ollydbg.exe", + L"idaq.exe", + L"idaq64.exe", + L"ida.exe", + L"ida64.exe", + L"Cheat Engine.exe", + L"cheatengine-x86_64.exe", + L"cheatengine-i386.exe", + L"Process Hacker.exe", + L"ProcessHacker.exe", + L"procdump.exe", + L"procmon.exe" +}; + +BOOL EnumWindowsCallback(HWND hWnd, LPARAM lParam) +{ + wchar_t WindowName[256] = { 0 }; + GetWindowTextW(hWnd, WindowName, 256); + for (int i = 0; i < sizeof(BlacklistedWindowName) / sizeof(wchar_t*); i++) + { + if (wcsstr(WindowName, BlacklistedWindowName[i])) + { + GetWindowThreadProcessId(hWnd, (LPDWORD)lParam); + return FALSE; + } + } + return TRUE; +} +__forceinline void CheckProcessHasMyHandle(void) +{ + ULONG returnLength = 0; + NTSTATUS status = NtQuerySystemInformation(SystemExtendedHandleInformation, nullptr, 0, &returnLength); + if (status != STATUS_INFO_LENGTH_MISMATCH) + return; + + ULONG bufferSize = returnLength; + PSYSTEM_HANDLE_INFORMATION_EX handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)malloc(bufferSize); + if (!handleInfo) + return; + + status = NtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, bufferSize, &returnLength); + if (status) + { + free(handleInfo); + return; + } + + //loop handles + for (int i = 0; i < handleInfo->NumberOfHandles; i++) + { + const auto& handle = handleInfo->Handles[i]; + + if (handle.ObjectTypeIndex == 7 && handle.UniqueProcessId != GetCurrentProcessId()) //Process + { + HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId); + if (!hProcess) + continue; + HANDLE hDupHandle = nullptr; + DuplicateHandle(hProcess, (HANDLE)handle.HandleValue, GetCurrentProcess(), &hDupHandle, 0, FALSE, 0); + if (!hDupHandle) + { + CloseHandle(hProcess); + continue; + } + + //check handle access has PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION + if ((handle.GrantedAccess & PROCESS_QUERY_INFORMATION) == 0 && (handle.GrantedAccess & PROCESS_QUERY_LIMITED_INFORMATION) == 0) + { + CloseHandle(hProcess); + CloseHandle(hDupHandle); + continue; + } + + if (GetProcessId(hDupHandle) != GetCurrentProcessId()) + { + CloseHandle(hProcess); + CloseHandle(hDupHandle); + continue; + } + // 尡. + + wchar_t path[MAX_PATH] = { 0 }; + GetModuleFileNameExW(hProcess, nullptr, path, MAX_PATH); + + std::string signType; + std::wstring catalogFile; + std::list SignChain; + if (!CheckFileDigitalSignature(path, nullptr, catalogFile, signType, SignChain)) + { + //TODO: Send log to server. + + } + + CloseHandle(hProcess); + CloseHandle(hDupHandle); + } + } +} +__forceinline void CheckProcess(void) +{ + CheckProcessHasMyHandle(); + DWORD detectedProcessId = 0; + EnumWindows(EnumWindowsCallback, (LPARAM)&detectedProcessId); + + if (detectedProcessId) + { + //TODO: Send log to server. + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, detectedProcessId); + if (hProcess) + { + TerminateProcess(hProcess, 0); + CloseHandle(hProcess); + } + } + PROCESSENTRY32 pe32{}; + pe32.dwSize = sizeof(PROCESSENTRY32); + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) + return; + + BOOL bRet = Process32First(hSnapshot, &pe32); + while (bRet) + { + for (int i = 0; i < sizeof(BlacklistedProcessName) / sizeof(wchar_t*); i++) + { + if (wcsstr(pe32.szExeFile, BlacklistedProcessName[i])) + { + //TODO: Send log to server. + } + } + bRet = Process32Next(hSnapshot, &pe32); + } + CloseHandle(hSnapshot); +} \ No newline at end of file diff --git a/Protector/AntiProcess.hpp b/Protector/AntiProcess.hpp new file mode 100644 index 0000000..7f10da1 --- /dev/null +++ b/Protector/AntiProcess.hpp @@ -0,0 +1,256 @@ +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX +{ + PVOID Object; + ULONG_PTR UniqueProcessId; + ULONG_PTR HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX; +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION + SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION + SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION + SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION + SystemPathInformation, // not implemented + SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION + SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION + SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION + SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION + SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 + SystemModuleInformation, // q: RTL_PROCESS_MODULES + SystemLocksInformation, // q: RTL_PROCESS_LOCKS + SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES + SystemPagedPoolInformation, // not implemented + SystemNonPagedPoolInformation, // not implemented + SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION + SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION + SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION + SystemVdmInstemulInformation, // q + SystemVdmBopInformation, // not implemented // 20 + SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache) + SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION + SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION + SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege) + SystemFullMemoryInformation, // not implemented + SystemLoadGdiDriverInformation, // s (kernel-mode only) + SystemUnloadGdiDriverInformation, // s (kernel-mode only) + SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) + SystemSummaryMemoryInformation, // not implemented + SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 + SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) + SystemObsolete0, // not implemented + SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION + SystemCrashDumpStateInformation, // s (requires SeDebugPrivilege) + SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION + SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION + SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege) + SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only + SystemPrioritySeperation, // s (requires SeTcbPrivilege) + SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40 + SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) + SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION + SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION + SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION + SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION + SystemTimeSlipNotification, // s (requires SeSystemtimePrivilege) + SystemSessionCreate, // not implemented + SystemSessionDetach, // not implemented + SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) + SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 + SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) + SystemVerifierThunkExtend, // s (kernel-mode only) + SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION + SystemLoadGdiDriverInSystemSpace, // s (kernel-mode only) (same as SystemLoadGdiDriverInformation) + SystemNumaProcessorMap, // q + SystemPrefetcherInformation, // q: PREFETCHER_INFORMATION; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation + SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemRecommendedSharedDataAlignment, // q + SystemComPlusPackage, // q; s + SystemNumaAvailableMemory, // 60 + SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION + SystemEmulationBasicInformation, // q + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX + SystemLostDelayedWriteInformation, // q: ULONG + SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION + SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION + SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION + SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION + SystemObjectSecurityMode, // q: ULONG // 70 + SystemWatchdogTimerHandler, // s (kernel-mode only) + SystemWatchdogTimerInformation, // q (kernel-mode only); s (kernel-mode only) + SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION + SystemWow64SharedInformationObsolete, // not implemented + SystemRegisterFirmwareTableInformationHandler, // s (kernel-mode only) + SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION + SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX + SystemVerifierTriageInformation, // not implemented + SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation + SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80 + SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation) + SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) + SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] + SystemVerifierCancellationInformation, // not implemented // name:wow64:whNT32QuerySystemVerifierCancellationInformation + SystemProcessorPowerInformationEx, // not implemented + SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation + SystemSpecialPoolInformation, // q; s (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0 + SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION + SystemErrorPortInformation, // s (requires SeTcbPrivilege) + SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90 + SystemHypervisorInformation, // q; s (kernel-mode only) + SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX + SystemTimeZoneInformation, // s (requires SeTimeZonePrivilege) + SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege) + SystemCoverageInformation, // q; s // name:wow64:whNT32QuerySystemCoverageInformation; ExpCovQueryInformation + SystemPrefetchPatchInformation, // not implemented + SystemVerifierFaultsInformation, // s (requires SeDebugPrivilege) + SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION + SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION + SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100 + SystemNumaProximityNodeInformation, // q + SystemDynamicTimeZoneInformation, // q; s (requires SeTimeZonePrivilege) + SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation + SystemProcessorMicrocodeUpdateInformation, // s + SystemProcessorBrandString, // q // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23 + SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation + SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship + SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] + SystemStoreInformation, // q; s // SmQueryStoreInformation + SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 + SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) + SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION + SystemCpuQuotaInformation, // q; s // PsQueryCpuQuotaInformation + SystemNativeBasicInformation, // not implemented + SystemSpare1, // not implemented + SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION + SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation + SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION + SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) + SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 + SystemNodeDistanceInformation, // q + SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 + SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation + SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 + SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 + SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) + SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION + SystemBadPageInformation, + SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA + SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 + SystemEntropyInterruptTimingCallback, + SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION + SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION + SystemThrottleNotificationInformation, + SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION + SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION + SystemDeviceDataEnumerationInformation, + SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION + SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION + SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140 + SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // since WINBLUE + SystemSpare0, + SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION + SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX + SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION + SystemEntropyInterruptTimingRawInformation, + SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION + SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) + SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX + SystemBootMetadataInformation, // 150 + SystemSoftRebootInformation, + SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION + SystemOfflineDumpConfigInformation, + SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION + SystemRegistryReconciliationInformation, + SystemEdidInformation, + SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD + SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION + SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION + SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160 + SystemVmGenerationCountInformation, + SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION + SystemKernelDebuggerFlags, + SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION + SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION + SystemHardwareSecurityTestInterfaceResultsInformation, + SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION + SystemAllowedCpuSetsInformation, + SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) + SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 + SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION + SystemCodeIntegrityPolicyFullInformation, + SystemAffinitizedInterruptProcessorInformation, + SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION + SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2 + SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION + SystemWin32WerStartCallout, + SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION + SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE + SystemInterruptSteeringInformation, // 180 + SystemSupportedProcessorArchitectures, + SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION + SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION + SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 + SystemControlFlowTransition, + SystemKernelDebuggingAllowed, + SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE + SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS + SystemCodeIntegrityPoliciesFullInformation, + SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 + SystemIntegrityQuotaInformation, + SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION + SystemProcessorIdleMaskInformation, // since REDSTONE3 + SystemSecureDumpEncryptionInformation, + SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION + SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION + SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 + SystemFirmwareBootPerformanceInformation, + SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION + SystemFirmwarePartitionInformation, // 200 + SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. + SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION + SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION + SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 + SystemCodeIntegrityUnlockModeInformation, + SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION + SystemFlags2Information, + MaxSystemInfoClass +} SYSTEM_INFORMATION_CLASS; + +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation, // OBJECT_BASIC_INFORMATION + ObjectNameInformation, // OBJECT_NAME_INFORMATION + ObjectTypeInformation, // OBJECT_TYPE_INFORMATION + ObjectTypesInformation, // OBJECT_TYPES_INFORMATION + ObjectHandleFlagInformation, // OBJECT_HANDLE_FLAG_INFORMATION + ObjectSessionInformation, + ObjectSessionObjectInformation, + MaxObjectInfoClass +} OBJECT_INFORMATION_CLASS; +typedef struct _OBJECT_BASIC_INFORMATION +{ + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[3]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; +} OBJECT_BASIC_INFORMATION, * POBJECT_BASIC_INFORMATION; \ No newline at end of file diff --git a/Protector/CodeIntegrity.cpp b/Protector/CodeIntegrity.hpp similarity index 75% rename from Protector/CodeIntegrity.cpp rename to Protector/CodeIntegrity.hpp index 6f42b75..69ef9f4 100644 --- a/Protector/CodeIntegrity.cpp +++ b/Protector/CodeIntegrity.hpp @@ -33,13 +33,23 @@ class CodeIntegrityVerifier DWORD_PTR m_moduleSize; DWORD m_sectionHash; public: - CodeIntegrityVerifier(DWORD_PTR moduleBase, DWORD_PTR moduleSize) + CodeIntegrityVerifier(DWORD_PTR moduleBase, DWORD_PTR moduleSize = 0) { m_moduleBase = moduleBase; m_moduleSize = moduleSize; + if (!m_moduleSize) + { + IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)m_moduleBase; + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) + return; + IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS*)(m_moduleBase + pDosHeader->e_lfanew); + if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) + return; + m_moduleSize = pNtHeaders->OptionalHeader.SizeOfImage; + } GetSectionHash(moduleBase, ".text", &m_sectionHash); } - bool Verify() + __forceinline bool Verify() { DWORD hash; if (!GetSectionHash(m_moduleBase, ".text", &hash)) diff --git a/Protector/Core.cpp b/Protector/Core.cpp index e69de29..62a826a 100644 --- a/Protector/Core.cpp +++ b/Protector/Core.cpp @@ -0,0 +1,95 @@ +#include "AntiProcess.hpp" +#include "CodeIntegrity.hpp" +inline bool AntiDebugTriggered(); +__forceinline void CheckLibrary(); +__forceinline void CheckProcess(void); + +DWORD64 lastDebugCheckTime = 0; +DWORD64 lastLibraryCheckTime = 0; +DWORD64 lastProcessCheckTime = 0; +DWORD64 lastCodeIntegrityCheckTime = 0; + +DWORD WINAPI AntiDebugThread(LPVOID lpParam) +{ + while (true) + { + Sleep(5000); + if (DWORD triggered = AntiDebugTriggered()) + { + //TODO: Send log to server. + } + lastDebugCheckTime = GetTickCount64(); + } +} + +DWORD WINAPI AntiLibraryThread(LPVOID lpParam) +{ + while (true) + { + Sleep(5000); + CheckLibrary(); + lastLibraryCheckTime = GetTickCount64(); + } +} + +DWORD WINAPI AntiProcessThread(LPVOID lpParam) +{ + while (true) + { + Sleep(5000); + CheckProcess(); + lastProcessCheckTime = GetTickCount64(); + } +} + +DWORD WINAPI AntiCodeIntegrityThread(LPVOID lpParam) +{ + CodeIntegrityVerifier* verifier = new CodeIntegrityVerifier((DWORD_PTR)GetModuleHandleW(nullptr)); + while (true) + { + Sleep(5000); + if (!verifier->Verify()) + { + //TODO: Send log to server. + } + lastCodeIntegrityCheckTime = GetTickCount64(); + } +} + +__forceinline void CheckThreadWorking(void) +{ + DWORD64 currentTime = GetTickCount64(); + if (currentTime - lastDebugCheckTime > 10000 && lastDebugCheckTime != 0) + { + __debugbreak(); //force make exception to crash + } + if (currentTime - lastLibraryCheckTime > 10000 && lastLibraryCheckTime != 0) + { + __debugbreak(); //force make exception to crash + } + if (currentTime - lastProcessCheckTime > 10000 && lastProcessCheckTime != 0) + { + __debugbreak(); //force make exception to crash + } + if (currentTime - lastCodeIntegrityCheckTime > 10000 && lastCodeIntegrityCheckTime != 0) + { + __debugbreak(); //force make exception to crash + } +} + +int main(void) +{ + //Initialize thread + CreateThread(nullptr, 0, AntiDebugThread, nullptr, 0, nullptr); + CreateThread(nullptr, 0, AntiLibraryThread, nullptr, 0, nullptr); + CreateThread(nullptr, 0, AntiProcessThread, nullptr, 0, nullptr); + CreateThread(nullptr, 0, AntiCodeIntegrityThread, nullptr, 0, nullptr); + + //Main loop + while (true) + { + CheckThreadWorking(); + Sleep(1000); + } + +} \ No newline at end of file diff --git a/Protector/Protector.vcxproj b/Protector/Protector.vcxproj index 923fb77..0457680 100644 --- a/Protector/Protector.vcxproj +++ b/Protector/Protector.vcxproj @@ -132,6 +132,10 @@ + + + + diff --git a/Protector/Protector.vcxproj.filters b/Protector/Protector.vcxproj.filters index b22b9e2..eac23f2 100644 --- a/Protector/Protector.vcxproj.filters +++ b/Protector/Protector.vcxproj.filters @@ -15,9 +15,6 @@ - - 소스 파일 - 소스 파일 @@ -30,5 +27,16 @@ 소스 파일 + + 소스 파일 + + + 소스 파일 + + + + + 헤더 파일 + \ No newline at end of file diff --git a/Protector/Utils.cpp b/Protector/Utils.cpp new file mode 100644 index 0000000..4453825 --- /dev/null +++ b/Protector/Utils.cpp @@ -0,0 +1,1295 @@ +/** + * COPYRIGHT NOTICE & DESCRIPTION + * + * Source: PESignAnalyzer.cpp + * Author: leeqwind + * E-mail: leeqw.live@outlook.com + * Notice: This program can retrieve signature information from PE + * files which signed by a/some certificate(s) on Windows. + * Supporting multi-signed information and certificates chain. + */ +#include "Utils.hpp" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; + +#define MY_ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) +#ifndef szOID_RFC3161_counterSign +#define szOID_RFC3161_counterSign "1.3.6.1.4.1.311.3.3.1" +#endif +#ifndef szOID_NESTED_SIGNATURE +#define szOID_NESTED_SIGNATURE "1.3.6.1.4.1.311.2.4.1" +#endif + +#pragma comment(lib, "Crypt32.lib") +#pragma comment(lib, "Wintrust.lib") + + + +typedef struct _SIGNDATA_HANDLE { + DWORD dwObjSize; + PCMSG_SIGNER_INFO pSignerInfo; + HCERTSTORE hCertStoreHandle; +} SIGNDATA_HANDLE, * PSIGNDATA_HANDLE; + +BOOL MyCryptMsgGetParam( + HCRYPTMSG hCryptMsg, + DWORD dwParamType, + DWORD dwIndex, + PVOID* pParam, + DWORD* dwOutSize +) { + BOOL bReturn = FALSE; + DWORD dwSize = 0; + if (!pParam) + { + return FALSE; + } + // Get size + bReturn = CryptMsgGetParam(hCryptMsg, dwParamType, dwIndex, NULL, &dwSize); + if (!bReturn) + { + return FALSE; + } + // Alloc memory via size + *pParam = (PVOID)LocalAlloc(LPTR, dwSize); + if (!*pParam) + { + return FALSE; + } + // Get data to alloced memory + bReturn = CryptMsgGetParam(hCryptMsg, dwParamType, dwIndex, *pParam, &dwSize); + if (!bReturn) + { + return FALSE; + } + if (dwOutSize) + { + *dwOutSize = dwSize; + } + return TRUE; +} + +CONST UCHAR SG_ProtoCoded[] = { + 0x30, 0x82, +}; + +CONST UCHAR SG_SignedData[] = { + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, +}; + +#define XCH_WORD_LITEND(num) \ + (WORD)(((((WORD)num) & 0xFF00) >> 8) | ((((WORD)num) & 0x00FF) << 8)) + +#define _8BYTE_ALIGN(offset, base) \ + (((offset + base + 7) & 0xFFFFFFF8L) - (base & 0xFFFFFFF8L)) + +// https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa374890(v=vs.85).aspx +BOOL GetNestedSignerInfo( + CONST PSIGNDATA_HANDLE AuthSignData, + std::list& NestedChain +) { + BOOL bSucceed = FALSE; + BOOL bReturn = FALSE; + HCRYPTMSG hNestedMsg = NULL; + PBYTE pbCurrData = NULL; + PBYTE pbNextData = NULL; + DWORD n = 0x00; + DWORD cbCurrData = 0x00; + + if (!AuthSignData->pSignerInfo) + { + return FALSE; + } + __try + { + // Traverse and look for a nested signature. + for (n = 0; n < AuthSignData->pSignerInfo->UnauthAttrs.cAttr; n++) + { + if (!lstrcmpA(AuthSignData->pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, + szOID_NESTED_SIGNATURE)) + { + break; + } + } + // Cannot find a nested signature attribute. + if (n >= AuthSignData->pSignerInfo->UnauthAttrs.cAttr) + { + bSucceed = FALSE; + __leave; + } + pbCurrData = AuthSignData->pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData; + cbCurrData = AuthSignData->pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData; + // Multiple nested signatures just add one attr in UnauthAttrs + // list of the main signature pointing to the first nested si- + // gnature. Every nested signature exists side by side in an 8 + // bytes aligned way. According to the size of major signature + // parse the nested signatures one by one. + while (pbCurrData > (BYTE*)AuthSignData->pSignerInfo && + pbCurrData < (BYTE*)AuthSignData->pSignerInfo + AuthSignData->dwObjSize) + { + SIGNDATA_HANDLE NestedHandle = { 0 }; + // NOTE: The size in 30 82 xx doesnt contain its own size. + // HEAD: + // 0000: 30 82 04 df ; SEQUENCE (4df Bytes) + // 0004: 06 09 ; OBJECT_ID(9 Bytes) + // 0006: | 2a 86 48 86 f7 0d 01 07 02 + // | ; 1.2.840.113549.1.7.2 PKCS 7 SignedData + if (memcmp(pbCurrData + 0, SG_ProtoCoded, sizeof(SG_ProtoCoded)) || + memcmp(pbCurrData + 6, SG_SignedData, sizeof(SG_SignedData))) + { + break; + } + + if (hNestedMsg) { + CryptMsgClose(hNestedMsg); + hNestedMsg = NULL; + } + hNestedMsg = CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + 0, + 0, + NULL, + 0 + ); + if (!hNestedMsg) // Fatal Error + { + bSucceed = FALSE; + __leave; + } + + // Big Endian -> Little Endian + cbCurrData = XCH_WORD_LITEND(*(WORD*)(pbCurrData + 2)) + 4; + pbNextData = pbCurrData; + pbNextData += _8BYTE_ALIGN(cbCurrData, (ULONG_PTR)pbCurrData); + bReturn = CryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, TRUE); + pbCurrData = pbNextData; + if (!bReturn) + { + continue; + } + bReturn = MyCryptMsgGetParam(hNestedMsg, CMSG_SIGNER_INFO_PARAM, + 0, + (PVOID*)&NestedHandle.pSignerInfo, + &NestedHandle.dwObjSize + ); + if (!bReturn) + { + continue; + } + NestedHandle.hCertStoreHandle = CertOpenStore(CERT_STORE_PROV_MSG, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + 0, + 0, + hNestedMsg + ); + bSucceed = TRUE; + NestedChain.push_back(NestedHandle); + } + } + __finally + { + if (hNestedMsg) CryptMsgClose(hNestedMsg); + } + return bSucceed; +} + +BOOL GetAuthedAttribute( + PCMSG_SIGNER_INFO pSignerInfo +) { + BOOL bSucceed = FALSE; + DWORD dwObjSize = 0x00; + DWORD n = 0x00; + + __try + { + for (n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) + { + if (!lstrcmpA(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign)) + { + bSucceed = TRUE; + break; + } + } + } + __finally + { + } + return bSucceed; +} + +// http://support.microsoft.com/kb/323809 +BOOL GetCounterSignerInfo( + PCMSG_SIGNER_INFO pSignerInfo, + PCMSG_SIGNER_INFO* pTargetSigner +) { + BOOL bSucceed = FALSE; + BOOL bReturn = FALSE; + DWORD dwObjSize = 0x00; + DWORD n = 0x00; + + if (!pSignerInfo || !pTargetSigner) + { + return FALSE; + } + __try + { + *pTargetSigner = NULL; + for (n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++) + { + if (!lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign)) + { + break; + } + } + if (n >= pSignerInfo->UnauthAttrs.cAttr) + { + bSucceed = FALSE; + __leave; + } + bReturn = CryptDecodeObject(MY_ENCODING, + PKCS7_SIGNER_INFO, + pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, + pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, + 0, + NULL, + &dwObjSize + ); + if (!bReturn) + { + bSucceed = FALSE; + __leave; + } + *pTargetSigner = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwObjSize); + if (!*pTargetSigner) + { + bSucceed = FALSE; + __leave; + } + bReturn = CryptDecodeObject(MY_ENCODING, + PKCS7_SIGNER_INFO, + pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, + pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, + 0, + (PVOID)*pTargetSigner, + &dwObjSize + ); + if (!bReturn) + { + bSucceed = FALSE; + __leave; + } + bSucceed = TRUE; + } + __finally + { + } + return bSucceed; +} + +std::string TimeToString( + FILETIME* pftIn, + SYSTEMTIME* pstIn = NULL +) { + SYSTEMTIME st = { 0 }; + CHAR szBuffer[256] = { 0 }; + + if (!pstIn) + { + if (!pftIn) + { + return std::string(""); + } + FileTimeToSystemTime(pftIn, &st); + pstIn = &st; + } + _snprintf_s(szBuffer, 256, "%04d/%02d/%02d %02d:%02d:%02d", + pstIn->wYear, + pstIn->wMonth, + pstIn->wDay, + pstIn->wHour, + pstIn->wMinute, + pstIn->wSecond + ); + return std::string(szBuffer); +} + +BOOL GetCounterSignerData( + CONST PCMSG_SIGNER_INFO SignerInfo, + SIGN_COUNTER_SIGN& CounterSign +) { + BOOL bReturn = FALSE; + DWORD n = 0x00; + DWORD dwData = 0x00; + FILETIME lft, ft; + SYSTEMTIME st; + + // Find szOID_RSA_signingTime OID. + for (n = 0; n < SignerInfo->AuthAttrs.cAttr; n++) + { + if (!lstrcmpA(SignerInfo->AuthAttrs.rgAttr[n].pszObjId, szOID_RSA_signingTime)) + { + break; + } + } + if (n >= SignerInfo->AuthAttrs.cAttr) + { + return FALSE; + } + // Decode and get FILETIME structure. + dwData = sizeof(ft); + bReturn = CryptDecodeObject(MY_ENCODING, + szOID_RSA_signingTime, + SignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, + SignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, + 0, + (PVOID)&ft, + &dwData + ); + if (!bReturn) + { + return FALSE; + } + // Convert. + FileTimeToLocalFileTime(&ft, &lft); + FileTimeToSystemTime(&lft, &st); + CounterSign.TimeStamp = TimeToString(NULL, &st); + return TRUE; +} + +BOOL SafeToReadNBytes( + DWORD dwSize, + DWORD dwStart, + DWORD dwRequestSize +) { + return dwSize - dwStart >= dwRequestSize; +} + +void ParseDERType( + BYTE bIn, + INT& iType, + INT& iClass +) { + iType = bIn & 0x3F; + iClass = bIn >> 6; +} + +DWORD ReadNumberFromNBytes( + PBYTE pbSignature, + DWORD dwStart, + DWORD dwRequestSize +) { + DWORD dwNumber = 0; + for (DWORD i = 0; i < dwRequestSize; i++) + { + dwNumber = dwNumber * 0x100 + pbSignature[dwStart + i]; + } + return dwNumber; +} + +BOOL ParseDERSize( + PBYTE pbSignature, + DWORD dwSize, + DWORD& dwSizefound, + DWORD& dwBytesParsed +) { + if (pbSignature[0] > 0x80 && + !SafeToReadNBytes(dwSize, 1, pbSignature[0] - 0x80)) + { + return FALSE; + } + if (pbSignature[0] <= 0x80) + { + dwSizefound = pbSignature[0]; + dwBytesParsed = 1; + } + else + { + dwSizefound = ReadNumberFromNBytes(pbSignature, 1, pbSignature[0] - 0x80); + dwBytesParsed = 1 + pbSignature[0] - 0x80; + } + return TRUE; +} + +BOOL ParseDERFindType( + INT iTypeSearch, + PBYTE pbSignature, + DWORD dwSize, + DWORD& dwPositionFound, + DWORD& dwLengthFound, + DWORD& dwPositionError, + INT& iTypeError +) { + DWORD dwPosition = 0; + DWORD dwSizeFound = 0; + DWORD dwBytesParsed = 0; + INT iType = 0; + INT iClass = 0; + + iTypeError = -1; + dwPositionFound = 0; + dwLengthFound = 0; + dwPositionError = 0; + if (NULL == pbSignature) + { + iTypeError = -1; + return FALSE; + } + while (dwSize > dwPosition) + { + if (!SafeToReadNBytes(dwSize, dwPosition, 2)) + { + dwPositionError = dwPosition; + iTypeError = -2; + return FALSE; + } + ParseDERType(pbSignature[dwPosition], iType, iClass); + switch (iType) + { + case 0x05: // NULL + dwPosition++; + if (pbSignature[dwPosition] != 0x00) + { + dwPositionError = dwPosition; + iTypeError = -4; + return FALSE; + } + dwPosition++; + break; + + case 0x06: // OID + dwPosition++; + if (!SafeToReadNBytes(dwSize - dwPosition, 1, pbSignature[dwPosition])) + { + dwPositionError = dwPosition; + iTypeError = -5; + return FALSE; + } + dwPosition += 1 + pbSignature[dwPosition]; + break; + + case 0x00: // ? + case 0x01: // boolean + case 0x02: // integer + case 0x03: // bit std::string + case 0x04: // octec std::string + case 0x0A: // enumerated + case 0x0C: // UTF8string + case 0x13: // printable std::string + case 0x14: // T61 std::string + case 0x16: // IA5String + case 0x17: // UTC time + case 0x18: // Generalized time + case 0x1E: // BMPstring + dwPosition++; + if (!ParseDERSize(pbSignature + dwPosition, dwSize - dwPosition, + dwSizeFound, + dwBytesParsed)) + { + dwPositionError = dwPosition; + iTypeError = -7; + return FALSE; + } + dwPosition += dwBytesParsed; + if (!SafeToReadNBytes(dwSize - dwPosition, 0, dwSizeFound)) + { + dwPositionError = dwPosition; + iTypeError = -8; + return FALSE; + } + if (iTypeSearch == iType) + { + dwPositionFound = dwPosition; + dwLengthFound = dwSizeFound; + return TRUE; + } + dwPosition += dwSizeFound; + break; + + case 0x20: // context specific + case 0x21: // context specific + case 0x23: // context specific + case 0x24: // context specific + case 0x30: // sequence + case 0x31: // set + dwPosition++; + if (!ParseDERSize(pbSignature + dwPosition, dwSize - dwPosition, + dwSizeFound, + dwBytesParsed)) + { + dwPositionError = dwPosition; + iTypeError = -9; + return FALSE; + } + dwPosition += dwBytesParsed; + break; + + case 0x22: // ? + dwPosition += 2; + break; + + default: + dwPositionError = dwPosition; + iTypeError = iType; + return FALSE; + } + } + return FALSE; +} + +BOOL GetGeneralizedTimeStamp( + PCMSG_SIGNER_INFO pSignerInfo, + std::string& TimeStamp +) { + BOOL bSucceed = FALSE; + BOOL bReturn = FALSE; + DWORD dwPositionFound = 0; + DWORD dwLengthFound = 0; + DWORD dwPositionError = 0; + DWORD n = 0; + INT iTypeError = 0; + SYSTEMTIME sst, lst; + FILETIME fft, lft; + + ULONG wYear = 0; + ULONG wMonth = 0; + ULONG wDay = 0; + ULONG wHour = 0; + ULONG wMinute = 0; + ULONG wSecond = 0; + ULONG wMilliseconds = 0; + + for (n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++) + { + if (!lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RFC3161_counterSign)) + { + break; + } + } + if (n >= pSignerInfo->UnauthAttrs.cAttr) + { + return FALSE; + } + bReturn = ParseDERFindType(0x04, + pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, + pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, + dwPositionFound, + dwLengthFound, + dwPositionError, + iTypeError + ); + if (!bReturn) + { + return FALSE; + } + PBYTE pbOctetString = &pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData[dwPositionFound]; + bReturn = ParseDERFindType(0x18, pbOctetString, dwLengthFound, + dwPositionFound, + dwLengthFound, + dwPositionError, + iTypeError + ); + if (!bReturn) + { + return FALSE; + } + CHAR szBuffer[256]; + strncpy_s(szBuffer, (CHAR*)&(pbOctetString[dwPositionFound]), dwLengthFound); + szBuffer[dwLengthFound] = 0; + _snscanf_s(szBuffer, 256, "%04d%02d%02d%02d%02d%02d.%03dZ", + &wYear, + &wMonth, + &wDay, + &wHour, + &wMinute, + &wSecond, + &wMilliseconds + ); + sst.wYear = (WORD)wYear; + sst.wMonth = (WORD)wMonth; + sst.wDay = (WORD)wDay; + sst.wHour = (WORD)wHour; + sst.wMinute = (WORD)wMinute; + sst.wSecond = (WORD)wSecond; + sst.wMilliseconds = (WORD)wMilliseconds; + SystemTimeToFileTime(&sst, &fft); + FileTimeToLocalFileTime(&fft, &lft); + FileTimeToSystemTime(&lft, &lst); + TimeStamp = TimeToString(NULL, &lst); + return TRUE; +} + +INT IsCharacterToStrip( + INT Character +) { + return 0 == Character || '\t' == Character || '\n' == Character || '\r' == Character; +} + +VOID StripString( + std::string& StrArg +) { + StrArg.erase(remove_if(StrArg.begin(), StrArg.end(), IsCharacterToStrip), StrArg.end()); +} + +BOOL GetStringFromCertContext( + PCCERT_CONTEXT pCertContext, + DWORD Type, + DWORD Flag, + std::string& String +) { + DWORD dwData = 0x00; + LPSTR pszTempName = NULL; + + dwData = CertGetNameStringA(pCertContext, Type, Flag, NULL, NULL, 0); + if (!dwData) + { + CertFreeCertificateContext(pCertContext); + return FALSE; + } + pszTempName = (LPSTR)LocalAlloc(LPTR, dwData * sizeof(CHAR)); + if (!pszTempName) + { + CertFreeCertificateContext(pCertContext); + return FALSE; + } + dwData = CertGetNameStringA(pCertContext, Type, Flag, NULL, pszTempName, dwData); + if (!dwData) + { + LocalFree(pszTempName); + return FALSE; + } + String = std::string(pszTempName); + StripString(String); + LocalFree(pszTempName); + return TRUE; +} + +BOOL CalculateSignVersion( + DWORD dwVersion, + std::string& Version +) { + switch (dwVersion) + { + case CERT_V1: + Version = "V1"; + break; + case CERT_V2: + Version = "V2"; + break; + case CERT_V3: + Version = "V3"; + break; + default: + Version = "Unknown"; + break; + } + StripString(Version); + return TRUE; +} + +BOOL CalculateDigestAlgorithm( + LPCSTR pszObjId, + std::string& Algorithm +) { + if (!pszObjId) + { + Algorithm = "Unknown"; + } + else if (!strcmp(pszObjId, szOID_OIWSEC_sha1)) + { + Algorithm = "SHA1"; + } + else if (!strcmp(pszObjId, szOID_RSA_MD5)) + { + Algorithm = "MD5"; + } + else if (!strcmp(pszObjId, szOID_NIST_sha256)) + { + Algorithm = "SHA256"; + } + else + { + Algorithm = std::string(pszObjId); + } + StripString(Algorithm); + return TRUE; +} + +BOOL CalculateCertAlgorithm( + LPCSTR pszObjId, + std::string& Algorithm +) { + if (!pszObjId) + { + Algorithm = "Unknown"; + } + else if (0 == strcmp(pszObjId, szOID_RSA_SHA1RSA)) + { + Algorithm = "sha1RSA(RSA)"; + } + else if (0 == strcmp(pszObjId, szOID_OIWSEC_sha1RSASign)) + { + Algorithm = "sha1RSA(OIW)"; + } + else if (0 == strcmp(pszObjId, szOID_RSA_MD5RSA)) + { + Algorithm = "md5RSA(RSA)"; + } + else if (0 == strcmp(pszObjId, szOID_OIWSEC_md5RSA)) + { + Algorithm = "md5RSA(OIW)"; + } + else if (0 == strcmp(pszObjId, szOID_RSA_MD2RSA)) + { + Algorithm = "md2RSA(RSA)"; + } + else if (0 == strcmp(pszObjId, szOID_RSA_SHA256RSA)) + { + Algorithm = "sha256RSA(RSA)"; + } + else + { + Algorithm = pszObjId; + } + StripString(Algorithm); + return TRUE; +} + +#define SHA1LEN 20 +#define BUFSIZE 2048 +#define MD5LEN 16 + +BOOL CalculateHashOfBytes( + BYTE* pbBinary, + ALG_ID Algid, + DWORD dwBinary, + std::string& Hash +) { + BOOL bReturn = FALSE; + DWORD dwLastError = 0; + HCRYPTPROV hProv = 0; + HCRYPTHASH hHash = 0; + DWORD cbHash = 0; + BYTE rgbHash[SHA1LEN] = { 0 }; + CHAR hexbyte[3] = { 0 }; + CONST CHAR rgbDigits[] = "0123456789abcdef"; + std::string CalcHash; + + bReturn = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + if (!bReturn) + { + dwLastError = GetLastError(); + return FALSE; + } + bReturn = CryptCreateHash(hProv, Algid, 0, 0, &hHash); + if (!bReturn) + { + dwLastError = GetLastError(); + CryptReleaseContext(hProv, 0); + return FALSE; + } + bReturn = CryptHashData(hHash, pbBinary, dwBinary, 0); + if (!bReturn) + { + dwLastError = GetLastError(); + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return FALSE; + } + if (CALG_SHA1 == Algid) + { + cbHash = SHA1LEN; + } + else if (CALG_MD5 == Algid) + { + cbHash = MD5LEN; + } + else + { + cbHash = 0; + } + hexbyte[2] = '\0'; + bReturn = CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0); + if (!bReturn) + { + dwLastError = GetLastError(); + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return FALSE; + } + for (DWORD i = 0; i < cbHash; i++) + { + hexbyte[0] = rgbDigits[rgbHash[i] >> 4]; + hexbyte[1] = rgbDigits[rgbHash[i] & 0xf]; + CalcHash.append(hexbyte); + } + Hash = CalcHash; + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return TRUE; +} + +BOOL CalculateCertCRLpoint( + DWORD cExtensions, + CERT_EXTENSION rgExtensions[], + std::wstring& CRLpoint +) { + BOOL bReturn = FALSE; + BYTE btData[512] = { 0 }; + WCHAR csProperty[512] = { 0 }; + ULONG ulDataLen = 512; + PCRL_DIST_POINTS_INFO pCRLDistPoint = (PCRL_DIST_POINTS_INFO)btData; + PCRL_DIST_POINT_NAME dpn = NULL; + PCERT_EXTENSION pe = NULL; + + CRLpoint.clear(); + pe = CertFindExtension(szOID_CRL_DIST_POINTS, cExtensions, rgExtensions); + if (!pe) + { + return FALSE; + } + bReturn = CryptDecodeObject(MY_ENCODING, szOID_CRL_DIST_POINTS, + pe->Value.pbData, + pe->Value.cbData, + CRYPT_DECODE_NOCOPY_FLAG, + pCRLDistPoint, &ulDataLen + ); + if (!bReturn) + { + return FALSE; + } + for (ULONG idx = 0; idx < pCRLDistPoint->cDistPoint; idx++) + { + dpn = &pCRLDistPoint->rgDistPoint[idx].DistPointName; + for (ULONG ulAltEntry = 0; ulAltEntry < dpn->FullName.cAltEntry; ulAltEntry++) + { + if (wcslen(csProperty) > 0) + { + wcscat_s(csProperty, 512, L";"); + } + wcscat_s(csProperty, 512, dpn->FullName.rgAltEntry[ulAltEntry].pwszURL); + } + } + CRLpoint = csProperty; + return TRUE; +} + +BOOL CalculateSignSerial( + BYTE* pbData, + DWORD cbData, + std::string& Serial +) { + BOOL bReturn = FALSE; + DWORD dwSize = 0x400; + BYTE abSerial[0x400] = { 0 }; + CHAR NameBuff[0x400] = { 0 }; + + Serial.clear(); + for (UINT uiIter = 0; uiIter < cbData && uiIter < 0x400; uiIter++) + { + abSerial[uiIter] = pbData[cbData - 1 - uiIter]; + } + bReturn = CryptBinaryToStringA(abSerial, cbData, CRYPT_STRING_HEX, NameBuff, &dwSize); + if (!bReturn) + { + return FALSE; + } + DWORD dwIter1 = 0; + DWORD dwIter2 = 0; + for (dwIter1 = 0; dwIter1 < dwSize; dwIter1++) + { + if (!isspace(NameBuff[dwIter1])) + { + NameBuff[dwIter2++] = NameBuff[dwIter1]; + } + } + NameBuff[dwIter2] = '\0'; + Serial = std::string(NameBuff); + StripString(Serial); + return TRUE; +} + +// Getting Signer Signature Information. +// If return TRUE, it will continue for caller; +// else, jump out the while loop. +BOOL GetSignerSignatureInfo( + CONST HCERTSTORE hSystemStore, + CONST HCERTSTORE hCertStore, + CONST PCCERT_CONTEXT pOrigContext, + PCCERT_CONTEXT& pCurrContext, + SIGN_NODE_INFO& SignNode +) { + BOOL bReturn = FALSE; + PCERT_INFO pCertInfo = pCurrContext->pCertInfo; + LPCSTR szObjId = NULL; + CERT_NODE_INFO CertNode; + + // Get certificate algorithm. + szObjId = pCertInfo->SignatureAlgorithm.pszObjId; + bReturn = CalculateCertAlgorithm(szObjId, CertNode.SignAlgorithm); + // Get certificate serial. + bReturn = CalculateSignSerial(pCertInfo->SerialNumber.pbData, + pCertInfo->SerialNumber.cbData, + CertNode.Serial + ); + // Get certificate version. + bReturn = CalculateSignVersion(pCertInfo->dwVersion, CertNode.Version); + // Get certficate subject. + bReturn = GetStringFromCertContext(pCurrContext, + CERT_NAME_SIMPLE_DISPLAY_TYPE, + 0, + CertNode.SubjectName + ); + // Get certificate issuer. + bReturn = GetStringFromCertContext(pCurrContext, + CERT_NAME_SIMPLE_DISPLAY_TYPE, + CERT_NAME_ISSUER_FLAG, + CertNode.IssuerName + ); + // Get certificate thumbprint. + bReturn = CalculateHashOfBytes(pCurrContext->pbCertEncoded, + CALG_SHA1, + pCurrContext->cbCertEncoded, + CertNode.Thumbprint + ); + // Get certificate CRL point. + bReturn = CalculateCertCRLpoint(pCertInfo->cExtension, + pCertInfo->rgExtension, + CertNode.CRLpoint + ); + // Get certificate validity. + CertNode.NotBefore = TimeToString(&pCertInfo->NotBefore); + CertNode.NotAfter = TimeToString(&pCertInfo->NotAfter); + + SignNode.CertChain.push_back(CertNode); + + // Get next certificate link node. + pCurrContext = CertFindCertificateInStore(hCertStore, + MY_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + (PVOID)&pCertInfo->Issuer, + NULL + ); + // Root certificate is always included pe file certstore, + // We can find it in system certstore. + if (!pCurrContext) + { + pCurrContext = CertFindCertificateInStore(hSystemStore, + MY_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + (PVOID)&pCertInfo->Issuer, + NULL + ); + } + if (!pCurrContext) + { + return FALSE; + } + // Sometimes issuer is equal to subject. Jump out if so. + return CertComparePublicKeyInfo(MY_ENCODING, + &pCurrContext->pCertInfo->SubjectPublicKeyInfo, + &pOrigContext->pCertInfo->SubjectPublicKeyInfo + ) == FALSE; +} + +// Getting Signer Certificate Information. +BOOL GetSignerCertificateInfo( + LPCWSTR FileName, + std::list& SignChain +) { + BOOL bSucceed = FALSE; + BOOL bReturn = FALSE; + HCERTSTORE hSystemStore = NULL; + SIGNDATA_HANDLE AuthSignData = { 0 }; + std::list SignDataChain; + + SignChain.clear(); + // Open system certstore handle, in order to find root certificate. + hSystemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, MY_ENCODING, + NULL, + CERT_SYSTEM_STORE_CURRENT_USER, + L"Root" + ); + if (!hSystemStore) + { + INT error = GetLastError(); + return FALSE; + } + // Query file auth signature and cert store Object. + HCRYPTMSG hAuthCryptMsg = NULL; + DWORD dwEncoding = 0x00; + bReturn = CryptQueryObject(CERT_QUERY_OBJECT_FILE, FileName, + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, + CERT_QUERY_FORMAT_FLAG_BINARY, + 0, + &dwEncoding, + NULL, + NULL, + &AuthSignData.hCertStoreHandle, + &hAuthCryptMsg, + NULL + ); + if (!bReturn) + { + INT error = GetLastError(); + CertCloseStore(hSystemStore, 0); + return FALSE; + } + // Get signer information pointer. + bReturn = MyCryptMsgGetParam(hAuthCryptMsg, CMSG_SIGNER_INFO_PARAM, + 0, + (PVOID*)&AuthSignData.pSignerInfo, + &AuthSignData.dwObjSize + ); + CryptMsgClose(hAuthCryptMsg); + hAuthCryptMsg = NULL; + if (!bReturn) + { + INT error = GetLastError(); + CertCloseStore(AuthSignData.hCertStoreHandle, 0); + CertCloseStore(hSystemStore, 0); + return FALSE; + } + + // Get and append nested signature information. + SignDataChain.push_back(AuthSignData); + bReturn = GetNestedSignerInfo(&AuthSignData, SignDataChain); + + list::iterator iter = SignDataChain.begin(); + for (; iter != SignDataChain.end(); iter++) + { + PCCERT_CONTEXT pOrigContext = NULL; + PCCERT_CONTEXT pCurrContext = NULL; + LPCSTR szObjId = NULL; + PCMSG_SIGNER_INFO pCounterSigner = NULL; + SIGN_NODE_INFO SignNode; + + GetAuthedAttribute(iter->pSignerInfo); + // Get signature timestamp. + GetCounterSignerInfo(iter->pSignerInfo, &pCounterSigner); + if (pCounterSigner) + { + bReturn = GetCounterSignerData(pCounterSigner, SignNode.CounterSign); + } + else + { + bReturn = GetGeneralizedTimeStamp(iter->pSignerInfo, + SignNode.CounterSign.TimeStamp + ); + } + // Get digest algorithm. + szObjId = iter->pSignerInfo->HashAlgorithm.pszObjId; + bReturn = CalculateDigestAlgorithm(szObjId, SignNode.DigestAlgorithm); + // Get signature version. + bReturn = CalculateSignVersion(iter->pSignerInfo->dwVersion, SignNode.Version); + // Find the first certificate Context information. + pCurrContext = CertFindCertificateInStore(iter->hCertStoreHandle, + MY_ENCODING, + 0, + CERT_FIND_ISSUER_NAME, + (PVOID)&iter->pSignerInfo->Issuer, + NULL + ); + bReturn = (pCurrContext != NULL); + while (bReturn) + { + pOrigContext = pCurrContext; + // Get every signer signature information. + bReturn = GetSignerSignatureInfo(hSystemStore, iter->hCertStoreHandle, + pOrigContext, + pCurrContext, + SignNode + ); + CertFreeCertificateContext(pOrigContext); + } + if (pCurrContext) CertFreeCertificateContext(pCurrContext); + if (pCounterSigner) LocalFree(pCounterSigner); + if (iter->pSignerInfo) LocalFree(iter->pSignerInfo); + if (iter->hCertStoreHandle) CertCloseStore(iter->hCertStoreHandle, 0); + bSucceed = TRUE; + SignChain.push_back(SignNode); + } + CertCloseStore(hSystemStore, 0); + return bSucceed; +} + +BOOL MyCryptCalcFileHash( + HANDLE FileHandle, + PBYTE* szBuffer, + DWORD* HashSize +) { + BOOL bReturn = FALSE; + if (!szBuffer || !HashSize) + { + return FALSE; + } + *HashSize = 0x00; + // Get size. + bReturn = CryptCATAdminCalcHashFromFileHandle(FileHandle, HashSize, NULL, 0x00); + if (0 == *HashSize) // HashSize being zero means fatal error. + { + return FALSE; + } + *szBuffer = (PBYTE)calloc(*HashSize, 1); + bReturn = CryptCATAdminCalcHashFromFileHandle(FileHandle, HashSize, *szBuffer, 0x00); + if (!bReturn) + { + free(*szBuffer); + } + return bReturn; +} + +BOOL CheckFileDigitalSignature( + LPCWSTR FilePath, + LPCWSTR CataPath, + std::wstring& CataFile, + std::string& SignType, + std::list& SignChain +) { + PVOID Context = NULL; + BOOL bReturn = FALSE; + + CataFile = CataPath ? CataPath : L""; + SignType = "embedded"; + + do + { + // Skip getting catalog Context if CataPath is specified. + if (CataPath) + { + break; + } + // Acquire signature Context structure. + bReturn = CryptCATAdminAcquireContext(&Context, NULL, 0); + if (!bReturn) + { + break; + } + // Open the specified file handle to get the file hash. + HANDLE FileHandle = CreateFileW(FilePath, GENERIC_READ, + 7, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + if (INVALID_HANDLE_VALUE == FileHandle) + { + break; + } + // Calculate file hash. + DWORD dwHashSize = 0x00; + PBYTE szBuffer = NULL; + bReturn = MyCryptCalcFileHash(FileHandle, &szBuffer, &dwHashSize); + CloseHandle(FileHandle); + if (!bReturn) + { + break; + } + // Get catalog Context structure. + UINT uiCataLimit = 0x00; + HCATINFO CataContext = NULL; + do + { + // Probe catalog Context structure layer. + CataContext = CryptCATAdminEnumCatalogFromHash(Context, + szBuffer, + dwHashSize, + 0, + uiCataLimit == 0 ? NULL : &CataContext + ); + uiCataLimit++; + } while (CataContext); + uiCataLimit--; + for (UINT uiIter = 0; uiIter < uiCataLimit; uiIter++) + { + // Get specified catalog Context structure. + CataContext = CryptCATAdminEnumCatalogFromHash(Context, + szBuffer, + dwHashSize, + 0, + &CataContext + ); + } + free(szBuffer); + if (!CataContext) + { + break; + } + // Get catalog information. + CATALOG_INFO CataInfo = { 0 }; + CataInfo.cbStruct = sizeof(CATALOG_INFO); + bReturn = CryptCATCatalogInfoFromContext(CataContext, &CataInfo, 0); + if (bReturn) + { + CataFile = CataInfo.wszCatalogFile; + } + // Release catalog Context structure. + bReturn = CryptCATAdminReleaseCatalogContext(Context, CataContext, 0); + CataContext = NULL; + } while (FALSE); + if (Context) + { + // Release signature Context structure. + bReturn = CryptCATAdminReleaseContext(Context, 0); + Context = NULL; + } + + // Get certificate information. + bReturn = GetSignerCertificateInfo(FilePath, SignChain); + if (!bReturn && !CataFile.empty()) + { + // If we cannot get embedded signature information, we + // just attempt to get cataloged signature information + // if it has catalog or catalog is specified. + SignType = "cataloged"; + bReturn = GetSignerCertificateInfo(CataFile.c_str(), SignChain); + } + return bReturn; +} + +void PrintSignatureInfo(std::string& SignType, std::wstring& CataFile, std::list& SignChain) +{ + std::cout << "signtype: " << SignType << endl; + std::wcout << L"catafile: " << CataFile << endl; + std::cout << "-----------------------" << endl; + UINT idx = 0; + std::list::iterator iter = SignChain.begin(); + for (; iter != SignChain.end(); iter++) + { + std::cout << "[ The " << ++idx << " Sign Info ]" << endl; + std::cout << "timestamp: " << iter->CounterSign.TimeStamp << endl; + std::cout << "version: " << iter->Version << endl; + std::cout << "digestAlgorithm: " << iter->DigestAlgorithm << endl; + + std::list::iterator iter1 = iter->CertChain.begin(); + for (; iter1 != iter->CertChain.end(); iter1++) + { + std::cout << " |--" << "-------------------" << endl; + std::cout << " |- " << "subject: " << iter1->SubjectName << endl; + std::cout << " |- " << "issuer: " << iter1->IssuerName << endl; + std::cout << " |- " << "serial: " << iter1->Serial << endl; + std::cout << " |- " << "thumbprint: " << iter1->Thumbprint << endl; + std::cout << " |- " << "signAlgorithm: " << iter1->SignAlgorithm << endl; + std::cout << " |- " << "version: " << iter1->Version << endl; + std::cout << " |- " << "notbefore: " << iter1->NotBefore << endl; + std::cout << " |- " << "notafter: " << iter1->NotAfter << endl; + std::wcout << L" |- " << L"CRLpoint: " << iter1->CRLpoint << endl; + } + std::cout << "-----------------------" << endl; + } +} \ No newline at end of file diff --git a/Protector/Utils.hpp b/Protector/Utils.hpp new file mode 100644 index 0000000..699c1cf --- /dev/null +++ b/Protector/Utils.hpp @@ -0,0 +1,34 @@ +#include + +#include +#include +typedef struct _SIGN_COUNTER_SIGN { + std::string SignerName; + std::string MailAddress; + std::string TimeStamp; +} SIGN_COUNTER_SIGN, * PSIGN_COUNTER_SIGN; +typedef struct _CERT_NODE_INFO { + std::string SubjectName; + std::string IssuerName; + std::string Version; + std::string Serial; + std::string Thumbprint; + std::string NotBefore; + std::string NotAfter; + std::string SignAlgorithm; + std::wstring CRLpoint; +} CERT_NODE_INFO, * PCERT_NODE_INFO; +typedef struct _SIGN_NODE_INFO { + std::string DigestAlgorithm; + std::string Version; + SIGN_COUNTER_SIGN CounterSign; + std::list CertChain; +} SIGN_NODE_INFO, * PSIGN_NODE_INFO; + +BOOL CheckFileDigitalSignature( + LPCWSTR FilePath, + LPCWSTR CataPath, + std::wstring& CataFile, + std::string& SignType, + std::list& SignChain); +void PrintSignatureInfo(std::string& SignType, std::wstring& CataFile, std::list& SignChain); \ No newline at end of file