dewuApp逆向
第一步就是抓包
根据抓到的包,可以看出需要破解的参数 newSign 、password、uuid 还有 headers 中的参数 shumeiid/x-auth-token/duuid/duimei/shumengid 。也就是有这么多的参数是不知道的,需要去 app 中找的。
第二步 使用 jadx 打开 app
直接搜索 api,
点进去后直接查找用例,就会跳转到下图。
走到这再去点的时候,发现一些参数而且调用了 newParams, 参数 userName、type、sourcePage、countryCode 都是没有加密的,所以重点就是看看这个 password。hook 这个方法发现里面密码是已经加密过的,直接查找用例
点进去就找到 password 的加密位置。
从这个方法中可以看到密码是 MD5Util 的加密。为了验证我的判断,直接 Hook MD5Util.a方法
复制md5_js_code = """
Java.perform(function () {
var MainActivity = Java.use('com.shizhuang.duapp.framework.util.encrypt.MD5Util');
MainActivity.a.overload('java.lang.String').implementation = function () {
console.log("password: #################" + arguments[0]);
var str2 = "12345678du";
Java.openClassFile("/data/local/tmp/r0gson.dex").load();
const gson = Java.use("com.r0ysue.gson.Gson");
console.log("11111111111111111111111111111111111111111+++++++++++++++++++++")
console.log(gson.$new().toJson(this.a(str2)));
console("------------------------------");
};
});
"""
打印的结果
然后点击 LoginFacade.c ,发现到了最开始的发起请求,拼接参数的地方。到这里 password 的就完事了。
然后又重新搜索参数 newSign
这里看看 OkHttp https://blog.csdn.net/qq_38851536/article/details/100146115
点进去后,发现基本参数,以及请求头这些东西都可以找到。剩下的就是这些具体的实现以及加密。
继续找到 RequestUtils.b 方法,这个方法最后就是该参数的加密位置以及加密方法。从名字看就是个 AES 加密。加密的内容就是请求参数转为字符串,然后拼接后加密。
继续进入这个 b 方法, 可以看到返回的是一个执行encodeByte 方法后的返回值。而这个方法是 native, 加载的 so 文件为 JNIEncrypt
剩下的就是关于这个加密参数的 Hook.
第三步直接 HOOK 这个方法,查看具体都加密了哪些东西
可以看到 java 层加密的就是这么多的东西,剩下的就是 native 层
参考文章
爬虫工程师的unidbg入门教程
通过 unidbg 直接调用 so 文件
直接去 github上下载 https://github.com/zhkl0228/unidbg ,
参考上面大佬文章中的代码,进行简单的修改。我逆向的版本中 encodeByte 方法有更新,简单修改一下,就可以了
复制public class du extends AbstractJni {
//ARM模拟器
private final AndroidEmulator emulator;
//vm
private final VM vm;
//载入的模块
private final Module module;
private final DvmClass TTEncryptUtils;
//初始化
public du() throws IOException {
//创建毒进程,这里其实可以不用写的,我这里是随便写的,使用app本身的进程就可以绕过进程检测
emulator = new AndroidARMEmulator("com.shizhuang.duapp");
final Memory memory = emulator.getMemory();
//作者支持19和23两个sdk
memory.setLibraryResolver(new AndroidResolver(23));
// memory.setCallInitFunction();
//创建DalvikVM,利用apk本身,可以为null
//如果用apk文件加载so的话,会自动处理签名方面的jni,具体可看AbstractJni,这就是利用apk加载的好处
vm = emulator.createDalvikVM(null);
vm.setVerbose(true);
vm.setJni(this);
// vm = emulator.createDalvikVM(null);
//加载so,使用armv8-64速度会快很多
DalvikModule dm = vm.loadLibrary(new File("src/test/resources/xiaohongshu/libJNIEncrypt.so"), false);
//调用jni
dm.callJNI_OnLoad(emulator);
module = dm.getModule();
//Jni调用的类,加载so
TTEncryptUtils = vm.resolveClass("com/duapp/aesjni/AESEncrypt");
}
//关闭模拟器
private void destroy() throws IOException {
emulator.close();
System.out.println("destroy");
}
public static void main(String[] args) throws IOException {
du t = new du();
t.encodeByte("123456");
t.destroy();
}
private String encodeByte(String strs) {
//调试
// 这里还支持gdb调试,
//emulator.attach(DebuggerType.GDB_SERVER);
//附加调试器
// emulator.attach(DebuggerType.SIMPLE);
// emulator.traceCode();
//这里是打断点,原地址0x00005028->新地址0x40005028 新地址需要改成0x4
// emulator.attach().addBreakPoint(null, 0x40001188);//encode地址
// emulator.attach().addBreakPoint(null, 0x40000D10);
Number ret = TTEncryptUtils.callStaticJniMethod(emulator, "getByteValues()Ljava/lang/String;");
System.out.println(ret);
System.out.println("-----------------------");
long hash = ret.intValue() & 0xffffffffL;
StringObject st1 = vm.getObject(hash);
//*这里要处理下字符串
String byteString = st1.getValue();
StringBuilder builder = new StringBuilder(byteString.length());
for (int i = 0; i < byteString.length(); i++) {
if (byteString.charAt(i) == '0') {
builder.append('1');
} else {
builder.append('0');
}
}
byte[] strs_byte = strs.getBytes();
//获取encodeByte地址
ret = TTEncryptUtils.callStaticJniMethod(emulator, "encodeByte([BLjava/lang/String;)Ljava/lang/String;", vm.addLocalObject(new ByteArray(strs_byte)),
//传参,这里需要两个字符串,所以就传入两个参数
// vm.addLocalObject(new StringObject(vm, strs)),
vm.addLocalObject(new StringObject(vm, builder.toString()))
);
//ret 返回的是地址,
hash = ret.intValue() & 0xffffffffL;
//获得其值
StringObject str = vm.getObject(hash);
System.out.println(str);
System.out.println("----------------------");
System.out.println(str.getValue());
return str.getValue();
}
}
这个执行完之后在进行 md5 . 就 OK 了
第四步:使用 python 调用 jar
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~