输入法注入源码_将注入进行到底:利用Mono注入C#游戏脚本
本文作者01dTan9,首發于三葉草小組博客:http://blog.sycsec.com/?? 致力于引領每一位對windows安全感興趣的萌新,希望讓萌新能夠對Windows有初步的了解。筆者的文章涉獵廣泛,從Windows基礎編程,加密與解密,跨平臺腳本語言,硬件安全,到游戲引擎逆向,涵蓋多方面,多領域的理論與技術,幫助萌新更快地從入門到入獄。
?1. 游戲腳本是什么?
腳本語言(英語:Scripting language)是為了縮短傳統的“編寫、編譯、鏈接、運行”(edit-compile-link-run)過程而創建的計算機編程語言。早期的腳本語言經常被稱為批處理語言或工作控制語言。一個腳本通常是解釋運行而非編譯。
游戲腳本由于腳本語言的開發成本低,許多游戲引擎不約而同地使用了腳本語言作為主要編程語言,比如大名鼎鼎的《魔獸世界》,就是使用的Lua進行開發的。本文所描述的游戲腳本是Unity(游戲引擎)中使用的主要編程語言——C#,并且Unity提供C#中的主要腳本API ,其腳本具有簡單、易學、易用的特性,目的就是希望能讓開發人員快速完成游戲開發。
2.為什么要注入游戲腳本?
1.?傳統注入方式
對于傳統的第三方游戲插件開發而言,由于沒有游戲廠商提供的官方接口,只能通過非常規的方式將插件的功能安裝在游戲中。
通常來說,這些安裝的方式與病毒的行為十分類似,更偏向于系統底層,比如利用Windows API修改目標進程中的數據,或者創建遠程線程讓目標進程執行匯編代碼或加載第三方庫(如DLL),更有甚者,直接在Windows內核中劫持目標進程網絡通訊,或進行APC注入。
目前傳統的應用層注入方式主要有以下幾種:
靜態注入類:
? ? ? ? 導入表注入
? ? ? ? 注冊表注入
? ? ? ? DLL劫持注入
動態注入類:
? ? ? ? ?鉤子注入
? ? ? ? ?APC注入
? ? ? ? ?遠程線程注入
? ? ? ? ?輸入法注入
? ? ? ? ?LSP注入
使用上述方法安裝的插件,其功能實現大部分要靠硬編碼、鉤子、內存修改來實現。這樣一來,需要耗費大量的時間分析游戲的匯編代碼與通過內存中的數據來構建結構體與游戲對象。
2. 從硬編碼注入到腳本注入
假如我們可以讓游戲腳本在游戲中執行,通過腳本直接使用游戲引擎封裝好的函數與對象,不就可以事半功倍了嗎?
3. Mono 與 Unity 下的C#游戲腳本
1.?Unity3D
Unity3D是由Unity Technol ogies開發的一個讓玩家輕松創建諸如三維視頻游戲、建筑可視化、實時三維動畫等類型互動內容的多平臺的綜合型游戲開發工具,是一個全面整合的專業游戲引擎。Unity使用戶能夠以2D和3D方式創建游戲,并且引擎提供C#中的主要腳本API ,用于插件形式的Unity編輯器,游戲本身以及拖放功能。在?C#作為引擎使用的主要編程語言之前,Unity支持?Boo?和?JavaScript?版本的?UnityScript。
2. Mono
Mono是一個免費的開源項目。由微軟的子公司Xamarin(前身為Novell,最初由Ximian)和.NET基金會領導。旨在構建符合ECMA(歐洲計算機制造商協會)標準的.NET Framework兼容工具集。包括?C#編譯器和帶有實時(JIT)編譯的公共語言運行時。
3.?Mono和Unity3D
簡單來說,Mono是Unity3D的一個運行時,負責C/C++和C#/CIL的交互。
舉個例子,隨便打開一個Unity游戲的根目錄,你會發現一個名為UnityPlayer.dll的動態鏈接庫,這個動態鏈接庫封裝是Unity的底層C++代碼。
在?游戲根目錄\Mono\EmbedRuntime\?(某些低版本Unity游戲目錄為游戲根目錄\Mono\,筆者的為 2018.2.0 Beta)下有一個名為mono.dll的動態鏈接庫,這個便是負責C/C++和C#/CIL的交互的模塊,網上有開源版本,但許多游戲公司為了防止游戲被惡意修改,通常都重新編譯mono.dll,在其中加入加密游戲數據與檢測惡意行為的代碼。
在游戲根目錄\游戲名_Data\Managed\中名為Assembly-CSharp.dll的文件便是C#腳本代碼。
三者的關系如下:
4.如何利用?Mono平臺實現游戲腳本入?
利用Mono平臺實現游戲腳本注入的主要方法有兩種,一種是靜態修改,直接PatchAssembly-CSharp.dll的代碼。
本文測試環境是在Windows下,主要是闡述思路,Android平臺的注入同理。
另一種是調用mono.dll的API,動態加載C#代碼(移動端同理),本文主要討論后者。
代碼實現主要由三部分組成:
? ? C#庫文件(負責實現第三方功能)
? ? 動態鏈接庫(用于在目標程序加載腳本)??
? ? 主程序(負責注入DLL到目標程序)
1.C#庫文件
負責實現第三方功能,代碼需要因游戲而定,主要是通過獲取或修改Unity原生組件(Transform、physics等)的數據實現第三方功能,也可以直接使用開發者定義的函數,但這種方法需要獲取游戲源代碼,需要解密腳本文件,在此不再贅述。
2.動態鏈接庫
在目標進程中載入C#腳本需要以下API,具體參數查閱mono官方文檔,上面都有詳細解釋。
通過文件名加載C#腳本文件鏡像。
????????mono_image_open_from_data
從文件鏡像中讀取并將C#代碼編譯為IL代碼,至此,C#代碼被即時編譯完畢。
????????mono_assembly_load_from_full
獲取IL代碼的鏡像。
????????mono_assembly_get_image
通過類名獲取類句柄,供????????????????????????mono\_class\_get\_method\_from\_name調用。
????????mono_class_from_name
通過類句柄和函數名獲取函數地址,供mono\_runtime\_invoke調用。
????????mono_class_get_method_from_name
通過函數地址運行IL代碼,代碼開始運行。
????????mono_runtime_invoke
在調用mono的API之前,我們需要獲取API的函數地址,基本方法如下:? ?
首先獲取mono.dll的模塊句柄
HMODULE hMono = GetModuleHandle(L"mono.dll");
再獲取API地址
typedef void* (__cdecl *MONO_IMAGE_OPEN_FROM_DATA)(char *ImageName);
MONO_IMAGE_OPEN_FROM_DATA mono_image_open_from_data;
mono_image_open_from_data = (MONO_IMAGE_OPEN_FROM_DATA)GetProcAddress(hMono, "mono_image_open_from_data");
用這種方法獲取所有需要調用的API
加載C#腳本代碼
#define ClassName L"ClassName" #define MethodName L"MethodName" #define name_space L"name_space" intptr_t raw_image = ImageOpenFromDataFull(file_data); intptr_t assembly = AssemblyLoadFromFull(raw_image); intptr_t image = AssemblyGetImage(assembly); intptr_t class_id = GetClassFromName(image, name_space, ClassName); intptr_t method = GetMethodFromName(class_id, MethodName); RuntimeInvokeMethod(method); |
還可以在DLL中實現C#熱更新,方便調試。
3.主程序
主程序負責將動態鏈接庫注入到目標程序。
通過上文提到的遠程線程注入方法
使用?CreateRemoteThread?遠程調用?LoadLibrary?即可。
5. 腳本注入攻防思路
1 . 如何對抗腳本注入(Anti-Cheat)
對抗腳本注入,有以下幾種、主要思路是在mono.dll上做手腳。
? ? ? ? ·當前流行的方法通過修改mono源碼,加密Assembly-CSharp.dll,并在mono_image_open_from_data里加入解密腳本的函數,這樣既可以防止腳本被靜態Patch,又可以防止動態注入。
? ? ? ? ? ·Android平臺下的進程保護
? ? ? ? ??·Windows平臺下的進程保護(R0、R3)
另外一種是在其他mono函數加入檢測代碼。筆者所遇到便是在mono_class_from_name加入檢測代碼,非原生腳本的加載都會導致函數調用崩潰。
2.?如何繞過防注入(By Pass)?
·利用沒有被修改的函數加載代碼,如mono_assembly_foreach枚舉IL代碼鏡像,繞過mono_class_from_name的檢測。
·重寫mono_class_from_name函數。
·加載另一個純凈的mono.dll,使用純凈模塊里面的函數來加載代碼。
6.總結
利用mono平臺注入C#代碼大大提高了開發效率,如果是單純用原生Unity組件開發出來的代碼基本上適用于所有用Unity引擎開發的游戲。
未來Unity可能會放棄mono平臺,轉用LICPP平臺,但是短時間內是不會放棄mono這個成熟的平臺的,所以,本方法在未來一段時間內都有利用價值。
點擊閱讀原文查看更多
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的输入法注入源码_将注入进行到底:利用Mono注入C#游戏脚本的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python翻译成计算机是啥_基于Pyt
- 下一篇: C#高级编程(第9版) 第06章 数组