Android 鍵盤監控的實現原理及過程

stchou的專欄發表於2015-05-18

鍵盤監控

鍵盤監控,顧名思義是在應用軟體在執行時,使用者在裝置上的一舉一動都將被詳細記錄下來,更多的實在使用者毫無覺察的情況下將螢幕內容以圖片的形式、按鍵內容以文字文件的形式儲存在指定的資料夾或傳送到指定的郵箱。鍵盤監控,包括物理按鍵與軟鍵盤的監控,通常監控的事件有:點選,長按,滑動等,這些時間在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命令,模擬傳送事件,這裡我們不做闡述了。

相關文章