Android 键盘监控的实现原理及过程
键盘监控
键盘监控,顾名思义是在应用软件在运行时,用户在设备上的一举一动都将被详细记录下来,更多的实在使用者毫无觉察的情况下 将屏幕内容以图片的形式、按键内容以文本文档的形式保存在指定的文件夹或发送到指定的邮箱。键盘监控,包括物理按键与软键盘的监控,通常监控的事件有:点 击,长按,滑动等,这些时间在Android上表现出来的都是一系列的KeyEvent。
为了实现键盘的监控,从新开发一个输入法是不现实的,一般的操作就是在系统的输入法机制中添加接口回调。我们知道,再应用程序中拿到按键的回调一般是监听onKeyDown的接口,如下所示:
public boolean onKeyDown(int keyCode, KeyEvent event)
开发者就可以根据回调方法中的参数, keyCode与KeyEvent来判断具体事件。但是,由于事件的回调机制在其的沙箱中运行,在其他应用中是无法拿到当前应用事件回调的。
那么我们就从上到下,具体的看看事件的传递机制。如下图所示,用户点击后,软键盘或物理按键的输入驱动就会产生一个中断,且向/dev/input /event*中写入一个相应的信号量。Android操作系统则会循环的读取其中的事件,再分发给WindowManagerServer。由 WindowManagerServer根据事件的来源分发到各个不同的ViewGroup与View中,从而产生不同的OnClick、 OnKeyDown和OnTouch等事件。
这个时候很自然的想到,黑客们希望做键盘监控,一定会向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后,我们能够看到设备中的一些列输入硬件驱动信息,同样下面会出现很多输入指令信号,通常情况下,这些信号量都在刷屏,如下图所示:
这些信号量的表示我们无法直接看懂,输入getevent –l加入Label我们能够看到一些添加的标签,如下所示:
其实这些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 | 触摸面积大小 |
了解了这些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 |
从上表中,我们发现要是按下的是物理按键,其输入出来的信息我们很容易读懂,如果按下的是软键盘中的按键,给出的信号信息就是一些位置坐标信息。我 们无法直接读懂,当然,我们可以根据这些位置坐标信息,再拿到Android设备的屏幕尺寸,计算比例也能够直接获得按键的具体内容。
当然,输出条件不会是想我们表格中的这么规范,中间会夹杂则各式各样的信息,有些可能是你不关心的。这里我们把一些无关的信号量过滤去掉了。实际查看上对应信息条件比较多,大家可以将Android设备连接如自己的电脑进行调试,这里我们就不做一一的解释了。
预防键盘监控
所以,为了安全起见,很多对于输入安全要求比较高的应用软件,除了自定义输入法进行安全输入以外,还需要将键盘上的各个字母数字位置随机打乱,防止黑客们在截获了位置信息后进行按键计算。这个也就是我们常在一些软件中看到打乱的键盘原因,打乱键盘效果如下图所示:
getevent是一个系统级命令,需要在Root情况下才可以使用。这里我们对getevent作为阐述,的主要目的就是告诉大家,在Root后 的Android设备中,我们可以使用对Linux底层信号做读取的方式,对设备进行键盘监控。当然,更可以使用sendevent命令,模拟发送事件, 这里我们不做阐述了。
来源: stchou的专栏