本帖最后由 webpad 于 2019-9-2 12:11 编辑
呃,我的账号还在啊,这贴烂尾楼我得赶紧完结了
安卓盒子破解实战系列
前言
如今国内安卓电视盒子/机顶盒/OTT/STB 采用的硬件方案比较多,安卓版本范围从 4.x 到 7.x;研发人员出于各种目的对方案商提供的SDK或多或少都有修改,造成碎片化情况愈演愈烈;
其中营运商定制版安卓盒子的常见限制有:禁止用户安装app、锁定桌面应用以及关键分区和系统文件的校验保护。
第一篇 解除app安装限制
一、原理分析
出于国情,国内市面上正式发售的盒子,都没有内置谷歌套件和市场,所以不会用谷歌框架实现对安装文件的合法性验证。
安卓应用的安装最终落实到对.apk安装包的操作,其基本流程如下:
PackageInstaller 或 pm install -> PackageManager -> PackageManagerService
当前国内研发人员实现限制安装的常见方法如下:
1、数字签名白名单
这种方法多见于安卓手机或车机等设备,盒子较少使用,
白名单数字证书一般位于/system/etc/security/;
2、修改版PackageInstaller
如果一个盒子可以在终端中用pm install 命令安装.apk,而在盒子的文件管理器中点击.apk却安装失败,
则多半可能是PackageInstaller这个安卓应用层面的安装器被“加强”了;
3、内置文件管理器过滤
原厂固件内置的文件管理器已将 .apk 文件列入过滤列表,不会响应用户的操作;
4、修改版系统框架
pms、ams这些安卓系统服务都位于 framework中,把安卓源代码改得面目全非是每个资深研发人员的“最高”追求,
这也是最常用的限制实现途径。
二、示例
1、实战对象
黑龙江移动魔百和M201-D,硬件方案为晶晨Amlogic S905L ,1+8GB,wifi模块为中龙通Cdtech ,支持蓝牙;
BTW:wifi模块还有可能是 AP6356S 或 RTL8822BS ,非常符合魔百和型号杂乱的现状;
原厂固件包 cmcc_hlj_H1.0.1_S1.0.11_SVN144542_20170918.1519.zip 来自于 /ghost 分区,SDK基于 Android4.4.2, 编译版本号为 1.0.11 ;
2、反编译搜寻文本资源
限制安装表现为在试图从文件管理器安装.apk时出现toast警告:
用户您好,本终端已关闭第三方应用的直接安装,请从移动应用商场安装,谢谢!
所以先从这个toast警告文本入手
①、 /system/app/PackageInstaller.apk
此系统应用为应用包安装器,会直接调用pm安装服务,是首要嫌疑犯;
反编译PackageInstaller.apk ,在 /res 资源目录中搜寻文本,没有结果!
在 /smali 目录中搜寻该段文本对应的 unicode编码 ,也没有结果!
②、/system/framework/ framework-res.apk
系统服务使用的资源位于/system/framework/ framework-res.apk,反编译后搜索有结果!
string.xml
[Java] 纯文本查看 复制代码 <string name="install_error">用户您好,本终端已关闭第三方应用的直接安装,请从移动应用商场安装,谢谢!</string>
public.xml
[Java] 纯文本查看 复制代码 <public type="string" name="install_error" id="0x01040613" />
install_error 的资源 id 为 0x01040613, 这就是下一步需要搜寻的内容,资源id是该文本被调用时的唯一索引。
3、反编译框架之一
/system/framework/ services.jar , pms 代码位于此处;
反编译后搜索 0x01040613 , 没找到!
搜索 0x1040613 ,找到了!
在 PackageManagerService.smali 中找到 两处,有戏:
这两处都位于安装服务底层方法 installPackageLI() 之中,当满足触发条件时由以下代码实现显示toast警告:
[Java] 纯文本查看 复制代码 move-object/from16 v0, p0
iget-object v2, v0, Lcom/android/server/pm/PackageManagerService;->mContext:Landroid/content/Context;
const v6, 0x1040613
const/4 v8, 0x1
invoke-static {v2, v6, v8}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;
move-result-object v2
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
installPackageLI()方法的部分代码如下:
.method private installPackageLI(Lcom/android/server/pm/PackageManagerService$InstallArgs;ZLcom/android/server/pm/PackageManagerService$PackageInstalledInfo;)V
.locals 25
.param p1, "args" # Lcom/android/server/pm/PackageManagerService$InstallArgs;
.param p2, "newInstall" # Z
.param p3, "res" # Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;
.prologue
.line 9249
move-object/from16 v0, p1
iget v0, v0, Lcom/android/server/pm/PackageManagerService$InstallArgs;->flags:I
move/from16 v16, v0
.line 9250
.local v16, "pFlags":I
move-object/from16 v0, p1
iget-object v7, v0, Lcom/android/server/pm/PackageManagerService$InstallArgs;->installerPackageName:Ljava/lang/String;
.line 9251
.local v7, "installerPackageName":Ljava/lang/String;
new-instance v24, Ljava/io/File;
invoke-virtual/range {p1 .. p1}, Lcom/android/server/pm/PackageManagerService$InstallArgs;->getCodePath()Ljava/lang/String;
move-result-object v2
move-object/from16 v0, v24
invoke-direct {v0, v2}, Ljava/io/File;-><init>(Ljava/lang/String;)V
.line 9252
.local v24, "tmpPackageFile":Ljava/io/File;
and-int/lit8 v2, v16, 0x1
if-eqz v2, :cond_0
const/4 v10, 0x1
.line 9253
.local v10, "forwardLocked":Z
:goto_0
and-int/lit8 v2, v16, 0x8
if-eqz v2, :cond_1
const/4 v15, 0x1
.line 9254
.local v15, "onSd":Z
:goto_1
const/16 v22, 0x0
.line 9255
.local v22, "replace":Z
if-eqz v15, :cond_2
const/4 v2, 0x0
:goto_2
or-int/lit8 v2, v2, 0x4
or-int/lit8 v6, v2, 0x8
if-eqz p2, :cond_3
const/16 v2, 0x10
:goto_3
or-int v5, v6, v2
.line 9258
.local v5, "scanMode":I
const/4 v2, 0x1
move-object/from16 v0, p3
iput v2, v0, Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;->returnCode:I
.line 9259
const-string v2, "ro.jsmobile.launcher"
const-string v6, "false"
invoke-static {v2, v6}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v12
.line 9260
.local v12, "jslauncher":Ljava/lang/String;
const-string v2, "sys.proj.type"
const-string v6, "ott"
invoke-static {v2, v6}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v20
.line 9261
.local v20, "proj_type":Ljava/lang/String;
const-string v2, "ro.product.name"
const-string v6, "false"
invoke-static {v2, v6}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v19
.line 9262
.local v19, "proj_name":Ljava/lang/String;
const-string v2, "true"
invoke-virtual {v2, v12}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-eqz v2, :cond_4
move-object/from16 v0, p1
iget v2, v0, Lcom/android/server/pm/PackageManagerService$InstallArgs;->flags:I
move-object/from16 v0, p0
move-object/from16 v1, v24
invoke-direct {v0, v1, v2}, Lcom/android/server/pm/PackageManagerService;->isAllowInstall(Ljava/io/File;I)Z
move-result v2
if-nez v2, :cond_4
.line 9263
move-object/from16 v0, p0
iget-object v2, v0, Lcom/android/server/pm/PackageManagerService;->mContext:Landroid/content/Context;
const v6, 0x1040613
# 第一处调用
const/4 v8, 0x1
invoke-static {v2, v6, v8}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;
move-result-object v2
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
.line 9264
const/16 v2, -0x64
move-object/from16 v0, p3
iput v2, v0, Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;->returnCode:I
.line 9404
:goto_4
return-void
.line 9252
.end local v5 # "scanMode":I
.end local v10 # "forwardLocked":Z
.end local v12 # "jslauncher":Ljava/lang/String;
.end local v15 # "onSd":Z
.end local v19 # "proj_name":Ljava/lang/String;
.end local v20 # "proj_type":Ljava/lang/String;
.end local v22 # "replace":Z
:cond_0
const/4 v10, 0x0
goto :goto_0
.line 9253
.restart local v10 # "forwardLocked":Z
:cond_1
const/4 v15, 0x0
goto :goto_1
.line 9255
.restart local v15 # "onSd":Z
.restart local v22 # "replace":Z
:cond_2
const/4 v2, 0x1
goto :goto_2
:cond_3
const/4 v2, 0x0
goto :goto_3
.line 9268
.restart local v5 # "scanMode":I
.restart local v12 # "jslauncher":Ljava/lang/String;
.restart local v19 # "proj_name":Ljava/lang/String;
.restart local v20 # "proj_type":Ljava/lang/String;
:cond_4
const-string v2, "unicom"
move-object/from16 v0, v20
invoke-virtual {v2, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-eqz v2, :cond_9
sget-object v2, Lcom/android/server/pm/PackageManagerService;->mPackageNameMap:Ljava/util/HashMap;
if-eqz v2, :cond_9
.line 9270
const/4 v9, 0x0
.line 9271
.local v9, "caninstall":Z
new-instance v18, Landroid/content/pm/PackageParser;
invoke-virtual/range {v24 .. v24}, Ljava/io/File;->getPath()Ljava/lang/String;
move-result-object v2
move-object/from16 v0, v18
invoke-direct {v0, v2}, Landroid/content/pm/PackageParser;-><init>(Ljava/lang/String;)V
.line 9272
.local v18, "pp":Landroid/content/pm/PackageParser;
const/4 v2, 0x0
move-object/from16 v0, p0
iget-object v6, v0, Lcom/android/server/pm/PackageManagerService;->mMetrics:Landroid/util/DisplayMetrics;
move-object/from16 v0, p0
iget v8, v0, Lcom/android/server/pm/PackageManagerService;->mDefParseFlags:I
move-object/from16 v0, v18
move-object/from16 v1, v24
invoke-virtual {v0, v1, v2, v6, v8}, Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;Ljava/lang/String;Landroid/util/DisplayMetrics;I)Landroid/content/pm/PackageParser$Package;
move-result-object v3
.line 9273
.local v3, "pkg":Landroid/content/pm/PackageParser$Package;
const/4 v11, 0x0
.local v11, "i":I
:goto_5
sget-object v2, Lcom/android/server/pm/PackageManagerService;->mPackageNameMap:Ljava/util/HashMap;
invoke-virtual {v2}, Ljava/util/HashMap;->size()I
move-result v2
if-ge v11, v2, :cond_7
.line 9274
iget-object v2, v3, Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String;
sget-object v6, Lcom/android/server/pm/PackageManagerService;->mPackageNameMap:Ljava/util/HashMap;
invoke-static {v11}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v8
invoke-virtual {v6, v8}, Ljava/util/HashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
move-result-object v6
invoke-virtual {v2, v6}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-nez v2, :cond_5
move-object/from16 v0, p0
iget-object v2, v0, Lcom/android/server/pm/PackageManagerService;->installapkpath:Ljava/lang/String;
if-eqz v2, :cond_6
move-object/from16 v0, p0
iget-object v2, v0, Lcom/android/server/pm/PackageManagerService;->installapkpath:Ljava/lang/String;
const-string v6, "com.huawei.dsm"
invoke-virtual {v2, v6}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
move-result v2
if-eqz v2, :cond_6
.line 9276
:cond_5
const/4 v9, 0x1
.line 9273
:cond_6
add-int/lit8 v11, v11, 0x1
goto :goto_5
.line 9278
:cond_7
move-object/from16 v0, p0
iget-object v2, v0, Lcom/android/server/pm/PackageManagerService;->installapkpath:Ljava/lang/String;
const-string v6, "/storage/emulated/0"
invoke-virtual {v2, v6}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
move-result v2
if-eqz v2, :cond_8
const-string v2, "cucc_shandong"
move-object/from16 v0, v19
invoke-virtual {v2, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-eqz v2, :cond_8
.line 9280
const/4 v9, 0x1
.line 9282
:cond_8
if-nez v9, :cond_9
.line 9283
move-object/from16 v0, p0
iget-object v2, v0, Lcom/android/server/pm/PackageManagerService;->mContext:Landroid/content/Context;
const v6, 0x1040613
# 第二处调用
const/4 v8, 0x1
invoke-static {v2, v6, v8}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;
move-result-object v2
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
.line 9284
const/16 v2, -0x64
move-object/from16 v0, p3
iput v2, v0, Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;->returnCode:I
goto/16 :goto_4
.line 9292
.end local v3 # "pkg":Landroid/content/pm/PackageParser$Package;
.end local v9 # "caninstall":Z
.end local v11 # "i":I
.end local v18 # "pp":Landroid/content/pm/PackageParser;
:cond_9
# 以下为正常安装进程,略...
*
*
*
.end method
含有两处toast警告的java代码大致如下:
[Java] 纯文本查看 复制代码 p3.returnCode = 0x1;
String "jslauncher" = SystemProperties.get("ro.jsmobile.launcher", "false");
String "proj_type" = SystemProperties.get("sys.proj.type", "ott");
String "proj_name" = SystemProperties.get("ro.product.name", "false");
if ("true".equals("jslauncher")) && (!isAllowInstall("tmpPackageFile", p1.flags))){
Toast.makeText(mContext, 0x1040613, 0x1).show(); #第一处toast
p3.returnCode = -0x64;
return;
}
}
if(("unicom".equals( "proj_type")) && (mPackageNameMap != null)) {
boolean "caninstall" = false;
PackageParser "pp" = new PackageParser("tmpPackageFile".getPath());
PackageParser.Package "pkg" = "pp".parsePackage("tmpPackageFile", 0x0, mMetrics, mDefParseFlags);
for(int "i" = 0x0; "i" < mPackageNameMap.size(); "i" = "i" + 0x1) {
if((!"pkg".packageName.equals(mPackageNameMap.get(Integer.valueOf("i")))) || (installapkpath == null) && (!installapkpath.contains("com.huawei.dsm"))) {
continue;
}
"caninstall" = true;
}
if((installapkpath.contains("/storage/emulated/0")) && ("cucc_shandong".equals( "proj_name"))) {
"caninstall" = true;
}
if(!"caninstall") {
Toast.makeText(mContext, 0x1040613, 0x1).show(); #第二处toast
p3.returnCode = -0x64;
}
return;
}
可以发现第一处的逻辑如下:
若系统属性com.jsmobile.launcher 为true (江苏移动定制版)且安装包不在允许列表内(isAllowInstall方法会从TR069服务取得允许列表并返回判断结果),
就会触发显示toast警告,并退出安装进程;
但build.prop 中没有 com.jsmobile.launcher 条目,默认赋值为 false,所以安装流程不会走入此if分支;
第二处逻辑如下:
若系统属性sys.proj.type 等于unicom(联通定制版)才会进行后续的条件判断,而本固件build.prop中没有sys.proj.type条目(将会赋值为默认值 ott),
也就是说安装流程并不会走入此 if 分支。
综上所述,这两处禁止安装的toast都不会被触发,显然另有其它机关。
4、反编译框架之二
未完待续
|