对某APP的逆向之旅(1)

来源:互联网 发布:3dmax测试软件 编辑:程序博客网 时间:2024/06/05 08:40

最近在研究游戏辅助相关的技术,因此有了下面的文章。
前面的准备工作,再此就不多介绍了,直接进入主题。
java层代码如下:

    static {        System.loadLibrary("encode");    }    public static int a(Context arg4) {        if(Thread.currentThread().getName().equals("main")) {            throw new IllegalStateException("runRootCommand can\'t run on main thread.");        }        int v0 = -1;        try {            String v1 = String.valueOf(arg4.getFilesDir().getAbsolutePath()) + "/gearcorez";            String v2 = System.getProperty("os.arch");            if(v2 != null && !v2.contains("arm")) {                return v0;            }            RootManager.a(arg4, "gearcore", v1);            RootManager.a(arg4, "speedman", arg4.getFilesDir() + "/libspeedman.so");            String v0_2 = String.valueOf(arg4.getFilesDir().getAbsolutePath()) + "/gearcore";            RootManager.decode(arg4.getApplicationContext(), v1, v0_2);            v0 = RootManager.a(arg4.getApplicationContext(), v0_2);            ag.a("suc=" + v0);        }        catch(IOException v0_1) {            IOException v1_1 = v0_1;            v0 = -2;            v1_1.printStackTrace();        }        arg4.deleteFile("gearcore");        return v0;    }

可以看到加载了encode动态库,并在函数a(Context arg4)中进行处理。过程为首先通过RootManager.a(, ,)函数进行文件拷贝,然后通过RootManager.decode函数进行解密,最后通过函数RootManager.a(,)运行解密后的文件。
其中函数RootManager.a(, ,)如下:

private static void a(Context arg5, String arg6, String arg7) {        int v3;        BufferedInputStream v1 = new BufferedInputStream(arg5.getAssets().open(arg6));        FileOutputStream v2 = new FileOutputStream(arg7);        byte[] v0 = new byte[4096];        try {            while(true) {            label_6:                v3 = v1.read(v0);                if(v3 != -1) {                    goto label_14;                }                v2.flush();                break;            }        }        catch(Throwable v0_1) {            goto label_17;        }        v2.close();        v1.close();        return;        try {        label_14:            v2.write(v0, 0, v3);            goto label_6;        }        catch(Throwable v0_1) {        label_17:            v2.close();            v1.close();            throw v0_1;        }    }

将assets中文件拷贝到指定目录中,函数比较简单。
本节,我们主要来分析下解密函数
IDA载入encode动态库文件,来到decode函数处
这里写图片描述

F5,其中参数名和变量名,是我修改过的,这个根据个人习惯,分析时修改即可。
这里写图片描述

获取包名
这里写图片描述

然后,通过一个算法解密字符串,算法如下:
这里写图片描述

然后,将解密后的字符传和包名比较,根据比较结果,进行文件的解密操作。
这里写图片描述

最后,附上算法还原后的代码(我也写到了so文件中),如下:

static unsigned char key[48] = { 0x70,0,0xc8,0,0x74,0,0x6a,0,0x32,0,                                 0x78,0,0x68,0,0x7b,0,0x77,0,0x78,0,                                 0x76,0,0x7e,0,0x3a,0,0x74,0,0x6f,0,                                 0x7c,0,0x75,0,0x84,0,0x82,0,0x78,0,                                 0x79,0,0x79,0,0x16,0,0};JNIEXPORT void JNICALL Java_example_com_applications_MainActivity_decode(JNIEnv *env, jobject obj, jobject context, jstring encodePath, jstring decodePath){    char temp[48];    char decodeKey[24];    //Context的类    jclass context_clazz = env->GetObjectClass(context);    // 得到 getPackageName 方法的 ID    jmethodID methodId_package = env->GetMethodID(context_clazz, "getPackageName", "()Ljava/lang/String;");    if (methodId_package != NULL)    {        // 获得当前应用的包名        jstring appPackageName = (jstring)env->CallObjectMethod(context, methodId_package);        const char* strPackage = env->GetStringUTFChars(appPackageName, 0);        LOGD("package name: %s", strPackage);        memcpy(temp, key, 0x2e);        int value = -1, index = 0, salt = 0;        for (int i = 0, j = 1; j < 23; ++i, ++j, ++value)        {            salt = 0;            index = i;            if (i > 0)            {                if (i == 1)                    continue;                index = value;                salt = value;            }            decodeKey[index] = temp[2 * i] - 1 - salt;        }        char* pMem = NULL;        pMem = (char*)malloc(0x16);        snprintf(pMem, 0x16, "%s", decodeKey);        LOGD("decodeKey: %s", decodeKey);        //简单的保护工作        if (!strcmp(strPackage, pMem))        {            const char* strEncodePath = env->GetStringUTFChars(encodePath, 0);            const char* strDecodePath = env->GetStringUTFChars(decodePath, 0);            FILE *fpEncode = fopen(strEncodePath, "rb");            if (fpEncode)            {                FILE *fpDecode = fopen(strDecodePath, "wb");                if (fpDecode)                {                    fseek(fpEncode, 0, 0);                    uint8_t nextByte;                    fread(&nextByte, 1, 1, fpEncode);                    uint8_t xorKey = nextByte;                    uint8_t decodeByte;                    while (fread(&nextByte, 1, 1, fpEncode))                    {                        decodeByte = ~((nextByte - 30) ^ xorKey) & 0xFF;                        nextByte = decodeByte;                        fputc(decodeByte, fpDecode);                    }                    fclose(fpDecode);                    chmod(strDecodePath, 0x1ED);                }                fclose(fpEncode);            }            remove(strEncodePath);            env->ReleaseStringUTFChars(encodePath, strEncodePath);            env->ReleaseStringUTFChars(decodePath, strDecodePath);            env->ReleaseStringUTFChars(appPackageName, strPackage);            free(pMem);        }        else         {            env->ReleaseStringUTFChars(appPackageName, strPackage);            free(pMem);        }    }}

其中上面解密后的字符串为
这里写图片描述

分析过程比较简单,仅供娱乐!

0 0
原创粉丝点击