吾愛破解 - LCG - LSG |安卓破解|病毒分析|www.mlqcje.live

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 7699|回復: 27
上一主題 下一主題

[Android 原創] 一套強勁的 Il2cpp Hook 框架

  [復制鏈接]
跳轉到指定樓層
樓主
CIBao 發表于 2019-6-22 08:31 回帖獎勵
本帖最后由 CIBao 于 2019-9-26 20:51 編輯

前言

前一段時間研究了一下Android的Native層Hook, 結果踩了一腳的雷
本文選用現成框架 VirtualApp 來實現Native層注入
對于il2cpp的Hook則采用的是替換類加載器進行針對性的HOOK
注意: VirtualApp 對安卓版本過高的系統不支持!

工具的準備

VirtualApp源碼一份: GayHub
AndroidStudio和SDK: AS官網
NDK低版本一份: NDK官方下載

以上工具獲取后請先自行編譯vapp的源碼, 能夠正常編譯出簽名版本即可

通過vapp的接口進行拓展

定位到目標接口

定位到 VirtualApp/lib/src/main/jni/Foundation/IOUniformer.cpp 文件
vapp劫持了所有內部軟件的dlopen調用, 留下了一個接口 onSoLoaded 以供開發人員進行其他操作

過濾無效的文件

onSoLoaded 的第一個形參是文件路徑, 第二個形參是句柄
只需要判斷 文件路徑 是否包含我們需要的lib就好了

if (!strstr(name, "libil2cpp.so"))
    return;

通過dlsym定位il2cpp的內置函數

查看Unity項目源碼中Class的定義, 會發現幾個有意思的函數

namespace il2cpp {
namespace vm{
class Class{
    ...
    static TypeInfo* FromName (Il2CppImage* image, const char* namespaze, const char *name);
    static const MethodInfo* GetMethodFromName (TypeInfo *klass, const char* name, int argsCount);
    static const MethodInfo* GetMethodFromNameFlags (TypeInfo *klass, const char* name, int argsCount, int32_t flags);
    ...
};
} /* namespace vm */
} /* namespace il2cpp */

FromName 函數是用來獲取類的鏡像 (字節碼文件?沒學過C#蛋疼T T)
GetMethodFromName 則是用來獲取指定的方法地址
可以直接通過 onSoLoaded 接口傳入的 句柄 定位這兩個函數

void *get_method_addr = dlsym(handle, "il2cpp_class_get_method_from_name");
void *get_class_addr = dlsym(handle, "il2cpp_class_from_name");

GetMethodFromName方法實際上會去調用GetMethodFromNameFlags
而flags參數是用來區分函數重載的各個函數, 默認為0

處理偏移

由于是導出函數, 編譯器都會進行優化, 都是抬手就 B指令
導致沒法使用Inline Hook, 想要使用Inline Hook去Hook函數, 這個函數就必須擁有兩條指令以上才能Hook成功


IDA中的il2cpp_class_get_method_from_name
IDA中的il2cpp_class_get_method_from_name函數
IDA中的il2cpp_class_get_method_from_name_0函數


IDA中的il2cpp_class_from_name
IDA中的il2cpp_class_from_name函數
IDA中的il2cpp_class_from_name_0函數
IDA中的sub_5F41AC8函數


通過手動解析 B指令 地址, 獲取到我們Hook的理想位置

inline void* CorrectBTarget(void *symbol){
    return ((char*)symbol + (*(int32_t*)(symbol) << 8 >> 6) + 8);
}
  1. *(int32_t *)(symbol) 獲取內存中指令的HEX
  2. << 8 抹除B指令的HEX, 但是內存中的HEX跟IDA中看到HEX是倒過來的, 所以不能用右移
  3. >> 6 初步解析指令的偏移
  4. + 8 人工計算具體偏移. 初步的解析指令偏移并不能一次性到點, 還是得靠人工修正一下
  5. (char*)symbol + 初始的地址加上偏移的地址就是目標的地址

若不止跳轉一次, 按照上面的步驟繼續解析加人工偏移就好了

inline void* CorrectGetMethodAddr(void *symbol) {
    return ((char*)symbol + (*(int32_t*)(symbol) << 8 >> 6) + (*(int32_t*)((char*)symbol + (*(int32_t*)(symbol) << 8 >> 6) + 12) << 8 >> 6) + 20);
}
inline void* CorrectGetClassAddr(void *symbol) {
    return ((char*)symbol + (*(int32_t*)(symbol) << 8 >> 6) + (*(int32_t *)((char*)symbol + (*(int32_t *)(symbol) << 8 >> 6) + 8) << 8 >> 6) + 16);
}

開始Hook

創建要Hook的函數原型, 還有要替換進去的新函數
要替換進去的函數的參數必須跟原函數一樣, 否則會替換失敗
那些特殊的 類指針/結構體指針/等等 直接寫 void* 就好了

void *(*_Il2cpp_ClassGetMethod)(void *, const char *, int, int32_t);
void *(*_Il2cpp_GetClass)(void *, const char *, const char *);

void *Il2cpp_ClassGetMethod(void *klass, const char *name, int argsCount, int32_t flags)
{
    return _Il2cpp_ClassGetMethod(klass, name, argsCount, flags);
}

void *Il2cpp_GetClass(void *image, const char *namespaze, const char *name)
{
    //LOGE("[namespaze]-> %s [name]-> %s", namespaze, name);
    return _Il2cpp_GetClass(image, namespaze, name);
}

寫好函數原型后就可以進行HOOK了, 直接使用vapp集成好的 MSHookFunction 直接HOOK就完事

//GetMethodFromName
MSHookFunction(CorrectGetMethodAddr(get_method_addr),
               (void*)Il2cpp_ClassGetMethod, 
               (void**)&_Il2cpp_ClassGetMethod);
//GetClassFromName
MSHookFunction(CorrectGetClassAddr(get_class_addr),
               (void*)Il2cpp_GetClass, 
               (void**)&_Il2cpp_GetClass);

正常啟動一遍vapp, 將目標應用安裝進去后啟動, 查看log輸出 (這里偷懶就莫得圖咯)

修改替換進去的函數實現針對性Hook

可以選擇判斷 名稱空間 或者 類名 進行下一步操作
因為后面還有Hook, 不能重復執行, 來一個全局變量限制一下就好

bool (*_AvatarManager_GetIsAutoBattle)(void*);
bool AvatarManager_GetIsAutoBattle(void* self) {return true;}

bool hookLock = false;
void* Il2cpp_GetClass(void* image, const char* namespaze, const char* name) {
    void* result = _Il2cpp_GetClass(image, namespaze, name);
    //限制Hook
    if (isHookAgain || strcmp(namespaze, "MoleMole"))
        return result;
    isHookAgain = true;

    //通過具體的 名稱空間 還有 類名, 獲取到對應的類
    void* AvatarManager = Il2cpp_GetClass(image, "MoleMole", "AvatarManager");
    //通過指定的類去Hook指定的方法
    hook_Il2cppFunc(AvatarManager, "get_isAutoBattle", 0,
                    AvatarManager_IsAutoBattle, &_AvatarManager_IsAutoBattle);

    return result;
}

注意一下: 由于C#是面向對象的語言, 普通成員函數第一個參數始終是實例自身, 也就是this, C#里寫代碼的時候并不需要自己加上, 但是Hook的函數原型必須加上, 否則會出大問題

hook_Il2cppFunc 函數對GetMethod的方法進行了封裝, 通過 類的image成員方法名, 即可獲取到對應的函數地址

template <class t1, class t2>
void hook_Il2cppFunc(void *classImage, const char *funcName, int argsCount, t1 newFunc, t2 origFunc)
{
    if (classImage)
    {
        int32_t *addr = (int32_t *)Il2cpp_ClassGetMethod(classImage, funcName, argsCount, 0);
        if (addr)
        {
            MSHookFunction(*addr, (void*)newFunc, (void**)origFunc);
            LOGD("HOOK SUCCESS >>> [%s]", funcName);
        }
        else
            LOGD("HOOK ERROR!! >>> [%s] ", funcName);
    }
}

argsCount 是函數原型的參數個數, 無需將this算入其內

想要Hook其他方法, 只需要寫上對應的 函數原型要Hook進去的新函數函數原型參數個數具體的類image, 并在 Il2cpp_GetClass 方法里面進行Hook, 就ok辣

總結

這套方案只要實現成功后基本上不需要過多的維護
用了一段時間了, 缺點總結兩點

  1. 遇到人工混淆的函數就嗝屁了
  2. 內部類目前還未找到方法實現抓取(螺的島就用到了大量的內部類)
    (之前的文章由于媒體庫炸了, 圖片全丟失, 所以重新優化了一遍)

相關 教程/工具

unity游戲生成與修改so文件教程
Perfare大大的Il2CppDumper工具
將注入進行到底:利用Mono注入C#游戲腳本

免費評分

參與人數 14威望 +1 吾愛幣 +27 熱心值 +13 收起 理由
zycode + 1 + 1 AS版本和NDK版本能詳細說說么。以前編譯的時候各種錯誤,最后放棄了
kwing112 + 1 我很贊同!
h080294 + 1 + 1 熱心回復!
qtfreet00 + 1 + 12 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
wxue + 1 + 1 [email protected]
5omggx + 1 + 1 [email protected]
CrazyNut + 2 + 1 膜拜大佬 學習一下
微若清風 + 1 + 1 [email protected]
www96 + 1 + 1 熱心回復!
獨行風云 + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
stars-one + 1 + 1 大佬,厲害!雖然我看得不是很懂。
笙若 + 1 + 1 [email protected]
末白 + 1 + 1 熱心回復!
XhyEax + 2 + 1 我很贊同!

查看全部評分

本帖被以下淘專輯推薦:

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
740002600 發表于 2019-9-29 20:16
大神,求教育, 下面的地址 怎么計算出來呀?
.text:0061823C F0 48 2D E9                                   STMFD           SP!, {R4-R7,R11,LR}
.text:00618240 10 B0 8D E2                                   ADD             R11, SP, #0x10
.text:00618244 08 D0 4D E2                                   SUB             SP, SP, #8
.text:00618248 00 40 A0 E1                                   MOV             R4, R0
.text:0061824C 0C 01 9F E5                                   LDR             R0, =(off_2A57B2C - 0x61825C)
.text:00618250 01 50 A0 E1                                   MOV             R5, R1
.text:00618254 00 00 9F E7                                   LDR             R0, [PC,R0] ; dword_2A9B364
.text:00618258 0C 00 80 E2                                   ADD             R0, R0, #0xC
.text:0061825C 00 00 84 E5                                   STR             R0, [R4]
.text:00618260 08 60 95 E5                                   LDR             R6, [R5,#8]
.text:00618264 06 00 A0 E1                                   MOV             R0, R6  ; s
.text:00618268 C5 FA F4 EB                                   BL              strlen
.text:0061826C 00 20 A0 E1                                   MOV             R2, R0
.text:00618270 04 00 A0 E1                                   MOV             R0, R4
.text:00618274 06 10 A0 E1                                   MOV             R1, R6
.text:00618278 9E A9 00 FA                                   BLX             sub_6428F8
.text:0061827C 2B 00 D5 E5                                   LDRB            R0, [R5,#0x2B]
.text:00618280 02 00 10 E3                                   TST             R0, #2
.text:00618284 24 00 00 0A                                   BEQ             loc_61831C
.text:00618288 1C 00 95 E5                                   LDR             R0, [R5,#0x1C]
.text:0061828C 08 60 90 E5                                   LDR             R6, [R0,#8]
.text:00618290 00 00 56 E3                                   CMP             R6, #0
.text:00618294 20 00 00 0A                                   BEQ             loc_61831C
推薦
pp7560 發表于 2019-9-30 19:21
大神,不會算,算了半天一直錯的,不知道怎么求出il2cpp_class_get_method_from_name正確地址的,這是的so 跳轉2次后的相關信息

.text:01A11998                     EXPORT il2cpp_class_get_method_from_name
.text:01A11998     il2cpp_class_get_method_from_name       ; DATA XREF: LOAD:0019BB18↑o
.text:01A11998 000                 B               j__ZN6il2cpp2vm5Class17GetMethodFromNameEP11Il2CppClassPKci ;  // plt loc_BFC8D0 il2cpp::vm::Class::GetMethodFromName(Il2CppClass *,char const*,int)
.text:01A11998     ; End of function il2cpp_class_get_method_from_name

loc_BFC8D0


.text:019EA184 ; il2cpp::vm::Class::GetMethodFromName(Il2CppClass *, char const*, int)
.text:019EA184                 EXPORT _ZN6il2cpp2vm5Class17GetMethodFromNameEP11Il2CppClassPKci
.text:019EA184 _ZN6il2cpp2vm5Class17GetMethodFromNameEP11Il2CppClassPKci
.text:019EA184                                         ; CODE XREF: il2cpp::vm::Class::GetMethodFromName(Il2CppClass *,char const*,int)+8↑j
.text:019EA184                                         ; DATA XREF: LOAD:002DD1C8↑o
.text:019EA184 ; __unwind {
.text:019EA184                 MOV             R3, #0
.text:019EA188                 B               j__ZN6il2cpp2vm5Class22GetMethodFromNameFlagsEP11Il2CppClassPKcii ; il2cpp::vm::Class::GetMethodFromNameFlags(Il2CppClass *,char const*,int,int)
.text:019EA188 ; } // starts at 19EA184
.text:019EA188 ; End of function il2cpp::vm::Class::GetMethodFromName(Il2CppClass *,char const*,int)
.text:019EA188
.text:019EA18C

.text:019EA18C ; Attributes: bp-based frame
.text:019EA18C
.text:019EA18C ; il2cpp::vm::Class::GetMethodFromNameFlags(Il2CppClass *, char const*, int, int)
.text:019EA18C                 EXPORT _ZN6il2cpp2vm5Class22GetMethodFromNameFlagsEP11Il2CppClassPKcii
.text:019EA18C _ZN6il2cpp2vm5Class22GetMethodFromNameFlagsEP11Il2CppClassPKcii
.text:019EA18C                                         ; CODE XREF: il2cpp::vm::Class::GetMethodFromNameFlags(Il2CppClass *,char const*,int,int)+8↑j
.text:019EA18C                                         ; DATA XREF: LOAD:0013B588↑o
.text:019EA18C ; __unwind {
.text:019EA18C                 STMFD           SP!, {R4-R11,LR}    //關鍵點應該是這里
.text:019EA190                 ADD             R11, SP, #0x1C
.text:019EA194                 SUB             SP, SP, #4
.text:019EA198                 MOV             R8, R3
.text:019EA19C                 MOV             R9, R2
.text:019EA1A0                 MOV             R6, R1
.text:019EA1A4                 MOV             R7, R0
.text:019EA1A8                 BL              j__ZN6il2cpp2vm5Class4InitEP11Il2CppClass ; il2cpp::vm::Class::Init(Il2CppClass *)
.text:019EA1AC                 MOV             R5, #0
.text:019EA1B0                 CMP             R7, #0
.text:019EA1B4                 BEQ             loc_19EA234
.text:019EA1B8                 MOV             R10, #0
.text:019EA1BC                 MOV             R4, SP
沙發
Light紫星 發表于 2019-6-22 09:00
3#
mancong122 發表于 2019-6-22 09:43
小老弟很有想法,遇到加殼的直接hook脫殼解密入口又能拓展出脫殼解密功能
4#
呱某包子 發表于 2019-6-22 10:14
膩害膩害
5#
多幸運遇見baby 發表于 2019-6-22 10:37
6#
胖子哦 發表于 2019-6-22 11:19
7#
syrmb 發表于 2019-6-22 12:08
神之GayHub
8#
花顏 發表于 2019-6-22 12:19
真的厲害~!!
9#
qhr319 發表于 2019-6-22 12:21
厲害支持
10#
lllcrhlll 發表于 2019-6-22 12:52
感謝分享
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:本版塊禁止灌水或回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2020-5-26 06:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表
内蒙古11选5开奖查询百度 秒速赛车开奖官网网址 广东麻将规则 新十一选五走势图一定牛 排列五开奖结果 澳洲幸运8官方网站开奖 体彩内蒙古快3走势图 澳洲幸运10平台群 哈皮河南麻将安卓版 宁夏11选五开奖结果走试图 棋牌娱乐在线看片 四人麻将游戏单机版下载 sg飞艇官方开奖记录 中原河南麻将房卡 2018开奖记录开奖现场 海南体彩4十l开奖号码 球探网足球即时比分