mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-15 19:08:12 +08:00
fixup native call
This commit is contained in:
@@ -3,6 +3,7 @@ using System.ComponentModel;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.System.Memory;
|
using Windows.Win32.System.Memory;
|
||||||
using Windows.Win32.System.Threading;
|
using Windows.Win32.System.Threading;
|
||||||
using YaeAchievement.Win32;
|
using YaeAchievement.Win32;
|
||||||
@@ -10,7 +11,7 @@ using YaeAchievement.Win32;
|
|||||||
namespace YaeAchievement;
|
namespace YaeAchievement;
|
||||||
|
|
||||||
public static class Injector {
|
public static class Injector {
|
||||||
public static unsafe bool CreateProcess(string path, out SafeHandle hProc, out SafeHandle hThread, out uint pid) {
|
public static unsafe bool CreateProcess(string path, out HANDLE hProc, out HANDLE hThread, out uint pid) {
|
||||||
Span<char> cmdLines = stackalloc char[1]; // "\0"
|
Span<char> cmdLines = stackalloc char[1]; // "\0"
|
||||||
var si = new STARTUPINFOW() { cb = unchecked((uint)sizeof(STARTUPINFOW)) };
|
var si = new STARTUPINFOW() { cb = unchecked((uint)sizeof(STARTUPINFOW)) };
|
||||||
var dir = Path.GetDirectoryName(path)!;
|
var dir = Path.GetDirectoryName(path)!;
|
||||||
@@ -19,53 +20,58 @@ public static class Injector {
|
|||||||
PROCESS_CREATION_FLAGS.CREATE_SUSPENDED, default, dir, in si, out var pi
|
PROCESS_CREATION_FLAGS.CREATE_SUSPENDED, default, dir, in si, out var pi
|
||||||
);
|
);
|
||||||
pid = pi.dwProcessId;
|
pid = pi.dwProcessId;
|
||||||
hProc = new SafeFileHandle(pi.hProcess, true);
|
hProc = pi.hProcess;
|
||||||
hThread = new SafeFileHandle(pi.hThread, true);
|
hThread = pi.hThread;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: refactor
|
// todo: refactor
|
||||||
public static unsafe int LoadLibraryAndInject(SafeHandle hProc, string libPath)
|
public static unsafe int LoadLibraryAndInject(HANDLE hProc, ReadOnlySpan<byte> libPath)
|
||||||
{
|
{
|
||||||
var hKernel = Native.GetModuleHandle("kernel32.dll");
|
fixed (char* lpModelName = "kernel32.dll")
|
||||||
if (hKernel.IsInvalid)
|
|
||||||
{
|
{
|
||||||
return new Win32Exception().PrintMsgAndReturnErrCode("GetModuleHandle fail");
|
HINSTANCE hKernel = Native.GetModuleHandle(lpModelName);
|
||||||
}
|
|
||||||
var pLoadLibrary = Native.GetProcAddress(hKernel, "LoadLibraryA");
|
|
||||||
if (pLoadLibrary.IsNull)
|
|
||||||
{
|
|
||||||
return new Win32Exception().PrintMsgAndReturnErrCode("GetProcAddress fail");
|
|
||||||
}
|
|
||||||
var pBase = Native.VirtualAllocEx(hProc, default, unchecked((uint)libPath.Length + 1), VIRTUAL_ALLOCATION_TYPE.MEM_RESERVE | VIRTUAL_ALLOCATION_TYPE.MEM_COMMIT, PAGE_PROTECTION_FLAGS.PAGE_READWRITE);
|
|
||||||
if ((nint)pBase == 0)
|
|
||||||
{
|
|
||||||
return new Win32Exception().PrintMsgAndReturnErrCode("VirtualAllocEx fail");
|
|
||||||
}
|
|
||||||
fixed (void* lpBuffer = libPath.ToCharArray())
|
|
||||||
{
|
|
||||||
if (!Native.WriteProcessMemory(hProc, pBase, lpBuffer, unchecked((uint)libPath.Length), default))
|
|
||||||
{
|
|
||||||
return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var lpStartAddress = pLoadLibrary.CreateDelegate<LPTHREAD_START_ROUTINE>();
|
|
||||||
|
|
||||||
using (var hThread = Native.CreateRemoteThread(hProc, default, 0, lpStartAddress, pBase, 0, default))
|
if (hKernel.IsNull)
|
||||||
{
|
|
||||||
if (hThread.IsInvalid)
|
|
||||||
{
|
{
|
||||||
var e = new Win32Exception();
|
return new Win32Exception().PrintMsgAndReturnErrCode("GetModuleHandle fail");
|
||||||
Native.VirtualFreeEx(hProc, pBase, 0, VIRTUAL_FREE_TYPE.MEM_RELEASE);
|
|
||||||
return e.PrintMsgAndReturnErrCode("CreateRemoteThread fail");
|
|
||||||
}
|
}
|
||||||
if (Native.WaitForSingleObject(hThread, 2000) == 0)
|
|
||||||
|
fixed(byte* lpProcName = "LoadLibraryA"u8)
|
||||||
{
|
{
|
||||||
Native.VirtualFreeEx(hProc, pBase, 0, VIRTUAL_FREE_TYPE.MEM_RELEASE);
|
var pLoadLibrary = Native.GetProcAddress(hKernel, (PCSTR)lpProcName);
|
||||||
|
if (pLoadLibrary.IsNull)
|
||||||
|
{
|
||||||
|
return new Win32Exception().PrintMsgAndReturnErrCode("GetProcAddress fail");
|
||||||
|
}
|
||||||
|
var pBase = Native.VirtualAllocEx(hProc, default, unchecked((uint)libPath.Length + 1), VIRTUAL_ALLOCATION_TYPE.MEM_RESERVE | VIRTUAL_ALLOCATION_TYPE.MEM_COMMIT, PAGE_PROTECTION_FLAGS.PAGE_READWRITE);
|
||||||
|
if ((nint)pBase == 0)
|
||||||
|
{
|
||||||
|
return new Win32Exception().PrintMsgAndReturnErrCode("VirtualAllocEx fail");
|
||||||
|
}
|
||||||
|
fixed (void* lpBuffer = libPath)
|
||||||
|
{
|
||||||
|
if (!Native.WriteProcessMemory(hProc, pBase, lpBuffer, unchecked((uint)libPath.Length), default))
|
||||||
|
{
|
||||||
|
return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lpStartAddress = pLoadLibrary.CreateDelegate<LPTHREAD_START_ROUTINE>();
|
||||||
|
var hThread = Native.CreateRemoteThread(hProc, default, 0, lpStartAddress, pBase, 0, default);
|
||||||
|
|
||||||
|
if (hThread.IsNull)
|
||||||
|
{
|
||||||
|
var e = new Win32Exception();
|
||||||
|
Native.VirtualFreeEx(hProc, pBase, 0, VIRTUAL_FREE_TYPE.MEM_RELEASE);
|
||||||
|
return e.PrintMsgAndReturnErrCode("CreateRemoteThread fail");
|
||||||
|
}
|
||||||
|
if (Native.WaitForSingleObject(hThread, 2000) == 0)
|
||||||
|
{
|
||||||
|
Native.VirtualFreeEx(hProc, pBase, 0, VIRTUAL_FREE_TYPE.MEM_RELEASE);
|
||||||
|
}
|
||||||
|
return !Native.CloseHandle(hThread) ? new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail") : 0;
|
||||||
}
|
}
|
||||||
//return !Native.CloseHandle(hThread) ? new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail") : 0;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||||
"className": "Native",
|
"className": "Native",
|
||||||
"allowMarshaling": true,
|
"allowMarshaling": true,
|
||||||
"public": false
|
"public": true
|
||||||
}
|
}
|
||||||
79
src/Utils.cs
79
src/Utils.cs
@@ -5,7 +5,8 @@ using System.IO.Pipes;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.System.Console;
|
using Windows.Win32.System.Console;
|
||||||
@@ -68,17 +69,20 @@ public static class Utils {
|
|||||||
return value != null && bool.TryParse(value, out var result) && result;
|
return value != null && bool.TryParse(value, out var result) && result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows5.0")]
|
|
||||||
public static unsafe void CopyToClipboard(string text) {
|
public static unsafe void CopyToClipboard(string text) {
|
||||||
if (Native.OpenClipboard(HWND.Null)) {
|
if (Native.OpenClipboard(HWND.Null))
|
||||||
|
{
|
||||||
Native.EmptyClipboard();
|
Native.EmptyClipboard();
|
||||||
Span<char> textSpan = text.ToCharArray();
|
HANDLE hGlobal = (HANDLE)Marshal.AllocHGlobal((text.Length + 1) * 2);
|
||||||
fixed (char* lpBuffer = textSpan)
|
IntPtr hPtr = (IntPtr)Native.GlobalLock(hGlobal);
|
||||||
{
|
Marshal.Copy(text.ToCharArray(), 0, hPtr, text.Length);
|
||||||
Native.SetClipboardData(/*CF_UNICODETEXT*/13, (HANDLE)(nint)lpBuffer);
|
Native.GlobalUnlock(hPtr);
|
||||||
Native.CloseClipboard();
|
Native.SetClipboardData(13, hGlobal);
|
||||||
}
|
Marshal.FreeHGlobal(hGlobal);
|
||||||
} else {
|
Native.CloseClipboard();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
throw new Win32Exception();
|
throw new Win32Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,37 +231,38 @@ public static class Utils {
|
|||||||
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
|
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
|
||||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
|
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
|
||||||
}
|
}
|
||||||
using (hProcess)
|
if (Injector.LoadLibraryAndInject(hProcess,Encoding.UTF8.GetBytes(GlobalVars.LibFilePath)) != 0)
|
||||||
{
|
{
|
||||||
if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibFilePath) != 0)
|
if (!Native.TerminateProcess(hProcess, 0))
|
||||||
{
|
{
|
||||||
if (!Native.TerminateProcess(hProcess, 0))
|
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
|
||||||
{
|
|
||||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Console.WriteLine(App.GameLoading, pid);
|
|
||||||
proc = Process.GetProcessById(Convert.ToInt32(pid));
|
|
||||||
proc.EnableRaisingEvents = true;
|
|
||||||
proc.Exited += (_, _) => {
|
|
||||||
if (GlobalVars.UnexpectedExit)
|
|
||||||
{
|
|
||||||
proc = null;
|
|
||||||
Console.WriteLine(App.GameProcessExit);
|
|
||||||
Environment.Exit(114514);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
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"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Console.WriteLine(App.GameLoading, pid);
|
||||||
|
proc = Process.GetProcessById(Convert.ToInt32(pid));
|
||||||
|
proc.EnableRaisingEvents = true;
|
||||||
|
proc.Exited += (_, _) => {
|
||||||
|
if (GlobalVars.UnexpectedExit)
|
||||||
|
{
|
||||||
|
proc = null;
|
||||||
|
Console.WriteLine(App.GameProcessExit);
|
||||||
|
Environment.Exit(114514);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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 ts = new ThreadStart(() => {
|
var ts = new ThreadStart(() => {
|
||||||
var server = new NamedPipeServerStream(GlobalVars.PipeName);
|
var server = new NamedPipeServerStream(GlobalVars.PipeName);
|
||||||
server.WaitForConnection();
|
server.WaitForConnection();
|
||||||
|
|||||||
Reference in New Issue
Block a user