Skip to content

Commit

Permalink
8.0 auto-commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rev1si0n committed Jan 19, 2025
1 parent 744e8ef commit 4acec6c
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 66 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
8.0
* 接口全面支持多开应用
* 远程桌面支持共享剪切板
* 新增部分机型无法打开APP的修复配置
* 新增 Yaml frida 脚本持久化
* 修复 6.0 等低版本系统兼容性
* 修复高版本系统自动化相关功能异常
* 移除/重命名部分方法
* 更新底层实现

7.90
* 持久化脚本支持 spawn 模式
* 支持持久化脚本输出日志
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<img src="https://img.shields.io/github/v/release/rev1si0n/lamda" />
</p>

<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>
<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>

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

Expand Down
2 changes: 1 addition & 1 deletion lamda/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
#
# Distributed under MIT license.
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
__version__ = "7.90"
__version__ = "8.0"
92 changes: 36 additions & 56 deletions lamda/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,19 +302,13 @@ def ocr(self, image):


class BaseCryptor(object):
def __str__(self):
return "{}".format(self.__class__.__name__)
__repr__ = __str__
def encrypt(self, data):
return data
def decrypt(self, data):
return data


class BaseServiceStub(object):
def __str__(self):
return "{}".format(self.__class__.__name__)
__repr__ = __str__
def __init__(self, stub):
self.stub = stub

Expand Down Expand Up @@ -467,8 +461,6 @@ def click_exists(self, corner=Corner.COR_CENTER):
corner=corner)
r = self.stub.selectorClickExists(req)
return r.value
def click_exist(self, *args, **kwargs):
return self.click_exists(*args, **kwargs)
def long_click(self, corner=Corner.COR_CENTER):
"""
长按选择器选中的控件
Expand All @@ -484,26 +476,12 @@ def exists(self):
req = protos.SelectorOnlyRequest(selector=self.selector)
r = self.stub.selectorExists(req)
return r.value
def exist(self, *args, **kwargs):
return self.exists(*args, **kwargs)
def info(self):
"""
获取选择器选中控件的信息
"""
req = protos.SelectorOnlyRequest(selector=self.selector)
return self.stub.selectorObjInfo(req)
def info_of_all_instances(self):
"""
获取选择器选中的所有控件的信息
"""
req = protos.SelectorOnlyRequest(selector=self.selector)
r = self.stub.selectorObjInfoOfAllInstances(req)
return r.objects
def all_instances(self):
"""
获取选择器选中的所有元素控件
"""
return list(self)
def _new_object(self, **kwargs):
selector = copy.deepcopy(self._selector)
selector.update(**kwargs)
Expand Down Expand Up @@ -559,6 +537,11 @@ def index(self, idx):
return self._new_object(index=idx)
def instance(self, idx):
return self._new_object(instance=idx)
def get(self, idx):
"""
获取匹配的第 N 个索引的元素
"""
return self.instance(idx)
def __iter__(self):
"""
遍历所有符合选择器条件的元素实例
Expand Down Expand Up @@ -1042,16 +1025,21 @@ def __init__(self, stub, application,
self.application = application
self.stub = stub
self.name = name
def __str__(self):
return "{}:Script:{}".format(self.application,
self.name)
__repr__ = __str__
def __call__(self, *args):
call_args = dict()
call_args["method"] = self.name
call_args["args"] = args
req = HookRpcRequest()
req.package = self.application.applicationId
req.user = self.application.user
req.callinfo = json.dumps(call_args)
result = self.stub.callScript(req)
r = json.loads(result.callresult)
return r
data = json.loads(result.callresult)
return data


class ApplicationOpStub:
Expand All @@ -1063,8 +1051,8 @@ def __init__(self, stub, applicationId, user=0):
self.applicationId = applicationId
self.stub = stub
def __str__(self):
return "{}:{}".format(self.stub.__class__.__name__,
self.applicationId)
return "Application:{}@{}".format(self.applicationId,
self.user)
__repr__ = __str__
def is_foreground(self):
"""
Expand Down Expand Up @@ -1118,24 +1106,22 @@ def is_permission_granted(self, permission):
req.user = self.user
r = self.stub.isPermissionGranted(req)
return r.value
def delete_cache(self):
def clear_cache(self):
"""
清空应用的缓存数据(非数据仅缓存)
"""
req = protos.ApplicationRequest(name=self.applicationId)
req.user = self.user
r = self.stub.deleteApplicationCache(req)
return r.value
def reset_data(self):
def reset(self):
"""
清空应用的所有数据
"""
req = protos.ApplicationRequest(name=self.applicationId)
req.user = self.user
r = self.stub.resetApplicationData(req)
return r.value
def reset(self):
return self.reset_data()
def start(self):
"""
启动应用
Expand Down Expand Up @@ -1226,27 +1212,34 @@ def attach_script(self, script, runtime=ScriptRuntime.RUNTIME_QJS,
req.spawn = spawn
req.destination = emit
req.encode = encode
req.user = self.user
r = self.stub.attachScript(req)
return r.value
def detach_script(self):
"""
移除注入应用的 Hook 脚本
"""
req = protos.String(value=self.applicationId)
req = protos.HookRequest()
req.package = self.applicationId
req.user = self.user
r = self.stub.detachScript(req)
return r.value
def is_attached_script(self):
"""
检查使用在此应用注入了 Hook 脚本
"""
req = protos.String(value=self.applicationId)
req = protos.HookRequest()
req.package = self.applicationId
req.user = self.user
r = self.stub.isScriptAttached(req)
return r.value
def is_script_alive(self):
"""
检查应用中的 Hook 脚本是否正常
"""
req = protos.String(value=self.applicationId)
req = protos.HookRequest()
req.package = self.applicationId
req.user = self.user
r = self.stub.isScriptAlive(req)
return r.value
def __getattr__(self, name):
Expand All @@ -1263,7 +1256,7 @@ def current_application(self):
获取当前处于前台的应用的信息
"""
top = self.stub.currentApplication(protos.Empty())
app = self.__call__(top.packageName)
app = self.__call__(top.packageName, user=top.user)
app.activity = top.activity
return app
def get_application_by_name(self, name, user=0):
Expand Down Expand Up @@ -1305,17 +1298,14 @@ def install_local_file(self, fpath):
安装设备上的 apk 文件(注意此路径为设备上的 apk 路径)
"""
req = protos.ApplicationRequest(path=fpath)
req.user = self.user
r = self.stub.installFromLocalFile(req)
return r
def __call__(self, applicationId, user=0):
return ApplicationOpStub(self.stub, applicationId, user)


class StorageOpStub:
def __str__(self):
return "{}:{}".format(self.stub.__class__.__name__,
self.name)
__repr__ = __str__
# 用于容器值序列化的方法
def _decrypt(self, data):
return self.cryptor.decrypt(data)
Expand Down Expand Up @@ -1734,20 +1724,20 @@ def stop_gproxy(self):


class SelinuxPolicyStub(BaseServiceStub):
def policy_set_allow(self, source, target, tclass, action):
def allow(self, source, target, tclass, action):
"""
selinux allow
"""
req = protos.SelinuxPolicyRequest(source=source, target=target,
tclass=tclass, action=action)
tclass=tclass, action=action)
r = self.stub.policySetAllow(req)
return r.value
def policy_set_disallow(self, source, target, tclass, action):
def disallow(self, source, target, tclass, action):
"""
selinux disallow
"""
req = protos.SelinuxPolicyRequest(source=source, target=target,
tclass=tclass, action=action)
tclass=tclass, action=action)
r = self.stub.policySetDisallow(req)
return r.value
def get_enforce(self):
Expand All @@ -1763,27 +1753,27 @@ def set_enforce(self, enforced=True):
req = protos.Boolean(value=enforced)
r = self.stub.setEnforce(req)
return r.value
def is_enabled(self):
def enabled(self):
"""
获取设备上的 selinux 是否已经启用
"""
r = self.stub.isEnabled(protos.Empty())
return r.value
def policy_set_enforce(self, name):
def enforce(self, name):
"""
设置一个域为 enforce
"""
req = protos.String(value=name)
r = self.stub.policySetEnforce(req)
return r.value
def policy_set_permissive(self, name):
def permissive(self, name):
"""
设置一个域为 permissive
"""
req = protos.String(value=name)
r = self.stub.policySetPermissive(req)
return r.value
def policy_create_domain(self, name):
def create_domain(self, name):
"""
新建一个 selinux 域
"""
Expand Down Expand Up @@ -2022,11 +2012,6 @@ def exists(self):
OCR - 检查元素是否存在
"""
return bool(self.find_target_item())
def exist(self):
"""
OCR - 检查元素是否存在
"""
return self.exists()
def click(self):
"""
OCR - 点击元素(不存在则报错)
Expand All @@ -2037,11 +2022,6 @@ def click_exists(self):
OCR - 点击元素(不存在将不会产生异常)
"""
return self.find_cb(self._click, False)
def click_exist(self):
"""
OCR - 点击元素(不存在将不会产生异常)
"""
return self.click_exists()
def screenshot(self, quality=100):
"""
OCR - 对元素进行截图
Expand Down
2 changes: 2 additions & 0 deletions lamda/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class InvalidAndroidPackage(Exception):
""" Exception """
class InvalidArgumentError(Exception):
""" Exception """
class InvalidOperationError(Exception):
""" Exception """
class InvalidRootCertificate(Exception):
""" Exception """
class MethodNotFoundException(Exception):
Expand Down
4 changes: 4 additions & 0 deletions lamda/rpc/application.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ message ApplicationActivityInfo {
int64 flags = 7;
bool debug = 8;
string data = 9;
uint32 user = 10;
}

message ApplicationActivityInfoList {
Expand All @@ -77,6 +78,7 @@ message ApplicationInfo {
uint32 versionCode = 10;
string versionName = 11;
string activity = 12;
uint32 user = 13;
}

message ApplicationProcess {
Expand All @@ -102,11 +104,13 @@ message HookRequest {
DataEncode encode = 5;
uint32 standup = 6;
bool spawn = 7;
uint32 user = 8;
}

message HookRpcRequest {
string package = 1;
string callinfo = 2;
uint32 user = 3;
}

message HookRpcResponse {
Expand Down
6 changes: 3 additions & 3 deletions lamda/rpc/services.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ service Application {
rpc getIdentifierByLabel(String) returns (String) {}

rpc callScript(HookRpcRequest) returns (HookRpcResponse) {}
rpc isScriptAlive(String) returns (Boolean) {}
rpc isScriptAttached(String) returns (Boolean) {}
rpc isScriptAlive(HookRequest) returns (Boolean) {}
rpc isScriptAttached(HookRequest) returns (Boolean) {}
rpc attachScript(HookRequest) returns (Boolean) {}
rpc detachScript(String) returns (Boolean) {}
rpc detachScript(HookRequest) returns (Boolean) {}
}

service Debug {
Expand Down
4 changes: 4 additions & 0 deletions properties.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ enhanced-stealth-mode=false
# the remote desktop, please set the following configuration:
touch.backend=system

# If the application fails to open after the service is started,
# please set this option to true.
dirtyfix_open_app=false

# ---------- OpenVPN Configuration ----------
# Do not manually write the following configuration. You should use
# our accompanying OpenVPN server setup solution to set it up and
Expand Down
8 changes: 8 additions & 0 deletions scripts/disable_flag_secure.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This script is used to disable the android FLAG_SECURE flag.
# Replace YOUR_APP_ID with the ID (eg. com.android.settings) of your target application.
enable: true
application: "YOUR_APP_ID"
version: "N/A"
script: !!binary "SmF2YS5wZXJmb3JtKGZ1bmN0aW9uICgpIHsKICAgICAgICB2YXIgRkxBR19TRUNVUkUgPSAweDIwMDA7CiAgICAgICAgdmFyIFdpbmRvdyA9IEphdmEudXNlKCJhbmRyb2lkLnZpZXcuV2luZG93Iik7CiAgICAgICAgdmFyIHNldEZsYWdzID0gV2luZG93LnNldEZsYWdzOwoKICAgICAgICBzZXRGbGFncy5pbXBsZW1lbnRhdGlvbiA9IGZ1bmN0aW9uIChmbGFncywgbWFzaykgewogICAgICAgICAgICBjb25zb2xlLmxvZygiRGlzYWJsaW5nIEZMQUdfU0VDVVJFLi4uIik7CiAgICAgICAgICAgIGZsYWdzICY9IH5GTEFHX1NFQ1VSRTsKICAgICAgICAgICAgc2V0RmxhZ3MuY2FsbCh0aGlzLCBmbGFncywgbWFzayk7CiAgICAgICAgfTsKfSk7Cg=="
standup: 0
spawn: false
2 changes: 1 addition & 1 deletion tools/magisk/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ui_print " installer "
pushd $(pwd)
cd $MODPATH
if [ ! -f $SERVER ]; then
abort "lamda-server-${ABI}.tar.gz not found in archive"
abort "lamda-server-${ABI}.tar.gz not in archive, please download and drop it to common/server."
fi

ui_print "- Extracting server files"
Expand Down
2 changes: 1 addition & 1 deletion tools/magisk/uninstall.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/system/bin/sh
MODPATH=${0%/*}

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

0 comments on commit 4acec6c

Please sign in to comment.