目錄
- 問題內容
- 遇到問題
- 簡單分析
- 解決問題
- 反序列化
- 指定格式輸出
- 總結
問題內容
遇到問題
6月3日逃跑吧少年PC端游戲更新,讓我康康官方又出了什么新東西,
AssetStudio,啟動!

咦~別的型別的檔案還好,怎么TextAsset文本檔案只有一個字母?難道是我的AssetStudio壞了?先Export出來康康,

好家伙亂碼了,要是前幾個版本,資料一般是保存為csv格式的文本檔案,難道白日夢為了不讓玩家拆包查看更新資訊給自己資料加密了?但不對啊,里面還是有不少可讀字符的,猜測編碼有問題,先換UTF-8編碼打開試試,

出現正常文字了,編碼選擇沒錯,但是可讀字串之間還混進不少不可讀的二進制資料,看來應該是將資料序列化后保存的結果,
檔案中似乎不存在變數名、型別等資訊,應該不會像php那樣不需要構造資料型別就能直接反序列化,還是逆向分析一下吧,
簡單分析
本人逆向還未入門,不過只是獲取反序列化所需的物件定義和序列化的方法應該就能完成反序列化,還是硬著頭皮上吧,
Il2CppDumper,啟動!DnSpy,啟動!
先直接搜索檔案名試試:

這個ZeroFormatter命名空間有點可疑,點開看看,

Aha,重寫了Serialize和Deserialize方法,看來這個ZeroFormatter應該就是序列化器了,搜了一下,這似乎是C#中最快的序列化器,看來這次游戲改格式更多是出于性能的考慮吧,

再往下看,這個ActivityLobbyObjectSegment類的屬性,基本對應此前版本ActivityLobby檔案的表頭資訊:


進而猜測ActivityLobby檔案中存盤的就是這個類的實體序列化的內容,接下來的任務就是對資料進行反序列化了,
解決問題
反序列化
因為我比較菜游戲會校驗檔案hash值,修改或者注入會比較麻煩,所以我選擇寫一個簡單的反序列化程式,負責讀取序列化后的資料并轉換為可讀的資料,
VS2019,啟動!創建一個.Net控制臺應用,通過NuGet安裝ZeroFormatter和ZeroFormatter.Interfaces,

ZeroFormatter的基本使用不難,序列化的方法很簡單,就是創建類、創建實體物件、序列化物件三步,進行序列化類的定義官網也給出了明確的規定,主要就是類需要指定ZeroFormattable,屬性需要指定Index并且要加上virtual關鍵字,
先根據ActivityLobbyInfoObjectSegment直接創建一個ActivityLobbyInfo類:
[ZeroFormattable]
public class ActivityLobbyInfo
{
[Index(0)]
public virtual int Id { get; set; }
[Index(1)]
public virtual string TabName { get; set; }
[Index(2)]
public virtual ActivityType Type { get; set; }
[Index(3)]
public virtual string Prefab { get; set; }
[Index(4)]
public virtual string TitleName { get; set; }
[Index(5)]
public virtual int Rank { get; set; }
[Index(6)]
public virtual string Desc { get; set; }
[Index(7)]
public virtual ActivityCollectionType CollectionType { get; set; }
[Index(8)]
public virtual int[] PreviewActivityIDs { get; set; }
[Index(9)]
public virtual string TimeDesc { get; set; }
[Index(10)]
public virtual int version { get; set; }
[Index(11)]
public virtual int gradeLimit { get; set; }
[Index(12)]
public virtual int Index { get; set; }
[Index(13)]
public virtual int startTime { get; set; }
[Index(14)]
public virtual int endTime { get; set; }
[Index(15)]
public virtual int exchangeEndTime { get; set; }
[Index(16)]
public virtual int MobileTimeOffset { get; set; }
}
其中部分列舉型別的資料也要根據逆向的結果進行定義:
public enum ActivityType
{
PREVIEW,
COLLECT_WORD,
DAILY_COLLECT_WORD,
MICRO_PAYMENT,
CUMULATION_RECHARGE,
WHEEL,
LOGIN_ACTIVITY,
BUY_NEW_CARD_DIRECT,
NEW_CARD_UPGRADE_REWARD,
NEW_CARD_GIFT,
FIRST_RECHARGE,
CHARACTER_PREVIEW,
CHARACTER_BUY_DIRECT,
CHARACTER_TASK_ACTIVITY,
CHARACTER_GIFT,
SHARE_ACTIVITY,
COMMON_TASK,
COMMON_EXCHANGE,
CHARACTER_LOTTERY,
ANNIVERSARY_GIFT,
WEEKEND_DOUBLE,
FIRST_RECHARGE2,
NEW_FIRST_RECHARGE,
PASS,
SEND_GIFT_ACTIVITY,
SEASON_GIFT_1,
SEASON_GIFT_2,
PASS_EXP_BONUS_ACTIVITY,
NEW_CARD_ACTIVITY_REWARD = 31,
GIVE_OLD_CARD,
GIVE_OLD_CARD_UP,
OLD_CARD_STRATEGY,
OLD_CARD_ACTIVITY_REWARD,
OLD_CARD_COLLECTION_REWARD,
LIGHT_UP_ACTIVITY,
CHARACTER_FREE_ACTIVITY,
VOTE_ACTIVITY,
CHARACTER_SUITE_LOTTERY,
ANNIVERSARY_REVIEW,
LIMITLOTTERY_ACTIVITY,
PINK_LOTTERY_ACTIVITY,
CHARACTER_UPGRADE_ACTIVITY,
PASS_LOTTERY_ACTIVITY,
CHARACTER_DISCOUNT_PACKAGE,
COMMON_LOGIN_ACTIVITY,
RESEARCH_LOTTERY_ACTIVITY,
MYSTERYSTORE_ACTIVITY,
OLD_MODEL_RESELL_DISCOUNT,
}
public enum ActivityCollectionType
{
NONE,
ACTIVITY_LOBBY,
NEW_CARD_ACTIVITY,
CHARACTER_ACTIVITY,
ANNIVERSART_ACTIVITY,
OLD_CARD_ACTIVITY,
LOTTERY_ACTIVITY,
ANNIVERSART_ACTIVITY2,
ANNIVERSART_ACTIVITY3,
}
執行反序列化:
public static void Main(string[] args)
{
using (FileStream fs = new FileStream(@"D:\TextAsset\ActivityLobby.txt", FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] bytes = new byte[(int)fs.Length];
fs.Read(bytes, 0, (int)fs.Length);
var data = ZeroFormatterSerializer.Deserialize<List<ActivityLobbyInfo>>(bytes);
Console.WriteLine(data.Count);
Console.WriteLine(data[0].TabName);
Console.WriteLine(data[10].TitleName);
Console.ReadLine();
}
}
運行一下,反序列化這部分應該是沒問題了,

指定格式輸出
現在已經可以將資料反序列化成物件,接下來的目標將物件實體轉化成一種可讀性比較好的格式,比如此前版本游戲保存資料用的csv格式,上NuGet搜搜看有沒有用于讀寫CSV格式的包,

好家伙,剛用過C#中最快的序列化器,這兒又有個.Net中最快的JSON、JSV、CSV文本序列化器?那么就決定是你了,ServiceStack.Text!
public static void Main(string[] args)
{
using (FileStream fs = new FileStream(@"D:\TextAsset\ActivityLobby.txt", FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] bytes = new byte[(int)fs.Length];
fs.Read(bytes, 0, (int)fs.Length);
var data = ZeroFormatterSerializer.Deserialize<List<ActivityLobbyInfo>>(bytes);
using (StreamWriter sw = new StreamWriter(@"D:\TextAsset\ActivityLobby.csv"))
{
string result = CsvSerializer.SerializeToString<List<ActivityLobbyInfo>>(data);
sw.WriteLine(result);
}
}
}
運行成功!問題解決,

總結
- 代碼寫得爛講究看看吧,水平有限,如有問題歡迎各位大佬批評指正,
- 部分程式官網:
ZeroFormatter:https://github.com/neuecc/ZeroFormatter
ServiceStack.Text:https://github.com/ServiceStack/ServiceStack.Text
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/287815.html
標籤:其他
上一篇:面試經:一線城市搬磚!又面軟體測驗崗,5000就知足了...
下一篇:技術人玩小游戲,如何“不戰而勝”
