文章目录

  • 前言
  • Adb Shell
    • am指令
    • pm指令
    • other…
  • Intent
    • 组件间调用
    • setPackage
    • 隐式意图劫持
    • 拒绝服务攻击
    • DeepLink链接
  • 组件权限
    • 自定义权限
    • 未定义权限

前言

前面写过 移动安全-Android安全测试框架Drozer 一文,记录了如何使用 Drozer 对 Android 四大组件进行安全测试,本文补充下其他一些零散的测试知识。

Adb Shell

adb shell 提供了很多实用的命令可供测试者使用,如 am、pm 等命令。

am指令

am 指令是 activity manager 的缩写,可以启动 Activity、Service、Broadcast,杀进程,监控等功能,这些功能都非常便捷调试程序。

目的 指令
指定 action 启动拨号 Activity am start -a android.intent.action.CALL -d tel:10086
指定 action 打开网页 Activity am start -a android.intent.action.VIEW -d https://www.baidu.com
指定组件名启动应用 Activity am start -n com.android.example/.MainActivity
启动一个服务 am startservice -n/-a XXX
发送一个广播 am broadcast -a <广播动作>
监控 Crash 与 ANR am monitor
强杀进程/强制停止某应用 am force-stop com.android.example

更多命令和功能请执行 adb shell am -h 查看完整的指令帮助信息。

【补充】参数释义

1、Intent 参数

参数名 解释
-a <ACTION> 指定 Intent action, 实现原理 Intent.setAction()
-n <COMPONENT> 指定组件名( 包名/.类名包名/类的全名),实现原理 Intent.setComponent()
-d <DATA_URI> 传入数据,指定 Intent data URI
-p <PACKAGE> 指定包名,实现原理 Intent.setPackage()
-f <FLAGS> 添加 flags,实现原理 Intent.setFlags(int ),紧接着的参数必须是 int 型

2、Extra 参数

来看一个示例:

am start -n com.android.example/.MainActivity -es website www.baidu.com

此处-es website www.baidu.com,等价于 Intent.putExtra(“website”, “www.baidu.com”)。其他类型的参数如下:

参数 类型
-e/-es String
-esn (String)null
-ez boolean
-ei int
-el long
-ef float
-eu uri
-ecn component
-esa String[] 数组
-eia int[] 数组

补充一句,移动安全-Activity劫持检测与防护 提到的关于 Activity 劫持的快速验证方法,可以使用如下 am 指令:

adb shell am start -n com.test.uihijack com.test.uihijack.MainActivity

pm指令

pm 工具为包管理 (Package Manager) 的简称,可以使用 pm 工具来执行应应用包的信息、系统权限查询,控制应用等。pm 工具是 Android 开发与测试过程中必不可少的工具,通常放置在 system/bin/pm 下。

常用指令比如查看指定应用版本信息:

pm dump com.tencent.mm|findstr versionName

More:

目的 指令
列出所有应用 pm list package
列出第三方应用 pm list package -3
列出所有系统应用 pm list package -s
列出所有已知权限 pm list permissions
查找应用安装包路径 pm path com.tencent.mm
清除应用的数据与缓存 pm clear com.tencent.mm
授予应用某个权限 pm grant com.tencent.mm android.permission.CAMERA
撤销应用某个权限 pm revoke com.tencent.mm android.permission.CAMERA
卸载应用 pm uninstall com.tencent.mm
隐藏应用桌面图标 pm hide com.tencent.mm
恢复隐藏的应用 pm unhide com.tencent.mm

以上列出了日常测试中常用的 pm 指令,更多指令信息可查看 adb shell pm 帮助信息。

other…

其他常用 adb shell 指令,如 :

//查看当前在运行的 Activity
adb shell dumpsys activity top | grep ACTIVITY
//抓取指定应用的错误日志
adb shell logcat *:E  --pid `pidof com.XX.XX`> /data/local/tmp/1.log
目的 指令
抓取错误日志 logcat -c && logcat *:E > /data/local/tmp/1.log
手机截屏 adb shell screencap -p /data/local/tmp/1.png
手机录屏 adb shell screenrecord /data/local/tmp/1.mp4
查看应用的详细权限、版本等信息 adb shell dumpsys package com.tencent.mm
content 指令查询数据库 adb shell content query --uri content://contacts/people

【补充】Android 的 Uri 由以下三部分组成: “content://”、数据的路径、标示ID(可选)。举些例子,如:

所有联系人的Uri: content://contacts/people
某个联系人的Uri:  content://contacts/people/5
所有图片Uri:     content://media/external
某个图片的Uri:   content://media/external/images/media/4

来看一下 Android 是如何管理多媒体文件(音频、视频、图片)的信息。通过 DDMS,可以在/data/data/com.android.providers.media下找到数据库文件:

打开 external.db 文件进一步查看:在 media 表格下,可以看到文件路径(_data) 和 Uri 的标示 ID(_id) 的对应关系。

Intent

组件间调用

安全测试经常需要编写 POC 程序调用其他应用程序 exported="true" 且无权限保护的可导出组件,以下是借助 Intent 调用其他应用程序的组件的方法:

//启动其他应用程序的Activity
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.Tr0e.example", "com.Tr0e.example.MyExampleActivity"));
startActivity(intent);//启动其他应用程序的Service
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.Tr0e.example", "com.Tr0e.example.MyExampleService"));
startService(intent);//发送广播给其他应用程序的Receiver
Intent intent = new Intent();
//Android 8以后想给静态注册的广播接收器(应用无需启动即可接收广播)发送广播,必须指定接收器的包名类名
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){intent.setComponent(new ComponentName("com.Tr0e.example", "com.Tr0e.example.MyExampleReciver"));
}
intent.setAction("android.intent.action.Mybroadcast");
sendBroadcast(intent);

此处补充一下,Android 8.0 开始之所以要限制静态注册的广播接收器所能接收的广播,是因为静态注册的广播接收器具有无需启动应用即可接收广播的特点,那么试想一下以下场景:一个恶意 APP 完成可以通过静态注册一个监听系统开机广播的广播接收器,来达到手机开机后立马执行恶意脚本的目的(典型的触发开机自启动的场景)。关于广播接收器和广播的更多基础知识可以参见:Android-广播。

setPackage

以上提到可以通过 intent.setComponent(pkg,cls) 接口来限制广播接收方,其实 Intent 还提供如下接口同样也可以达到限制广播接收方的目的:

//https://developer.android.com/reference/android/content/Intent#setPackage(java.lang.String)
public Intent setPackage (String packageName)

通过 intent.setPackage(com.Tr0e.example);即可限定只能由指定的应用来接收、解析该 Intent 实例。

故给非系统应用静态注册的广播接收器发送广播的方式也可以如下:

Intent intent = new Intent();
intent.setPackage("com.Tr0e.example");
intent.setAction("android.intent.action.Mybroadcast");
sendBroadcast(intent);

隐式意图劫持

众所皆知,Intent 可分为隐式(implicitly) 和显式 (explicitly) 两种:

1)显式Intent

即在构造 Intent 对象时就指定接收者,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的,如下:

Intent intent = new Intent(MainActivit.this, NewActivity.class);
startActivity(intent);

2)隐式Intent

即 Intent 的发送者在构造 Intent 对象时,并不知道也不关心接收者是谁,有利于降低发送者和接收者之间的耦合,它一般用在没有明确指出目标组件名称的前提下,一般是用于不同应用程序之间,如下:

Intent intent = new Intent();
intent.setAction("com.wooyun.test");
startActivity(intent);

对于显式 Intent,Android 不需要去做解析,因为目标组件已经很明确,Android 需要解析的是那些隐式 Intent,通过解析将 Intent 映射给可以处理此 Intent 的 Activity、Receiver 或 Service。

攻击场景

如果使用隐式 Intent 启动 Activity 组件,系统中凡是满足 action="XXX" 的组件否有可能被启动,系统会弹出选项框,由用户决定启动哪个 Activity。此时如果 Intent 中如果携带敏感数据且用户选错组件的话,攻击者便能劫持该 Intent 并获取敏感数据。整体的攻击场景如下图所示:

Demo 案例

1)在受害者 A 应用(Test)中发送 Intent


Intent intent = new Intent();
intent.setAction("com.bwshen.intent.action_test");
intent.putExtra("password","admin123");
startActivity(intent);

同时在 A 应用(Test)中定义目标组件:

<activity android:name=".LoginActivity"><intent-filter><action android:name="com.bwshen.intent.action_test" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

2)在攻击者 B 应用 (Attack)中同样定义相同 Action 的组件:

<activity android:name=".LoginActivity"><intent-filter><action android:name="com.bwshen.intent.action_test" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

此时 A 应用发生 Intent 时将弹出如下选项框供用户选择:

以上如果用户选择错应用,那么 password 信息将被攻击者获取。综上所述,应尽量避免使用隐式启动的方式来调用组件,特别是传递了敏感数据的 Intent。开发者可以使用 setPackage(pkgName)setComponent(pkg,cls) 来明确指定接收方,从而防止 Intent 劫持和敏感数据泄露。

拒绝服务攻击

Intent 可以通过 putExtra(String name, XXX value) 来给目标组件传递各种类型的数据,如下图所示:

攻击场景

如果目标组件在使用 getXXXExtra() 接口接收数据时没有对异常、畸形数据进行异常捕获,那么攻击者向应用发送空数据、异常或者畸形数据可达到致使受害者应用崩溃、形成拒绝服务攻击的效果。此类本地拒绝服务漏洞对于锁屏应用、安全防护类软件危害是巨大的。

漏洞示例

注意到传递的一类特殊数据—— Bundle:

(1)先来看下 MainActivity 正常情况下如何在 Intent 中传递 Bundle 对象:

Intent intent = new Intent(MainActivity.this,LoginActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name","admin");
bundle.putString("password","admin123");
intent.putExtra("data",bundle);
startActivity(intent);

LoginActivity 接收数据:

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);Intent intent = getIntent();Bundle bundle_data = intent.getBundleExtra("data");String password = (String)bundle_data.get("password");Log.e(TAG,"password="+password);
}

程序运行效果:

(2)接下来看看如果 MainActivity 中不传递名字为 data 的 Bundle 对象的话,将导致什么结果:

Intent intent = new Intent(MainActivity.this,LoginActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name","admin");
bundle.putString("password","admin123");
intent.putExtra("data111",bundle);
startActivity(intent);

运行程序并出发 Intent 发送事件,发现程序崩溃,日志如下:

2022-05-11 22:30:20.759 3873-3873/com.bwshen.test E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.bwshen.test, PID: 3873java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bwshen.test/com.bwshen.test.LoginActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object referenceat android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)at android.app.ActivityThread.-wrap11(Unknown Source:0)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)at android.os.Handler.dispatchMessage(Handler.java:105)at android.os.Looper.loop(Looper.java:164)at android.app.ActivityThread.main(ActivityThread.java:6541)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object referenceat com.bwshen.test.LoginActivity.onCreate(LoginActivity.java:18)at android.app.Activity.performCreate(Activity.java:6975)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

可以看到触发了空指针引用的异常,修复方法很简单,增加异常捕获:

Intent intent = getIntent();
try {Bundle bundle_data = intent.getBundleExtra("data");String password = (String)bundle_data.get("password");Log.e(TAG,"password="+password);
}catch (Exception e){Log.e(TAG, String.valueOf(e));
}

除了传递 Bundle 对象外,Intent 中传递如下指针类型的数据时,接收方均应该进行异常捕获:

接收方对应的获取数据的接口(重点关注)如:getSerializable、getParcelable、getDoubleArray 等。

DeepLink链接

在 Android 设备中,可以通过点击 Deeplink 可以打开指定应用的 Activity 组件,该特性可以用于发现存在本地 Activity 存在漏洞(如上述拒绝服务攻击)后发起网络钓鱼链接攻击,将漏洞的攻击向量由本地攻击转为远程攻击(有利于 CVSS 漏洞评分),从而提高漏洞危害。

为了能够正确定位到需要打开的应用,并正确打开指定的 Activity,需要应用开发过程中对 Intent 进行过滤接收进行配置(就是intent-filter)。具体做法是在 AndroidManifest.xml 中对 Activity 声明的时候添加<intent-filter><data>节点,配置schema和一些必要的区分属性参数(如:host、path 等)即可,配置的属性参数越多越详细,越能保证唯一性,准确打开需要打开的应用,而不是弹出打开应用选择框。

DeepLink 唤起 APP 示例

继续以上面的 LoginActivity 为例,修改 AndroidMainfest.xml 中其配置如下:

<activity android:name=".LoginActivity"><intent-filter><action android:name="com.bwshen.intent.action_test" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><!--ACTION_VIEW:支持被检索--><action android:name="android.intent.action.VIEW" /><!--CATEGORY_DEFAULT:响应隐式Intent--><category android:name="android.intent.category.DEFAULT" /><!--CATEGORY_BROWSABLE:可被Web浏览器唤起--><category android:name="android.intent.category.BROWSABLE" /><!--data:一个或多个,必须含有scheme标签,决定被唤起的URL格式--><data android:scheme="rsdkdemo"android:host="rs.com"android:pathPrefix="/test"/></intent-filter>
</activity>

上述添加的<intent-filter>标签包含以下属性:

属性 作用
action 动作 外部打开必须配置成ACTION_VIEW,这样外部的打开指令才能到达
category 范畴 (1)必须包含 DEFAULT,这个 category 允许你的 Activity 可以接收隐式 Intent,如果没有配置这个,Activity 只能通过指定应用程序容器名称打开;
(2)必须包含 BROWSABLE,这个 category 允许你的 intent-filter 可以在 Web 浏览器中访问,如果没有配置这个,点击Web浏览器中的 Deeplink 链接将无法解析并打开 Activity。
data 数据 需要添加一个或者多个<data>标签,每一个<data>标签都描述了什么样格式的 URI 将会分派到 Activity 进行处理,同时每一个<data>标签至少且必须包含一个android:schema属性。

Deeplink 的链接类型一般是 schema://host/path?params 样式,上述链接即为 rsdkdemo://rs.com/testrsdkdemo://rs.com/test?referer=Deeplink_Test

(1)命令行 adb 测试 deeplink

adb shell am start -a android.intent.action.VIEW -d "rsdkdemo://rs.com/test"

效果如下:

(2)原生代码访问 deeplink

对应的如果是原生 Android 代码启动上述组件的代码则是:

Intent intent = new Intent();
intent.setData(Uri.parse("rsdkdemo://rs.com/test"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

(3)测试网页点击 deeplink

编写 html 页面 poc.html 如下:

<!DOCTYPE html>
<html>
<head><title>MyPoc</title>
</head>
<body><input type="button" value="点击我打开Deeplink" onclick="javascrtpt:window.location.href='rsdkdemo://rs.com/test?referer=Deeplink_Test'">
</body>
</html>

搭建 Python Web 服务提供远程服务,手机浏览器访问 poc.html :

点击按钮成功访问目标 APP 组件:

对应的在 h5 页面上唤起上述组件的方式还有:

<!--1.通过a标签打开,点击标签是启动,注意这里的 href 格式-->
<a href="rsdkdemo://rs.com/test">open android app</a>
<!--2.通过iframe打开,设置iframe.src即会启动-->
<iframe src="rsdkdemo://rs.com/test"></iframe>
<!--3.直接通过window.location 进行跳转-->
window.location.href= "rsdkdemo://rs.com/test";

(4)传递数据的 DeepLink

修改 LoginActivity 组件的配置:

<activity android:name=".LoginActivity"><intent-filter><action android:name="com.bwshen.intent.action_test" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><!--ACTION_VIEW:支持被检索--><action android:name="android.intent.action.VIEW" /><!--CATEGORY_DEFAULT:响应隐式Intent--><category android:name="android.intent.category.DEFAULT" /><!--CATEGORY_BROWSABLE:可被Web浏览器唤起--><category android:name="android.intent.category.BROWSABLE" /><!--data:一个或多个,必须含有scheme标签,决定被唤起的URL格式--><data android:scheme="rsdkdemo"/></intent-filter>
</activity>

以下 POC 可唤醒组件同时传递数据:

<!DOCTYPE html>
<html>
<head><title>MyPoc</title>
</head><body><h1><a href="intent://externalapp/#Intent;scheme=rsdkdemo;component=com.bwshen.test/.LoginActivity;S.password=admin123;end">open android app</a></body>
</html>

访问效果如下:

成功在浏览器启动目标 APP 的 Activity 组件并传递数据:

读者如果细心的话肯定发现我传递的是字符串而不是原先示例程序的 Bundle 对象,因为 Bundle 对象我暂不知道如何传递……知道的可以告诉我,谢谢!

组件权限

导出组件一般有以下三种形式:

  1. 在 AndroidManifest.xml 中组件显式设置了组件属性 android:exported=“true”;
  2. 如果组件没有显式设置 android:exported=“false”,但是其存在 intent-filter 以及 action ,则也为导出组件;
  3. API Level 在 17 以下的所有 App 的 provider 组件的 android:exported 属性默认值为 true,17 及以上默认值为 false。

任意第三方 App 都可以访问导出组件。

自定义权限

Android 提供了许多权限(权限列表可参见:Android 危险权限与所有权限大全)来限制第三方应用程序的行为,比如相机权限 android.permission.CAMERA可防止三方应用程序在用户未授权情况下访问相机。

除了系统自带的权限之外,Android 应用程序也可以自定义权限来保护自身组件。自定义的权限在 AndroidMainfest.xml 文件中声明,格式如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.Tr0e.example"><permissionandroid:name="com.Tr0e.permission.TEST"android:description="@string/test_permission_description"android:permissionGroup="@string/test_permissionGroup"android:protectionLevel="signature" />...
</manifest><!-- 需定义字符串资源 src/main/res/values/strings.xml -->
<resources><string name="app_name">Test</string><string name="test_permission_description">this is a test permission</string><string name="test_permissionGroup">android.permission-group.COST_MONEY</string>
</resources>

解释下各个属性:

  • name,该标签就是权限的名字;
  • description(可选项),该标签就是权限的介绍;
  • permissionGroup(可选项),指定该权限的组;
  • protectionLevel(必需项),指定保护级别。

Android 将权限分为若干个保护级别,比如:

  1. normal 就是正常权限,该权限并不会给用户或者设备的隐私带来风险;
  2. dangerous 就是危险权限,该级别的权限通常会给用户的数据或设备的隐私带来风险;
  3. signature 指的是只有相同签名的应用才能使用该权限;
  4. signatureOrSystem 指的是签名相同或者申请权限的应用为系统应用(预置在 system image 中,非 root 无法卸载)。

【注意】自定义权限一般不指定 protectionLevel=normal,因为保护级别为正常权限的话,其他三方应用可随意申请该权限,那么就没法实现自定义权限所预期想要的保护特定组件的效果了。

我们继续以上面讨论过的广播和广播接收器权限为例,看看如何通过自定义保护组件。

(1)谁有权给我发广播?

首先可以在 AndroidMainfest.xml 中定义静态广播接收器的时候指定组件的保护权限:

<receiverandroid:name="MyExampleReciver"android:permission="com.Tr0e.permission.TEST" ><intent-filter ><actionandroid:name="android.intent.action.Mybroadcast" /></intent-filter></receiver>

以上可以限定广播发送方应具有特点权限后才能给该静态注册的广播接收器发送广播。如果是动态注册的广播接收器则可以通过在 registerReceiver() 函数中添加权限字段的方式来添加权限保护:

public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter;private NetworkChangeReceiver networkChangeReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//创建IntentFilter实例,并添加actionintentFilter = new IntentFilter();//当网络发生变化时,系统发出的广播为android.net.conn.CONNECTIVITY_CHANGEintentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//创建NetworkChangeReceiver实例networkChangeReceiver = new NetworkChangeReceiver();//调用registerReceiver()方法进行注册,同时声明广播发送者应具有的权限(可选项,默认为空)registerReceiver(networkChangeReceiver, intentFilter,"com.Tr0e.permission.TEST");}@Overrideprotected void onDestroy() {super.onDestroy();//活动结束时,调用unregisterReceiver方法实现取消注册unregisterReceiver(networkChangeReceiver);}//创建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法即可。//具体的处理逻辑是在onReceive()中执行(不支持多线程,所以不要处理太复杂的信息)class NetworkChangeReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();if (networkInfo != null && networkInfo.isAvailable()) {Toast.makeText(context, "network is available",Toast.LENGTH_SHORT).show();} else {Toast.makeText(context, "network is unavailable",Toast.LENGTH_SHORT).show();}}}
}

(2)谁有权收我的广播?

以上是针对广播接收器组件的保护,而对于广播的保护,则可以通过 sendBroadcast(Intent, String) 的接口在发送广播时指定接收者必须具备的 permission 权限:

Intent intent = new Intent();
intent.setAction("android.intent.action.Mybroadcast");
sendBroadcast(intent, "com.Tr0e.permission.TEST");

如果担心反编译后,权限被窃取导致限制失效。可以在声明权限时,提高权限的 leverl 为签名验证,即只有相同签名的应用且有该权限才能够接收,这样就能够满足产品簇的问题。

未定义权限

自定义权限虽然能有效保护组件不被非法访问,但是权限管理又成为了一个必须考虑的问题。

经常会遇到某 apk 使用了未定义的权限来保护组件,这将使得防护形同虚设,恶意应用可以在自身 apk 中定义受害者应用所引用的未定义的权限,从而成功获得访问受害者应用该类“受保护”的组件。

游离权限的排查,需关注以下两种场景:

  1. AndroidMainfest.xml 中定义组件时使用的 permission;
  2. 动态注册的广播接收器使用的 permission(参照上文案例)。

判断权限是否已定义的方法:

adb shell pm list permissions | findstr  com.Tr0e.permission.TEST

如下是安装了自定义权限 app 前后的权限检查结果对比:

同时可以通过命令查询权限的完整信息:

C:\Users\True
λ adb shell pm list permissions -f | grep -A4  com.Tr0e.permission.TEST
+ permission:com.Tr0e.permission.TESTpackage:com.bwshen.testlabel:nulldescription:this is a test permissionprotectionLevel:signature
C:\Users\True
λ

Android 应用层组件安全测试基础实战技巧相关推荐

  1. 使用Drozer对Android四大组件进行测试

    使用Drozer对Android四大组件进行测试 一.介绍 Drozer是一款安卓的安全测试框架,可以用来对安卓应用进行渗透测试,工作方式为交互式,有点类似于MSF,可以选择模块和payload对风险 ...

  2. 渗透测试 ( 5 ) --- 扫描之王 nmap、渗透测试工具实战技巧合集

    Nmap 官方文档 ( 中文文档是 Nmap 版本4.50,英文文档是最新的 ): 英文文档:https://nmap.org/book/man.html 中文文档:https://nmap.org/ ...

  3. 视频教程-Kali Linux渗透测试基础入门到进阶实战全程课-渗透测试

    Kali Linux渗透测试基础入门到进阶实战全程课 本人有多年的服务器高级运维与开发经验,擅长计算机与服务器攻防及网络攻防技术!对网络安全领域有持续的关注和研究! 林晓炜 ¥499.00 立即订阅 ...

  4. Android实战技巧:深入解析AsyncTask

    AsyncTask的介绍及基本使用方法 关于AsyncTask的介绍和基本使用方法可以参考官方文档和Android实战技巧:多线程AsyncTask这里就不重复. AsyncTask引发的一个问题 上 ...

  5. 《内网安全攻防:渗透测试实战指南》读书笔记(一):内网渗透测试基础

    目录 前言 一.内网基础知识 1.工作组 2.域 3.活动目录 (1)活动目录的功能 (2)DC和AD区别 4.安全域的划分 (1)DMZ (2)内网 5.域中计算机的分类 6.域内权限 (1)组 ( ...

  6. Android测试(二):Android测试基础

    原文地址:https://developer.android.com/training/testing/fundamentals.html 用户在不同的级别上与你的应用产生交互.从按下按钮到将信息下载 ...

  7. JavaScript 测试系列实战(一):使用 Jest 和 Enzyme 测试 React 组件

    你或许早已经知道"单元测试""端到端测试"这些名词,但从未真正付诸实践.在这一系列实战教程中,我们将手把手带你掌握 Jest.Enzyme.Cypress 等测 ...

  8. Android实战技巧之十一:Android Studio和Gradle

    2019独角兽企业重金招聘Python工程师标准>>> 经过两个多月的AS体验,我认为是时候将Android的开发环境迁移到AS上了.目前最新版本是1.0.2(大年30当天升级到1. ...

  9. 《软件测试技术大全:测试基础 流行工具 项目实战(第3版)》—第1章1.2节软件测试的发展...

    本节书摘来自异步社区<软件测试技术大全:测试基础 流行工具 项目实战(第3版)>一书中的第1章,第1.2节软件测试的发展,作者陈能技 , 黄志国,更多章节内容可以访问云栖社区"异 ...

最新文章

  1. Java中 实体类 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念
  2. 部署项目到阿里云服务器上遇到的问题
  3. crudandroidandroid——CRUD(在上一篇博客的基础上)
  4. ExtJS 2.0官方实例目录
  5. mysql插入日期 vs oracle插入日期
  6. 远东传动收购机器人_一张图为你总结最近5年在机器人领域收购案例
  7. html img图片等比例缩放_我掏空了各大搜索引擎,整理了HTML图片标签笔记,满满干货...
  8. 技校考大专单招计算机考试,高职单招题简单吗 单招一般考什么科目
  9. mysql的sql性能分析器
  10. 操作记录-2020-11-13:精简代码处理ChIP_seq数据
  11. VOC2007数据集详细分析
  12. 马知恩周义仓编常微分方程定性与稳定性方法部分习题参考解答
  13. npm WARN deprecated
  14. pygame编写飞机大战(9)-播放爆炸动画
  15. struck(结构化SVM用于视觉跟踪)--源代码详解--main.cpp
  16. 基本数据类型一题解析:已知m=11,n=41,输出m和n的2次方、3次方、4次方。(附代码)
  17. 【团体天梯赛/PTA】7-34 福到了 (15 分)
  18. 机器学习之GD、SGD
  19. Tensorflow2.0之用遗传算法优化卷积神经网络结构 Version2
  20. 1646 获取生成数组中的最大值(模拟)

热门文章

  1. 简单分析为什么知识要付费
  2. 树莓派远程视频监控的移植pistreaming
  3. Python爬虫自学系列(五)
  4. Jetpack架构组件 (一)-- Android Jetpack 简介
  5. 电脑无法打开Office提示很抱歉,此功能看似已中断解决办法
  6. RESTFUL API API身份认证
  7. 上班族怎么创业?白领一族创业当老板!
  8. 网络丢包,网络延迟?这款神器帮你解决所有
  9. Linux安装Chrome及依赖解决
  10. office2016 你个小贱人