手把手教你搭个Frida + Sekiro Rpc框架

1. 看一个手机号加密的例子

img.png
这个例子来自某视频App,可以看到mobile字段是被加密的。

一、尝试字符串匹配

也许是手机号都是1xx开头,也许是这个加密字符串有个特征头。反正经过我们观察,发现它大概率是 3sCt 开头。
而这种加密算法大概率是在Native层去做的。所以我们首选是去 hook_libart 里面的 GetStringUTFCharsNewStringUTF
结果木有结果。

二、尝试Base64

这个3sCt开头的字符串,很像Base64的结果。我们尝试用Base64去解一下,发现能解开。
那就毫不犹豫地尝试 Hook android.util.Base64
依然木有结果,这就比较神奇了,唯一的解释是 App木有用标准的Base64库函数,而是自己写了一个Base64算法。毕竟Base64的算法满天飞,有手就行。

三、搜索关键字mobile

现在死马当活马医吧。只能尝试去搜搜字符串了
img.png
结果并不多,比较有重大嫌疑的就是这两处了。
我们点进去分析 m434739f 函数。
img_1.png
这个App已经混淆到令人发指了,居然还能出现 atlasEncrypt 这么明显的函数,一定得好好Hook它。
m60341e 也值得我们注意,这个类很像是Base64算法,这也解释了为啥Hook android.util.Base64 木有结果。

四、写个demo验证

var IKSecurityExCls = Java.use("com.xxxixxxu.android.security.KSecurity");

IKSecurityExCls.atlasEncrypt.implementation = function(a){
    var StrCls = Java.use('java.lang.String');
    var inStr = StrCls.$new(a);

    var result = this.atlasEncrypt(a);
    console.log(inStr + " >>> atlasEncrypt(Hex) " + bytesToHex(result));
    console.log(inStr + " >>> atlasEncrypt(Base64) " + bytesToBase64(result));

    return result;
}

最后发现可以得到预期的结果~

2. Frida开发Sekiro客户端

Sekiro是个相当牛X的库,基本上就是开箱即用了。

// 在普通Android应用中使用sekiro
new SekiroClient("test-android", UUID.randomUUID().toString())
    .setupSekiroRequestInitializer(new SekiroRequestInitializer(){
        @Overridepublic void onSekiroRequest(SekiroRequest sekiroRequest, HandlerRegistry handlerRegistry) {
            handlerRegistry.registerSekiroHandler(new ClientTimeHandler());
            }
    }).start(); 

在Android代码里面这样一条api就可以了,然后在ClientTimeHandler类里面写逻辑。

Frida使用就稍稍有点复杂,复杂的点就在于要创建一个java类ClientTimeHandler来处理调用逻辑。

function initSekiro() {
    const SekiroClient = Java.use('com.virjar.sekiro.business.api.SekiroClient');
    const ActionHandler = Java.use('com.virjar.sekiro.business.api.interfaze.ActionHandler');
    const SekiroRequestInitializer = Java.use('com.virjar.sekiro.business.api.interfaze.SekiroRequestInitializer');

    //注册一个ClientTimeHandler类,继承 ActionHandlerconst 
    ClientTimeHandler = Java.registerClass({
        name: 'ClientTimeHandler',
        implements: [ActionHandler],
        methods: {
            action: function () {return 'mobile';},
            handleRequest: function (sekiroRequest, sekiroResponse) {
                const requestJsonData = sekiroRequest.getJsonModel();
                const requestData = JSON.parse(requestJsonData)['requestData'];
                if(!requestData){
                    sekiroResponse.failed(JavaString.$new('requestData 不能为空'));
                }else{
                    try{
                        sekiroResponse.success(callMobile(requestData));
                    }catch(error){
                        sekiroResponse.failed(JavaString.$new(error.stack));
                        throw error;
                    }
                }
            }
        }
    })

    // 注册一个 SekiroRequestDefault类, 继承SekiroRequestInitializerconst 
    SekiroRequestDefault = Java.registerClass({
        name: "SekiroRequestDefault",
        implements: [SekiroRequestInitializer],
        methods: {
            nSekiroRequest: function (sekiroRequest, handlerRegistry) {
                handlerRegistry.registerSekiroHandler(ClientTimeHandler.$new());
            }
        }
    });
    const clientID = guid();
    const group = 'fridaHook_atlasEncrypt';
    const ip = '110.42.246.110';

    // 服务端端口号 默认是 conf/config.properties 里面配置5620, 这里改成了 8989
    const sekiro = SekiroClient.$new(group, clientID, ip, 8989);
    sekiro.setupSekiroRequestInitializer(SekiroRequestDefault.$new());
    sekiro.start();
}

三、验证

http://110.42.246.110:8989/business-demo/groupList 展示当前系统中注册过的所有 group

{"data":["fridaHook_atlasEncrypt"],"ok":true,"status":0}

http://110.42.246.110:8989/business-demo/clientQueue?group=fridaHook_atlasEncrypt 展示特定 group 下,注册过哪些客户端/手机。

{"data":["65c8e8b5-1a67-2036-5b38-769cb670aeb3"],"ok":true,"status":0}

执行一下看看结果

import requests
url = 'http://110.42.246.110:8989/business-demo/invoke'
mobileid = '18913872618'
data = {
    'group': 'fridaHook_atlasEncrypt',
    'action': 'mobile',
    'requestData': mobileid
}
res = requests.post(url,json=data).json()
print(res['data'])

结果很完美
3sCt3iAAMzIwOTAxMjA4AM8HAO7Jtk8ia8xTExAAAACFS7z70nRA3Ppgtdz9Kefb
收工~


> 本文出处 > http://91fans.com.cn/post/fridasekirorpc/#gsc.tab=0
> http://91fans.com.cn/post/smallvideosignthr/#gsc.tab=0