Fix project name, detect runtime type of process

This commit is contained in:
HoLLy 2021-04-03 00:37:35 +02:00
Родитель 469ed838da
Коммит 2d8f8508de
10 изменённых файлов: 257 добавлений и 5 удалений

Просмотреть файл

@ -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