一、目标

一、目标

某段子App协议分析(三) 这篇文章里面,我们用frida rpc调用的方式来实现了某段子App的段子爬虫,但是在实际使用的过程中,我们发现有如下两个问题:

  1. frida不是很稳定,偶尔会崩溃退出
  2. flask服务是运行在pc上,所以还需要一台pc一直开机

所以我们最好能实现在Android手机中运行一个稳定的web服务,然后把 手机的端口通过路由器映射出去,这样就可以在任意环境下来调用签名服务了。

二、分析

Xposed模块的开发方法可以参照 最新的Xposed模块编写教程2020,在xposed中调用App中的静态函数使用 XposedHelpers.callStaticMethod:

public static Object callMethod(Object obj, String methodName, Object... args)

public static Object callMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object... args)

public static Object callStaticMethod(Class<?> clazz, String methodName, Object... args)

public static Object callStaticMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes, Object... args)

我们以调用 com.izuiyou.network.NetCrypto.getProtocolKey 为例:

Class<?> clazzZy = null;
try {
        // 首先获取 com.izuiyou.network.NetCrypto类
        clazzZy = loadPackageParam.classLoader.loadClass("com.izuiyou.network.NetCrypto");
        log("load class:" + clazzZy);
} catch (Exception e) {
        log("load class err:" + Log.getStackTraceString(e));
        return newFixedLengthResponse("load class is null");
}

// 然后调用 getProtocolKey
String rc = (String) XposedHelpers.callStaticMethod(clazzZy, "getProtocolKey");

调用函数完成之后,我们需要启动一个http服务来把数据传输出来,这里使用 NanoHTTPD

  1. 下载nanohttpd-2.3.1.jar 放到Android项目中的libs目录下。
  2. /app/build.gradle 文件的dependencies段增加

      compileOnly 'org.nanohttpd:nanohttpd:2.3.1’

1、2步也可以试试合并成直接在 /app/build.gradle 文件的dependencies段增加

  implementation'org.nanohttpd:nanohttpd:2.3.1'
 <uses-permission android:name="android.permission.INTERNET"/>

然后我们创建一个myHttpServer类来启动http服务

import java.io.IOException;
import fi.iki.elonen.NanoHTTPD;

class myHttpServer extends NanoHTTPD {

public myHttpServer() throws IOException {
        // 端口是8088,也就是说要通过http://127.0.0.1:8088来访当问
        super(8888);
        start(NanoHTTPD.SOCKET_READ_TIMEOUT, true);
        log("---fenfei Server---");
}

@Override
public Response serve(IHTTPSession session) {
        // log("serve");
        //这个就是之前分析,重写父类的一个参数的方法,
        //这里边已经把所有的解析操作已经在这里执行了
        return super.serve(session);
}

@Override
public Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> parms, Map<String, String> files) {

        // 获取类
        Class<?> clazzZy = null;
        try {
                clazzZy = loadPackageParam.classLoader.loadClass("com.izuiyou.network.NetCrypto");
                log("load class:" + clazzZy);
        } catch (Exception e) {
                log("load class err:" + Log.getStackTraceString(e));
                return newFixedLengthResponse("load class is null");
        }

        // 判断是否是getkey请求
        if (StringUtils.containsIgnoreCase(uri, "getkey")) {//判断uri是否正确
        return getKey(clazzZy);
        }

        // 判断是否是setkey请求,并且取出post过来的数据
        if (StringUtils.containsIgnoreCase(uri, "setkey")) {//判断uri是否正确
                String postData = files.get("postData");
                if (!StringUtils.isEmpty(postData)) {//判断post过来的数据是否正确
                        return setkey(clazzZy,postData);
                }else{
                        return newFixedLengthResponse("postData is null");
                }
        }
}

public Response setkey(Class<?> clazzUse,String strKey){
        XposedHelpers.callStaticMethod(clazzUse, "setProtocolKey",strKey);
        log("setkey = "+strKey);
        return newFixedLengthResponse("set key ok");
}

}

// 创建httpServer实例
new myHttpServer();

把上次从frida RPC获取签名的地址 http://127.0.0.1:5000 改成新的xposed RPC的地址 http://192.168.2.102:8888,就可以正常获取数据了。

rc
1:bashrc

三、总结

Xposed RPC比frida RPC稳定,如果线上环境使用的话,还需要增加一个看门狗程序,当某段子App异常退出之后,可以及时的把某段子App再调起来。

100

关注微信公众号,最新技术干货实时推送

100