Files
squad-rain-ops-mini/Helpers/MemoryExtraction.cs

342 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}