mirror of
https://github.com/k1tbyte/Wand-Enhancer.git
synced 2026-09-03 17:01:03 +00:00
bump version to 1.0.5.0, refactor patching logic, remove unused code
This commit is contained in:
@@ -1,178 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WeModPatcher.Models;
|
||||
using WeModPatcher.Utils.Win32;
|
||||
|
||||
namespace WeModPatcher.Utils
|
||||
{
|
||||
public class MemoryUtils
|
||||
{
|
||||
public static int ScanMemoryBlock(byte[] buffer, int bufferLength, byte[] pattern, byte[] mask)
|
||||
{
|
||||
var patternLength = pattern.Length;
|
||||
if (bufferLength < patternLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make a length of length outside the first cycle for optimization
|
||||
var searchEnd = bufferLength - patternLength;
|
||||
|
||||
// first pass - use the first non-empty byte of the mask for a quick check
|
||||
var firstValidIndex = -1;
|
||||
for (var i = 0; i < patternLength; i++)
|
||||
{
|
||||
if (mask[i] == 1)
|
||||
{
|
||||
firstValidIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstValidIndex == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var firstByte = pattern[firstValidIndex];
|
||||
|
||||
for (var i = 0; i <= searchEnd; i++)
|
||||
{
|
||||
// quick check by the first byte before full comparison
|
||||
if (buffer[i + firstValidIndex] != firstByte)
|
||||
continue;
|
||||
|
||||
var found = true;
|
||||
|
||||
// check only those positions where mask = 1
|
||||
for (var j = 0; j < patternLength; j++)
|
||||
{
|
||||
if (mask[j] == 0 || buffer[i + j] == pattern[j])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void ParseSignature(string signatureStr, out byte[] pattern, out byte[] mask)
|
||||
{
|
||||
var parts = signatureStr.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var length = parts.Length;
|
||||
|
||||
pattern = new byte[length];
|
||||
mask = new byte[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
if (parts[i] == "??" || parts[i] == "?")
|
||||
{
|
||||
pattern[i] = 0;
|
||||
// wildcard byte
|
||||
mask[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
pattern[i] = Convert.ToByte(parts[i], 16);
|
||||
mask[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SafeWriteVirtualMemory(IntPtr hProcess, IntPtr address, byte[] bytes)
|
||||
{
|
||||
if (!Imports.VirtualProtectEx(hProcess, address, (IntPtr)1, 0x40, out uint oldProtect))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = Imports.WriteProcessMemory(hProcess, address, bytes, bytes.Length, out _);
|
||||
|
||||
// Restore the previous access rights
|
||||
Imports.VirtualProtectEx(hProcess, address, (IntPtr)1, oldProtect, out _);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IntPtr ScanVirtualMemory(IntPtr hProcess, IntPtr startAddress, int searchSize, byte[] signature, byte[] mask)
|
||||
{
|
||||
const int BUFFER_SIZE = 4096;
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
|
||||
// We can't copy all the crap of the process into a byte array at once. Don't try this
|
||||
for (long currentAddress = startAddress.ToInt64();
|
||||
currentAddress < startAddress.ToInt64() + searchSize;
|
||||
currentAddress += BUFFER_SIZE - signature.Length)
|
||||
{
|
||||
if (!Imports.ReadProcessMemory(hProcess, new IntPtr(currentAddress), buffer, BUFFER_SIZE, out int bytesRead) || bytesRead == 0)
|
||||
{
|
||||
// Read error or end of memory, throw mb?
|
||||
continue;
|
||||
}
|
||||
|
||||
var i = ScanMemoryBlock(buffer, bytesRead, signature, mask);
|
||||
if (i != -1)
|
||||
{
|
||||
return new IntPtr(currentAddress + i);
|
||||
}
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
public static int PatchFile(string filePath, Signature signature, byte[] patchBytes)
|
||||
{
|
||||
const int bufferSize = 8192;
|
||||
var buffer = new byte[bufferSize + signature.Length - 1];
|
||||
|
||||
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
|
||||
{
|
||||
int filePosition = 0;
|
||||
while (true)
|
||||
{
|
||||
int bytesRead = fileStream.Read(buffer, 0, bufferSize);
|
||||
if (bytesRead == 0) break;
|
||||
|
||||
int matchIndex = ScanMemoryBlock(buffer, bytesRead, signature, signature.Mask);
|
||||
if (matchIndex != -1)
|
||||
{
|
||||
int functionStartPosition = filePosition + matchIndex;
|
||||
|
||||
var checkBuffer = new byte[patchBytes.Length];
|
||||
fileStream.Seek(functionStartPosition + signature.Offset, SeekOrigin.Begin);
|
||||
fileStream.Read(checkBuffer, 0, patchBytes.Length);
|
||||
|
||||
if (checkBuffer.SequenceEqual(patchBytes))
|
||||
{
|
||||
return 0; // Memory already patched
|
||||
}
|
||||
|
||||
// Go to patch position
|
||||
fileStream.Seek(functionStartPosition + signature.Offset, SeekOrigin.Begin);
|
||||
fileStream.Write(patchBytes, 0, patchBytes.Length);
|
||||
|
||||
return functionStartPosition; // Return the address of the function start by signature
|
||||
}
|
||||
|
||||
filePosition += bytesRead;
|
||||
Array.Copy(buffer, bufferSize, buffer, 0, signature.Length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace WeModPatcher.Utils.Win32
|
||||
{
|
||||
public static class Imports
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ReadProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
[Out] byte[] lpBuffer,
|
||||
int dwSize,
|
||||
out int lpNumberOfBytesRead);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte[] lpBuffer,
|
||||
int nSize,
|
||||
out IntPtr lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool VirtualProtectEx(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpAddress,
|
||||
IntPtr dwSize,
|
||||
uint flNewProtect,
|
||||
out uint lpflOldProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool WaitForDebugEvent(ref DEBUG_EVENT lpDebugEvent, uint dwMilliseconds);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool DebugActiveProcessStop(uint dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool DebugActiveProcess(int dwProcessId);
|
||||
|
||||
[DllImport("psapi.dll", SetLastError = true)]
|
||||
public static extern bool EnumProcessModules(
|
||||
IntPtr hProcess,
|
||||
IntPtr lphModule,
|
||||
uint cb,
|
||||
out uint lpcbNeeded);
|
||||
|
||||
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern int GetModuleFileNameEx(
|
||||
IntPtr hProcess,
|
||||
IntPtr hModule,
|
||||
StringBuilder lpFilename,
|
||||
int nSize);
|
||||
|
||||
[DllImport("psapi.dll", SetLastError = true)]
|
||||
public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, uint cb);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
public static extern bool CreateProcessA
|
||||
(
|
||||
String lpApplicationName,
|
||||
String lpCommandLine,
|
||||
IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
Boolean bInheritHandles,
|
||||
uint dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
String lpCurrentDirectory,
|
||||
[In] ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ContinueDebugEvent(uint dwProcessId, uint dwThreadId, uint dwContinueStatus);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct StartupInfo
|
||||
{
|
||||
public Int32 cb ;
|
||||
public IntPtr lpReserved ;
|
||||
public IntPtr lpDesktop ;
|
||||
public IntPtr lpTitle ;
|
||||
public Int32 dwX ;
|
||||
public Int32 dwY ;
|
||||
public Int32 dwXSize ;
|
||||
public Int32 dwYSize ;
|
||||
public Int32 dwXCountChars ;
|
||||
public Int32 dwYCountChars ;
|
||||
public Int32 dwFillAttribute ;
|
||||
public Int32 dwFlags ;
|
||||
public Int16 wShowWindow ;
|
||||
public Int16 cbReserved2 ;
|
||||
public IntPtr lpReserved2 ;
|
||||
public IntPtr hStdInput ;
|
||||
public IntPtr hStdOutput ;
|
||||
public IntPtr hStdError ;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ProcessInformation
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public Int32 dwProcessId;
|
||||
public Int32 dwThreadId;
|
||||
}
|
||||
|
||||
#region Debug event structures
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct DEBUG_EVENT
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public uint dwDebugEventCode;
|
||||
[FieldOffset(4)]
|
||||
public uint dwProcessId;
|
||||
[FieldOffset(8)]
|
||||
public uint dwThreadId;
|
||||
[FieldOffset(16)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 160)]
|
||||
public byte[] Union;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct EXCEPTION_DEBUG_INFO
|
||||
{
|
||||
public EXCEPTION_RECORD ExceptionRecord;
|
||||
public uint dwFirstChance;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct EXCEPTION_RECORD
|
||||
{
|
||||
public uint ExceptionCode;
|
||||
public uint ExceptionFlags;
|
||||
public IntPtr pExceptionRecord;
|
||||
public IntPtr ExceptionAddress;
|
||||
public uint NumberParameters;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
||||
public IntPtr[] ExceptionInformation;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct CREATE_THREAD_DEBUG_INFO
|
||||
{
|
||||
public IntPtr hThread;
|
||||
public IntPtr lpThreadLocalBase;
|
||||
public IntPtr lpStartAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct CREATE_PROCESS_DEBUG_INFO
|
||||
{
|
||||
public IntPtr hFile;
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public IntPtr lpBaseOfImage;
|
||||
public uint dwDebugInfoFileOffset;
|
||||
public uint nDebugInfoSize;
|
||||
public IntPtr lpThreadLocalBase;
|
||||
public IntPtr lpStartAddress;
|
||||
public IntPtr lpImageName;
|
||||
public ushort fUnicode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct MODULEINFO
|
||||
{
|
||||
public IntPtr lpBaseOfDll;
|
||||
public uint SizeOfImage;
|
||||
public IntPtr EntryPoint;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct EXIT_THREAD_DEBUG_INFO
|
||||
{
|
||||
public uint dwExitCode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct EXIT_PROCESS_DEBUG_INFO
|
||||
{
|
||||
public uint dwExitCode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct LOAD_DLL_DEBUG_INFO
|
||||
{
|
||||
public IntPtr hFile;
|
||||
public IntPtr lpBaseOfDll;
|
||||
public uint dwDebugInfoFileOffset;
|
||||
public uint nDebugInfoSize;
|
||||
public IntPtr lpImageName;
|
||||
public ushort fUnicode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct UNLOAD_DLL_DEBUG_INFO
|
||||
{
|
||||
public IntPtr lpBaseOfDll;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct OUTPUT_DEBUG_STRING_INFO
|
||||
{
|
||||
public IntPtr lpDebugStringData;
|
||||
public ushort fUnicode;
|
||||
public ushort nDebugStringLength;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RIP_INFO
|
||||
{
|
||||
public uint dwError;
|
||||
public uint dwType;
|
||||
}
|
||||
|
||||
|
||||
public static T MapUnmanagedStructure<T>(byte[] debugInfo)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(debugInfo, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Determining constants for debugging
|
||||
public const uint INFINITE = 0xFFFFFFFF;
|
||||
public const uint DEBUG_PROCESS = 0x00000001;
|
||||
public const uint DBG_CONTINUE = 0x00010002;
|
||||
public const uint CREATE_PROCESS_DEBUG_EVENT = 3;
|
||||
public const uint EXIT_PROCESS_DEBUG_EVENT = 5;
|
||||
public const uint EXCEPTION_DEBUG_EVENT = 1;
|
||||
public const uint LOAD_DLL_DEBUG_EVENT = 6;
|
||||
public const uint OUTPUT_DEBUG_STRING_EVENT = 8;
|
||||
public const uint EXCEPTION_BREAKPOINT = 0x80000003;
|
||||
public const uint DBG_EXCEPTION_NOT_HANDLED = 0x80010001;
|
||||
|
||||
// Constants for VirtualProtectex
|
||||
public const uint PAGE_EXECUTE_READWRITE = 0x40;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user