Root你的设备(二)

理论上Root权限是系统的超级用户权限,Root之后的手机什么都能操作。这也就使得很多恶意应用与很多安全应用都在争夺Root权限,来完成自己的一些高权限的操作。当然,这些高权限的操作一些确实给用户带来了方便,但是,更多的Root后的操作往往是恶意的。这节我们具体看看对Root之后的设备,一般都能会有些什么操作。

1.1.1  静默安装

静默安装,指的是安装时无需任何用户干预,直接按默认设置安装应用。因为,它的无需用户干预,很多情况下变成了用户压根不知道,应用不知不觉就安装上了。是在推广上极为流氓的手段,很类似PC上的捆绑安装。正因为静默安装时极为流氓的推广行为,所以,其推广价格也极其高。

 

Android应用安装有如下四种方式

安装形式

完成方式

系统应用安装

开机时完成,需要加入开机执行的脚本,没有安装界面

网络下载应用安装

通过系统market应用完成,没有安装界面

ADB工具中进行安装

使用pm install命令,没有安装界面。

第三方应用安装

通过SD卡里的APK文件安装,有安装界面,由PackageInstaller.apk应用处理安装及卸载过程的界面。

 

 

应用安装的流程及路径

目录

主要功能

/system/app

系统自带的应用程序存放,Root权限才可更改

/data/app

用户程序安装的目录,有删除权限。安装时把apk文件复制到此目录

/data/data

存放应用程序的数据

Data/dalvik-cache

将apk中的dex文件安装到dalvik-cache目录下

 

 

安装过程

复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。

 

 

卸载过程

删除安装过程中在上述三个目录下创建的文件及目录。

 

 

 

Google的安全策略要求任何应用在安装确认的时候应该提示APK安装包的权限,即确认开发者在AndroidManafest.xml中声明的权限。当然,Google在Android上也做了一些操作,允许一些系统内部的应用不经过授权界面直接进行安装。而系统进入安装界面其实也是根据此intent跳转到了PackageInstaller应用来完成权限的提示与安装的。

我们在应用程序中控制安装应用APP,其实就是发送一个如下的intent。去调用packageinstaller进行安装,具体的操作代码如下:

 

/* 安装apk */

Intent intent = new Intent();

intent.setAction(Intent.ACTION_VIEW);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setDataAndType(Uri.parse("file://"+ fileName),

   "application/vnd.android.package-archive");

context.startActivity(intent);

 

对比应用正常安装的流程,静默安装的本质就是去掉如下图所示的用户授权同意安装的过程,直接进行应用安装。

 Root你的设备(二)_第1张图片


 

阅读过源码后我们知道,系统的安装过程其实是调用了系统中的PackageInstaller来完成的。希望做到静默安装,就是找到一个方法,绕过PackageInstaller中的权限授予提示,继续完成安装的步骤。

所以,思路很简单,我们可以从两方面去操作:

l  找到PackageInstaller源码,跳过权限授予提醒,直接调用后面的安装API即可完成安装。(这样能够良好的兼容正常安装,不易出错)

l  使用pm install 命令进行安装。

 

1.1.1.1 调用PackageInstaller中隐藏的API

查看PackageInstaller源码我们能够发现,其实PackageInstaller也是通过使用PackageManager进行安装的。调用的是其installPackage方法,但是此方法是一个abstract,且是对外不可见的(hide),定义如下所示:

 

public abstractclass PackageManager {

………

/**

 * 安装应用APK文件

 * @param packageURI 待安装的APK文件位置,可以是'file:'或'content:' URI.

 * @param observer 一个APK文件安装状态的观察器

 * @param flags 安装形式 INSTALL_FORWARD_LOCK, INSTALL_REPLACE_EXISTING, INSTALL_ALLOW_TEST.

 * @paraminstallerPackageName APK安装包的PackageName

 */

// @SystemApi

public abstract void installPackage(UripackageURI, PackageInstallObserverobserver,int flags,

        StringinstallerPackageName);

}

   

且PackageManager与installPackage两者皆为abstract抽象的。其具体实现都在ApplicationPackageManager中,其installPackage中的实现为:

 

final classApplicationPackageManager extends PackageManager {

   ......

   

   ApplicationPackageManager(ContextImpl context, IPackageManager pm) {

       mContext = context;

        mPM = pm;

   }

 

   @Override

   public void installPackage(Uri packageURI, IPackageInstallObserver observer,intflags, String installerPackageName){

        try {

            mPM.installPackage(packageURI, observer, flags, installerPackageName);

        } catch (RemoteException e) {

            // Should never happen!

        }

   }

}

 

 

可见调用的installPackage方法为IPackageManager中的installPackage方法。在ContextImpl中通过调用ActivityThread.getPackageManager()获得IPackageManager实例对象。而在在ActivityThread.getPackageManager()方法中,是调用SystemService中的名为package的Service来实例化的。代码如下:

 

staticIPackageManager sPackageManager;

 

public staticIPackageManager getPackageManager() {

   if (sPackageManager != null) {

        return sPackageManager;

   }

   IBinder b = ServiceManager.getService("package");

   sPackageManager = IPackageManager.Stub.asInterface(b);

   return sPackageManager;

}

因为,installPackage是系统的API,为了使用PackageManagerService.installPackage(),考虑通过反射机制可以调用installPackage(),但其中难以得到的是其参数中的IPackageInstallObserver类型,我们看来一下IPackageInstallObserver,发现IPackageInstallObserver是由aidl文件定义的。这个也难不倒我们,通过aidl文件的特性,将IPackageInstallObserver.aidl文件拷到本地程序中,可以得到类IPackageInstallObserver.calss,通过它反射出installPackage()方法。但在invoke调用该方法时,却无法得到IPackageInstallObserver的实例对象,IPackageInstallObserver的实例对象必须通过IPackageInstallObserver.Stub.asInterface(Binder binder)方式得到,无法得到与其绑定的Binder对象,因而无法执行反射出来的方法。

其次,应为是系统API,需要声明安装应用的权限:android.permission.INSTALL_PACKAGES。当时这类比较敏感的权限不是说声明系统就会给予的,还需要我们的安装包APK文件拥有与系统相同的签名,才能完成静默安装操作。这个方式的静默安装,对于广泛的推广应用是不现实的。

 

 

1.1.1.2 使用pm命令安装

pm 命令是Android里面PackageManage的命令行,用于安装包的操作。而系统也主要是提供我们在adb shell中进行使用pm命令,因此pm命令也存在与“/system”目录下,当然,拥有了Root权限后的应用程序就能够使用它进行静默安装了。

具体的操作代码如下所示:

 

// xxx.apk放置在内置储存的根目录下

execCommand("system/bin/pminstall -r " + "sdcard/xxx.apk");

// 执行command

public booleanexecCommand(String cmd) {

   Process process = null;

   try {

        process = Runtime.getRuntime().exec(cmd);

        process.waitFor();

   } catch (Exception e) {

        return false;

   } finally {

        try {

           process.destroy();

        } catch (Exception e) {

        }

   }

   return true;

}

 

pm命令源码目录:/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java,我们查看其源码,如下:

 

public finalclass Pm {

   IPackageManager mPm;

   IUserManager mUm;

 

   private WeakHashMap<String, Resources> mResourceCache

            = new WeakHashMap<String, Resources>();

 

   private String[] mArgs;

   private int mNextArg;

   private String mCurArgData;

 

   private static final String PM_NOT_RUNNING_ERR =

        "Error: Could not access thePackage Manager.  Is the systemrunning?";

 

   public static void main(String[] args) {

        new Pm().run(args);

   }

 

   /**

    * 解析命令参数

    * @param args 参数

    */

   public void run(String[] args) {

        boolean validCommand = false;

        if (args.length < 1) {

            showUsage();

            return;

        }

 

        mUm =IUserManager.Stub.asInterface(ServiceManager.getService("user"));

        mPm =IPackageManager.Stub.asInterface(ServiceManager.getService("package"));

        if (mPm == null) {

           System.err.println(PM_NOT_RUNNING_ERR);

            return;

        }

 

 

        ......

 

        if("install".equals(op)) {

            runInstall();

            return;

        }

 

        ......

   }

   

   /**

    * 开始安装

    */

   private void runInstall() {

        ......

 

        // 安装逻辑的具体调用

        PackageInstallObserver obs = newPackageInstallObserver();

        try {

            VerificationParamsverificationParams = new VerificationParams(verificationURI,

                    originatingURI, referrerURI, VerificationParams.NO_UID,null);

           

           mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,

                    installerPackageName, verificationParams, encryptionParams);

 

            synchronized (obs) {

                while (!obs.finished) {

                    try {

                        obs.wait();

                    } catch(InterruptedException e) {

                    }

                }

                if (obs.result ==PackageManager.INSTALL_SUCCEEDED) {

                   System.out.println("Success");

                } else {

                    System.err.println("Failure["

                            +installFailureToString(obs.result)

                            + "]");

                }

            }

        } catch (RemoteException e) {

            System.err.println(e.toString());

           System.err.println(PM_NOT_RUNNING_ERR);

        }

   }

   

   ......

}

 

         发现其实pm命令也是调用了PackageManager中的安装方法,只不过是一个验证和加密的方法installPackageWithVerificationAndEncryption进行安装的。即,它的安装过程与PackageInstaller是一样的。

而我们安装应用APP的时候,可以是自己的APK安装包文件存储在两个地方“data/app”与“system/app”下,静默安装的时候一般情况都是选择将自己的APK文件push到“system/app”目录下, 因为此目录是系统应用的目录,在此目录下的恶意应用,进行偷发短信、窃取邮件等操作,用户是很难察觉的。

 

1.1.2  删除预装

大部分的普通用户Root手机的主要目的就是删除系统预先安装的应用程序,要删除它们,我们首先要知道什么是预装应用,它们存放在哪里。或者我们换一个思路来看看,系统制造商将应用程序的APK文件存放在哪里才能变为系统的应用。

1.        系统默认的常规应用存放处

Android系统的捆绑应用软件基本安装在“/system/app”文件夹下,删除下面的对应的了第三方软件APK文件即可完美卸载。我们知道“/system”是系统的目录,对此目录进行操作需要Root权限,所以我们删除预装应用需要Root手机。每个系统程序基本上都是成对的,对应的删除掉后缀分别是.apk 和.odex(优化过的dex文件)文件即可删除预装应用。

如下图,使用了Root Explorer查看“/system/app”目录。则能够看到了系统中的所有的系统内置应用程序。

Root你的设备(二)_第2张图片

2.        修改系统引导的预装

对于存放Apk文件到”/system/app“目录下已经是很普通的预装方式了,这就导致了,预装应用很容易就被卸载掉。恶意的手机ROM就会想着更加恶心的方法来留住预装应用,比如修改系统ROM的逻辑,让系统在开机的时候检测一下自己的预装是否完整然后重新安装。那么,当然系统预装应用的安装文件也会在另一个保存一份。

         这类的预装应用,又称为“开机静默安装”,常用的方式就是修改init.rc,添加一个开机执行的脚本,在脚本中调用一个Service使用pm install命令批量安装应用。如,自顶一个一个init.local.rc内容如下:

 

#Preinstall

onproperty:dev.bootcomplete=1

         start loadpreinstalls

 

serviceloadpreinstalls /system/bin/logwrapper /system/bin/loadpreinstalls.sh

         disabled

         oneshot

 

         在系统的init.rc脚本中调用init.local.rc如下:

 

#在sysinit前面加

# Include extrainit file

             import /system/etc/init.local.rc

        

         而具体的预装脚本存在/system/bin/ loadpreinstalls.sh

 

# do preinstall job

if [ ! -e /data/.notfirstrun ]

then

echo "dopreinstall sys" >> /system/log.txt

#安装/system/preinstall下的所有apk文件

    APKLIST=`ls /system/preinstall/*.apk`

   for INFILES in $APKLIST

   do

     echo  setup package:$INFILES

     pm install -r $INFILES

   done

 

echo "dopreinstall sd" >> /system/log.txt

#安装/sdcard/preinstall下的所有apk文件

   APKLIST=`ls /sdcard/preinstall/*.apk`

   for INFILES in $APKLIST

   do

     echo  setup package:$INFILES

     pm install -r $INFILES

   done

   echo "do preinstall ok" >> /system/log.txt

   busybox touch /data/.notfirstrun   

fi

 

echo "============================================">> /system/log.txt

exit

 

         此方式做预装用户在使用Root后删除掉/system/app下的已安装应用后,系统重启后又会执行启动脚本自动重装预装应用回来,且预装apk文件的存放目录根据不同的系统ROM还不一样,是极为流氓的推广策略。当然,我们通过分析已经看到了,如果要删除此类的预装应用,只需要全盘的扫描apk文件再进行删除即可。

 

1.1.3  键盘监控

键盘监控,顾名思义是在应用软件在运行时,用户在设备上的一举一动都将被详细记录下来,更多的实在使用者毫无觉察的情况下将屏幕内容以图片的形式、按键内容以文本文档的形式保存在指定的文件夹或发送到指定的邮箱。键盘监控,包括物理按键与软键盘的监控,通常监控的事件有:点击,长按,滑动等,这些时间在Android上表现出来的都是一系列的KeyEvent。

为了实现键盘的监控,从新开发一个输入法是不现实的,一般的操作就是在系统的输入法机制中添加接口回调。我们知道,再应用程序中拿到按键的回调一般是监听onKeyDown的接口,如下所示:

 

public boolean onKeyDown(int keyCode, KeyEvent event)

 

开发者就可以根据回调方法中的参数, keyCode与KeyEvent来判断具体事件。但是,由于事件的回调机制在其的沙箱中运行,在其他应用中是无法拿到当前应用事件回调的。

那么我们就从上到下,具体的看看事件的传递机制。如下图所示,用户点击后,软键盘或物理按键的输入驱动就会产生一个中断,且向/dev/input/event*中写入一个相应的信号量。Android操作系统则会循环的读取其中的事件,再分发给WindowManagerServer。由WindowManagerServer根据事件的来源分发到各个不同的ViewGroup与View中,从而产生不同的OnClick、OnKeyDown和OnTouch等事件。

Root你的设备(二)_第3张图片

 

这个时候很自然的想到,黑客们希望做键盘监控,一定会向Linux底层增加自定义的事件。这里我们使用的是Linux中的getevent获得/dev/input/eventX设备汇报的事件,这个命令还会输出所有event设备的基本信息。包括触屏、按键、耳机插入等等。其基本用法如下:

Usage: getevent [-t] [-n] [-sswitchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]

   -t: show time stamps

   -n: don't print newlines

   -s: print switch states for given bits

   -S: print all switch states

   -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32,props=64)

   -d: show HID descriptor, if available

   -p: show possible events (errs, dev, name, pos. events)

   -i: show all device info and possible events

   -l: label event types and names in plain text

   -q: quiet (clear verbosity mask)

   -c: print given number of events then exit

   -r: print rate events are received

        

 

键入getevent后,我们能够看到设备中的一些列输入硬件驱动信息,同样下面会出现很多输入指令信号,通常情况下,这些信号量都在刷屏,如下图所示:

图4‑7

 

这些信号量的表示我们无法直接看懂,输入getevent –l加入Label我们能够看到一些添加的标签,如下所示:

图4‑8

其实这些Lable已经在其input.h头文件中定义好,其中type的定义如下:

 

   /* 

    * Event types 

    */ 

   #define EV_SYN          0x00 

   #define EV_KEY          0x01 

   #define EV_REL          0x02 

   #define EV_ABS          0x03 

   #define EV_MSC          0x04 

   #define EV_SW           0x05 

   #define EV_LED          0x11 

   #define EV_SND          0x12 

   #define EV_REP          0x14 

   #define EV_FF           0x15 

   #define EV_PWR          0x16 

   #define EV_FF_STATUS       0x17 

   #define EV_MAX          0x1f 

   #define EV_CNT         (EV_MAX+1) 

 

一般来说,常用的是EV_KEY、EV_REL、EV_ABS、EV_SYN,分别对应键盘按键、相对坐标、绝对坐标、同步事件。EV_SYN则表示一组完整事件已经完成,需要处理,EV_SYN的code定义事件分发的类型。

 

在触摸事件上的几个常见的Label说明如下表所示:

 

标签名

说明

ABS_X

对应触摸屏的X坐标

ABS_Y

对应触摸屏的Y坐标

ABS_PRESSURE

压力值,一般触摸屏也只是区分是否有按下去,按下去的话值会大于多少,没有按的话值小于多少。

ABS_TOOL_WIDTH

触摸工具的宽度

ABS_MT_POSITION_X

接触面的形心的X坐标值

ABS_MT_POSITION_Y

接触面的形心的Y坐标值

ABS_MT_TOUCH_MAJOR

触摸手指大小

ABS_MT_WIDTH_MAJOR

触摸面积大小

表4‑1

 

了解了这些Label的含义我们再看看信号量就简单多了,如我们列举几个常见的事件与信号,如下表所示:

操作

输出信号

按下电源键

/dev/input/event0: EV_KEY       KEY_POWER            DOWN
/dev/input/event0: EV_SYN       SYN_REPORT           000000
/dev/input/event0: EV_KEY       KEY_POWER            UP
/dev/input/event0: EV_SYN       SYN_REPORT           000000

音量键下

/dev/input/event8: EV_KEY       KEY_VOLUMEDOWN       DOWN

/dev/input/event8: EV_SYN       SYN_REPORT           00000000

/dev/input/event8: EV_KEY       KEY_VOLUMEDOWN       UP

/dev/input/event8: EV_SYN       SYN_REPORT           00000000

音量键上

/dev/input/event8: EV_KEY       KEY_VOLUMEUP         DOWN

/dev/input/event8: EV_SYN       SYN_REPORT           00000000

/dev/input/event8: EV_KEY       KEY_VOLUMEUP         UP

/dev/input/event8: EV_SYN       SYN_REPORT           00000000

按下物理按键“1”

/dev/input/event0: EV_KEY       KEY_1                DOWN

/dev/input/event0: EV_KEY       KEY_1                UP

按下物理按键“q”

/dev/input/event0: EV_KEY              KEY_Q                DOWN
/dev/input/event0: EV_KEY          KEY_Q                UP

按下软键盘上的“q”字母

/dev/input/event0: EV_ABS       ABS_X                0000001b

/dev/input/event0: EV_ABS       ABS_Y                000001d5

/dev/input/event0: EV_KEY       BTN_TOUCH            DOWN

/dev/input/event0: EV_SYN       SYN_REPORT           00000000

/dev/input/event0: EV_KEY       BTN_TOUCH            UP

/dev/input/event0: EV_SYN       SYN_REPORT           00000000

按下软件键盘上的的“1”按键

/dev/input/event0: EV_ABS       ABS_X                00000019

/dev/input/event0: EV_ABS       ABS_Y                000001d7

/dev/input/event0: EV_KEY       BTN_TOUCH            DOWN

/dev/input/event0: EV_SYN       SYN_REPORT           00000000

/dev/input/event0: EV_KEY       BTN_TOUCH            UP

/dev/input/event0: EV_SYN       SYN_REPORT           00000000

表4‑2

 

从上表中,我们发现要是按下的是物理按键,其输入出来的信息我们很容易读懂,如果按下的是软键盘中的按键,给出的信号信息就是一些位置坐标信息。我们无法直接读懂,当然,我们可以根据这些位置坐标信息,再拿到Android设备的屏幕尺寸,计算比例也能够直接获得按键的具体内容。

当然,输出条件不会是想我们表格中的这么规范,中间会夹杂则各式各样的信息,有些可能是你不关心的。这里我们把一些无关的信号量过滤去掉了。实际查看上对应信息条件比较多,大家可以将Android设备连接如自己的电脑进行调试,这里我们就不做一一的解释了。

所以,为了安全起见,很多对于输入安全要求比较高的应用软件,除了自定义输入法进行安全输入以外,还需要将键盘上的各个字母数字位置随机打乱,防止黑客们在截获了位置信息后进行按键计算。这个也就是我们常在一些软件中看到打乱的键盘原因,打乱键盘效果如下图所示:

Root你的设备(二)_第4张图片

 

 

getevent是一个系统级命令,需要在Root情况下才可以使用。这里我们对getevent作为阐述,的主要目的就是告诉大家,在Root后的Android设备中,我们可以使用对Linux底层信号做读取的方式,对设备进行键盘监控。当然,更可以使用sendevent命令,模拟发送事件,这里我们不做阐述了。

 

 Root你的设备(二)_第5张图片

 

 

 

1.1.4  短信拦截与发送

短信拦截

 

其实短信拦截与获取Root权限的关系不是特别的大,我们知道Android系统接收到短信的时候会发送出来一个系统广播,即非Root的手机也能收到此广播。但是,由于短信拦截的危害性还比较大,我们也在此作为例子说明。

而广播有两种不同的类型:普通广播(Normal Broadcasts)和有序广播(OrderedBroadcasts)。普通广播是完全异步的,可以被所有的接收者接收到,并且接收者无法终止广播的传播,而有序广播是按照接收者声明的优先级别,被接收者依次接收到。 由于短信广播是一种有序广播,该有序广播会先发送给优先级最高的那个Receiver,这样就提供给我们了一个利用优先级的方式。声明一个高优先级的广播接收器,去过滤拦截短信。如下代码就是声明一个优先级为9999的短信广播接收器SmsReceiver。

 

<receiverandroid:name=".SmsReceiver"> 

          <intent-filterandroid:priority="9999"> 

              <actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/> 

          </intent-filter> 

 </receiver>

 

如下,我们在接收后的SmsReceiver做走一些拦截操作。

 

public classSmsReceiver extends BroadcastReceiver {

   @Override

   public void onReceive(Context context, Intent intent) {

        // 判断是系统短信;

        if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){

            StringBuffer msgText = newStringBuffer();

            String sender = null;

            Bundle bundle = intent.getExtras();

            if (bundle != null) {

                // 通过pdus获得接收到的所有短信消息,获取短信内容;

                Object[] pdus = (Object[])bundle.get("pdus");

                // 构建短信对象数组;

                SmsMessage[] mges = newSmsMessage[pdus.length];

                for (int i = 0; i< pdus.length; i++) {

                    // 获取单条短信内容,以pdu格式存,并生成短信对象;

                    mges[i] =SmsMessage.createFromPdu((byte[]) pdus[i]);

                }

                for (SmsMessage mge :mges) {

                    msgText.append("短信来自:" + mge.getDisplayOriginatingAddress() +"\n");

                    msgText.append("短信内容:" + mge.getMessageBody());

 

                    if("5555".equals(sender)) {

                        // 屏蔽手机号为5555的短信

                        // 这里还可以时行一些处理,如把该信息发送到第三人的手机等等。

                        abortBroadcast();

                    }

                }

                // 显示信息

                Toast.makeText(context, msgText.toString(), Toast.LENGTH_LONG).show();

            }

        }

   }

}

 

短信静默发送

短息静默发送,即短信在不通过用户的许可之下在后台静默地发送以达到扣费的目的。2014年底的时候有一款比较可爱的病毒 “xx神器”,就是通过短信传播造成用户话费损失的。“xx神器”就是在节日前后以朋友的名义发送的病毒类短信,很多Android用户都中招了,之后还被各大媒体所报道确实让“xx神器”火了一把。为什么说它可爱,是在我们真的拿到了“xx神器”病毒样本来看的时候,其实现逻辑之粗暴简单确实让我们觉得惊讶。

在Android系统里,希望发动短信的话,一般都是通过调用系统的SmsManager中的sendTextMessage方法来完成。

        

 

1.1.5  电话监控

曾经名噪一时的著名病毒“X卧底”应用软件就是以监控用户的手机的通话记录及短信而出名的,这款应用软件网上疯狂流传,甚至还产生了自己的一套盈利模式。在手机里安装该软件后,就能够远程监听该手机的通话,发送和接收的短信也可以在互联网上查阅。

 

TelephonyManager中的方法是针对设备同通话的封装,常用的方法有dial(拨号界面)、call(直接通话)、endCall(结束通话)、answerRingingCall(接听通话),其API是不对系统外的应用外开放的(注解为@Systemapi的方法)。但是,开发者们仍然能够通过Java中的反射方法去调用其接口完成通话直接拨打电话。如下代码,只需要在AndroidManifest.xml中声明CALL_PHONE权限然后调用call方法,就能够在不经过用户允许授权的情况下,进行电话拨打。

 

private voidcall(String number) {

   Class<TelephonyManager> c = TelephonyManager.class;

   Method getITelephonyMethod = null;

   try {

// setAccessible(true) 跳过java中的private方法的反射权限检查

// 及我们能够在外部调用private方法而不报错

        getITelephonyMethod =c.getDeclaredMethod("getITelephony", (Class[])null);

        getITelephonyMethod.setAccessible(true);

   } catch (SecurityException e) {

        e.printStackTrace();

   } catch (NoSuchMethodException e) {

        e.printStackTrace();

   }

 

   try {

        TelephonyManager tManager =(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

        Object iTelephony;

        iTelephony = (Object)getITelephonyMethod.invoke(tManager,(Object[])null);

// 反射 call方法

        Method dial =iTelephony.getClass().getDeclaredMethod("call", String.class);

        dial.invoke(iTelephony, number);

   } catch (IllegalArgumentException e) {

        e.printStackTrace();

   } catch (IllegalAccessException e) {

       e.printStackTrace();

   } catch (SecurityException e) {

        e.printStackTrace();

   } catch (NoSuchMethodException e) {

        e.printStackTrace();

   } catch (InvocationTargetException e) {

        e.printStackTrace();

   }

}

 

         当然,不经过用户的同意拨打电话的方式比较流氓,而且收益不会很大,很多恶意木马不会这么做。如上述所说的“X卧底”类的恶意程序,更多的是在窃取用户的通话记录,有些还会在通话的时候进行录音。在Android系统中进行电话监控也是很容易的事情,只需要在TelephonyManager中如果注册了PhoneStateListener就能够拿到当前通话状态的变化,当然也能做相应处理。

 

 

// 注册监听通话状态

TelephonyManager telephoneyManager =(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

telephoneyManager.listen(newMyPhoneCallListener(),PhoneStateListener.LISTEN_CALL_STATE);

   

/**

 * 监控电话的具体实现

 */

public classMyPhoneCallListener extends PhoneStateListener

{

   @Override

   public void onCallStateChanged(int state, String incomingNumber)

   {

        switch (state)

        {

            // 电话通话的状态

            caseTelephonyManager.CALL_STATE_OFFHOOK:                 

            break;

            // 电话响铃的状态

            caseTelephonyManager.CALL_STATE_RINGING:                  

            break;

            // 空闲中

            caseTelephonyManager.CALL_STATE_IDLE:

            break;

        }

        super.onCallStateChanged(state, incomingNumber);

   }

}

 

“X卧底”是一个专门对手机进行远程监控的病毒,主要是对通话录音、通话记录、短信进行监控。“X卧底”提取用户隐私后将隐私想用户贩卖,已经形成了自己的盈利模式。其实,Android上的“X卧底”就是用到了上述的TelephonyManager的PhoneStateListener来进行监听,“X卧底”手机通话监控的原型图如下图所示:

Root你的设备(二)_第6张图片



/**
 * @author zhoushengtao(周圣韬)
 * @since 2015年1月27日 上午14:02:22
 * @weixin stchou_zst  Root你的设备(二)_第7张图片

 * @blog http://blog.csdn.net/yzzst

 * @交流学习QQ群:341989536

 * @私人QQ:445914891
 */



你可能感兴趣的:(Root你的设备(二))