- 内存操作
///
/// Memory.dll class. Full documentation at /// public class Mem { #region DllImports [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess( UInt32 dwDesiredAccess, bool bInheritHandle, Int32 dwProcessId );
#if WINXP
#else
[DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx")]
public static extern UIntPtr Native_VirtualQueryEx(IntPtr hProcess, UIntPtr lpAddress,
out MEMORY_BASIC_INFORMATION32 lpBuffer, UIntPtr dwLength);
[DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx")]
public static extern UIntPtr Native_VirtualQueryEx(IntPtr hProcess, UIntPtr lpAddress,
out MEMORY_BASIC_INFORMATION64 lpBuffer, UIntPtr dwLength);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
public UIntPtr VirtualQueryEx(IntPtr hProcess, UIntPtr lpAddress,
out MEMORY_BASIC_INFORMATION lpBuffer)
{
UIntPtr retVal;
// TODO: Need to change this to only check once.
if (Is64Bit || IntPtr.Size == 8)
{
// 64 bit
MEMORY_BASIC_INFORMATION64 tmp64 = new MEMORY_BASIC_INFORMATION64();
retVal = Native_VirtualQueryEx(hProcess, lpAddress, out tmp64, new UIntPtr((uint)Marshal.SizeOf(tmp64)));
lpBuffer.BaseAddress = tmp64.BaseAddress;
lpBuffer.AllocationBase = tmp64.AllocationBase;
lpBuffer.AllocationProtect = tmp64.AllocationProtect;
lpBuffer.RegionSize = (long)tmp64.RegionSize;
lpBuffer.State = tmp64.State;
lpBuffer.Protect = tmp64.Protect;
lpBuffer.Type = tmp64.Type;
return retVal;
}
MEMORY_BASIC_INFORMATION32 tmp32 = new MEMORY_BASIC_INFORMATION32();
retVal = Native_VirtualQueryEx(hProcess, lpAddress, out tmp32, new UIntPtr((uint)Marshal.SizeOf(tmp32)));
lpBuffer.BaseAddress = tmp32.BaseAddress;
lpBuffer.AllocationBase = tmp32.AllocationBase;
lpBuffer.AllocationProtect = tmp32.AllocationProtect;
lpBuffer.RegionSize = tmp32.RegionSize;
lpBuffer.State = tmp32.State;
lpBuffer.Protect = tmp32.Protect;
lpBuffer.Type = tmp32.Type;
return retVal;
}
[DllImport("kernel32.dll")]
static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);
#endif
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("dbghelp.dll")]
static extern bool MiniDumpWriteDump(
IntPtr hProcess,
Int32 ProcessId,
IntPtr hFile,
MINIDUMP_TYPE DumpType,
IntPtr ExceptionParam,
IntPtr UserStreamParam,
IntPtr CallackParam);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr w, IntPtr l);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(
IntPtr hProcess,
UIntPtr lpBaseAddress,
string lpBuffer,
UIntPtr nSize,
out IntPtr lpNumberOfBytesWritten
);
[DllImport("kernel32.dll")]
static extern int GetProcessId(IntPtr handle);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern uint GetPrivateProfileString(
string lpAppName,
string lpKeyName,
string lpDefault,
StringBuilder lpReturnedString,
uint nSize,
string lpFileName);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool VirtualFreeEx(
IntPtr hProcess,
UIntPtr lpAddress,
UIntPtr dwSize,
uint dwFreeType
);
[DllImport("kernel32.dll")]
private static extern bool ReadProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, [Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
private static extern bool ReadProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, [Out] byte[] lpBuffer, UIntPtr nSize, out ulong lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
private static extern bool ReadProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, [Out] IntPtr lpBuffer, UIntPtr nSize, out ulong lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern UIntPtr VirtualAllocEx(
IntPtr hProcess,
UIntPtr lpAddress,
uint dwSize,
uint flAllocationType,
uint flProtect
);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern UIntPtr GetProcAddress(
IntPtr hModule,
string procName
);
[DllImport("kernel32.dll", EntryPoint = "CloseHandle")]
private static extern bool _CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(
IntPtr hObject
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(
string lpModuleName
);
[DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
internal static extern Int32 WaitForSingleObject(
IntPtr handle,
Int32 milliseconds
);
[DllImport("kernel32.dll")]
private static extern bool WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesWritten);
// Added to avoid casting to UIntPtr
[DllImport("kernel32.dll")]
private static extern bool WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
UIntPtr lpStartAddress, // raw Pointer into remote process
UIntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId
);
[DllImport("kernel32")]
public static extern bool IsWow64Process(IntPtr hProcess, out bool lpSystemInfo);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
// privileges
const int PROCESS_CREATE_THREAD = 0x0002;
const int PROCESS_QUERY_INFORMATION = 0x0400;
const int PROCESS_VM_OPERATION = 0x0008;
const int PROCESS_VM_WRITE = 0x0020;
const int PROCESS_VM_READ = 0x0010;
// used for memory allocation
const uint MEM_FREE = 0x10000;
const uint MEM_COMMIT = 0x00001000;
const uint MEM_RESERVE = 0x00002000;
private const uint PAGE_READONLY = 0x02;
const uint PAGE_READWRITE = 0x04;
const uint PAGE_WRITECOPY = 0x08;
private const uint PAGE_EXECUTE_READWRITE = 0x40;
private const uint PAGE_EXECUTE_WRITECOPY = 0x80;
private const uint PAGE_EXECUTE = 0x10;
private const uint PAGE_EXECUTE_READ = 0x20;
private const uint PAGE_GUARD = 0x100;
private const uint PAGE_NOACCESS = 0x01;
private uint MEM_PRIVATE = 0x20000;
private uint MEM_IMAGE = 0x1000000;
#endregion
///
/// The process handle that was opened. (Use OpenProcess function to populate this variable)
///
public IntPtr pHandle;
Dictionary FreezeTokenSrcs = new Dictionary();
public Process theProc = null;
internal enum MINIDUMP_TYPE
{
MiniDumpNormal = 0x00000000,
MiniDumpWithDataSegs = 0x00000001,
MiniDumpWithFullMemory = 0x00000002,
MiniDumpWithHandleData = 0x00000004,
MiniDumpFilterMemory = 0x00000008,
MiniDumpScanMemory = 0x00000010,
MiniDumpWithUnloadedModules = 0x00000020,
MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
MiniDumpFilterModulePaths = 0x00000080,
MiniDumpWithProcessThreadData = 0x00000100,
MiniDumpWithPrivateReadWriteMemory = 0x00000200,
MiniDumpWithoutOptionalData = 0x00000400,
MiniDumpWithFullMemoryInfo = 0x00000800,
MiniDumpWithThreadInfo = 0x00001000,
MiniDumpWithCodeSegs = 0x00002000
}
bool IsDigitsOnly(string str)
{
foreach (char c in str)
{
if (c < '0' || c > '9')
return false;
}
return true;
}
///
/// Freeze a value to an address.
///
/// Your address
/// byte, 2bytes, bytes, float, int, string, double or long.
/// Value to freeze
/// ini file to read address from (OPTIONAL)
public void FreezeValue(string address, string type, string value, string file = "")
{
CancellationTokenSource cts = new CancellationTokenSource();
if (FreezeTokenSrcs.ContainsKey(address))
{
Debug.WriteLine("Changing Freezing Address " + address + " Value " + value);
try
{
FreezeTokenSrcs[address].Cancel();
FreezeTokenSrcs.Remove(address);
}
catch
{
Debug.WriteLine("ERROR: Avoided a crash. Address " + address + " was not frozen.");
}
}
else
Debug.WriteLine("Adding Freezing Address " + address + " Value " + value);
FreezeTokenSrcs.Add(address, cts);
Task.Factory.StartNew(() =>
{
while (!cts.Token.IsCancellationRequested)
{
WriteMemory(address, type, value, file);
Thread.Sleep(25);
}
},
cts.Token);
}
///
/// Unfreeze a frozen value at an address
///
/// address where frozen value is stored
public void UnfreezeValue(string address)
{
Debug.WriteLine("Un-Freezing Address " + address);
try
{
FreezeTokenSrcs[address].Cancel();
FreezeTokenSrcs.Remove(address);
}
catch
{
Debug.WriteLine("ERROR: Address " + address + " was not frozen.");
}
}
///
/// Open the PC game process with all security and access rights.
///
/// Use process name or process ID here.
///
public bool OpenProcess(int pid)
{
try
{
if (theProc != null && theProc.Id == pid)
return true;
if (pid <= 0)
{
Debug.WriteLine("ERROR: OpenProcess given proc ID 0.");
return false;
}
theProc = Process.GetProcessById(pid);
if (theProc != null && !theProc.Responding)
{
Debug.WriteLine("ERROR: OpenProcess: Process is not responding or null.");
return false;
}
pHandle = OpenProcess(0x1F0FFF, true, pid);
Process.EnterDebugMode();
if (pHandle == IntPtr.Zero)
{
var eCode = Marshal.GetLastWin32Error();
}
mainModule = theProc.MainModule;
GetModules();
// Lets set the process to 64bit or not here (cuts down on api calls)
Is64Bit = Environment.Is64BitOperatingSystem && (IsWow64Process(pHandle, out bool retVal) && !retVal);
Debug.WriteLine("Program is operating at Administrative level. Process #" + theProc + " is open and modules are stored.");
return true;
}
catch {
Debug.WriteLine("ERROR: OpenProcess has crashed. Are you trying to hack a x64 game? https://github.com/erfg12/memory.dll/wiki/64bit-Games");
return false;
}
}
///
/// Open the PC game process with all security and access rights.
///
/// Use process name or process ID here.
///
public bool OpenProcess(string proc)
{
return OpenProcess(GetProcIdFromName(proc));
}
///
/// Check if opened process is 64bit. Used primarily for getCode().
///
/// True if 64bit false if 32bit.
private bool _is64Bit;
public bool Is64Bit
{
get { return _is64Bit; }
private set { _is64Bit = value; }
}
///
/// Builds the process modules dictionary (names with addresses).
///
public void GetModules()
{
if (theProc == null)
return;
modules.Clear();
foreach (ProcessModule Module in theProc.Modules)
{
if (!string.IsNullOrEmpty(Module.ModuleName) && !modules.ContainsKey(Module.ModuleName))
modules.Add(Module.ModuleName, Module.BaseAddress);
}
}
public void SetFocus()
{
//int style = GetWindowLong(procs.MainWindowHandle, -16);
//if ((style & 0x20000000) == 0x20000000) //minimized
// SendMessage(procs.Handle, 0x0112, (IntPtr)0xF120, IntPtr.Zero);
SetForegroundWindow(theProc.MainWindowHandle);
}
///
/// Get the process ID number by process name.
///
/// Example: "eqgame". Use task manager to find the name. Do not include .exe
///
public int GetProcIdFromName(string name) //new 1.0.2 function
{
Process[] processlist = Process.GetProcesses();
if (name.ToLower().Contains(".exe"))
name = name.Replace(".exe", "");
if (name.ToLower().Contains(".bin")) // test
name = name.Replace(".bin", "");
foreach (Process theprocess in processlist)
{
if (theprocess.ProcessName.Equals(name, StringComparison.CurrentCultureIgnoreCase)) //find (name).exe in the process list (use task manager to find the name)
return theprocess.Id;
}
return 0; //if we fail to find it
}
///
/// Get code from ini file.
///
/// label for address or code
/// path and name of ini file
///
public string LoadCode(string name, string file)
{
StringBuilder returnCode = new StringBuilder(1024);
uint read_ini_result;
if (file != "")
read_ini_result = GetPrivateProfileString("codes", name, "", returnCode, (uint)returnCode.Capacity, file);
else
returnCode.Append(name);
return returnCode.ToString();
}
private int LoadIntCode(string name, string path)
{
try
{
int intValue = Convert.ToInt32(LoadCode(name, path), 16);
if (intValue >= 0)
return intValue;
else
return 0;
} catch
{
Debug.WriteLine("ERROR: LoadIntCode function crashed!");
return 0;
}
}
///
/// Dictionary with our opened process module names with addresses.
///
public Dictionary modules = new Dictionary();
///
/// Make a named pipe (if not already made) and call to a remote function.
///
/// remote function to call
/// name of the thread
public void ThreadStartClient(string func, string name)
{
//ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(name))
{
if (!pipeStream.IsConnected)
pipeStream.Connect();
//MessageBox.Show("[Client] Pipe connection established");
using (StreamWriter sw = new StreamWriter(pipeStream))
{
if (!sw.AutoFlush)
sw.AutoFlush = true;
sw.WriteLine(func);
}
}
}
private ProcessModule mainModule;
///
/// Cut a string that goes on for too long or one that is possibly merged with another string.
///
/// The string you want to cut.
///
public string CutString(string str)
{
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (c >= ' ' && c <= '~')
sb.Append(c);
else
break;
}
return sb.ToString();
}
///
/// Clean up a string that has bad characters in it.
///
/// The string you want to sanitize.
///
public string SanitizeString(string str)
{
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (c >= ' ' && c <= '~')
sb.Append(c);
}
return sb.ToString();
}
#region readMemory
///
/// Reads up to `length ` bytes from an address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// The maximum bytes to read.
/// path and name of ini file.
/// The bytes read or null
public byte[] ReadBytes(string code, long length, string file = "")
{
byte[] memory = new byte[length];
UIntPtr theCode = GetCode(code, file);
if (!ReadProcessMemory(pHandle, theCode, memory, (UIntPtr)length, IntPtr.Zero))
return null;
return memory;
}
///
/// Read a float value from an address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and name of ini file. (OPTIONAL)
/// Round the value to 2 decimal places
///
public float ReadFloat(string code, string file = "", bool round = true)
{
byte[] memory = new byte[4];
UIntPtr theCode;
theCode = GetCode(code, file);
try
{
if (ReadProcessMemory(pHandle, theCode, memory, (UIntPtr)4, IntPtr.Zero))
{
float address = BitConverter.ToSingle(memory, 0);
float returnValue = (float)address;
if (round)
returnValue = (float)Math.Round(address, 2);
return returnValue;
}
else
return 0;
}
catch
{
return 0;
}
}
///
/// Read a string value from an address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and name of ini file. (OPTIONAL)
/// length of bytes to read (OPTIONAL)
/// terminate string at null char
///
public string ReadString(string code, string file = "", int length = 32, bool zeroTerminated = true)
{
byte[] memoryNormal = new byte[length];
UIntPtr theCode;
theCode = GetCode(code, file);
if (ReadProcessMemory(pHandle, theCode, memoryNormal, (UIntPtr)length, IntPtr.Zero))
return (zeroTerminated) ? Encoding.Unicode.GetString(memoryNormal).Split('\0')[0] : Encoding.Unicode.GetString(memoryNormal);
else
return "";
}
///
/// Read a double value
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and name of ini file. (OPTIONAL)
/// Round the value to 2 decimal places
///
public double ReadDouble(string code, string file = "", bool round = true)
{
byte[] memory = new byte[8];
UIntPtr theCode;
theCode = GetCode(code, file);
try
{
if (ReadProcessMemory(pHandle, theCode, memory, (UIntPtr)8, IntPtr.Zero))
{
double address = BitConverter.ToDouble(memory, 0);
double returnValue = (double)address;
if (round)
returnValue = (double)Math.Round(address, 2);
return returnValue;
}
else
return 0;
}
catch
{
return 0;
}
}
public int ReadUIntPtr(UIntPtr code)
{
byte[] memory = new byte[4];
if (ReadProcessMemory(pHandle, code, memory, (UIntPtr)4, IntPtr.Zero))
return BitConverter.ToInt32(memory, 0);
else
return 0;
}
///
/// Read an integer from an address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and name of ini file. (OPTIONAL)
///
public int ReadInt(string code, string file = "")
{
byte[] memory = new byte[4];
UIntPtr theCode;
theCode = GetCode(code, file);
if (ReadProcessMemory(pHandle, theCode, memory, (UIntPtr)4, IntPtr.Zero))
return BitConverter.ToInt32(memory, 0);
else
return 0;
}
///
/// Read a long value from an address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and name of ini file. (OPTIONAL)
///
public long ReadLong(string code, string file = "")
{
byte[] memory = new byte[16];
UIntPtr theCode;
theCode = GetCode(code, file);
if (ReadProcessMemory(pHandle, theCode, memory, (UIntPtr)16, IntPtr.Zero))
return BitConverter.ToInt64(memory, 0);
else
return 0;
}
///
/// Read a UInt value from address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and name of ini file. (OPTIONAL)
///
public UInt64 ReadUInt(string code, string file = "")
{
byte[] memory = new byte[4];
UIntPtr theCode;
theCode = GetCode(code, file);
if (ReadProcessMemory(pHandle, theCode, memory, (UIntPtr)4, IntPtr.Zero))
return BitConverter.ToUInt64(memory, 0);
else
return 0;
}
///
/// Reads a 2 byte value from an address and moves the address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// Quantity to move.
/// path and name of ini file (OPTIONAL)
///
public int Read2ByteMove(string code, int moveQty, string file = "")
{
byte[] memory = new byte[4];
UIntPtr theCode;
theCode = GetCode(code, file);
UIntPtr newCode = UIntPtr.Add(theCode, moveQty);
if (ReadProcessMemory(pHandle, newCode, memory, (UIntPtr)2, IntPtr.Zero))
return BitConverter.ToInt32(memory, 0);
else
return 0;
}
///
/// Reads an integer value from address and moves the address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// Quantity to move.
/// path and name of ini file (OPTIONAL)
///
public int ReadIntMove(string code, int moveQty, string file = "")
{
byte[] memory = new byte[4];
UIntPtr theCode;
theCode = GetCode(code, file);
UIntPtr newCode = UIntPtr.Add(theCode, moveQty);
if (ReadProcessMemory(pHandle, newCode, memory, (UIntPtr)4, IntPtr.Zero))
return BitConverter.ToInt32(memory, 0);
else
return 0;
}
///
/// Get UInt and move to another address by moveQty. Use in a for loop.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// Quantity to move.
/// path and name of ini file (OPTIONAL)
///
public ulong ReadUIntMove(string code, int moveQty, string file = "")
{
byte[] memory = new byte[8];
UIntPtr theCode;
theCode = GetCode(code, file, 8);
UIntPtr newCode = UIntPtr.Add(theCode, moveQty);
if (ReadProcessMemory(pHandle, newCode, memory, (UIntPtr)8, IntPtr.Zero))
return BitConverter.ToUInt64(memory, 0);
else
return 0;
}
///
/// Read a 2 byte value from an address. Returns an integer.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and file name to ini file. (OPTIONAL)
///
public int Read2Byte(string code, string file = "")
{
byte[] memoryTiny = new byte[4];
UIntPtr theCode;
theCode = GetCode(code, file);
if (ReadProcessMemory(pHandle, theCode, memoryTiny, (UIntPtr)2, IntPtr.Zero))
return BitConverter.ToInt32(memoryTiny, 0);
else
return 0;
}
///
/// Read 1 byte from address.
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and file name of ini file. (OPTIONAL)
///
public int ReadByte(string code, string file = "")
{
byte[] memoryTiny = new byte[1];
UIntPtr theCode = GetCode(code, file);
if (ReadProcessMemory(pHandle, theCode, memoryTiny, (UIntPtr) 1, IntPtr.Zero))
return memoryTiny[0];
return 0;
}
///
/// Reads a byte from memory and splits it into bits
///
/// address, module + pointer + offset, module + offset OR label in .ini file.
/// path and file name of ini file. (OPTIONAL)
/// Array of 8 booleans representing each bit of the byte read
public bool[] ReadBits(string code, string file = "")
{
byte[] buf = new byte[1];
UIntPtr theCode = GetCode(code, file);
bool[] ret = new bool[8];
if (!ReadProcessMemory(pHandle, theCode, buf, (UIntPtr) 1, IntPtr.Zero))
return ret;
if (!BitConverter.IsLittleEndian)
throw new Exception("Should be little endian");
for (var i = 0; i < 8; i++)
ret[i] = Convert.ToBoolean(buf[0] & (1 << i));
return ret;
}
public int ReadPByte(UIntPtr address, string code, string file = "")
{
byte[] memory = new byte[4];
if (ReadProcessMemory(pHandle, address + LoadIntCode(code, file), memory, (UIntPtr)1, IntPtr.Zero))
return BitConverter.ToInt32(memory, 0);
else
return 0;
}
public float ReadPFloat(UIntPtr address, string code, string file = "")
{
byte[] memory = new byte[4];
if (ReadProcessMemory(pHandle, address + LoadIntCode(code, file), memory, (UIntPtr)4, IntPtr.Zero))
{
float spawn = BitConverter.ToSingle(memory, 0);
return (float)Math.Round(spawn, 2);
}
else
return 0;
}
public int ReadPInt(UIntPtr address, string code, string file = "")
{
byte[] memory = new byte[4];
if (ReadProcessMemory(pHandle, address + LoadIntCode(code, file), memory, (UIntPtr)4, IntPtr.Zero))
return BitConverter.ToInt32(memory, 0);
else
return 0;
}
public string ReadPString(UIntPtr address, string code, string file = "")
{
byte[] memoryNormal = new byte[32];
if (ReadProcessMemory(pHandle, address + LoadIntCode(code, file), memoryNormal, (UIntPtr)32, IntPtr.Zero))
return CutString(System.Text.Encoding.ASCII.GetString(memoryNormal));
else
return "";
}
#endregion
#region writeMemory
///
///Write to memory address. See https://github.com/erfg12/memory.dll/wiki/writeMemory() for more information.
///
///address, module + pointer + offset, module + offset OR label in .ini file.
///byte, 2bytes, bytes, float, int, string, double or long.
///value to write to address.
///path and name of .ini file (OPTIONAL)
///System.Text.Encoding.Unicode (DEFAULT). Other options: ascii, unicode, utf32, utf7
public bool WriteMemory(string code, string type, string write, string file = "", System.Text.Encoding stringEncoding = null)
{
byte[] memory = new byte[4];
int size = 4;
UIntPtr theCode;
theCode = GetCode(code, file);
if (type.ToLower() == "float")
{
memory = BitConverter.GetBytes(Convert.ToSingle(write));
size = 4;
}
else if (type.ToLower() == "int")
{
memory = BitConverter.GetBytes(Convert.ToInt32(write));
size = 4;
}
else if (type.ToLower() == "byte")
{
memory = new byte[1];
memory[0] = Convert.ToByte(write, 16);
size = 1;
}
else if (type.ToLower() == "2bytes")
{
memory = new byte[2];
memory[0] = (byte)(Convert.ToInt32(write) % 256);
memory[1] = (byte)(Convert.ToInt32(write) / 256);
size = 2;
}
else if (type.ToLower() == "bytes")
{
if (write.Contains(",") || write.Contains(" ")) //check if it's a proper array
{
string[] stringBytes;
if (write.Contains(","))
stringBytes = write.Split(',');
else
stringBytes = write.Split(' ');
//Debug.WriteLine("write:" + write + " stringBytes:" + stringBytes);
int c = stringBytes.Count();
memory = new byte[c];
for (int i = 0; i < c; i++)
{
memory[i] = Convert.ToByte(stringBytes[i], 16);
}
size = stringBytes.Count();
}
else //wasnt array, only 1 byte
{
memory = new byte[1];
memory[0] = Convert.ToByte(write, 16);
size = 1;
}
}
else if (type.ToLower() == "double")
{
memory = BitConverter.GetBytes(Convert.ToDouble(write));
size = 8;
}
else if (type.ToLower() == "long")
{
memory = BitConverter.GetBytes(Convert.ToInt64(write));
size = 8;
}
else if (type.ToLower() == "string")
{
if (stringEncoding == null)
memory = System.Text.Encoding.Unicode.GetBytes(write);
else
memory = stringEncoding.GetBytes(write);
size = memory.Length;
}
//Debug.Write("DEBUG: Writing bytes [TYPE:" + type + " ADDR:" + theCode + "] " + String.Join(",", memory) + Environment.NewLine);
return WriteProcessMemory(pHandle, theCode, memory, (UIntPtr)size, IntPtr.Zero);
}
///
/// Write to address and move by moveQty. Good for byte arrays. See https://github.com/erfg12/memory.dll/wiki/Writing-a-Byte-Array for more information.
///
///address, module + pointer + offset, module + offset OR label in .ini file.
///byte, bytes, float, int, string or long.
/// byte to write
/// quantity to move
/// path and name of .ini file (OPTIONAL)
///
public bool WriteMove(string code, string type, string write, int moveQty, string file = "")
{
byte[] memory = new byte[4];
int size = 4;
UIntPtr theCode;
theCode = GetCode(code, file);
if (type == "float")
{
memory = new byte[write.Length];
memory = BitConverter.GetBytes(Convert.ToSingle(write));
size = write.Length;
}
else if (type == "int")
{
memory = BitConverter.GetBytes(Convert.ToInt32(write));
size = 4;
}
else if (type == "double")
{
memory = BitConverter.GetBytes(Convert.ToDouble(write));
size = 8;
}
else if (type == "long")
{
memory = BitConverter.GetBytes(Convert.ToInt64(write));
size = 8;
}
else if (type == "byte")
{
memory = new byte[1];
memory[0] = Convert.ToByte(write, 16);
size = 1;
}
else if (type == "string")
{
memory = new byte[write.Length];
memory = System.Text.Encoding.Unicode.GetBytes(write);
size = write.Length;
}
UIntPtr newCode = UIntPtr.Add(theCode, moveQty);
Debug.Write("DEBUG: Writing bytes [TYPE:" + type + " ADDR:[O]" + theCode + " [N]" + newCode + " MQTY:" + moveQty + "] " + String.Join(",", memory) + Environment.NewLine);
Thread.Sleep(1000);
return WriteProcessMemory(pHandle, newCode, memory, (UIntPtr)size, IntPtr.Zero);
}
///
/// Write byte array to addresses.
///
/// address to write to
/// byte array to write
/// path and name of ini file. (OPTIONAL)
public void WriteBytes(string code, byte[] write, string file = "")
{
UIntPtr theCode;
theCode = GetCode(code, file);
WriteProcessMemory(pHandle, theCode, write, (UIntPtr)write.Length, IntPtr.Zero);
}
///
/// Takes an array of 8 booleans and writes to a single byte
///
/// address to write to
/// Array of 8 booleans to write
/// path and name of ini file. (OPTIONAL)
public void WriteBits(string code, bool[] bits, string file = "")
{
if(bits.Length != 8)
throw new ArgumentException("Not enough bits for a whole byte", nameof(bits));
byte[] buf = new byte[1];
UIntPtr theCode = GetCode(code, file);
for (var i = 0; i < 8; i++)
{
if (bits[i])
buf[0] |= (byte)(1 << i);
}
WriteProcessMemory(pHandle, theCode, buf, (UIntPtr) 1, IntPtr.Zero);
}
///
/// Write byte array to address
///
/// Address to write to
/// Byte array to write to
public void WriteBytes(UIntPtr address, byte[] write)
{
WriteProcessMemory(pHandle, address, write, (UIntPtr)write.Length, out IntPtr bytesRead);
}
#endregion
///
/// Convert code from string to real address. If path is not blank, will pull from ini file.
///
/// label in ini file or code
/// path to ini file (OPTIONAL)
/// size of address (default is 8)
///
public UIntPtr GetCode(string name, string path = "", int size = 8)
{
string theCode = "";
if (Is64Bit)
{
//Debug.WriteLine("Changing to 64bit code...");
if (size == 8) size = 16; //change to 64bit
return Get64BitCode(name, path, size); //jump over to 64bit code grab
}
if (path != "")
theCode = LoadCode(name, path);
else
theCode = name;
if (theCode == "")
{
//Debug.WriteLine("ERROR: LoadCode returned blank. NAME:" + name + " PATH:" + path);
return UIntPtr.Zero;
}
else
{
//Debug.WriteLine("Found code=" + theCode + " NAME:" + name + " PATH:" + path);
}
// remove spaces
if (theCode.Contains(" "))
theCode.Replace(" ", String.Empty);
if (!theCode.Contains("+") && !theCode.Contains(",")) return new UIntPtr(Convert.ToUInt32(theCode, 16));
string newOffsets = theCode;
if (theCode.Contains("+"))
newOffsets = theCode.Substring(theCode.IndexOf('+') + 1);
byte[] memoryAddress = new byte[size];
if (newOffsets.Contains(','))
{
List offsetsList = new List();
string[] newerOffsets = newOffsets.Split(',');
foreach (string oldOffsets in newerOffsets)
{
string test = oldOffsets;
if (oldOffsets.Contains("0x")) test = oldOffsets.Replace("0x","");
int preParse = 0;
if (!oldOffsets.Contains("-"))
preParse = Int32.Parse(test, NumberStyles.AllowHexSpecifier);
else
{
test = test.Replace("-", "");
preParse = Int32.Parse(test, NumberStyles.AllowHexSpecifier);
preParse = preParse * -1;
}
offsetsList.Add(preParse);
}
int[] offsets = offsetsList.ToArray();
if (theCode.Contains("base") || theCode.Contains("main"))
ReadProcessMemory(pHandle, (UIntPtr)((int)mainModule.BaseAddress + offsets[0]), memoryAddress, (UIntPtr)size, IntPtr.Zero);
else if (!theCode.Contains("base") && !theCode.Contains("main") && theCode.Contains("+"))
{
string[] moduleName = theCode.Split('+');
IntPtr altModule = IntPtr.Zero;
if (!moduleName[0].ToLower().Contains(".dll") && !moduleName[0].ToLower().Contains(".exe") && !moduleName[0].ToLower().Contains(".bin"))
{
string theAddr = moduleName[0];
if (theAddr.Contains("0x")) theAddr = theAddr.Replace("0x", "");
altModule = (IntPtr)Int32.Parse(theAddr, NumberStyles.HexNumber);
}
else
{
try
{
altModule = modules[moduleName[0]];
}
catch
{
Debug.WriteLine("Module " + moduleName[0] + " was not found in module list!");
Debug.WriteLine("Modules: " + string.Join(",", modules));
}
}
ReadProcessMemory(pHandle, (UIntPtr)((int)altModule + offsets[0]), memoryAddress, (UIntPtr)size, IntPtr.Zero);
}
else
ReadProcessMemory(pHandle, (UIntPtr)(offsets[0]), memoryAddress, (UIntPtr)size, IntPtr.Zero);
uint num1 = BitConverter.ToUInt32(memoryAddress, 0); //ToUInt64 causes arithmetic overflow.
UIntPtr base1 = (UIntPtr)0;
for (int i = 1; i < offsets.Length; i++)
{
base1 = new UIntPtr(Convert.ToUInt32(num1 + offsets[i]));
ReadProcessMemory(pHandle, base1, memoryAddress, (UIntPtr)size, IntPtr.Zero);
num1 = BitConverter.ToUInt32(memoryAddress, 0); //ToUInt64 causes arithmetic overflow.
}
return base1;
}
else // no offsets
{
int trueCode = Convert.ToInt32(newOffsets, 16);
IntPtr altModule = IntPtr.Zero;
//Debug.WriteLine("newOffsets=" + newOffsets);
if (theCode.ToLower().Contains("base") || theCode.ToLower().Contains("main"))
altModule = mainModule.BaseAddress;
else if (!theCode.ToLower().Contains("base") && !theCode.ToLower().Contains("main") && theCode.Contains("+"))
{
string[] moduleName = theCode.Split('+');
if (!moduleName[0].ToLower().Contains(".dll") && !moduleName[0].ToLower().Contains(".exe") && !moduleName[0].ToLower().Contains(".bin"))
{
string theAddr = moduleName[0];
if (theAddr.Contains("0x")) theAddr = theAddr.Replace("0x", "");
altModule = (IntPtr)Int32.Parse(theAddr, NumberStyles.HexNumber);
}
else
{
try
{
altModule = modules[moduleName[0]];
}
catch
{
Debug.WriteLine("Module " + moduleName[0] + " was not found in module list!");
Debug.WriteLine("Modules: " + string.Join(",", modules));
}
}
}
else
altModule = modules[theCode.Split('+')[0]];
return (UIntPtr)((int)altModule + trueCode);
}
}
///
/// Convert code from string to real address. If path is not blank, will pull from ini file.
///
/// label in ini file OR code
/// path to ini file (OPTIONAL)
/// size of address (default is 16)
///
public UIntPtr Get64BitCode(string name, string path = "", int size = 16)
{
string theCode = "";
if (path != "")
theCode = LoadCode(name, path);
else
theCode = name;
if (theCode == "")
return UIntPtr.Zero;
// remove spaces
if (theCode.Contains(" "))
theCode.Replace(" ", String.Empty);
string newOffsets = theCode;
if (theCode.Contains("+"))
newOffsets = theCode.Substring(theCode.IndexOf('+') + 1);
byte[] memoryAddress = new byte[size];
if (!theCode.Contains("+") && !theCode.Contains(",")) return new UIntPtr(Convert.ToUInt64(theCode, 16));
if (newOffsets.Contains(','))
{
List offsetsList = new List();
string[] newerOffsets = newOffsets.Split(',');
foreach (string oldOffsets in newerOffsets)
{
string test = oldOffsets;
if (oldOffsets.Contains("0x")) test = oldOffsets.Replace("0x", "");
Int64 preParse = 0;
if (!oldOffsets.Contains("-"))
preParse = Int64.Parse(test, NumberStyles.AllowHexSpecifier);
else
{
test = test.Replace("-", "");
preParse = Int64.Parse(test, NumberStyles.AllowHexSpecifier);
preParse = preParse * -1;
}
offsetsList.Add(preParse);
}
Int64[] offsets = offsetsList.ToArray();
if (theCode.Contains("base") || theCode.Contains("main"))
ReadProcessMemory(pHandle, (UIntPtr)((Int64)mainModule.BaseAddress + offsets[0]), memoryAddress, (UIntPtr)size, IntPtr.Zero);
else if (!theCode.Contains("base") && !theCode.Contains("main") && theCode.Contains("+"))
{
string[] moduleName = theCode.Split('+');
IntPtr altModule = IntPtr.Zero;
if (!moduleName[0].ToLower().Contains(".dll") && !moduleName[0].ToLower().Contains(".exe") && !moduleName[0].ToLower().Contains(".bin"))
altModule = (IntPtr)Int64.Parse(moduleName[0], System.Globalization.NumberStyles.HexNumber);
else
{
try
{
altModule = modules[moduleName[0]];
}
catch
{
Debug.WriteLine("Module " + moduleName[0] + " was not found in module list!");
Debug.WriteLine("Modules: " + string.Join(",", modules));
}
}
ReadProcessMemory(pHandle, (UIntPtr)((Int64)altModule + offsets[0]), memoryAddress, (UIntPtr)size, IntPtr.Zero);
}
else // no offsets
ReadProcessMemory(pHandle, (UIntPtr)(offsets[0]), memoryAddress, (UIntPtr)size, IntPtr.Zero);
Int64 num1 = BitConverter.ToInt64(memoryAddress, 0);
UIntPtr base1 = (UIntPtr)0;
for (int i = 1; i < offsets.Length; i++)
{
base1 = new UIntPtr(Convert.ToUInt64(num1 + offsets[i]));
ReadProcessMemory(pHandle, base1, memoryAddress, (UIntPtr)size, IntPtr.Zero);
num1 = BitConverter.ToInt64(memoryAddress, 0);
}
return base1;
}
else
{
Int64 trueCode = Convert.ToInt64(newOffsets, 16);
IntPtr altModule = IntPtr.Zero;
if (theCode.Contains("base") || theCode.Contains("main"))
altModule = mainModule.BaseAddress;
else if (!theCode.Contains("base") && !theCode.Contains("main") && theCode.Contains("+"))
{
string[] moduleName = theCode.Split('+');
if (!moduleName[0].ToLower().Contains(".dll") && !moduleName[0].ToLower().Contains(".exe") && !moduleName[0].ToLower().Contains(".bin"))
{
string theAddr = moduleName[0];
if (theAddr.Contains("0x")) theAddr = theAddr.Replace("0x", "");
altModule = (IntPtr)Int64.Parse(theAddr, NumberStyles.HexNumber);
}
else
{
try
{
altModule = modules[moduleName[0]];
}
catch
{
Debug.WriteLine("Module " + moduleName[0] + " was not found in module list!");
Debug.WriteLine("Modules: " + string.Join(",", modules));
}
}
}
else
altModule = modules[theCode.Split('+')[0]];
return (UIntPtr)((Int64)altModule + trueCode);
}
}
///
/// Close the process when finished.
///
public void CloseProcess()
{
if (pHandle == null)
return;
CloseHandle(pHandle);
theProc = null;
}
///
/// Inject a DLL file.
///
/// path and name of DLL file.
public void InjectDll(String strDllName)
{
IntPtr bytesout;
foreach (ProcessModule pm in theProc.Modules)
{
if (pm.ModuleName.StartsWith("inject", StringComparison.InvariantCultureIgnoreCase))
return;
}
if (!theProc.Responding)
return;
int lenWrite = strDllName.Length + 1;
UIntPtr allocMem = VirtualAllocEx(pHandle, (UIntPtr)null, (uint)lenWrite, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(pHandle, allocMem, strDllName, (UIntPtr)lenWrite, out bytesout);
UIntPtr injector = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (injector == null)
return;
IntPtr hThread = CreateRemoteThread(pHandle, (IntPtr)null, 0, injector, allocMem, 0, out bytesout);
if (hThread == null)
return;
int Result = WaitForSingleObject(hThread, 10 * 1000);
if (Result == 0x00000080L || Result == 0x00000102L)
{
if (hThread != null)
CloseHandle(hThread);
return;
}
VirtualFreeEx(pHandle, allocMem, (UIntPtr)0, 0x8000);
if (hThread != null)
CloseHandle(hThread);
return;
}
#if WINXP
#else
///
/// Creates a code cave to write custom opcodes in target process
///
/// Address to create the trampoline
/// The opcodes to write in the code cave
/// The number of bytes being replaced
/// size of the allocated region
/// ini file to look in
///
/// if you replace halfway in an instruction you may cause bad things
///
public UIntPtr CreateCodeCave(string code, byte[] newBytes, int replaceCount, int size = 0x1000, string file = "")
{
if (replaceCount < 5)
return UIntPtr.Zero; // returning UIntPtr.Zero instead of throwing an exception
// to better match existing code
UIntPtr theCode;
theCode = GetCode(code, file);
UIntPtr address = theCode;
// if x64 we need to try to allocate near the address so we dont run into the +-2GB limit of the 0xE9 jmp
UIntPtr caveAddress = UIntPtr.Zero;
UIntPtr prefered = address;
for(var i = 0; i < 10 && caveAddress == UIntPtr.Zero; i++)
{
caveAddress = VirtualAllocEx(pHandle, FindFreeBlockForRegion(prefered, (uint)size),
(uint)size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (caveAddress == UIntPtr.Zero)
prefered = UIntPtr.Add(prefered, 0x10000);
}
// Failed to allocate memory around the address we wanted let windows handle it and hope for the best?
if (caveAddress == UIntPtr.Zero)
caveAddress = VirtualAllocEx(pHandle, UIntPtr.Zero, (uint)size, MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
int nopsNeeded = replaceCount > 5 ? replaceCount - 5 : 0;
// (to - from - 5)
int offset = (int)((long)caveAddress - (long)address - 5);
byte[] jmpBytes = new byte[5 + nopsNeeded];
jmpBytes[0] = 0xE9;
BitConverter.GetBytes(offset).CopyTo(jmpBytes, 1);
for(var i = 5; i < jmpBytes.Length; i++)
{
jmpBytes[i] = 0x90;
}
WriteBytes(address, jmpBytes);
byte[] caveBytes = new byte[5 + newBytes.Length];
offset = (int)(((long)address + jmpBytes.Length) - ((long)caveAddress + newBytes.Length) - 5);
newBytes.CopyTo(caveBytes, 0);
caveBytes[newBytes.Length] = 0xE9;
BitConverter.GetBytes(offset).CopyTo(caveBytes, newBytes.Length + 1);
WriteBytes(caveAddress, caveBytes);
return caveAddress;
}
private UIntPtr FindFreeBlockForRegion(UIntPtr baseAddress, uint size)
{
UIntPtr minAddress = UIntPtr.Subtract(baseAddress, 0x70000000);
UIntPtr maxAddress = UIntPtr.Add(baseAddress, 0x70000000);
UIntPtr ret = UIntPtr.Zero;
UIntPtr tmpAddress = UIntPtr.Zero;
GetSystemInfo(out SYSTEM_INFO si);
if (Is64Bit)
{
if ((long)minAddress > (long)si.maximumApplicationAddress ||
(long)minAddress < (long)si.minimumApplicationAddress)
minAddress = si.minimumApplicationAddress;
if ((long)maxAddress < (long)si.minimumApplicationAddress ||
(long)maxAddress > (long)si.maximumApplicationAddress)
maxAddress = si.maximumApplicationAddress;
}
else
{
minAddress = si.minimumApplicationAddress;
maxAddress = si.maximumApplicationAddress;
}
MEMORY_BASIC_INFORMATION mbi;
UIntPtr current = minAddress;
UIntPtr previous = current;
while (VirtualQueryEx(pHandle, current, out mbi).ToUInt64() != 0)
{
if ((long)mbi.BaseAddress > (long)maxAddress)
return UIntPtr.Zero; // No memory found, let windows handle
if (mbi.State == MEM_FREE && mbi.RegionSize > size)
{
if ((long)mbi.BaseAddress % si.allocationGranularity > 0)
{
// The whole size can not be used
tmpAddress = mbi.BaseAddress;
int offset = (int)(si.allocationGranularity -
((long)tmpAddress % si.allocationGranularity));
// Check if there is enough left
if((mbi.RegionSize - offset) >= size)
{
// yup there is enough
tmpAddress = UIntPtr.Add(tmpAddress, offset);
if((long)tmpAddress < (long)baseAddress)
{
tmpAddress = UIntPtr.Add(tmpAddress, (int)(mbi.RegionSize - offset - size));
if ((long)tmpAddress > (long)baseAddress)
tmpAddress = baseAddress;
// decrease tmpAddress until its alligned properly
tmpAddress = UIntPtr.Subtract(tmpAddress, (int)((long)tmpAddress % si.allocationGranularity));
}
// if the difference is closer then use that
if (Math.Abs((long)tmpAddress - (long)baseAddress) < Math.Abs((long)ret - (long)baseAddress))
ret = tmpAddress;
}
}
else
{
tmpAddress = mbi.BaseAddress;
if((long)tmpAddress < (long)baseAddress) // try to get it the cloest possible
// (so to the end of the region - size and
// aligned by system allocation granularity)
{
tmpAddress = UIntPtr.Add(tmpAddress, (int)(mbi.RegionSize - size));
if ((long)tmpAddress > (long)baseAddress)
tmpAddress = baseAddress;
// decrease until aligned properly
tmpAddress =
UIntPtr.Subtract(tmpAddress, (int)((long)tmpAddress % si.allocationGranularity));
}
if (Math.Abs((long)tmpAddress - (long)baseAddress) < Math.Abs((long)ret - (long)baseAddress))
ret = tmpAddress;
}
}
if (mbi.RegionSize % si.allocationGranularity > 0)
mbi.RegionSize += si.allocationGranularity - (mbi.RegionSize % si.allocationGranularity);
previous = current;
current = UIntPtr.Add(mbi.BaseAddress, (int)mbi.RegionSize);
if ((long)current > (long)maxAddress)
return ret;
if ((long)previous > (long)current)
return ret; // Overflow
}
return ret;
}
#endif
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
public static void SuspendProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
continue;
SuspendThread(pOpenThread);
CloseHandle(pOpenThread);
}
}
public static void ResumeProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
continue;
var suspendCount = 0;
do
{
suspendCount = ResumeThread(pOpenThread);
} while (suspendCount > 0);
CloseHandle(pOpenThread);
}
}
#if WINXP
#else
async Task PutTaskDelay(int delay)
{
await Task.Delay(delay);
}
#endif
void AppendAllBytes(string path, byte[] bytes)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bytes.Length);
}
}
public byte[] FileToBytes(string path, bool dontDelete = false) {
byte[] newArray = File.ReadAllBytes(path);
if (!dontDelete)
File.Delete(path);
return newArray;
}
public string MSize()
{
if (Is64Bit)
return ("x16");
else
return ("x8");
}
///
/// Convert a byte array to hex values in a string.
///
/// your byte array to convert
///
public static string ByteArrayToHexString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
int i = 1;
foreach (byte b in ba)
{
if (i == 16)
{
hex.AppendFormat("{0:x2}{1}", b, Environment.NewLine);
i = 0;
}
else
hex.AppendFormat("{0:x2} ", b);
i++;
}
return hex.ToString().ToUpper();
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
hex.AppendFormat("{0:x2} ", b);
}
return hex.ToString().TrimEnd();
}
#if WINXP
#else
public struct SYSTEM_INFO
{
public ushort processorArchitecture;
ushort reserved;
public uint pageSize;
public UIntPtr minimumApplicationAddress;
public UIntPtr maximumApplicationAddress;
public IntPtr activeProcessorMask;
public uint numberOfProcessors;
public uint processorType;
public uint allocationGranularity;
public ushort processorLevel;
public ushort processorRevision;
}
public struct MEMORY_BASIC_INFORMATION32
{
public UIntPtr BaseAddress;
public UIntPtr AllocationBase;
public uint AllocationProtect;
public uint RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
public struct MEMORY_BASIC_INFORMATION64
{
public UIntPtr BaseAddress;
public UIntPtr AllocationBase;
public uint AllocationProtect;
public uint __alignment1;
public ulong RegionSize;
public uint State;
public uint Protect;
public uint Type;
public uint __alignment2;
}
public struct MEMORY_BASIC_INFORMATION
{
public UIntPtr BaseAddress;
public UIntPtr AllocationBase;
public uint AllocationProtect;
public long RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
public ulong GetMinAddress()
{
SYSTEM_INFO SI;
GetSystemInfo(out SI);
return (ulong)SI.minimumApplicationAddress;
}
///
/// 获取引用类型的内存地址方法
///
///
///
public static string GetMemory(object o)
{
GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned);
IntPtr addr = h.AddrOfPinnedObject();
return "0x" + addr.ToString("X");
}
///
/// Dump memory page by page to a dump.dmp file. Can be used with Cheat Engine.
///
public bool DumpMemory(string file = "dump.dmp")
{
Debug.Write("[DEBUG] memory dump starting... (" + DateTime.Now.ToString("h:mm:ss tt") + ")" + Environment.NewLine);
SYSTEM_INFO sys_info = new SYSTEM_INFO();
GetSystemInfo(out sys_info);
UIntPtr proc_min_address = sys_info.minimumApplicationAddress;
UIntPtr proc_max_address = sys_info.maximumApplicationAddress;
// saving the values as long ints so I won't have to do a lot of casts later
Int64 proc_min_address_l = (Int64)proc_min_address; //(Int64)procs.MainModule.BaseAddress;
Int64 proc_max_address_l = (Int64)theProc.VirtualMemorySize64 + proc_min_address_l;
//int arrLength = 0;
if (File.Exists(file))
File.Delete(file);
MEMORY_BASIC_INFORMATION memInfo = new MEMORY_BASIC_INFORMATION();
while (proc_min_address_l < proc_max_address_l)
{
VirtualQueryEx(pHandle, proc_min_address, out memInfo);
byte[] buffer = new byte[(Int64)memInfo.RegionSize];
UIntPtr test = (UIntPtr)((Int64)memInfo.RegionSize);
UIntPtr test2 = (UIntPtr)((Int64)memInfo.BaseAddress);
ReadProcessMemory(pHandle, test2, buffer, test, IntPtr.Zero);
AppendAllBytes(file, buffer); //due to memory limits, we have to dump it then store it in an array.
//arrLength += buffer.Length;
proc_min_address_l += (Int64)memInfo.RegionSize;
proc_min_address = new UIntPtr((ulong)proc_min_address_l);
}
Debug.Write("[DEBUG] memory dump completed. Saving dump file to " + file + ". (" + DateTime.Now.ToString("h:mm:ss tt") + ")" + Environment.NewLine);
return true;
}
///
/// Array of byte scan.
///
/// array of bytes to search for, OR your ini code label.
/// Include writable addresses in scan
/// Include executable addresses in scan
/// ini file (OPTIONAL)
/// IEnumerable of all addresses found.
public Task> AoBScan(string search, bool writable = false, bool executable = true, string file = "")
{
return AoBScan(0, long.MaxValue, search, writable, executable, file);
}
///
/// Array of byte scan.
///
/// array of bytes to search for, OR your ini code label.
/// Include readable addresses in scan
/// Include writable addresses in scan
/// Include executable addresses in scan
/// ini file (OPTIONAL)
/// IEnumerable of all addresses found.
public Task> AoBScan(string search, bool readable, bool writable, bool executable, string file = "")
{
return AoBScan(0, long.MaxValue, search, readable, writable, executable, file);
}
///
/// Array of Byte scan.
///
/// Your starting address.
/// ending address
/// array of bytes to search for, OR your ini code label.
/// ini file (OPTIONAL)
/// Include writable addresses in scan
/// Include executable addresses in scan
/// IEnumerable of all addresses found.
public Task> AoBScan(long start, long end, string search, bool writable = false, bool executable = true, string file = "")
{
// Not including read only memory was scan behavior prior.
return AoBScan(start, end, search, false, writable, executable, file);
}
///
/// Array of Byte scan.
///
/// Your starting address.
/// ending address
/// array of bytes to search for, OR your ini code label.
/// ini file (OPTIONAL)
/// Include readable addresses in scan
/// Include writable addresses in scan
/// Include executable addresses in scan
/// IEnumerable of all addresses found.
public Task> AoBScan(long start, long end, string search, bool readable, bool writable, bool executable, string file = "")
{
return Task.Run(() =>
{
var memRegionList = new List();
string memCode = LoadCode(search, file);
string[] stringByteArray = memCode.Split(' ');
byte[] aobPattern = new byte[stringByteArray.Length];
byte[] mask = new byte[stringByteArray.Length];
for (var i = 0; i < stringByteArray.Length; i++)
{
string ba = stringByteArray[i];
if (ba == "??" || (ba.Length == 1 && ba == "?"))
{
mask[i] = 0x00;
stringByteArray[i] = "0x00";
}
else if (Char.IsLetterOrDigit(ba[0]) && ba[1] == '?')
{
mask[i] = 0xF0;
stringByteArray[i] = ba[0] + "0";
}
else if (Char.IsLetterOrDigit(ba[1]) && ba[0] == '?')
{
mask[i] = 0x0F;
stringByteArray[i] = "0" + ba[1];
}
else
mask[i] = 0xFF;
}
for (int i = 0; i < stringByteArray.Length; i++)
aobPattern[i] = (byte)(Convert.ToByte(stringByteArray[i], 16) & mask[i]);
SYSTEM_INFO sys_info = new SYSTEM_INFO();
GetSystemInfo(out sys_info);
UIntPtr proc_min_address = sys_info.minimumApplicationAddress;
UIntPtr proc_max_address = sys_info.maximumApplicationAddress;
if (start < (long)proc_min_address.ToUInt64())
start = (long)proc_min_address.ToUInt64();
if (end > (long)proc_max_address.ToUInt64())
end = (long)proc_max_address.ToUInt64();
Debug.WriteLine("[DEBUG] memory scan starting... (start:0x" + start.ToString(MSize()) + " end:0x" + end.ToString(MSize()) + " time:" + DateTime.Now.ToString("h:mm:ss tt") + ")");
UIntPtr currentBaseAddress = new UIntPtr((ulong)start);
MEMORY_BASIC_INFORMATION memInfo = new MEMORY_BASIC_INFORMATION();
//Debug.WriteLine("[DEBUG] start:0x" + start.ToString("X8") + " curBase:0x" + currentBaseAddress.ToUInt64().ToString("X8") + " end:0x" + end.ToString("X8") + " size:0x" + memInfo.RegionSize.ToString("X8") + " vAloc:" + VirtualQueryEx(pHandle, currentBaseAddress, out memInfo).ToUInt64().ToString());
while (VirtualQueryEx(pHandle, currentBaseAddress, out memInfo).ToUInt64() != 0 &&
currentBaseAddress.ToUInt64() < (ulong)end &&
currentBaseAddress.ToUInt64() + (ulong)memInfo.RegionSize >
currentBaseAddress.ToUInt64())
{
bool isValid = memInfo.State == MEM_COMMIT;
isValid &= memInfo.BaseAddress.ToUInt64() < (ulong)proc_max_address.ToUInt64();
isValid &= ((memInfo.Protect & PAGE_GUARD) == 0);
isValid &= ((memInfo.Protect & PAGE_NOACCESS) == 0);
isValid &= (memInfo.Type == MEM_PRIVATE) || (memInfo.Type == MEM_IMAGE);
if (isValid)
{
bool isReadable = (memInfo.Protect & PAGE_READONLY) > 0;
bool isWritable = ((memInfo.Protect & PAGE_READWRITE) > 0) ||
((memInfo.Protect & PAGE_WRITECOPY) > 0) ||
((memInfo.Protect & PAGE_EXECUTE_READWRITE) > 0) ||
((memInfo.Protect & PAGE_EXECUTE_WRITECOPY) > 0);
bool isExecutable = ((memInfo.Protect & PAGE_EXECUTE) > 0) ||
((memInfo.Protect & PAGE_EXECUTE_READ) > 0) ||
((memInfo.Protect & PAGE_EXECUTE_READWRITE) > 0) ||
((memInfo.Protect & PAGE_EXECUTE_WRITECOPY) > 0);
isReadable &= readable;
isWritable &= writable;
isExecutable &= executable;
isValid &= isReadable || isWritable || isExecutable;
}
if (!isValid)
{
currentBaseAddress = new UIntPtr(memInfo.BaseAddress.ToUInt64() + (ulong)memInfo.RegionSize);
continue;
}
MemoryRegionResult memRegion = new MemoryRegionResult
{
CurrentBaseAddress = currentBaseAddress,
RegionSize = memInfo.RegionSize,
RegionBase = memInfo.BaseAddress
};
currentBaseAddress = new UIntPtr(memInfo.BaseAddress.ToUInt64() + (ulong)memInfo.RegionSize);
//Console.WriteLine("SCAN start:" + memRegion.RegionBase.ToString() + " end:" + currentBaseAddress.ToString());
if (memRegionList.Count > 0)
{
var previousRegion = memRegionList[memRegionList.Count - 1];
if ((long)previousRegion.RegionBase + previousRegion.RegionSize == (long)memInfo.BaseAddress)
{
memRegionList[memRegionList.Count - 1] = new MemoryRegionResult
{
CurrentBaseAddress = previousRegion.CurrentBaseAddress,
RegionBase = previousRegion.RegionBase,
RegionSize = previousRegion.RegionSize + memInfo.RegionSize
};
continue;
}
}
memRegionList.Add(memRegion);
}
ConcurrentBag bagResult = new ConcurrentBag();
Parallel.ForEach(memRegionList,
(item, parallelLoopState, index) =>
{
long[] compareResults = CompareScan(item, aobPattern, mask);
foreach (long result in compareResults)
bagResult.Add(result);
});
Debug.WriteLine("[DEBUG] memory scan completed. (time:" + DateTime.Now.ToString("h:mm:ss tt") + ")");
return bagResult.ToList().OrderBy(c => c).AsEnumerable();
});
}
///
/// Array of bytes scan
///
/// Starting address or ini label
/// ending address
/// array of bytes to search for or your ini code label
/// ini file
/// First address found
public async Task AoBScan(string code, long end, string search, string file ="")
{
long start = (long)GetCode(code, file).ToUInt64();
return (await AoBScan(start, end, search, true, true, true, file)).FirstOrDefault();
}
private long[] CompareScan(MemoryRegionResult item, byte[] aobPattern, byte[] mask)
{
if (mask.Length != aobPattern.Length)
throw new ArgumentException($"{nameof(aobPattern)}.Length != {nameof(mask)}.Length");
IntPtr buffer = Marshal.AllocHGlobal((int)item.RegionSize);
ReadProcessMemory(pHandle, item.CurrentBaseAddress, buffer, (UIntPtr)item.RegionSize, out ulong bytesRead);
int result = 0 - aobPattern.Length;
List ret = new List();
unsafe
{
do
{
result = FindPattern((byte*)buffer.ToPointer(), (int)bytesRead, aobPattern, mask, result + aobPattern.Length);
if (result >= 0)
ret.Add((long) item.CurrentBaseAddress + result);
} while (result != -1);
}
Marshal.FreeHGlobal(buffer);
return ret.ToArray();
}
private int FindPattern(byte[] body, byte[] pattern, byte[] masks, int start = 0)
{
int foundIndex = -1;
if (body.Length <= 0 || pattern.Length <= 0 || start > body.Length - pattern.Length ||
pattern.Length > body.Length) return foundIndex;
for (int index = start; index <= body.Length - pattern.Length; index++)
{
if (((body[index] & masks[0]) == (pattern[0] & masks[0])))
{
var match = true;
for (int index2 = 1; index2 <= pattern.Length - 1; index2++)
{
if ((body[index + index2] & masks[index2]) == (pattern[index2] & masks[index2])) continue;
match = false;
break;
}
if (!match) continue;
foundIndex = index;
break;
}
}
return foundIndex;
}
private unsafe int FindPattern(byte* body, int bodyLength, byte[] pattern, byte[] masks, int start = 0)
{
int foundIndex = -1;
if (bodyLength <= 0 || pattern.Length <= 0 || start > bodyLength - pattern.Length ||
pattern.Length > bodyLength) return foundIndex;
for (int index = start; index <= bodyLength - pattern.Length; index++)
{
if (((body[index] & masks[0]) == (pattern[0] & masks[0])))
{
var match = true;
for (int index2 = 1; index2 <= pattern.Length - 1; index2++)
{
if ((body[index + index2] & masks[index2]) == (pattern[index2] & masks[index2])) continue;
match = false;
break;
}
if (!match) continue;
foundIndex = index;
break;
}
}
return foundIndex;
}
#endif
}
2. 鼠标操作
public static partial class WindowMouse
{
//当前光标的句柄
[DllImport("User32.dll", EntryPoint = "GetCursor")]
private static extern IntPtr GetCursor();
//按键,鼠标移动和鼠标点击。
[DllImport("User32.dll", EntryPoint = "SendInput", SetLastError = true)]
private static extern int _SendInput(int nInputs, MKH_Input[] pInputs, int cbSize);
//获取鼠标的位置
[DllImport("User32", EntryPoint = "GetCursorPos", SetLastError = true)]
public extern static bool GetCursorPos(out M_CursorPos lpPoint);
//设置鼠标的位置
[DllImport("User32", EntryPoint = "SetCursorPos", SetLastError = true)]
public extern static bool SetCursorPOS(int x, int y);
//销毁一个光标并释放它占用的任何内存,不要使用该函数去消毁一个共享光标
[DllImport("User32", EntryPoint = "DestroyCUrsor", SetLastError = true)]
public extern static bool DestroyCUrsor(IntPtr hCursor);
//显示或隐藏光标。
[DllImport("User32.dll", EntryPoint = "ShowCursor")]
public extern static int ShowCursor(bool bShow);
}
3 窗体操作
public partial class WindowForm
{
internal delegate bool EnumChildWindowsCallBack(IntPtr hwnd, int lParam);
//关闭窗体
[DllImport("User32.dll", EntryPoint = "CloseWindow", SetLastError = true)]
internal static extern bool _CloseWindow(IntPtr hWnd);
//获得给定窗口的可视状态
[DllImport("User32.dll", EntryPoint = "IsWindowVisible")]
internal static extern bool _IsWindowVisible(IntPtr hWnd);
//移动窗体
[DllImport("User32.dll", EntryPoint = "MoveWindow", SetLastError = true)]
internal static extern bool _MoveWindow(IntPtr hWnd, int left, int top, int nWidth, int nHeight, bool BRePaint);
//激活前台窗体
[DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
internal static extern bool _SetForegroundWindow(IntPtr hwnd);
//设置指定窗口的显示状态。
[DllImport("User32.dll", EntryPoint = "ShowWindow")]
internal static extern bool _ShowWindow(IntPtr hWnd, int nCmdShow);
//指出一个被属窗口,可见窗口,顶级弹出窗口,或层叠窗日是否在屏幕上存在。这个函数搜索整个屏幕,而不仅仅搜索应用程序的客户区。
[DllImport("User32.dll", EntryPoint = "AnyPopup")]
internal static extern bool AnyPopup();
[DllImport("user32.dll")]
internal static extern int EnumChildWindows(IntPtr hWndParent, EnumChildWindowsCallBack lpfn, int lParam);
//取窗口句柄 FindWindow 不查询子窗体 不区分大小写
[DllImport("User32.dll", EntryPoint = "FindWindow", SetLastError = true)]
internal extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
//检索其类名和窗口名称与指定字符串匹配的窗口的句柄。该函数搜索子窗口
[DllImport("User32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
internal static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
//检索指定窗口所属的类的名称。
[DllImport("User32.dll", EntryPoint = "GetClassName", SetLastError = true)]
internal static extern IntPtr GetClassName(IntPtr hwnd, string lpClassName, int length);
//返回桌面窗口的句柄
[DllImport("User32.dll", EntryPoint = "GetDesktopWindow")]
internal static extern IntPtr GetDesktopWindow();
//前台窗体
[DllImport("User32.dll", EntryPoint = "GetForegroundWindow")]
internal static extern IntPtr GetForegroundWindow();
[DllImport("User32.dll", EntryPoint = "GetNextWindow", SetLastError = true)]
internal static extern IntPtr GetNextWindow(IntPtr hwnd, int wcmd);
[DllImport("User32.dll", EntryPoint = "GetParent", SetLastError = true)]
internal static extern IntPtr GetParent(IntPtr hwnd);
//获取窗体中 z序子窗体顶部
[DllImport("User32.dll", EntryPoint = "GetTopWindow", SetLastError = true)]
internal static extern IntPtr GetTopWindow(IntPtr hwnd);
//指定窗口的显示状态和还原的,最小化的和最大化的位置。
[DllImport("User32.dll", EntryPoint = "GetWindowPlacement", SetLastError = true)]
internal static extern bool GetWindowPlacement(IntPtr hwnd, out W_PLACEMENT wp);
//该函数返回指定窗口的边框矩形的尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出
[DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)]
internal static extern bool GetWindowRect(IntPtr hwnd, out W_RECT lpRect);
//指定窗口的标题条文本
[DllImport("User32.dll", EntryPoint = "GetWindowText", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool GetWindowText(IntPtr hwnd, byte[] data, int length);
//获取标题条文本长度
[DllImport("User32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hWnd);
//判断是否是子窗口
[DllImport("User32.dll", EntryPoint = "IsChild")]
internal static extern bool IsChild(IntPtr hWndParant, IntPtr hWnd);
//窗体最小化
[DllImport("User32.dll", EntryPoint = "IsIconic")]
internal static extern bool IsIconic(IntPtr hWnd);
//判断是否是一个窗体
[DllImport("User32.dll", EntryPoint = "IsWindow")]
internal static extern bool isWindow(IntPtr hWnd);
//指定的窗口是否是本地Unicode窗口。
[DllImport("User32.dll", EntryPoint = "IsWindowUnicode")]
internal static extern bool IsWindowUnicode(IntPtr hWnd);
[DllImport("User32.dll", EntryPoint = "IsZoomed")]
internal static extern bool IsZoomed(IntPtr hWnd);
//最小化(标志性)窗口恢复到其先前的大小和位置;然后激活窗口。
[DllImport("User32.dll", EntryPoint = "OpenIcon", SetLastError = true)]
internal static extern bool OpenIcon(IntPtr hWnd);
//指定窗口的显示状态和还原的,最小化的和最大化的位置。
[DllImport("User32.dll", EntryPoint = "SetWindowPlacement", SetLastError = true)]
internal static extern bool SetWindowPlacement(IntPtr hwnd, out W_PLACEMENT wp);
[DllImport("user32.dll")]
internal static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cX, int cY, int wFlags);
//设置由不同线程产生的窗口的显示状态。 避免在等待一个挂起的应用程序完成处理show-window事件时也被挂起。
[DllImport("User32.dll", EntryPoint = "ShowWindowAsync")]
internal static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
//从指定的坐标获取窗体
[DllImport("User32.dll", EntryPoint = "WindowFromPoint")]
internal static extern IntPtr WindowFromPoint(Point point);
//定的消息发送到窗口或窗口
[DllImport("User32.dll", EntryPoint = "SendMessage",SetLastError =true)]
internal static extern int _SendMessage(int hWnd, int Msg, int wParam, int lParam );
}
参考 https://docs.microsoft.com/zh-cn/windows/win32/apiindex/windows-api-list
demo https://aescr.coding.net/p/window/git