安卓逆向吾爱破解2023春节领红包第三、第四题
写在前面
这几天跟着正己大佬学习了一些安卓逆向的知识,真心感觉大佬录制的课程不错,受益匪浅,吾爱破解安卓逆向入门教程《安卓逆向这档事》课程链接 https://www.bilibili.com/video/BV1wT411N7sV
课程中提到了春节领红包题目于是我觉得来试一下,虽然可能有点晚了,但是我决定贡献一下自己的解题思路,我对frida相对熟悉一些,所以主要使用的是frida
和jadx
,当然lsposed
、JEB
也是可以的。
环境介绍
活动帖子(已经结束) https://www.52pojie.cn/thread-1738015-1-1.html
活动已结束,题目打包放到爱盘供大家下载学习(web也一起打包,可以重新下载):
https://down.52pojie.cn/Challenge/Happy_New_Year_2023_Challenge.rar
frida 环境还需安装相应的python环境,对此相关的文章介绍较多,不多赘述
第三题
首先直接用jadx反编译
以上的逻辑非常清楚,只要点击999下响应的flag信息就会显示出来
有两种方法,一是修改我们点击的次数,二是主动调用decrypt方法解密相关字符串
import frida, sys
from pprint import pp
def on_message(message, data):
if message['type'] == 'send':
print(" {0}".format(message['payload']))
else:
print(pp(message))
jscode = '''
Java.perform(function () {
let MainActivity = Java.use("com.zj.wuaipojie2023_3.MainActivity");
MainActivity["check"].implementation = function () {
console.log(`MainActivity.check is called`);
// let result = this["check"]();
let result = 999; // 修改我们点击的次数
console.log(`MainActivity.check result=${result}`);
return result;
};
MainActivity["decrypt"].implementation = function (encryptTxt, i) {
console.log(`MainActivity.decrypt is called: encryptTxt=${encryptTxt}, i=${i}`);
let result = this["decrypt"](encryptTxt, i);
console.log(`MainActivity.decrypt result=${result}`);
return result;
};
})
'''
device = frida.get_remote_device()
# device = frida.get_usb_device() # usb调试的真机
# 方式1 hook 启动后的app
process = device.attach("【2023春节】解题领红包之三")
script = process.create_script(jscode)
script.on('message', on_message)
print('Running Hook')script.load()
sys.stdin.read()
效果如下:
或者通过主动调用
import frida, sys
from pprint import pp
def on_message(message, data):
if message['type'] == 'send':
print(" {0}".format(message['payload']))
else:
print(pp(message))
jscode = '''
Java.perform(function () {
// 主动调用
Java.choose('com.zj.wuaipojie2023_3.MainActivity', {
onMatch: function (instance) {
// textView = instance.textView;
console.log(instance["decrypt"]("hnci}|jwfclkczkppkcpmwckng\u007f", 2))
},
onComplete: function () {}
});
})
'''
device = frida.get_remote_device()
# device = frida.get_usb_device() # usb调试的真机
# 方式1 hook 启动后的app
process = device.attach("【2023春节】解题领红包之三")
script = process.create_script(jscode)
script.on('message', on_message)
print(' Running Hook')
script.load()
sys.stdin.read()
也可以顺利拿到flag
对于第二种方法使用了java.choose(...)
找到了com.zj.wuaipojie2023_3.MainActivity
类的实例,然后调用该实例的的decrypt
方法;按道理还可以new一个新的实例进行调用,但是我失败了,可能是MainActivity
的作为比较特殊的Activity
入参需要一些安卓的环境,有知道的大佬不吝赐教。
动态方法,有两种方法可以调用动态方法
第一种是,使用内存中已存在实例的方法,需要用到java.choose(...)
,这个是在内存中寻找对象
//从内存中(堆)直接搜索已存在的对象
Java.choose('xxx.xxx.xxx', //这里写类名
{ //onMatch 匹配到对象执行的回调函数
onMatch: function (instance) {
},
//堆中搜索完成后执行的回调函数
onComplete: function () {
}
});
第二种是,我们new一个新的实例,然后调用实例中的方法
//获取类的引用
var cls = Java.use('这里写类名');
//调用构造函数 创建新对象 这里注意参数
var obj = cls.$new();
第四题
还是老套路,先用jadx反编译(能反编译没有加壳真的很幸福,脱壳真的很麻烦)
flag正确字符串明显,进入到B方法
发现核心代码
其实此时已经可以还原出算法了,但是为了方便起见,直接hook areEqual
方法最简单,但是注意输入的验证flag形式如flag{XXX}
,不然不会进入验证的逻辑。
hook代码如下
Java.perform(function () {
let Intrinsics = Java.use("kotlin.jvm.internal.Intrinsics");
Intrinsics["areEqual"].overload('java.lang.Object', 'java.lang.Object').implementation = function (obj, obj2) {
console.log(`Intrinsics.areEqual is called: obj=${obj}, obj2=${obj2}`);
let result = this["areEqual"](obj, obj2);
console.log(`Intrinsics.areEqual result=${result}`);
return result;
};
})
此外这题还有针对jeb
的反动态调试,因为我用的frida,所有没有受到影响【狗头】
还有一个简单的签名验证,如果要删掉这段反调试的代码还要过掉这个签名验证,否则按钮就不可见了【真坏】