金三银四 某招聘软件登录及搜索接口

职场中,一直有“金三银四、金九银十”的说法,这指的是一年中求职的两个高峰期.
招聘软件十大排行榜 BOSS直聘、前程无忧51Job、智联招聘、58同城、猎聘、赶集网、拉勾招聘、店长直聘、聘达人、实习僧
如果你想整理一座城市的招聘信息,手动搜索属实是太麻烦了,如果你会爬虫的话,几行代码的事就可以轻松整理出一份城市与岗位的excel表,再配合数据可视化或者词云图可以看的更直观.
这期的内容是上面10大软件中的一个,之前有一期出了个市面上知名度很高的招聘软件,直接被开发警告了,火速删文,对方才得以撤回一条律师函,所以这个名字也是不能透露的.这期主要的是分析登录以及搜索接口的加密参数,涉及的内容有so的加密以及webview的滑块和无感验证码逆向,前面那块是安卓逆向中的内容,后面是js逆向的内容了.
我创建了个js 安卓 ios逆向交流群,欢迎加入交流技术!在最后面,7天有效.
学习交流,请勿违法使用!!!

登录

抓包

在这里插入图片描述

中间有4个值是极验的产品,校验通过后返回的geetestValidate,这个验证码有时候是滑块,有时候是无感.
密码我输入的是123456,加密成了767367756c66,视乎看不出来什么规律,换个密码再加密一遍,123456123456,加密成767367756c666366656b6e69,长度变成了,可能是对称加密算法,比如des或者aes.目前来看就是需要逆向掉极验的验证码还有密码加密就可以自动登录了.

password

先拿算法助手hook看一下是不是java层的加密,小公司可以先验证一下,大公司就别想了,肯定是so的.
军哥的算法助手地址 https://github.com/Xposed-Modules-Repo/com.junge.algorithmaide
需要先在xposed环境下安装好,xp里面也要勾选上目标应用,然后就是算法助手内部也勾上.
在这里插入图片描述
这些就不介绍了,字面意思应该也能看懂.往下滑还有需要开启的地方.
在这里插入图片描述
webview可调式以及弹窗定位,无感或者是滑块都有一个弹窗,可以通过这个定位到关键函数.webview可调式开启后,如果app使用的是webview的滑块那就需要开启浏览器远程调试才能逆向,后面再说这个,默认app是会关掉这个webview可调式的,当然也可以用frida来hook掉,只不过xp更持久一点.

setTimeout(function(){
    Java.perform(function() {
        var Webview = Java.use("android.webkit.WebView")
        Webview.loadUrl.overload("java.lang.String").implementation = function(url) {
            console.log("\n[+]Loading URL from\n", url);
            console.log("[+]Setting the value of setWebContentsDebuggingEnabled() to TRUE");
            this.setWebContentsDebuggingEnabled(true);
            this.loadUrl.overload("java.lang.String").call(this, url);
        }
    });
},0);

都勾上后重启app,登录一下,在算法助手的日志里搜索一下123456加密成的767367756c66
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

没搜到,可能是java层的自写算法或者是so的加密,先来尝试下定位到关键函数.

查壳

在这里插入图片描述
不过这个pkid作者不更新了,这个版本太老了,很多新的安全产商没有融入进去比如网易易盾,几维安全等等,如果你反编译的代码感觉很少或者缺少关键类很有可能是加固了但是没有检测出来,推荐用mt管理器查看一下,因为mt管理器是一直更新的.这个我看了下确实是没有加固的,可能是觉得有极验可以保护他.

代码定位

没加固直接扔到jadx里就好了,你可以尝试搜索"password",但是这样结果很多的话就显得麻烦了.

hook hashmap.put

var hashMap = Java.use("java.util.HashMap");
hashMap.put.implementation = function (a, b) {
if(a!=null && a.equals("password")){
    console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
    console.log("hashMap.put: ", a, b);
}
return this.put(a, b);}

额,什么输出也没有,那应该不是通过hashmap添加到表单里的.接下来就不是很好定位了,因为它既没有base64,也没有拼接什么特殊字符串,无法hook base64或者stringbuilder.你可以返回去尝试最原始的定位方式,搜索大法,只不过会比较费时间,还不一定能定位到.
我觉得它有可能是so的算法,所以我hook了NewStringUTF,前提是结果通过字符串返回去的,如果是字节数组就不是那么好hook了.也可以hook下GetStringUTFChars,这个是jstring转cstring的,可以刷选下jstring里面是否有传入的明文123456来定位.这两种方法对这个app都有效.

NewStringUTF

var addrNewStringUTF = null;
var symbols = Module.enumerateSymbolsSync("libart.so");
for (var i = 0; i < symbols.length; i++) {
    var symbol = symbols[i];
    if (symbol.name.indexOf("NewStringUTF") >= 0 && symbol.name.indexOf("CheckJNI") < 0) {
        addrNewStringUTF = symbol.address;
        console.log("NewStringUTF is at ", symbol.address, symbol.name);
    }   

}
    if (addrNewStringUTF != null) {
    Interceptor.attach(addrNewStringUTF, {
        onEnter: function (args) {

            var c_string = args[1];
            var dataString = c_string.readCString();
            if (dataString) {
                if (dataString=='767367756c66') {  //这里写要对字符串的筛选
                    console.log(dataString);
                    //读取当前是在那个so文件,那个地址
                    // console.log(Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\n') + '\n');
                    //先用下面的
                    // console.log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
                    console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
                }
            }

        },
    });
}

结果

NewStringUTF is at  0x74d81bf680 _ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc
767367756c66
java.lang.Throwable
	at com.zhaopin.social.jni.NdkTool.encryptPwd(Native Method)
	at com.zhaopin.social.passport.usecase.CPwdLoginUseCase.c(CPwdLoginUseCase.kt:8)
	at com.zhaopin.social.passport.usecase.CPwdLoginUseCase$invoke$1.invokeSuspend(Unknown Source:16)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:4)
	at kotlinx.coroutines.v0.run(DispatchedTask.kt:18)
	at android.os.Handler.handleCallback(Handler.java:883)
	at android.os.Handler.dispatchMessage(Handler.java:100)
	at android.os.Looper.loop(Looper.java:214)
	at android.app.ActivityThread.main(ActivityThread.java:7356)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

优先看最上面的堆栈,com.zhaopin.social.jni.NdkTool下的encryptPwd方法.
在这里插入图片描述
是一个native方法,直接右键复制frida片段看看入参是什么

let NdkTool = Java.use("com.zhaopin.social.jni.NdkTool");
NdkTool["encryptPwd"].implementation = function (str) {
    console.log(`NdkTool.encryptPwd is called: str=${str}`);
    let result = this["encryptPwd"](str);
    console.log(`NdkTool.encryptPwd result=${result}`);
    return result;
};

在这里插入图片描述
入参就是输入的,结果也是包里面的. so文件是_zhaopin_v1.0
只有64位的,用ida64打开

so分析

在这里插入图片描述
搜一下java 有结果,静态注册,点过去
在这里插入图片描述
先改jnienv对象,这样有些jni的方法可以显示出来,燃弧入参改一下input,这样更明显
没改jnienv对象前,看不出来这个是jni方法
在这里插入图片描述
改完之后就可以看到GetStringUTFChars和NewStringUTF了,分别是jstriing转cstring和cstring转jstring.
在这里插入图片描述
没有混淆,直接看静态代码配合frida来hook应该问题不大.
在这里插入图片描述

这里是主程序逻辑,这伪c代码写得很清晰了.中间有个sub_EFE4函数,frida hook看一下,它在一个while循环里,可以添加一个数字看他调用了几次

// EFE4
var soAddr = Module.findBaseAddress("lib_zhaopin_v1.0.so");
var funcAddr = soAddr.add(0xEFE4)  //32位的话记得+1
var num = 0
Interceptor.attach(funcAddr,{
            onEnter: function(args){
                num+=1
                console.log(`${num}次:`)
                console.log('onEnter arg[0]: ',args[0])
                console.log('onEnter arg[3]: ',args[3])
                // this.arg0 = args[0]
            },
            onLeave: function(retval){
                // console.log('onLeave arg[]: ')
                // console.log('onLeave result: ',retval)
            }
        });

在此之前,可以先写一个java层的主动调用,这样就可以让手机息屏了,或者是关掉wifi,这样可以减少网络请求,如果有很多请求走这个函数就会输出很混乱,主动调用可以确保就调用一次.

function call(){
    Java.perform(function (){
    let NdkTool = Java.use("com.zhaopin.social.jni.NdkTool");
    var res = NdkTool["encryptPwd"]('123456')
    console.log('res:',res)
    })
}

终端call()一下,报错不能调一个方法而没有实例
在这里插入图片描述
上面看到了native方法没有加static,所以这个是一个实例方法,需要先实例化一个对象,加一个.$new()即可

function call(){
    Java.perform(function (){
    let NdkTool = Java.use("com.zhaopin.social.jni.NdkTool");
    var res = NdkTool.$new()["encryptPwd"]('123456')
    console.log('res:',res)
    })
}

主动调用后就有结果了,接下来配合着主动调用来hook so的sub_EFE4函数
在这里插入图片描述
入参1是一个地址,入参4就是password加密的结果未拼接之前,最终结果是767367756c66,这个是入参并不是执行后的结果,看下入参4是什么
在这里插入图片描述
就是aEa4a7024279346[v9 & 0x3F] + v7,v7来着v4也就是入参,123456第一位的1的十六进制是0x31,
aEa4a7024279346[v9 & 0x3F]是在根据索引取数组的值,v9刚开始是0,循环一次加1,最后与0x3f位与.
很清晰了,刚开始0 & 0x3f = 0,aEa4a7024279346的第0个是什么?
在这里插入图片描述
28F46偏移处都是aEa4a7024279346的,第0个是0x45,0x45+0x31=0x76,对上了,后面的也是这样的流程,相信不需要我多说了.

验证码

app端的滑块怎么分析呢?
App端滑块一般由原生组件或在WebView 中使用 Web 技术来实现,为了不重复构建代码做到跨平台兼容性,一般都是使用webview实现滑块,并且app端滑块与web端滑块加密一般都相同,在加密的入参上可能会有一些区别;

那么针对webview滑块该如何进行分析呢?在 Android 应用程序中,WebView 可以理解为一个嵌入式的浏览器引擎。和我们分析web端滑块一样,在谷歌开发者工具中进行断点调试就行。但是大多数情况下,apk打包出来都会禁止WebView调试,这时我们需要hook WebView让它可调式。在最上面已经说过了webview可调式.

devtools开启调试

手机usb连上电脑,浏览器地址栏输入chrome://inspect/#devices,edge浏览器就换成edge://inspect/#devices,其他的类似.等待一会.
在这里插入图片描述

点击inspect进去
在这里插入图片描述

之后就和浏览器调试一样了,相信不需要我多说了,做js逆向的应该都懂,极验滑块应该是js逆向接触的第一种滑块,网上教程很多,应该不需要我这里多说了.

无感webview

由于无感太快了,2到3秒内就验证完成了,但此时浏览器的inspect页面还没有出现可调式就结束了,这个怎么解决呢
我尝试了用charles添加断点把极验的几个请求都打上了断点
在这里插入图片描述
天真的我以为他会像浏览器一样直接断住
在这里插入图片描述
charles中是断住了,但是后续一会app没有收到响应直接网络超时后弹窗就消失了,这样也开启不了调试,只可以去hook java中的函数了,让这个弹窗刚出现的时候hook上让他延时加载,这样理论就有足够的时间等待浏览器的inspect界面出现可调式,hook这个弹窗前面的算法助手就可以hook上,再回溯堆栈就能定位到弹窗的位置了.点击inspect进去的时候可能需要科学上网环境,需要访问谷歌的站点下载些组件.

搜索接口

需要先登录才能搜索
在这里插入图片描述

抓了两个搜索的包,初看似乎没有什么加密参数

总结

解决了登录和搜索的问题就可以越快的编写爬虫程序了,账号风控的话可能还需要多账号.本章主要就是介绍一下webview的滑块,以及so的逆向,虽然你看我上面说的似乎挺简单的,但是到你自己独立去弄一个app的so的时候没有别人写的分析文章可能就有些吃力了,所以还是需要自己多练,毕竟这个也只能算是个比较简单的自写算法,也没有混淆什么的.
说到混淆就必须看看这个图了,上图,自行欣赏!
在这里插入图片描述

最后

知识星球
在这里插入图片描述
微信公众号
在这里插入图片描述
技术交流群
在这里插入图片描述

### 软件测试面试技巧 对于参与软件测试职位的候选人来说,在准备过程中应注重以下几个方面: - **理解基础概念**:掌握基本的计算机科学原理以及编程语言的基础知识。熟悉不同类型的测试方法,如单元测试、集成测试、系统测试和验收测试等[^2]。 - **工具和技术熟练度**:能够操作常用的自动化框架(Selenium, Appium)、性能测试平台(JMeter, LoadRunner),并能编写脚本来提高工作效率。 - **沟通能力**:清晰表达想法的能力非常重要,尤其是在描述缺陷报告时要准确无误;同时也要善于倾听他人的意见以便更好地协作解决问题。 - **逻辑思维与问题解决技能**:面对复杂情况可以快速定位原因,并给出合理的解决方案建议。 - **持续学习的态度**:技术更新迅速,保持好奇心不断探索新知有助于个人成长和发展职业道路。 #### 常见问题示例 以下是几个可能出现在软件测试岗位上的典型问题及其解答思路: 1. **如何检测应用程序是否存在内存泄漏?** 使用`adb shell dumpsys meminfo packagename -d`命令来监控退出应用后的视图(Views)和活动(Activities),当这些对象的数量不为零时,则表明可能存在潜在的记忆泄露风险。此时可以通过LeakCanary这类专门用于捕捉Java/Kotlin程序中的未释放资源问题的应用来进行更深入地排查,必要情况下借助MAT(Memory Analyzer Tool)做进一步的数据挖掘工作直至找到根本原因并加以修复。 2. **解释一下黑盒测试与白盒测试的区别在哪里?** 黑盒测试主要侧重于验证系统的外部行为是否符合预期的功能需求说明文档所规定的内容,而不关心内部结构是如何实现的具体细节;相反的是,白盒测试会基于源代码层面去评估算法效率、路径覆盖程度等方面的表现状况,确保每一行指令都能被执行到从而保障整体质量可靠稳定。 3. **谈谈你对敏捷开发模式下QA角色的理解吧。** 敏捷环境中,质量保证(QA)不再局限于传统的后期介入方式而是贯穿整个项目周期始终参与到各个迭代环节当中。这意味着团队成员之间需要更加紧密合作交流信息共享经验共同进步,同时也赋予了每位参与者更多自主权以灵活应对变化多端的需求环境挑战未知领域开拓创新空间无限可能性。 4. **请举例说明你在实际工作中遇到的一个棘手Bug是怎么被发现并且最终得以解决的过程。** 这类开放型题目旨在考察应聘者的实战经历及处理突发状况的经验积累水平。可以从具体场景切入讲述当时面临的技术难题所在之处采取哪些措施逐步缩小范围锁定目标直至彻底根除隐患恢复正常使用状态为止的经历分享给对方听闻。 5. **假如现在让你负责一款移动APP产品的全流程测试计划制定你会怎么做呢?** 需要考虑的因素包括但不限于功能性验证、兼容性适配、安全防护机制审查等多个维度进行全面考量规划合理的时间表安排合适的人员配置选用恰当的方法论指导实践操作流程等等一系列准备工作都要做到位才能确保任务顺利完成达到既定的质量标准要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨如画.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值