首页
论坛
课程
招聘
[原创]一道简单的ollvm算法题还原
2021-6-28 00:08 11406

[原创]一道简单的ollvm算法题还原

2021-6-28 00:08
11406

本题出自看雪3W班 12月ollvm题

题目要求

得益于Unicorn的强大的指令trace能力,可以很容易实现对cpu执行的每一条汇编指令的跟踪,进而对ollvm保护的函数进行剪枝,去掉虚假块,大大提高逆向分析效率。请分别使用Unidbg和Stalker引擎完成对该app中的jnicheck函数的trace跟踪,并简单分析该apk逻辑,找出flag。

解题思路

题目要求使用unidbg对ollvm加密后的算法进行还原。需要调用的native函数中,又会使用CallStaticBooleanMethodV调用另一个native函数。当时unidbg本身好像不支持这种方式,需要对unidbg代码进行部分修改之后才能正确进行模拟执行。
可以模拟执行之后,简单的思路就是使用unidbg进行trace找出哪些代码分支是可能被执行的,哪些条件分支是可以被优化掉的,之后对so进行patch,再使用ida进行分析。

知识点

本题主要有两个知识点,第一是对unidbg本身的修改使得能够支持一些原本不支持的场景,第二是对函数进行trace后patch源文件减少ollvm的干扰。

解题步骤

DvmObject.java 中新增initArgs,用于初始化调用参数

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
60
public void initArgs(Emulator<?> emulator, Object...args) {
    if (objectType == null) {
        throw new IllegalStateException("objectType is null");
    }
    initArgs(emulator, vm, this, args);
}
public static Arguments initArgs(Emulator<?> emulator, VM vm, DvmObject<?> thisObj, Object...args) {
    List<Object> list = new ArrayList<>(10);
    list.add(vm.getJNIEnv());
    list.add(thisObj.hashCode());
    if (args != null) {
        for (Object arg : args) {
            if (arg instanceof Boolean) {
                list.add((Boolean) arg ? VM.JNI_TRUE : VM.JNI_FALSE);
                continue;
            } else if(arg instanceof Hashable) {
                list.add(arg.hashCode()); // dvm object
 
                if(arg instanceof DvmObject) {
                    vm.addLocalObject((DvmObject<?>) arg);
                }
                continue;
            } else if (arg instanceof String) {
                StringObject str = new StringObject(vm, (String) arg);
                list.add(str.hashCode());
                vm.addLocalObject(str);
                continue;
            } else if(arg instanceof byte[]) {
                ByteArray array = new ByteArray(vm, (byte[]) arg);
                list.add(array.hashCode());
                vm.addLocalObject(array);
                continue;
            }
 
            list.add(arg);
        }
    }
    args = list.toArray();
    List<Number> numList = new ArrayList<>(args.length);
    for (Object arg : args) {
        if (arg instanceof String) {
            numList.add(new StringNumber((String) arg));
        } else if(arg instanceof byte[]) {
            numList.add(new ByteArrayNumber((byte[]) arg));
        } else if(arg instanceof UnidbgPointer) {
            UnidbgPointer pointer = (UnidbgPointer) arg;
            numList.add(new PointerNumber(pointer));
        } else if(arg instanceof UnidbgStructure) {
            UnidbgStructure structure = (UnidbgStructure) arg;
            numList.add(new PointerNumber((UnidbgPointer) structure.getPointer()));
        } else if (arg instanceof Number) {
            numList.add((Number) arg);
        } else if(arg == null) {
            numList.add(new PointerNumber(null)); // null
        } else {
            throw new IllegalStateException("Unsupported arg: " + arg);
        }
    }
    return ARM.initArgs(emulator, true, numList.toArray(new Number[0]));
}

DalvikVM64.java中修改CallStaticBooleanMethodV的hook代码,用于支持函数直接初始化调用参数后直接修改pc来call,通过R0来区分判断是否是这种方式调用.

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
Pointer _CallStaticBooleanMethodV = svcMemory.registerSvc(new Arm64Svc() {
    @Override
    public long handle(Emulator<?> emulator) {
        UnidbgPointer clazz = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X1);
        UnidbgPointer jmethodID = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X2);
        UnidbgPointer va_list = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X3);
        if (log.isDebugEnabled()) {
            log.debug("CallStaticBooleanMethodV clazz=" + clazz + ", jmethodID=" + jmethodID + ", va_list=" + va_list);
        }
        DvmClass dvmClass = classMap.get(clazz.toIntPeer());
        DvmMethod dvmMethod = dvmClass == null ? null : dvmClass.getStaticMethod(jmethodID.toIntPeer());
        if (dvmMethod == null) {
            throw new BackendException();
        } else {
            long oriX0 = emulator.getBackend().reg_read(Arm64Const.UC_ARM64_REG_X0).longValue();
            VaList vaList = new VaList64(emulator, DalvikVM64.this, va_list, dvmMethod);
            long ret = dvmMethod.callStaticBooleanMethodV(vaList);
            long newX0 = emulator.getBackend().reg_read(Arm64Const.UC_ARM64_REG_X0).longValue();
            if (oriX0 != newX0) {
                ret = newX0 - 1;
            }
            if (verbose) {
                System.out.printf("JNIEnv->CallStaticBooleanMethodV(%s, %s(%s) => %s) was called from %s%n", dvmClass, dvmMethod.methodName, vaList.formatArgs(), ret == JNI_TRUE, UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_LR));
            }
            return ret;
        }
    }
});

MainActivity.java 主要的模拟调用代码

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package com.kanxue.crackme;
 
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.arm.backend.BlockHook;
import com.github.unidbg.linux.android.AndroidARM64Emulator;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.memory.Memory;
import capstone.Capstone;
import keystone.Keystone;
import keystone.KeystoneArchitecture;
import keystone.KeystoneMode;
import org.apache.commons.codec.binary.Hex;
import unicorn.Arm64Const;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
 
public class MainActivity {
    public static byte[] readFile(File file) throws IOException {
        long len = file.length();
        byte[] bytes = new byte[(int)len];
 
        try (FileInputStream in = new FileInputStream(file)) {
            in.read(bytes);
        }
 
        return bytes;
    }
 
    public static void main(String[] args) throws IOException {
        MainActivity mainActivity = new MainActivity();
        emulator = new AndroidARM64Emulator();
        Memory memory = emulator.getMemory();
        LibraryResolver resolver = new AndroidResolver(23);
        memory.setLibraryResolver(resolver);
        vm = emulator.createDalvikVM(null);
        vm.setVerbose(true);
        vm.setDvmClassFactory(new ProxyClassFactory());
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/kanxue-dec/03/libnative-lib.so"), true);
        dm.callJNI_OnLoad(emulator);
 
        crypt2Addr = dm.getModule().findSymbolByName("Java_com_kanxue_crackme_MainActivity_crypt2").getAddress();
 
        obj = ProxyDvmObject.createObject(vm,mainActivity);
//        emulator.traceCode(dm.getModule().base, dm.getModule().base + dm.getModule().size);
 
        Map<Long, List<String>> blockAsm = new HashMap<>();
        Map<Long, Long> blockEnd = new HashMap<>();
        Map<Long, List<Long>> blockCount = new HashMap<>();
        Map<Long, Set<Long>> jumpCount = new HashMap<>();
 
        long start = dm.getModule().base;
        long end = start + dm.getModule().size;
        System.out.println("base:" + Long.toHexString(dm.getModule().base) + " end:" + Long.toHexString(end));
 
        emulator.getBackend().hook_add_new((BlockHook) (backend, address, size, user) -> {
            blockEnd.put(address, address + size);
            if (!blockCount.containsKey(address)) {
                blockCount.put(address, new ArrayList<>());
            }
            if (!jumpCount.containsKey(lastBlock)) {
                jumpCount.put(lastBlock, new HashSet<>());
            }
            jumpCount.get(lastBlock).add(address);
            blockCount.get(address).add(lastBlock);
            lastBlock = address;
            if (!blockAsm.containsKey(address)) {
                Capstone.CsInsn[] csInsns = emulator.disassemble(address, size, 0);
                ArrayList<String> asms = new ArrayList<>(csInsns.length);
                for (Capstone.CsInsn csInsn : csInsns) {
                    asms.add(csInsn.mnemonic);
                }
                blockAsm.put(address, asms);
            }
        }, start, end, null);
 
        byte[] content = readFile(new File("unidbg-android/src/test/resources/example_binaries/kanxue-dec/03/libnative-lib.so"));
        Set<String> blackList = new HashSet<>();
        blackList.add("orr,tbnz");
        blackList.add("stur,tbnz");
        blackList.add("stur,tbz");
        blackList.add("str,tbz");
        blackList.add("str,tbnz");
 
        boolean result = obj.callJniMethodBoolean(emulator,"jnicheck(Ljava/lang/String;)Z","aaa");
        obj.callJniMethodBoolean(emulator,"jnicheck(Ljava/lang/String;)Z","bbbb");
        obj.callJniMethodBoolean(emulator,"jnicheck(Ljava/lang/String;)Z","cc");
 
        Keystone ks = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian);
 
        jumpCount.forEach((aLong, aLong2) -> {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append('[');
            aLong2.forEach(addr -> stringBuilder.append("0x" + Long.toHexString(addr) + ","));
            stringBuilder.setLength(stringBuilder.length() - 1);
            stringBuilder.append(']');
            List<String> asms = blockAsm.get(aLong);
            if (asms != null && asms.size() >= 2) {
                String lastTwo = asms.get(asms.size() - 2) + "," + asms.get(asms.size() - 1);
                stringBuilder.append(" <").append(lastTwo).append('>');
                if (aLong2.size() == 1) {
                    if (blackList.contains(lastTwo)) {
                        int address = blockEnd.get(aLong).intValue() - 4;
                        byte[] code = ks.assemble("b #0x" + Long.toHexString(aLong2.iterator().next()), address).getMachineCode();
                        System.out.println("file address: 0x" + Long.toHexString(address - start - 0x10000) + " patch address: 0x" + Long.toHexString(address) + " code:" + Hex.encodeHexString(code));
                        for (int i = 0; i < code.length; i++) {
                            content[(int) (address - start + i)] = code[i];
                        }
                    }
                }
            }
            System.out.println("0x" + Long.toHexString(aLong) + " : " + stringBuilder.toString());
        });
        try (FileOutputStream out = new FileOutputStream(new File("unidbg-android/src/test/resources/example_binaries/kanxue-dec/03/libnative-lib.fix.so"))) {
            out.write(content);
        }
        System.out.println("result:" + result);
    }
 
    public static boolean crypt2(String arg0) {
        obj.initArgs(emulator, arg0);
        // 通过R0告诉CallStaticBooleanMethodV忽略函数返回值
        long x0 = emulator.getBackend().reg_read(Arm64Const.UC_ARM64_REG_X0).longValue();
        emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0, x0 + 1);
        emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_PC, crypt2Addr);
        // 该返回值将被忽略
        return true;
    }
 
    private static long lastBlock = 0;
    private static AndroidEmulator emulator;
    private static VM vm;
    private static DvmObject obj;
    private static long crypt2Addr;
}

不太懂ollvm怎么剪枝,通过观察发现ollvm生成的很多块都有一些特征,于是直接通过一些简单的条件来把一些块末尾跳转直接改成无条件跳转.
条件是:1.这个块在执行时的下一个块是唯一的 2.块的结尾两条汇编指令符合一定特征

1
2
3
4
5
6
Set<String> blackList = new HashSet<>();
blackList.add("orr,tbnz");
blackList.add("stur,tbnz");
blackList.add("stur,tbz");
blackList.add("str,tbz");
blackList.add("str,tbnz");

然后随便用几个输入调用一下函数,让尽可能多的块被执行

1
2
3
obj.callJniMethodBoolean(emulator,"jnicheck(Ljava/lang/String;)Z","aaa");
obj.callJniMethodBoolean(emulator,"jnicheck(Ljava/lang/String;)Z","bbbb");
obj.callJniMethodBoolean(emulator,"jnicheck(Ljava/lang/String;)Z","cc");

之后把patch后的so保存下来.使用IDA进行分析
Java_com_kanxue_crackme_MainActivity_jnicheck的反编译结果如下

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
__int64 __fastcall Java_com_kanxue_crackme_MainActivity_jnicheck(__int64 a1, __int64 a2, __int64 a3)
{
  __int64 v3; // x0
  __int64 v4; // x8
  __int64 v5; // x11
  int v6; // w0
  __int64 v7; // x9
  __int64 v8; // x0
  __int64 v9; // x8
  __int64 v10; // x0
  __int64 v11; // x0
  __int64 v12; // x8
  __int64 v13; // x0
  __int64 v14; // x8
  char v15; // w0
  __int64 v16; // x8
  _BOOL4 v17; // w7
  unsigned int v18; // w9
  __int64 v20; // [xsp-110h] [xbp-480h] BYREF
  __int64 v21; // [xsp-100h] [xbp-470h] BYREF
  __int64 v22; // [xsp-F0h] [xbp-460h] BYREF
  __int64 v23; // [xsp-E0h] [xbp-450h] BYREF
  _BYTE v24[112]; // [xsp-D0h] [xbp-440h] BYREF
  __int64 v25; // [xsp-60h] [xbp-3D0h] BYREF
  __int64 v26; // [xsp-50h] [xbp-3C0h] BYREF
  _QWORD v27[6]; // [xsp-40h] [xbp-3B0h] BYREF
  _QWORD v28[72]; // [xsp-10h] [xbp-380h] BYREF
  int v29; // [xsp+238h] [xbp-138h]
  int v30; // [xsp+240h] [xbp-130h]
  int v31; // [xsp+244h] [xbp-12Ch]
  int v32; // [xsp+248h] [xbp-128h]
  int v33; // [xsp+24Ch] [xbp-124h]
  int v34; // [xsp+250h] [xbp-120h]
  int v35; // [xsp+258h] [xbp-118h]
  int v36; // [xsp+260h] [xbp-110h]
  int v37; // [xsp+268h] [xbp-108h]
  int v38; // [xsp+270h] [xbp-100h]
  int v39; // [xsp+278h] [xbp-F8h]
  int v40; // [xsp+280h] [xbp-F0h]
  int v41; // [xsp+288h] [xbp-E8h]
  _BOOL4 v42; // [xsp+28Ch] [xbp-E4h]
  int v43; // [xsp+290h] [xbp-E0h]
  int v44; // [xsp+294h] [xbp-DCh]
  __int64 v45; // [xsp+298h] [xbp-D8h]
  __int64 *v46; // [xsp+2A0h] [xbp-D0h]
  _BYTE *v47; // [xsp+2A8h] [xbp-C8h]
  char *v48; // [xsp+2B0h] [xbp-C0h]
  __int64 *v49; // [xsp+2B8h] [xbp-B8h]
  __int64 *v50; // [xsp+2C0h] [xbp-B0h]
  _QWORD *v51; // [xsp+2C8h] [xbp-A8h]
  _QWORD *v52; // [xsp+2D0h] [xbp-A0h]
  _BYTE *v53; // [xsp+2D8h] [xbp-98h]
  __int64 *v54; // [xsp+2E0h] [xbp-90h]
  __int64 *v55; // [xsp+2E8h] [xbp-88h]
  __int64 *v56; // [xsp+2F0h] [xbp-80h]
  int v57; // [xsp+2FCh] [xbp-74h]
  int v58; // [xsp+304h] [xbp-6Ch]
  int v59; // [xsp+30Ch] [xbp-64h]
  int v60; // [xsp+314h] [xbp-5Ch]
  int v61; // [xsp+31Ch] [xbp-54h]
  int v62; // [xsp+324h] [xbp-4Ch]
  int v63; // [xsp+32Ch] [xbp-44h]
  __int64 v64; // [xsp+330h] [xbp-40h]
  __int64 v65; // [xsp+338h] [xbp-38h]
  __int64 v66; // [xsp+340h] [xbp-30h]
  __int64 v67; // [xsp+348h] [xbp-28h]
 
  v67 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v66 = a3;
  v65 = a2;
  v64 = a1;
  v63 = y_14;
  v62 = y_14;
  v61 = y_14;
  v60 = y_14;
  v59 = y_14;
  v58 = y_14;
  v57 = y_14;
  v27[4] = a1;
  v27[2] = a2;
  v27[0] = a3;
  v56 = &v22;
  v55 = &v21;
  v54 = &v20;
  v53 = v28;
  v52 = v28;
  v51 = v27;
  v50 = &v26;
  v49 = &v25;
  v48 = v24;
  v47 = v24;
  v46 = &v23;
  v45 = 0LL;
  v3 = sub_26F30(a1, a3, 0LL);
  v4 = (__int64)v51;
  *(v51 - 2) = v3;
  *(v50 - 2) = v45;
  v5 = (__int64)v49;
  *((_DWORD *)v49 - 4) = 0;
  *(_OWORD *)(v5 - 32) = 0u;
  *(_OWORD *)(v5 - 48) = 0u;
  *(_OWORD *)(v5 - 64) = 0u;
  *(_OWORD *)(v5 - 80) = 0u;
  *(_OWORD *)(v5 - 96) = 0u;
  *(_OWORD *)(v5 - 112) = 0u;
  v6 = sprintf(v48, "%s666", *(const char **)(v4 - 16));
  v7 = *(v52 - 2);
  v44 = v6;
  v8 = sub_273D0(v7, v48);
  v9 = (__int64)v47;
  *((_QWORD *)v47 - 2) = v8;
  v10 = sub_26F30(*(v52 - 2), *(_QWORD *)(v9 - 16), v45);
  *(v46 - 2) = v10;
  v11 = sub_27BD0(*(v52 - 2), "com/kanxue/crackme/MainActivity");
  v12 = (__int64)v56;
  *(v56 - 2) = v11;
  v13 = sub_28C40(*(v52 - 2), *(_QWORD *)(v12 - 16), "crypt2", "(Ljava/lang/String;)Z");
  v14 = (__int64)v55;
  *(v55 - 2) = v13;
  v15 = sub_28EB8(*(v52 - 2), *(v56 - 2), *(_QWORD *)(v14 - 16), *((_QWORD *)v47 - 2));
  v16 = (__int64)v54;
  *((_BYTE *)v54 - 16) = v15;
  v17 = *(_BYTE *)(v16 - 16) != 0;
  v43 = *(unsigned __int8 *)(v16 - 16);
  v42 = v17;
  v41 = y_14;
  v40 = y_14;
  v39 = y_14;
  v38 = y_14;
  v37 = y_14;
  v36 = y_14;
  v35 = y_14;
  if ( v17 )
  {
    v34 = y_14;
    if ( ((x_13 * (x_13 - 1)) & 1) != 0 )
    {
      v33 = v34 - 9;
      if ( v34 > 9 )
        goto LABEL_9;
    }
    while ( 1 )
    {
      *v53 = 1;
      v32 = y_14;
      if ( ((x_13 * (x_13 - 1)) & 1) == 0 )
        break;
      v31 = v32 - 9;
      if ( v32 <= 9 )
        break;
LABEL_9:
      *v53 = 1;
    }
  }
  else
  {
    v30 = y_14;
    *v53 = 0;
    v29 = y_14;
  }
  v18 = (unsigned __int8)*v53;
  v28[71] = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40) - v67;
  return v18;
}

可以看到返回值主要取决于sub_28EB8

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
__int64 sub_28EB8(JNIEnv *a1, __int64 a2, __int64 a3, ...)
{
  jboolean (*v3)(JNIEnv *, jclass, jmethodID, va_list); // x1
  jboolean v4; // w0
  __int64 v5; // x8
  gcc_va_list va1; // [xsp-80h] [xbp-220h] BYREF
  gcc_va_list va; // [xsp-60h] [xbp-200h] BYREF
  _QWORD v9[21]; // [xsp-30h] [xbp-1D0h] BYREF
  unsigned int v10; // [xsp+7Ch] [xbp-124h]
  _QWORD *v11; // [xsp+80h] [xbp-120h]
  jboolean (*v12)(JNIEnv *, jclass, jmethodID, va_list); // [xsp+88h] [xbp-118h]
  int v13; // [xsp+94h] [xbp-10Ch]
  int v14; // [xsp+9Ch] [xbp-104h]
  int v15; // [xsp+A4h] [xbp-FCh]
  int v16; // [xsp+ACh] [xbp-F4h]
  int v17; // [xsp+B4h] [xbp-ECh]
  int v18; // [xsp+BCh] [xbp-E4h]
  int v19; // [xsp+C4h] [xbp-DCh]
  JNIEnv *v20; // [xsp+C8h] [xbp-D8h]
  void *v21; // [xsp+D0h] [xbp-D0h]
  __int64 v22; // [xsp+D8h] [xbp-C8h]
  __int64 v23; // [xsp+188h] [xbp-18h]
 
  va_start(va, a3);
  v23 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v22 = a3;
  v21 = (void *)a2;
  v20 = a1;
  v19 = y_24;
  v18 = y_24;
  v17 = y_24;
  v16 = y_24;
  v15 = y_24;
  v14 = y_24;
  v13 = y_24;
  v9[4] = a1;
  v9[2] = a2;
  v9[0] = a3;
  v3 = (*a1)->CallStaticBooleanMethodV;
  va_copy(va1, va);
  v12 = v3;
  v11 = v9;
  v4 = v3(a1, v21, (jmethodID)a3, va1);
  v5 = (__int64)v11;
  *((_BYTE *)v11 - 16) = v4;
  v10 = *(unsigned __int8 *)(v5 - 16);
  _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
  return v10;
}

sub_28EB8实际上就是去调用Java_com_kanxue_crackme_MainActivity_crypt2

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
__int64 __fastcall Java_com_kanxue_crackme_MainActivity_crypt2(__int64 a1, __int64 a2, __int64 a3)
{
  const char *v4; // [xsp+68h] [xbp-A8h]
  unsigned __int8 v5; // [xsp+8Ch] [xbp-84h]
  char s[16]; // [xsp+90h] [xbp-80h] BYREF
  __int128 v7; // [xsp+A0h] [xbp-70h]
  __int128 v8; // [xsp+B0h] [xbp-60h]
  __int128 v9; // [xsp+C0h] [xbp-50h]
  __int128 v10; // [xsp+D0h] [xbp-40h]
  __int128 v11; // [xsp+E0h] [xbp-30h]
  int v12; // [xsp+F0h] [xbp-20h]
  __int64 v13; // [xsp+F8h] [xbp-18h]
 
  v13 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v4 = (const char *)sub_26F30(a1, a3, 0LL);
  v12 = 0;
  v11 = 0u;
  v10 = 0u;
  v9 = 0u;
  v8 = 0u;
  v7 = 0u;
  *(_OWORD *)s = 0u;
  sprintf(s, "%s", v4);
  if ( (sub_22390(s) & 1) != 0 )
  {
    while ( ((x_25 * (x_25 - 1)) & 1) != 0 && y_26 > 9 )
      ;
    do
      v5 = 1;
    while ( ((x_25 * (x_25 - 1)) & 1) != 0 && y_26 > 9 );
    while ( ((x_25 * (x_25 - 1)) & 1) != 0 && y_26 > 9 )
      ;
  }
  else
  {
    v5 = 0;
  }
  _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
  return v5;
}

Java_com_kanxue_crackme_MainActivity_crypt2的返回值取决于sub_22390,通过调试可以知道它的参数就是我们的输入的字符串后面拼接666

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
__int64 __fastcall sub_22390(const char *a1)
{
  __int64 v1; // x0
  __int64 v2; // x8
  __int64 v4; // [xsp-40h] [xbp-4B0h] BYREF
  _QWORD v5[4]; // [xsp-30h] [xbp-4A0h] BYREF
  _DWORD v6[28]; // [xsp-10h] [xbp-480h] BYREF
  int v7; // [xsp+60h] [xbp-410h]
  int v8; // [xsp+64h] [xbp-40Ch]
  int v9; // [xsp+68h] [xbp-408h]
  int v10; // [xsp+6Ch] [xbp-404h]
  int v11; // [xsp+70h] [xbp-400h]
  int v12; // [xsp+74h] [xbp-3FCh]
  int v13; // [xsp+78h] [xbp-3F8h]
  int v14; // [xsp+7Ch] [xbp-3F4h]
  int v15; // [xsp+80h] [xbp-3F0h]
  int v16; // [xsp+84h] [xbp-3ECh]
  int v17; // [xsp+88h] [xbp-3E8h]
  int v18; // [xsp+8Ch] [xbp-3E4h]
  int v19; // [xsp+90h] [xbp-3E0h]
  int v20; // [xsp+94h] [xbp-3DCh]
  int v21; // [xsp+98h] [xbp-3D8h]
  int v22; // [xsp+9Ch] [xbp-3D4h]
  int v23; // [xsp+A0h] [xbp-3D0h]
  int v24; // [xsp+A4h] [xbp-3CCh]
  int v25; // [xsp+A8h] [xbp-3C8h]
  int v26; // [xsp+1A0h] [xbp-2D0h]
  int v27; // [xsp+1A4h] [xbp-2CCh]
  int v28; // [xsp+1A8h] [xbp-2C8h]
  int v29; // [xsp+1ACh] [xbp-2C4h]
  int v30; // [xsp+1B0h] [xbp-2C0h]
  int v31; // [xsp+1B4h] [xbp-2BCh]
  int v32; // [xsp+1B8h] [xbp-2B8h]
  int v33; // [xsp+1BCh] [xbp-2B4h]
  int v34; // [xsp+1C0h] [xbp-2B0h]
  int v35; // [xsp+1C4h] [xbp-2ACh]
  int v36; // [xsp+1C8h] [xbp-2A8h]
  int v37; // [xsp+1CCh] [xbp-2A4h]
  int v38; // [xsp+1D0h] [xbp-2A0h]
  int v39; // [xsp+1D4h] [xbp-29Ch]
  int v40; // [xsp+1D8h] [xbp-298h]
  int v41; // [xsp+1DCh] [xbp-294h]
  __int64 v42; // [xsp+1E0h] [xbp-290h]
  int v43; // [xsp+1F0h] [xbp-280h]
  int v44; // [xsp+1F4h] [xbp-27Ch]
  int v45; // [xsp+1FCh] [xbp-274h]
  int v46; // [xsp+204h] [xbp-26Ch]
  int v47; // [xsp+20Ch] [xbp-264h]
  int v48; // [xsp+214h] [xbp-25Ch]
  int v49; // [xsp+21Ch] [xbp-254h]
  int v50; // [xsp+224h] [xbp-24Ch]
  int v51; // [xsp+22Ch] [xbp-244h]
  int v52; // [xsp+234h] [xbp-23Ch]
  int v53; // [xsp+23Ch] [xbp-234h]
  int v54; // [xsp+244h] [xbp-22Ch]
  int v55; // [xsp+24Ch] [xbp-224h]
  int v56; // [xsp+254h] [xbp-21Ch]
  int v57; // [xsp+25Ch] [xbp-214h]
  int v58; // [xsp+264h] [xbp-20Ch]
  int v59; // [xsp+26Ch] [xbp-204h]
  int v60; // [xsp+274h] [xbp-1FCh]
  int v61; // [xsp+27Ch] [xbp-1F4h]
  int v62; // [xsp+284h] [xbp-1ECh]
  int v63; // [xsp+28Ch] [xbp-1E4h]
  int v64; // [xsp+294h] [xbp-1DCh]
  int v65; // [xsp+29Ch] [xbp-1D4h]
  int v66; // [xsp+2A4h] [xbp-1CCh]
  int v67; // [xsp+2ACh] [xbp-1C4h]
  int v68; // [xsp+2B0h] [xbp-1C0h]
  int v69; // [xsp+2B4h] [xbp-1BCh]
  int v70; // [xsp+2B8h] [xbp-1B8h]
  int v71; // [xsp+2BCh] [xbp-1B4h]
  int v72; // [xsp+2C0h] [xbp-1B0h]
  int v73; // [xsp+2C4h] [xbp-1ACh]
  int v74; // [xsp+2C8h] [xbp-1A8h]
  int v75; // [xsp+2CCh] [xbp-1A4h]
  int v76; // [xsp+2D0h] [xbp-1A0h]
  int v77; // [xsp+2D4h] [xbp-19Ch]
  int v78; // [xsp+2D8h] [xbp-198h]
  int v79; // [xsp+2DCh] [xbp-194h]
  int v80; // [xsp+2E0h] [xbp-190h]
  int v81; // [xsp+2E4h] [xbp-18Ch]
  int v82; // [xsp+2E8h] [xbp-188h]
  int v83; // [xsp+2ECh] [xbp-184h]
  int v84; // [xsp+2F0h] [xbp-180h]
  int v85; // [xsp+2F4h] [xbp-17Ch]
  int v86; // [xsp+2F8h] [xbp-178h]
  int v87; // [xsp+2FCh] [xbp-174h]
  int v88; // [xsp+300h] [xbp-170h]
  int v89; // [xsp+304h] [xbp-16Ch]
  int v90; // [xsp+308h] [xbp-168h]
  int v91; // [xsp+30Ch] [xbp-164h]
  int v92; // [xsp+310h] [xbp-160h]
  int v93; // [xsp+314h] [xbp-15Ch]
  int v94; // [xsp+318h] [xbp-158h]
  int v95; // [xsp+31Ch] [xbp-154h]
  int v96; // [xsp+320h] [xbp-150h]
  int v97; // [xsp+324h] [xbp-14Ch]
  int v98; // [xsp+328h] [xbp-148h]
  int v99; // [xsp+32Ch] [xbp-144h]
  int v100; // [xsp+330h] [xbp-140h]
  int v101; // [xsp+334h] [xbp-13Ch]
  int v102; // [xsp+338h] [xbp-138h]
  int v103; // [xsp+33Ch] [xbp-134h]
  int v104; // [xsp+340h] [xbp-130h]
  int v105; // [xsp+344h] [xbp-12Ch]
  int v106; // [xsp+348h] [xbp-128h]
  int v107; // [xsp+34Ch] [xbp-124h]
  int v108; // [xsp+350h] [xbp-120h]
  int v109; // [xsp+354h] [xbp-11Ch]
  int v110; // [xsp+358h] [xbp-118h]
  int v111; // [xsp+35Ch] [xbp-114h]
  int v112; // [xsp+360h] [xbp-110h]
  int v113; // [xsp+364h] [xbp-10Ch]
  int v114; // [xsp+368h] [xbp-108h]
  int v115; // [xsp+36Ch] [xbp-104h]
  int v116; // [xsp+370h] [xbp-100h]
  int v117; // [xsp+374h] [xbp-FCh]
  int v118; // [xsp+378h] [xbp-F8h]
  int v119; // [xsp+37Ch] [xbp-F4h]
  int v120; // [xsp+380h] [xbp-F0h]
  int v121; // [xsp+384h] [xbp-ECh]
  int v122; // [xsp+388h] [xbp-E8h]
  int v123; // [xsp+38Ch] [xbp-E4h]
  int v124; // [xsp+390h] [xbp-E0h]
  int v125; // [xsp+394h] [xbp-DCh]
  int v126; // [xsp+398h] [xbp-D8h]
  int v127; // [xsp+39Ch] [xbp-D4h]
  int v128; // [xsp+3A0h] [xbp-D0h]
  int v129; // [xsp+3A4h] [xbp-CCh]
  int v130; // [xsp+3A8h] [xbp-C8h]
  int v131; // [xsp+3ACh] [xbp-C4h]
  int v132; // [xsp+3B0h] [xbp-C0h]
  int v133; // [xsp+3B4h] [xbp-BCh]
  int v134; // [xsp+3B8h] [xbp-B8h]
  int v135; // [xsp+3BCh] [xbp-B4h]
  int v136; // [xsp+3C0h] [xbp-B0h]
  int v137; // [xsp+3C4h] [xbp-ACh]
  int v138; // [xsp+3C8h] [xbp-A8h]
  int v139; // [xsp+3CCh] [xbp-A4h]
  int v140; // [xsp+3D0h] [xbp-A0h]
  int v141; // [xsp+3D4h] [xbp-9Ch]
  int v142; // [xsp+3D8h] [xbp-98h]
  int v143; // [xsp+3DCh] [xbp-94h]
  int v144; // [xsp+3E0h] [xbp-90h]
  int v145; // [xsp+3E4h] [xbp-8Ch]
  int v146; // [xsp+3E8h] [xbp-88h]
  int v147; // [xsp+3ECh] [xbp-84h]
  int v148; // [xsp+3F4h] [xbp-7Ch]
  int v149; // [xsp+3FCh] [xbp-74h]
  int v150; // [xsp+404h] [xbp-6Ch]
  int v151; // [xsp+40Ch] [xbp-64h]
  int v152; // [xsp+414h] [xbp-5Ch]
  _BOOL4 v153; // [xsp+418h] [xbp-58h]
  int v154; // [xsp+41Ch] [xbp-54h]
  __int64 v155; // [xsp+420h] [xbp-50h]
  const char *v156; // [xsp+428h] [xbp-48h]
  _QWORD *v157; // [xsp+430h] [xbp-40h]
  __int64 *v158; // [xsp+438h] [xbp-38h]
  _BYTE *v159; // [xsp+440h] [xbp-30h]
  int v160; // [xsp+44Ch] [xbp-24h]
  const char *v161; // [xsp+450h] [xbp-20h]
  __int64 v162; // [xsp+458h] [xbp-18h]
 
  v162 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v161 = a1;
  v160 = y_12;
  v5[2] = a1;
  v4 = 0LL;
  v159 = v6;
  v158 = &v4;
  v157 = v5;
  v156 = a1;
  v155 = strlen(a1);
  v1 = sub_19A60(v156, v155, v158);
  v2 = (__int64)v157;
  *(v157 - 2) = v1;
  v154 = strcmp((const char *)qword_2C0C8, *(const char **)(v2 - 16));
  v153 = v154 == 0;
  v152 = y_12;
  v151 = y_12;
  v150 = y_12;
  v149 = y_12;
  v148 = y_12;
  if ( !v154 )
  {
    v147 = y_12;
    if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
      v146 = v147 - 9;
    do
    {
      v145 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
        break;
      v144 = v145 - 9;
    }
    while ( v145 > 9 );
    v143 = y_12;
    if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
    {
      v142 = v143 - 9;
      if ( v143 > 9 )
        goto LABEL_105;
    }
    while ( 1 )
    {
      v141 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
        break;
      v140 = v141 - 9;
      if ( v141 <= 9 )
        break;
LABEL_105:
      v25 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        v24 = v25 - 9;
      do
      {
        v23 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v22 = v23 - 9;
      }
      while ( v23 > 9 );
    }
    v139 = y_12;
    if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
      v138 = v139 - 9;
    do
    {
      v137 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        v136 = v137 - 9;
      do
      {
        v135 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v134 = v135 - 9;
      }
      while ( v135 > 9 );
      v133 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
        break;
      v132 = v133 - 9;
    }
    while ( v133 > 9 );
    v131 = y_12;
    if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
      v130 = v131 - 9;
    do
    {
      v129 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        v128 = v129 - 9;
      do
      {
        v127 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v126 = v127 - 9;
      }
      while ( v127 > 9 );
      v125 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        v124 = v125 - 9;
      do
      {
        v123 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v122 = v123 - 9;
        do
        {
          v121 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v120 = v121 - 9;
        }
        while ( v121 > 9 );
        v119 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v118 = v119 - 9;
      }
      while ( v119 > 9 );
      v117 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
        break;
      v116 = v117 - 9;
    }
    while ( v117 > 9 );
    v115 = y_12;
    if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
    {
      v114 = v115 - 9;
      if ( v115 > 9 )
        goto LABEL_111;
    }
    while ( 1 )
    {
      v113 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        v112 = v113 - 9;
      do
      {
        v111 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v110 = v111 - 9;
      }
      while ( v111 > 9 );
      v109 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
        break;
      v108 = v109 - 9;
      if ( v109 <= 9 )
        break;
LABEL_111:
      v21 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        v20 = v21 - 9;
      do
      {
        v19 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v18 = v19 - 9;
      }
      while ( v19 > 9 );
    }
    v107 = y_12;
    if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
      v106 = v107 - 9;
    while ( 1 )
    {
      v105 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
      {
        v104 = v105 - 9;
        if ( v105 > 9 )
          goto LABEL_116;
      }
      while ( 1 )
      {
        v103 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v102 = v103 - 9;
        do
        {
          v101 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v100 = v101 - 9;
        }
        while ( v101 > 9 );
        v99 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
          break;
        v98 = v99 - 9;
        if ( v99 <= 9 )
          break;
LABEL_116:
        v17 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v16 = v17 - 9;
        do
        {
          v15 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v14 = v15 - 9;
        }
        while ( v15 > 9 );
      }
      v97 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
      {
        v96 = v97 - 9;
        if ( v97 > 9 )
          continue;
      }
      v95 = y_12;
      if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
        goto LABEL_56;
      v94 = v95 - 9;
      if ( v95 <= 9 )
        goto LABEL_56;
      while ( 1 )
      {
        v41 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v40 = v41 - 9;
        do
        {
          v39 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v38 = v39 - 9;
        }
        while ( v39 > 9 );
        v37 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v36 = v37 - 9;
          if ( v37 > 9 )
          {
LABEL_126:
            v9 = y_12;
            if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
            {
              v8 = v9 - 9;
              if ( v9 > 9 )
LABEL_136:
                *v159 = 1;
            }
            *v159 = 1;
            v7 = y_12;
            if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
            {
              v6[27] = v7 - 9;
              if ( v7 > 9 )
                goto LABEL_136;
            }
          }
        }
        v35 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v34 = v35 - 9;
          if ( v35 > 9 )
LABEL_135:
            *v159 = 1;
        }
        *v159 = 1;
        v33 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v32 = v33 - 9;
          if ( v33 > 9 )
            goto LABEL_135;
        }
        v31 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v30 = v31 - 9;
          if ( v31 > 9 )
            goto LABEL_126;
        }
        v29 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v28 = v29 - 9;
        do
        {
          v27 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v26 = v27 - 9;
        }
        while ( v27 > 9 );
LABEL_56:
        v93 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v92 = v93 - 9;
        do
        {
          v91 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v90 = v91 - 9;
        }
        while ( v91 > 9 );
        v89 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v88 = v89 - 9;
        do
        {
          v87 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          {
            v86 = v87 - 9;
            if ( v87 > 9 )
              goto LABEL_121;
          }
          while ( 1 )
          {
            v85 = y_12;
            if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
              v84 = v85 - 9;
            do
            {
              v83 = y_12;
              if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
                break;
              v82 = v83 - 9;
            }
            while ( v83 > 9 );
            v81 = y_12;
            if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
              break;
            v80 = v81 - 9;
            if ( v81 <= 9 )
              break;
LABEL_121:
            v13 = y_12;
            if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
              v12 = v13 - 9;
            do
            {
              v11 = y_12;
              if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
                break;
              v10 = v11 - 9;
            }
            while ( v11 > 9 );
          }
          v79 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v78 = v79 - 9;
        }
        while ( v79 > 9 );
        v77 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v76 = v77 - 9;
          if ( v77 > 9 )
          {
LABEL_103:
            *v159 = 1;
            goto LABEL_74;
          }
        }
LABEL_74:
        *v159 = 1;
        v75 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v74 = v75 - 9;
          if ( v75 > 9 )
            goto LABEL_103;
        }
        v73 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
          v72 = v73 - 9;
        do
        {
          v71 = y_12;
          if ( ((x_11 * (x_11 - 1)) & 1) == 0 )
            break;
          v70 = v71 - 9;
        }
        while ( v71 > 9 );
        v69 = y_12;
        if ( ((x_11 * (x_11 - 1)) & 1) != 0 )
        {
          v68 = v69 - 9;
          if ( v69 > 9 )
            continue;
        }
        goto LABEL_84;
      }
    }
  }
  v67 = y_12;
  v66 = y_12;
  v65 = y_12;
  v64 = y_12;
  v63 = y_12;
  v62 = y_12;
  v61 = y_12;
  v60 = y_12;
  v59 = y_12;
  v58 = y_12;
  v57 = y_12;
  v56 = y_12;
  v55 = y_12;
  v54 = y_12;
  v53 = y_12;
  *v159 = 0;
  v52 = y_12;
  v51 = y_12;
  v50 = y_12;
LABEL_84:
  v49 = y_12;
  v48 = y_12;
  v47 = y_12;
  v46 = y_12;
  v45 = y_12;
  v44 = (unsigned __int8)*v159;
  v43 = y_12;
  v42 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40) - v162;
  return v44 & 1;
}

sub_22390中还是有大量的ollvm混淆后的分支,说明我们之前的几个错误输入都没有进入到里面执行,因此我们需要想办法构造一个输入来进入到里面进行执行,我们的输入首先被传入了sub_19A60中

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
60
61
62
63
64
65
66
67
68
_BYTE *__fastcall sub_19A60(__int64 a1, __int64 a2, __int64 *a3)
{
  int v4; // [xsp+78h] [xbp-38h]
  int v5; // [xsp+7Ch] [xbp-34h]
  _BYTE *v6; // [xsp+80h] [xbp-30h]
  __int64 v7; // [xsp+88h] [xbp-28h]
  _BYTE *v11; // [xsp+A8h] [xbp-8h]
 
  if ( a2 % 3 )
    v7 = 4 * (a2 / 3 + 1);
  else
    v7 = 4 * (a2 / 3);
  v6 = malloc((int)v7 + 1);
  if ( v6 )
  {
    v6[v7] = 0;
    *a3 = v7;
    v5 = 0;
    v4 = 0;
    while ( v5 < v7 - 2 )
    {
      while ( 1 )
      {
        v6[v5] = aAbcdefghijklmn[(int)*(unsigned __int8 *)(a1 + v4) >> 2];
        v6[v5 + 1] = aAbcdefghijklmn[(16 * (*(_BYTE *)(a1 + v4) & 3)) | ((int)*(unsigned __int8 *)(a1 + v4 + 1) >> 4)];
        v6[v5 + 2] = aAbcdefghijklmn[(4 * (*(_BYTE *)(a1 + v4 + 1) & 0xF)) | ((int)*(unsigned __int8 *)(a1 + v4 + 2) >> 6)];
        v6[v5 + 3] = aAbcdefghijklmn[*(_BYTE *)(a1 + v4 + 2) & 0x3F];
        if ( x * (x - 1) % 2u == 0 || y < 10 )
          break;
        v6[v5] = aAbcdefghijklmn[(int)*(unsigned __int8 *)(a1 + v4) >> 2];
        v6[v5 + 1] = aAbcdefghijklmn[(16 * (*(_BYTE *)(a1 + v4) & 3)) | ((int)*(unsigned __int8 *)(a1 + v4 + 1) >> 4)];
        v6[v5 + 2] = aAbcdefghijklmn[(4 * (*(_BYTE *)(a1 + v4 + 1) & 0xF)) | ((int)*(unsigned __int8 *)(a1 + v4 + 2) >> 6)];
        v6[v5 + 3] = aAbcdefghijklmn[*(_BYTE *)(a1 + v4 + 2) & 0x3F];
      }
      v4 += 3;
      v5 += 4;
    }
    if ( a2 % 3 == 1 )
    {
      v6[v5 - 2] = 61;
      v6[v5 - 1] = 61;
    }
    else if ( a2 % 3 == 2 )
    {
      v6[v5 - 1] = 61;
    }
    v11 = v6;
  }
  else
  {
    while ( x * (x - 1) % 2u != 0 && y >= 10 )
      ;
    while ( x * (x - 1) % 2u != 0 && y >= 10 )
      ;
    while ( x * (x - 1) % 2u != 0 && y >= 10 )
      ;
    do
      v11 = 0LL;
    while ( x * (x - 1) % 2u != 0 && y >= 10 );
    while ( x * (x - 1) % 2u != 0 && y >= 10 )
      ;
    while ( x * (x - 1) % 2u != 0 && y >= 10 )
      ;
    while ( x * (x - 1) % 2u != 0 && y >= 10 )
      ;
  }
  return v11;
}

很显然是一个base64的函数,通过调试可以知道之后的结果通过strcmp与WFVlNjY2进行比较来判断是否进入下面的分支中运行.WFVlNjY2解码得到XUe666,因此我们在模拟调用时以XUe作为参数再次运行后对so进行patch,可以发现XUe就是正确的答案,同时之前一些分支的混淆也被去除了

 

sub_22390

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
__int64 __fastcall sub_22390(const char *a1)
{
  __int64 v1; // x0
  __int64 v2; // x8
  __int64 v4; // [xsp-40h] [xbp-4B0h] BYREF
  _QWORD v5[4]; // [xsp-30h] [xbp-4A0h] BYREF
  __int64 v6; // [xsp-10h] [xbp-480h] BYREF
  char v7; // [xsp+1F4h] [xbp-27Ch]
  int v8; // [xsp+1FCh] [xbp-274h]
  int v9; // [xsp+204h] [xbp-26Ch]
  int v10; // [xsp+20Ch] [xbp-264h]
  int v11; // [xsp+214h] [xbp-25Ch]
  int v12; // [xsp+21Ch] [xbp-254h]
  int v13; // [xsp+224h] [xbp-24Ch]
  int v14; // [xsp+22Ch] [xbp-244h]
  int v15; // [xsp+234h] [xbp-23Ch]
  int v16; // [xsp+23Ch] [xbp-234h]
  int v17; // [xsp+244h] [xbp-22Ch]
  int v18; // [xsp+24Ch] [xbp-224h]
  int v19; // [xsp+254h] [xbp-21Ch]
  int v20; // [xsp+25Ch] [xbp-214h]
  int v21; // [xsp+264h] [xbp-20Ch]
  int v22; // [xsp+26Ch] [xbp-204h]
  int v23; // [xsp+274h] [xbp-1FCh]
  int v24; // [xsp+27Ch] [xbp-1F4h]
  int v25; // [xsp+284h] [xbp-1ECh]
  int v26; // [xsp+28Ch] [xbp-1E4h]
  int v27; // [xsp+294h] [xbp-1DCh]
  int v28; // [xsp+29Ch] [xbp-1D4h]
  int v29; // [xsp+2A4h] [xbp-1CCh]
  int v30; // [xsp+2ACh] [xbp-1C4h]
  int v31; // [xsp+2B4h] [xbp-1BCh]
  int v32; // [xsp+2BCh] [xbp-1B4h]
  int v33; // [xsp+2C4h] [xbp-1ACh]
  int v34; // [xsp+2CCh] [xbp-1A4h]
  int v35; // [xsp+2D4h] [xbp-19Ch]
  int v36; // [xsp+2DCh] [xbp-194h]
  int v37; // [xsp+2E4h] [xbp-18Ch]
  int v38; // [xsp+2ECh] [xbp-184h]
  int v39; // [xsp+2F4h] [xbp-17Ch]
  int v40; // [xsp+2FCh] [xbp-174h]
  int v41; // [xsp+304h] [xbp-16Ch]
  int v42; // [xsp+30Ch] [xbp-164h]
  int v43; // [xsp+314h] [xbp-15Ch]
  int v44; // [xsp+31Ch] [xbp-154h]
  int v45; // [xsp+324h] [xbp-14Ch]
  int v46; // [xsp+32Ch] [xbp-144h]
  int v47; // [xsp+334h] [xbp-13Ch]
  int v48; // [xsp+33Ch] [xbp-134h]
  int v49; // [xsp+344h] [xbp-12Ch]
  int v50; // [xsp+34Ch] [xbp-124h]
  int v51; // [xsp+354h] [xbp-11Ch]
  int v52; // [xsp+35Ch] [xbp-114h]
  int v53; // [xsp+364h] [xbp-10Ch]
  int v54; // [xsp+36Ch] [xbp-104h]
  int v55; // [xsp+374h] [xbp-FCh]
  int v56; // [xsp+37Ch] [xbp-F4h]
  int v57; // [xsp+384h] [xbp-ECh]
  int v58; // [xsp+38Ch] [xbp-E4h]
  int v59; // [xsp+394h] [xbp-DCh]
  int v60; // [xsp+39Ch] [xbp-D4h]
  int v61; // [xsp+3A4h] [xbp-CCh]
  int v62; // [xsp+3ACh] [xbp-C4h]
  int v63; // [xsp+3B4h] [xbp-BCh]
  int v64; // [xsp+3BCh] [xbp-B4h]
  int v65; // [xsp+3C4h] [xbp-ACh]
  int v66; // [xsp+3CCh] [xbp-A4h]
  int v67; // [xsp+3D4h] [xbp-9Ch]
  int v68; // [xsp+3DCh] [xbp-94h]
  int v69; // [xsp+3E4h] [xbp-8Ch]
  int v70; // [xsp+3ECh] [xbp-84h]
  int v71; // [xsp+3F4h] [xbp-7Ch]
  int v72; // [xsp+3FCh] [xbp-74h]
  int v73; // [xsp+404h] [xbp-6Ch]
  int v74; // [xsp+40Ch] [xbp-64h]
  int v75; // [xsp+414h] [xbp-5Ch]
  _BOOL4 v76; // [xsp+418h] [xbp-58h]
  int v77; // [xsp+41Ch] [xbp-54h]
  __int64 v78; // [xsp+420h] [xbp-50h]
  const char *v79; // [xsp+428h] [xbp-48h]
  _QWORD *v80; // [xsp+430h] [xbp-40h]
  __int64 *v81; // [xsp+438h] [xbp-38h]
  char *v82; // [xsp+440h] [xbp-30h]
  int v83; // [xsp+44Ch] [xbp-24h]
  const char *v84; // [xsp+450h] [xbp-20h]
  __int64 v85; // [xsp+458h] [xbp-18h]
 
  v85 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v84 = a1;
  v83 = y_12;
  v5[2] = a1;
  v4 = 0LL;
  v82 = (char *)&v6;
  v81 = &v4;
  v80 = v5;
  v79 = a1;
  v78 = strlen(a1);
  v1 = sub_19A60(v79, v78, v81);
  v2 = (__int64)v80;
  *(v80 - 2) = v1;
  v77 = strcmp((const char *)qword_2C0C8, *(const char **)(v2 - 16));
  v76 = v77 == 0;
  v75 = y_12;
  v74 = y_12;
  v73 = y_12;
  v72 = y_12;
  v71 = y_12;
  if ( v77 )
  {
    v30 = y_12;
    v29 = y_12;
    v28 = y_12;
    v27 = y_12;
    v26 = y_12;
    v25 = y_12;
    v24 = y_12;
    v23 = y_12;
    v22 = y_12;
    v21 = y_12;
    v20 = y_12;
    v19 = y_12;
    v18 = y_12;
    v17 = y_12;
    v16 = y_12;
    *v82 = 0;
    v15 = y_12;
    v14 = y_12;
    v13 = y_12;
  }
  else
  {
    v70 = y_12;
    v69 = y_12;
    v68 = y_12;
    v67 = y_12;
    v66 = y_12;
    v65 = y_12;
    v64 = y_12;
    v63 = y_12;
    v62 = y_12;
    v61 = y_12;
    v60 = y_12;
    v59 = y_12;
    v58 = y_12;
    v57 = y_12;
    v56 = y_12;
    v55 = y_12;
    v54 = y_12;
    v53 = y_12;
    v52 = y_12;
    v51 = y_12;
    v50 = y_12;
    v49 = y_12;
    v48 = y_12;
    v47 = y_12;
    v46 = y_12;
    v45 = y_12;
    v44 = y_12;
    v43 = y_12;
    v42 = y_12;
    v41 = y_12;
    v40 = y_12;
    v39 = y_12;
    v38 = y_12;
    v37 = y_12;
    v36 = y_12;
    v35 = y_12;
    *v82 = 1;
    v34 = y_12;
    v33 = y_12;
    v32 = y_12;
    v31 = y_12;
  }
  v12 = y_12;
  v11 = y_12;
  v10 = y_12;
  v9 = y_12;
  v8 = y_12;
  v7 = *v82;
  _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
  return v7 & 1;
}

去除混淆后,可以发现sub_22390的逻辑很简单,就是返回输入的值经过base64与一个常量比较的结果.至此整个逻辑分析完毕,正确答案是XUe

 

由于本题的ollvm混淆比较有特征性,所以才能够简单的去除掉。


2021 KCTF 秋季赛 防守篇-征题倒计时(11月14日截止)!

上传的附件:
收藏
点赞2
打赏
分享
最新回复 (1)
雪    币: 2482
活跃值: 活跃值 (1157)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Dyingchen 活跃值 2021-7-30 16:11
2
0
楼主能加个好友吗,您这个脚本我复现了很久没有成功,想问一下您相关问题
游客
登录 | 注册 方可回帖
返回