Revert injector extraction (#504)

* Revert "Extract injector to its own process (#503)"

This reverts commit 9dbe4c5eaf.

* Revert injector extraction
This commit is contained in:
2023-12-04 14:54:34 +01:00
committed by GitHub
parent 9dbe4c5eaf
commit 29fe12f094
7 changed files with 129 additions and 313 deletions
+1 -6
View File
@@ -20,7 +20,7 @@ jobs:
strategy:
matrix:
targetplatform: [x64]
targetplatform: [x86]
runs-on: windows-latest
@@ -97,11 +97,6 @@ jobs:
env:
RuntimeIdentifier: win-${{ matrix.targetplatform }}
- name: Create publish injector files
run: dotnet publish .\Daybreak.Injector\Daybreak.Injector.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=false --self-contained true -o .\Publish
env:
RuntimeIdentifier: win-x86
- name: Pack publish files
run: |
Write-Host $env
@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Platforms>AnyCPU;x86;x64</Platforms>
<Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
-52
View File
@@ -1,52 +0,0 @@
using System.Runtime.InteropServices;
namespace Daybreak.Injector;
internal static class NativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", 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,
IntPtr dwSize,
uint dwAllocationType,
uint dwProtect);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern bool VirtualFreeEx(
IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
uint dwFreeType);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetExitCodeThread(IntPtr hHandle, out IntPtr dwMilliseconds);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
IntPtr lpBuffer,
int nSize,
out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
IntPtr lpBuffer,
int nSize,
out IntPtr lpNumberOfBytesRead);
}
-191
View File
@@ -1,191 +0,0 @@
// See https://aka.ms/new-console-template for more information
using Daybreak.Injector;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
static bool InjectWithWinApi(Process process, string pathToDll)
{
string modulefullpath = Path.GetFullPath(pathToDll);
if (!File.Exists(modulefullpath))
{
Console.WriteLine("Dll to inject not found");
return false;
}
nint hKernel32 = NativeMethods.GetModuleHandle("kernel32.dll");
if (hKernel32 == IntPtr.Zero)
{
Console.WriteLine("Unable to get a handle of kernel32.dll");
return false;
}
nint hLoadLib = NativeMethods.GetProcAddress(hKernel32, "LoadLibraryW");
if (hLoadLib == IntPtr.Zero)
{
Console.WriteLine("Unable to get the address of LoadLibraryW");
return false;
}
nint hStringBuffer = NativeMethods.VirtualAllocEx(process.Handle, IntPtr.Zero, new IntPtr(2 * (modulefullpath.Length + 1)),
0x3000 /* MEM_COMMIT | MEM_RESERVE */, 0x4 /* PAGE_READWRITE */);
if (hStringBuffer == IntPtr.Zero)
{
Console.WriteLine("Unable to allocate memory for module path");
return false;
}
WriteWString(process, hStringBuffer, modulefullpath);
if (ReadWString(process, hStringBuffer, 260) != modulefullpath)
{
Console.WriteLine("Module path string is not correct");
return false;
}
nint hThread = NativeMethods.CreateRemoteThread(process.Handle, IntPtr.Zero, 0, hLoadLib, hStringBuffer, 0, out _);
if (hThread == IntPtr.Zero)
{
Console.WriteLine("Unable to create remote thread");
return false;
}
uint threadResult = NativeMethods.WaitForSingleObject(hThread, 30000u);
if (threadResult is 0x102 or 0xFFFFFFFF /* WAIT_FAILED */)
{
Console.WriteLine($"Exception occurred while waiting for the remote thread. Result is {threadResult}");
return false;
}
uint dllResult = NativeMethods.GetExitCodeThread(hThread, out _);
if (dllResult == 0)
{
Console.WriteLine($"Injected dll returned non-success status code {dllResult}");
return false;
}
bool memoryFreeResult = NativeMethods.VirtualFreeEx(process.Handle, hStringBuffer, 0, 0x8000 /* MEM_RELEASE */);
if (!memoryFreeResult)
{
Console.WriteLine($"Failed to free dll memory");
}
return memoryFreeResult;
}
static void WriteBytes(Process process, IntPtr address, byte[] data)
{
int size = data.Length;
nint buffer = Marshal.AllocHGlobal(size);
Marshal.Copy(data, 0, buffer, size);
_ = NativeMethods.WriteProcessMemory(
process.Handle,
address,
buffer,
size,
out _);
Marshal.FreeHGlobal(buffer);
}
static void WriteWString(Process process, IntPtr address, string data)
{
WriteBytes(process, address, Encoding.Unicode.GetBytes(data));
}
static string ReadWString(Process process, IntPtr address, int maxsize, Encoding? encoding = null)
{
encoding ??= Encoding.Unicode;
byte[] rawbytes = ReadBytes(process, address, maxsize);
if (rawbytes.Length == 0)
{
return "";
}
string ret = encoding.GetString(rawbytes);
if (ret.Contains('\0'))
{
ret = ret[..ret.IndexOf('\0')];
}
return ret;
}
static byte[] ReadBytes(Process process, IntPtr address, int size)
{
nint buffer = Marshal.AllocHGlobal(size);
_ = NativeMethods.ReadProcessMemory(process.Handle,
address,
buffer,
size,
out _
);
byte[] ret = new byte[size];
Marshal.Copy(buffer, ret, 0, size);
Marshal.FreeHGlobal(buffer);
return ret;
}
Console.WriteLine("Hello, World!");
int processId = -1;
string filePath = string.Empty;
for (int i = 0; i < args.Length; i++)
{
if (args[i] is "-p" or "--processId")
{
i++;
if (!int.TryParse(args[i], out int id))
{
Console.WriteLine($"Unable to parce process id {args[i]}");
return 1;
}
processId = id;
}
else if (args[i] is "-f" or "--filePath")
{
i++;
filePath = args[i];
}
else
{
Console.WriteLine($"Unknown argument {args[i]} {args[(i + 1) % args.Length]}");
return 1;
}
}
if (processId is -1)
{
Console.WriteLine("Must specify target process with -p [id]");
return 1;
}
if (string.IsNullOrWhiteSpace(filePath))
{
Console.WriteLine("Must specify dll to inject with -f [filePath]");
return 1;
}
Process process = default!;
try
{
process = Process.GetProcessById(processId);
}
catch
{
Console.WriteLine($"Failed to get process with id {processId}");
return 1;
}
if (!InjectWithWinApi(process, filePath))
{
Console.WriteLine("Injection failed");
return 1;
}
Console.WriteLine("Injection success");
return 0;
+6 -20
View File
@@ -34,8 +34,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.7ZipExtractor", "Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj", "{CA60F9AC-A496-4DB6-970E-ECE73B051C05}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.Injector", "Daybreak.Injector\Daybreak.Injector.csproj", "{61CFB42E-947A-48AE-9F3C-4DF685882B1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -72,8 +70,8 @@ Global
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x86.Build.0 = Release|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.ActiveCfg = Debug|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.ActiveCfg = Debug|x64
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|x64
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x86.ActiveCfg = Debug|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x86.Build.0 = Debug|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -84,28 +82,16 @@ Global
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.Build.0 = Release|x86
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x64.ActiveCfg = Debug|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x64.Build.0 = Debug|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x64.ActiveCfg = Debug|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x64.Build.0 = Debug|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x86.ActiveCfg = Debug|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Debug|x86.Build.0 = Debug|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|Any CPU.Build.0 = Release|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x64.ActiveCfg = Release|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x64.Build.0 = Release|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x64.ActiveCfg = Release|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x64.Build.0 = Release|Any CPU
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x86.ActiveCfg = Release|x64
{CA60F9AC-A496-4DB6-970E-ECE73B051C05}.Release|x86.Build.0 = Release|x64
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Debug|x64.ActiveCfg = Debug|x86
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Debug|x64.Build.0 = Debug|x86
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Debug|x86.ActiveCfg = Debug|x86
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Debug|x86.Build.0 = Debug|x86
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Release|Any CPU.Build.0 = Release|Any CPU
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Release|x64.ActiveCfg = Release|Any CPU
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Release|x64.Build.0 = Release|Any CPU
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Release|x86.ActiveCfg = Release|x86
{61CFB42E-947A-48AE-9F3C-4DF685882B1D}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+1 -1
View File
@@ -12,7 +12,7 @@
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.8.158</Version>
<Version>0.9.8.159</Version>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+121 -30
View File
@@ -1,8 +1,12 @@
using Microsoft.Extensions.Logging;
using Daybreak.Utils;
using Microsoft.Extensions.Logging;
using System;
using System.Core.Extensions;
using System.Diagnostics;
using System.Extensions;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -17,51 +21,138 @@ internal sealed class ProcessInjector : IProcessInjector
this.logger = logger.ThrowIfNull();
}
public async Task<bool> Inject(Process process, string pathToDll, CancellationToken cancellationToken)
public Task<bool> Inject(Process process, string pathToDll, CancellationToken cancellationToken)
{
return await this.InjectWithWinApi(process, pathToDll, cancellationToken);
return Task.Factory.StartNew(() =>
{
return this.InjectWithWinApi(process, pathToDll);
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
}
private async Task<bool> InjectWithWinApi(Process process, string pathToDll, CancellationToken cancellationToken)
private bool InjectWithWinApi(Process process, string pathToDll)
{
var scopedLogger = this.logger.CreateScopedLogger(nameof(InjectWithWinApi), pathToDll);
if (!File.Exists(pathToDll))
var modulefullpath = Path.GetFullPath(pathToDll);
if (!File.Exists(modulefullpath))
{
scopedLogger.LogError("File does not exist");
scopedLogger.LogError("Dll to inject not found");
return false;
}
if (process is null)
var hKernel32 = NativeMethods.GetModuleHandle("kernel32.dll");
if (hKernel32 == IntPtr.Zero)
{
scopedLogger.LogError("Provided process is null");
scopedLogger.LogError("Unable to get a handle of kernel32.dll");
return false;
}
var injectionProcess = new Process()
var hLoadLib = NativeMethods.GetProcAddress(hKernel32, "LoadLibraryW");
if (hLoadLib == IntPtr.Zero)
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
FileName = Path.GetFullPath("Daybreak.Injector.exe"),
UseShellExecute = false,
Arguments = $"-p {process.Id} -f {pathToDll}"
}
};
injectionProcess.Start();
await injectionProcess.WaitForExitAsync(cancellationToken);
var output = await injectionProcess.StandardOutput.ReadToEndAsync(cancellationToken);
var error = await injectionProcess.StandardError.ReadToEndAsync(cancellationToken);
if (injectionProcess.ExitCode != 0)
{
scopedLogger.LogError($"Failed to inject\nOutput: {output}\nError: {error}");
scopedLogger.LogError("Unable to get the address of LoadLibraryW");
return false;
}
scopedLogger.LogInformation("Injected");
return true;
var hStringBuffer = NativeMethods.VirtualAllocEx(process.Handle, IntPtr.Zero, new IntPtr(2 * (modulefullpath.Length + 1)),
0x3000 /* MEM_COMMIT | MEM_RESERVE */, 0x4 /* PAGE_READWRITE */);
if (hStringBuffer == IntPtr.Zero)
{
scopedLogger.LogError("Unable to allocate memory for module path");
return false;
}
WriteWString(process, hStringBuffer, modulefullpath);
if (ReadWString(process, hStringBuffer, 260) != modulefullpath)
{
scopedLogger.LogError("Module path string is not correct");
return false;
}
var hThread = NativeMethods.CreateRemoteThread(process.Handle, IntPtr.Zero, 0, hLoadLib, hStringBuffer, 0, out _);
if (hThread == IntPtr.Zero)
{
scopedLogger.LogError("Unable to create remote thread");
return false;
}
var threadResult = NativeMethods.WaitForSingleObject(hThread, 30000u);
if (threadResult is 0x102 or 0xFFFFFFFF /* WAIT_FAILED */)
{
scopedLogger.LogError($"Exception occurred while waiting for the remote thread. Result is {threadResult}");
return false;
}
var dllResult = NativeMethods.GetExitCodeThread(hThread, out _);
if (dllResult == 0)
{
scopedLogger.LogError($"Injected dll returned non-success status code {dllResult}");
return false;
}
var memoryFreeResult = NativeMethods.VirtualFreeEx(process.Handle, hStringBuffer, 0, 0x8000 /* MEM_RELEASE */);
if (!memoryFreeResult)
{
scopedLogger.LogError($"Failed to free dll memory");
}
return memoryFreeResult;
}
private static void WriteBytes(Process process, IntPtr address, byte[] data)
{
var size = data.Length;
var buffer = Marshal.AllocHGlobal(size);
Marshal.Copy(data, 0, buffer, size);
NativeMethods.WriteProcessMemory(
process.Handle,
address,
buffer,
size,
out _);
Marshal.FreeHGlobal(buffer);
}
private static void WriteWString(Process process, IntPtr address, string data)
{
WriteBytes(process, address, Encoding.Unicode.GetBytes(data));
}
private static string ReadWString(Process process, IntPtr address, int maxsize, Encoding? encoding = null)
{
encoding ??= Encoding.Unicode;
var rawbytes = ReadBytes(process, address, maxsize);
if (rawbytes.Length == 0)
{
return "";
}
var ret = encoding.GetString(rawbytes);
if (ret.Contains('\0'))
{
ret = ret[..ret.IndexOf('\0')];
}
return ret;
}
private static byte[] ReadBytes(Process process, IntPtr address, int size)
{
var buffer = Marshal.AllocHGlobal(size);
NativeMethods.ReadProcessMemory(process.Handle,
address,
buffer,
size,
out _
);
var ret = new byte[size];
Marshal.Copy(buffer, ret, 0, size);
Marshal.FreeHGlobal(buffer);
return ret;
}
}