程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 鉤子的應用:程序運行監視

鉤子的應用:程序運行監視

編輯:關於C++

程序介紹:

利用這個程序:

1.可以監視在你的電腦運行的程序, 把在你的電腦運行過的程序的時間和名字記錄下來;

2.可以阻止你規定的禁用程序的執行, 比如不讓玩游戲。

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: [email protected] ==========\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;
}

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

本程序包含兩個工程文件:

hwhpdrv.bpr 創建 .DLL 動態鏈接庫

hwhpapp.bpr 創建 .EXE 應用程序

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved