[Honkai 3]Bypass MTP

发布于 2020-03-22  6.9k 次阅读


0x00 前言

总结部分 Honkai 3 Bypass MTP的方案,持续更新

0x01 方案1:hook tersafe2

本方案借鉴Google空间(现OurPlay)的做法。使用Google空间启动崩坏3,查看maps下存在关键内容:

实现了Bypass功能的kxqpplatform.so,32位

使用ida分析之,搜索字符串“tersafe2.so”,查看引用:

逐步回溯,得到基本流程如下:

sub_3FCF4

我们分别看看这个unk_118F3A和关键函数sub_4010C是什么:

unk_118F3A,用memmem来搞字符数组匹配?奇怪的知识增加了

试试用最后几个hex字符“00 00 B0 E1 1E FF 2F 51”在libtersafe2.so里能搜索到什么?:

orig_tersafe_sysopen in tersafe2.so,0xD6820
sub_4010C

可知实际返回的是orig_ tersafe_sysopen(a1,"",a3,a4,a5,a6,a7,a8,a9,a10,a11)。接下来我们就可以依葫芦画瓢,使用hookzz构造类似的hook

我们使用多开分身构造dkplugin后,因为其自身的libchaos.so已经实现了对dlopen的hook,可以参照VA中的写法,“借用”相关接口:

//VirtualApp/IOUniformer.cpp
HOOK_DEF(void*, dlopen, const char *filename, int flag) {
    int res;
    const char *redirect_path = relocate_path(filename, &res);
    void *ret = orig_dlopen(redirect_path, flag);
    onSoLoaded(filename, ret);
    ALOGD("dlopen : %s, return : %p.", redirect_path, ret);
    FREE(redirect_path, filename);
    return ret;
}

HOOK_DEF(void*, do_dlopen_V19, const char *filename, int flag, const void *extinfo) {
    int res;
    const char *redirect_path = relocate_path(filename, &res);
    void *ret = orig_do_dlopen_V19(redirect_path, flag, extinfo);
    onSoLoaded(filename, ret);
    ALOGD("do_dlopen : %s, return : %p.", redirect_path, ret);
    FREE(redirect_path, filename);
    return ret;
}

HOOK_DEF(void*, do_dlopen_V24, const char *name, int flags, const void *extinfo,
         void *caller_addr) {
    int res;
    const char *redirect_path = relocate_path(name, &res);
    void *ret = orig_do_dlopen_V24(redirect_path, flags, extinfo, caller_addr);
    onSoLoaded(name, ret);
    ALOGD("do_dlopen : %s, return : %p.", redirect_path, ret);
    FREE(redirect_path, name);
    return ret;
}

void onSoLoaded(const char *name, void *handle) {
}
libchaos.so
//jni\module_ReplaceDlopen.cpp
char* LIB_PATH;
bool count = false;

void initLibPath() {
    LIB_PATH = (char *)"/data/app/dkplugin.gxs.oza-Lwm7ENsog-HIXC1rUIv9Jw==/lib/arm/libchaos.so";
}

void onSoLoaded(const char *name, void *handle) {
    if (!count && strstr(name, "libtersafe2.so")) {
        count = true;
        anti_tersafe2((int32_t) handle);
    }
}

void *(*_R_dlopen)(const char *, int);
void *R_dlopen(const char *name, int flag) {
    void *handle = _R_dlopen(name, flag);
    onSoLoaded(name, handle);
    return handle;
}

void *(*_R_dlopen_V19)(const char *, int, int);
void *R_dlopen_V19(const char *name, int flag1, int flag2) {
    void *handle = _R_dlopen_V19(name, flag1, flag2);
    onSoLoaded(name, handle);
    return handle;
}

void *(*_R_dlopen_V24)(const char *, int, int, int);
void *R_dlopen_V24(const char *name, int flag1, int flag2, int flag3) {
    void *handle = _R_dlopen_V24(name, flag1, flag2, flag3);
    onSoLoaded(name, handle);
    return handle;
}

void *(*_R_dlopen_V26)(const char *, int, int, int);
void *R_dlopen_V26(const char *name, int flag1, int flag2, int flag3) {
    void *handle = _R_dlopen_V26(name, flag1, flag2, flag3);
    onSoLoaded(name, handle);
    return handle;
}

void ReplaceDlopen() {
    initLibPath();
    void *handle = dlopen(LIB_PATH, RTLD_NOW);
    if (!handle)
        return;

    void *dlopen_addr = dlsym(handle, "replace_dlopen");
    if (!dlopen_addr)
        return;

    void *V19_addr = dlsym(handle, "replace_do_dlopen_V19");
    if (!V19_addr)
        return;

    void *V24_addr = dlsym(handle, "replace_do_dlopen_V24");
    if (!V24_addr)
        return;

    void *V26_addr = dlsym(handle, "replace_do_dlopen_V26");
    if (!V26_addr)
        return;

    ZzHook((void *)dlopen_addr, (void *)R_dlopen, (void **)&_R_dlopen, NULL, NULL, false);
    ZzHook((void *)V19_addr, (void *)R_dlopen_V19, (void **)&_R_dlopen_V19, NULL, NULL, false);
    ZzHook((void *)V24_addr, (void *)R_dlopen_V24, (void **)&_R_dlopen_V24, NULL, NULL, false);
    ZzHook((void *)V26_addr, (void *)R_dlopen_V26, (void **)&_R_dlopen_V26, NULL, NULL, false);

    LOGI("dlopen hook done.\nhandle >> 0x%lX", (long)handle);
}
//jni\module_AntiMtp.cpp
//tersafe2hex 00 00 B0 E1 1E FF 2F 51
int (*orig_tersafe_sysopen)(int, const char*, int, int, int, int, int, int, int, int, int);
int new_tersafe_sysopen(int a1, const char* a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11) {
	return orig_tersafe_sysopen(a1, "", a3, a4, a5, a6, a7, a8, a9, a10, a11);
}

void anti_tersafe2(int32_t handle) {
	long tersafe2 = get_module_base("libtersafe2.so");
	ZzHook((void *)(tersafe2 + 0xD6820), (void *)new_tersafe_sysopen, (void **)&orig_tersafe_sysopen, NULL, NULL, false);
	LOGI("anti_tersafe2 done.");
}

0x02 方案2:hook il2cpp & tprt

//jni\module_AntiMtp.cpp
unsigned long NOP  = 0xE320F000;
unsigned long BXLR = 0xE12FFF1E;

void anti_tersafe2_inIl2cppLib(long base_addr) {	
    unsigned long addr = base_addr + 0x6A1DC54;//SDKMTPManager$$Tp2UserLogin
    unsigned long addr2 = base_addr + 0x0C63014;//NetworkManager$$OnGetValidDipatchServerData中的SDKMTPManager$$InitMTP
    unsigned long addr3 = base_addr + 0x378E1B4;//MonoMTP$$Tp2UserLogin
    ZzRuntimeCodePatch((void *)addr, (void *)&BXLR, 4);
    ZzRuntimeCodePatch((void *)addr2, (void *)&NOP, 4);
    ZzRuntimeCodePatch((void *)addr3, (void *)&BXLR, 4);
	LOGI("anti_tersafe2_inIl2cppLib done.");
}

hook了上述三个点位之后还是不够的,体现在游戏在正常运行120秒左右闪退。hook sleep并打印后发现存在10秒和120秒的轮询。遂hook之并返回86400秒:

//jni\module_AntiMtp.cpp
int new_sleep(unsigned int seconds) {
	if ((seconds == 120) || (seconds == 10)) {
		return sleep(86400);
	}
	return sleep(seconds);
}

void *anti_tprt(void *arg) {
	while (true) {
		long tprt = get_module_base("libtprt.so");
		if (tprt != 0) {
			xhook_register(".*/libtprt\\.so$", "sleep", (void *)new_sleep, NULL);
			xhook_refresh(0);
			break;
		}
		usleep(500000);
	}
	return NULL;
}

0x03 相关资料

libchaos.idb

libkxqpplatform.so

libtersafe2.so.idb