win32 define and injector

This commit is contained in:
HolographicHat
2022-06-10 18:34:24 +08:00
parent 8aed3fd095
commit 12348a3941
17 changed files with 312 additions and 139 deletions

5
src/GlobalVars.cs Normal file
View File

@@ -0,0 +1,5 @@
namespace YaeAchievement;
public static class GlobalVars {
public static bool Verbose = false;
}

53
src/Injector.cs Normal file
View File

@@ -0,0 +1,53 @@
using System.ComponentModel;
using YaeAchievement.Win32;
namespace YaeAchievement;
public static class Injector {
public static bool CreateProcess(string path, ref IntPtr phThread, ref IntPtr phProcess) {
ProcessInformation pi;
unsafe {
var si = new StartupInfo();
SecurityAttributes* attr = null;
var result = Native.CreateProcess(
path, null, ref *attr, ref *attr, false,
CreationFlags.CreateSuspended, IntPtr.Zero, null, ref si, out pi
);
if (!result) {
return false;
}
}
phThread = pi.hThread;
phProcess = pi.hProcess;
return true;
}
public static int LoadLibraryAndInject(IntPtr handle, string libPath) {
var hKernel = Native.GetModuleHandle("kernel32.dll");
if (hKernel == IntPtr.Zero) {
return new Win32Exception().PrintMsgAndReturnErrCode("GetModuleHandle fail");
}
var pLoadLibrary = Native.GetProcAddress(hKernel, "LoadLibraryA");
if (pLoadLibrary == IntPtr.Zero) {
return new Win32Exception().PrintMsgAndReturnErrCode("GetProcAddress fail");
}
var pBase = Native.VirtualAllocEx(handle, IntPtr.Zero, libPath.Length + 1, AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ReadWrite);
if (pBase == IntPtr.Zero) {
return new Win32Exception().PrintMsgAndReturnErrCode("VirtualAllocEx fail");
}
if (!Native.WriteProcessMemory(handle, pBase, libPath.ToCharArray(), libPath.Length, out _)) {
return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail");
}
var hThread = Native.CreateRemoteThread(handle, IntPtr.Zero, 0, pLoadLibrary, pBase, 0, out _);
if (hThread == IntPtr.Zero) {
var e = new Win32Exception();
if (!Native.VirtualFreeEx(handle, pBase, 0, AllocationType.Release)) {
new Win32Exception().PrintMsgAndReturnErrCode("VirtualFreeEx fail");
}
return e.PrintMsgAndReturnErrCode("CreateRemoteThread fail");
}
return !Native.CloseHandle(hThread) ? new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail") : 0;
}
}

View File

@@ -1,3 +1,46 @@
// See https://aka.ms/new-console-template for more information
using System.ComponentModel;
using System.IO.Pipes;
using YaeAchievement;
using YaeAchievement.Win32;
Console.WriteLine("Hello, World!");
var hThread = IntPtr.Zero;
var hProcess = IntPtr.Zero;
if (!Injector.CreateProcess("exePath", ref hThread, ref hProcess)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
}
if (Injector.LoadLibraryAndInject(hProcess, "YaeAchievementLib.dll") != 0) {
if (!Native.TerminateProcess(hProcess, 0)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
}
}
if (Native.ResumeThread(hThread) == 0xFFFFFFFF) {
var e = new Win32Exception();
if (!Native.TerminateProcess(hProcess, 0)) {
new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail");
}
Environment.Exit(e.PrintMsgAndReturnErrCode("ResumeThread fail"));
}
if (!Native.CloseHandle(hProcess)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail"));
}
bool OnXXXReceived(string something) {
return true;
}
var ts = new ThreadStart(() => {
var server = new NamedPipeServerStream("");
server.WaitForConnection();
var reader = new StreamReader(server);
while (true) {
var line = reader.ReadLine();
if (line?.Length > 0) {
if (OnXXXReceived(line)) {
break;
}
server.Disconnect();
server.WaitForConnection();
}
}
});
new Thread(ts).Start();

View File

@@ -0,0 +1,13 @@
namespace YaeAchievement.Win32;
public static class AllocationType {
public const int Commit = 0x1000;
public const int Reserve = 0x2000;
public const int Decommit = 0x4000;
public const int Release = 0x8000;
public const int Reset = 0x80000;
public const int Physical = 0x400000;
public const int TopDown = 0x100000;
public const int WriteWatch = 0x200000;
public const int LargePages = 0x20000000;
}

View File

@@ -0,0 +1,8 @@
namespace YaeAchievement.Win32;
public static class CreationFlags {
public const int CreateSuspended = 0x00000004;
public const int DetachedProcess = 0x00000008;
public const int CreateNoWindow = 0x08000000;
public const int ExtendedStartupInfoPresent = 0x00080000;
}

15
src/Win32/Extensions.cs Normal file
View File

@@ -0,0 +1,15 @@
using System.ComponentModel;
namespace YaeAchievement.Win32;
public static class Extensions {
public static int PrintMsgAndReturnErrCode(this Win32Exception ex, string msg) {
Console.WriteLine($"{msg}: {ex.Message}");
if (GlobalVars.Verbose) {
Console.WriteLine(ex.StackTrace);
}
return ex.NativeErrorCode;
}
}

View File

@@ -0,0 +1,15 @@
namespace YaeAchievement.Win32;
public static class MemoryProtection {
public const int Execute = 0x10;
public const int ExecuteRead = 0x20;
public const int ExecuteReadWrite = 0x40;
public const int ExecuteWriteCopy = 0x80;
public const int NoAccess = 0x01;
public const int ReadOnly = 0x02;
public const int ReadWrite = 0x04;
public const int WriteCopy = 0x08;
public const int GuardModifierFlag = 0x100;
public const int NoCacheModifierFlag = 0x200;
public const int WriteCombineModifierFlag = 0x400;
}

74
src/Win32/Native.cs Normal file
View File

@@ -0,0 +1,74 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
namespace YaeAchievement.Win32;
[SuppressMessage("Interoperability", "CA1401:P/Invokes 应该是不可见的")]
public static class Native {
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CreateProcess(
string lpApplicationName,
string? lpCommandLine,
ref SecurityAttributes lpProcessAttributes,
ref SecurityAttributes lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
IntPtr lpEnvironment,
string? lpCurrentDirectory,
[In] ref StartupInfo lpStartupInfo,
out ProcessInformation lpProcessInformation
);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
char[] lpBuffer,
int nSize,
out IntPtr lpNumberOfBytesWritten
);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
[SuppressMessage("Globalization", "CA2101:指定对 P/Invoke 字符串参数进行封送处理")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling=true)]
public static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
int dwSize,
int flAllocationType,
int flProtect
);
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int dwFreeType);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint ResumeThread(IntPtr hThread);
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
int dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId
);
}

View File

@@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
namespace YaeAchievement.Win32;
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation {
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}

View File

@@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
namespace YaeAchievement.Win32;
[StructLayout(LayoutKind.Sequential)]
public struct SecurityAttributes {
public int nLength;
public IntPtr lpSecurityDescriptor;
}

28
src/Win32/StartupInfo.cs Normal file
View File

@@ -0,0 +1,28 @@
using System.Runtime.InteropServices;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
namespace YaeAchievement.Win32;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct StartupInfo {
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}