一、基本概念
1.1 动态调试
动态调试是指自带的调试器跟踪自己软件的运行,可以在调试的过程中知道参数或者局部变量的值记忆捋清代码运行的先后顺序。
多用于爆破注册码(CTF必备技能)
1.2 Log插桩
Log插桩
是指在反编译APK文件时,在对应的smali文件里,添加相应的smali代码,将程序的关键信息,以log日志的形式进行输出。
二、动态调试
2.1 修改debug权限
方法一:在AndroidManifest.xml
里添加可调试权限
android:debuggable="true"
方法二:XappDebug模块hook对应的app
项目地址
XappDebug
方法三:Magisk命令(重启失效)
1. adb shell # adb进入命令行模式
2. su # 切换至超级用户
3. magisk resetprop ro.debuggable 1
4. stop;start; # 一定要通过该方式重启
方法四:刷入MagiskHide Props Config模块(永久有效)
一般来说,在4选项中如果有ro.debuggable
那就直接修改
没有的话就选5
修改ro.debuggable
的值为1
2.2 端口转发以及开启adb权限
版本后点击七次开启开发者模式并开启adb调试权限
夜神模拟器: adb connect 127.0.0.1:62001
2.3 下端点
Jeb里使用ctrl + b
下断点
2.4 debug模式启动
adb shell am start -D -n com.zj.wuaipojie/.ui.MainActivity
- adb shell am start -D -n 包名/类名
- am start -n 表示启动一个activity
- am start -D 表示将应用设置为可调试模式
2.5 Jeb附加调试进程
快捷键 | 作用 |
---|---|
F6 | 进入方法 |
F7 | 从方法中跳出来 |
F8 | |
R | 运行到光标处 |
三、修改debug权限实操
3.1 修改AndroidManifest
3.2 XAppDebug模块
3.3 Magisk命令
上文
3.4 MigiskHide Props Config
安装模块
打开Mt管理器
终端模拟器
输入props
进入模块
然后按照上文操作即可
四、追码练习
4.1 开发者选项开启USB调试
,目标App要开启Debug调试
4.2 apk拖入JEB,搜索关键字密钥错误
发现关键点是
if(this.check(((EditText)this.findViewById(0x7F0800AC)).getText().toString())) { // id:edit_check
Context context0 = (Context)this;
Toast.makeText(context0, "恭喜你,密钥正确!", 1).show();
SPUtils.INSTANCE.saveInt(context0, "level", 3);
return;
}
Toast.makeText(((Context)this), "密钥错误哦,再想想!", 1).show();
4.3 继续追check
方法,双击方法名进入
public final boolean check(String s) {
int v = 0;
Integer integer0 = null;
if(!StringsKt.startsWith$default(s, "flag{", false, 2, null)) {
return false;
}
if(!StringsKt.endsWith$default(s, "}", false, 2, null)) {
return false;
}
String s1 = s.substring(5, s.length() - 1);
Intrinsics.checkNotNullExpressionValue(s1, "this as java.lang.String…ing(startIndex, endIndex)");
String s2 = SPUtils.INSTANCE.getString(((Context)this), "id", "");
if(s2 != null) {
integer0 = (int)s2.length();
}
int v1 = 1000;
Intrinsics.checkNotNull(integer0);
int v2 = (int)integer0;
if(v2 >= 0) {
while(true) {
v1 += -7;
if(v == v2) {
break;
}
++v;
}
}
byte[] arr_b = Encode.encode(s2 + v1).getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(arr_b, "this as java.lang.String).getBytes(charset)");
return Intrinsics.areEqual(s1, Base64Utils.INSTANCE.encodeToString(arr_b));
}
首先密钥必须以flag{
开头,以}
结尾
然后回取出除开头和结尾中间的内容和一个base64
加密的字符串进行比对
base64加密的数据是由s2(打开软件注册的用户名) + v1(整数常量组成),当s2固定时base64加密的结果也就固定了。
下一步就需要对加密结果打断点
4.4 app开启调试
4.5 Jeb附加调试进程
然后再去应用模拟验证一下
已经成功断点了,右边的寄存器也能看到局部变量
此时已拿到密钥:5YaF57OkDAUM
五、Log插桩
5.1 日志插桩dex注入
5.2 代码关键处添加输出
invoke-static {对应寄存器}, Lcom/mtools/LogUtils;->v(Ljava/lang/Object;)V
5.3 使用算法助手查看日志
然后启动 去触发一下关键点
拿到密钥
实战
反编译发现程序逻辑如下:
可以直接通过程序跑出来结果:
let str = 'e10adc3949ba59abbe56e057f20f883e'; // 对 123456 进行md5 再转 十六进制的结果
let sb = ''
for(let i = 0;true;i+=2){
if(i >= str.length){
console.log(sb);
return sb == '123';
}
// 将 str i位置上的字符追加到sb中
sb += str.charAt(i);
}
引用
1.《安卓逆向这档事》五、1000-7=?&动态调试&Log插桩:https://www.52pojie.cn/thread-1714727-1-1.html
2.吾爱破解安卓逆向入门教程《安卓逆向这档事》五、1000-7? & 动态调试&Log插桩:https://www.bilibili.com/video/BV1hg411q7dj/
3.JEB动态调试Smali-真机/模拟器(详细,新手必看):https://www.52pojie.cn/thread-1598242-1-1.html
4.Log简易打印工具,超简单的调用方法:https://www.52pojie.cn/thread-411454-1-1.html
5.Android修改ro.debuggable 的四种方法:https://blog.csdn.net/jinmie0193/article/details/111355867
评论 (0)