本帖最后由 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 ,支持蓝牙;

Cdtech4761743.jpg (68.11 KB, 下载次数: 7)

下载附件

2018-3-21 19:31 上传

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 资源目录中搜寻文本,没有结果!

PackageInstaller_01.JPG (54.97 KB, 下载次数: 9)

下载附件

2018-3-21 20:01 上传

在 /smali 目录中搜寻该段文本对应的 unicode编码 ,也没有结果!

PackageInstaller_02.JPG (69.06 KB, 下载次数: 7)

下载附件

2018-3-21 20:02 上传

②、/system/framework/ framework-res.apk

系统服务使用的资源位于/system/framework/ framework-res.apk,反编译后搜索有结果!

string.xml

[Java] 纯文本查看 复制代码 用户您好,本终端已关闭第三方应用的直接安装,请从移动应用商场安装,谢谢!

public.xml

[Java] 纯文本查看 复制代码

install_error 的资源 id 为 0x01040613, 这就是下一步需要搜寻的内容,资源id是该文本被调用时的唯一索引。

3、反编译框架之一

/system/framework/ services.jar , pms 代码位于此处;

反编译后搜索 0x01040613 , 没找到!

搜索 0x1040613 ,找到了!

在 PackageManagerService.smali 中找到 两处,有戏:

pms_01.JPG (98.71 KB, 下载次数: 7)

下载附件

2018-3-21 20:15 上传

这两处都位于安装服务底层方法 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;->(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;->(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、反编译框架之二

未完待续