不被偷窥的Edit控件
不被偷窥的Edit控件在每次用户敲键以后都会产生一些随机键盘事件。键盘间谍将会捕捉到用户的键盘事件和控件创建的虚假事件,从而很难判断真实敲键的内容。另一方面,用户的输入是被保存在控件的成员变量中的,应用程序不会受到影响。虚假键盘事件是利用SendInput API函数产生的。我分别实现了MFC和C#可用的控件。
不被偷窥的Edit控件假定SendInput产生键盘事件的速度远快于用户本身的输入,但这可能导致在一些较慢的机器上, 控件会返回错误的用户输入,尤其是C#的实现中。
MFC CSafeEdit:
void CSafeEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_SHIFT || nChar == VK_CONTROL || nChar == VK_MENU)
return;
if (nChar == VK_DELETE || nChar == VK_BACK)
{
SetWindowText("");
m_sRealText = "";
return;
}
if (m_state == 0)
{
m_iDummyKeyStrokesCount = SendDummyKeyStrokes();
m_state = 1;
CString text;
GetWindowText(text);
m_sRealText += text.Right(1);
}
else
{
if (m_state++ >= m_iDummyKeyStrokesCount)
m_state = 0;
}
CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
}
/
CString CSafeEdit::GetRealText()
{
return m_sRealText;
}
/
int CSafeEdit::SendDummyKeyStrokes()
{
srand((unsigned)::GetTickCount());
int iKeyStrokeCount = rand() % 5 + 1;
int key;
INPUT inp[2];
inp[0].type = INPUT_KEYBOARD;
inp[0].ki.dwExtraInfo = ::GetMessageExtraInfo();
inp[0].ki.dwFlags = 0;
inp[0].ki.time = 0;
for (int i=0; i < iKeyStrokeCount; i++)
{
key = rand() % ('Z'-'A') + 'A';
inp[0].ki.wScan = key;
inp[0].ki.wVk = key;
inp[1] = inp[0];
inp[1].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(2, inp, sizeof(INPUT));
}
return iKeyStrokeCount;
}
删除间谍类库(SpyRemover)
基于钩子的间谍程序都是依赖于存放钩子程序的DLL文件的,因此应用程序的进程中通过调用FreeLibrary API移除掉钩子DLL,将会使键盘间谍钩子失效。SpyRemover的构造函数中创建一个授权模块的列表,然后通过枚举进程所有已加载的模块来检测未授权的模块,键盘间谍的钩子DLL也在其中。
VOID SpyRemover::TimerProc(HWND hwnd, UINT uMsg,
unsigned int idEvent, DWORD dwTime)
{
m_SpyRemover->EnumModules();
}
//
SpyRemover::SpyRemover(char* szAuthorizedList)
{
m_SpyRemover = this;
m_szAuthorizedList = " ";
m_szAuthorizedList += szAuthorizedList;
m_szAuthorizedList += " ";
m_szAuthorizedList.MakeLower();
::SetTimer(NULL, 0, 500, TimerProc);
}
//
void SpyRemover::EnumModules()
{
DWORD dwPID = ::GetCurrentProcessId();
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
//Take a snapshot of all modules in the process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
return;
me32.dwSize = sizeof( MODULEENTRY32 );
//Retrieve information about the first module (application.exe)
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap );
return;
}
//Walk the module list of the process
do
{
if (!IsModuleAuthorized(me32.szModule))
{
HMODULE hmodule = me32.hModule;
CloseHandle(hModuleSnap);
FreeLibrary(hmodule);
return;
}
} while( Module32Next( hModuleSnap, &me32 ) );
CloseHandle(hModuleSnap);
}
//
bool SpyRemover::IsModuleAuthorized(char* szModuleName)
{
char szModule[1024];
sprintf(szModule, " %s ", szModuleName);
strcpy(szModule, _strlwr(szModule));
if (strstr(m_szAuthorizedList, szModule))
return true;
else
return false;
}