Jireh程序猿的那些事 Jireh程序猿的那些事

记录分享生活、程序、信息的精彩人生

目录
[转]Python反反爬虫 – Frida破解某盒子hkey反爬虫算法
/      

[转]Python反反爬虫 – Frida破解某盒子hkey反爬虫算法

[转]Python反反爬虫 – Frida破解某盒子hkey反爬虫算法

前言

这盒子有个抽奖功能,但是中奖率感人~
故,hack!
用到的工具:

1.抓包软件:NetKeeper[安卓端]
2.jeb分析工具[PC端]
3.ida分析工具[PC端]
4.Frida [Python模块以及服务端]

分析处理

先抓个包包吧

image.png

主要请求部分如下:

POST /account/data_report/?type=13&time_=1595993115&heybox_id=17584182&imei=xxxxx&os_type=Android
&os_version=6.0&version=1.3.114&_time=1595993115&hkey=bd34ee4c62
&channel=heybox_yingyongbao HTTP/1.1

经过测试hkey会随time_值变动而变动

jeb分析

搜寻hkey

image.png

v1v2的值来源似乎不好处理,

为了减少脑细胞与头发的消耗,可以尝试从NDKTools->encode方法入手。

但是,到达encode位置后(Ctrl+双击),

image.png

啊,这得上ida了

ida分析

进入ida的encode中,

image.png

image.png

看似没什么大问题,来hook:

console.log("========Hook Start==========")
 
String.prototype.format = function () {
    var values = arguments;
    return this.replace(/\{(\d+)\}/g, function (match, index) {
        if (values.length > index) {
            return values[index];
        } else {
            return "";
        }
    });
}
 
var JNI_LOAD_POINTER = Module.getExportByName('libnative-lib.so', 'JNI_OnLoad'); // 首先拿到 JNI_OnLoad方法的地址
var BASE_ADDR = parseInt(JNI_LOAD_POINTER) - parseInt('0x1C6C'); // 用程序运行中JNI_OnLoad的绝对地址减去它的相对地址得到基址
 
 
// encode
Java.perform(function() {
    var hookpointer = '0x' + parseInt(BASE_ADDR + parseInt('0x1B00')).toString(16) // 获取要hook方法的地址
    var pointer = new NativePointer(hookpointer) // 根据方法地址构建NativePointer
    console.log('[encode] hook pointer: ', pointer)
    
    var arg0, arg1, arg2, arg3
    Interceptor.attach(pointer, {
            onEnter: function(args) {
                arg0 = args[0]
                arg1 = args[1]
                arg2 = args[2]
                arg3 = args[3]
                console.log('\n')
                console.log('=====> [encode] -> [方法调用前]')
                console.log('参数1: {0} => {1}'.format(arg0, Memory.readCString(arg0)))
                console.log('参数2: {0} => {1}'.format(arg1, Memory.readCString(arg1)))
                console.log('参数3: {0} => {1}'.format(arg2, Memory.readCString(arg2)))
                console.log('参数4: {0} => {1}'.format(arg3, Memory.readCString(arg3)))
                console.log('参数5: {0} => {1}'.format(args[4], Memory.readCString(args[4])))
                console.log('\n')
            },
            onLeave: function(retval) {
                console.log('\n')
                console.log('=====> [encode] -> [方法调用后]:')
                console.log('返回值: ', retval)
                console.log('参数1: {0} => {1}'.format(retval, Memory.readCString(retval)))
                console.log('\n')
            }
        }   
    )
})

但是,还是出了些问题:

image.png

额,我不觉得肉眼能看出这是什么东西

既然程序处理了一些不能看的东西,那就尝试去找出能看的东西吧 😑

我觉得选择MDString比较好,因为可以看到什么东西被拿去算md5了。

hook MDString:

console.log("========Hook Start==========")
 
String.prototype.format = function () {
    var values = arguments;
    return this.replace(/\{(\d+)\}/g, function (match, index) {
        if (values.length > index) {
            return values[index];
        } else {
            return "";
        }
    });
}
 
var JNI_LOAD_POINTER = Module.getExportByName('libnative-lib.so', 'JNI_OnLoad'); // 首先拿到 JNI_OnLoad方法的地址
var BASE_ADDR = parseInt(JNI_LOAD_POINTER) - parseInt('0x1C6C'); // 用程序运行中JNI_OnLoad的绝对地址减去它的相对地址得到基址
 
// MDString
Java.perform(function() {
    var hookpointer = '0x' + parseInt(BASE_ADDR + parseInt('0x15C4')).toString(16) // 获取要hook方法的地址
    var pointer = new NativePointer(hookpointer) // 根据方法地址构建NativePointer
    console.log('[MDString] hook pointer: ', pointer)
    
    var arg0, arg1, arg2, arg3
    Interceptor.attach(pointer, {
            onEnter: function(args) {
                arg0 = args[0]
                arg1 = args[1]
                arg2 = args[2]
                console.log('\n')
                console.log('=====> [MDString] -> [方法调用前]')
                console.log('参数1: {0} => {1}'.format(arg0, Memory.readCString(arg0)))
                console.log('\n')
            },
            onLeave: function(retval) {
                console.log('\n')
                console.log('=====> [MDString] -> [方法调用后]:')
                console.log('返回值: ', retval)
                console.log('返回: {0} => {1}'.format(retval, Memory.readCString(retval)))
                console.log('参数1: {0} => {1}'.format(arg0, Memory.readCString(arg0)))
                console.log('\n')
            }
        }   
    )
})

输出:

image.png

可以发现,返回值正是将/game/all_recommend/bfhdkud_time=1596004491进行MD5加密:

image.png

结合抓包到的请求,可以得到NDKTOOL->encode的原理:

由路径/game/all_recommend与时间戳1596004491以及/bfhdkud_time=

拼接成/game/all_recommend/bfhdkud_time=1596004491算出32位 小写md5 837444501881f2af92b9cc0f0a9505fc

结论

hkey的处理流程:

image.png

注:Hook代码编写,参考:Python反反爬虫 – Frida破解某安卓社区token反爬虫


如果觉得这篇文章不错的话,请我喝一杯 咖啡☕吧
标题:[转]Python反反爬虫 – Frida破解某盒子hkey反爬虫算法
作者:Jireh
地址:https://jireh.xyz/articles/2020/07/30/1596118953825.html
本作品由 Jireh 采用 署名 – 非商业性使用 – 禁止演绎 4.0 国际许可协议进行许可,转载请注明出处。