HNHuangJingYU 发表于 2021-9-29 20:16

《攻防世界》MOBILE--easyjni

本帖最后由 HNHuangJingYU 于 2021-9-30 10:47 编辑

1.将easyjni.apk拖进jeb分析代码,和常一样进入启动页分析(职业病了都)

2.这里介绍输入字符进行判断,往往,一看便知又是逆向算法的题目

3.核心函数,将输入的字符串传入a类中的a函数进行加密,点进来看就知道就是一个Base64加密,只不过换了码表,之后再将java加密后的字符串穿入so层加密并且进行判断,打开ida:


4.从这里知道memcmp函数就是将内存中的前0x20个字节数据进行对比相等则返回0,后面对v13进行了判断如果v13==0则这个函数返回true,分析下来很简单,就是我们输入的函数经过两层加密后要等于”MbT3sQgX039i3g==AQOoMQFPskB1Bsc7”,首先我们来正向分析下:
signed int __fastcall Java_com_a_easyjni_MainActivity_ncheck(_JNIEnv *env, int jclass, int string)
{
int v3; // r8
_JNIEnv *env_1; // r5
void *string_1; // r8
const char *data; // r6
int index; // r0
char *v8; // r2
char v9; // r1
int index2; // r0
bool v11; // nf
unsigned __int8 v12; // vf
int v13; // r1
signed int result; // r0
char s1; //
char v16; //
int v17; //

v17 = v3;
env_1 = env;
string_1 = string;
data = env->functions->GetStringUTFChars(&env->functions, string, 0);//分配内存存储字符串
if ( strlen(data) == 32 ) //java层加密后的数据必须为32长度的字符串
{
    index = 0;    //flag{just_ANot#er_@p3}
    do
    {
      v8 = &s1;
      s1 = data;   //把data位 给 s1位
      v9 = data;       //把data位 给 s1位   
      v8 = v9;
    }
    while ( index != 16 );      //第一层循环是将data前16位和后16位换位置给s1
    env_1->functions->ReleaseStringUTFChars(&env_1->functions, string_1, data); //清空jVM内存配合GetStringUTFChars使用
    index2 = 0;
    do
    {
      v12 = __OFSUB__(index2, 30);
      v11 = index2 - 30 < 0;
      v16 = s1;      
      s1 = s1;
      s1 = v16;
      index2 += 2;
    }
    while ( v11 ^ v12 );    //将s1索引处1,2换位置 3,4换位置依次类推
    v13 = memcmp(s1, "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7", 0x20u);
    result = 0;
    if ( !v13 )
      result = 1;
}
else
{
    env_1->functions->ReleaseStringUTFChars(&env_1->functions, string_1, data);
    result = 0;
}
return result;
}
5.再进行逆向算法:@Test
public void demo6() {
    //如果输入1234567890123456789012
    //则加密后应该为:...9fH3T1Dd4coiKf==4f9GL1Cq91pKLfwW...........
    //但是ida调试的时候显示这个字符串害我搞了半天:...9fH3T1Dd4coiKf==4f9GL1Cq91pKLfwWWb...........(求大佬解答)

   
    System.out.println("----------------正向加密---------------");
    String inputString = "1234567890123456789012";
    System.out.println("输入的字符串:" + inputString);
    inputString = new AClass().a(inputString.getBytes());      //这个就是apk中加密函数的a类只不过我换了个名字看的清楚点
    System.out.println("java加密:" + inputString + "长度为:" + inputString.length());

    char[] data = inputString.toCharArray();
    char[] s1 = new char; //
    char v9;
    if (data.length == 32) {
      int index = 0;
      do {
            s1 = data;
            v9 = data;
            s1 = v9;
            index++;
      }
      while (index != 16);
      //第二次循环
      int index2 = 0;
      char v16;
      do {
            v16 = s1;
            s1 = s1;
            s1 = v16;
            index2 += 2;
      }
      while (index2 < 32);
      System.out.println("so加密后:");
      System.out.println(s1);
    }


    System.out.println("----------------逆向还原flag---------------");
    String flag = "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7";
    StringBuilder sb = new StringBuilder();
    char[] chars = flag.toCharArray();
    for (int i = 0; i < chars.length; i += 2) {
      char aChar = chars;
      chars = chars;
      chars = aChar;
    }

    List<Character> list = new ArrayList<>();
    for (int i = 0; i < chars.length; i++) {
      if (i < 16) {
            list.add(chars);
            chars = chars;
      } else
            chars = list.get(i - 16);
      sb.append(chars);
    }
    System.out.println("so还原:");
    System.out.println(sb);
    System.out.println("java还原:");
    new AClass().Base64Decode(sb.toString());      //java层逆向解码
}
6.再使用还原还原,这里就是easy_apk那题的向算法:public void Base64Decode(String enflag) {
    StringBuilder flag = new StringBuilder();
    String flag_temp = "";
    for(int i = 0;i < enflag.length();i+=4)
    {
      String enf = enflag.substring(i,i+4);
      byte flag1 = (byte)(((getIndex(enf.charAt(0)) & 255) << 2 | ((getIndex(enf.charAt(1)) & 255) >>> 4)));
      byte flag2 = (byte)(((getIndex(enf.charAt(1)) & 255) << 4 | ((getIndex(enf.charAt(2)) & 255) >>> 2)));
      byte flag3 = (byte)(((getIndex(enf.charAt(2)) & 255) << 6 | ((getIndex(enf.charAt(3)) & 255))));

      flag_temp = "" + (char)flag1 + (char)flag2 + (char)flag3;
      flag.append(flag_temp);
    }
    System.out.println(flag);
}

public byte getIndex(char x)
{
    byte index = -1;
    String talbe = new String(AClass.a);
    if(x != '=') {
      index = (byte) talbe.indexOf(x);
    }
    else {
      index = 0;
    }
    return index;
}

最后打印结果:flag{just_ANot#er_@p3}

xiaohuihui3 发表于 2021-9-30 10:26

Design 发表于 2021-9-30 10:31

大佬,你是咋修复jni 结构的

HNHuangJingYU 发表于 2021-9-30 10:38

Design 发表于 2021-9-30 10:31
大佬,你是咋修复jni 结构的
正常情况来说,如果是静态函数那么参数一是JNIEnv,参数二是jclass,参数三、四就是java传入的参数了,动态函数(JNIOnload)参数一就是JavaVm,参数二是jobject,参数三、四上同,明白了对应的参数类型用jni.h头文件进行转化就可以了

Design 发表于 2021-9-30 11:50

HNHuangJingYU 发表于 2021-9-30 10:38
正常情况来说,如果是静态函数那么参数一是JNIEnv,参数二是jclass,参数三、四就是java传入的参数了,动 ...

可以顺便上传样本吗

wantwill 发表于 2021-10-19 17:14

技术就是生产力呀
页: [1]
查看完整版本: 《攻防世界》MOBILE--easyjni