猿人学APP逆向对抗前三题
第一题是java层加密,第二道是so加密,第三道是so混淆,经过分析前三道题sign生成算法不同,但是可以用相同的方法获取flag,这里以第一题为例:charles
+ postern
抓包分析获取到两个接口。/time
接口获取时间戳,/app1
接口传入参数page,sign和前面获取的时间戳,返回数据就是对应page页面的所有数据。
题目需要计算所有0-100页面中所有值的和。有两个思路,一是主动调用app发送http请求的函数并hook接收返回数据的函数获取所有页面的值,二是分析sign的算法,然后主动调用sign算法生成sign值并构造http请求获取0-100页面的值,最后将值相加。
分析sign算法主动构造http请求#
因为/app1
接口会请求对应page页面的数据,jadx直接搜索接口字符串可以看到对应的接口函数。
查看什么位置调用了此接口函数。
来到接口函数调用处,很清楚的看到其将"page=" + page页面值 + 时间戳组合后调用sign函数生成sign值。
对应的sign函数貌似就是一个md4的哈希函数,接下来就可以通过主动调用此sign函数生成sign值并构造http请求了。
js中主动调用sign函数并导出,python利用rpc调用此导出函数生成sign并构造http请求即可获得所有页面的值,最后计算和为4902423
。
function callsign(string1){
var sign_value;
Java.perform(function(){
sign_value = Java.use("com.yuanrenxue.match2022.security.Sign").$new().sign(stringToByte(string1));
})
return sign_value;
}
rpc.exports = {
callsign: callsign,
};
hook app自身的收发包函数#
另一种方法就是直接通过主动调用app的发包函数和hook收包函数来计算所有页面的值。查看反编译代码发现lambda$initListeners$3
函数会先获取时间戳,然后调用lambda$initListeners$2
获取页面数据,所以只要主动调用100次此函数就可以获取到所有页面的值。
lambda$initListeners$3
是ChallengeOneFragment
类的成员函数,所以需要先在内存中找到ChallengeOneFragment
类实例。
var ChallengeOne_instance;
Java.choose("com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment", {
onMatch:function(instance){
ChallengeOne_instance = instance;
console.log(ChallengeOne_instance);
},onComplete:function(){}
})
lambda$initListeners$3
还有一个参数是一个接口类,右键查看调用实例发现OooO0oO
函数会调用lambda$initListeners$3
并传递接口类作为参数。
紧接着右键查看是哪个函数调用的OooO0oO
,可以看到有两个位置会调用此函数并且传入的参数都是com.scwang.smartrefresh.layout.SmartRefreshLayout
类实例。
最后就得到lambda$initListeners$3
函数的参数是com.scwang.smartrefresh.layout.SmartRefreshLayout
类实例,所以需要先在内存中找到此实例。
var Smart_instance;
Java.choose("com.scwang.smartrefresh.layout.SmartRefreshLayout",{
onMatch:function(instance){
Smart_instance = instance;
console.log(Smart_instance);
},onComplete:function(){
}
})
现在就可以主动调用lambda$initListeners$3
函数请求0-100所有页面的数据了。
for(var i = 0; i < 100; i++){
ChallengeOne_instance.page.value = i;
ChallengeOne_instance.lambda$initListeners$3(Smart_instance);
Thread.sleep(1)
}
还需要hook接收数据包的函数,进一步获取所有请求的返回值并计算所有页面之和。再次查看lambda$initListeners$3
函数发现其最后会调用subscribe
函数并new了一个对象。
查看此对象对应的类发现了onNext
函数,此函数的参数是一个C3751OooO00o
(名称反混淆过了)类对象。
查看此类对象发现其成员包含了返回数据包中的state
, data
。而data
是一个类对象列表,列表中对象的成员变量包含了页面的value
值。
所以通过hook onNext函数并调用C3751OooO00o
类的成员函数即可获得此次请求返回的页面value值,onNext类是内部类com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment$OooO0O0
的成员函数。这里还要特别注意onNext函数的参数是java.lang.Object
类型,需要先利用Java.cast
强制转换为对应的类后才能调用对应的成员函数和获取其成员变量。
var sum = 0;
Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment$OooO0O0").onNext.overload('java.lang.Object').implementation = function(arg1){
var class1 = Java.cast(arg1, Java.use("o00O000.OooO00o"));
var class2_array = class1.OooO00o().toArray();
for(var i = 0; i < class2_array.length; i++){
var class2 = Java.cast(class2_array[i], Java.use("o00O000.OooO0OO"));
var value_string = class2.OooO00o();
sum = sum + int64(value_string);
}
}
最后通过主动调用app发包函数,并hook收包函数获取所有页面的value之和为4902423
完整的脚本如下:
function main(){
Java.perform(function(){
Java.use("com.yuanrenxue.match2022.security.Sign").sign.overload('[B').implementation = function(arg1){
var arg1_string = byteToString(arg1);
console.log("\narg1 :", arg1_string);
console.log("sign_value is :", this.sign(arg1));
return this.sign(arg1);
}
var ChallengeOne_instance;
Java.choose("com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment", {
onMatch:function(instance){
ChallengeOne_instance = instance;
console.log(ChallengeOne_instance);
},onComplete:function(){}
})
var Smart_instance;
Java.choose("com.scwang.smartrefresh.layout.SmartRefreshLayout",{
onMatch:function(instance){
Smart_instance = instance;
console.log(Smart_instance);
},onComplete:function(){
}
})
var sum = 0;
Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment$OooO0O0").onNext.overload('java.lang.Object').implementation = function(arg1){
var class1 = Java.cast(arg1, Java.use("o00O000.OooO00o"));
var class2_array = class1.OooO00o().toArray();
for(var i = 0; i < class2_array.length; i++){
var class2 = Java.cast(class2_array[i], Java.use("o00O000.OooO0OO"));
var value_string = class2.OooO00o();
sum = sum + int64(value_string);
}
}
for(var i = 0; i < 100; i++){
ChallengeOne_instance.page.value = i;
ChallengeOne_instance.lambda$initListeners$3(Smart_instance);
Thread.sleep(1)
}
console.log("sum is ", sum);
})
}
setImmediate(main)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】