using RainOpsMini.Helpers;
using System.Diagnostics;
using System.Runtime.InteropServices;
public class MemoryExtraction
{
///
/// 阵营1基址 (由TicketQueryPlugin配置管理)
///
public static List team1offsets = new List { 0x158, 0x408, 0x8, 0x2C0, 0x2B0 };
///
/// 阵营2基址 (由TicketQueryPlugin配置管理)
///
public static List team2offsets = new List { 0x158, 0x408, 0x10, 0x2C0, 0x2B0 };
///
/// 基础偏移量 (由TicketQueryPlugin配置管理)
///
public static int baseoffset = 0x0BAF53B8;
///
/// 主程序运行目录 (由TicketQueryPlugin配置管理)
///
public static string path = "";
///
/// 更新偏移量配置
///
public static void UpdateOffsets(int baseOff, List t1, List t2)
{
baseoffset = baseOff;
team1offsets = t1;
team2offsets = t2;
}
// 定义 Windows API 函数
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hObject);
// 打开进程并获取进程句柄
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
// 进程访问权限标志
[Flags]
private enum ProcessAccessFlags : uint
{
All = 0x1F0FFF,
QueryInformation = 0x0400,
VirtualMemoryRead = 0x0010,
}
///
/// 修改票数
///
///
/// 值为0代表查询
///
public static int TickChange(int TeamID, int Tick = 0)
{
try
{
//进程ID
int PID = GetSquadPID(path);
//获取PID失败了
if (PID <= 0)
{
RainOpsLog.Log("【无法读取票数】找不到:" + path + "(绝对路径)文件对应的PID");
return 0;
}
int teamtick = ChangeTeamTick(PID, TeamID, Tick);
return teamtick;
}
catch (Exception e)
{
return 0;
}
}
///
/// 读取游戏指定路径的进程ID
///
///
private static int GetSquadPID(string path)
{
string processName = Path.GetFileName(path);
if (string.IsNullOrEmpty(processName)) return -1;
try
{
Process[] processes = Process.GetProcesses();
foreach (var process in processes)
{
try
{
// 获取进程的路径
if (process.MainModule != null && string.Equals(process.MainModule.FileName, path, StringComparison.OrdinalIgnoreCase))
{
return process.Id;
}
}
catch
{
// 忽略无法访问的进程
}
}
}
catch (Exception ex)
{
Console.WriteLine($"发生错误: {ex.Message}");
}
return -1;
}
///
/// 修改票数
///
/// 进程ID
/// 队伍ID
///
///
private static int ChangeTeamTick(int PID, int teamID, int Tick)
{
try
{
//进程ID
var targetProcessId = PID;
// 获取目标进程的模块信息
var targetProcess = Process.GetProcessById(PID);
if (targetProcess == null)
{
Console.WriteLine("未找到目标进程");
return 0;
}
// 遍历进程模块来获取特定模块的基址
foreach (ProcessModule module in targetProcess.Modules)
{
//主程序地址
IntPtr hProcess = MemoryHelper.OpenProcess(0x1F0FFF, false, targetProcess.Id);
IntPtr baseAddress = module.BaseAddress;
//Console.WriteLine($"PID:" + PID.ToString("X"));
//Console.WriteLine($"基址:" + baseAddress.ToString("X"));
// 读取该地址的值
if (hProcess == IntPtr.Zero)
{
Console.WriteLine("无法打开进程!");
return 0;
}
if (module.ModuleName != null && module.ModuleName.StartsWith("SquadGameServer"))
{
// 计算最终地址 + 基础偏移
IntPtr finalAddress = baseAddress + baseoffset;
//Console.WriteLine($" 计算最终地址 + 基础偏移:" + finalAddress.ToString("X"));
var value = ReadMemoryValue(hProcess, finalAddress);
// 将字符串解析为整数
long baseValue = Convert.ToInt64(value, 16);
long fullAddress = baseValue;
// 使用示例
List offsets = new List();
if (teamID == 1)
{
offsets = team1offsets;
}
else if (teamID == 2)
{
offsets = team2offsets;
}
// 转换为 IntPtr
IntPtr addressPtr = new IntPtr(fullAddress);
List readVal = new List();
for (int i = 0; i < offsets.Count; i++)
{
var temp_addressPtr = new IntPtr(fullAddress);
addressPtr = new IntPtr(fullAddress);
addressPtr = new IntPtr(addressPtr.ToInt64() + offsets[i]);
var readMemoryValue = ReadMemoryValue(hProcess, addressPtr);
if (!string.IsNullOrEmpty(readMemoryValue))
{
readMemoryValue = readMemoryValue.ToString().TrimStart('0');
}
//Console.WriteLine("【" + (i + 1) + "】信息:" + temp_addressPtr.ToString("X") + "+" + offsets[i].ToString("X") + "\t" + readMemoryValue);
//偏移指针地址
fullAddress = Convert.ToInt64(readMemoryValue, 16);
}
//当前票数
int now_tick = Convert.ToInt32(fullAddress);
if (Tick != 0)
{
WriteMemoryValue(hProcess, addressPtr, Tick);
}
return now_tick;
}
}
}
catch (Exception e)
{
RainOpsLog.Log("阵营(" + teamID + ")票数查询失败:" + e.Message);
return 0;
}
return 0;
}
///
/// 读取内存地址值
///
///
///
///
///
public static string ReadMemoryValue(IntPtr hProcess, IntPtr finalAddress, int length = 8) // 默认读取8字节
{
ulong value = 0; // 使用无符号长整型
byte[] buffer = new byte[length]; // 读取8字节(ulong)
if (MemoryHelper.ReadProcessMemory(hProcess, finalAddress, buffer, buffer.Length, out int bytesRead))
{
// 使用 BitConverter.ToUInt64 来确保读取的是无符号长整型
value = BitConverter.ToUInt64(buffer, 0);
}
else
{
// 读取失败
Console.WriteLine("读取失败!");
return "0";
}
// 输出十六进制格式,确保与 CE 一致
return value.ToString("X16"); // 保证 16 位宽度,适应64位数据
}
///
/// 根据内存地址写入数据
///
///
///
///
///
///
///
[DllImport("kernel32.dll")]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesWritten);
///
/// 写入内存值
///
/// 进程句柄
/// 内存地址
/// 要写入的值
/// 写入的字节长度
/// 是否成功
private static bool WriteMemoryValue(IntPtr hProcess, IntPtr finalAddress, int value, int length = 4)
{
// 将整数值转换为字节数组
byte[] buffer = BitConverter.GetBytes(value);
// 确保字节数组长度和指定长度一致
if (buffer.Length != length)
{
Array.Resize(ref buffer, length);
}
uint bytesWritten;
// 使用 WriteProcessMemory 函数写入内存
var res = WriteProcessMemory(hProcess, finalAddress, buffer, (uint)buffer.Length, out bytesWritten);
return res;
}
}
public class MemoryHelper
{
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, out int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hObject);
}