解碼的套路(二)
上篇文章講解了如何修改資源進(jìn)行解碼。
這篇文章將介紹通過(guò)逆向修改代碼來(lái)解碼。
首先稍微講一下原理,在Unity引擎制作的2D游戲中,馬賽克通常就是一個(gè)material材質(zhì)球和關(guān)聯(lián)的Shader著色器實(shí)現(xiàn)的,這兩個(gè)東西在上篇文章的資源過(guò)程中是可以直接修改來(lái)實(shí)現(xiàn)解碼的。一個(gè)材質(zhì)如果沒(méi)有代碼來(lái)控制的話功能是非常有限的,往往需要一些額外的代碼來(lái)完善和提高其靈活性。換句話說(shuō)就是,找到控制馬賽克材質(zhì)的代碼也就能輕松的對(duì)馬賽克進(jìn)行一些修改了。

首先打開(kāi)dnSpy把游戲的Assembly-CSharp.dll文件拖進(jìn)去。
在解碼的過(guò)程中,找到控制馬賽克材質(zhì)的方法是關(guān)鍵也是難點(diǎn),只要能定位到對(duì)應(yīng)的方法那么就有無(wú)數(shù)的手段干掉馬賽克。
因此經(jīng)驗(yàn)和耐心是非常重要的,通常來(lái)說(shuō)最常見(jiàn)的關(guān)鍵詞:mosaic是要搜索一下的。
其他游戲可能搜個(gè)mosaic真就給找到了,但是鑒于本文章有一點(diǎn)點(diǎn)的教程性質(zhì),所以找的例子也是比較坑的。

搜一下啥都沒(méi)有,去掉你個(gè)字母留下mo雖然能出來(lái)一大堆,但是看了一圈也沒(méi)有。
這種情況下,搜索功能就失效了,畢竟每個(gè)作者的命名思路都不一樣,有些作者偷偷懶打個(gè)縮寫(xiě)啥的也是非常常見(jiàn)的,最玄學(xué)的就是縮寫(xiě)了,自己想怎么縮就怎么縮,只要自己能看懂管它縮成啥樣呢。因此還是老老實(shí)實(shí)的找其他出路。
這時(shí)候我就想到,既然直接找找不到,那么就間接找,在游戲中,馬賽克是顯示在插圖上的,也就是CG上,那么應(yīng)該會(huì)有專(zhuān)門(mén)控制CG顯示的代碼,并且該代碼中極大可能會(huì)調(diào)用顯示馬賽克的代碼。為了驗(yàn)證這個(gè)思路,嘗試搜索一下CG關(guān)鍵詞。
因?yàn)檎业氖?strong>方法所以為了避免其他的干擾項(xiàng)直接縮小范圍設(shè)定成只搜索方法搜索出來(lái)的方法數(shù)量不算少也不算多,過(guò)濾掉一些名字是亂碼的方法后也就剩下幾十個(gè),完全可以人工在進(jìn)一步篩選一下。

在這一堆中可以看見(jiàn),直接跟cg直接有關(guān)的是wcgmode的類(lèi),經(jīng)驗(yàn)告訴我,wcgmode這個(gè)詞不簡(jiǎn)單,為什么這么說(shuō)呢,因?yàn)槿サ舨幻饕馑嫉膚后cgmode就是我們平時(shí)游戲里的cg瀏覽頁(yè)面。
那么話不多說(shuō),直接點(diǎn)開(kāi)這個(gè)類(lèi)看看里面哪個(gè)方法比較可疑。(友情提示:本文的步驟只提供一種思路,試錯(cuò)的過(guò)程都已經(jīng)省略,試錯(cuò)花的時(shí)間占了整個(gè)流程的90%)

可以看到wcgmode這個(gè)類(lèi)方法不多,下面的亂碼方法直接忽略就行,是一些涉及到加密的方法。
這里一堆的方法其實(shí)都是可以忽略不看的,因?yàn)榉椒▋?nèi)部就是幾行代碼,也沒(méi)有調(diào)用到可疑的方法。
最終篩選下就剩下3個(gè)方法:

全加到分析器里,看看這些方法的調(diào)用和被調(diào)用。
Init方法是初始化,調(diào)用了ReloadThumb這個(gè)方法。
再看了Init方法調(diào)用的其他方法后,沒(méi)有一個(gè)看上去和馬賽克有關(guān)。
然后看一下Show方法,這個(gè)方法嫌疑是最大的,可以看到這個(gè)方法傳入的是一個(gè)GameObject
也就是說(shuō)這個(gè)方法直接控制GameObject,再?gòu)拿峡磻?yīng)該是顯示傳入的GameObject。
但是看了一圈代碼后,沒(méi)有啥收獲。
最后就只剩下ReloadThumb方法,字面意思是重載略縮圖,應(yīng)該跟游戲中CG頁(yè)面下的方框小圖有關(guān)。
點(diǎn)開(kāi)分析器里的ReloadThumb方法,看一下他調(diào)用其他方法的情況,

往下拉看見(jiàn)了一個(gè)非??梢傻姆椒ǎ彩乔懊鎺讉€(gè)方法中沒(méi)有見(jiàn)過(guò)的。
SetMSC,看到這個(gè)名字其實(shí)心理差不多就有底了,前面提到過(guò)mosaic是馬賽克的全稱(chēng),作者偷懶的話怎么簡(jiǎn)寫(xiě)就不知道了,現(xiàn)在重新回過(guò)來(lái)看應(yīng)該一清二楚了,這作者把馬賽克mosaic,中三個(gè)主要發(fā)音的字母縮寫(xiě)成MSC,方法名就是設(shè)置馬賽克。
直接雙擊方法定位到SetMSC

傳入的是GameObject,代碼看上去一大堆,以前的文章提到過(guò),這代碼本質(zhì)上就3行,看后面的分號(hào)";"個(gè)數(shù)就行。
第一行:創(chuàng)建material對(duì)象存一個(gè)外部加載的材質(zhì)
第二行:material對(duì)象的某個(gè)屬性賦值this.GM.m_MSC,初始化的時(shí)候this.GM.m_MSC = 10
第三行:調(diào)用SetMSCChild方法
這里最好的方法是直接下斷點(diǎn)動(dòng)態(tài)調(diào)試一下,確定一下被加密的字符串到底是什么。
不過(guò)也可以直接試,畢竟代碼就這么點(diǎn),
大膽的猜一下就是:
material材質(zhì)是馬賽克材質(zhì),
g則是要被打馬的對(duì)象。
然后用SetMSCChild進(jìn)行進(jìn)一步的合成。
為了驗(yàn)證猜想其實(shí)很簡(jiǎn)單,既然前面material這個(gè)對(duì)象已經(jīng)加載過(guò)了,為什么又要給其中一個(gè)屬性賦值呢?
很明顯這個(gè)屬性至關(guān)重要,起到?jīng)Q定性的作用,繼續(xù)大膽猜測(cè)一下:就是通常馬賽克代碼實(shí)現(xiàn)中的像素大小的屬性。(可以動(dòng)態(tài)調(diào)試驗(yàn)證,在逆向中猜測(cè)就是思路,不要覺(jué)得猜測(cè)就是瞎掰,最怕的就是連猜都不會(huì),那樣就是一點(diǎn)思路也沒(méi)有瞎折騰)
也就是說(shuō)直接修改this.GM.m_MSC這個(gè)變量就行,在這里要注意一下修改的時(shí)候不要改成0,雖然說(shuō)是像素大小,但是實(shí)現(xiàn)的過(guò)程這個(gè)量會(huì)出現(xiàn)在分母中,如果改成0了不報(bào)錯(cuò)也會(huì)達(dá)不到預(yù)期。

在第二行右鍵選擇‘編輯IL指令’
選擇9,10,11行,然后按n,nop掉,也可以自己選nop操作碼

然后在第9行操作碼選擇ldc.r4(這個(gè)操作碼是float類(lèi)型),值輸個(gè)0.000001足夠小就行,但不要太小,不能為0。

改完后確定

值已經(jīng)變了。
然后保存模塊(記得把原文件先備份一下)


到此有關(guān)解碼的兩種方法就都大致介紹了一下,
以后若能找到合適的例子,我也會(huì)將其寫(xiě)成文章記錄。
下次我將會(huì)對(duì)Flash游戲的解碼進(jìn)行非常粗略的介紹。(接觸的比較少)