日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

android unity hook,[原创]Unity3d安卓游戏DLL动态调式与HOOK基础

發(fā)布時(shí)間:2025/3/20 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android unity hook,[原创]Unity3d安卓游戏DLL动态调式与HOOK基础 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

[原創(chuàng)]Unity3d安卓游戲DLL動(dòng)態(tài)調(diào)式與HOOK基礎(chǔ)

2016-4-4 02:40

8207

[原創(chuàng)]Unity3d安卓游戲DLL動(dòng)態(tài)調(diào)式與HOOK基礎(chǔ)

2016-4-4 02:40

8207

本文作者七少月,文章中很多觀點(diǎn)和技術(shù)手段為本人原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處,由于本人技術(shù)水平有限,不當(dāng)之處,還請(qǐng)斧正。

前言:

由于本人一直以來(lái)都比較忙,開(kāi)班、工作等等事情太多,所以很長(zhǎng)一段時(shí)間沒(méi)有發(fā)帖。其實(shí)我確實(shí)想看一看,尤其是Unity3d安卓游戲逆向領(lǐng)域有沒(méi)有更出彩的文章。可能有些不恰當(dāng)?shù)恼f(shuō),確實(shí)這一段時(shí)間以來(lái),雖然也有一些Unity3d安卓游戲逆向的優(yōu)秀文章,如對(duì)金庸群俠傳X1.0的數(shù)據(jù)庫(kù)解密和功能解鎖修改,但無(wú)論從數(shù)量上,還是從難度上,我都難以滿(mǎn)意。不知道是愿意共享的人少了,還是覺(jué)得U3D逆向技術(shù)太簡(jiǎn)單了,如果是后一種原因,我只想說(shuō),U3D在安全開(kāi)發(fā)的投入和技術(shù)發(fā)展是難以想象的飛速,如U3D把關(guān)鍵函數(shù)引向lua,利用Lualib實(shí)現(xiàn)C#與LUA交互,不僅實(shí)現(xiàn)熱更新,也保護(hù)了代碼,而lua腳本文件則作為資源文件打包混淆。以上是后話(huà),現(xiàn)在最大的問(wèn)題在于,即使DLL解密脫殼后,我們依然在靜態(tài)分析DLL。

難以逾越的鴻溝:

本篇技術(shù)文章需要一定的U3D安卓逆向基礎(chǔ),沒(méi)有的推薦看法總的教程,至少你能用reflector把DLL中一個(gè)return hp語(yǔ)句修改為return 99999.在之前我們說(shuō)過(guò),由于U3D底層并不開(kāi)源,而且DLL運(yùn)行在安卓上已經(jīng)是受到了很大限制,所以在給我們逆向帶來(lái)比普通安卓的dex和so目標(biāo)更為明確的同時(shí),也讓我們逆向手段帶來(lái)很大拘束。導(dǎo)致的一個(gè)結(jié)果就是,我們逆向U3D的DLL,只能使用靜態(tài)分析,通過(guò)搜索,然后修改,最后測(cè)試。一直以來(lái),我們認(rèn)為,只要把關(guān)鍵DLL拿到,即使是網(wǎng)游,也可以進(jìn)行修改。但以后就不是這個(gè)樣子,可能以后DLL確實(shí)是所謂的關(guān)鍵DLL,但就不做保護(hù)地?cái)[在那里,都沒(méi)有什么作用。如果你一直看我U3D逆向的相關(guān)文章,這是繼U3D把DLL加密加殼階段的下一個(gè)新的階段,我稱(chēng)為關(guān)鍵DLL無(wú)效的階段?;氐奖疚?#xff0c;我們好像確實(shí)很為難,只能使用靜態(tài)分析仿佛成了我們一道無(wú)法逾越的鴻溝。

Unity3d游戲DLL動(dòng)態(tài)調(diào)式與HOOK:

能實(shí)現(xiàn)對(duì)U3D游戲進(jìn)行動(dòng)態(tài)調(diào)試,是我和法總一直以來(lái)的愿望。早先,我寫(xiě)過(guò)一篇理論指導(dǎo)性的文章《Unity3d游戲動(dòng)態(tài)調(diào)試?yán)碚摽蚣堋?。?dāng)然,就在那不久之后,里面的思想相繼得到了實(shí)現(xiàn)。最具代表性的,就是利用IDA動(dòng)態(tài)調(diào)試libmono.so,DUMP下來(lái)解密后的DLL。但很可惜,那種動(dòng)態(tài)調(diào)試,實(shí)質(zhì)是在動(dòng)態(tài)調(diào)試so,離我們當(dāng)初想實(shí)現(xiàn)的真正的DLL動(dòng)態(tài)調(diào)試相距甚遠(yuǎn),更別提對(duì)DLL進(jìn)行更深層的HOOK。當(dāng)然,如若想實(shí)現(xiàn)DLL能像dex或SO那樣進(jìn)行單步調(diào)式,可能還是比較遙遠(yuǎn),首先就是沒(méi)有工具,IDA對(duì)安卓DLL的效果很不理想,我們的神器reflector還不提供遠(yuǎn)程調(diào)式安卓DLL的功能,但確實(shí)可以存在一些替代性的策略。下面,我們要知道以下幾點(diǎn):

1. 任何一種動(dòng)態(tài)調(diào)試,并非一定要實(shí)現(xiàn)單步調(diào)式才叫動(dòng)態(tài)調(diào)式,能實(shí)現(xiàn)單步調(diào)式是我們最理想的狀態(tài),但動(dòng)態(tài)調(diào)試都是從log開(kāi)始的;

2. 把程序在運(yùn)行時(shí)斷下來(lái),是動(dòng)態(tài)調(diào)試的精髓所在,但也有一些簡(jiǎn)單的替換性策略,比如我在C#編寫(xiě)的EXE中的代碼中,插入一句message.show(“運(yùn)行到此處”)代碼,讓程序在運(yùn)行到我感興趣的那段代碼時(shí)彈出對(duì)話(huà)框。但這個(gè)在U3D中實(shí)現(xiàn)是很困難的,遠(yuǎn)沒(méi)有安卓smali中通過(guò)靜態(tài)注入Alert對(duì)話(huà)框代碼那樣簡(jiǎn)單,因?yàn)閁3D的腳本代碼和組件聯(lián)系太過(guò)緊密,U3D本身更貼近于一個(gè)類(lèi)似于3DMAX的三維設(shè)計(jì)軟件。

3. HOOK本質(zhì)的意義是注入代碼,也是替換程序原本函數(shù),所以DLL的HOOK可以分為內(nèi)部HOOK和外部HOOK。由于reflector的插件reflexil本身就可以對(duì)DLL進(jìn)行注入類(lèi)、方法、變量、屬性等,通過(guò)這種方式的HOOK就是內(nèi)部HOOK。而外部HOOK,就是在其他DLL,甚至是其他的非C#編寫(xiě)的任何文件去HOOK這個(gè)DLL。

說(shuō)了這么多,理論基礎(chǔ)終于講完了,本篇是基礎(chǔ),只講解簡(jiǎn)單的LOG和內(nèi)部HOOK注入。

準(zhǔn)備及樣本:

為了方便,我們采用比較簡(jiǎn)單的berryrush游戲作為樣本,該樣本在法總教程中存在。

首先,我們需要游戲的關(guān)鍵Assembliy-csharp.dll,當(dāng)然這個(gè)DLL要是解密后的,而且要是真正的關(guān)鍵DLL,當(dāng)然它要對(duì)游戲有決定性作用,而不是里面只有不關(guān)鍵的支持性代碼,關(guān)鍵性代碼存在于別的地方。其次,我們要把UnityEngine.dll拿出來(lái),一般這個(gè)類(lèi)被處理的很少。然后把它們一起拉到Reflector工具中。下面,我們來(lái)認(rèn)識(shí)一下,UnityEngine.dll的UnityEngine命名空間中的Debug調(diào)式類(lèi)。該類(lèi)有Break、Logstr等方法。如圖:

已經(jīng)淘汰的U3D開(kāi)發(fā)技術(shù):

由于這些技術(shù)過(guò)于簡(jiǎn)單,非常容易被逆向,在現(xiàn)今的U3D中,已經(jīng)被淘汰

1. 把關(guān)鍵變量寫(xiě)成屬性,且可以被外部調(diào)用,表現(xiàn)為其關(guān)鍵變量是個(gè)屬性,存在get_XX和set_XX方法。現(xiàn)今,都是對(duì)變量進(jìn)行不可被調(diào)用的聲明,也就是為變量,表現(xiàn)為在Reflector中用藍(lán)色長(zhǎng)方體作為圖標(biāo),且往往其聲明為protected或private,而不是public

2. 不再存在如GetCoins(),這樣明顯的關(guān)鍵性函數(shù),即使有,要不代碼非常復(fù)雜,邏輯特別難懂,要不就是修改了也沒(méi)用的;

3. 不再存在關(guān)鍵性變量在使用時(shí)直接進(jìn)行賦值語(yǔ)句,如this.coinscount = 0,與上種情況相同

以上說(shuō)明只是讓大家知道,本例中這些情況是存在的。

Debug類(lèi)的初步使用下斷:

我們選擇GetCoins()這個(gè)函數(shù),我們加一句代碼Debug.Break()。那么在IL語(yǔ)言中怎么添加中,首先,我們要注意,在添加指令的時(shí)候,指令是call,類(lèi)型是Method,操作數(shù)是Debug.Break()這個(gè)函數(shù)。

我們的代碼就是:

Offset

OpCode

Operand

0

ldarg.0

1

ldfld

System.Int32 StrawberryPlayer::coinsCount

6

call

System.Void UnityEngine.Debug::Break()

11

ret

然后,我們回編,利用手機(jī)版的log工具(會(huì)在附件中里有),對(duì)其進(jìn)行l(wèi)og,我們發(fā)現(xiàn)游戲并沒(méi)有停止運(yùn)行,但是在這句代碼被執(zhí)行時(shí),會(huì)給予該代碼執(zhí)行的時(shí)間及一些狀態(tài),如果下多個(gè)這樣的斷點(diǎn),是完全可以了解一定的程序運(yùn)行邏輯的。

DLL的內(nèi)部注入HOOK:

首先,我們要知道,HOOKDLL究竟有多大的好處。HOOK就是注入,替換。我們舉個(gè)例子,上面已經(jīng)說(shuō)過(guò),現(xiàn)在關(guān)鍵性的變量都沒(méi)有g(shù)et,set,也不在函數(shù)中進(jìn)行賦值,總之一切都在U3D內(nèi)部邏輯完全,緊密貼合于組件。這就好比是客戶(hù)端和服務(wù)端,如果一直這么雙方聯(lián)系著,會(huì)對(duì)我們分析和修改帶來(lái)很大不便。我們注入就好比是中間人,假設(shè)我們注入是一個(gè)變量,那么這個(gè)變量可以去替換一個(gè)程序原先使用的變量在函數(shù)里出現(xiàn)的位置,我們根本不需要知道原本這個(gè)變量如何計(jì)算得到,我們只需要定義一下這個(gè)中間變量,然后賦值給原先的變量,然后觀察程序運(yùn)行的反應(yīng)和效果。這樣一來(lái),我們就找到了一個(gè)突破點(diǎn),順著這個(gè)點(diǎn),再繼續(xù)分析下去。本例中,我選取StrawberryPlayer類(lèi)中的StartRunning()函數(shù),變量則選取該類(lèi)里的coinsCount,在游戲中表示金幣數(shù),在StartRunning()函數(shù)中被賦值為0。

在進(jìn)行DLL HOOK之前,我們一定要知道,我們通過(guò)靜態(tài)分析,得到的關(guān)鍵類(lèi)、關(guān)鍵方法、關(guān)鍵變量是什么,任何動(dòng)態(tài)調(diào)試,如果沒(méi)有靜態(tài)分析時(shí)的確定目標(biāo),那就是無(wú)頭蒼蠅。本例的關(guān)鍵在剛剛已經(jīng)寫(xiě)得非常清楚。

接下來(lái),我們?cè)陉P(guān)鍵類(lèi)StrawberryPlayer類(lèi)右鍵,選擇Reflexil2.0(我的該插件版本是2.0),然后選擇inject field,即注入變量,這里要注意,注入的變量數(shù)據(jù)類(lèi)型要和原本想替換的變量數(shù)據(jù)類(lèi)型一致,本例的coinsCount是一個(gè)Int32型,變量命名為coinlog。

注入后,DLL加載會(huì)刷新一次,然后你就發(fā)現(xiàn)在該類(lèi)下有了coinlog變量。

下面,我們到StartRunning()函數(shù)中,在代碼的尾部添加以下幾句代碼,也就是先賦值coinlog變量為99999,再讓coinsCount=coinlog,最后Debug.Logstr(“金幣已做修改”)。對(duì)于賦值語(yǔ)句添加是基礎(chǔ)內(nèi)容,可去學(xué)習(xí)法總教程,對(duì)于Debug類(lèi)使用上述已經(jīng)說(shuō)過(guò),這里只給結(jié)果:

274

ldarg.0

275

ldc.i4

99999

280

stfld

System.Int32 StrawberryPlayer::coinlog

285

ldarg.0

286

ldarg.0

287

ldfld

System.Int32 StrawberryPlayer::coinlog

292

stfld

System.Int32 StrawberryPlayer::coinsCount

297

ldstr

金幣已做修改

302

call

System.Void UnityEngine.Debug::Log(System.Object)

307

ret

簡(jiǎn)單說(shuō)一下:274-280偏移指令是this.coinlog=99999;285-292偏移指令是coinsCount=coinlog;297-302偏移指令是Debug.Logstr(“金幣已做修改”)。注意一下,這里的274等數(shù)字是指令所在的相對(duì)偏移地址,也就是offset,如果簡(jiǎn)單用第幾句指令的話(huà),應(yīng)該是第86句-95句。

我們回編測(cè)試,自然游戲初始化的金幣就是99999了,用log手機(jī)版查看,也非常清晰,可以看到這個(gè)函數(shù)是何時(shí)被調(diào)用的。

下載地址:http://pan.baidu.com/s/1gfdfsbT

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的android unity hook,[原创]Unity3d安卓游戏DLL动态调式与HOOK基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。