Convert to new namespace stuff and implicit usings
This commit is contained in:
@@ -3,54 +3,53 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Prospect.Launcher.Invoke;
|
||||
|
||||
namespace Prospect.Launcher
|
||||
namespace Prospect.Launcher;
|
||||
|
||||
public static class Inject
|
||||
{
|
||||
public static class Inject
|
||||
{
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 4;
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 4;
|
||||
|
||||
// https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
|
||||
public static unsafe bool Library(uint processId, string path)
|
||||
// https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
|
||||
public static unsafe bool Library(uint processId, string path)
|
||||
{
|
||||
IntPtr procHandle = Kernel32.OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, (int)processId);
|
||||
|
||||
var loadLibraryAddr = Kernel32.GetProcAddress(Kernel32.GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
||||
if (loadLibraryAddr == IntPtr.Zero)
|
||||
{
|
||||
IntPtr procHandle = Kernel32.OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, (int)processId);
|
||||
|
||||
var loadLibraryAddr = Kernel32.GetProcAddress(Kernel32.GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
||||
if (loadLibraryAddr == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed GetProcAddress.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var allocMemAddress = Kernel32.VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((path.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (allocMemAddress == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed VirtualAllocEx.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var libraryBytes = Encoding.Default.GetBytes(path);
|
||||
|
||||
fixed (byte* pLibraryBytes = libraryBytes)
|
||||
{
|
||||
Kernel32.WriteProcessMemory(procHandle, allocMemAddress, pLibraryBytes, libraryBytes.Length + 1, out _);
|
||||
}
|
||||
|
||||
var threadHandle = Kernel32.CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);
|
||||
if (threadHandle == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed CreateRemoteThread.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
Console.WriteLine("Failed GetProcAddress.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var allocMemAddress = Kernel32.VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((path.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (allocMemAddress == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed VirtualAllocEx.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var libraryBytes = Encoding.Default.GetBytes(path);
|
||||
|
||||
fixed (byte* pLibraryBytes = libraryBytes)
|
||||
{
|
||||
Kernel32.WriteProcessMemory(procHandle, allocMemAddress, pLibraryBytes, libraryBytes.Length + 1, out _);
|
||||
}
|
||||
|
||||
var threadHandle = Kernel32.CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);
|
||||
if (threadHandle == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed CreateRemoteThread.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,52 +2,51 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
namespace Prospect.Launcher.Invoke
|
||||
namespace Prospect.Launcher.Invoke;
|
||||
|
||||
internal static class Kernel32
|
||||
{
|
||||
internal static class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
|
||||
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 ProcessInformation lpProcessInformation);
|
||||
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
|
||||
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 ProcessInformation lpProcessInformation);
|
||||
|
||||
public static bool CreateProcess(
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
ProcessCreationFlags dwCreationFlags,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation) => CreateProcess(lpApplicationName, lpCommandLine, IntPtr.Zero,
|
||||
IntPtr.Zero, false, dwCreationFlags, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation);
|
||||
public static bool CreateProcess(
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
ProcessCreationFlags dwCreationFlags,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation) => CreateProcess(lpApplicationName, lpCommandLine, IntPtr.Zero,
|
||||
IntPtr.Zero, false, dwCreationFlags, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern unsafe bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte* lpBuffer,
|
||||
Int32 nSize,
|
||||
out IntPtr lpNumberOfBytesWritten
|
||||
);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern unsafe bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte* lpBuffer,
|
||||
Int32 nSize,
|
||||
out IntPtr lpNumberOfBytesWritten
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
}
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
}
|
||||
@@ -1,26 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Prospect.Launcher.Invoke.Structs
|
||||
namespace Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
[Flags]
|
||||
internal enum ProcessCreationFlags : uint
|
||||
{
|
||||
[Flags]
|
||||
internal enum ProcessCreationFlags : uint
|
||||
{
|
||||
ZERO_FLAG = 0x00000000,
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
|
||||
CREATE_NEW_CONSOLE = 0x00000010,
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200,
|
||||
CREATE_NO_WINDOW = 0x08000000,
|
||||
CREATE_PROTECTED_PROCESS = 0x00040000,
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
|
||||
CREATE_SEPARATE_WOW_VDM = 0x00001000,
|
||||
CREATE_SHARED_WOW_VDM = 0x00001000,
|
||||
CREATE_SUSPENDED = 0x00000004,
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
|
||||
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
|
||||
DEBUG_PROCESS = 0x00000001,
|
||||
DETACHED_PROCESS = 0x00000008,
|
||||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
|
||||
INHERIT_PARENT_AFFINITY = 0x00010000
|
||||
}
|
||||
ZERO_FLAG = 0x00000000,
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
|
||||
CREATE_NEW_CONSOLE = 0x00000010,
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200,
|
||||
CREATE_NO_WINDOW = 0x08000000,
|
||||
CREATE_PROTECTED_PROCESS = 0x00040000,
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
|
||||
CREATE_SEPARATE_WOW_VDM = 0x00001000,
|
||||
CREATE_SHARED_WOW_VDM = 0x00001000,
|
||||
CREATE_SUSPENDED = 0x00000004,
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
|
||||
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
|
||||
DEBUG_PROCESS = 0x00000001,
|
||||
DETACHED_PROCESS = 0x00000008,
|
||||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
|
||||
INHERIT_PARENT_AFFINITY = 0x00010000
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Prospect.Launcher.Invoke.Structs
|
||||
namespace Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ProcessInformation
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ProcessInformation
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Prospect.Launcher.Invoke.Structs
|
||||
namespace Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct StartupInfo
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct StartupInfo
|
||||
{
|
||||
public uint cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
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 short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
public uint cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
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 short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
@@ -4,75 +4,74 @@ using System.IO;
|
||||
using Prospect.Launcher.Invoke;
|
||||
using Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
namespace Prospect.Launcher
|
||||
namespace Prospect.Launcher;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
internal static class Program
|
||||
/// <summary>
|
||||
/// Steam AppId.
|
||||
/// - https://steamdb.info/app/480/
|
||||
/// - https://steamdb.info/app/1600360/
|
||||
/// </summary>
|
||||
private const string AppId = "480";
|
||||
|
||||
/// <summary>
|
||||
/// Executable name of the game.
|
||||
/// </summary>
|
||||
private const string FileName = "Prospect-Win64-Shipping.exe";
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam AppId.
|
||||
/// - https://steamdb.info/app/480/
|
||||
/// - https://steamdb.info/app/1600360/
|
||||
/// </summary>
|
||||
private const string AppId = "480";
|
||||
|
||||
/// <summary>
|
||||
/// Executable name of the game.
|
||||
/// </summary>
|
||||
private const string FileName = "Prospect-Win64-Shipping.exe";
|
||||
|
||||
private static void Main(string[] args)
|
||||
if (args.Length != 1)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
Console.WriteLine("Usage: ./Prospect.Launcher <Game directory>");
|
||||
return;
|
||||
}
|
||||
|
||||
var gamePath = Path.Combine(args[0], "Prospect", "Binaries", "Win64");
|
||||
var gameBinary = Path.Combine(gamePath, FileName);
|
||||
var gameArgs = new List<string>();
|
||||
|
||||
// 2EA46 = Default
|
||||
// A22AB = The Cycle Playtest
|
||||
gameArgs.Add("-empty");
|
||||
gameArgs.Add("-log");
|
||||
gameArgs.Add("-windowed");
|
||||
gameArgs.Add("-noeac");
|
||||
gameArgs.Add("-nointro");
|
||||
gameArgs.Add("-steam_auth");
|
||||
gameArgs.Add("PF_TITLEID=A22AB");
|
||||
|
||||
// Ensure "steam_appid.txt" exists, to fix steam authentication.
|
||||
var steamAppId = Path.Combine(gamePath, "steam_appid.txt");
|
||||
|
||||
File.WriteAllText(steamAppId, AppId);
|
||||
|
||||
// Spawn.
|
||||
var startupInfo = new StartupInfo();
|
||||
|
||||
if (!Kernel32.CreateProcess(gameBinary, string.Join(' ', gameArgs), ProcessCreationFlags.CREATE_SUSPENDED, ref startupInfo, out var processInfo))
|
||||
{
|
||||
Console.WriteLine("Failed to spawn game.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Spawned.");
|
||||
|
||||
// Inject DLL.
|
||||
var agentPath = Path.Combine(AppContext.BaseDirectory, "Prospect.Agent.dll");
|
||||
|
||||
if (!Inject.Library(processInfo.dwProcessId, agentPath))
|
||||
{
|
||||
Console.WriteLine("Failed to inject library.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Injected.");
|
||||
|
||||
// Resume.
|
||||
Kernel32.ResumeThread(processInfo.hThread);
|
||||
|
||||
Console.WriteLine("Resumed.");
|
||||
Console.WriteLine("Usage: ./Prospect.Launcher <Game directory>");
|
||||
return;
|
||||
}
|
||||
|
||||
var gamePath = Path.Combine(args[0], "Prospect", "Binaries", "Win64");
|
||||
var gameBinary = Path.Combine(gamePath, FileName);
|
||||
var gameArgs = new List<string>();
|
||||
|
||||
// 2EA46 = Default
|
||||
// A22AB = The Cycle Playtest
|
||||
gameArgs.Add("-empty");
|
||||
gameArgs.Add("-log");
|
||||
gameArgs.Add("-windowed");
|
||||
gameArgs.Add("-noeac");
|
||||
gameArgs.Add("-nointro");
|
||||
gameArgs.Add("-steam_auth");
|
||||
gameArgs.Add("PF_TITLEID=A22AB");
|
||||
|
||||
// Ensure "steam_appid.txt" exists, to fix steam authentication.
|
||||
var steamAppId = Path.Combine(gamePath, "steam_appid.txt");
|
||||
|
||||
File.WriteAllText(steamAppId, AppId);
|
||||
|
||||
// Spawn.
|
||||
var startupInfo = new StartupInfo();
|
||||
|
||||
if (!Kernel32.CreateProcess(gameBinary, string.Join(' ', gameArgs), ProcessCreationFlags.CREATE_SUSPENDED, ref startupInfo, out var processInfo))
|
||||
{
|
||||
Console.WriteLine("Failed to spawn game.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Spawned.");
|
||||
|
||||
// Inject DLL.
|
||||
var agentPath = Path.Combine(AppContext.BaseDirectory, "Prospect.Agent.dll");
|
||||
|
||||
if (!Inject.Library(processInfo.dwProcessId, agentPath))
|
||||
{
|
||||
Console.WriteLine("Failed to inject library.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Injected.");
|
||||
|
||||
// Resume.
|
||||
Kernel32.ResumeThread(processInfo.hThread);
|
||||
|
||||
Console.WriteLine("Resumed.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user