tujia民宿X-TJH及请求数据unidbg实现
环境
app 8.45.0
Java层
jadx搜索x-tjh
com.tujia.libs.engine.model.TJRequest.g
com.tujia.gundam.Gundam.a
com.tujia.gundam.Gundam.encrypt
最终X-TJH
是调用encrypt
函数,请求数据是调用BodyEncrypt
函数,这两个函数都是在libtujia_encrypt.so
中。
hook看看输入
android hooking watch class_method com.tujia.gun dam.Gundam.encrypt --dump-args --dump-return
android hooking watch class_method com.tujia.gun dam.Gundam.bodyEncrypt --dump-args --dump-return
固定参数
为了方便之后的逆向,frida固定输入,然后看看加密结果。
function call_encrypt() {
var Gundam = Java.use("com.tujia.gundam.Gundam");
var body = "{\"code\":\"hello everhu\"}";
var ret = Gundam.encrypt(
"key=nodeApiConfig",
"Mozilla/5.0",
"LON=null;LAT=null;",
body,
body.length,
1642084337
);
console.log(ret);
}
function call_bodyEncrypt() {
var Gundam = Java.use("com.tujia.gundam.Gundam");
var salt = "everever";
var body = "{\"code\":\"hello everhu\"}";
var ret = Gundam.bodyEncrypt(
"3",
1642126567,
salt,
salt.length,
body,
body.length
);
console.log(ret);
}
unidbg实现
public class TuJia extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
public static String pkgName = "com.tujia.hotel";
public static String apkPath = "unidbg-android/src/test/java/com/tujia/tujia8450.apk";
public static String soPath = "";
public TuJia() {
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName(pkgName).build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM(new File(apkPath));
vm.setJni(this);
vm.setVerbose(true);
DalvikModule dm = vm.loadLibrary("tujia_encrypt", true);
module = dm.getModule();
dm.callJNI_OnLoad(emulator);
}
public static void main(String[] args) {
TuJia test = new TuJia();
}
}
@Override
public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
switch (signature) {
case "com/tujia/hotel/TuJiaApplication->getInstance()Lcom/tujia/hotel/TuJiaApplication;": {
return vm.resolveClass("com/tujia/hotel/TuJiaApplication").newObject(null);
}
}
return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);
}
@Override
public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
switch (signature) {
case "com/tujia/hotel/TuJiaApplication->getPackageName()Ljava/lang/String;": {
return new StringObject(vm, pkgName);
}
}
return super.callObjectMethod(vm, dvmObject, signature, varArg);
}
case "com/tujia/hotel/TuJiaApplication->getPackageManager()Landroid/content/pm/PackageManager;": {
return vm.resolveClass("android/content/pm/PackageManager").newObject(null);
}
case "java/security/MessageDigest->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;": {
try {
MessageDigest digest = MessageDigest.getInstance(varArg.getObjectArg(0).getValue().toString());
return vm.resolveClass("java/security/MessageDigest").newObject(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
case "java/security/MessageDigest->digest([B)[B": {
MessageDigest digest = (MessageDigest) dvmObject.getValue();
byte[] data = digest.digest((byte[]) varArg.getObjectArg(0).getValue());
return new ByteArray(vm, data);
}
JNI_OnLoad补完了,开始调用。
public void call_encrypt() {
List<Object> list = new ArrayList<>(10);
list.add(vm.getJNIEnv());
list.add(vm.addLocalObject(0);
// url params
list.add(vm.addLocalObject(new StringObject(vm, "key=nodeApiConfig")));
// user-agent
list.add(vm.addLocalObject(new StringObject(vm, "Mozilla/5.0")));
// X-App-Client
list.add(vm.addLocalObject(new StringObject(vm, "LON=null;LAT=null;")));
// POST body
String body = "{\"code\":\"hello everhu\"}";
System.out.println("Body length:" + body.getBytes(StandardCharsets.UTF_8).length);
list.add(vm.addLocalObject(new StringObject(vm, body)));
list.add(body.getBytes(StandardCharsets.UTF_8).length);
// ts
list.add(1642084337L);
Number ret = module.callFunction(emulator, 0x36a9, list.toArray());
System.out.println("encrypt ret: " + vm.getObject(ret.intValue()).getValue().toString());
}
public static void main(String[] args) {
TuJia test = new TuJia();
test.call_encrypt();
}
public void call_bodyEncrypt() {
List<Object> list = new ArrayList<>(10);
list.add(vm.getJNIEnv());
list.add(0);
// ver
list.add(vm.addLocalObject(new StringObject(vm, "3")));
// ts
list.add(1642126567L);
// salt
String salt = "everever";
list.add(vm.addLocalObject(new StringObject(vm, salt)));
list.add(salt.getBytes(StandardCharsets.UTF_8).length);
// body
String body = "{\"code\":\"hello everhu\"}";
list.add(vm.addLocalObject(new StringObject(vm, body)));
list.add(body.getBytes(StandardCharsets.UTF_8).length);
Number ret = module.callFunction(emulator, 0x380d, list.toArray());
System.out.println("bodyEncrypt ret: " + vm.getObject(ret.intValue()).getValue().toString());
}
完整实现
package com.tujia;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TuJia extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
public static String pkgName = "com.tujia.hotel";
public static String apkPath = "unidbg-android/src/test/java/com/tujia/tujia8450.apk";
public static String soPath = "";
public TuJia() {
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName(pkgName).build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM(new File(apkPath));
vm.setJni(this);
vm.setVerbose(true);
DalvikModule dm = vm.loadLibrary("tujia_encrypt", true);
module = dm.getModule();
dm.callJNI_OnLoad(emulator);
emulator.attach().addBreakPoint(module.base + 0x302c+1);
}
@Override
public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
switch (signature) {
case "com/tujia/hotel/TuJiaApplication->getInstance()Lcom/tujia/hotel/TuJiaApplication;": {
return vm.resolveClass("com/tujia/hotel/TuJiaApplication").newObject(null);
}
case "java/security/MessageDigest->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;": {
try {
MessageDigest digest = MessageDigest.getInstance(varArg.getObjectArg(0).getValue().toString());
return vm.resolveClass("java/security/MessageDigest").newObject(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);
}
@Override
public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
switch (signature) {
case "com/tujia/hotel/TuJiaApplication->getPackageName()Ljava/lang/String;": {
return new StringObject(vm, pkgName);
}
case "com/tujia/hotel/TuJiaApplication->getPackageManager()Landroid/content/pm/PackageManager;": {
return vm.resolveClass("android/content/pm/PackageManager").newObject(null);
}
case "java/security/MessageDigest->digest([B)[B": {
MessageDigest digest = (MessageDigest) dvmObject.getValue();
byte[] data = digest.digest((byte[]) varArg.getObjectArg(0).getValue());
return new ByteArray(vm, data);
}
}
return super.callObjectMethod(vm, dvmObject, signature, varArg);
}
public void call_encrypt() {
List<Object> list = new ArrayList<>(10);
list.add(vm.getJNIEnv());
list.add(0);
// url params
list.add(vm.addLocalObject(new StringObject(vm, "key=nodeApiConfig")));
// user-agent
list.add(vm.addLocalObject(new StringObject(vm, "Mozilla/5.0")));
// X-App-Client
list.add(vm.addLocalObject(new StringObject(vm, "LON=null;LAT=null;")));
// POST body
String body = "{\"code\":\"hello everhu\"}";
System.out.println("Body length:" + body.getBytes(StandardCharsets.UTF_8).length);
list.add(vm.addLocalObject(new StringObject(vm, body)));
list.add(body.getBytes(StandardCharsets.UTF_8).length);
// ts
list.add(1642084337L);
Number ret = module.callFunction(emulator, 0x36a9, list.toArray());
System.out.println("encrypt ret: " + vm.getObject(ret.intValue()).getValue().toString());
}
public void call_bodyEncrypt() {
List<Object> list = new ArrayList<>(10);
list.add(vm.getJNIEnv());
list.add(0);
// ver
list.add(vm.addLocalObject(new StringObject(vm, "3")));
// ts
list.add(1642126567L);
// salt G-TJS
String salt = "everever";
list.add(vm.addLocalObject(new StringObject(vm, salt)));
list.add(salt.getBytes(StandardCharsets.UTF_8).length);
// body
String body = "{\"code\":\"hello everhu\"}";
list.add(vm.addLocalObject(new StringObject(vm, body)));
list.add(body.getBytes(StandardCharsets.UTF_8).length);
Number ret = module.callFunction(emulator, 0x380d, list.toArray());
System.out.println("bodyEncrypt ret: " + vm.getObject(ret.intValue()).getValue().toString());
}
public static void main(String[] args) {
TuJia test = new TuJia();
test.call_encrypt();
// test.call_bodyEncrypt();
}
}