内存解析libmono函数地址

前面文章搞了搞libil2cpp.so用来批量hook函数确实方便
https://bbs.pediy.com/thread-264813.htm
https://github.com/axhlzy/Il2CppHookScripts/tree/master/MonoHook
这里又想着搞搞libmono.so,在加载*.dll 的过程中看看能不能搞点东西出来


  • 大概思路就分为四部分吧:
  1. 找到MonoImage,找到MonoClass(mono_image_loaded , mono_class_from_name)
  2. 找到函数Method的对象指针(mono_class_get_method_from_name)
  3. 能去主动调用函数(mono_runtime_invoke)
  4. 能去拦截函数的调用并获取和修改参数及其返回值(mono_compile_method)

  • 找到MonoImage

启动时候HookDlopen,并在加载libmono.so的时候对导出函数 mono_image_open_from_data_with_name 进行Hook 拿到加载进来的dll的image对象,返回值就是一个_MonoImage结构体指针

_MonoImage结构体

关注上图中的
*raw_data dll在内存中的起始地址
raw_data_len dll的长度
即可写出,记录下arr_imgs_addr 和 arr_imgs_name

/**
 * 启动时候Hook mono_image_open_from_data_with_name 记录dll的起始位置,名称
 */
function HookMono() {
    //MonoImage *mono_image_open_from_data_with_name (char *data, uint32_t data_len, mono_bool need_copy,MonoImageOpenStatus *status, mono_bool refonly, const char *name);
    Interceptor.attach(Module.findExportByName(soName,"mono_image_open_from_data_with_name"), {
        onEnter: function (args) {
            this.name = args[5].readCString()
            this.size = args[1].toInt32()
        },
        onLeave: function (ret) {
            var t_ret = ret
            LOG("[*] "+t_ret + "\t"+this.name,LogColor.C36)
            var t_arr = this.name.split("/")
            var t_name = t_arr[(t_arr.length)-1].split(".dll")[0]
            arr_imgs_addr.push(String(t_ret))
            arr_imgs_name.push(t_name)
        }
    });
}

以上为启动的时候就进行Hook可以拿到Image结构体,不在启动的时候Hook同样也可以拿到
使用导出函数中的 mono_image_loaded 即可

MonoImage    *mono_image_loaded   (const char *name);

对于如何拿到method对象的话,我们还是冲导出函数入手,使用IDA查看一下导出函数,看看关键字method,可以看到这些函数,选几个长得像那么回事的函数去源码搜搜


导出函数

搜了一下源码得到一下声明

MonoMethod *mono_get_method (MonoImage *image, uint32_t token, MonoClass *klass);
MonoMethod *mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count);
MonoMethod *mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags);
MonoMethod *mono_class_get_methods       (MonoClass* klass, void **iter);

第一个token我们不好找,放弃
第二个flags也不好找,放弃
第四个显然就是一个通过class来遍历method的方法,可用但是没必要


  • 找到 MonoClass

所以看参数我们要去找 MonoClass,那继续去找导出函数


O475Z2F~WT6XC)51D_SM)SB.png

于是找到了 mono_class_from_name

//函数声明
MonoClass *mono_class_from_name       (MonoImage *image, const char* name_space, const char *name);

struct _MonoMethod {
    guint16 flags;  /* method flags */
    guint16 iflags; /* method implementation flags */
    guint32 token;
    MonoClass *klass; /* To what class does this method belong */
    MonoMethodSignature *signature;
    /* name is useful mostly for debugging */
    const char *name;
    .....
}

struct _MonoClass {
    MonoClass *element_class; 
    MonoClass *cast_class; 
    MonoClass **supertypes;
    guint16     idepth;
    guint8     rank;          
    int        instance_size; 
    ......
    MonoImage *image;
    const char *name;
    const char *name_space;
    ......
}

struct _MonoMethodSignature {
    MonoType     *ret;
#ifdef MONO_SMALL_CONFIG
    guint8        param_count;
    gint8         sentinelpos;
    unsigned int  generic_param_count : 5;
#else
    guint16       param_count;
    gint16        sentinelpos;
    unsigned int  generic_param_count : 16;
#endif
    unsigned int  call_convention     : 6;
    unsigned int  hasthis             : 1;
    unsigned int  explicit_this       : 1;
    unsigned int  pinvoke             : 1;
    unsigned int  is_inflated         : 1;
    unsigned int  has_type_parameters : 1;
    MonoType     *params [MONO_ZERO_LEN_ARRAY];
};

  • 找到函数Method

由此我们需要的参数也都筹齐了,写出一下hook代码

/**
 * 获得 MonoMethod
 * getMethod("UnityEngine","UnityEngine","Application","get_identifier",0)
 * getMethod("UnityEngine",'UnityEngine','Debug',"LogError",1,true)
 * @param {String}  imageName 
 * @param {String}  NameSpace 
 * @param {String}  className 
 * @param {String}  FunctName 
 * @param {Int}     argsCount 
 * @param {Boolean} showDetail 
 */
function getMethod(imageName,NameSpace,className,FunctName,argsCount,showDetail){
    if (imageName==undefined ||NameSpace==undefined||className==undefined||FunctName==undefined||argsCount==undefined) return ptr(0)
    if (showDetail == undefined) showDetail = false
    // var mono_thread_attach = new NativeFunction(Module.findExportByName(soName,"mono_thread_attach"),'pointer',['pointer'])
    // var mono_get_root_domain = new NativeFunction(Module.findExportByName(soName,"mono_get_root_domain"),'pointer',[])
    var mono_class_from_name = new NativeFunction(Module.findExportByName(soName,"mono_class_from_name"),'pointer',['pointer','pointer','pointer'])
    var mono_class_get_method_from_name = new NativeFunction(Module.findExportByName(soName,"mono_class_get_method_from_name"),'pointer',['pointer','pointer','int'])
    var mono_image_loaded = new NativeFunction(Module.findExportByName(soName,"mono_image_loaded"),'pointer',['pointer'])

    // mono_thread_attach(mono_get_root_domain())

    var p_image = getImageByName(imageName) == 0 ? mono_image_loaded(allcStr(imageName)) : getImageByName(imageName)
    var p_class = mono_class_from_name(ptr(p_image),allcStr(NameSpace),allcStr(className))
    var p_method = mono_class_get_method_from_name(p_class,allcStr(FunctName),argsCount)

    if (!showDetail) return ptr(p_method)

    LOG(getLine(85),LogColor.C33)
    LOG("MonoImage\t---->\t"+p_image,LogColor.C36)
    LOG("MonoClass\t---->\t"+p_class,LogColor.C36)
    LOG("MonoMethod\t---->\t"+p_method + " ("+ReadMethodName(p_method)+")",LogColor.C36)
    LOG(getLine(85),LogColor.C33)
}

运行见效果:


运行见效果

  • 主动调用函数

简单的看了一下导出函数,发现有一个 mono_runtime_invoke 传参就是 MonoMethod
于是可以尝试主动调用

//MonoObject* mono_runtime_invoke (MonoMethod *method, void *obj, void **params,MonoObject **exc);
var mono_runtime_invoke = new NativeFunction(Module.findExportByName(soName,"mono_runtime_invoke"),'pointer',['pointer','pointer','pointer','pointer'])
function invoke(monoMethod, obj, params,monoObject){
    obj = obj == undefined ? NULL : obj
    params = params == undefined ? NULL : params
    monoObject = monoObject == undefined ? NULL : monoObject
    return mono_runtime_invoke(ptr(monoMethod),obj,params,monoObject) 
}

这里选了一个get_identifier 来主动调用,可以发现没问题
(但是这里仅限于不带参数的Static方法)


主动调用

看着这个mono_runtime_invoke(MonoMethod *method, void *obj, void **params,MonoObject **exc)的声明参数就不想看他了,可以去研究,但是有更简单的方法,这里就简述一下这个简单的方法
我们换一个思路,总所周知,dll是被加载进去内存在动态编译的,这里我们手动调用mono_compile_method来编译这个MonoMethod即可得到类似于il2cpp中的MethodInfo的函数指针,详见下图

函数内存地址

  • 能去拦截函数的调用并获取和修改参数及其返回值

最后这部分也没啥好说的了,函数地址都有了,剩下的就是交给各位大佬为所欲为了

function TestAttach(){
    HookMonoMethod("UnityEngine",'UnityEngine','Debug',"LogError",1,{
        onEnter:function(args){
            LOG(readU16(args[0]))
        },
        onLeave:function(ret){}
    })
}

function HookMonoMethod(imageName,NameSpace,className,FunctName,argsCount,callbacks) {
    var mPtr = mono_compile_method(getMethod(imageName,NameSpace,className,FunctName,argsCount))
    Interceptor.attach(ptr(mPtr),callbacks)
}

补充:

https://github.com/axhlzy/Il2CppHookScripts/tree/master/MonoHook

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,442评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,604评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,576评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,652评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,495评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,370评论 1 274
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,792评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,435评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,735评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,777评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,553评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,399评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,806评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,038评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,330评论 1 253
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,766评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,964评论 2 337

推荐阅读更多精彩内容

  • [#go74pe]比较typeof与instanceof? 相同点:JavaScript 中 typeof 和 i...
    刘巴哥阅读 124评论 0 0
  • 转自长亭知乎专栏,实习时小姐姐的约稿,已经不在那边了所以版权不归我哈 笔者一直自认玩过不少游戏,无奈水平太菜,日常...
    hyrathon阅读 1,571评论 0 0
  • 0x00 引子 平时做应用测试时,手机root对测试人员来说是件很重要的事(沙箱目录访问、代码hook等操作),但...
    老江_阅读 5,524评论 2 7
  • 推荐指数: 6.0 书籍主旨关键词:特权、焦点、注意力、语言联想、情景联想 观点: 1.统计学现在叫数据分析,社会...
    Jenaral阅读 5,686评论 0 5
  • 城空了,有树长出来 我的城死了 铸起它的人,杀死它的人 不愿因为这件事而骄傲 一座城的终结 永远因为终结这件事而显...
    于十六阅读 2,841评论 6 17