当前位置:   article > 正文

riru_riru-core

riru-core

riru官网

https://github.com/RikkaApps/Riru

 

1.riru原理

    Riru的原理是通过替换会被Zygote加载的libmemtrack.so从而实现Zygote注入,而安卓应用进程都是从Zygote fork的,注入了Zygote也就等同于注入了接下来会启动的游戏,也就可以轻松实现修改了。然后hook掉Zygote.nativeForkAndSpecialize函数监听app启动。

2.riru 安装

    Riru是Magisk的模块,所以首先要安装Magisk,不过现在手机root应该都是选择Magisk了,然后去Riru的Github的Releases页面下载最新的riru-core包,在magisk里安装,安装好Riru后就可以动手写自己的修改模块了。

 

3.开发riru模块

去Riru的Github上下载所有代码,根据官方README,先给自己的模块取个名字,比如perfare,然后修改riru-module-template/jni/main/Android.mk中的模块名字

1LOCAL_MODULE := libriru_perfare

 

接着修改riru-module-template/build.gradle中的模块信息

1

def moduleName = "perfare"

这两个地方的模块名字一定要一样,其他模块信息自己看着修改就好,修改好后就开始写代码吧,打开riru-module-template/jni/main/main.cpp

在main.cpp中本身已经写好了一些函数,我们只需要关注两个函数
nativeForkAndSpecializePre 通过解析参数appDataDir从而得到当前启动的进程包名,判断是不是我们要修改的游戏
nativeForkAndSpecializePost 在这里创建新线程进行修改

首先写个函数判断包名

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

static int enable_hack;

static const char* game_name = "com.aniplex.fategrandorder";

 

int isGame(JNIEnv *env, jstring appDataDir) {

    if (!appDataDir)

        return 0;

 

    const char *app_data_dir = env->GetStringUTFChars(appDataDir, NULL);

 

    int user = 0;

    static char package_name[256];

    if (sscanf(app_data_dir, "/data/%*[^/]/%d/%s", &user, package_name) != 2) {

        if (sscanf(app_data_dir, "/data/%*[^/]/%s", package_name) != 1) {

            package_name[0] = '\0';

            LOGW("can't parse %s", app_data_dir);

            return 0;

        }

    }

    env->ReleaseStringUTFChars(appDataDir, app_data_dir);

    if (strcmp(package_name, game_name) == 0) {

        LOGD("detect game: %s", package_name);

        return 1;

    }

    else {

        return 0;

    }

}

然后在nativeForkAndSpecializePre里调用这个函数

1

2

3

4

5

6

7

8

9

void nativeForkAndSpecializePre(

        JNIEnv *env, jclass clazz, jint *_uid, jint *gid, jintArray *gids, jint *runtime_flags,

        jobjectArray *rlimits, jint *_mount_external, jstring *se_info, jstring *se_name,

        jintArray *fdsToClose, jintArray *fdsToIgnore, jboolean *is_child_zygote,

        jstring *instructionSet, jstring *appDataDir, jstring *packageName,

        jobjectArray *packagesForUID, jstring *sandboxId) {

    // packageName, packagesForUID, sandboxId exists from Android Q

    enable_hack = isGame(env, *appDataDir);

}

之后就可以在nativeForkAndSpecializePost里根据enable_hack来修改了,这里选择启动一个新线程来修改

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

int nativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {

    if (res == 0) {

        // in app process

        if (enable_hack) {

            int ret;

            pthread_t ntid;

            if ((ret = pthread_create(&ntid, NULL, hack_thread, NULL))) {

                LOGE("can't create thread: %s\n"strerror(ret));

            }

        }

    else {

        // in zygote process, res is child pid

        // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66

    }

    return 0;

}

至于hack_thread里要怎么修改游戏就看你自己了,这里随便示范一个简单的libil2cpp.so修改,通过不断读取/proc/self/maps确定libil2cpp.so的载入和获取基址,然后直接通过指针修改text段代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

unsigned long get_module_base(const char* module_name)

{

    FILE *fp;

    unsigned long addr = 0;

    char *pch;

    char filename[32];

    char line[1024];

 

    snprintf(filename, sizeof(filename), "/proc/self/maps");

 

    fp = fopen(filename, "r");

 

    if (fp != NULL) {

        while (fgets(line, sizeof(line), fp)) {

            if (strstr(line, module_name)) {

                pch = strtok(line, "-");

                addr = strtoul(pch, NULL, 16);

                if (addr == 0x8000)

                    addr = 0;

                break;

            }

        }

        fclose(fp);

    }

    return addr;

}

 

void *hack_thread(void *arg)

{

    LOGD("hack thread :%d", gettid());

    unsigned long base_addr;

    while (true)

    {

        base_addr = get_module_base("libil2cpp.so");

        if (base_addr != 0) {

            break;

        }

    }

    LOGD("detect libil2cpp.so %lx", base_addr);

    LOGD("hack game begin");

 

    unsigned long hack_addr = base_addr + 偏移;

 

    //设置属性可写

    void* page_start = (void*)(hack_addr - hack_addr % PAGE_SIZE);

    if (-1 == mprotect(page_start, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) {

        LOGE("mprotect failed(%d)"errno);

        return NULL;

    }

 

    unsigned char* tmp = (unsigned char*)(void*)hack_addr;

    tmp[0] = 0x00;

    tmp[1] = 0x00;

    tmp[2] = 0x00;

    tmp[3] = 0x00;

 

    LOGD("hack game finish");

    return NULL;

}

到这里代码就写完了,可以使用gradlew.bat assembleMagiskRelease命令直接编译或者用Android Studio,在release文件夹下就会生成zip包,在Magisk安装即可

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/268283
推荐阅读
相关标签
  

闽ICP备14008679号