lamda 7.76__tar.gz → 7.85__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. {lamda-7.76 → lamda-7.85}/PKG-INFO +1 -1
  2. {lamda-7.76 → lamda-7.85}/lamda/__init__.py +1 -1
  3. {lamda-7.76 → lamda-7.85}/lamda/client.py +155 -4
  4. {lamda-7.76 → lamda-7.85}/lamda/rpc/application.proto +29 -0
  5. {lamda-7.76 → lamda-7.85}/lamda/rpc/services.proto +6 -0
  6. {lamda-7.76 → lamda-7.85}/lamda.egg-info/PKG-INFO +1 -1
  7. {lamda-7.76 → lamda-7.85}/README.md +0 -0
  8. {lamda-7.76 → lamda-7.85}/lamda/bcast.proto +0 -0
  9. {lamda-7.76 → lamda-7.85}/lamda/const.py +0 -0
  10. {lamda-7.76 → lamda-7.85}/lamda/exceptions.py +0 -0
  11. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/any.proto +0 -0
  12. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/api.proto +0 -0
  13. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/compiler/plugin.proto +0 -0
  14. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/descriptor.proto +0 -0
  15. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/duration.proto +0 -0
  16. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/empty.proto +0 -0
  17. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/field_mask.proto +0 -0
  18. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/source_context.proto +0 -0
  19. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/struct.proto +0 -0
  20. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/timestamp.proto +0 -0
  21. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/type.proto +0 -0
  22. {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/wrappers.proto +0 -0
  23. {lamda-7.76 → lamda-7.85}/lamda/rpc/debug.proto +0 -0
  24. {lamda-7.76 → lamda-7.85}/lamda/rpc/file.proto +0 -0
  25. {lamda-7.76 → lamda-7.85}/lamda/rpc/policy.proto +0 -0
  26. {lamda-7.76 → lamda-7.85}/lamda/rpc/proxy.proto +0 -0
  27. {lamda-7.76 → lamda-7.85}/lamda/rpc/settings.proto +0 -0
  28. {lamda-7.76 → lamda-7.85}/lamda/rpc/shell.proto +0 -0
  29. {lamda-7.76 → lamda-7.85}/lamda/rpc/status.proto +0 -0
  30. {lamda-7.76 → lamda-7.85}/lamda/rpc/storage.proto +0 -0
  31. {lamda-7.76 → lamda-7.85}/lamda/rpc/types.proto +0 -0
  32. {lamda-7.76 → lamda-7.85}/lamda/rpc/uiautomator.proto +0 -0
  33. {lamda-7.76 → lamda-7.85}/lamda/rpc/util.proto +0 -0
  34. {lamda-7.76 → lamda-7.85}/lamda/rpc/wifi.proto +0 -0
  35. {lamda-7.76 → lamda-7.85}/lamda/types.py +0 -0
  36. {lamda-7.76 → lamda-7.85}/lamda.egg-info/SOURCES.txt +0 -0
  37. {lamda-7.76 → lamda-7.85}/lamda.egg-info/dependency_links.txt +0 -0
  38. {lamda-7.76 → lamda-7.85}/lamda.egg-info/not-zip-safe +0 -0
  39. {lamda-7.76 → lamda-7.85}/lamda.egg-info/requires.txt +0 -0
  40. {lamda-7.76 → lamda-7.85}/lamda.egg-info/top_level.txt +0 -0
  41. {lamda-7.76 → lamda-7.85}/setup.cfg +0 -0
  42. {lamda-7.76 → lamda-7.85}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lamda
3
- Version: 7.76
3
+ Version: 7.85
4
4
  Summary: Android reverse engineering & automation framework (Client API)
5
5
  Home-page: https://github.com/firerpa/lamda
6
6
  Author: rev1si0n
@@ -2,4 +2,4 @@
2
2
  #
3
3
  # Distributed under MIT license.
4
4
  # See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5
- __version__ = "7.76"
5
+ __version__ = "7.85"
@@ -57,6 +57,8 @@ logger.addHandler(handler)
57
57
 
58
58
  sys.path.append(joinpath(dirname(__file__)))
59
59
  sys.path.append(joinpath(dirname(__file__), "rpc"))
60
+ # use native resolver to support mDNS
61
+ os.environ["GRPC_DNS_RESOLVER"] = "native"
60
62
 
61
63
  protos, services = grpc.protos_and_services("services.proto")
62
64
  __all__ = [
@@ -179,6 +181,8 @@ def contain(a, b):
179
181
  b.right <= a.right])
180
182
 
181
183
  def equal(a, b):
184
+ if not isinstance(b, protos.Bound):
185
+ return False
182
186
  return all([b.top == a.top,
183
187
  b.left == a.left,
184
188
  b.bottom == a.bottom,
@@ -194,6 +198,8 @@ Corner = protos.Corner
194
198
  Direction = protos.Direction
195
199
  GproxyType = protos.GproxyType
196
200
  GrantType = protos.GrantType
201
+ ScriptRuntime = protos.ScriptRuntime
202
+ DataEncode = protos.DataEncode
197
203
 
198
204
  Group = protos.Group
199
205
  Key = protos.Key
@@ -256,6 +262,9 @@ TouchSequence.appendUp = touchSequenceAppendUp
256
262
  TouchSequence.__getitem__ = touchSequenceIndexer
257
263
  TouchSequence.__iter__ = touchSequenceIter
258
264
 
265
+ HookRpcRequest = protos.HookRpcRequest
266
+ HookRpcResponse = protos.HookRpcResponse
267
+
259
268
  Bound.width = property(width)
260
269
  Bound.height = property(height)
261
270
 
@@ -380,13 +389,14 @@ class GrpcRemoteExceptionInterceptor(ClientInterceptor):
380
389
 
381
390
 
382
391
  class ObjectUiAutomatorOpStub:
383
- def __init__(self, stub, selector):
392
+ def __init__(self, caller, selector):
384
393
  """
385
394
  UiAutomator 子接口,用来模拟出实例的意味
386
395
  """
387
396
  self._selector = selector
388
397
  self.selector = Selector(**selector)
389
- self.stub = stub
398
+ self.stub = caller.stub
399
+ self.caller = caller
390
400
  def __str__(self):
391
401
  selector = ", ".join(["{}={}".format(k, v) \
392
402
  for k, v in self._selector.items()])
@@ -489,6 +499,72 @@ class ObjectUiAutomatorOpStub:
489
499
  req = protos.SelectorOnlyRequest(selector=self.selector)
490
500
  r = self.stub.selectorObjInfoOfAllInstances(req)
491
501
  return r.objects
502
+ def all_instances(self):
503
+ """
504
+ 获取选择器选中的所有元素控件
505
+ """
506
+ return list(self)
507
+ def _new_object(self, **kwargs):
508
+ selector = copy.deepcopy(self._selector)
509
+ selector.update(**kwargs)
510
+ instance = self.caller(**selector)
511
+ return instance
512
+ def text(self, txt):
513
+ return self._new_object(text=txt)
514
+ def resourceId(self, name):
515
+ return self._new_object(resourceId=name)
516
+ def description(self, desc):
517
+ return self._new_object(description=desc)
518
+ def packageName(self, name):
519
+ return self._new_object(packageName=name)
520
+ def className(self, name):
521
+ return self._new_object(className=name)
522
+ def textContains(self, needle):
523
+ return self._new_object(textContains=needle)
524
+ def descriptionContains(self, needle):
525
+ return self._new_object(descriptionContains=needle)
526
+ def textStartsWith(self, needle):
527
+ return self._new_object(textStartsWith=needle)
528
+ def descriptionStartsWith(self, needle):
529
+ return self._new_object(descriptionStartsWith=needle)
530
+ def textMatches(self, match):
531
+ return self._new_object(textMatches=match)
532
+ def descriptionMatches(self, match):
533
+ return self._new_object(descriptionMatches=match)
534
+ def resourceIdMatches(self, match):
535
+ return self._new_object(resourceIdMatches=match)
536
+ def packageNameMatches(self, match):
537
+ return self._new_object(packageNameMatches=match)
538
+ def classNameMatches(self, match):
539
+ return self._new_object(classNameMatches=match)
540
+ def checkable(self, value):
541
+ return self._new_object(checkable=value)
542
+ def clickable(self, value):
543
+ return self._new_object(clickable=value)
544
+ def focusable(self, value):
545
+ return self._new_object(focusable=value)
546
+ def scrollable(self, value):
547
+ return self._new_object(scrollable=value)
548
+ def longClickable(self, value):
549
+ return self._new_object(longClickable=value)
550
+ def enabled(self, value):
551
+ return self._new_object(enabled=value)
552
+ def checked(self, value):
553
+ return self._new_object(checked=value)
554
+ def focused(self, value):
555
+ return self._new_object(focused=value)
556
+ def selected(self, value):
557
+ return self._new_object(selected=value)
558
+ def index(self, idx):
559
+ return self._new_object(index=idx)
560
+ def instance(self, idx):
561
+ return self._new_object(instance=idx)
562
+ def __iter__(self):
563
+ """
564
+ 遍历所有符合选择器条件的元素实例
565
+ """
566
+ yield from [self.instance(i) for i in \
567
+ range(self.count())]
492
568
  def count(self):
493
569
  """
494
570
  获取选择器选中控件的数量
@@ -957,7 +1033,25 @@ class UiAutomatorStub(BaseServiceStub):
957
1033
  r = self.stub.waitForIdle(protos.Integer(value=timeout))
958
1034
  return r.value
959
1035
  def __call__(self, **kwargs):
960
- return ObjectUiAutomatorOpStub(self.stub, kwargs)
1036
+ return ObjectUiAutomatorOpStub(self, kwargs)
1037
+
1038
+
1039
+ class AppScriptRpcInterface(object):
1040
+ def __init__(self, stub, application,
1041
+ name):
1042
+ self.application = application
1043
+ self.stub = stub
1044
+ self.name = name
1045
+ def __call__(self, *args):
1046
+ call_args = dict()
1047
+ call_args["method"] = self.name
1048
+ call_args["args"] = args
1049
+ req = HookRpcRequest()
1050
+ req.package = self.application.applicationId
1051
+ req.callinfo = json.dumps(call_args)
1052
+ result = self.stub.callScript(req)
1053
+ r = json.loads(result.callresult)
1054
+ return r
961
1055
 
962
1056
 
963
1057
  class ApplicationOpStub:
@@ -1114,6 +1208,51 @@ class ApplicationOpStub:
1114
1208
  req.user = self.user
1115
1209
  r = self.stub.isInstalled(req)
1116
1210
  return r.value
1211
+ def attach_script(self, script, runtime=ScriptRuntime.RUNTIME_QJS,
1212
+ emit="",
1213
+ encode=DataEncode.DATA_ENCODE_NONE,
1214
+ standup=5):
1215
+ """
1216
+ 向应用注入持久化 Hook 脚本
1217
+ """
1218
+ s = isinstance(script, str)
1219
+ script = script.encode() if s else script
1220
+ req = protos.HookRequest()
1221
+ req.package = self.applicationId
1222
+ req.script = script
1223
+ req.runtime = runtime
1224
+ req.standup = standup
1225
+ req.destination = emit
1226
+ req.encode = encode
1227
+ r = self.stub.attachScript(req)
1228
+ return r.value
1229
+ def detach_script(self):
1230
+ """
1231
+ 移除注入应用的 Hook 脚本
1232
+ """
1233
+ req = protos.String(value=self.applicationId)
1234
+ r = self.stub.detachScript(req)
1235
+ return r.value
1236
+ def is_attached_script(self):
1237
+ """
1238
+ 检查使用在此应用注入了 Hook 脚本
1239
+ """
1240
+ req = protos.String(value=self.applicationId)
1241
+ r = self.stub.isScriptAttached(req)
1242
+ return r.value
1243
+ def is_script_alive(self):
1244
+ """
1245
+ 检查应用中的 Hook 脚本是否正常
1246
+ """
1247
+ req = protos.String(value=self.applicationId)
1248
+ r = self.stub.isScriptAlive(req)
1249
+ return r.value
1250
+ def __getattr__(self, name):
1251
+ """
1252
+ 调用注入应用 Hook 脚本的导出方法
1253
+ """
1254
+ return AppScriptRpcInterface(self.stub, self,
1255
+ name)
1117
1256
 
1118
1257
 
1119
1258
  class ApplicationStub(BaseServiceStub):
@@ -1974,6 +2113,14 @@ class Device(object):
1974
2113
  session=None):
1975
2114
  self.certificate = certificate
1976
2115
  self.server = "{0}:{1}".format(host, port)
2116
+ policy = dict()
2117
+ policy["maxAttempts"] = 5
2118
+ policy["retryableStatusCodes"] = ["UNAVAILABLE"]
2119
+ policy["backoffMultiplier"] = 2
2120
+ policy["initialBackoff"] = "0.5s"
2121
+ policy["maxBackoff"] = "15s"
2122
+ config = json.dumps(dict(methodConfig=[{"name": [{}],
2123
+ "retryPolicy": policy,}]))
1977
2124
  if certificate is not None:
1978
2125
  with open(certificate, "rb") as fd:
1979
2126
  key, crt, ca = self._parse_certdata(fd.read())
@@ -1983,10 +2130,14 @@ class Device(object):
1983
2130
  self._chan = grpc.secure_channel(self.server, creds,
1984
2131
  options=(("grpc.ssl_target_name_override",
1985
2132
  self._parse_cname(crt)),
2133
+ ("grpc.service_config", config),
1986
2134
  ("grpc.enable_http_proxy",
1987
2135
  0)))
1988
2136
  else:
1989
- self._chan = grpc.insecure_channel(self.server)
2137
+ self._chan = grpc.insecure_channel(self.server,
2138
+ options=(("grpc.service_config", config),
2139
+ ("grpc.enable_http_proxy", 0))
2140
+ )
1990
2141
  session = session or uuid.uuid4().hex
1991
2142
  interceptors = [ClientSessionMetadataInterceptor(session),
1992
2143
  GrpcRemoteExceptionInterceptor(),
@@ -13,6 +13,16 @@ enum GrantType {
13
13
  GRANT_IGNORE = 2;
14
14
  }
15
15
 
16
+ enum DataEncode {
17
+ DATA_ENCODE_NONE = 0;
18
+ DATA_ENCODE_ZLIB = 1;
19
+ }
20
+
21
+ enum ScriptRuntime {
22
+ RUNTIME_QJS = 0;
23
+ RUNTIME_V8 = 1;
24
+ }
25
+
16
26
  message ApplicationRequest {
17
27
  string name = 1;
18
28
  string permission = 2;
@@ -83,3 +93,22 @@ message ApplicationProcesses {
83
93
  message ApplicationPkgNames {
84
94
  repeated string names = 1;
85
95
  }
96
+
97
+ message HookRequest {
98
+ string package = 1;
99
+ bytes script = 2;
100
+ ScriptRuntime runtime = 3;
101
+ string destination = 4;
102
+ DataEncode encode = 5;
103
+ uint32 standup = 6;
104
+ }
105
+
106
+ message HookRpcRequest {
107
+ string package = 1;
108
+ string callinfo = 2;
109
+ }
110
+
111
+ message HookRpcResponse {
112
+ string package = 1;
113
+ string callresult = 2;
114
+ }
@@ -50,6 +50,12 @@ service Application {
50
50
  rpc addToDozeModeWhiteList(ApplicationRequest) returns (Boolean) {}
51
51
  rpc removeFromDozeModeWhiteList(ApplicationRequest) returns (Boolean) {}
52
52
  rpc getIdentifierByLabel(String) returns (String) {}
53
+
54
+ rpc callScript(HookRpcRequest) returns (HookRpcResponse) {}
55
+ rpc isScriptAlive(String) returns (Boolean) {}
56
+ rpc isScriptAttached(String) returns (Boolean) {}
57
+ rpc attachScript(HookRequest) returns (Boolean) {}
58
+ rpc detachScript(String) returns (Boolean) {}
53
59
  }
54
60
 
55
61
  service Debug {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lamda
3
- Version: 7.76
3
+ Version: 7.85
4
4
  Summary: Android reverse engineering & automation framework (Client API)
5
5
  Home-page: https://github.com/firerpa/lamda
6
6
  Author: rev1si0n
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes