Files
Nitrox/NitroxModel/Platforms/OS/Windows/Internal/Win32Native.cs
2025-07-06 00:23:46 +02:00

495 lines
14 KiB
C#

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
}
/// <summary>
/// Gets the associated program for the file extension.
/// </summary>
/// <param name="str"></param>
/// <param name="extension"></param>
/// <returns></returns>
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);
/// <summary>
/// If true, kills the debugged process when debugger detaches.
/// </summary>
/// <param name="killOnExit"></param>
[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);
}
}