有很多游戲玩家會用到按鍵精靈類軟件,通過定制腳本來完成任務(wù)
也有很多人惡意作弊,通過定時腳本多線程觸發(fā)第一時間搶到禮包 紅包
有不少公司利用按鍵精靈自動化操作來完成各種商業(yè)目的
也有很多公司為了防住按鍵精靈等軟件苦思各種對策
等等
這篇文章的目的:純討論技術(shù),不涉及灰色黑色產(chǎn)業(yè),特此申明。
有哪一些方式可以實現(xiàn)?
Instrumentation? 需要系統(tǒng)簽名,這就明你只能自行編譯android系統(tǒng)。并且只能在你點擊軟件處于前臺的時候才能處理,切換到別的app成為后臺后就無法處理了。
IWindowManager? IWindowManager里面的模擬按鍵和觸摸事件的api,這類方法在很早版本就被google屏蔽了,想嘗試通過反射繞過java的權(quán)限限制非常麻煩,而且很可能最后又被系統(tǒng)權(quán)限給攔住了。
按鍵精靈類軟件。它們都是在root環(huán)境下使用的,不需要系統(tǒng)簽名,不需要運行在前臺,完美滿足通過代碼來模擬點擊的行為。
按鍵精靈的觸摸原理分析
Android的touch系統(tǒng)架構(gòu)簡圖(省略了一些過程,包括windowManagerService的一些過程,有興趣同學(xué)可以查看相關(guān)實現(xiàn))
觀察整個Android的touch分發(fā)流程,在最開始的時候,用戶觸摸屏幕,對/dev/input/event寫入信號量。Android系統(tǒng)循環(huán)讀取里面的輸出,在進(jìn)行向下分發(fā)。那么我們站在黑客的角度思考下,按鍵精靈類軟件是root過的,最好的方式就是自定義linux的觸摸事件,不斷發(fā)送到/dev/input/event,從而順理成章的模擬了android系統(tǒng)的點擊行為。
Linux命令 getevent sendevent 備好一臺root過的android手機(jī)
一、getevent
1 在adb shell下面輸入 getevent后,我們就能看到設(shè)備輸入的硬件信息
dwlovehcy@bogon:~/OpenSource$ adb devices
List of devices attached
192.168.82.226:5555 device
dwlovehcy@bogon:~/OpenSource$ adb shell
shell@OnePlus2:/ $ getevent
add device 1: /dev/input/event8
name: "msm8994-tomtom-mtp-snd-card Headset Jack"
add device 2: /dev/input/event7
name: "msm8994-tomtom-mtp-snd-card Button Jack"
add device 3: /dev/input/event4
name: "qpnp_pon"
add device 4: /dev/input/event2
name: "STM VL6180 proximity sensor"
could not get driver version for /dev/input/mouse1, Not a typewriter
add device 5: /dev/input/event1
name: "fpc1020tp"
could not get driver version for /dev/input/mouse0, Not a typewriter
add device 6: /dev/input/event0
name: "fpc1020"
could not get driver version for /dev/input/mice, Not a typewriter
add device 7: /dev/input/event6
name: "gpio-keys"
add device 8: /dev/input/event3
name: "synaptics,s1302"
add device 9: /dev/input/event5
name: "synaptics,s3320"
2 嘗試點擊一次屏幕,看看shell的輸出:
/dev/input/event5: 0003 0039 0000001c
/dev/input/event5: 0001 014a 00000001
/dev/input/event5: 0003 0035 00000220
/dev/input/event5: 0003 0036 0000059e
/dev/input/event5: 0003 0030 00000006
/dev/input/event5: 0000 0000 00000000
/dev/input/event5: 0003 0039 ffffffff
/dev/input/event5: 0001 014a 00000000
/dev/input/event5: 0000 0000 00000000
分析:此手機(jī)的event5負(fù)責(zé)了這個單點事件,這里面包含了1個touchdown、1到多個touchmove和1個touchup。
3 按一下手機(jī)的鎖屏鍵:
/dev/input/event4: 0001 0074 00000001
/dev/input/event4: 0000 0000 00000000
/dev/input/event4: 0001 0074 00000000
/dev/input/event4: 0000 0000 00000000
分析:此手機(jī)的event4負(fù)責(zé)了這個鎖屏按鈕,里面包含一個按鍵的按下和放開
從上面2處可以看到,我們只要定義出類似的動作,就可以完成Android的單點點擊和鎖屏 {具體實現(xiàn)請具體看下文}
4 getevent的詳細(xì)用法
shell@OnePlus2:/ $ getevent -h
Usage: getevent [-t] [-n] [-s switchmask] [-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
其中-l可顯示event的定義,把剛才的輸入翻譯成指令集,我們使用-l并點擊一下屏幕獲得輸出:
/dev/input/event5: EV_ABS ABS_MT_TRACKING_ID 00000022
/dev/input/event5: EV_KEY BTN_TOUCH DOWN
/dev/input/event5: EV_ABS ABS_MT_POSITION_X 000001f2
/dev/input/event5: EV_ABS ABS_MT_POSITION_Y 0000058a
/dev/input/event5: EV_ABS ABS_MT_TOUCH_MAJOR 00000006
/dev/input/event5: EV_SYN SYN_REPORT 00000000
/dev/input/event5: EV_ABS ABS_MT_TRACKING_ID ffffffff
/dev/input/event5: EV_KEY BTN_TOUCH UP
/dev/input/event5: EV_SYN SYN_REPORT 00000000
點擊一下鎖屏鍵獲得輸出:
/dev/input/event4: EV_KEY KEY_POWER DOWN
/dev/input/event4: EV_SYN SYN_REPORT 00000000
/dev/input/event4: EV_KEY KEY_POWER UP
/dev/input/event4: EV_SYN SYN_REPORT 00000000
我們得到了更加詳細(xì)的輸出,而這些輸出跟linux的input.h的定義方式一樣,從字面上我們得出各種類型的含義,具體解釋可以參考linux的input.h
二、sendevent
1、sendevent這個命令可以使我們可以向root手機(jī)發(fā)送觸摸信號量,我們再次觀察下剛才getevent情況下鎖屏的輸出:
/dev/input/event4: 0001 0074 00000001
/dev/input/event4: 0000 0000 00000000
/dev/input/event4: 0001 0074 00000000
/dev/input/event4: 0000 0000 00000000
命令行輸入sendevent -h:
1|shell@OnePlus2:/ $ sendevent
use: sendevent device type code value
命令行提示我們需要發(fā)送device type 和 取值,根據(jù)觀察device type就是/dev/input/event4, 而value就是后面的例如:0001 0074 00000001(我們可以翻譯成十進(jìn)制來使用)
實際操作:
shell@OnePlus2:/ $ sendevent /dev/input/event4 1 116 1
shell@OnePlus2:/ $ sendevent /dev/input/event4 0 0 0
shell@OnePlus2:/ $ sendevent /dev/input/event4 1 116 0
shell@OnePlus2:/ $ sendevent /dev/input/event4 0 0 0
屏幕并沒有被鎖屏了,why,因為咋們輸入速度不夠快,中間有別的事件發(fā)生了或者超過了一系列時間的最大間隔~~~
咋們直接一起執(zhí)行這4個命令:
shell@OnePlus2:/ $ sendevent /dev/input/event4 1 116 1 & /dev/input/event4 0 0 0 & /dev/input/event4 1 116 0 &/dev/input/event4 0 0 0
屏幕順利被鎖定,HOHO,我們完成了最簡單的一個HACK
2、測試下觸摸,選擇桌面上一個app,打開getevent,記錄下這個過程中的信號量
/dev/input/event5: 0003 0039 00000030
/dev/input/event5: 0001 014a 00000001
/dev/input/event5: 0003 0035 00000225
/dev/input/event5: 0003 0036 000003b4
/dev/input/event5: 0000 0000 00000000
/dev/input/event5: 0003 0039 ffffffff
/dev/input/event5: 0001 014a 00000000
/dev/input/event5: 0000 0000 00000000
回到桌面,開始用sendevent來執(zhí)行,大家可以動手自己把這段用sendevent組合起來,一樣如預(yù)期,打開了剛才那個app。
Good job,我們能控制Android的單點點擊了
如何完成各種Android機(jī)型的適配?
1. 在完成上面的過程后,有想徹底搞懂的同學(xué)你會有以下幾個問題要問:
a、各種android手機(jī)對應(yīng)的單點event居然不一樣,甚至同廠家也是,怎么處理?
b、android手機(jī)多點觸摸怎么處理?
c、 android手機(jī)滑動怎么處理?
等等各種問題
2. 統(tǒng)一為這些問題做一個解答:
- 仔細(xì)閱讀linux input.h,里面定義了所有觸摸定義,包括最基本的觸摸坐標(biāo),壓力值,觸摸面積,按鍵,物理鍵,虛擬鍵盤等。然后繼續(xù)對比getevent的輸出。比如從上面的例子你就可以發(fā)現(xiàn)ABS_MT_POSITION_X,ABS_MT_POSITION_X是觸摸的x和y坐標(biāo)的代表位,并且他們值一定是0x35和0x36
- 每個手機(jī)都有不同的/dev/input/event,你需要找到一種探測方式,逐一探測所有event鎖定你需要的event
Android有好幾種多點觸摸協(xié)議,同二你可以在源碼中找到實現(xiàn)方式,滑動也是如此
其他:如何應(yīng)對按鍵精靈等軟件作弊
純從技術(shù)層面,不考慮其他輔助策略,現(xiàn)有的按鍵精靈等軟件在對外的接口中只注重了對一部分參數(shù)的關(guān)注(點擊坐標(biāo),位置,滑動時間等),而另一些參數(shù)沒有做過處理,用代碼點出來跟真人點擊會產(chǎn)生很大的區(qū)別。抓取此行為可以提高對按鍵精靈類軟件識別準(zhǔn)確率