Skeleton
先上一个程序skeleton, 然后逐步分析
import frida, sys
jscode = '''
...................
'''
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
session = frida.get_usb_device().attach('com.package.name')
script = session.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
Android side当然要运行起服务, 默认操作就可以. 如果遇到对抗端口, 进程名等情况相应对抗即可. 服务怎么运行资料比较多这里不具体展开了.
session = frida.get_usb_device().attach('com.package.name')
attach到远端进程
script = session.create_script(jscode)
script.on('message', on_message)
script.load()
三个语句分别新建一段js脚本, 注册消息回调, 正式加载相关脚本. js脚本具体语法比较重要后面会详细介绍.
on_message
即回调函数, 具体为什么这么写不想了解, 暂时打算就按照这个形式, 有需求再查
sys.stdin.read()必须要跑一下, 为的是使程序阻塞不退出. 因为frida设计问题, 远端session似乎没有状态, 如果不阻塞当前进程直接退出...
js脚本与Java世界通信
以如下脚本为例解释一下
Java.perform(function() {
var launcher_activity = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');
var main_activity = Java.use('de.fraunhofer.sit.premiumapp.MainActivity');
var StringClz = Java.use('java.lang.String');
var LicenseStr = StringClz.$new('LICENSEKEYOK');
launcher_activity.getKey.implementation = function (){
var mac = this.getMac();
var mInstance = main_activity.$new();
var macJavaStr = StringClz.$new(mac);
var macByte = macJavaStr.getBytes();
var licenseByte = LicenseStr.getBytes();
send(macByte);
send(licenseByte);
xorResult = mInstance.xor(macByte, licenseByte);
send(xorResult);
var xorResultStr = StringClz.$new(xorResult, "UTF-8");
return xorResultStr;
}
});
Java.perform接收一个函数作为参数, 将在其中执行与Java世界的交互
Java.use通过名字拿到Java类(准确的说是一个Java类在js空间wrap之后的形势)
javaClz.$new(params)形式在Java空间new对象
launcher_activity.getKey.implementation = function() {....} 可以利用这种形式直接覆盖一个Java函数实现hook
从js空间操作Java对象比较费劲, 可以参考这里我的做法(与参考的看雪文章有所差异), 通过反射拿需要的Java类, 实例化出对象, 然后利用其方法操作需要操作的对象, 整个过程不做Java世界到js世界的转换, 都在Java中完成.