其他
基于Mono注入保存Draw & Guess历史房间数据
看雪论坛作者ID:xhyeax
由于众所周知的服务器原因,经常有人掉线或闪退(也可能是自己的原因),重连后无法返回之前的房间。于是考虑使用Mono注入技术,实现历史房间数据的保存。
1
逆向分析过程
1、文件结构分析
2、房间代码生成
(1)匹配时玩家列表
类结构:
public static LobbyPlayerList Instance;
public List<RectTransform> PlayerList = new List<RectTransform>();
public List<LobbyPlayerInfo> Players = new List<LobbyPlayerInfo>();
游戏时玩家列表
类结构:
public static LobbyPlayerList Instance;
public List<RectTransform> PlayerList = new List<RectTransform>();
public List<LobbyPlayerInfo> Players = new List<LobbyPlayerInfo>();
AddPlayer 函数:
4、确定获取时机
查看AddPlayer调用栈:
RoundManager.UserCode_RpcSetInfo(对应LobbyPlayerList)
LobbyPlayerInfo.UserCode_RpcSetPlayerInfo(对应IngamePlayerList)
5、确定Hook函数
双击UserCode_RpcGetCountdown函数,查看函数体:
2
注入模块开发
1、创建项目并导入依赖
2、编写注入代码
3、模块加载提示
public static void StartReplace()
{
// 先调用原函数
StartProxy();
// 输出信息到聊天框
LobbyChat.Instance.ReceiveChat("<color=#778899>[DAGHistory]: Loaded</color>");
}
4、自定义类RoomData
使用该类保存房间数据。
public class Player
{
ulong steamID;
string name;
public Player(string name, ulong steamID)
{
this.name = name;
this.steamID = steamID;
}
public string Name { get => name; set => name = value; }
public ulong SteamID { get => steamID; set => steamID = value; }
}
public class RoomData
{
string roomCode;
List<Player> playerList;
public string RoomCode { get => roomCode; set => roomCode = value; }
public List<Player> PlayerList { get => playerList; set => playerList = value; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
5、获取房间数据
public static RoomData getRoomData()
{
RoomData roomData = new RoomData();
if (LobbyPlayerList.Instance != null && LobbyPlayerList.Instance.Players != null
&& LobbyPlayerList.Instance.Players.Count != 0)
{
List<LobbyPlayerInfo> players = LobbyPlayerList.Instance.Players;
roomData.PlayerList = new List<Player>();
for (int i = 0; i < players.Count; i++)
{
LobbyPlayerInfo lobbyPlayerInfo = players[i];
string name = lobbyPlayerInfo.Name;
ulong steamID = lobbyPlayerInfo.SteamID.m_SteamID;
if (i == 0)
{
roomData.RoomCode = CodeEncoder.codeEncode(steamID);
}
roomData.PlayerList.Add(new Player(name, steamID));
}
}
return roomData;
}
6、自动保存房间数据
public static void UserCode_RpcGetCountdownReplace(byte s)
{
// 调用原函数
UserCode_RpcGetCountdownProxy(s);
// 如果距离上一次调用该函数超过10秒,获取房间数据并保存到文件
if (Time.realtimeSinceStartup - lastCallTime > 10)
{
RoomUtil.saveRoomData();
LobbyChat.Instance.ReceiveChat("<color=#778899>[DAGHistory]: Saved</color>");
lastCallTime = Time.realtimeSinceStartup;
}
}
7、加入房间
public static void joinRoom(string code)
{
if (code != null)
{
LobbyManager.s_Singleton.Join(CodeEncoder.codeDecode(code).ToString());
}
}
8、获取日志路径
private static string ReturnLogPath()
{
RuntimePlatform platform = Application.platform;
switch (platform)
{
case RuntimePlatform.OSXEditor:
case RuntimePlatform.OSXPlayer:
return "~/Library/Logs/Unity/";
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.LinuxEditor:
return Path.Combine("~/.config/unity3d", Application.companyName, "Draw_Guess");
case RuntimePlatform.WindowsPlayer:
return Path.Combine(Environment.GetEnvironmentVariable("AppData"), "..", "LocalLow",
Application.companyName, "Draw_Guess");
default:
return Path.GetTempPath();
}
}
9、GUI
10、生成dll文件
3
测试
1、注入dll并调用Load函数
.\smi.exe -p "Draw&Guess" -a "DAGHistory.dll" -n "DAGHistory" -c "Loader" -m "Load" inject
2、查看日志
其中LastRoom.json和DAGHistory.log即注入模块生成的日志文件。前者保存上次游玩的房间数据(用于复制代码及快速加入),后者保存历史记录。
看雪ID:xhyeax
https://bbs.pediy.com/user-home-691226.htm
*本文由看雪论坛 xhyeax 原创,转载请注明来自看雪社区
# 往期推荐
1. 一个方案:家用路由器D-LINK DIR-81漏洞挖掘实例分析
4. 记一次MEMZ样本分析
球分享
球点赞
球在看
点击“阅读原文”,了解更多!