From ef6a72312c40adbb784130f9ef361e81478e3550 Mon Sep 17 00:00:00 2001 From: HolographicHat Date: Sat, 11 Jun 2022 00:36:54 +0800 Subject: [PATCH] optimize code and update --- src/Events/IEventBase.cs | 5 ++ src/Events/PipeRecvEvent.cs | 14 +++++ src/GlobalVars.cs | 5 +- src/Injector.cs | 27 ++++------ src/Program.cs | 94 ++++++++++++++++++++------------- src/Win32/AllocationType.cs | 21 ++++---- src/Win32/CreationFlags.cs | 11 ++-- src/Win32/MemoryProtection.cs | 27 +++++----- src/Win32/Native.cs | 8 +-- src/Win32/ProcessInformation.cs | 4 +- src/Win32/StartupInfo.cs | 22 ++++---- 11 files changed, 139 insertions(+), 99 deletions(-) create mode 100644 src/Events/IEventBase.cs create mode 100644 src/Events/PipeRecvEvent.cs diff --git a/src/Events/IEventBase.cs b/src/Events/IEventBase.cs new file mode 100644 index 0000000..8bcec9c --- /dev/null +++ b/src/Events/IEventBase.cs @@ -0,0 +1,5 @@ +namespace YaeAchievement.Events; + +public interface IEventBase { + +} \ No newline at end of file diff --git a/src/Events/PipeRecvEvent.cs b/src/Events/PipeRecvEvent.cs new file mode 100644 index 0000000..42dbe6e --- /dev/null +++ b/src/Events/PipeRecvEvent.cs @@ -0,0 +1,14 @@ +namespace YaeAchievement.Events; + +public class PipeRecvEvent : IEventBase { + + private readonly byte[] _data; + + public PipeRecvEvent(string content) { + _data = Convert.FromBase64String(content); + } + + public byte[] GetData() { + return _data; + } +} \ No newline at end of file diff --git a/src/GlobalVars.cs b/src/GlobalVars.cs index a78f57e..ad77b11 100644 --- a/src/GlobalVars.cs +++ b/src/GlobalVars.cs @@ -2,4 +2,7 @@ public static class GlobalVars { public static bool Verbose = false; -} \ No newline at end of file + public const string LibName = "YaeAchievementLib.dll"; + public const string PipeName = "YaeAchievementPipe"; + public static bool UnexpectedExit = true; +} diff --git a/src/Injector.cs b/src/Injector.cs index 40c8b21..d8ced07 100644 --- a/src/Injector.cs +++ b/src/Injector.cs @@ -5,22 +5,17 @@ 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 unsafe bool CreateProcess(string path, out IntPtr hProc, out IntPtr hThread, out uint pid) { + 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 var pi + ); + pid = pi.dwProcessID; + hProc = pi.hProcess; + hThread = pi.hThread; + return result; } public static int LoadLibraryAndInject(IntPtr handle, string libPath) { diff --git a/src/Program.cs b/src/Program.cs index d98e810..dc03702 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,46 +1,66 @@ using System.ComponentModel; +using System.Diagnostics; using System.IO.Pipes; using YaeAchievement; +using YaeAchievement.Events; using YaeAchievement.Win32; -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")); +// ReSharper disable once UnusedLocalFunctionReturnValue +Thread StartAndWaitResult(string exePath, Func onEvent) { + if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) { + Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess 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(); + if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibName) != 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")); + } + var proc = Process.GetProcessById(Convert.ToInt32(pid)); + proc.EnableRaisingEvents = true; + proc.Exited += (_, _) => { + if (GlobalVars.UnexpectedExit) { + Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}"); + Environment.Exit(114514); + } + }; + var ts = new ThreadStart(() => { + var server = new NamedPipeServerStream(GlobalVars.PipeName); + server.WaitForConnection(); + var reader = new StreamReader(server); + while (true) { + var line = reader.ReadLine(); + if (line?.Length > 0) { + if (onEvent(new PipeRecvEvent(line))) { + break; + } + server.Disconnect(); + server.WaitForConnection(); + } + } + }); + var th = new Thread(ts); + th.Start(); + return th; +} + +StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", evt => { + switch (evt) { + case PipeRecvEvent @event: { + var bytes = @event.GetData(); + GlobalVars.UnexpectedExit = false; + return BitConverter.ToUInt32(bytes, 2) == 123456; + } + default: + return false; + } }); -new Thread(ts).Start(); diff --git a/src/Win32/AllocationType.cs b/src/Win32/AllocationType.cs index 0ab8f83..254fc22 100644 --- a/src/Win32/AllocationType.cs +++ b/src/Win32/AllocationType.cs @@ -1,13 +1,14 @@ 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; +[Flags] +public enum AllocationType : uint { + Commit = 0x1000, + Reserve = 0x2000, + Decommit = 0x4000, + Release = 0x8000, + Reset = 0x80000, + Physical = 0x400000, + TopDown = 0x100000, + WriteWatch = 0x200000, + LargePages = 0x20000000 } diff --git a/src/Win32/CreationFlags.cs b/src/Win32/CreationFlags.cs index b89b70d..b9c7529 100644 --- a/src/Win32/CreationFlags.cs +++ b/src/Win32/CreationFlags.cs @@ -1,8 +1,9 @@ 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; +[Flags] +public enum CreationFlags : uint { + CreateSuspended = 0x00000004, + DetachedProcess = 0x00000008, + CreateNoWindow = 0x08000000, + ExtendedStartupInfoPresent = 0x00080000 } diff --git a/src/Win32/MemoryProtection.cs b/src/Win32/MemoryProtection.cs index 2b3559c..d6899ec 100644 --- a/src/Win32/MemoryProtection.cs +++ b/src/Win32/MemoryProtection.cs @@ -1,15 +1,16 @@ -namespace YaeAchievement.Win32; +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; +[Flags] +public enum MemoryProtection : uint { + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + ExecuteWriteCopy = 0x80, + NoAccess = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08, + GuardModifierFlag = 0x100, + NoCacheModifierFlag = 0x200, + WriteCombineModifierFlag = 0x400 } diff --git a/src/Win32/Native.cs b/src/Win32/Native.cs index 4141ce8..4387b5f 100644 --- a/src/Win32/Native.cs +++ b/src/Win32/Native.cs @@ -14,7 +14,7 @@ public static class Native { ref SecurityAttributes lpProcessAttributes, ref SecurityAttributes lpThreadAttributes, bool bInheritHandles, - int dwCreationFlags, + CreationFlags dwCreationFlags, IntPtr lpEnvironment, string? lpCurrentDirectory, [In] ref StartupInfo lpStartupInfo, @@ -46,12 +46,12 @@ public static class Native { IntPtr hProcess, IntPtr lpAddress, int dwSize, - int flAllocationType, - int flProtect + AllocationType flAllocationType, + MemoryProtection flProtect ); [DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)] - public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int dwFreeType); + public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType); [DllImport("kernel32.dll", SetLastError = true)] public static extern uint ResumeThread(IntPtr hThread); diff --git a/src/Win32/ProcessInformation.cs b/src/Win32/ProcessInformation.cs index 10281ca..192a5e3 100644 --- a/src/Win32/ProcessInformation.cs +++ b/src/Win32/ProcessInformation.cs @@ -9,6 +9,6 @@ namespace YaeAchievement.Win32; public struct ProcessInformation { public IntPtr hProcess; public IntPtr hThread; - public int dwProcessId; - public int dwThreadId; + public uint dwProcessID; + public uint dwThreadID; } diff --git a/src/Win32/StartupInfo.cs b/src/Win32/StartupInfo.cs index 6400a02..89c46eb 100644 --- a/src/Win32/StartupInfo.cs +++ b/src/Win32/StartupInfo.cs @@ -7,20 +7,20 @@ namespace YaeAchievement.Win32; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct StartupInfo { - public int cb; + public uint 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 uint dwX; + public uint dwY; + public uint dwXSize; + public uint dwYSize; + public uint dwXCountChars; + public uint dwYCountChars; + public uint dwFillAttribute; + public uint dwFlags; + public ushort wShowWindow; + public ushort cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput;