1,抓包
?2,定位关键位置,
?这次太简单了
frida hook 一下
Java.perform(function(){
var header=Java.use("com.xxxx.xxxx.xxxx");
console.log("start hook!!")
header.a.overload('java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'int', 'long').implementation=function(str1,str2,str3,str4,int1,long){
console.log("\nstr1",str1,"\nstr2",str2,"\nstr3",str3,"\nstr4",str4,"\nint1",int1,"\nlong",long)
var ret=this.a(str1,str2,str3,str4,int1,long)
//printStack()
console.log("X-TGH :",ret)
return ret;
}
header.encrypt.implementation=function(str1,str2,str3,str4,int1,long){
console.log("\nstr1",str1,"\nstr2",str2,"\nstr3",str3,"\nstr4",str4,"\nint1",int1,"\nlong",long)
var retval=this.encrypt(str1,str2,str3,str4,int1,long)
console.log("X-TGH encrypt :",retval)
return retval;
}
})
?打印结果
str1 null
str2 Mozilla/5.0 (Linux; Android 8.1.0; Pixel Build/OPM4.171019.021.P1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36 tujia(hotel/263/263 mNet/wifi loc/zh_CN) 设备信息
str3 LON=null;LAT=null;AX=null;OY=null;CID=-1;LAC=-1;UID=c93a7674-d056-3b90-a9f9-ff195e6a27c8;OSVersion=8.1.0;AppVersion=263_263;DevType=2;DevModel=Pixel;Manufacturer=Google;;TJM=0;VersionName=8.40.1;
str4 {"api_level":"263","platform":"1","res":null,"seed":651798267,"session_id":"c93a7674-d056-3b90-a9f9-ff195e6a27c8_1657895363857","timestamp":1657895780,"uid":"c93a7674-d056-3b90-a9f9-ff195e6a27c8"}
int1 196 str4.lenght
long 1657895838 time
X-TGH encrypt : 09b8b7593131ede78b53e91ae9d807684e068cfc
X-TGH : 09b8b7593131ede78b53e91ae9d807684e068cfc
?主动调用一下
function invoke(){
Java.perform(function(){
var Gundam = Java.use("com.xxxxxx");
var StrCls = Java.use('java.lang.String');
var arg0_str ="";
var arg0 = StrCls.$new(arg0_str);
var arg1_str = "Mozilla/5.0 (Linux; Android 8.1.0; Pixel Build/OPM4.171019.021.P1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36 tujia(hotel/263/263 mNet/wifi loc/zh_CN)"
var arg1 = StrCls.$new(arg1_str);
var arg2_str = "LON=null;LAT=null;AX=null;OY=null;CID=-1;LAC=-1;UID=c93a7674-d056-3b90-a9f9-ff195e6a27c8;OSVersion=8.1.0;AppVersion=263_263;DevType=2;DevModel=Pixel;Manufacturer=Google;;TJM=0;VersionName=8.40.1;"
var arg2 = StrCls.$new(arg2_str);
var arg3_str = "{\"code\":null,\"parameter\":{\"abTests\":{\"T_login_831\":{\"s\":true,\"v\":\"A\"},\"searchhuojia\":{\"s\":true,\"v\":\"D\"},\"listfilter_227\":{\"s\":true,\"v\":\"D\"},\"T_renshu_292\":{\"s\":true,\"v\":\"D\"},\"Tlisttest_45664\":{\"s\":true,\"v\":\"C\"},\"Tlist_168\":{\"s\":true,\"v\":\"C\"},\"T_LIST27620\":{\"s\":true,\"v\":\"C\"}}},\"client\":{\"abTest\":{},\"abTests\":{}"
var arg3 = StrCls.$new(arg3_str);
var arg4 = arg3.getBytes().length;
var arg5 = 1657895838;
var ret = Gundam.encrypt(arg0,arg1,arg2,arg3,arg4,arg5);
console.log("invoke encrypt ret:" + ret);
})
}
3,so层分析。用下Unidbg
第一步先把框架搭起来,
package com.xxxx;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
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.api.PackageInfo;
import com.github.unidbg.linux.android.dvm.api.Signature;
import com.github.unidbg.linux.android.dvm.array.ArrayObject;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import net.dongliu.apk.parser.bean.CertificateMeta;
import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class xxxx extends AbstractJni {
private static final String APP_PACKAGE_NAME="xxxx";
private final AndroidEmulator mEmulator;
private final Memory mMemory;
private final VM vm;
private final Module dvmModule;
xxxx(){
//创建模拟器实列
mEmulator = AndroidEmulatorBuilder.for32Bit().setProcessName(APP_PACKAGE_NAME).build();
//emulator = AndroidEmulatorBuilder.for32Bit().setProcessName(APP_PACKAGE_NAME).build();
//获取模拟器内存接口
mMemory = mEmulator.getMemory();
//设置系统类库解析
mMemory.setLibraryResolver(new AndroidResolver(23));
//创建虚拟机,传入apk
vm = mEmulator.createDalvikVM(new File("F:\\xxx.apk"));
//加载so
DalvikModule dvm = vm.loadLibrary(new File("F:\\libtujia_encrypt.so"), true);
//获取本SO模块的句柄
dvmModule = dvm.getModule();
//设置jni
vm.setJni(this);
//打印日志
vm.setVerbose(true);
// 调用JNI OnLoad
dvm.callJNI_OnLoad(mEmulator);
}
public static void main(String[] args) {
xxxx xxxx = new xxxx();
}
@Override
public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
switch (signature){
case "com/xxxx/xxxx/xxxxx->getInstance()Lcom/tujia/hotel/TuJiaApplication;":
return vm.resolveClass("com/xxxx/xxxx/xxxxx").newObject(signature);
case "java/security/MessageDigest->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;":{
StringObject type = varArg.getObjectArg(0);
System.out.println(type);
String name = "";
if ("\"SHA1\"".equals(type.toString())) {
name = "SHA1";
} else {
name = type.toString();
System.out.println("else name: " + name);
}
try {
return vm.resolveClass("java/security/MessageDigest").newObject(MessageDigest.getInstance(name));
} 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/xxxx/xxxx/xxxxxx->getPackageName()Ljava/lang/String;":{
return new StringObject(vm,"com.tujia.hotel");
}
case "com/xxxx/xxxx/xxxxxx->getPackageManager()Landroid/content/pm/PackageManager;":{
return vm.resolveClass("android/content/pm/PackageManager").newObject(signature);
}
case "java/security/MessageDigest->digest([B)[B":{
MessageDigest messageDigest = (MessageDigest) dvmObject.getValue();
byte[] input = (byte[]) varArg.getObjectArg(0).getValue();
byte[] result = messageDigest.digest(input);
return new ByteArray(vm,result);
}
}
return super.callObjectMethod(vm, dvmObject, signature, varArg);
}
@Override
public DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
switch (signature){
case "com/xxxx/xxxx/x->xxxxx:[Landroid/content/pm/Signature;":
return vm.resolveClass("Landroid/content/pm/Signature").newObject(signature);
}
return super.getObjectField(vm, dvmObject, signature);
}
}
补完环境跑一下
[main]D/Gundam: sign input 3 = 3687596384,~= 607370911
[main]D/Gundam: sign arr2 3 = 607370911,tempX= 607370911
[main]D/Gundam: sign input 4 = 699393680,~= 3595573615
[main]D/Gundam: sign arr2 4 = 3595573615,tempX= -699393681
[main]D/Gundam: result = 1
[main]D/Gundam: check result is ok
JNIEnv->RegisterNatives(com/xxxx/xxxx/xxxxx, RW@0x4001f000[libtujia_encrypt.so]0x1f000, 2) was called from RX@0x400040f3[libtujia_encrypt.so]0x40f3
RegisterNative(com/xxxx/xxxx/xxxxx, encrypt(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IJ)Ljava/lang/String;, RX@0x400036a9[libtujia_encrypt.so]0x36a9)
RegisterNative(com/xxxx/xxxx/xxxxx, bodyEncrypt(Ljava/lang/String;JLjava/lang/String;ILjava/lang/String;I)Ljava/lang/String;, RX@0x4000380d[libtujia_encrypt.so]0x380d)
成功跑出来了,现在主动调用一下encrypt();
public void invoke_encrypt() {
//构建数组
ArrayList<Object> args = new ArrayList<>();
DvmClass dvmClass = vm.resolveClass("com/xxxxxx");
DvmObject<?> dvmObject = dvmClass.newObject(null);
Object arg0 = vm.addLocalObject(new StringObject(vm, ""));
String arg1 ="Mozilla/5.0 (Linux; Android 8.1.0; Pixel Build/OPM4.171019.021.P1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36 tujia(hotel/263/263 mNet/wifi loc/zh_CN)";
Object args1_str=vm.addLocalObject(new StringObject(vm,arg1));
String arg2 = "LON=null;LAT=null;AX=null;OY=null;CID=-1;LAC=-1;UID=c93a7674-d056-3b90-a9f9-ff195e6a27c8;OSVersion=8.1.0;AppVersion=263_263;DevType=2;DevModel=Pixel;Manufacturer=Google;;TJM=0;VersionName=8.40.1;";
Object arg2_str=vm.addLocalObject(new StringObject(vm,arg2));
String arg3 = "{\"code\":null,\"parameter\":{\"abTests\":{\"T_login_831\":{\"s\":true,\"v\":\"A\"},\"searchhuojia\":{\"s\":true,\"v\":\"D\"},\"listfilter_227\":{\"s\":true,\"v\":\"D\"},\"T_renshu_292\":{\"s\":true,\"v\":\"D\"},\"Tlisttest_45664\":{\"s\":true,\"v\":\"C\"},\"Tlist_168\":{\"s\":true,\"v\":\"C\"},\"T_LIST27620\":{\"s\":true,\"v\":\"C\"}}},\"client\":{\"abTest\":{},\"abTests\":{},\"adTest\":{\"m1\":\"Color OS V5.2.1\",\"m2\":\"\"}";
Object arg3_str=vm.addLocalObject(new StringObject(vm,arg3));
int arg4_len = arg3.getBytes(StandardCharsets.UTF_8).length;
long arg5_long=1657895838L;
args.add(vm.getJNIEnv()); //第一个参数是env
args.add(0); //第二个参数一般是jObject或者jClass 可以填写0,一般用不到
args.add(arg0);
args.add(args1_str);
args.add(arg2_str);
args.add(arg3_str);
args.add(arg4_len);
args.add(arg5_long);
Number number = dvmModule.callFunction(mEmulator, 0x36a9, args.toArray());
//System.out.println("number :"+number);
String sign = vm.getObject(number.intValue()).getValue().toString();
System.out.println("invoke_encrypt sign :"+sign);
}
unidbg已经跑通了,用ida去看下so文件。
解析完成以后,G->跳转到0x36a9,就是encrypt()的函数地址
?
?能看到这么一个方法,进去瞅瞅
?里面有点乱 ,一点一点看
有两种,第一种,跟着传参看。第二种,从返回值看。
?看这种看起来类似算法常量,复制搜索一下。
接着往下看,
j_tjtxtutf8()? ?点进去,是base64,有两处调用的
.?
再往下进入tjcreate()
?看这个常量是SHA1的K值,剩下的呢。
SHA1常量:0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,0xC3D2E1F0
SHA K值:0x5A827999 ,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6
?这是在初始化 SHA1
?猜测一下,j_tjreset(),是运算。j_tjget()是 SHA1的结果
function hook_native(){
Java.perform(function(){
var encrypt_addr=Module.findBaseAddress("libxxxx.so")
console.log("encrypt_addr :",encrypt_addr)
var sha1_update=encrypt_addr.add(0x2C94+1)
Interceptor.attach(sha1_update,{
onEnter:function(args){
console.log("sha1_update args[0] onEnter:\n",hexdump(args[0],{length:128}))
this.r0=args[0]
console.log("\nsha1_update args[1] onEnter:\n",hexdump( args[1], parseInt(args[2])))
},onLeave:function(retval){
console.log("\nsha1_update retval onLeave:\n",hexdump(this.r0,{length:128}))
}
})
})
}
主动调用invoke()
?也可以用unidbg HOOK。
先试一下SHA1,
?和我们的sign对不上。
那就是魔改喽,返回到算法里看下。
我们知道 SHA1 只会和常量和K值表进行运算。
所以你算什么?
?测试一下
?好啦
大致流程已经知道了。等下 看下明文是个什么。
?对照咱们的传参比较一下;
1,#arg1_str#arg5#字符串#arg2_str#(arg3_str(排序))
2,字符串反转
3,Base64
4,xor 0x21
5,SHA1
|