下面就來演示一下這種方式。我是這樣做的,首先寫一個DLL作爲被替換的DLL,名爲DllLib.dll(最後更名爲_DllLib.dll),然後寫特洛伊DLL,名爲TroyDll.Dll(最後更名爲原有DLL名,即DllLib.dll),與DllLib.Dll具有相同的API函數過程,但是對其中的一個API函數做更改,使其完成我們的工作,因爲另外還有一個API函數需要對其進行函數轉發,轉給原來的DLL,即(更名爲_DllLib.dll的DllLib.dll)。這時我們的測試程序本來是調用的DllLib.dll的,但由於DllLib.dll已經被TroyDll.dll替換了,所以測試程序實際上調用的是TroyDll.dll,而對於做轉發的函數,則是通過TroyDll.Dll調用DllLib.dll(更名後的_DllLib.dll)完成的。此時我們的特洛伊DLL實際上已經注入到我們的測試程序的進程空間中來了。
1、編寫本來的DLL。DllLib.dll(更名後爲_DllLib.dll)的代碼如下:
//===========================================================================
// 文件: UnitLib.cpp
// 說明: 演示用特洛伊DLL進行DLL注入.這個是本身的DLL,另一個特洛伊DLL將
// 對它進行函數轉發,並實現另外的功能.
// 作者: 陶冶(無邪)
//===========================================================================
// 函數聲明
extern "C" __declspec(dllexport) __stdcall void About();
extern "C" __declspec(dllexport) __stdcall int Add(int a, int b);
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
//---------------------------------------------------------------------------
void __declspec(dllexport) __stdcall About()
{
try
{
MessageBox(NULL,"這是本來的DLL文件!","原來的DLL",
MB_ICONINFORMATION + MB_OK);
}catch(Exception &e)
{
MessageBox(NULL,e.Message.c_str(),"DllLib",MB_OK);
}
}
// 兩數相加(注意:這裏是兩數相加)
int __declspec(dllexport) __stdcall Add(int a, int b)
{
return (a + b);
}
2、編寫特洛伊DLL。TroyDll.dll的代碼如下:
//===========================================================================
// 文件: UnitTroy.cpp
// 說明: 這個是特洛伊DLL,呆會將它的DLL文件更改爲要替換的DLL文件名
// 作者: 陶冶
//===========================================================================
extern "C" __declspec(dllexport) __stdcall void About();
extern "C" __declspec(dllexport) __stdcall int Add(int a, int b);
int Multiply(int a, int b);
// DLL中的函數原形聲明
typedef void (WINAPI *ABOUT)();
typedef int (WINAPI *ADD)(int a, int b);
static String szDllName;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
szDllName = Application->ExeName;
szDllName = szDllName.SubString(0,szDllName.Length()
- String(StrRScan(szDllName.c_str(),'/')).Length());
// 更名後的DllLib.dll文件名
szDllName = szDllName + "/_DllLib.dll";
return 1;
}
//---------------------------------------------------------------------------
void __declspec(dllexport) __stdcall About()
{
// 直接做函數轉發
HANDLE hDll = NULL;
hDll = LoadLibrary(szDllName.c_str());
ABOUT about;
try
{
if (hDll != NULL)
{
about = (ABOUT)GetProcAddress(hDll,"About");
if (about != NULL)
about();
}
else
MessageBox(NULL,"載入原來的DLL錯誤!", "特洛伊DLL",
MB_ICONINFORMATION + MB_OK);
}catch(Exception &e)
{
MessageBox(NULL,e.Message.c_str(),"DllTroy",MB_OK);
}
}
int __declspec(dllexport) __stdcall Add(int a, int b)
{
int nRet;
HANDLE hDll = NULL;
ADD add;
hDll = LoadLibrary(szDllName.c_str());
if (hDll != NULL)
{
// 爲了方便演示,這裏再做一次函數轉發,以便看到本來應該返回的值。
add = (ADD)GetProcAddress(hDll,"Add");
if (add != NULL)
nRet = add(a, b);
ShowMessage("這是本來DLL中的調用結果:" + IntToStr(nRet));
}
else
MessageBox(NULL, "載入本來的DLL錯誤!", "特洛伊DLL", MB_OK);
// 將原來完成兩數相加的更改爲兩數相乘,返回兩數的積。
nRet = Multiply(a, b);
return nRet;
}
int Multiply(int a, int b)
{
return (a * b);
}
3、編寫測試工程。在窗體中添加兩個按鈕,分別調用DllLib.dll中的兩個API函數。代碼如下:
typedef (WINAPI *ABOUT)();
typedef int (WINAPI *ADD)(int a, int b);
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::FormCreate(TObject *Sender)
{
m_szDllName = Application->ExeName;
m_szDllName = m_szDllName.SubString(0,m_szDllName.Length()
- String(StrRScan(m_szDllName.c_str(),'/')).Length());
m_szDllName = m_szDllName + "/DllLib.dll";
}
//---------------------------------------------------------------------------
// 調用About()函數
void __fastcall TfrmMain::Button1Click(TObject *Sender)
{
HANDLE hDll;
ABOUT about;
try
{
hDll = LoadLibrary(m_szDllName.c_str());
if (hDll != NULL)
{
about = (ABOUT)GetProcAddress(hDll,"About");
if (about != NULL)
about();
}
}catch(Exception &e)
{
MessageBox(Handle, e.Message.c_str(), "ERROR",MB_OK);
}
}
//---------------------------------------------------------------------------
// 調用Add()函數
void __fastcall TfrmMain::Button2Click(TObject *Sender)
{
HANDLE hDll;
ADD add;
int nRet;
hDll = LoadLibrary(m_szDllName.c_str());
if (hDll != NULL)
{
add = (ADD)GetProcAddress(hDll,"Add");
if (add != NULL)
nRet = add(10, 2);
ShowMessage("從特洛伊DLL中返回的結果 : " + IntToStr(nRet));
}
}
4、測試。將DllLib.dll更名爲_DllLib.dll,將TroyDll.dll更名爲DllLib.dll,即完成了DLL的替換。下面運行我們的測試工程,單擊調用About()函數的按鈕,因爲About()是通過DllLib.dll(即TroyDll.dll)做的函數轉發(轉以給原DLL,即_DllLib.dll),所以看到的是原DLL(即_DllLib.dll)中彈出的信息框。此時用查看進程模塊的工具來查看進程空間,你會發現,你的特洛伊DLL(更名後的DllLib.dll)已經成功以注入到了測試程序的進程空間中了。
單擊調用Add()函數的按鈕,你會看到本來是完成兩數相加的,返回的結果卻是兩數的積,因爲我們已經在特洛伊DLL中對它做了手腳。這下是利用它的關鍵了。WINDOWS登錄時的GINA,知道吧,想得到別人登錄的密碼嗎?那麼就是用這種方法了,把MSGINA.dll這個東西給它替換成自己的DLL,再複雜的密碼也照樣得到啊,一點也不費精神,呵呵~。(想自己寫嗎?看看《WinLogon登錄管理和GINA簡介》吧)
環境:
WIN2000 Server + BCB 6.0
附:本文相關程序代碼
參考:《WINDOWS核心編程》