点击上方↑↑↑蓝字[协议分析与还原]关注我们
“ 一次玩游戏过程中过某模拟器检测框架。”
作为一个各类程序爱好者,想象一下这个场景:你好不容易找到了一款好玩的游戏,兴冲冲地想用模拟器来玩,结果刚一登录就被游戏系统一脚踢了出来,提示你“请勿使用模拟器”。这就像是你精心准备了一桌大餐,却发现有人偷偷在你饭里放了辣椒,那种感觉,真是让人欲哭无泪。
就比如下面这样:
01
—
为什么游戏这么讨厌模拟器
游戏讨厌模拟器,无外乎以下几点:
外挂横行:模拟器就像是一个万能工具箱,外挂开发者们可以用它来制作各种各样的外挂,比如自动打怪、无限金币等等。这对于普通玩家来说,简直就是赤裸裸的伤害,谁愿意和开了挂的对手对战呢?
账号安全:模拟器很容易被用来批量注册账号、刷量等,这不仅会破坏游戏的平衡,还会给游戏运营商带来巨大的损失。
版权保护:有些模拟器被用来运行破解版游戏,这侵犯了开发商的版权,他们当然要想办法阻止这种行为。
游戏开发者为了防止玩家用模拟器,很是费了一番苦心,也取得了一番成果,用什么指纹识别,行为检测,系统调用检测搞定了大部分不按规矩来的玩家。
02
—
游戏怎么检测模拟器
当今天我准备玩游戏时,看到禁止模拟器运行这几个字,很是恼火。那就只能干掉你了。
老规矩,先解包看看你怎么检测的,一番探索,原来这个游戏检测过程中调用了好多次Java_com_snail_antifake_jni_PropertiesGet_native_1get__Ljava_lang_String_2Ljava_lang_String_2这个函数,网上搜一下,看看有没有现成的解决方法,居然发现了它的实现代码:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <sys/system_properties.h>
#include <android/log.h>
#include <string.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"lishang",__VA_ARGS__)
JNIEXPORT jstring JNICALL
Java_com_snail_antifake_jni_PropertiesGet_native_1get__Ljava_lang_String_2Ljava_lang_String_2
(JNIEnv *env, jclass clazz, jstring keyJ, jstring defJ) {
int len;
const char *key;
char buf[100];
jstring rvJ = NULL;
if (keyJ == NULL) {
LOGI("key must not be null.");
goto error;
}
key = (*env)->GetStringUTFChars(env, keyJ, NULL);
len = __system_property_get(key, buf);
if ((len <= 0) && (defJ != NULL)) {
rvJ = defJ;
} else if (len >= 0) {
rvJ = (*env)->NewStringUTF(env, buf);
} else {
rvJ = (*env)->NewStringUTF(env, "");
}
(*env)->ReleaseStringUTFChars(env, keyJ, key);
error:
return rvJ;
}
JNIEXPORT jstring JNICALL
Java_com_snail_antifake_jni_PropertiesGet_native_1get__Ljava_lang_String_2
(JNIEnv *env, jclass clazz, jstring keyJ) {
return Java_com_snail_antifake_jni_PropertiesGet_native_1get__Ljava_lang_String_2Ljava_lang_String_2(
env, clazz, keyJ, NULL);
}
看了看没啥用,我需要的是过检测,不是检测,还得自己来搞定它。看了下它的lib库,有这么几个so,很明显,libemulator_check.so英语我也认识啦:
可是,很遗憾,打开找了半天,没用前面频繁调用的函数,只有个Java_com_snail_antifake_jni_EmulatorDetectUtil_detect()函数,不想分析它。
继续找,终于在libproperty_get.so找到了想要的函数:
用IDA pro看了下伪码,正常返回0,不正常返回非0。
int __fastcall Java_com_snail_antifake_jni_PropertiesGet_native_1get__Ljava_lang_String_2Ljava_lang_String_2(
int *a1,
int a2,
int a3,
int a4)
{
int v7; // r9
int v8; // r0
int v9; // r1
int v10; // r0
_BYTE v12[100]; // [sp+0h] [bp-88h] BYREF
if ( a3 )
{
v7 = (*(int (__fastcall **)(int *, int, _DWORD))(*a1 + 0x2A4))(a1, a3, 0);
v8 = _system_property_get(v7, v12);
v9 = *a1;
if ( v8 > 0 )
goto LABEL_6;
if ( a4 )
{
LABEL_9:
(*(void (__fastcall **)(int *, int, int))(*a1 + 0x2A8))(a1, a3, v7);
return a4;
}
if ( v8 )
v10 = (*(int (__fastcall **)(int *, void *))(v9 + 0x29C))(a1, &unk_1D82);
else
LABEL_6:
v10 = (*(int (__fastcall **)(int *, _BYTE *))(v9 + 0x29C))(a1, v12);
a4 = v10;
goto LABEL_9;
}
a4 = 0;
_android_log_print(4, "lishang", "key must not be null.");
return a4;
}
那就好办了,让全部返回0就可以了。
03
—
我怎么过模拟器检测
分析到了函数,知道函数的内容,那过检测就容易了,简单点,改so就可以了。
首先找到想要修改的位置,这里,我们需要把LABEL_9返回的a4的值改成0,这个a4是函数里算出来的v10,改它就可以了。
用点偷懒的方法,直接把这个mov干掉就可以了,这个mov占两个字节,把这两字节改成0000即可,改好了,活基本就干完了,拿去试试:
一般来说,游戏会检测自己是否完整,是否被人背后下刀子了,我们先试试,没有检测就算幸运,有检测就再想办法更进一步了。
换进模拟器的/lib/arm目录,打开游戏试试,ok了。
大家开心的用起来,想干嘛就干嘛了。
04
—
轻松一下
活干完了,给大家出个题玩一玩。
有一天,一艘飞碟降落在了小明家的后院。从飞碟里走出来了一群外星人,他们长着大大的眼睛和长长的耳朵,手里还拿着一张纸。原来,他们想在地球上举办一场披萨派对,但是不知道怎么分披萨。小明是个喜欢数学的孩子,他自告奋勇地帮外星人来解决这个问题。外星人一共带来了12个披萨,他们有6个人,小明一家有4个人。小明该怎么分,才能让大家都能吃到同样多的披萨呢?
祝大家好运。
别忘点“在看”、“赞”和“分享”
新的规则,及时收推文要先给公号星标
别忘了星标一下,不然就错过了
长按进行关注,时刻进行交流。