一、目标
李老板: 奋飞呀,我最近从Apk里面跟踪到一个算法,代码清晰,但是我不会java,把他翻译成python貌似挺费劲的,有没有轻松省力的方法呀?
奋飞: 有的呀,给我加工资,我来翻译。
某电商App v10.4.5, 升级之后老有小伙伴说他的sign算法变了,其实他就是做了点小动作。sign参数没有动,uuid是明文去做签名,但是抓包请求里面找不到明文uuid,而是藏在ep参数里面,做了一次加密。
今天我们就来手把手教大家扣出这个加密算法。
java老艺术家就不用往下看了,你们都会。
二、步骤
编辑加编译
大家也跟了这么多期了,如何找到ep,如何定位uuid的加密算法这个步骤,可以自行完成,需要提醒一下的就是,这个uuid加密还有缓存,同样的数据被加密一次之后就会记入一个map里面。下次优先找这个map,所以很多时候都不会触发你hook的加密函数。
但是不要怀疑,你找的就是对的。
今天的大boss就是它,从名称上看貌似是个魔改的Base64算法。
有理想的同学可以试着翻译成别的语言,当然我们今天要做的不是翻译,而是把他扣出来,直接利用。
首先创建一个 ModifiedBase64.java文件,把jadx反编译的结果拷贝进去。
把文件第一行的 包名 删掉,就是那个 package xxx;
TIP: 有包名的话,后面运行的时候需要带上包名,为了简单起见,直接把他删除了吧
然后在 ModifiedBase64 类里面增加一个Main函数
public static void main(String[] args) throws Exception{
ModifiedBase64 zObj = new ModifiedBase64();
String strIn = "DwO4EJPrDJCmY2G2EJq5EG==";
String strOut = new String(zObj.m23209eC(strIn));
System.out.println(strOut);
}
这就ok了,然后开始编译
javac ModifiedBase64.java
ModifiedBase64.java:1: 错误: 程序包com.google.common.primitives不存在
import com.google.common.primitives.SignedBytes;
^
ModifiedBase64.java:63: 错误: 找不到符号
b = SignedBytes.MAX_POWER_OF_TWO;
^
符号: 变量 SignedBytes
位置: 类 ModifiedBase64
2 个错误
报错了,有个包名找不到,常规做法是引入这个包名。
不过我们仔细观察下,发现这个包就干了一件事。
导入了 SignedBytes.MAX_POWER_OF_TWO; 常量。
光吃饭,不干活,那就别怪我们不客气了,问问谷哥。
哥说了
public static final byte MAX_POWER_OF_TWO = 1 << 6;
掐指一算,这不就是 0x40 嘛 ,毫不犹豫删掉这个包,然后把 b的赋值直接改成 0x40
重新编译
javac ModifiedBase64.java
ModifiedBase64.java:41: 错误: 无法访问的语句
while (true) {
^
1 个错误
还有错, 这不科学呀。
仔细看看这个 pf 函数 ,确实不科学
public static void m23208pf() throws Exception {
int i = 0;
int i2 = 0;
while (true) {
byte[] bArr = aaf;
if (i2 <= bArr.length - 1) {
bArr[i2] = -1;
i2++;
}
}
while (true) {
char[] cArr = aae;
if (i <= cArr.length - 1) {
aaf[cArr[i]] = (byte) i;
i++;
} else {
return;
}
}
}
第一个while成死循环了,根本不会往下跑。
应该是jadx不乖了, 结合下 jeb的翻译结果,我们给他加上个退出机制
public static void m23208pf() throws Exception {
int i = 0;
int i2 = 0;
while (true) {
byte[] bArr = aaf;
if (i2 <= bArr.length - 1) {
bArr[i2] = -1;
i2++;
}else{
break;
}
}
while (true) {
char[] cArr = aae;
if (i <= cArr.length - 1) {
aaf[cArr[i]] = (byte) i;
i++;
} else {
return;
}
}
}
完美,这下编译成功,跑一下
javac ModifiedBase64.java
java ModifiedBase64
6a891a530cd69899
可以解密出来了。
打包jar
这还没完,我们总不能每次都去改代码,最好可以传个参数进去调用。
先改改代码
public static void main(String[] args) throws Exception{
ModifiedBase64 zObj = new ModifiedBase64();
String strIn = args[0];
String strOut = new String(zObj.m23209eC(strIn));
System.out.println(strOut);
}
密文不再写死,而是传参进去。
// 编译
javac ModifiedBase64.java
// 打包jar
jar cvfe ModifiedBase64.jar ModifiedBase64 ModifiedBase64.class
打包要注意两点:
1、 e参数,来指定Main类
2、 打包文件是编译之后的 .class 而不是 .java
成功之后生成 ModifiedBase64.jar ,就可以命令行调用了
java -jar ModifiedBase64.jar DwO4EJPrDJCmY2G2EJq5EG==
6a891a530cd69899
完美收工。
三、总结
要练就火眼金睛,hook是不会骗人的,参数没变,算法没变,只是多套了一层做了加密而已。
手工编译java和打包,了解原理即可,简单的算法这么搞,复杂一点的还是上 IDEA吧。
年轻人,学点java吧。
人们曾经不只是为了某个具体的目的去研究一个个具体的问题,而是追求深层次的真理,又怎样由此而造出美好的世界,这就是创造。
TIP: 本文的目的只有一个就是学习更多的逆向技巧和思路,如果有人利用本文技术去进行非法商业获取利益带来的法律责任都是操作者自己承担,和本文以及作者没关系,本文涉及到的代码项目可以去 奋飞的朋友们 知识星球自取,欢迎加入知识星球一起学习探讨技术。有问题可以加我wx: fenfei331 讨论下。
关注微信公众号: 奋飞安全,最新技术干货实时推送