我原來寫過有關HOOK的介紹,如果你看過了或者是以前寫過HOOK程序,那麼你已經會這種DLL注入了。它其它就是爲系統或某個線程安裝一個鉤子。這裏要說的是,如果是全局鉤子,那麼你的DLL將會在進程調用時載入到任意一個調用的進程的地址空間中,這樣是相當浪費資源的。因此我在下載的演示中就只對某一個指定的線程安裝線程鉤子。
1、用BCB建立一個DLL工程(如果你用的是VC或其它,請自己對照),輸入以下代碼:
//===========================================================================
// 文件: UnitLib.cpp
// 說明: 演示利用鉤子技術進行DLL注入.
// 將本DLL中的代碼注入到指定的進程空間.
// 作者: 陶冶(無邪)
//===========================================================================
// 函數聲明
extern "C" __declspec(dllexport) __stdcall
bool SetHook(DWORD dwThreadId);
extern "C" __declspec(dllexport) __stdcall
LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam);
static HHOOK hHook = NULL; // 鉤子句柄
static HINSTANCE hInst; // 當前DLL句柄
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
hInst = hinst;
return 1;
}
//---------------------------------------------------------------------------
// 安裝鉤子函數
bool __declspec(dllexport) __stdcall SetHook(DWORD dwThreadId)
{
if (dwThreadId != 0)
{
MessageBox(NULL, ("DLL已經注入!nThreadId = " +
IntToStr(dwThreadId)).c_str(),"DLL",
MB_ICONINFORMATION + MB_OK);
// 安裝指定線程的鉤子
hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MyProc,
hInst,dwThreadId);
if (hHook != NULL)
return true;
}else
{
MessageBox(NULL, "DLL即將從記事本進程空間中撤出!","DLL",
MB_ICONINFORMATION + MB_OK);
return (UnhookWindowsHookEx(hHook));
}
return true;
}
// 鉤子函數
LRESULT CALLBACK __declspec(dllexport) __stdcall
MyProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// 因爲只是演示DLL注入,所以這裏什麼也不做,交給系統處理
return (CallNextHookEx(hHook, nCode, wParam, lParam));
}
//---------------------------------------------------------------------------
該DLL中有兩個函數,一個爲安裝鉤子函數(SetHook),另一個爲鉤子函數(MyProc)。其中安裝鉤子函數提供了一個參數,由該參數指定安裝到哪個線程,如果該參數爲0,則卸載鉤子。
編譯該工程,即生成我們要用來注入到指定進程中的DLL文件了。
2、建立測試工程。用BCB建立一個應用程序工程,在窗體中添加兩個按鈕,一個用來安裝線程鉤子,一個用來卸載。代碼如下:
//---------------------------------------------------------------------------
// SetHook函數原型聲明
typedef BOOL (WINAPI *LPSETHOOK)(unsigned long dwThreadId);
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
// 安裝鉤子
void __fastcall TfrmMain::Button1Click(TObject *Sender)
{
String szPath;
LPSETHOOK lproc;
HANDLE hDll;
BOOL bRet;
PROCESS_INFORMATION info;
STARTUPINFO start;
memset(&start, 0, sizeof(start));
// 取得要載入的DLL文件名
szPath = Application->ExeName;
szPath = szPath.SubString(0, szPath.Length()
- String(StrRScan(szPath.c_str(),'/')).Length());
szPath = szPath + "/DllLib.dll";
// 載入DLL
hDll = LoadLibrary(szPath.c_str());
if (hDll != NULL)
{
lproc = (LPSETHOOK)GetProcAddress(hDll,"SetHook");
if (lproc != NULL)
{
// 因爲沒有適當的工具可以取得線程ID,也爲了簡單起見,所以這裏新創建了一個記事本進程,以便取得它的線程ID,對其安裝鉤子,把我們的DLL注入到記事本進程中。
bRet = CreateProcess(NULL,
"c:/winnt/system32/notepad.exe",
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&start,
&info);
if (bRet != 0)
{
if((*lproc)(info.dwThreadId) == false)
ShowMessage("Sethook failed with error " +
IntToStr(GetLastError()));
}
else
{
ShowMessage("CreateProcess failed with error " +
IntToStr(GetLastError()));
}
}
}
}
//---------------------------------------------------------------------------
// 卸載鉤子
void __fastcall TfrmMain::Button2Click(TObject *Sender)
{
String szPath;
LPSETHOOK lproc;
HANDLE hDll;
szPath = Application->ExeName;
szPath = szPath.SubString(0, szPath.Length()
- String(StrRScan(szPath.c_str(),'/')).Length());
szPath = szPath + "/DllLib.dll";
hDll = LoadLibrary(szPath.c_str());
if (hDll != NULL)
{
lproc = (LPSETHOOK)GetProcAddress(hDll,"SetHook");
if (lproc != NULL)
(*lproc)(0);
}
}
//---------------------------------------------------------------------------
接下來生成可執行文件,點擊第一個安裝鉤子按鈕,然後你就可以用我們最開始寫的查看模塊的工具來查看了,你將會在模塊中看到你剛纔DLL的路徑及文件名,這表明我們已經成功地將自己的DLL注入到了記事本進程空間。點擊卸載按鈕後,再查看記事本進程中的模塊,將不會看到我們DLL文件的完整文件名,這表明已經成功撤消了對記事本進程的注入。
1、用BCB建立一個DLL工程(如果你用的是VC或其它,請自己對照),輸入以下代碼:
//===========================================================================
// 文件: UnitLib.cpp
// 說明: 演示利用鉤子技術進行DLL注入.
// 將本DLL中的代碼注入到指定的進程空間.
// 作者: 陶冶(無邪)
//===========================================================================
// 函數聲明
extern "C" __declspec(dllexport) __stdcall
bool SetHook(DWORD dwThreadId);
extern "C" __declspec(dllexport) __stdcall
LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam);
static HHOOK hHook = NULL; // 鉤子句柄
static HINSTANCE hInst; // 當前DLL句柄
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
hInst = hinst;
return 1;
}
//---------------------------------------------------------------------------
// 安裝鉤子函數
bool __declspec(dllexport) __stdcall SetHook(DWORD dwThreadId)
{
if (dwThreadId != 0)
{
MessageBox(NULL, ("DLL已經注入!nThreadId = " +
IntToStr(dwThreadId)).c_str(),"DLL",
MB_ICONINFORMATION + MB_OK);
// 安裝指定線程的鉤子
hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MyProc,
hInst,dwThreadId);
if (hHook != NULL)
return true;
}else
{
MessageBox(NULL, "DLL即將從記事本進程空間中撤出!","DLL",
MB_ICONINFORMATION + MB_OK);
return (UnhookWindowsHookEx(hHook));
}
return true;
}
// 鉤子函數
LRESULT CALLBACK __declspec(dllexport) __stdcall
MyProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// 因爲只是演示DLL注入,所以這裏什麼也不做,交給系統處理
return (CallNextHookEx(hHook, nCode, wParam, lParam));
}
//---------------------------------------------------------------------------
該DLL中有兩個函數,一個爲安裝鉤子函數(SetHook),另一個爲鉤子函數(MyProc)。其中安裝鉤子函數提供了一個參數,由該參數指定安裝到哪個線程,如果該參數爲0,則卸載鉤子。
編譯該工程,即生成我們要用來注入到指定進程中的DLL文件了。
2、建立測試工程。用BCB建立一個應用程序工程,在窗體中添加兩個按鈕,一個用來安裝線程鉤子,一個用來卸載。代碼如下:
//---------------------------------------------------------------------------
// SetHook函數原型聲明
typedef BOOL (WINAPI *LPSETHOOK)(unsigned long dwThreadId);
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
// 安裝鉤子
void __fastcall TfrmMain::Button1Click(TObject *Sender)
{
String szPath;
LPSETHOOK lproc;
HANDLE hDll;
BOOL bRet;
PROCESS_INFORMATION info;
STARTUPINFO start;
memset(&start, 0, sizeof(start));
// 取得要載入的DLL文件名
szPath = Application->ExeName;
szPath = szPath.SubString(0, szPath.Length()
- String(StrRScan(szPath.c_str(),'/')).Length());
szPath = szPath + "/DllLib.dll";
// 載入DLL
hDll = LoadLibrary(szPath.c_str());
if (hDll != NULL)
{
lproc = (LPSETHOOK)GetProcAddress(hDll,"SetHook");
if (lproc != NULL)
{
// 因爲沒有適當的工具可以取得線程ID,也爲了簡單起見,所以這裏新創建了一個記事本進程,以便取得它的線程ID,對其安裝鉤子,把我們的DLL注入到記事本進程中。
bRet = CreateProcess(NULL,
"c:/winnt/system32/notepad.exe",
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&start,
&info);
if (bRet != 0)
{
if((*lproc)(info.dwThreadId) == false)
ShowMessage("Sethook failed with error " +
IntToStr(GetLastError()));
}
else
{
ShowMessage("CreateProcess failed with error " +
IntToStr(GetLastError()));
}
}
}
}
//---------------------------------------------------------------------------
// 卸載鉤子
void __fastcall TfrmMain::Button2Click(TObject *Sender)
{
String szPath;
LPSETHOOK lproc;
HANDLE hDll;
szPath = Application->ExeName;
szPath = szPath.SubString(0, szPath.Length()
- String(StrRScan(szPath.c_str(),'/')).Length());
szPath = szPath + "/DllLib.dll";
hDll = LoadLibrary(szPath.c_str());
if (hDll != NULL)
{
lproc = (LPSETHOOK)GetProcAddress(hDll,"SetHook");
if (lproc != NULL)
(*lproc)(0);
}
}
//---------------------------------------------------------------------------
接下來生成可執行文件,點擊第一個安裝鉤子按鈕,然後你就可以用我們最開始寫的查看模塊的工具來查看了,你將會在模塊中看到你剛纔DLL的路徑及文件名,這表明我們已經成功地將自己的DLL注入到了記事本進程空間。點擊卸載按鈕後,再查看記事本進程中的模塊,將不會看到我們DLL文件的完整文件名,這表明已經成功撤消了對記事本進程的注入。