轉:DLL注入大法—之利用特洛伊DLL進行注入

這種方法的原理就是由自己寫一個與原有進程調用的DLL具有相同接口函數的DLL,再用我們的DLL替換原有的DLL。在替換的過程中,由我們自己編寫感興趣的函數替換原有函數,而對其它不感興趣的函數,則以函數轉發的形式調用原有DLL中的函數。這裏面有個前提,就是你在編寫DLL時你必須知道原有DLL中的函數都有哪些,以免導至其它進程調用DLL時找不到相應的API函數,特別是在替換系統DLL文件時更要小心。

下面就來演示一下這種方式。我是這樣做的,首先寫一個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核心編程》

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章