vc全域鉤子實現程式監控

來源:互聯網
上載者:User

 
 
再來做一個全域鉤子的程式。

程式大體功能:
1.可以監視在你的電腦啟動並執行程式, 把在你的電腦運行過的程式的時間和名字記錄下來;
2.可以挖出不是經過你自己允許而自動啟動並執行程式,大部分木馬都是自己偷偷啟動並執行。
2.可以阻止你規定的禁用程式的執行, 比如不讓登QQ不讓玩遊戲。
3.這個程式需要加入註冊表, 在系統啟動時就運行, 達到監視的目的。註冊表大概都不陌生,就是這裡:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

程式的記錄結果格式:

2003-02-03 17:31:25 - [System Startup - Windows XP 5.01.2600]
2003-02-03 17:31:29 "CabinetWClass" -> "我的電腦"
2003-02-03 17:31:59 "Red Alert" -> "Red Alert" (關閉禁用程式)
2003-02-03 17:32:19 "掃雷" -> "掃雷" (關閉禁用程式)
2003-02-03 17:32:35 "OpusApp" -> "Microsoft Word"
2003-02-03 17:32:50 - [System Shutdown - 0 days, 0 hrs, 1 mins, 25 secs]

2003-02-03 17:35:37 - [System Startup - Windows 98 SE 4.10.2222]
2003-02-03 17:35:53 "掃雷" -> "掃雷" (關閉禁用程式)
2003-02-03 17:36:05 "CabinetWClass" -> ""
2003-02-03 17:36:31 "Red Alert" -> "Red Alert" (關閉禁用程式)
2003-02-03 17:36:56 "ExploreWClass" -> ""
2003-02-03 17:37:07 - [System Shutdown - 0 days, 0 hrs, 1 mins, 30 secs]

程式運行只需要3個檔案:
  hwhpapp.exe 可執行檔
  hwhpdrv.dll 安裝鉤子的動態連結程式庫
  hwhpapp.cfg 禁用軟體黑名單, 可用記事本修改
程式運行會自動產生記錄檔案:
  hwhpapp.sys 可以用記事本開啟看

下面來講一下程式原理:

一.鉤子
利用 API 函數 SetWindowsHookEx() 安裝一個全域鉤子, 鉤子類型為 WH_SHELL。
WH_SHELL 鉤子可監視所有應用程式的主視窗建立或者關閉。
最典型的應用就是 Windows 的狀態列,當程式運行時,把主視窗的標題加入狀態列,程式退出時,從狀態列刪除。
如果你截獲這個鉤子,可以做到禁止狀態列的顯示,也可以自己作一個狀態列,或者作一個記錄,把所有在你電腦曾經啟動並執行程式記錄下來。如果啟動並執行程式不是你希望的,你可以直接關閉這個程式,達到禁止啟動並執行目的。

二.動態連結程式庫
由於鉤子是全域的,必須把這個鉤子定義到 .DLL 的動態連結程式庫裡,這就涉及到建立動態連結程式庫。

三.共用記憶體
由於鉤子是安裝到系統裡的,鉤子的運行是在作業系統裡面,因此這個鉤子不能使用你的程式所定義的任何全域變數!
既然如此,有什麼辦法解決呢?在本程式裡利用共用記憶體技術,利用 API 函數 CreateFileMapping() 可建立共用記憶體,這個記憶體可以在任何啟動並執行程式中使用,也就是說任何啟動並執行 .EXE、.DLL 和其他程式都可以使用這塊記憶體。在本程式中直接使用了 Victor 串口 VCL 控制項裡的 TSharedMemory 共用記憶體類。

四.記錄檔案和軟體黑名單檔案
把所有在你的電腦執行的程式記錄儲存在一個文字檔裡, 因為副檔名為 .txt 很容易被發現,因此採用副檔名 .sys
軟體黑名單檔案儲存在 .cfg 檔案裡,同樣因為 .ini 檔案很容易發現並且開啟修改。
這兩個檔案都儲存在與你的 .exe 檔的相同檔案夾裡,並且與 .exe 檔同名.

五.保證你的程式只能同時運行一個
如果你同時運行兩個程式,記錄檔案就會亂套,所以必須保證只能運行一個。
當你的程式剛開始啟動並執行時候,就是在 WinMain() 函數的最開始,就要判斷是否已經運行了,如果已經運行,就直接退出。
判斷的方法很簡單,就是檢查程式共用的記憶體是否存在,如果檢查到共用的記憶體已經存在,那就是已經運行了。

六.程式隱藏, 不能顯示在工作列和工作管理員裡面
這個也很簡單,只要在主程式的 Application->Run(); 前面加一句話:
SetWindowLong(Application->Handle, GWL_EXSTYLE, GetWindowLong(Application->Handle, GWL_EXSTYLE)|WS_EX_TOOLWINDOW);
就可以了。

--------------------------------------------------------------------------------

程式介紹
.DLL 檔案:這是最關鍵的鉤子的代碼:

#include <vcl.h>
#include "yb_base.h" //Victor 串口控制項裡面的一個標頭檔

#define MYAPPMARK "VICTOR_APPMONI_20010612" //共用記憶體標誌

class __export THookedProcs
{
public:
 THookedProcs();
 ~THookedProcs();
 void WINAPI InitFuncs(void);
 void WINAPI UninitFuncs(void);
private:
 HHOOK hThisHook; //儲存鉤子的控制代碼
 static LRESULT CALLBACK HookedShellProc(int nCode, WPARAM wParam, LPARAM lParam);
};

//定義共用的資料結構
typedef struct
{
 HHOOK hHook; //當前使用的 HOOK
 //... 此處可增加其他共用的資料
} THookSharedData;

THookedProcs::THookedProcs()
{
 hThisHook = NULL;
}

THookedProcs::~THookedProcs()
{
 UninitFuncs();
}

void WINAPI THookedProcs::InitFuncs(void)
{
 UninitFuncs();
 hThisHook = SetWindowsHookEx(WH_SHELL, (HOOKPROC) HookedShellProc, HInstance, 0);
 TSharedMemory AppMem(MYAPPMARK,4096); //在 EXE 檔案裡共用的記憶體
 THookSharedData *HookSharedData = ((THookSharedData*)(AppMem.AppInfo->Data)); //共用的資料
 HookSharedData->hHook = hThisHook; //把 hThisHook 儲存到共用記憶體裡
}

void WINAPI THookedProcs::UninitFuncs(void)
{
 if(hThisHook)
  {
   UnhookWindowsHookEx(hThisHook);
   hThisHook = NULL;
  }
}

LRESULT CALLBACK THookedProcs::HookedShellProc(int nCode, WPARAM wParam, LPARAM lParam)
{
 TSharedMemory AppMem(MYAPPMARK, 4096); //使用在 .EXE 檔案裡共用的記憶體
 if(AppMem.Valid)if(AppMem.Exists) //如果共用記憶體存在
  {
   HWND hMainWnd = AppMem.AppInfo->hMainForm;

   if(hMainWnd)
    {
     if(nCode==HSHELL_WINDOWCREATED)
      {
        PostMessage(hMainWnd, WM_USERCMD, UC_WINHOOK, wParam);
      }
    }
  }

 //在 Hook 裡無法調用 hThisHook, 必須用共用記憶體裡面的 hHook
 THookSharedData *HookSharedData = ((THookSharedData*)(AppMem.AppInfo->Data)); //共用的資料
 return CallNextHookEx(HookSharedData->hHook, nCode, wParam, lParam);
}

--------------------------------------------------------------------------------

EXE檔案主程式的代碼:

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int)
{
 if(!AppMem.Valid)
  {
   return 1;
  }
 if(AppMem.Exists) //已經存在 (程式以前已經運行過了, 並且正在運行)
  {
   if(stricmp(lpCmdLine, "/SHOW")==0) //如果監測到命令列參數 /SHOW 就顯示出已經啟動並執行程式的主視窗
    {
     PostMessage(AppMem.AppInfo->hMainForm, WM_USERCMD, UC_SHOWWIN, 0);
    }
   return 0;
  }
 AppMem.ClearBuffer();

 try
  {
    Application->Initialize();
    Application->CreateForm(__classid(TFormMain), &FormMain);
    //下面的語句是防止顯示在狀態列和工作管理員
    SetWindowLong(Application->Handle, GWL_EXSTYLE, GetWindowLong(Application->Handle, GWL_EXSTYLE)|WS_EX_TOOLWINDOW);
    Application->Run();
  }
 catch (Exception &exception)
  {
    Application->ShowException(&exception);
  }
 catch (...)
  {
    try
    {
      throw Exception("");
    }
    catch (Exception &exception)
    {
      Application->ShowException(&exception);
    }
  }
 return 0;
}

--------------------------------------------------------------------------------

主視窗程式:

TSharedMemory AppMem(MYAPPMARK, 4096); //定義共用的記憶體,這個記憶體是真正存在的

__fastcall TFormMain::TFormMain(TComponent* Owner)
: TForm(Owner)
{
  AppMem.AppInfo->hMainWnd = Application->Handle;
  AppMem.AppInfo->hMainForm = Handle;
  WriteStartupMessage(); //在記錄檔案裡加入啟動資訊
  PostMessage(Handle, WM_USERCMD, UC_INITWIN, 0);

  MyHook = new THookedProcs;
  MyHook->InitFuncs(); //安裝鉤子
}
//---------------------------------------------------------------------------
__fastcall TFormMain::~TFormMain()
{
  MyHook->UninitFuncs(); //刪除鉤子
  delete MyHook;
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::FormCloseQuery(TObject *Sender, bool &CanClose)
{
  WriteShutdownMessage(); //在記錄檔案裡加入退出資訊
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::WndProc(Messages::TMessage &Message)
{
  if(Message.Msg == WM_USERCMD)
  {
    if(Message.WParam == UC_SHOWWIN)
    {
      Show();
      AppMem.ActiveAppWnd();
    }
    else if(Message.WParam == UC_INITWIN)
    {
      Hide();
      Left = (Screen->Width - Width) / 2;
      Top = (Screen->Height - Height) / 2;
    }
    else if(Message.WParam == UC_WINHOOK)
    {
      WinHookMessage(Message.LParam);
    }
  }
  TForm::WndProc(Message);
}
//---------------------------------------------------------------------------

void __fastcall TFormMain::BnExitClick(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------

void __fastcall TFormMain::BnHideClick(TObject *Sender)
{
  Hide();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::CreateParams(Controls::TCreateParams &Params)
{
  TForm::CreateParams(Params);
  Params.Style = WS_OVERLAPPED|WS_DLGFRAME|WS_CAPTION|WS_SYSMENU;
  Params.ExStyle |= WS_EX_TOPMOST;
  Params.X = Screen->Width - 8;
  Params.Y = Screen->Height - 8;
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::WinHookMessage(long Param)
{
  HWND hWnd = (HWND) Param;

  char szWinCaption[256];
  char szWinClass[256];
  AnsiString s;

  DateTimeX x;
  s += AnsiString().sprintf("%04d-%02d-%02d %02d:%02d:%02d ", x.Year, x.Month, x.Day, x.Hour, x.Minute, x.Second);

  if(!GetWindowText(hWnd, szWinCaption, 256))
   *szWinCaption = 0;
  if(!GetClassName(hWnd,szWinClass,256))
   *szWinClass = 0;
  s += "\"" + AnsiString(szWinClass) + "\" -> \"" + AnsiString(szWinCaption) + "\"";

  if(!ValidAppCheck(hWnd, szWinClass,szWinCaption))
  s += " (關閉禁用程式)";
  s += "\r\n";

  TBinFileFuncs::WriteLogFileInfo(TRelPath().Extension("sys").c_str(), s.c_str()); //與 .exe 同名的 .sys 檔案

}
//---------------------------------------------------------------------------
void __fastcall TFormMain::WriteStartupMessage(void)
{
  AnsiString s;
  DateTimeX x = StartupTime;
  TSysInfo si;

  s += "========== Copyright (C) Victor Chen ===== Email:
victor@cppfans.com ==========\r\n";
  s += AnsiString().sprintf("%04d-%02d-%02d %02d:%02d:%02d - ", x.Year, x.Month, x.Day, x.Hour, x.Minute, x.Second);
  s += AnsiString().sprintf("[System Startup - %s %d.%02d.%04d]", si.OS->OSName, si.OS->MajorVer, si.OS->MinorVer, si.OS->BuildNum);
  s += "\r\n";

  TBinFileFuncs::WriteLogFileInfo(TRelPath().Extension("sys").c_str(), s.c_str()); //與 .exe 同名的 .sys 檔案
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::WriteShutdownMessage(void)
{
  AnsiString s;
  DateTimeX x;
  TimeX t; t.S000 = (x - StartupTime) % (24*60*60);
  int d = (x - StartupTime) / (24*60*60);

  s += AnsiString().sprintf("%04d-%02d-%02d %02d:%02d:%02d - ", x.Year, x.Month, x.Day, x.Hour, x.Minute, x.Second);
  s += AnsiString().sprintf("[System Shutdown - %d days, %d hrs, %d mins, %d secs]", d, t.Hour, t.Minute, t.Second);
  s += "\r\n";

  TBinFileFuncs::WriteLogFileInfo(TRelPath().Extension("sys").c_str(), s.c_str()); //與 .exe 同名的 .sys 檔案
}
//---------------------------------------------------------------------------
bool __fastcall TFormMain::ValidAppCheck(HWND hwnd, char *cls, char *cap)
{
  TBinFile f;
  f.FileName = TRelPath().Extension("cfg"); //與 .exe 同名的 .cfg 檔案
  f.OpenMode = TBinFile::omRead; //準備讀檔案

  if(f.Exists) //如果檔案存在
  {
    try
    {
      f.Active = true; //開啟檔案
      char aLine[2048];
      while(fgets(aLine,2000,f)) //讀一行文本 (標準 C 函數)
      {
        if(strnicmp(aLine,"CLASS=",6)==0) //用類名識別
        {
          TBinFileFuncs::DeleteSpaces(aLine+6,1,1); //去除空格
          if(stricmp(aLine+6,cls)==0)
          {
            PostMessage(hwnd, WM_CLOSE, 0, 0); //關閉程式
            return false;
          }
        }
        else if(strnicmp(aLine,"CAPTION=",8)==0) //用標題識別
        {
          TBinFileFuncs::DeleteSpaces(aLine+8,1,1); //去除空格
          if(stricmp(aLine+8,cap)==0)
          {
            PostMessage(hwnd, WM_CLOSE, 0, 0); //關閉程式
            return false;
          }
        }
      }
    }
    catch(Exception &e)
    {
      //忽略錯誤提示, 當然也可以在此處把錯誤資訊添加到一個錯誤資訊檔
    }
  }
  return true;
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.