mirror of
https://gitee.com/xiarenalofs/squad-rain-ops-mini.git
synced 2026-08-06 13:26:25 +08:00
342 lines
10 KiB
C#
342 lines
10 KiB
C#
using RainOpsMini.Helpers;
|
||
using System.Diagnostics;
|
||
using System.Runtime.InteropServices;
|
||
|
||
public class MemoryExtraction
|
||
{
|
||
|
||
|
||
/// <summary>
|
||
/// 阵营1基址 (由TicketQueryPlugin配置管理)
|
||
/// </summary>
|
||
public static List<int> team1offsets = new List<int> { 0x158, 0x408, 0x8, 0x2C0, 0x2B0 };
|
||
|
||
/// <summary>
|
||
/// 阵营2基址 (由TicketQueryPlugin配置管理)
|
||
/// </summary>
|
||
public static List<int> team2offsets = new List<int> { 0x158, 0x408, 0x10, 0x2C0, 0x2B0 };
|
||
|
||
/// <summary>
|
||
/// 基础偏移量 (由TicketQueryPlugin配置管理)
|
||
/// </summary>
|
||
public static int baseoffset = 0x0BAF53B8;
|
||
|
||
/// <summary>
|
||
/// 主程序运行目录 (由TicketQueryPlugin配置管理)
|
||
/// </summary>
|
||
public static string path = "";
|
||
|
||
/// <summary>
|
||
/// 更新偏移量配置
|
||
/// </summary>
|
||
public static void UpdateOffsets(int baseOff, List<int> t1, List<int> 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,
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 修改票数
|
||
/// </summary>
|
||
/// <param name="TeamID"></param>
|
||
/// <param name="Tick">值为0代表查询</param>
|
||
/// <returns></returns>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取游戏指定路径的进程ID
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 修改票数
|
||
/// </summary>
|
||
/// <param name="PID">进程ID</param>
|
||
/// <param name="teamID">队伍ID</param>
|
||
/// <param name="Tick"></param>
|
||
/// <returns></returns>
|
||
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<int> offsets = new List<int>();
|
||
|
||
|
||
if (teamID == 1)
|
||
{
|
||
offsets = team1offsets;
|
||
}
|
||
else if (teamID == 2)
|
||
{
|
||
offsets = team2offsets;
|
||
}
|
||
|
||
|
||
// 转换为 IntPtr
|
||
IntPtr addressPtr = new IntPtr(fullAddress);
|
||
|
||
List<string> readVal = new List<string>();
|
||
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取内存地址值
|
||
/// </summary>
|
||
/// <param name="hProcess"></param>
|
||
/// <param name="finalAddress"></param>
|
||
/// <param name="length"></param>
|
||
/// <returns></returns>
|
||
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位数据
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 根据内存地址写入数据
|
||
/// </summary>
|
||
/// <param name="hProcess"></param>
|
||
/// <param name="lpBaseAddress"></param>
|
||
/// <param name="lpBuffer"></param>
|
||
/// <param name="nSize"></param>
|
||
/// <param name="lpNumberOfBytesWritten"></param>
|
||
/// <returns></returns>
|
||
[DllImport("kernel32.dll")]
|
||
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesWritten);
|
||
|
||
|
||
/// <summary>
|
||
/// 写入内存值
|
||
/// </summary>
|
||
/// <param name="hProcess">进程句柄</param>
|
||
/// <param name="finalAddress">内存地址</param>
|
||
/// <param name="value">要写入的值</param>
|
||
/// <param name="length">写入的字节长度</param>
|
||
/// <returns>是否成功</returns>
|
||
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);
|
||
}
|
||
|