mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-07-15 15:19:57 +00:00
Revert injector extraction (#504)
* Revert "Extract injector to its own process (#503)"
This reverts commit 9dbe4c5eaf.
* Revert injector extraction
This commit is contained in:
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user