(okwary) 小叹的学习园地

与天斗?不够高~ 与地斗?不够阔 与人斗? 脸皮不够厚

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

利用特洛伊DLL进行注入

 

 

 (okwary) 小叹的学习园地


这种方法的原理就是由自己写一个与原有进程调用的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核心编程

posted on 2008-12-20 11:02  okwary  阅读(455)  评论(0编辑  收藏  举报
ggg