有史以來第一次,您可以敲打一下計算機并得到有意義的響應!使用 Linux® 和 Hard Drive Active Protection System(硬盤活動保護系統,HDAPS)內核驅動程序,我們可以訪問 Lenovo(以前稱為 IBM®)ThinkPads 上的嵌入式加速器,然后處理加速器的數據來讀取特定 “敲打” 事件序列(也就是您使用關節敲打筆記本的事件序列),并基于這些敲打事件運行一些命令。雙擊鎖定屏幕,然后敲入密碼來解鎖。敲打顯示屏一次就可以讓 MP3 播放器前進一個音軌。這類可能事物是無窮無盡的。
2003 年,IBM 開始發行集成了加速器和相關軟件的 ThinkPad 筆記本,以便在筆記本掉到地上時對硬盤進行保護。來自 IBM 和其他地方的黑客已經為 Linux 內核開發了一些模塊來利用這些傳感器的優點。屏幕顯示方向、桌面切換、甚至是游戲控制和實時的筆記本傾斜度 3D 模塊現在都已經可以使用了。本文將展示 “敲打代碼” 這種新技術和一個簡單程序,該程序在檢測到特定的敲打代碼時會運行一些命令。
使用帶有 HDAPS 驅動的已更新的內核,我們就可以用一個簡單程序 knockAge 來生成敲打代碼了。我們也可以下載并使用一個 Perl 腳本來定制自己的敲打輸入環境。請參閱本文最后的 下載 和 參考資料 部分給出的鏈接,其中包括了解 knockAge 操作的鏈接。
![]() |
|
很多在 2003 年以及這以后生產的 IBM(現在是 Lenovo)的 ThinkPads 中都有 HDAPS 硬件。如果您不確定自己的硬件配置,可以檢查 Lenovo 的 Web 站點上關于您自己型號的機器的技術細節。如果您的機器上沒有 ThinkPad,那么這段代碼可能無法在您的筆記本上正常工作。
本文是在 x86 體系架構上編寫的。本文中的代碼是在 ThinkPad T42p 的兩個不同模塊上進行開發和測試的。有關 ThinkPad 硬件的鏈接,請參閱 參考資料 部分。
如果您有一臺 Apple MacBook,那么您可能也有這種加速器,并且可以使用相同的方法,通過內核訪問它們。然而,本文中的代碼并沒有在 Apple 硬件上進行測試。
HDAPS 驅動程序必須包括在內核中才能啟用對加速器的訪問。試圖對現有內核增加補丁也不會獲得成功,因此我們建議從自己喜歡的鏡像站點上下載最新的內核。新內核發行版中已經包含了對 HDAPS 驅動程序的支持。
啟動內核配置選擇程序,并在配置中包含 HDAPS 驅動程序。HDAPS 驅動程序位于 Device Drivers > Hardware Monitoring Support > IBM Hard Drive Active Protection System (hdaps) 選項中。更多的內核配置和安裝過程已經超出了本文的范圍,但是在 Web 站點上有很多教程可以提供具體的幫助;有關可以幫助我們入門的鏈接,請參閱 參考資料 一節的內容。
本文是在 2.6.15.1 版本的內核上進行開發和測試的。
從 下載 一節的鏈接中下載源代碼,并從中找到 knockAge.pl 腳本。這就是讓我們可以創建敲打序列的主要 Perl 程序,它還允許監聽特殊的敲打序列并運行命令。下面讓我們來介紹一下這個用戶空間程序的用法,以及 knockAge.pl 程序的配置,然后再對這個函數進行回顧。
使用下面的命令運行 knockAge.pl 程序:
perl knockAge.pl -c
這會啟動 Perl 程序來監聽敲打事件并記錄下它們之間的間距以供將來使用。一旦程序開始運行之后,對筆記本進行的敲打操作就會產生效果。我們并不需要在物理上移動自己的 ThinkPad 來注冊敲打事件,如果 ThinkPad 在一個平面上,只要對其進行一些移動和滑行即可。我建議您用左右握住 ThinkPad 左邊接近連接軸的地方,同時用右手在距離 LCD 底部 3 英寸的地方敲打顯示屏即可。請參閱 下載 部分給出的視頻展示,或參閱 參考資料 中用來創建敲打序列的例子。
體驗不同的敲打幅度和力度,從而了解 knockAge 程序能夠捕獲的事件判斷率。對于創建復雜的敲打事件來說,這非常重要。
第一次真正嘗試敲打應該非常簡單,兩次雙擊之間停留 0.5 秒,然后再次運行 perl knockAge.pl -c
,在看到 “enter a knock sequence” 時穩定地敲打 LCD 邊上兩次,中間停留 0.5 秒。在 4 秒之后會自動超時(這是可以配置的),您所敲打的序列會被打印出來,這類似于下面的例子:
0 540031 _#_ (command here) _#_ <comments here>
讓我們來分析一下這一行的內容:敲打序列,分隔符,命令區,分隔符,最后是注釋區。我們的下一個步驟是將這行內容復制到 knockAge.pl 程序使用的默認配置文件 {$HOME}/.knockFile 中,該配置文件也可能是 /home/<username>/.knockFile 文件。在使用上面的敲打序列行創建好 .knockFile 文件之后,就可以對這行進行修改來運行程序了。將 (command here)
文本修改成 /bin/echo "double tap",并將注釋區的內容修改成更有意義的內容,例如:
0 540031 _#_ /bin/echo "double tap" _#_ Double tap event
現在我們已經修改好這個配置文件,可以打印一條通知了,接下來使用下面的命令在守護模式下運行 knockAge 腳本:
perl knockAge.pl
這個程序會在后臺安靜地監聽 ~/.knockFile 所羅列的事件。請使用相同的間隔再次雙擊屏幕,您會看到在屏幕上打印出了 “double tap” 消息。如果我們希望更詳細地了解 knockAge.pl 腳本是如何工作的,那么我們可以使用下面的命令在守護模式下運行它:
perl knockAge.pl -v
使用下面的命令在 “create” 模式下運行 knockAge.pl 程序:
perl knockAge.pl -c
現在我們需要創建一個解鎖的密碼序列;我建議使用 “刮臉和理發的動作”。請確保每次您都可以以一貫精確的方式執行這個動作。盡管您可以通過修改參數來控制輸入密碼敲打操作所需要的精度,但是這仍然很難匹配精確的時間。“刮臉和理發動作” 除了可以提供穩定的擊打順序之外,其復雜性和簡單性對于屏保解鎖密碼來說也非常適合。下面是一個 “刮臉和理發動作” 的擊打序列示例:
0 564025 1185795 621350 516038 960035 444421 _#_ /bin/echo "shave the haircut" _#_ two bits
在進行下一步操作之前,您應該體驗一下上面的命令和 ~/.knockFile 配置文件中的雙擊命令。這可以在屏保運行時提供很好的幫助,它更難檢測出敲打是否正確。
以下設置假設您已經登錄到了窗口管理器中,并且已經使用您的 userid 啟動了xscreensaver 程序。例如,如果您正在運行 Fedora Core 4,并且使用 gdm 登錄到 KDE 中,那么 xscreensaver 就會自動啟動。因此,要激活它,則需要將雙擊命令從:
/bin/echo "double tap"
修改為:
xscreensaver-command -activate &
現在,每次識別出有 “雙擊” 事件發生時,xscreensaver 程序都會使用所指定的內容來激活。一旦 screensaver 被激活,就可以通過輸入密碼(如果是這樣配置的)對屏幕進行解鎖。不過我們真正希望的是自己的朋友也可以使用密碼解鎖代碼來解除屏保。因此,我們需要在 ~/.knockFile 文件中將下面的命令:
/bin/echo "shave the haircut"
替換為:
killall xscreensaver ; nohup xscreensaver -nosplash >/dev/null 2>/dev/null &
這個命令會停止當前運行的所有 xscreensaver 程序,然后在后臺再重新啟動 xscreensaver,F在我們可以通過敲打屏幕邊來重復加鎖和解鎖計算機屏保的過程。這比藍牙提供的近似度加鎖更加安全或更方便嗎?答案可能是否定的。它更酷嗎?當然!
HDAPS 傳感器和 knockAge.pl 程序提供了另外一種用戶輸入設備,我們可以使用它們以獨特的方式進行輸入。例如:
- 如果計劃在一個基礎上測試新的 X 配置文件,可以將雙擊條目更改為重新啟動配置好的 X 服務器。這樣就不需要敲任何其他鍵來強制重啟了。
- 在命令區中可以放上我們喜歡使用的任何 shell 腳本,這樣就可以使用雙擊來查看 e-mail。
- 以最新的組合節拍進行敲打,讓 ThinkLight 顯示 WWII 代在 Kinakuta 的黃金存儲設備的 Morse 密碼位置。
- 敲入 Morse 編碼,防止鍵盤輸入被記錄。
請參閱 參考資料 部分給出的有關將 ThinkPad 的傾斜度用于游戲、顯示工具的例子;蛘咧苯犹^這部分內容,將 Threshold 變量設置為 15,這樣您使勁踢一腳 ThinkPad,它就會自動重啟了。
Jeff Molofee 所編寫的 hdaps-gl.c 是 knockAge.pl 代碼的基礎。Hdaps-gl.c 是一個非常好的展示程序,可以展示如何使用傾斜傳感器來實時地顯示有關 ThinkPad 的方向的信息。二者之間的區別是本例將時間上隔離的事件組織在一起創建了敲打事件,同時提供了相關的代碼來創建并監聽敲打事件序列。
下面讓我們來使用對時間和傳感器敏感的一些參數來啟動 knockAge.pl:
require 'sys/syscall.ph'; # for subsecond timing
my $option = $ARGV[0] || ""; # simple option handling
# filename for hdaps sensor reads
my $hdapsFN = "/sys/devices/platform/hdaps/position";
my $UPDATE_THRESHOLD = 4; # threshold of force that indicates a knock
my $INTERVAL_THRESHOLD = 100000; # microseconds of time required between knock
# events
my $SLEEP_INTERVAL = 0.01; # time to pause between hdaps reads
my $MAX_TIMEOUT_LENGTH = 4; # maximum length in seconds of knock pattern
# length
my $MAX_KNOCK_DEV = 100000; # maximum acceptable deviation between recorded
# pattern values and knocking values
my $LISTEN_TIMEOUT = 2; # timeout value in seconds between knock
# events when in listening mode
這些變量及其注釋都非常簡單。它們的用法和配置選項在本文后面部分會進行解釋。下面是其余的一些全局變量及其描述。
my @baseKnocks = (); # contains knock intervals currently entered
my %knockHash = (); # contains knock patterns, associated commands
my $prevInterval = 0; # previous interval of time
my $knockCount = 0; # current number of knocks detected
my $restX = 0; # `resting' positiong of X axis accelerometer
my $restY = 0; # `resting' positiong of Y axis accelerometer
my $currX = 0; # current position of X axis accelerometer
my $currY = 0; # current position of Y axis accelerometer
my $lastX = 0; # most recent position of X axis accelerometer
my $lastY = 0; # most recent position of Y axis accelerometer
my $startTime = 0; # to manage timeout intervals
my $currTime = 0; # to manage timeout intervals
my $timeOut = 0; # perpetual loop variable
my $knockAge = 0; # count of knocks to cycle time interval
在我們的子程序清單中首先是一個簡單的邏輯塊,用來檢查是否有加速器可讀:
sub checkAccelerometer() {
my $ret;
$ret = readPosition ();
if( $ret ){
print "no accelerometer data available - tis bork ed\n";
exit(1);
}
}#checkAccelerometer
Jeff Molofee 編寫的 hdaps-gl.c 代碼為 knockAge.pl 中的所有代碼提供了一個很好的起點。在下面的 readPosition
子程序中,我們可以看到他的注釋。這個子程序將打開一個文件,從中讀取當前的加速器數據,然后關閉文件,并返回不包含 “,
(逗號)” 字符的數據。
## comments from Jeff Molofee in hdaps-gl.c
#* read_position - read the (x,y) position pair from hdaps.
#*
#* We open and close the file on every invocation, which is lame but due to
#* several features of sysfs files:
#*
#* (a) Sysfs files are seekable.
#* (b) Seeking to zero and then rereading does not seem to work.
##
sub readPosition() {
my ($posX, $posY) = "";
my $fd = open(FH," $hdapsFN");
while( <FH> ){
s/\(//g;
s/\)//g;
($posX, $posY) = split ",";
}# while read
close(FH);
return( $posX, $posY );
}#readPosition
getEpochSeconds
和 getEpochMicroSeconds
提供了有關敲打模式狀態的詳細而精確的信息。
sub getEpochMicroSeconds {
my $TIMEVAL_T = "LL"; # LL for microseconds
my $timeVal = pack($TIMEVAL_T, ());
syscall(&SYS_gettimeofday, $timeVal, 0) != -1 or die "micro seconds: $!";
my @vals = unpack( $TIMEVAL_T, $timeVal );
$timeVal = $vals[0] . $vals[1];
$timeVal = substr( $timeVal, 6);
my $padLen = 10 - length($timeVal);
$timeVal = $timeVal . "0" x $padLen;
return($timeVal);
}#getEpochMicroSeconds
sub getEpochSeconds {
my $TIMEVAL_T = "LL"; # LL for microseconds
my $start = pack($TIMEVAL_T, ());
syscall(&SYS_gettimeofday, $start, 0) != -1 or die "seconds: $!";
return( (unpack($TIMEVAL_T, $start))[0] );
}#getEpochSeconds
接下來是 knockListen
子程序,前 5 行負責讀取當前的加速器數據值,并對基本的值讀取進行調整。如果加速器的數量在某一維度上大于更新上限值,那么 checkKnock
變量就被設置為 1。為了調整這個程序,使它只響應我們需要的敲打事件或類似的加速值,我們需要擴大更新上限。例如,我們可以將 ThinkPad 放到自己的汽車中,并讓它在檢測到硬加速(或減速)時更改 MP3 播放列表。
如果敲打筆記本的力度足夠大,并且大于了更新上限,那么就會導致調用 getEpochMicroSeconds
子程序。然后 diffInterval
變量會在兩次敲打事件之間被賦值。這個值將很多擊打力度大于更新上限的很多快速加速讀取壓縮到一個時間中。如果沒有間隔上限檢查,一次硬敲打就會被注冊成很多事件,就仿佛是加速器連續一段時間產生大量事件一樣。這種行為對于用戶的視力和觸覺來說都是無法感知到的,但對于 HDAPS 來說顯然并非如此。如果已經達到了間隔上限,那么敲打間隔會被記錄在 baseKnocks
數組中,然后將兩次敲打之間的間隔重置。
仔細修改這些變量可以幫助對程序進行優化,從而識別出您特有的敲打風格?s小更新上限并擴大周期上限可以檢測出更多間隔的輕微敲打。機械敲打設備或特定的敲打方法可能會需要降低間隔上限,從而識別出獨特的敲打事件。
sub knockListen() {
my $checkKnock = 0;
($currX, $currY) = readPosition();
$currX -= $restX; # adjust for rest data state
$currY -= $restY; # adjust for rest data state
# require a high threshold of acceleration to ignore non-events like
# bashing the enter key or hitting the side with the mouse
if( abs ($currX) > $UPDATE_THRESHOLD) {
$checkKnock = 1;
}
if( abs ($currY) > $UPDATE_THRESHOLD) {
$checkKnock = 1;
}
if( $checkKnock == 1 ){
my $currVal = getEpochMicroSeconds();
my $diffInterval = abs($prevInterval - $currVal);
# hard knock events can create continuous acceleration across a large time
# threshold. requiring an elapsed time between knock events effectively
# reduces what appear as multiple events according to sleep_interval and
# update_threshold into a singular event.
if( $diffInterval > $INTERVAL_THRESHOLD ){
if( $knockCount == 0 ){ $diffInterval = 0 }
if( $option ){
print "Knock: $knockCount ## last: [$currVal] curr: [$prevInterval] ";
print "difference is: $diffInterval\n";
}
push @baseKnocks, $diffInterval;
$knockCount++;
}# if the difference interval is greater than the threshold
$prevInterval = $currVal;
}#if checkknock passed
}#knockListen
在創建敲打模式時,該模式會被放入 ~/.knockFile 文件中,并使用下面的子程序進行讀。
sub readKnockFile {
open(KNCKFILE,"$ENV{HOME}/.knockFile") or die "no knock file: $!";
while(<KNCKFILE>){
if( !/^#/ ){
my @arrLine = split "_#_";
$knockHash{ $arrLine[0] }{ cmd } = $arrLine[1];
$knockHash{ $arrLine[0] }{ comment } = $arrLine[2];
}#if not a comment line
}#for each line in file
close(KNCKFILE);
}#readKnockFile
當 knockListen
獲得敲打模式時,它會將該模式與從 readKnockFile
中讀取的敲打模式進行比較。下面的 compareKnockSequences
子程序會對敲打之間的時間進行簡單的區別檢查。注意,敲打之間的差別并不是簡單混合在一起的:很多次敲打時的少量時間差別并不會累積成總體的匹配失效。
第一個要比較的是敲打的次數,因為我們沒有必要將一個七次敲打的序列與一個兩次敲打的序列進行比較。如果敲打的次數與 ~/.knockFile 中現有的敲打序列匹配,每次敲打之間的差別也少于最大敲打偏差,那么這次敲打就可以認為是完全匹配的。在允許敲打序列進行不精確匹配時,最大敲打偏差非常關鍵。我們可以增大最大敲打偏差來使敲打節奏更加自由,但是要注意,這可能會導致敲打模式匹配不正確。例如,我們可以在所期望的時間之前或之后半秒鐘允許自己的敲打模式發生偏離,但這仍然可以匹配。這樣就可以有效地說明 “刮臉和理發” 可以與 “Mary 姓 Little Lamb” 匹配,因此在修改這個參數時一定要小心。
如果完整的模式可以匹配,就會運行 ~/.knockFile 中指定的命令,如果啟用了冗余模式,則會打印結果。下一個步驟是如果沒有找到匹配項,就退出這個子程序;如果找到了匹配項,就重置所記錄的敲打序列。這個步驟會執行 compareKnockSequences
子程序:
sub compareKnockSequences {
my $countMatch = 0; # record how many knocks matched
# for each knock sequence in the config file
for( keys %knockHash ){
# get the timings between knocks
my @confKnocks = split;
# if the count of knocks match
if( $knockCount eq @confKnocks ){
my $knockDiff = 0;
my $counter = 0;
for( $counter=0; $counter<$knockCount; $counter++ ){
$knockDiff = abs($confKnocks[$counter] - $baseKnocks[$counter]);
my $knkStr = "k $counter b $baseKnocks[$counter] ".
"c $confKnocks[$counter] d $knockDiff\n";
# if it's an exact match, increment the matching counter
if( $knockDiff < $MAX_KNOCK_DEV ){
if( $option ){ print "MATCH $knkStr" }
$countMatch++;
# if the knocks don't match, move on to the next pattern in the list
}else{
if( $option ){ print "DISSONANCE $knkStr" }
last;
}# deviation check
}#for each knock
}#if number of knocks matches
# if the count of knocks is an exact match, run the command
if( $countMatch eq @confKnocks ){
my $cmd = system( $knockHash{"@confKnocks "}{ cmd } );
if( $option ){ print "$cmd\n" }
last;
# otherwise, make the count of matches zero, in order to not reset
}else{
$countMatch = 0;
}
}#for keys
# if the match count is zero, exit and don't reset variables so a longer
# knock sequence can be entered and checked
if( $countMatch == 0 ){ return() }
# if a match occurred, reset the variables so it won't match another pattern
$knockCount = 0;
@baseKnocks = ();
}#compareKnockSequences
利用這些子程序,主程序的邏輯允許用戶創建敲打序列,或在守護模式下監聽敲打序列并執行命令。第一部分是在用戶指定 -c
選項(用于創建模式)時執行的?梢杂煤唵蔚某瑫r進程來結束敲打序列。增大最大超時長度變量的值可以讓兩次敲打序列之間暫停 4 秒以上。如果我們保留最大超時長度為 4 秒,那么程序運行到這個時間時就會結束,并打印當前輸入的敲打序列。
if( $option eq "-c" ){
print "create a knock pattern:\n";
$startTime = getEpochSeconds(); # reset time out start
while( $timeOut == 0 ){
$currTime = getEpochSeconds();
# check if there has not been a knock in a while
if( $currTime - $startTime > $MAX_TIMEOUT_LENGTH ){
$timeOut = 1; # exit the loop
}else{
# if a knock has been entered before timeout, reset timers so
# more knocks can be entered
if( $knockCount != $knockAge ){
$startTime = $currTime; # reset timer for longer delay
$knockAge = $knockCount; # synchronize knock counts
}# if a new knock came in
}# if timer not reached
knockListen();
select(undef, undef, undef, $SLEEP_INTERVAL);
}#timeOut =0
if( @baseKnocks ){
print "place the following line in $ENV{HOME}/.knockFile\n\n";
for( @baseKnocks ){ print "$_ " }
print "_#_ (command here) _#_ <comments here>\n\n";
}#if knocks entered
第二部分是用來在一個無限循環中監聽敲打序列的主邏輯,它在一個循環中大約要睡眠 1/100 秒。在這個循環中還使用了一個基于秒的超時,在足夠的延時之后重置敲打序列。注意,在這個例子中,敲打監聽超時時間為 2 秒,而最大超時時間為 4 秒。這樣就提供了在敲打創建模式下進行簡單測試設置的功能,并為敲打序列的監聽模式提供了一個快速重置選項。
}else{
# main code loop to listen for knocking and run commands
readKnockFile();
$startTime = getEpochSeconds();
while( $timeOut == 0 ){
$currTime = getEpochSeconds();
if( $currTime - $startTime > $LISTEN_TIMEOUT ){
$knockCount = 0;
@baseKnocks = ();
$startTime = $currTime;
if( $option ){ print "listen timeout - resetting knocks \n" }
}else{
if( $knockCount != $knockAge ){
$startTime = $currTime; # reset timer for longer delay
$knockAge = $knockCount; # synchronize knock counts
}# if a new knock came in
compareKnockSequences();
}#if not reset timeout
knockListen();
select(undef, undef, undef, $SLEEP_INTERVAL);
}#main knock listen loop
}# if create or listen for knocks
knockAge 程序非常適合用于為系統提供一種額外的用戶輸入通道。然而,需要注意的是使用 knockAge 來做任何事都需要在系統上進行認證。是的,它可以防止密鑰記錄程序監聽密碼的問題,但是很多與 “敲打認證” 有關的因素都表明在對安全性敏感的環境中使用這種技術還不夠成熟。敲打序列目前是以 4 到 9 個數字在 ~/.knockFile 中進行存儲的,它們以毫秒為單位來表示延時。這個 “密碼” 文件非常容易讀取,并且通過嘗試和匹配敲打模式,可以獲得對系統的訪問權限。排除毫秒值中一些精度是一種可用的方法,但是這種練習就留給那些希望自行對系統風險進行評估的讀者好了。
在任何敏感環境中,我們都應該進行一些研究,判斷用戶是否有足夠的應變能力并能夠精確地重現敲打序列。例如,我們是否具有能力創建并連續輸入可接受長度的敲打密碼?具有普通智商的人是否可以直觀地使用這種敲打序列?或者我們是否準備使用 “刮臉和理發操作” 來作為密碼?
文章來源于領測軟件測試網 http://www.kjueaiud.com/
版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備2023014753號-2
技術支持和業務聯系:info@testage.com.cn 電話:010-51297073
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月