小迪安全v2023学习笔记(八十八讲)—— 安卓逆向篇JEB反编译断点动态调试加密算法还原逻辑会员绕过
文章目录
- 前记
- APP攻防——第八十八天
- 安卓逆向篇&JEB反编译断点&动态调试&加密算法还原&逻辑会员绕过
- APK逆向 - 反编译&动态调试-JEB&ADB
- ADB
- JEB
- 调试前奏
- APK逆向 - 反编译&动态调试-算法分析
- 靶场演示
- 实战案例
- APK逆向 - 反编译&动态调试-会员机制
前记
- 今天是学习小迪安全的第八十八天,本节课延续上节课的内容,主要是关于小程序反编译之后动态调试的内容
- 本节课主要是学会使用JEB这款工具,然后了解调试的思路,包括如何搜索到关键的代码,如何设置断点,如何调试等等
- 所需要用到的资源已放至下方链接,需要的自取:
- https://pan.baidu.com/s/1rt8k2j6enenjl0qJb5od5A
- 提取码:yyds
APP攻防——第八十八天
安卓逆向篇&JEB反编译断点&动态调试&加密算法还原&逻辑会员绕过
APK逆向 - 反编译&动态调试-JEB&ADB
- 这里是环境的配置,在学习这节课之前,我们需要配置配置两个东西:JEB以及ADB
ADB
-
这个就是安卓模拟器的一个USB调试器,可以用自带的,这里安装通用的是为了配合后续的JEB使用
-
下载地址:Android 调试桥 (adb) | Android Studio | Android Developers
-
安装好之后就将其配置到环境变量中,以Android命名,并同时放到Path中:
-
这里最好在用户变量和系统变量中都设置一下,然后开启模拟机,并打开cmd运行如下命令:
adb devices
- 这里如果提示有
xxx device
说明有模拟器启动并开启了USB调试,如果没有显示就说明没有开启
JEB
-
这个是一个很好用的APK反编译调试软件,类似IDA PRO,可以用于APK的反编译以及动态调试
-
下载地址:JEB-5.29.0.202505042038_by_CXV.7z ~ pixeldrain,这是比较新的破解版本,但非官方链接,请谨慎下载
-
如果用小迪提供的Java环境需要为11版本,如果是我这里下载的Java环境需要为17版本!
-
然后这里直接下载之后运行
.\jeb_wincon.bat
文件即可,如果出现如下报错:
-
说明是Java环境不对,需要更换Java环境,如果Java环境是17但仍然报这个错误,需要更改
.bat
文件为如下所示:
rem Prefer local JRE
set JAVA=更改为JAVA17的路径
if exist %JAVA% goto :runinst
- 然后再运行
.bat
文件即可:
调试前奏
- 在正式使用上面工具调试之前,我们需要做以下前置步骤:
- 运行APP进行动态调试:使用MT对APK反编译后,在
AndroidManifest.xml
文件中<application>
标签处添加如下代码
android:debuggable="true"
- 端口转发以及开启adb权限:
MuMu 模拟器:adb connect 127.0.0.1:7555
夜神模拟器:adb connect 127.0.0.1:62001
雷电模拟器:adb connect 127.0.0.1:5555
逍遥安卓模拟器:adb connect 127.0.0.1:21503
天天模拟器:adb connect 127.0.0.1:6555
海马玩模拟器:adb connect 127.0.0.1:53001
- debug模式启动APP:
adb shell am start -D -n 包名/类名
例:adb shell am start -D -n com.zj.wuaipojie/.ui.MainActivity其中:
adb shell 表示进入模拟器终端
am start -n 表示启动一个 activity
am start -D 表示将应用设置为可调试模式
APK逆向 - 反编译&动态调试-算法分析
靶场演示
-
这里我们使用上节课的吾爱破解靶场的第四关来作为演示,看看怎么通过动态调试了解他背后的算法,拿到一些东西
-
这里我们随便输入密钥发现他会提示错误,当然如果他硬编码到代码中,我们可以直接反编译拿取,但是这里是动态生成的,所以我们需要用到JEB动态调试
-
首先用MT对其添加上述运行调试的代码:
-
然后重打包,之后用JEB打开该apk,他就会自动反编译为Smail代码:
-
如果看不懂,可以选中某一个方法,右键点击反编译,他就会变成Java代码:
-
我们首先看一下他的
AndroidManifest.xml
文件中有没有能够调试的配置:
-
然后我们就可以开始调试了,首先我们需要定位到关键的地方,这里根据关键词 “密钥错误哦,再想想”,我们就可以直接
ctrl+f
搜索:
-
可以看到搜到一个“密钥正确”,那这里不就是我们需要进入的地方吗,点开看看,整个方法是这样:
-
反编译为Java代码,然后看看他的逻辑是怎样的:
-
这里他是一个
if
判断,调用check()
方法,传入findVieById
的值,这里传入的id
可以知道就是我们传入的值 -
如果
check()
返回为true
,就进入“密钥正确”的逻辑,否则进入“密钥错误”的逻辑,于是我们尝试去找check()
方法,直接双击该方法即可:
-
我们可以看到如果要让他返回
true
,那么还是有两种思路,一种是直接让他返回true
,一种是找到正确的flag
值 -
这里采用第二种方式去解决这个问题,这时要用到动态调试的方法,我们先右键反编译到Smail语法,然后设置需要断点的地方,看一看他运行到
Base64Utils.INSTANCE.encodeToString(arr_b)
打印的结果
-
我们找到想要断点的地方,然后
ctrl + b
设置断点,点击开始运行,他会弹出如下信息:
-
如果这里没东西说明上面的配置没配好,然后我们点击附加,选中局部变量:
-
之后我们就在模拟器上随便输入一个密钥,注意要输入
flag{}
格式,才能让他执行到这个地方:
-
可以看到成功执行到这个地方,然后右边的调试界面出现了我们输入的密钥值123,然后点击单步调试(遇到可疑的地方点击单步跳入,其余点击单步跳过),仔细观察右边的变动:
-
这里也是慢慢调出了他正确的密钥,然后我们直接用这个密钥进行验证:
-
验证成功
实战案例
-
这里我们通过嘟嘟牛软件来演示一下这种APP传输的数据如果进行加密了,该如何处理的情况
-
我就直接用小黄鸟抓包看了,点开登录页面,随便输入账号和密码抓包:
-
我们看到请求的数据包为JSON格式,并且参数已经被加密了:
{"Encrypt" : "NIszaqFPos1vd0pFqKlB42Np5itPxaNH\/\/FDsRnlBfgL4lcVxjXii8Fj5MCFvD1pCdd8ypLqNKJV\nzPy7wHsBhvqoY3s1l4GAc8eK4M9zxjng8WB4idJwbQZksstQ\/MJz4D47R42sg+dOHD\/JU7GHtOdR\nWGekoKyS6aZsyRV6FJP\/XwhUCvWxleCbp\/V8oq\/SDZ6+QdbLWKbd8btqf+brI7rpCdza+mYdPg4V\nNO+J+yk=\n"
}
-
根据之前JS逆向讲的,如果要进行测试,那就需要知道他的加密逻辑,而这里不能直接看到源代码,所以就需要反编译看他的逻辑,先看看他能不能被调试:
-
这里是原本就可以的,然后去尝试找到我们的这个加密代码,关键词搜索 ”Encrypt“、登录、登录密码等等都可以看看:
-
然后就一个一个慢慢看吧,基本就是看他有这种方法加密的,这里如果实在不知道,感觉每个都很像的话,就多打几个断点然后慢慢看即可
-
这里可以找到这个地方的代码,看到有个
JSONObject
,因为我们传输的数据也是JSON格式的,那他就很可能是,直接下断点然后调试:
-
emmm,这里应该是这个软件出现问题了,一直显示数据加载失败,服务器可能是关掉了,复现不了了
-
所以理解他的思路即可,其实就和JS逆向差不多,找到他的加密逻辑,比如这里我们可以知道他是AES加密,然后也能找到他硬编码的key和iv:
-
然后我们可以尝试AES解码一下,这里也编写了个解密的代码可以尝试解密:
// 前面是JS的AES库函数function test(){ var key = CryptoJS.MD5('65102933') + '' ; key = CryptoJS.enc.Hex.parse(key); var iv = CryptoJS.enc.Utf8.parse("32028092"); var dec = CryptoJS.DES.decrypt('NIszaqFPos1vd0pFqKlB42Np5itPxaNH\/\/FDsRnlBfgL4lcVxjXii5CB5x5odgFUoXTWEi4ZL6xCz5AB7rx\/rw11ZSivXUGWJrKn2v0wjwcOnU4ekpYP6GYEgMfcchmOA+MyPktBo+OsbSIl857DByZ3lOu7ely+p5BnAPoOInpX0Wp10ME0Lp19l7GEMc8ANbX16Td4sdWWf6D0EwKUOiRddMNekbh1nrp8Hsk1rsk=',key,{ iv: iv, mode: CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return dec.toString(CryptoJS.enc.Utf8);
} test()
- 我们就可以编写一个加密的代码然后放到BP上,实时加密去测试我们的payload
APK逆向 - 反编译&动态调试-会员机制
-
这个就是上节课的淘小说APP,之前是通过MT去反编译然后搜索找到相关代码,但是那样太复杂了
-
他不能定位,只能一步一步手动搜索,而我们今天就使用JEB去演示一下怎么简化我们的逆向过程
-
还是先添加
debuggable
的设置,然后用JEB反编译,搜索我们的关键字 ”开通“:
-
其他都是开通之后怎么样,这里直接出现个已开通,是一种状态,说明很有可能就是我们要找的地方,点开看看:
-
可以看到这里他就是判断一种状态,
if
语句里面就是判断它是否开通的逻辑,所以我们直接双击追踪y5()
函数即可:
-
那我们就能够看到它的逻辑了,其实可以看到逻辑的核心就是这个
getIsVip()
函数,因为前面哪个就是个判断用户是否存在的 -
昨天的课,我们就是直接改动的这里,让他的返回值为
true
,今天我们可以继续往前追踪:
-
那它的逻辑就是这样的,所以我们就只用让他这里永远为
true
即可,反编译为Smail语法,找到返回值:
-
所以我们只用将
const/4 v0, 0
改为const/4 v0, 1
即可,因为JEB不支持重打包,还得到MT中去重打包,看看这个函数出现在哪个类中:
-
改动之后,签名重打包发现我们成功成为了尊贵的会员: