unidbg 主要是一个屌工具,可以在电脑上直接抠出安卓的函数, 用虚拟环境模拟运行, 这样直接不用开调试器了
主要参考了几个文章:
首先打开 apk 文件,找到 MainActivity
然后可以看到对于 flag 对比的逻辑主要在 inspect.inspect 中
public class inspect { public static boolean inspect(String input_str) { try { byte[] input_flag = input_str.getBytes(StandardCharsets.UTF_8); byte[] str2 = jni.getkey().getBytes(StandardCharsets.UTF_8); Arrays.copyOf(str2, 8); SecretKeySpec key = new SecretKeySpec(str2, "AES"); byte[] ivBytes = jni.getiv().getBytes(StandardCharsets.UTF_8); IvParameterSpec iv = new IvParameterSpec(ivBytes); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(1, key, iv); byte[] encryptedBytes = cipher.doFinal(input_flag); String encryptedFlag = Base64.encodeToString(encryptedBytes, 0).trim(); boolean bool = encryptedFlag.equals("JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw=="); if (!bool) { return true; } return false; } catch (Exception exception) { exception.printStackTrace(); return true; } }}
然后可以看到这个地方他用自己的函数去做了一个 DES 加密。只要拿到 key
和 iv
就行了。
理论上这个地方应该可以使用类似算法助手、frida 的 hook 工具,但是我的虚拟机只要运行到 jni 函数就会直接闪退,所以这个地方采用 unidbg 直接模拟运行出结果就行。
将这个程序用到的两个 so 文件丢到 unidbg 的 unidbg-android/src/test/resources/example_binaries/arm64-v8a
文件夹下面
然后创建一个自己的包 unidbg-android/src/test/java/dev/node/reso
, 再创建一个 MainActivity 类写代码模拟运行即可,
crack
函数中是主要的调用逻辑,其他部分都是必要的模版
package dev.node.reso;
import com.github.unidbg.AndroidEmulator;import com.github.unidbg.LibraryResolver;import com.github.unidbg.arm.backend.DynarmicFactory;import com.github.unidbg.linux.android.AndroidEmulatorBuilder;import com.github.unidbg.linux.android.AndroidResolver;import com.github.unidbg.linux.android.dvm.DalvikModule;import com.github.unidbg.linux.android.dvm.DvmClass;import com.github.unidbg.linux.android.dvm.DvmObject;import com.github.unidbg.linux.android.dvm.VM;import com.github.unidbg.memory.Memory;
import java.io.File;
public class MainActivity {
public static void main(String[] args) { long start = System.currentTimeMillis(); dev.node.reso.MainActivity mainActivity = new dev.node.reso.MainActivity(); System.out.println("load offset=" + (System.currentTimeMillis() - start) + "ms"); mainActivity.crack(); }
private final AndroidEmulator emulator; private final DvmClass dvmClass; private final VM vm;
private MainActivity() { emulator = AndroidEmulatorBuilder .for64Bit() .addBackendFactory(new DynarmicFactory(true)) .build(); Memory memory = emulator.getMemory(); LibraryResolver resolver = new AndroidResolver(23); // 自带 sdk 23 版本 memory.setLibraryResolver(resolver);
vm = emulator.createDalvikVM(new File("/Users/node/Downloads/app-debug.apk")); //打印日志 vm.setVerbose(true); DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/arm64-v8a/libSecret_entrance.so"), true); dm.callJNI_OnLoad(emulator); dvmClass = vm.resolveClass("com/example/re11113/jni"); // jni 函数所在的类 }
private void crack() { DvmObject<?> result = dvmClass.callStaticJniMethodObject(emulator, "getkey()Ljava/lang/String;"); System.out.println("result is => " + result.getValue());
result = dvmClass.callStaticJniMethodObject(emulator, "getiv()Ljava/lang/String;"); System.out.println("result is => " + result.getValue()); }}
运行结果如图:
最后使用 tools fx 密码学工具箱解密即可