Fix project name, detect runtime type of process
This commit is contained in:
Родитель
469ed838da
Коммит
2d8f8508de
|
@ -0,0 +1,13 @@
|
|||
using CommandLine;
|
||||
|
||||
namespace ManagedInjector.CLI
|
||||
{
|
||||
public class CliOptions
|
||||
{
|
||||
[Option('n', "name", Group = "process", Required = true, HelpText = "Specifies the target process name")]
|
||||
public string? ProcessName { get; set; }
|
||||
|
||||
[Option('p', "pid", Group = "process", Required = true, HelpText = "Specifies the target process id")]
|
||||
public int? ProcessId { get; set; }
|
||||
}
|
||||
}
|
|
@ -8,7 +8,11 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ManagedInjectior.Lib\ManagedInjectior.Lib.csproj" />
|
||||
<ProjectReference Include="..\ManagedInjector.Lib\ManagedInjector.Lib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using CommandLine;
|
||||
using HoLLy.ManagedInjector;
|
||||
|
||||
namespace ManagedInjector.CLI
|
||||
{
|
||||
|
@ -6,7 +10,52 @@ namespace ManagedInjector.CLI
|
|||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
var result = Parser.Default.ParseArguments<CliOptions>(args)
|
||||
.WithParsed(Run);
|
||||
}
|
||||
|
||||
private static void Run(CliOptions cli)
|
||||
{
|
||||
int pid = GetProcessId(cli);
|
||||
var process = new InjectableProcess(pid);
|
||||
|
||||
Console.WriteLine("PID: " + pid);
|
||||
Console.WriteLine("Status: " + process.GetStatus());
|
||||
Console.WriteLine("Arch: " + process.GetArchitecture());
|
||||
|
||||
if (process.GetStatus() != ProcessStatus.Ok)
|
||||
throw new Exception("Expected OK status for process");
|
||||
}
|
||||
|
||||
private static int GetProcessId(CliOptions cli)
|
||||
{
|
||||
if (cli.ProcessName is not null)
|
||||
{
|
||||
var processes = Process.GetProcessesByName(cli.ProcessName);
|
||||
|
||||
if (processes.Length == 0)
|
||||
{
|
||||
var message = $"Could not find process by name '{cli.ProcessName}'.";
|
||||
|
||||
bool hasExtension = cli.ProcessName.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (hasExtension)
|
||||
message += " Make sure not to add a file extension.";
|
||||
|
||||
throw new Exception(message);
|
||||
}
|
||||
|
||||
if (processes.Length > 1)
|
||||
throw new Exception($"Multiple processes found by name '{cli.ProcessName}'.");
|
||||
|
||||
return processes.Single().Id;
|
||||
}
|
||||
|
||||
if (cli.ProcessId is not null)
|
||||
{
|
||||
return cli.ProcessId.Value;
|
||||
}
|
||||
|
||||
throw new Exception("No target process found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace HoLLy.ManagedInjector
|
||||
{
|
||||
public class InjectableProcess : IDisposable
|
||||
{
|
||||
private readonly int _pid;
|
||||
private IntPtr _handle;
|
||||
private ProcessStatus _status = ProcessStatus.Unknown;
|
||||
private ProcessArchitecture _architecture = ProcessArchitecture.Unknown;
|
||||
|
||||
public InjectableProcess(int pid)
|
||||
{
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
public ProcessStatus GetStatus()
|
||||
{
|
||||
if (_status != ProcessStatus.Unknown)
|
||||
return _status;
|
||||
|
||||
var handle = GetHandle();
|
||||
|
||||
if (NativeHelper.In64BitProcess != NativeHelper.Is64BitProcess(handle))
|
||||
return _status = ProcessStatus.ArchitectureMismatch;
|
||||
|
||||
if (GetArchitecture() == ProcessArchitecture.Unknown)
|
||||
return _status = ProcessStatus.NoRuntimeFound;
|
||||
|
||||
return _status = ProcessStatus.Ok;
|
||||
}
|
||||
|
||||
public ProcessArchitecture GetArchitecture()
|
||||
{
|
||||
if (_architecture != ProcessArchitecture.Unknown)
|
||||
return _architecture;
|
||||
|
||||
// TODO: no architectures detected yet
|
||||
using var process = Process.GetProcessById(_pid);
|
||||
|
||||
bool HasModule(string s) => process.Modules.OfType<ProcessModule>().Any(x => x.ModuleName.Equals(s, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
// .NET 2 has mscoree and mscorwks
|
||||
// .NET 4 has mscoree and clr
|
||||
// .NET Core 3.1 has coreclr
|
||||
// Some unity games have mono-2.0-bdwgc.dll
|
||||
|
||||
if (HasModule("mscoree.dll"))
|
||||
{
|
||||
if (HasModule("clr.dll"))
|
||||
return _architecture = ProcessArchitecture.NetFrameworkV4;
|
||||
|
||||
if (HasModule("mscorwks.dll"))
|
||||
return _architecture = ProcessArchitecture.NetFrameworkV2;
|
||||
}
|
||||
|
||||
if (HasModule("coreclr.dll"))
|
||||
return _architecture = ProcessArchitecture.NetCore;
|
||||
|
||||
// TODO: also check non-bleeding mono dll
|
||||
if (HasModule("mono-2.0-bdwgc.dll"))
|
||||
return _architecture = ProcessArchitecture.Mono;
|
||||
|
||||
return ProcessArchitecture.Unknown;
|
||||
}
|
||||
|
||||
private IntPtr GetHandle()
|
||||
{
|
||||
if (_handle == IntPtr.Zero)
|
||||
_handle = Native.OpenProcess(Native.ProcessAccessFlags.QueryInformation, false, _pid);
|
||||
|
||||
return _handle;
|
||||
}
|
||||
|
||||
private void ReleaseUnmanagedResources()
|
||||
{
|
||||
if (_handle != IntPtr.Zero)
|
||||
Native.CloseHandle(_handle);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReleaseUnmanagedResources();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~InjectableProcess()
|
||||
{
|
||||
ReleaseUnmanagedResources();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>9</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<RootNamespace>HoLLy.ManagedInjectior</RootNamespace>
|
||||
<RootNamespace>HoLLy.ManagedInjector</RootNamespace>
|
||||
|
||||
<PackageId>HoLLy.ManagedInjector</PackageId>
|
||||
<Authors>HoLLy</Authors>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HoLLy.ManagedInjector
|
||||
{
|
||||
internal static class Native
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle,
|
||||
int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool IsWow64Process(IntPtr processHandle, out bool wow64Process);
|
||||
|
||||
[Flags]
|
||||
public enum ProcessAccessFlags : uint
|
||||
{
|
||||
Terminate = 0x0001,
|
||||
CreateThread = 0x0002,
|
||||
VirtualMemoryOperation = 0x0008,
|
||||
VirtualMemoryRead = 0x0010,
|
||||
VirtualMemoryWrite = 0x0020,
|
||||
DuplicateHandle = 0x0040,
|
||||
CreateProcess = 0x0080,
|
||||
SetQuota = 0x0100,
|
||||
SetInformation = 0x0200,
|
||||
QueryInformation = 0x0400,
|
||||
QueryLimitedInformation = 0x1000,
|
||||
|
||||
Synchronize = 0x0010_0000,
|
||||
|
||||
//All = 0x001F_0FFF,
|
||||
All = Terminate | CreateThread | 0x0004 | VirtualMemoryOperation
|
||||
| VirtualMemoryRead | VirtualMemoryWrite | DuplicateHandle | CreateProcess
|
||||
| SetQuota | SetInformation | QueryInformation | 0x0800
|
||||
| 0x001F_0000,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace HoLLy.ManagedInjector
|
||||
{
|
||||
internal static class NativeHelper
|
||||
{
|
||||
public static bool In64BitProcess { get; } = Is64BitProcess();
|
||||
public static bool In64BitMachine { get; } = Is64BitMachine();
|
||||
|
||||
public static bool Is64BitProcess(IntPtr handle) => Is64BitMachine() && !IsWow64Process(handle);
|
||||
|
||||
private static bool IsWow64Process(IntPtr handle) => Native.IsWow64Process(handle, out bool wow64) && wow64;
|
||||
private static bool Is64BitMachine() => In64BitProcess || IsWow64Process(Process.GetCurrentProcess().Handle);
|
||||
private static bool Is64BitProcess() => IntPtr.Size == 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace HoLLy.ManagedInjector
|
||||
{
|
||||
public enum ProcessArchitecture
|
||||
{
|
||||
Unknown,
|
||||
NetFrameworkV2,
|
||||
NetFrameworkV4,
|
||||
NetCore,
|
||||
Mono,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
namespace HoLLy.ManagedInjector
|
||||
{
|
||||
public enum ProcessStatus
|
||||
{
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// DLL injection is supported in this process
|
||||
/// </summary>
|
||||
Ok,
|
||||
|
||||
/// <summary>
|
||||
/// The target process is 32-bit, while the host process is 64-bit (or vice versa).
|
||||
/// </summary>
|
||||
ArchitectureMismatch,
|
||||
|
||||
/// <summary>
|
||||
/// No supported .NET runtime was found in the target process.
|
||||
/// </summary>
|
||||
NoRuntimeFound,
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedInjectior.Lib", "ManagedInjectior.Lib\ManagedInjectior.Lib.csproj", "{FFAB3771-5AF9-431C-B3B8-39B8C79E791C}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedInjector.Lib", "ManagedInjector.Lib\ManagedInjector.Lib.csproj", "{FFAB3771-5AF9-431C-B3B8-39B8C79E791C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedInjector.CLI", "ManagedInjector.CLI\ManagedInjector.CLI.csproj", "{4F7965E3-6CCE-45BA-9321-E07A0D08EC7F}"
|
||||
EndProject
|
Загрузка…
Ссылка в новой задаче