0x01 前言
有时候在对APP抓包的时候,经常会遇到参数加密,app也不像web端一样,可以直接打断点进行调试,找到加密方法, 在app没有加壳的情况下,我们可以反编译找加密点,或者是动态调试,这里使用反编译的方法。
0x02 正文
在登陆处点击登录,然后抓包,具体环境配置教程以及抓包教程可以看前两篇文章,可以看到账号密码被加密了,这时候如果apk没有加壳的话,我们可以使用JADX进行反编译
因为抓包的时候,路由是/user/login,我们反编译apk后,直接搜索这个
基本可以确定就是从这里发起网络请求
跟进addRequestMap方法分析
这一看逻辑就清晰了
先添加一个时间戳,在对sign进行加密后在调用encodeDesMap进行加密
最后put到请求中
在分析encodeDesMap
有KEY和IV,不是AES就是DES加密
encrypt64
DES加密后在Base64加密
那么data就是明文了,hook这个方法取到参数
1
2
3
4
5
6
7
8
let RequestUtil = Java.use("com.xxx.xxx.http.RequestUtil");
RequestUtil["encodeDesMap"].overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function (data, desKey, desIV) {
console.log("**********获取DES明文**********");
console.log(`参数明文----> ${data}, desKey= ${desKey}, desIV= ${desIV}`);
let result = this["encodeDesMap"](data, desKey, desIV);
console.log(`参数加密结果----> ${result}`);
return result;
};
与抓包结果一样,这样明文就拿到了。
sign分析,回到刚刚那个传递sign参数的那个函数
字符串最后拼接了一个key后在进行md5加密,
hook一下md5这个函数
很明显,拼接除了sign参数其余全部在添加一个key=sdlkjsdljf0j2fsjk 的最终字符串在进行md5加密。
这样sign与参数加密都分析完了。
再使用java模拟加密过程,反写解密就OK了。
package APP;//import android.util.Base64;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import java.util.stream.Collectors;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
/* loaded from: classes.dex */
public class DuDu {
Cipher deCipher;
Cipher enCipher;
public DuDu(String key, String iv) throws Exception {
if (key == null) {
throw new NullPointerException("Parameter is null!");
}
InitCipher(key.getBytes(), iv.getBytes());
}
private void InitCipher(byte[] secKey, byte[] secIv) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(secKey);
DESKeySpec dsk = new DESKeySpec(md.digest());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(dsk);
IvParameterSpec iv = new IvParameterSpec(secIv);
this.enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
this.deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
this.enCipher.init(1, key, iv);
this.deCipher.init(2, key, iv);
}
public String encrypt64(byte[] data) throws Exception {
byte[] encryptedBytes = this.enCipher.doFinal(data);
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public byte[] decrypt64(String data) throws Exception {
return this.deCipher.doFinal(Base64.getDecoder().decode(data));
}
public String sign(String data) throws Exception {
String append = "sdlkjsdljf0j2fsjk";
// 将 JSON 字符串转换为 Map Map<String, String> paramMap = Arrays.stream(data.replace("{", "").replace("}", "").split(","))
.map(pair -> pair.split(":"))
.collect(Collectors.toMap(
kv -> kv[0].trim().replace("\"", ""),
kv -> kv[1].trim().replace("\"", "")
));
// 对 Map 中的键进行排序
List<String> keys = new ArrayList<>(paramMap.keySet());
Collections.sort(keys);
// 拼接参数字符串
String paramStr = keys.stream()
.filter(key -> !"sign".equals(key))
.map(key -> {
return key + "=" + URLEncoder.encode(paramMap.get(key), StandardCharsets.UTF_8);
})
.collect(Collectors.joining("&")) + "&key=" + URLEncoder.encode(append, StandardCharsets.UTF_8);
System.out.println("sign明文:" + paramStr);
// 对拼接后的参数字符串进行 MD5 加密
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(paramStr.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString().toUpperCase();
}
public static void main(String[] args) throws Exception {
DuDu du = new DuDu("65102933","32028092");
String enc = "";
String decryptedString = new String(du.decrypt64(enc));
System.out.println("明文:" + decryptedString);
System.out.println("sign密文:" + du.sign(decryptedString));
}
}
function duduhook() {
Java.perform(function () {
let RequestUtil = Java.use("com.xxx.xxx.http.RequestUtil");
RequestUtil["encodeDesMap"].overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function (data, desKey, desIV) {
console.log("**********获取DES明文**********");
console.log(`参数明文----> ${data}, desKey= ${desKey}, desIV= ${desIV}`);
let result = this["encodeDesMap"](data, desKey, desIV);
console.log(`参数加密结果----> ${result}`);
return result;
};
let Utils = Java.use("com.xxx.xxx.util.Utils");
Utils["md5"].implementation = function (string) {
console.log("**********获取SIGN明文**********");
console.log(`SIGN明文----> ${string}`);
let result = this["md5"](string);
console.log(`MD5加密结果----> ${result}`);
return result;
};
let RequestUtil1 = Java.use("com.xxx.xxx.http.RequestUtil");
RequestUtil1["paraMap"].overload('java.util.Map', 'java.lang.String', 'java.lang.String').implementation = function (addMap, append, sign) {
console.log(`RequestUtil.paraMap is called: addMap=${addMap}, append=${append}, sign=${sign}`);
let result = this["paraMap"](addMap, append, sign);
console.log(`RequestUtil.paraMap result=${result}`);
return result;
};
});
}
setImmediate(duduhook);
0x03 文末
工具下载
本文所涉及的工具,均打包网盘,后台回复“安卓渗透”即可获取。
实习/校招/社招
安全服务工程师、安全攻防工程师、安全研发工程师、前后端开发工程师、测试工程师等等,所有岗位均可内推 |
推荐阅读
渗透实战|记一次简单的Docker逃逸+反编译jar接管云主机