一、目标
在 某段子App协议分析(三) 这篇文章里面,我们用frida rpc调用的方式来实现了某段子App的段子爬虫,但是在实际使用的过程中,我们发现有如下两个问题:
- frida不是很稳定,偶尔会崩溃退出
- 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
- 下载nanohttpd-2.3.1.jar 放到Android项目中的libs目录下。
在 /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,就可以正常获取数据了。
三、总结
Xposed RPC比frida RPC稳定,如果线上环境使用的话,还需要增加一个看门狗程序,当某段子App异常退出之后,可以及时的把某段子App再调起来。
关注微信公众号,最新技术干货实时推送