1
mirror of https://github.com/thepeacockproject/Peacock synced 2024-11-22 22:12:45 +01:00
Peacock/patcher/Pinvoke.cs
Reece Dunham 3a2dbeec18
Patcher: unify Linux/Windows implementation
Signed-off-by: Reece Dunham <me@rdil.rocks>
2023-11-20 15:21:00 -05:00

107 lines
4.4 KiB
C#

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace HitmanPatcher
{
// from https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants
[Flags]
public enum MemProtection : uint
{
PAGE_EXECUTE = 0x00000010,
PAGE_EXECUTE_READ = 0x00000020,
PAGE_EXECUTE_READWRITE = 0x00000040,
PAGE_EXECUTE_WRITECOPY = 0x00000080,
PAGE_NOACCESS = 0x00000001,
PAGE_READONLY = 0x00000002,
PAGE_READWRITE = 0x00000004,
PAGE_WRITECOPY = 0x00000008,
PAGE_GUARD = 0x00000100,
PAGE_NOCACHE = 0x00000200,
PAGE_WRITECOMBINE = 0x00000400
}
// from https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
// I've only listed the ones that I use
[Flags]
public enum ProcessAccess : uint
{
PROCESS_QUERY_INFORMATION = 0x0400, // Required to retrieve certain information about a process.
PROCESS_VM_READ = 0x0010, // Required to read memory in a process using ReadProcessMemory.
PROCESS_VM_WRITE = 0x0020, // Required to write to memory in a process using WriteProcessMemory.
PROCESS_VM_OPERATION = 0x0008 // Required to perform an operation on the address space of a process using VirtualProtectEx
}
// from https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
public enum PROCESSINFOCLASS
{
ProcessBasicInformation = 0,
ProcessDebugPort = 7,
ProcessWow64Information = 26,
ProcessImageFileName = 27,
ProcessBreakOnTermination = 29,
ProcessSubsystemInformation = 75
}
// from https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_BASIC_INFORMATION
{
public IntPtr Reserved1;
public IntPtr PebBaseAddress;
public IntPtr Reserved2_0;
public IntPtr Reserved2_1;
public IntPtr UniqueProcessId;
public IntPtr Reserved3;
}
public static class Pinvoke
{
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory([In] IntPtr hProcess, [In] IntPtr address, [In, MarshalAs(UnmanagedType.LPArray)] byte[] buffer, [In] UIntPtr size, [Out] out UIntPtr byteswritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory([In] IntPtr hProcess, [In] IntPtr address, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] buffer, [In] UIntPtr size, [Out] out UIntPtr numberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool VirtualProtectEx([In] IntPtr hProcess, [In] IntPtr lpAddress, [In] UIntPtr dwSize, [In] MemProtection flNewProtect, [Out] out MemProtection lpflOldProtect);
[DllImport("ntdll.dll")]
public static extern int NtQueryInformationProcess(IntPtr hProcess, PROCESSINFOCLASS processInformationClass, out PROCESS_BASIC_INFORMATION processInformation, uint processInformationLength, out uint returnLength);
public static int GetProcessParentPid(Process process)
{
IntPtr hProcess = OpenProcess(
ProcessAccess.PROCESS_VM_READ
| ProcessAccess.PROCESS_QUERY_INFORMATION,
false, process.Id);
if (hProcess == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to get a process handle.");
}
PROCESS_BASIC_INFORMATION PEB = new PROCESS_BASIC_INFORMATION();
int result = NtQueryInformationProcess(hProcess,
PROCESSINFOCLASS.ProcessBasicInformation, out PEB,
(uint) Marshal.SizeOf(PEB), out _);
CloseHandle(hProcess);
if (result != 0)
{
throw new Win32Exception(result, "(NTSTATUS)"); // not a w32 status code, but an NTSTATUS
}
return PEB.Reserved3.ToInt32(); // undocumented, but should hold the parent PID
}
}
}