栏目分类
[原创]Unity3D手游破盾之旅-Android安全-看雪-安全社区|安全招聘|kanxue.com
发布日期:2025-01-04 17:33 点击次数:159
工具与环境:手机: 小米4系统版本: 4.4.2Hook 框架: Cydia substrate 和 iqyi的xHook某易游戏出了一款篮球游戏,试玩了一下,内容就不过多的评价了,出于职业习惯,对它的保护系统倒是很感兴趣。先行基础是必须会用Cydia substrate这个hook框架,如果不会用请先去论坛搜索教程。先静态分析一下libmono.so,各种关键函数都搜不到,应该是对so进行处理了,然而,在动态运行时,总要还原的嘛。先定义MonoImage结构体,后续dump文件时有用。
struct _MonoImage {
int ref_count;
void *raw_data_handle;
char *raw_data;
int raw_data_len;
};
闲话少说,直接上神器Cydia substrate,使用Cydia substrate框架去hook dlopen函数和hook libmono.so中的mono_image_open_from_data_with_name,启动代码如下:
MSConfig(MSFilterLibrary, "/system/lib/libdvm.so");
Void* (*old_dlopen)(const char *filename, int myflags);
void* new_dlopen( const char *filename, int myflags) {
if(!(strstr(filename, "/system/lib/")))
{
LOGE("[dlopen] The dlopen name : %s.\n", filename);
}
void *handle = NULL;
handle = orig_dlopen(filename, myflags);
if(strstr(filename, "libunity.so")) {
hookU3D();
}
return handle;
}
MSInitialize {
//获取dlopen地址
void *dlopen_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlopen);
//hook dlopen方法
MSHookFunction((void*)dlopen_addr, (void*)&new_dlopen, (void**)&orig_dlopen);
}
//hookU3D函数和替换函数如下:
_MonoImage *(* orig_my_open)(char *data, int32_t data_len, int need_copy, int *status, int refonly, char *name);
_MonoImage* new_ my_open(char *data, int32_t data_len, int need_copy, int *status, int refonly, char *name)
{
_MonoImage *ret = orig_my_open(data, data_len, need_copy, status, refonly, name);
if(strstr(name, "Assembly-CSharp")) {
if(strstr(name, "arp.dl"))
{
saveDllFile(ret->raw_data,data_len, getFilePath(".dll", "Assembly-CSharp").c_str());
}
else {
saveDllFile(ret->raw_data,data_len,getFilePath(".dll","Assembly-CSharp-firstpass").c_str());
}
}
return ret;
}
void hookU3D()
{
void *myhandle = dlopen("libmono.so", RTLD_NOW | RTLD_GLOBAL);
void*addr = dlsym(myhandle, "mono_image_open_from_data_with_name");
MSHookFunction(addr, (void *) new_my_open,(void **) &orig_my_open);
}
不出所料,游戏崩了,通过代码打印出函数所在地址的前8位:
void printOpcode(char *addr)
{
LOGD("Addr %p --> 8 : x x x x x x x x",addr,addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],addr[6],addr[7]);
LOGD("Addr %p --> 16 : x x x x x x x x",addr,addr[8],addr[9],addr[10],addr[11],addr[12],addr[13],addr[14],addr[15]);
LOGD("Addr %p --> 24 : x x x x x x x x",addr,addr[16],addr[17],addr[18],addr[19],addr[20],addr[21],addr[22],addr[23]);
LOGD("Addr %p --> 32 : x x x x x x x x",addr,addr[24],addr[25],addr[26],addr[27],addr[28],addr[29],addr[30],addr[31]);
}
输出结果:
前面4位为 04 f0 1f e5 转换为arm汇编为 LDR PC, [PC, #-4],为跳转到指定目标地址的特征码,inline hook中常见得特征码。后面4位为要跳转到的地址 为 0x75e6bf09。
分析到这里,既然保护系统会先Hook,那我就去hook那个要跳转的地址吧,这样就可以改变流程为 原函数 --> 我的函数 --> 保护系统中的处理函数。这样就可以在我的函数中对保护系统中的处理函数的返回结果进行处理了。
//代理hook函数
void hook_proxy(void *handle)
{
(void *)hook_addr = dlsym(handle, "mono_image_open_from_data_with_name");
// get jump addr's first 8 bytes
proxy_offset = *reinterpret_cast<int *>(hook_addr + 4 );
// Hook by Cydia Substrate
MSHookFunction((void *) (proxy_offset), (void *) new_my_open,(void **) &orig_my_open);
}
// 修改hookU3D函数内容
void hookU3D()
{
void *handle = dlopen("libmono.so", RTLD_GLOBAL | RTLD_NOW);
hook_proxy(handle);
}
嗯,插件编译安装后,愉快的运行游戏,然而,游戏加载到Assembly-CSharp-firstpass.dll时居然还是崩了。此时,内心的崩溃的,连续骚扰了几个大牛,突然某人的一句话惊醒梦中人啊。那就是可以试试got表的hook嘛,根据unity3d的版本,2017之前的版本,都会在got表中存在mono_image_open_from_data_with_name这些关键函数的嘛。
确定好思路后,直接开干,Got hook最近iqiyi不是才开源一个xHook框架滴嘛,正好整合进Cydia substrate试试。
从git(https://github.com/iqiyi/xHook)上获取到源码,添加进项目中。在配置文件Android.mk的LOCAL_C_INCLUDES 和 LOCAL_SRC_FILES中添加相应的文件。
LOCAL_C_INCLUDES += $(LOCAL_PATH)/ELEHook/include \
$(LOCAL_PATH)/xHook/include
LOCAL_SRC_FILES += xHook/xhook.c \
xHook/xh_core.c \
xHook/xh_elf.c \
xHook/xh_jni.c \
xHook/xh_log.c \
xHook/xh_util.c \
xHook/xh_version.c
定义got hook函数如下:
void hook_Got()
{
while(1)
{
void *base = get_module_base(getpid(), "libunity.so");
if(base != NULL)
{
if(xhook_register(".*libunity.so$", "mono_image_open_from_data_with_name", (void *)new_my_open, (void **)&orig_my_open) != 0)
{
return;
}
if(xhook_refresh(1) != 0)
{
LOGE("[U3DHook] GOT hook failed!\n");
return;
}
break;
}
}
编译运行,游戏正常运行了,在指定的目录下去查看,只dump出了Assemlby-CSharp-firstpass.dll,直接使用dnSpy打开,报错了,无法查看。
仔细想了一下,肯定是对文件进行了什么操作,需要修复,这里就不讲修复过程了,有兴趣的自己去看看这两篇文章(https://www.cnblogs.com/dwlsxj/p/4052871.html , https://www.cnblogs.com/dwlsxj/p/PE.html)后,就能修复了。多学点东西,吃透了才是自己的。修复后再使用dnSpy打开,结果如下:
通过此函数,再到相应的so文件中查看相关的函数,分析后得到Assembly-CSharp.dll直接通过此so中进行加载,通过hook 相关函数后直接dump出文件,使用dySpy打开后如下所示:
至此,关键文件和源码获取完毕。
总的来说,该套保护方案还是比较强。分析这个还是用了很多时间。技术较菜,求大牛轻喷。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
下一篇:MOLI万站,正式上线
相关资讯