Skip to content

Commit 4acec6c

Browse files
committed
8.0 auto-commit
1 parent 744e8ef commit 4acec6c

File tree

12 files changed

+71
-66
lines changed

12 files changed

+71
-66
lines changed

CHANGELOG.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
8.0
2+
* 接口全面支持多开应用
3+
* 远程桌面支持共享剪切板
4+
* 新增部分机型无法打开APP的修复配置
5+
* 新增 Yaml frida 脚本持久化
6+
* 修复 6.0 等低版本系统兼容性
7+
* 修复高版本系统自动化相关功能异常
8+
* 移除/重命名部分方法
9+
* 更新底层实现
10+
111
7.90
212
* 持久化脚本支持 spawn 模式
313
* 支持持久化脚本输出日志

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<img src="https://img.shields.io/github/v/release/rev1si0n/lamda" />
1313
</p>
1414

15-
<p align="center"><a href="https://device-farm.com/doc/index.html">使用文档</a> | <a href="https://t.me/lamda_dev">TELEGRAM</a> | <a href="https://lamda.run/join/qq">QQ 群组</a> | <a href="https://github.com/rev1si0n/lamda/blob/HEAD/CHANGELOG.txt">更新历史</a></p>
15+
<p align="center"><a href="https://device-farm.com/doc/index.html">使用文档</a> | <a href="https://t.me/lamda_dev">TELEGRAM</a> | <a href="https://lamda.run/join/qq">QQ 群组</a> | <a href="https://device-farm.com/doc/版本历史.html">更新历史</a></p>
1616

1717
智能机的崛起,传统网页端的普及度也开始显著减弱,数据与应用正加速向移动端转移。越来越多的人选择通过智能手机和平板等移动设备来获取信息和服务。随着移动设备的普及,用户享受到更便捷访问体验,传统的网页内容模式面临重新审视。与此同时,数据采集的技术也亟需适应这一趋势。过去,许多数据采集工具专注于网页内容,在移动端环境中,尤其是在移动端封闭的黑盒中,现今的常规采集技术也面临着新的挑战。LAMDA 的诞生,为这一切创造了可能。
1818

lamda/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
#
33
# Distributed under MIT license.
44
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5-
__version__ = "7.90"
5+
__version__ = "8.0"

lamda/client.py

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -302,19 +302,13 @@ def ocr(self, image):
302302

303303

304304
class BaseCryptor(object):
305-
def __str__(self):
306-
return "{}".format(self.__class__.__name__)
307-
__repr__ = __str__
308305
def encrypt(self, data):
309306
return data
310307
def decrypt(self, data):
311308
return data
312309

313310

314311
class BaseServiceStub(object):
315-
def __str__(self):
316-
return "{}".format(self.__class__.__name__)
317-
__repr__ = __str__
318312
def __init__(self, stub):
319313
self.stub = stub
320314

@@ -467,8 +461,6 @@ def click_exists(self, corner=Corner.COR_CENTER):
467461
corner=corner)
468462
r = self.stub.selectorClickExists(req)
469463
return r.value
470-
def click_exist(self, *args, **kwargs):
471-
return self.click_exists(*args, **kwargs)
472464
def long_click(self, corner=Corner.COR_CENTER):
473465
"""
474466
长按选择器选中的控件
@@ -484,26 +476,12 @@ def exists(self):
484476
req = protos.SelectorOnlyRequest(selector=self.selector)
485477
r = self.stub.selectorExists(req)
486478
return r.value
487-
def exist(self, *args, **kwargs):
488-
return self.exists(*args, **kwargs)
489479
def info(self):
490480
"""
491481
获取选择器选中控件的信息
492482
"""
493483
req = protos.SelectorOnlyRequest(selector=self.selector)
494484
return self.stub.selectorObjInfo(req)
495-
def info_of_all_instances(self):
496-
"""
497-
获取选择器选中的所有控件的信息
498-
"""
499-
req = protos.SelectorOnlyRequest(selector=self.selector)
500-
r = self.stub.selectorObjInfoOfAllInstances(req)
501-
return r.objects
502-
def all_instances(self):
503-
"""
504-
获取选择器选中的所有元素控件
505-
"""
506-
return list(self)
507485
def _new_object(self, **kwargs):
508486
selector = copy.deepcopy(self._selector)
509487
selector.update(**kwargs)
@@ -559,6 +537,11 @@ def index(self, idx):
559537
return self._new_object(index=idx)
560538
def instance(self, idx):
561539
return self._new_object(instance=idx)
540+
def get(self, idx):
541+
"""
542+
获取匹配的第 N 个索引的元素
543+
"""
544+
return self.instance(idx)
562545
def __iter__(self):
563546
"""
564547
遍历所有符合选择器条件的元素实例
@@ -1042,16 +1025,21 @@ def __init__(self, stub, application,
10421025
self.application = application
10431026
self.stub = stub
10441027
self.name = name
1028+
def __str__(self):
1029+
return "{}:Script:{}".format(self.application,
1030+
self.name)
1031+
__repr__ = __str__
10451032
def __call__(self, *args):
10461033
call_args = dict()
10471034
call_args["method"] = self.name
10481035
call_args["args"] = args
10491036
req = HookRpcRequest()
10501037
req.package = self.application.applicationId
1038+
req.user = self.application.user
10511039
req.callinfo = json.dumps(call_args)
10521040
result = self.stub.callScript(req)
1053-
r = json.loads(result.callresult)
1054-
return r
1041+
data = json.loads(result.callresult)
1042+
return data
10551043

10561044

10571045
class ApplicationOpStub:
@@ -1063,8 +1051,8 @@ def __init__(self, stub, applicationId, user=0):
10631051
self.applicationId = applicationId
10641052
self.stub = stub
10651053
def __str__(self):
1066-
return "{}:{}".format(self.stub.__class__.__name__,
1067-
self.applicationId)
1054+
return "Application:{}@{}".format(self.applicationId,
1055+
self.user)
10681056
__repr__ = __str__
10691057
def is_foreground(self):
10701058
"""
@@ -1118,24 +1106,22 @@ def is_permission_granted(self, permission):
11181106
req.user = self.user
11191107
r = self.stub.isPermissionGranted(req)
11201108
return r.value
1121-
def delete_cache(self):
1109+
def clear_cache(self):
11221110
"""
11231111
清空应用的缓存数据(非数据仅缓存)
11241112
"""
11251113
req = protos.ApplicationRequest(name=self.applicationId)
11261114
req.user = self.user
11271115
r = self.stub.deleteApplicationCache(req)
11281116
return r.value
1129-
def reset_data(self):
1117+
def reset(self):
11301118
"""
11311119
清空应用的所有数据
11321120
"""
11331121
req = protos.ApplicationRequest(name=self.applicationId)
11341122
req.user = self.user
11351123
r = self.stub.resetApplicationData(req)
11361124
return r.value
1137-
def reset(self):
1138-
return self.reset_data()
11391125
def start(self):
11401126
"""
11411127
启动应用
@@ -1226,27 +1212,34 @@ def attach_script(self, script, runtime=ScriptRuntime.RUNTIME_QJS,
12261212
req.spawn = spawn
12271213
req.destination = emit
12281214
req.encode = encode
1215+
req.user = self.user
12291216
r = self.stub.attachScript(req)
12301217
return r.value
12311218
def detach_script(self):
12321219
"""
12331220
移除注入应用的 Hook 脚本
12341221
"""
1235-
req = protos.String(value=self.applicationId)
1222+
req = protos.HookRequest()
1223+
req.package = self.applicationId
1224+
req.user = self.user
12361225
r = self.stub.detachScript(req)
12371226
return r.value
12381227
def is_attached_script(self):
12391228
"""
12401229
检查使用在此应用注入了 Hook 脚本
12411230
"""
1242-
req = protos.String(value=self.applicationId)
1231+
req = protos.HookRequest()
1232+
req.package = self.applicationId
1233+
req.user = self.user
12431234
r = self.stub.isScriptAttached(req)
12441235
return r.value
12451236
def is_script_alive(self):
12461237
"""
12471238
检查应用中的 Hook 脚本是否正常
12481239
"""
1249-
req = protos.String(value=self.applicationId)
1240+
req = protos.HookRequest()
1241+
req.package = self.applicationId
1242+
req.user = self.user
12501243
r = self.stub.isScriptAlive(req)
12511244
return r.value
12521245
def __getattr__(self, name):
@@ -1263,7 +1256,7 @@ def current_application(self):
12631256
获取当前处于前台的应用的信息
12641257
"""
12651258
top = self.stub.currentApplication(protos.Empty())
1266-
app = self.__call__(top.packageName)
1259+
app = self.__call__(top.packageName, user=top.user)
12671260
app.activity = top.activity
12681261
return app
12691262
def get_application_by_name(self, name, user=0):
@@ -1305,17 +1298,14 @@ def install_local_file(self, fpath):
13051298
安装设备上的 apk 文件(注意此路径为设备上的 apk 路径)
13061299
"""
13071300
req = protos.ApplicationRequest(path=fpath)
1301+
req.user = self.user
13081302
r = self.stub.installFromLocalFile(req)
13091303
return r
13101304
def __call__(self, applicationId, user=0):
13111305
return ApplicationOpStub(self.stub, applicationId, user)
13121306

13131307

13141308
class StorageOpStub:
1315-
def __str__(self):
1316-
return "{}:{}".format(self.stub.__class__.__name__,
1317-
self.name)
1318-
__repr__ = __str__
13191309
# 用于容器值序列化的方法
13201310
def _decrypt(self, data):
13211311
return self.cryptor.decrypt(data)
@@ -1734,20 +1724,20 @@ def stop_gproxy(self):
17341724

17351725

17361726
class SelinuxPolicyStub(BaseServiceStub):
1737-
def policy_set_allow(self, source, target, tclass, action):
1727+
def allow(self, source, target, tclass, action):
17381728
"""
17391729
selinux allow
17401730
"""
17411731
req = protos.SelinuxPolicyRequest(source=source, target=target,
1742-
tclass=tclass, action=action)
1732+
tclass=tclass, action=action)
17431733
r = self.stub.policySetAllow(req)
17441734
return r.value
1745-
def policy_set_disallow(self, source, target, tclass, action):
1735+
def disallow(self, source, target, tclass, action):
17461736
"""
17471737
selinux disallow
17481738
"""
17491739
req = protos.SelinuxPolicyRequest(source=source, target=target,
1750-
tclass=tclass, action=action)
1740+
tclass=tclass, action=action)
17511741
r = self.stub.policySetDisallow(req)
17521742
return r.value
17531743
def get_enforce(self):
@@ -1763,27 +1753,27 @@ def set_enforce(self, enforced=True):
17631753
req = protos.Boolean(value=enforced)
17641754
r = self.stub.setEnforce(req)
17651755
return r.value
1766-
def is_enabled(self):
1756+
def enabled(self):
17671757
"""
17681758
获取设备上的 selinux 是否已经启用
17691759
"""
17701760
r = self.stub.isEnabled(protos.Empty())
17711761
return r.value
1772-
def policy_set_enforce(self, name):
1762+
def enforce(self, name):
17731763
"""
17741764
设置一个域为 enforce
17751765
"""
17761766
req = protos.String(value=name)
17771767
r = self.stub.policySetEnforce(req)
17781768
return r.value
1779-
def policy_set_permissive(self, name):
1769+
def permissive(self, name):
17801770
"""
17811771
设置一个域为 permissive
17821772
"""
17831773
req = protos.String(value=name)
17841774
r = self.stub.policySetPermissive(req)
17851775
return r.value
1786-
def policy_create_domain(self, name):
1776+
def create_domain(self, name):
17871777
"""
17881778
新建一个 selinux 域
17891779
"""
@@ -2022,11 +2012,6 @@ def exists(self):
20222012
OCR - 检查元素是否存在
20232013
"""
20242014
return bool(self.find_target_item())
2025-
def exist(self):
2026-
"""
2027-
OCR - 检查元素是否存在
2028-
"""
2029-
return self.exists()
20302015
def click(self):
20312016
"""
20322017
OCR - 点击元素(不存在则报错)
@@ -2037,11 +2022,6 @@ def click_exists(self):
20372022
OCR - 点击元素(不存在将不会产生异常)
20382023
"""
20392024
return self.find_cb(self._click, False)
2040-
def click_exist(self):
2041-
"""
2042-
OCR - 点击元素(不存在将不会产生异常)
2043-
"""
2044-
return self.click_exists()
20452025
def screenshot(self, quality=100):
20462026
"""
20472027
OCR - 对元素进行截图

lamda/exceptions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class InvalidAndroidPackage(Exception):
2222
""" Exception """
2323
class InvalidArgumentError(Exception):
2424
""" Exception """
25+
class InvalidOperationError(Exception):
26+
""" Exception """
2527
class InvalidRootCertificate(Exception):
2628
""" Exception """
2729
class MethodNotFoundException(Exception):

lamda/rpc/application.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ message ApplicationActivityInfo {
5454
int64 flags = 7;
5555
bool debug = 8;
5656
string data = 9;
57+
uint32 user = 10;
5758
}
5859

5960
message ApplicationActivityInfoList {
@@ -77,6 +78,7 @@ message ApplicationInfo {
7778
uint32 versionCode = 10;
7879
string versionName = 11;
7980
string activity = 12;
81+
uint32 user = 13;
8082
}
8183

8284
message ApplicationProcess {
@@ -102,11 +104,13 @@ message HookRequest {
102104
DataEncode encode = 5;
103105
uint32 standup = 6;
104106
bool spawn = 7;
107+
uint32 user = 8;
105108
}
106109

107110
message HookRpcRequest {
108111
string package = 1;
109112
string callinfo = 2;
113+
uint32 user = 3;
110114
}
111115

112116
message HookRpcResponse {

lamda/rpc/services.proto

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ service Application {
5252
rpc getIdentifierByLabel(String) returns (String) {}
5353

5454
rpc callScript(HookRpcRequest) returns (HookRpcResponse) {}
55-
rpc isScriptAlive(String) returns (Boolean) {}
56-
rpc isScriptAttached(String) returns (Boolean) {}
55+
rpc isScriptAlive(HookRequest) returns (Boolean) {}
56+
rpc isScriptAttached(HookRequest) returns (Boolean) {}
5757
rpc attachScript(HookRequest) returns (Boolean) {}
58-
rpc detachScript(String) returns (Boolean) {}
58+
rpc detachScript(HookRequest) returns (Boolean) {}
5959
}
6060

6161
service Debug {

properties.local.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ enhanced-stealth-mode=false
4747
# the remote desktop, please set the following configuration:
4848
touch.backend=system
4949

50+
# If the application fails to open after the service is started,
51+
# please set this option to true.
52+
dirtyfix_open_app=false
53+
5054
# ---------- OpenVPN Configuration ----------
5155
# Do not manually write the following configuration. You should use
5256
# our accompanying OpenVPN server setup solution to set it up and

scripts/disable_flag_secure.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This script is used to disable the android FLAG_SECURE flag.
2+
# Replace YOUR_APP_ID with the ID (eg. com.android.settings) of your target application.
3+
enable: true
4+
application: "YOUR_APP_ID"
5+
version: "N/A"
6+
script: !!binary "SmF2YS5wZXJmb3JtKGZ1bmN0aW9uICgpIHsKICAgICAgICB2YXIgRkxBR19TRUNVUkUgPSAweDIwMDA7CiAgICAgICAgdmFyIFdpbmRvdyA9IEphdmEudXNlKCJhbmRyb2lkLnZpZXcuV2luZG93Iik7CiAgICAgICAgdmFyIHNldEZsYWdzID0gV2luZG93LnNldEZsYWdzOwoKICAgICAgICBzZXRGbGFncy5pbXBsZW1lbnRhdGlvbiA9IGZ1bmN0aW9uIChmbGFncywgbWFzaykgewogICAgICAgICAgICBjb25zb2xlLmxvZygiRGlzYWJsaW5nIEZMQUdfU0VDVVJFLi4uIik7CiAgICAgICAgICAgIGZsYWdzICY9IH5GTEFHX1NFQ1VSRTsKICAgICAgICAgICAgc2V0RmxhZ3MuY2FsbCh0aGlzLCBmbGFncywgbWFzayk7CiAgICAgICAgfTsKfSk7Cg=="
7+
standup: 0
8+
spawn: false

tools/magisk/install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ ui_print " installer "
2121
pushd $(pwd)
2222
cd $MODPATH
2323
if [ ! -f $SERVER ]; then
24-
abort "lamda-server-${ABI}.tar.gz not found in archive"
24+
abort "lamda-server-${ABI}.tar.gz not in archive, please download and drop it to common/server."
2525
fi
2626

2727
ui_print "- Extracting server files"

tools/magisk/uninstall.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/system/bin/sh
22
MODPATH=${0%/*}
33

4-
rm -rf /data/usr
4+
echo "/data/usr will not be removed, please remove it manually"

0 commit comments

Comments
 (0)