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 密码学工具箱解密即可