Android爬虫比赛 第一关解析

VSole2023-01-14 11:11:54

一、环境

frida 12.8.20

python 3.8.10

jadx-gui-1.2.0

fiddler

二、实战步骤

1、安装APP,来到第一关,翻页时抓包。

jadx打开APP ,根据page= 查找到 com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment 类。

此处有sign函数,很大几率为翻页调用函数,hook当前函数查看 this.page 和 oooOO0O.OooO00o().longValue()的值:

function hook_ChallengeOneFragment(){    //访问内部类函数    Java.perform(function(){          var InnerClasses = Java.use("com.yuanrenxue.match2022.fragment.challenge.ChallengeOneFragment");        // console.log(InnerClasses);        InnerClasses.lambda$initListeners$2.overload('o00O000.OooOO0O').implementation = function(age){            console.log("this.page.value:",this.page.value);//查看page的值            console.log("age.OooO00o().longValue() :",age.OooO00o().longValue());//查看值            console.log("age:",age)//查看参数              var res = this.lambda$initListeners$2(age)//运行函数            console.log("res:",res,"type:",res.$className);//返回值和返回值类型              var Map = Java.use('retrofit2.adapter.rxjava2.BodyObservable');//根据返回值类型创建对象            var NewP = Java.cast(res, Map); //将返回值转成相应类型            console.log("NewP:",NewP.toString());//输出返回值            return res;        };      });}

分析代码:

StringBuilder 为可变字符串。

根据代码得出 sb的值为页码+时间戳 "page=21652931584"。

再次hook Sign函数查看参数和返回值并与fiddler对比。

function hook_SignClass(){    //访问内部类函数    Java.perform(function(){          // 访问内部类时,在当前类后加$符号,后跟内部类名        var InnerClasses = Java.use("com.yuanrenxue.match2022.security.Sign");        // console.log(InnerClasses);        InnerClasses.sign.overload('[B').implementation = function(arge1){            console.log("参数和参数类型:",arge1,arge1.$className);//数组类型一般会返回null            console.log("数组类型转码:",JSON.stringify(arge1));//数组类型可尝试使用json解析            var res = this.sign(arge1);//运行函数            // return true;            console.log("res",res);//返回值            return res;        };      });}

此时已经可以断定,这个Sign就是翻页的加密函数 。

根据jadx反汇编代码:

new Sign().sign(sb.toString().getBytes(StandardCharsets.UTF_8))

我们用python实现一下。

time_ = '1652932157's = 'page=1' + time_print("s:",s)bArr = [x for x in bytearray(s,'utf_8')]print("bArr:",bArr)  #s: page=11652932157#bArr: [112, 97, 103, 101, 61, 49, 49, 54, 53, 50, 57, 51, 50, 49, 53, 55]

此时直接调用sign生成加密参数,抓取100页的值相加得出flag:

#!/usr/bin/env python# -*- coding: utf-8 -*-  import fridaimport requestsimport time  #发送接收frida_js信息def on_message(message, data):    if message['type'] == 'send':        print("[*] {0}".format(message['payload']))    else:        print(message)  js = open('hook.js', 'r', encoding='utf8').read()   #读取frida脚本  session = frida.get_remote_device().attach('com.yuanrenxue.match2022')#根据包名启动APP  script = session.create_script(js)script.on('message', on_message)script.load()#加载frida脚本    if __name__ == '__main__':      time_ = int(time.time())#获取世家戳      header2 = {         'Accept-Language':'zh-CN,zh;q=0.8',         'User-Agent':'Mozilla/5.0 (Linux; U; Android 10; zh-cn; Mi9 Pro 5G Build/QKQ1.190825.002) AppleWebKit/533.1 (KHTML, like Gecko) Version/5.0 Mobile Safari/533.1',         'Content-Type':'application/x-www-form-urlencoded',         'Content-Length':'57',         'Host':'appmatch.yuanrenxue.com',         'Connection':'Keep-Alive',         'Accept-Encoding':'gzip',         'Cache-Control':'no-cache',    }    count = 0  #记数    for i in range(1,101):          s = f'page={i}' + str(time_)        bArr = [x for x in bytearray(s,'utf_8')]        res = script.exports.callsecretfunctionedy(bArr) #调用frida_js函数获取加密参数          payload = {            'page': str(i),            'sign': res,            't': time_,        }          r = requests.post("https://appmatch.yuanrenxue.com/app1", data=payload, headers = header2, verify = False )          data = r.json()['data']        for v in data:            count += int(v['value'])      print("flag count:",count)
var result;function callDYFun(bArr) { //定义导出函数    Java.perform(function () {        console.log("bArr:",bArr);        var ss = Java.use('com.yuanrenxue.match2022.security.Sign');        var str = Java.use("java.lang.String");        var res = str.$new(ss.$new().sign(bArr));        result = str.valueOf(res)        console.log("result:",result);      });    return result;//返回值给python}rpc.exports = {    callsecretfunctionedy: callDYFun,};

类中有两个函数一模一样lambda$initListeners$2和lambda$initListeners$0 。

经测试调用的是 lambda$initListeners$2。

sign解析函数
本作品采用《CC 协议》,转载必须注明作者和本文链接
首先使用jadx对apk进行逆向。?搜索关键字 QDSign,可以直接找到对应的类,可以看到参数经过加密得到。??进一步跟踪,发现了c类中有如下三个so方法,还有3个loadlibrary,分别进行了hook,发现c-lib动态注册了sign,sos动态注册了s,没有发现crypto有动态注册。
根据代码得出 sb的值为页码+时间戳 "page=21652931584"。再次hook Sign函数查看参数和返回值并与fiddler对比。此时已经可以断定,这个Sign就是翻页的加密函数 。我们用python实现一下。此时直接调用sign生成加密参数,抓取100页的值相加得出flag:#!
无意中看到ch1ng师傅的文章觉得很有趣,不得不感叹师傅太厉害了,但我一看那长篇的函数总觉得会有更骚的东西,所幸还真的有,借此机会就发出来一探究竟,同时也不得不感慨下RFC文档的妙处,当然本文针对的技术也仅仅只是在流量层面上waf的绕过。Pre很神奇对吧,当然这不是终点,接下来我们就来一探究竟。前置这里简单说一下师傅的思路部署与处理上传war的servlet是?
大厂基本为了程序的安全,会使用大量内联SVC去调用系统函数,以此来保护程序的安全。如何实现SVC指令的IO重定向,成为最大的问题。内核态是当Linux需要处理文件,或者进行中断IO等操作的时候就会进入内核态。当arm系列cpu发现svc指令的时候,就会陷入中断,简称0x80中断。
Java命名和目录接口是Java编程语言中接口的名称( JNDI )。它是一个API(应用程序接口),与服务器一起工作,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。 可以使用命名约定从数据库获取文件。JNDI为Java⽤户提供了使⽤Java编码语⾔在Java中搜索对象的⼯具。 简单来说呢,JNDI相当与是Java里面的一个api,它可以通过命名来查找数据和对象。
它通过解压缩 APK 并应用一系列规则来检测这些漏洞来做到这一点https://github.com/SUPERAndroidAnalyzer/super9、AndroBugs 框架是一种高效的 Android 漏洞扫描程序,可帮助开发人员或黑客发现 Android 应用程序中的潜在安全漏洞。它可以修改任何主进程的代码,不管是用Java还是C/C++编写的。
下一代加密技术接口是微软在 Windows 下实现的取代上一代加密应用程序接口的密码服务接口。其目的是提供一种可扩展的方式以支持各种应用程序和未知的密码算法,以便不同的算法、协议向操作系统注册,并对应用程序提供统一的调用接口,应用程序无需改造即可支持对新算法的使用。研究了基于下一代加密技术接口在操作系统中注册国密SM2、SM3 算法,完成解析和验证国密 SM2 证书,实现了国密算法在系统中的注册及
APP协议分析心得
2023-07-18 09:23:41
对脱壳流程有不明白的可参考我之前写的文章:[原创]ART环境下dex加载流程分析及frida dump dex方案。var magic_Hex = [0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00];var dex_path = "/data/data/" + apk_Name + "/" + dex_size + ".dex";
也防止有人通过inlinehook 直接hook recv ,recvform,recvmsg 直接在收到数据包的时候被拦截和替换掉。
关注一波,谢谢各位师傅感谢ch1e师傅帮忙总结ch1e‘blog:https://ch1e.gitee.io
VSole
网络安全专家