diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a3b07bf..90667e1 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,9 @@ +7.80 +* 优化实时投屏流畅度 +* 新增持久化 Hook 脚本支持 +* 新增 Hook RPC 支持 +* 新增数据上报支持 + 7.76 * 修复工具版本依赖 * 修复 Python 版本匹配问题 diff --git a/lamda/__init__.py b/lamda/__init__.py index ca8de97..fc3543b 100644 --- a/lamda/__init__.py +++ b/lamda/__init__.py @@ -2,4 +2,4 @@ # # Distributed under MIT license. # See file LICENSE for detail or copy at https://opensource.org/licenses/MIT -__version__ = "7.76" +__version__ = "7.80" diff --git a/lamda/client.py b/lamda/client.py index c503e20..3bbe9b5 100644 --- a/lamda/client.py +++ b/lamda/client.py @@ -256,6 +256,11 @@ def corner(b, position): TouchSequence.__getitem__ = touchSequenceIndexer TouchSequence.__iter__ = touchSequenceIter +DataEncode = protos.DataEncode +ScriptRuntime = protos.ScriptRuntime +HookRpcRequest = protos.HookRpcRequest +HookRpcResponse = protos.HookRpcResponse + Bound.width = property(width) Bound.height = property(height) @@ -960,6 +965,24 @@ def __call__(self, **kwargs): return ObjectUiAutomatorOpStub(self.stub, kwargs) +class AppScriptRpcInterface(object): + def __init__(self, stub, application, + name): + self.application = application + self.stub = stub + self.name = name + def __call__(self, *args): + call_args = dict() + call_args["method"] = self.name + call_args["args"] = args + req = HookRpcRequest() + req.package = self.application.applicationId + req.callinfo = json.dumps(call_args) + result = self.stub.callScript(req) + r = json.loads(result.callresult) + return r + + class ApplicationOpStub: def __init__(self, stub, applicationId, user=0): """ @@ -1114,6 +1137,51 @@ def is_installed(self): req.user = self.user r = self.stub.isInstalled(req) return r.value + def attach_script(self, script, runtime=ScriptRuntime.RUNTIME_QJS, + emit="", + encode=DataEncode.DATA_ENCODE_NONE, + standup=5): + """ + 向应用注入持久化 Hook 脚本 + """ + s = isinstance(script, str) + script = script.encode() if s else script + req = protos.HookRequest() + req.package = self.applicationId + req.script = script + req.runtime = runtime + req.standup = standup + req.destination = emit + req.encode = encode + r = self.stub.attachScript(req) + return r.value + def detach_script(self): + """ + 移除注入应用的 Hook 脚本 + """ + req = protos.String(value=self.applicationId) + r = self.stub.detachScript(req) + return r.value + def is_attached_script(self): + """ + 检查使用在此应用注入了 Hook 脚本 + """ + req = protos.String(value=self.applicationId) + r = self.stub.isScriptAttached(req) + return r.value + def is_script_alive(self): + """ + 检查应用中的 Hook 脚本是否正常 + """ + req = protos.String(value=self.applicationId) + r = self.stub.isScriptAlive(req) + return r.value + def __getattr__(self, name): + """ + 调用注入应用 Hook 脚本的导出方法 + """ + return AppScriptRpcInterface(self.stub, self, + name) class ApplicationStub(BaseServiceStub): diff --git a/lamda/rpc/application.proto b/lamda/rpc/application.proto index 3fdedc3..168393a 100644 --- a/lamda/rpc/application.proto +++ b/lamda/rpc/application.proto @@ -13,6 +13,16 @@ enum GrantType { GRANT_IGNORE = 2; } +enum DataEncode { + DATA_ENCODE_NONE = 0; + DATA_ENCODE_ZLIB = 1; +} + +enum ScriptRuntime { + RUNTIME_QJS = 0; + RUNTIME_V8 = 1; +} + message ApplicationRequest { string name = 1; string permission = 2; @@ -83,3 +93,22 @@ message ApplicationProcesses { message ApplicationPkgNames { repeated string names = 1; } + +message HookRequest { + string package = 1; + bytes script = 2; + ScriptRuntime runtime = 3; + string destination = 4; + DataEncode encode = 5; + uint32 standup = 6; +} + +message HookRpcRequest { + string package = 1; + string callinfo = 2; +} + +message HookRpcResponse { + string package = 1; + string callresult = 2; +} \ No newline at end of file diff --git a/lamda/rpc/services.proto b/lamda/rpc/services.proto index 0f5bc61..d534ed3 100644 --- a/lamda/rpc/services.proto +++ b/lamda/rpc/services.proto @@ -50,6 +50,12 @@ service Application { rpc addToDozeModeWhiteList(ApplicationRequest) returns (Boolean) {} rpc removeFromDozeModeWhiteList(ApplicationRequest) returns (Boolean) {} rpc getIdentifierByLabel(String) returns (String) {} + + rpc callScript(HookRpcRequest) returns (HookRpcResponse) {} + rpc isScriptAlive(String) returns (Boolean) {} + rpc isScriptAttached(String) returns (Boolean) {} + rpc attachScript(HookRequest) returns (Boolean) {} + rpc detachScript(String) returns (Boolean) {} } service Debug { diff --git a/tools/fridarpc.py b/tools/fridarpc.py index 9b0c548..97791a4 100755 --- a/tools/fridarpc.py +++ b/tools/fridarpc.py @@ -17,7 +17,7 @@ help="service port") parser.add_argument("-f", type=argparse.FileType("r"), dest="script", help="frida script", required=True) - parser.add_argument("-delay", type=int, dest="delay", default=1.5, + parser.add_argument("-delay", type=int, dest="delay", default=5, help="attach after delay") parser.add_argument("-cert", type=str, default=cert, help="ssl cert") @@ -26,17 +26,8 @@ d = Device(args.device, port=args.port, certificate=args.cert) - pid = d.frida.spawn(args.package) - d.frida.resume(pid) - - time.sleep(args.delay) - session = d.frida.attach(pid) - session.on("detached", print) - - sc = session.create_script(args.script.read()) - - sc.on("destroyed", print) - sc.on("message", print) - sc.load() - sc.eternalize() + app = d.application(args.package) + app.detach_script() + app.attach_script(args.script.read(), + standup=args.delay) exit (0) \ No newline at end of file