前置知识

SHA-1算法

SHA1的java实现

MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update("xiaojianbang".getBytes());
sha1.digest();

特点

摘要长度为160bit

加密后的字节数组可以编码成Hex、Base64

没有任何输入,也能计算hash值

初始化常量

0x67452301
0xEFCDAB89
0x98BADCFE
0X10325476
0XC3D2E1F0

AES算法

根据长度不同,可以分成 AES-128、AES-192、AES-256

AES 密钥长度(比特) 分组长度(比特) 向量长度(比特) 加密轮数
AES-128 128 128 128 10
AES-192 192 128 128 12
AES-256 256 128 128 14

AES的java实现

SecretKeySpec key = new SecretKeySpec("1234567890abcdef".getBytes(), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec("1234567890abcdef".getBytes());
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
ase.init(Ciphter.ENCRYPT_MODE, key, iv);
ase.doFinal("hyq1234hyq1234".getBytes());

逆向目的

得到sign值的生成方法

分析步骤

0x01查壳

使用PKID查壳,发现没有加壳

0x02抓包

tzrd的值为:

"tnzGmE\/WClaYonm3ftYls5zr1TrTrHZGEPhQS1IMDCHyDns9cYbFR3RvnbI00QaEaxAtzefO\/WZHpIwkW8t4+UFCTNXLyszLHD+wUtVB4LvOtXcti2TNWChGeSh8xLATYB2dEs6QGIkgwkKaqhWRzHY3\/uum9RkLL9sYSWhZskEagGZ9N3AzksELmmTUX\/wZuuWxBtFJX21Snj6DiViyIoHlajuOrypVz8xgGtWXXXOxCVIgY9wXLIoTtfuSmSXnww4QBNvrfSHOS47DTVLC59ElJiH0ucWEibHBO5rGxnGLnaSjMeZPpL0myv+KIAqMOr1xGqY6qvwlbXKryvIpXL8Fl2xm6DWd1epO4JMxWojBdz4G\/zJOJjq9DR+Zw71aTbCx91NlSXxjyG2M2g5ZbgO+ZO5wVE9ohoIJrX9\/IddnRQpgq6Ayv1bGZv3hpt\/0vyls\/gnbeLrl5rztPSqWLI6h0asI7cszUTwQ0tsj71zMPg9y8KLmnUGCjjVlqURxAL4POPh0Id1OpKG\/mDvi6OhhMzQxD6geGVfrHb0meKxmF00NpJzME9A6eSxsw8wsFBUxUL7T68CPjg1StduEYViXXCwMzbQJQMgW3sOX5Odl\/vzLjANbdnGfbMNYkCmhCd+BlPKlN7Rvo942hHoRgY\/o97Y8hK6ro66wj62r+5V+Dmld0WfABxhu3XFjQ8C5+mImObTKmyziZlOgxuaSJF5nPfBSrNPzDxEuvq2\/u7bY54qbktbFs2uGbRXX1nqLABMQwmI3kRF8Fi8Fzs+9nW12OOLISp41bb0l1gUpsTJgneppUm9ls4mcwlbKo0HU+N3SsnHhN8XBMxOph59us\/cdJ1RYNOPpsY32Rq9RzA1uCXbOK9SxHM8SvtBSNlnt0VSBEfI2UtNtHJuSQu8oQ4lIHUAMojlvY6Q8YUgBbL2N4FTKFmaTGjKttnv6oZmcpvwAU\/tlDHrqddaOEzJfAeIiPL0\/VN4cpCrEDJZI+V3AjkH25XmTJIPUqZAPjW3QFFol4qv0siM0wI1xP+FGSfTYLqE\/VxRrSXgsoADEZ\/Jbu4unkeZ72oW4lHMlqY0yKkRJW3mqQvbrfU3uUK75Tg=="

看出明显使用了base64加密,于是我们便可尝试对他进行解密

解密后发现是乱码,说明这个字段是经过加密的,那么我们接下来可以使用下java层算法自吐脚本来看看这个app用了哪些算法


Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

function logOutPut(msg) {
Java.use("android.util.Log").d("xiaojianbang", "frida inject: " + msg);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
//logOutPut(tag + " Base64: " + ByteString.of(data).base64());
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
//logOutPut(tag + " Hex: " + ByteString.of(data).hex());
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
//logOutPut(tag + " Utf8: " + ByteString.of(data).utf8());
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}
// toBase64([48,49,50,51,52]);
// toHex([48,49,50,51,52]);
// toUtf8([48,49,50,51,52]);
//console.log(Java.enumerateLoadedClassesSync().join("\n"));

var messageDigest = Java.use("java.security.MessageDigest");
messageDigest.update.overload('byte').implementation = function (data) {
console.log("MessageDigest.update('byte') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('[B').implementation = function (data) {
console.log("MessageDigest.update('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.update('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
messageDigest.digest.overload().implementation = function () {
console.log("MessageDigest.digest() is called!");
showStacks();
var result = this.digest();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B').implementation = function (data) {
console.log("MessageDigest.digest('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.digest('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data, start, length);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", start, length);
return result;
}

var mac = Java.use("javax.crypto.Mac");
mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
return this.init(key, AlgorithmParameterSpec);
}
mac.init.overload('java.security.Key').implementation = function (key) {
console.log("Mac.init('java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = key.getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
console.log("=======================================================");
return this.init(key);
}
mac.update.overload('byte').implementation = function (data) {
console.log("Mac.update('byte') is called!");
return this.update(data);
}
mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Mac.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
mac.update.overload('[B').implementation = function (data) {
console.log("Mac.update('[B') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Mac.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
mac.doFinal.overload().implementation = function () {
console.log("Mac.doFinal() is called!");
var result = this.doFinal();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}

var cipher = Java.use("javax.crypto.Cipher");
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters') is called!");
return this.init.apply(this, arguments);
}

cipher.init.overload('int', 'java.security.Key').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var className = JSON.stringify(arguments[1]);
if(className.indexOf("OpenSSLRSAPrivateKey") === -1){
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
}
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
var tags = algorithm + " init iv";
var iv = Java.cast(arguments[2], Java.use("javax.crypto.spec.IvParameterSpec"));
var ivBytes = iv.getIV();
toUtf8(tags, ivBytes);
toHex(tags, ivBytes);
toBase64(tags, ivBytes);
console.log("=======================================================");
return this.init.apply(this, arguments);
}

cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function () {
console.log("Cipher.doFinal('java.nio.ByteBuffer', 'java.nio.ByteBuffer') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B', 'int') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload().implementation = function () {
console.log("Cipher.doFinal() is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}

cipher.doFinal.overload('[B').implementation = function () {
console.log("Cipher.doFinal('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
cipher.doFinal.overload('[B', 'int', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", arguments[1], arguments[2]);
return result;
}

var signature = Java.use("java.security.Signature");
signature.update.overload('byte').implementation = function (data) {
console.log("Signature.update('byte') is called!");
return this.update(data);
}
signature.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Signature.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
signature.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Signature.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
signature.sign.overload('[B', 'int', 'int').implementation = function () {
console.log("Signature.sign('[B', 'int', 'int') is called!");
return this.sign.apply(this, arguments);
}
signature.sign.overload().implementation = function () {
console.log("Signature.sign() is called!");
var result = this.sign();
var algorithm = this.getAlgorithm();
var tag = algorithm + " sign result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
});

通过这个算法我们可以看出,这个app使用了AES加密,并且关键代码应该是在MhRequestUtil这个类中,接下来我们便对这个类进行分析

0x03MhRequestUtil

使用jadx对apk进行反编译

发现了sign这个字段,并且它的取值还与nonce、app_ver、tzrd等字段有关,所以在不同的时刻进行抓包的sign的值是不同的;为了方便我可以对这个封装个函数来对这个方法进行主动调用

首先先编写hook脚本得到传入的参数值和返回的结果值,同时为了使抓到的包的各个字段和hook到的各个字段的结果一致,我们需要同时进行抓包和hook

Java.perform(function (){
var TreUtil = Java.use("com.maihan.tredian.util.TreUtil");
TreUtil.sign.implementation = function (args) {
console.log("TreUtil.signStr: ",args);
var retval = this.sign(args);
console.log(retval);
return retval;
}
});

脚本运行结果:

TreUtil.signStr:  app_ver=100&nonce=8x8xlm1743356079741&timestamp=1743356079&tzrd=BwzXzSGFyiPstMIVuzTZb7LzTZzbXRJOFzpbQiIaT7t/KDL9RCbvH/vr0qdSE1IMBjy6D/SQoXbTBgojGsCYv2+yA2ocToOyRo6AzjqzrJyb8VrkmCMBJgRIOqclRLXoi89XGEHB6Ex6hBHNKGYmYjUnGJIwg+xJZtEpjHyTruX1SgO/D0fWycPYMw1EGrck16pUYEr+VIPb8lEVr0YlQo6uBdEB9nibWV9HK9iOaQ2t4O/0/YdyK4Qe6F/GennBx6MwWXmTHQ9t2x56+l5y7qY46KvMwHKWf2zTOjS3fqAfMWGGs5Czy24fplFUwbT13Rg/m7ruyIQfJ7QqqoZmXvNqtRxkN6al8yHPkxtqjkRbUoK3d8p7ZSW2YU2aQ+iqRYtfXibuZrHYpilRJq0tWtLcFkM/c6mQYDUe5ntwKRs=
7220e2b77013915951905df18a1235d9838cfd66

抓包结果:

发现脚本运行的结果和抓包结果的sign值是一样的,说明sign值的确是由这个函数产生的

接下来为了方便我们的分析,我们封装一个函数,来对这个方法进行主动调用

Java.perform(function (){
var TreUtil = Java.use("com.maihan.tredian.util.TreUtil");
TreUtil.sign.implementation = function (args) {
// console.log("TreUtil.signStr: ",args);
var retval = this.sign(args);
console.log(retval);
return retval;
}
});

function call_java(){
Java.perform(function (){
var TreUtil = Java.use("com.maihan.tredian.util.TreUtil");
var retval = TreUtil.sign("app_ver=100&nonce=8x8xlm1743356079741&timestamp=1743356079&tzrd=BwzXzSGFyiPstMIVuzTZb7LzTZzbXRJOFzpbQiIaT7t/KDL9RCbvH/vr0qdSE1IMBjy6D/SQoXbTBgojGsCYv2+yA2ocToOyRo6AzjqzrJyb8VrkmCMBJgRIOqclRLXoi89XGEHB6Ex6hBHNKGYmYjUnGJIwg+xJZtEpjHyTruX1SgO/D0fWycPYMw1EGrck16pUYEr+VIPb8lEVr0YlQo6uBdEB9nibWV9HK9iOaQ2t4O/0/YdyK4Qe6F/GennBx6MwWXmTHQ9t2x56+l5y7qY46KvMwHKWf2zTOjS3fqAfMWGGs5Czy24fplFUwbT13Rg/m7ruyIQfJ7QqqoZmXvNqtRxkN6al8yHPkxtqjkRbUoK3d8p7ZSW2YU2aQ+iqRYtfXibuZrHYpilRJq0tWtLcFkM/c6mQYDUe5ntwKRs=")
});
}

跑一下脚本,发现结果和sign值一致

[Pixel XL::淘最热点]-> call_java()
7220e2b77013915951905df18a1235d9838cfd66

接下来我们便进一步分析sign这个方法

0x04分析sign方法

发现这是个native方法,并且加载的是tre这个so库,于是我们使用ida来分析它

ida将参数a1的类型识别错了,因为是JNI函数,我们可手动将它改成JNIEnv* a1,这样便可正确识别出许多函数

从这我们可以看到几个关键函数,并且可以看出v26是我们的结果,编写hook脚本对v26的值进行验证:

function print_arg(addr){
var module = Process.findRangeByAddress(addr);
if(module != null) return hexdump(addr) + "\n";
return ptr(addr) + "\n";
}
function hook_native_addr(funcPtr, paramsNum){
var module = Process.findModuleByAddress(funcPtr);
Interceptor.attach(funcPtr, {
onEnter: function(args){
this.logs = [];
this.params = [];
this.logs.push("call " + module.name + "!" + ptr(funcPtr).sub(module.base) + "\n");
for(let i = 0; i < paramsNum; i++){
this.params.push(args[i]);
this.logs.push("this.args" + i + " onEnter: " + print_arg(args[i]));
}
}, onLeave: function(retval){
for(let i = 0; i < paramsNum; i++){
this.logs.push("this.args" + i + " onLeave: " + print_arg(this.params[i]));
}
this.logs.push("retval onLeave: " + print_arg(retval) + "\n");
console.log(this.logs);
}
});
}
var soAddr = Module.findBaseAddress("libtre.so");
var SHA1Result = soAddr.add(0x14C8+1);
hook_native_addr(SHA1Result,2);

脚本运行结果:

this.args1 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
c3210c14 72 20 e2 b7 70 13 91 59 51 90 5d f1 8a 12 35 d9 r ..p..YQ.]...5.
c3210c24 83 8c fd 66 b7 e2 20 72 59 91 13 70 f1 5d 90 51 ...f.. rY..p.].Q
c3210c34 d9 35 12 8a 66 fd 8c 83 00 00 00 00 00 00 00 00 .5..f...........
c3210c44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c3210c54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c3210c64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c3210c74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c3210c84 00 00 52 b2 01 00 00 00 00 00 00 00 62 32 71 4b ..R.........b2qK
c3210c94 67 74 61 57 34 2c 39 7a 39 44 60 46 6d 73 74 3f gtaW4,9z9D`Fmst?
c3210ca4 4b 35 4a 5a 62 4c 59 4f 59 5d 4e 50 36 73 73 47 K5JZbLYOY]NP6ssG
c3210cb4 66 32 55 7e 3b 7a 6b 39 6f 43 4e 67 6f 79 74 56 f2U~;zk9oCNgoytV
c3210cc4 21 7d 77 57 37 69 61 2b 60 77 39 67 00 00 5c 00 !}wW7ia+`w9g..\.
c3210cd4 00 00 43 00 d6 a0 da fe 00 00 00 00 00 28 87 e0 ..C..........(..
c3210ce4 10 0e 21 c3 94 0d 21 c3 54 5a b6 c8 02 00 00 00 ..!...!.TZ......
c3210cf4 00 28 87 e0 1e 98 bd c9 1b 78 e7 c8 54 5a b6 c8 .(.......x..TZ..
c3210d04 14 2a 21 c3 02 00 00 00 a8 2d 9d c8 f8 b7 64 13 .*!......-....d.

发现的确和我们的sign一致,所以sign最后是由这个值产生的

接下来对SHA1Input进行hook看看它的输入值是是什么,由于输入的值过长,hexdump()无法显示完全,我们使用readCString()方法

var soAddr = Module.findBaseAddress("libtre.so");
var SHA1Input = soAddr.add(0x15BE+1);
//hook_native_addr(SHA1Input,3);
Interceptor.attach(SHA1Input,{
onEnter: function(args){
console.log(args[1].readCString());
}, onLeave: function(retval){

}
});

结果:

[Pixel XL::淘最热点]-> call_java()
YXBwX3Zlcj0xMDAmbm9uY2U9OHg4eGxtMTc0MzM1NjA3OTc0MSZ0aW1lc3RhbXA9MTc0MzM1NjA3OSZ0enJkPUJ3elh6U0dGeWlQc3RNSVZ1elRaYjdMelRaemJYUkpPRnpwYlFpSWFUN3QvS0RMOVJDYnZIL3ZyMHFkU0UxSU1Cank2RC9TUW9YYlRCZ29qR3NDWXYyK3lBMm9jVG9PeVJvNkF6anF6ckp5YjhWcmttQ01CSmdSSU9xY2xSTFhvaTg5WEdFSEI2RXg2aEJITktHWW1ZalVuR0pJd2creEpadEVwakh5VHJ1WDFTZ08vRDBmV3ljUFlNdzFFR3JjazE2cFVZRXIrVklQYjhsRVZyMFlsUW82dUJkRUI5bmliV1Y5SEs5aU9hUTJ0NE8vMC9ZZHlLNFFlNkYvR2VubkJ4Nk13V1htVEhROXQyeDU2K2w1eTdxWTQ2S3ZNd0hLV2YyelRPalMzZnFBZk1XR0dzNUN6eTI0ZnBsRlV3YlQxM1JnL203cnV5SVFmSjdRcXFvWm1Ydk5xdFJ4a042YWw4eUhQa3h0cWprUmJVb0szZDhwN1pTVzJZVTJhUStpcVJZdGZYaWJ1WnJIWXBpbFJKcTB0V3RMY0ZrTS9jNm1RWURVZTVudHdLUnM9YjJxS2d0YVc0LDl6OURgRm1zdD9LNUpaYkxZT1ldTlA2c3NHZjJVfjt6azlvQ05nb3l0ViF9d1c3aWErYHc5Zw==

再对base64进行hook

var soAddr = Module.findBaseAddress("libtre.so");
var base64 = soAddr.add(0x13B4+1);

Interceptor.attach(base64,{
onEnter: function(args){
console.log("args[0].readCString(): ",args[0].readCString());
this.args1= args[1];
}, onLeave: function(retval){
console.log("args1.readCString(): ",this.args1.readCString());
}
});

结果:

[Pixel XL::淘最热点]-> call_java()
args[0].readCString(): app_ver=100&nonce=8x8xlm1743356079741&timestamp=1743356079&tzrd=BwzXzSGFyiPstMIVuzTZb7LzTZzbXRJOFzpbQiIaT7t/KDL9RCbvH/vr0qdSE1IMBjy6D/SQoXbTBgojGsCYv2+yA2ocToOyRo6AzjqzrJyb8VrkmCMBJgRIOqclRLXoi89XGEHB6Ex6hBHNKGYmYjUnGJIwg+xJZtEpjHyTruX1SgO/D0fWycPYMw1EGrck16pUYEr+VIPb8lEVr0YlQo6uBdEB9nibWV9HK9iOaQ2t4O/0/YdyK4Qe6F/GennBx6MwWXmTHQ9t2x56+l5y7qY46KvMwHKWf2zTOjS3fqAfMWGGs5Czy24fplFUwbT13Rg/m7ruyIQfJ7QqqoZmXvNqtRxkN6al8yHPkxtqjkRbUoK3d8p7ZSW2YU2aQ+iqRYtfXibuZrHYpilRJq0tWtLcFkM/c6mQYDUe5ntwKRs=b2qKgtaW4,9z9D`Fmst?K5JZbLYOY]NP6ssGf2U~;zk9oCNgoytV!}wW7ia+`w9g
args1.readCString(): YXBwX3Zlcj0xMDAmbm9uY2U9OHg4eGxtMTc0MzM1NjA3OTc0MSZ0aW1lc3RhbXA9MTc0MzM1NjA3OSZ0enJkPUJ3elh6U0dGeWlQc3RNSVZ1elRaYjdMelRaemJYUkpPRnpwYlFpSWFUN3QvS0RMOVJDYnZIL3ZyMHFkU0UxSU1Cank2RC9TUW9YYlRCZ29qR3NDWXYyK3lBMm9jVG9PeVJvNkF6anF6ckp5YjhWcmttQ01CSmdSSU9xY2xSTFhvaTg5WEdFSEI2RXg2aEJITktHWW1ZalVuR0pJd2creEpadEVwakh5VHJ1WDFTZ08vRDBmV3ljUFlNdzFFR3JjazE2cFVZRXIrVklQYjhsRVZyMFlsUW82dUJkRUI5bmliV1Y5SEs5aU9hUTJ0NE8vMC9ZZHlLNFFlNkYvR2VubkJ4Nk13V1htVEhROXQyeDU2K2w1eTdxWTQ2S3ZNd0hLV2YyelRPalMzZnFBZk1XR0dzNUN6eTI0ZnBsRlV3YlQxM1JnL203cnV5SVFmSjdRcXFvWm1Ydk5xdFJ4a042YWw4eUhQa3h0cWprUmJVb0szZDhwN1pTVzJZVTJhUStpcVJZdGZYaWJ1WnJIWXBpbFJKcTB0V3RMY0ZrTS9jNm1RWURVZTVudHdLUnM9YjJxS2d0YVc0LDl6OURgRm1zdD9LNUpaYkxZT1ldTlA2c3NHZjJVfjt6azlvQ05nb3l0ViF9d1c3aWErYHc5Zw==

结论

sign的值是将java层传入的参数进行一个加盐处理,再进行一个base64加密,最后再进行SHA1加密得到的