内存解析libmono函数地址
前面文章搞了搞libil2cpp.so用来批量hook函数确实方便
https://bbs.pediy.com/thread-264813.htm
https://github.com/axhlzy/Il2CppHookScripts/tree/master/MonoHook
这里又想着搞搞libmono.so,在加载*.dll 的过程中看看能不能搞点东西出来
-
大概思路就分为四部分吧:
- 找到MonoImage,找到MonoClass(mono_image_loaded , mono_class_from_name)
- 找到函数Method的对象指针(mono_class_get_method_from_name)
- 能去主动调用函数(mono_runtime_invoke)
- 能去拦截函数的调用并获取和修改参数及其返回值(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)
}