Step-by-step guide to set up a Frida + Sekiro RPC framework

1. Viewing an Example of Encrypted Phone Number

img.png

This example is from a certain video app, where the “mobile” field appears to be encrypted.

I. Attempting String Matching

Perhaps phone numbers all start with “1xx”, or maybe this encrypted string has a distinct starting pattern. After observing, we noticed that it most likely starts with “3sCt”. This encryption algorithm is most likely performed at the Native layer. Therefore, our initial approach was to hook into GetStringUTFChars and NewStringUTF inside libart. Unfortunately, this yielded no results.

II. Attempting Base64

The string starting with “3sCt” resembles Base64-encoded data. We attempted to decode it using Base64 and found that it could be decoded. Without hesitation, we tried hooking android.util.Base64. Still, no luck. It’s quite perplexing; the only explanation could be that the app isn’t using standard Base64 library functions but has implemented a custom Base64 algorithm. After all, Base64 algorithms are abundant and can be implemented as needed.

III. Searching for the Keyword “mobile”

At this point, let’s try searching for the string. img.png There aren’t many results, but these two are highly suspicious. Let’s analyze the m434739f function. img_1.png This app is heavily obfuscated, yet it still contains the unmistakable function atlasEncrypt, which definitely needs to be hooked. m60341e is also noteworthy; this class appears to be a Base64 algorithm, which explains why hooking android.util.Base64 didn’t yield any results.

IV. Writing a Demo to Verify

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;
}

Finally, we found that we can obtain the expected results.

2. Developing a Sekiro Client with Frida

Sekiro is an incredibly powerful library, essentially ready to use out of the box.

// Using Sekiro in a regular Android application
new SekiroClient("test-android", UUID.randomUUID().toString())
    .setupSekiroRequestInitializer(new SekiroRequestInitializer(){
        @Override
        public void onSekiroRequest(SekiroRequest sekiroRequest, HandlerRegistry handlerRegistry) {
            handlerRegistry.registerSekiroHandler(new ClientTimeHandler());
        }
    }).start();

In Android code, this single API call is all that’s needed, and then the logic can be written in the ClientTimeHandler class.

Using Frida is a bit more complex, as it involves creating a Java class, ClientTimeHandler, to handle the invocation logic.```javascript 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<br>
```json
{"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}

Execute and see the results.

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'])

The results are perfect.
3sCt3iAAMzIwOTAxMjA4AM8HAO7Jtk8ia8xTExAAAACFS7z70nRA3Ppgtdz9Kefb
Job done~


> This article is from the following source: > http://91fans.com.cn/post/fridasekirorpc/#gsc.tab=0
> http://91fans.com.cn/post/smallvideosignthr/#gsc.tab=0