using System; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security; using System.Text; using Microsoft.Win32.SafeHandles; namespace NitroxModel.Platforms.OS.Windows.Internal; internal static class Win32Native { [Flags] public enum AssocF : uint { None = 0, Init_NoRemapCLSID = 0x1, Init_ByExeName = 0x2, Open_ByExeName = 0x2, Init_DefaultToStar = 0x4, Init_DefaultToFolder = 0x8, NoUserSettings = 0x10, NoTruncate = 0x20, Verify = 0x40, RemapRunDll = 0x80, NoFixUps = 0x100, IgnoreBaseClass = 0x200, Init_IgnoreUnknown = 0x400, Init_FixedProgId = 0x800, IsProtocol = 0x1000, InitForFile = 0x2000 } public enum AssocStr { Command = 1, Executable, FriendlyDocName, FriendlyAppName, NoOpen, ShellNewValue, DDECommand, DDEIfExec, DDEApplication, DDETopic, InfoTip, QuickTip, TileInfo, ContentType, DefaultIcon, ShellExtension, DropTarget, DelegateExecute, SupportedUriProtocols, // The values below ('Max' excluded) have been introduced in W10 1511 ProgID, AppID, AppPublisher, AppIconReference, Max } /// /// Gets the associated program for the file extension. /// /// /// /// public static string AssocQueryString(AssocStr str, string extension) { const int S_OK = 0; const int S_FALSE = 1; uint length = 0; uint ret = AssocQueryString(AssocF.None, str, extension, null, null, ref length); if (ret != S_FALSE) { return null; } StringBuilder sb = new((int)length); ret = AssocQueryString(AssocF.None, str, extension, null, sb, ref length); if (ret != S_OK) { return null; } return sb.ToString(); } [DllImport("kernel32.dll", SetLastError = true)] [SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle(IntPtr hObject); /// /// If true, kills the debugged process when debugger detaches. /// /// [DllImport("kernel32.dll")] public static extern void DebugSetProcessKillOnExit(bool killOnExit); [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWow64Process( [In] SafeHandle hProcess, [Out] [MarshalAs(UnmanagedType.Bool)] out bool wow64Process ); public static string QueryFullProcessImageName(SafeHandle process, uint flags = 0) { try { StringBuilder fileNameBuilder = new(1024); int size = fileNameBuilder.Capacity; return QueryFullProcessImageName(process, flags, fileNameBuilder, ref size) ? fileNameBuilder.ToString() : null; } catch (Exception) { return null; } } [DllImport("kernel32.dll")] public static extern bool TerminateProcess(SafeHandle hProcess, int exitCode); [DllImport("kernel32.dll")] public static extern uint SuspendThread(SafeHandle hThread); [DllImport("kernel32.dll")] public static extern uint ResumeThread(SafeHandle hThread); [DllImport("ntdll.dll", PreserveSig = false)] public static extern void NtSuspendProcess(SafeHandle processHandle); [DllImport("ntdll.dll", PreserveSig = false, SetLastError = true)] public static extern void NtResumeProcess(SafeHandle processHandle); [DllImport("kernel32.dll")] public static extern bool CreateProcess( string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref StartupInfo lpStartupInfo, out ProcessInfo lpProcessInformation ); [DllImport("kernel32.dll", SetLastError = true)] public static extern SafeProcessHandle OpenProcess( ProcessAccessFlags processAccess, bool bInheritHandle, int processId ); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool ReadProcessMemory( SafeHandle hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool WriteProcessMemory(SafeHandle hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out int lpNumberOfBytesWritten); [DllImport("ntdll.dll")] public static extern NtStatus NtQueryInformationProcess(SafeHandle processHandle, int processInformationClass, ref ProcessBasicInformation processInformation, int processInformationLength, IntPtr returnLength); [DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread( SafeHandle hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId); [DllImport("kernel32.dll")] internal static extern bool FlushInstructionCache(SafeHandle hProcess, IntPtr lpBaseAddress, uint dwSize); [DllImport("kernel32.dll", SetLastError = true)] internal static extern SafeAccessTokenHandle OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern uint AssocQueryString(AssocF flags, AssocStr str, string extension, string pszExtra, [Out] StringBuilder pszOut, ref uint pcchOut); [DllImport("kernel32.dll")] private static extern bool QueryFullProcessImageName([In] SafeHandle hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In] [Out] ref int lpdwSize); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool QueryFullProcessImageName([In] SafeHandle hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize); [DllImport("Wintrust.dll", PreserveSig = true, SetLastError = false)] private static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData); public static bool IsTrusted(string fileName) { return WinVerifyTrust(fileName) == 0; } private static uint WinVerifyTrust(string fileName) { Guid wintrust_action_generic_verify_v2 = new("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}"); uint result = 0; using (WINTRUST_FILE_INFO fileInfo = new(fileName, Guid.Empty)) using (UnmanagedPointer guidPtr = new(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))), AllocMethod.HGlobal)) using (UnmanagedPointer wvtDataPtr = new(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_DATA))), AllocMethod.HGlobal)) { WINTRUST_DATA data = new(fileInfo); IntPtr pGuid = guidPtr; IntPtr pData = wvtDataPtr; Marshal.StructureToPtr(wintrust_action_generic_verify_v2, pGuid, true); Marshal.StructureToPtr(data, pData, true); result = WinVerifyTrust(IntPtr.Zero, pGuid, pData); } return result; } internal struct WINTRUST_FILE_INFO : IDisposable { public WINTRUST_FILE_INFO(string fileName, Guid subject) { cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)); pcwszFilePath = fileName; if (subject != Guid.Empty) { pgKnownSubject = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))); Marshal.StructureToPtr(subject, pgKnownSubject, true); } else { pgKnownSubject = IntPtr.Zero; } hFile = IntPtr.Zero; } public uint cbStruct; [MarshalAs(UnmanagedType.LPTStr)] public string pcwszFilePath; public IntPtr hFile; public IntPtr pgKnownSubject; public void Dispose() => Dispose(true); private void Dispose(bool disposing) { if (pgKnownSubject != IntPtr.Zero) { Marshal.DestroyStructure(pgKnownSubject, typeof(Guid)); Marshal.FreeHGlobal(pgKnownSubject); } } } private enum AllocMethod { HGlobal, CoTaskMem } private enum UnionChoice { File = 1, Catalog, Blob, Signer, Cert } private enum UiChoice { All = 1, NoUI, NoBad, NoGood } private enum RevocationCheckFlags { None = 0, WholeChain } private enum StateAction { Ignore = 0, Verify, Close, AutoCache, AutoCacheFlush } private enum TrustProviderFlags { UseIE4Trust = 1, NoIE4Chain = 2, NoPolicyUsage = 4, RevocationCheckNone = 16, RevocationCheckEndCert = 32, RevocationCheckChain = 64, RecovationCheckChainExcludeRoot = 128, Safer = 256, HashOnly = 512, UseDefaultOSVerCheck = 1024, LifetimeSigning = 2048 } private enum UIContext { Execute = 0, Install } [DllImport("user32.dll", EntryPoint = "SetWindowLong")] internal static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] internal static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, long dwNewLong); [Flags] public enum WS : long { WS_BORDER = 0x00800000L, WS_CAPTION = 0x00C00000L, WS_CHILD = 0x40000000L, WS_CHILDWINDOW = 0x40000000L, WS_CLIPCHILDREN = 0x02000000L, WS_CLIPSIBLINGS = 0x04000000L, WS_DISABLED = 0x08000000L, WS_DLGFRAME = 0x00400000L, WS_GROUP = 0x00020000L, WS_HSCROLL = 0x00100000L, WS_ICONIC = 0x20000000L, WS_MAXIMIZE = 0x01000000L, WS_MAXIMIZEBOX = 0x00010000L, WS_MINIMIZE = 0x20000000L, WS_MINIMIZEBOX = 0x00020000L, WS_OVERLAPPED = 0x00000000L, WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, WS_POPUP = 0x80000000L, WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU, WS_SIZEBOX = 0x00040000L, WS_SYSMENU = 0x00080000L, WS_TABSTOP = 0x00010000L, WS_THICKFRAME = 0x00040000L, WS_TILED = 0x00000000L, WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, WS_VISIBLE = 0x10000000L, WS_VSCROLL = 0x00200000L } [StructLayout(LayoutKind.Sequential)] private struct WINTRUST_DATA : IDisposable { public WINTRUST_DATA(WINTRUST_FILE_INFO fileInfo) { cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA)); pInfoStruct = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO))); Marshal.StructureToPtr(fileInfo, pInfoStruct, false); dwUnionChoice = UnionChoice.File; pPolicyCallbackData = IntPtr.Zero; pSIPCallbackData = IntPtr.Zero; dwUIChoice = UiChoice.NoUI; fdwRevocationChecks = RevocationCheckFlags.None; dwStateAction = StateAction.Ignore; hWVTStateData = IntPtr.Zero; pwszURLReference = IntPtr.Zero; dwProvFlags = TrustProviderFlags.Safer; dwUIContext = UIContext.Execute; } public uint cbStruct; public IntPtr pPolicyCallbackData; public IntPtr pSIPCallbackData; public UiChoice dwUIChoice; public RevocationCheckFlags fdwRevocationChecks; public UnionChoice dwUnionChoice; public IntPtr pInfoStruct; public StateAction dwStateAction; public IntPtr hWVTStateData; private readonly IntPtr pwszURLReference; public TrustProviderFlags dwProvFlags; public UIContext dwUIContext; public void Dispose() => Dispose(true); private void Dispose(bool disposing) { if (dwUnionChoice == UnionChoice.File) { WINTRUST_FILE_INFO info = new(); Marshal.PtrToStructure(pInfoStruct, info); info.Dispose(); Marshal.DestroyStructure(pInfoStruct, typeof(WINTRUST_FILE_INFO)); } Marshal.FreeHGlobal(pInfoStruct); } } private sealed class UnmanagedPointer : IDisposable { private readonly AllocMethod m_meth; private IntPtr m_ptr; public UnmanagedPointer(IntPtr ptr, AllocMethod method) { m_meth = method; m_ptr = ptr; } public static implicit operator IntPtr(UnmanagedPointer ptr) => ptr.m_ptr; ~UnmanagedPointer() { Dispose(false); } private void Dispose(bool disposing) { if (m_ptr != IntPtr.Zero) { if (m_meth == AllocMethod.HGlobal) { Marshal.FreeHGlobal(m_ptr); } else if (m_meth == AllocMethod.CoTaskMem) { Marshal.FreeCoTaskMem(m_ptr); } m_ptr = IntPtr.Zero; } if (disposing) { GC.SuppressFinalize(this); } } public void Dispose() => Dispose(true); } }