实现DLL内存补丁,DLL劫持技术

帖子连接:http://www.debug.net.cn/view.asp?id=8

 

在自己品读了kanxue大哥的加密解密之后,不禁想在论坛上写篇这样的文章.小弟新手,高手前辈请别取笑小弟。
      大伙都知道,在windows下当一个可执行文件运行时,Windows加载器将可执行模块映射到进程的地址空间中,加载器分析可执行模块的输入表,并设法找出任何需要的DLL,并将它们映射到进程的地址空间中。由于输入表是根据DLL名来进行查找,首先是查找当前目录下有没这文件,没有话在去查找系统目录C:\\Windows\\system32有没这文件,所以我们可以完全趁这个机会去劫持DLL,把他劫持下来后就可以在里面进行我们要做的事情。例如:
1.//补丁前,程序运行方式如下:

2..//补丁后,程序运行方式如下

为了让我们自己开发的补丁DLL有导出函数,我们可以用 #parma comment(..),代码如:

#pragma comment(linker, "/EXPORT:testadd=_TESTDLLLIB_testadd,@1")

我写了个DLL,分别是补丁前和补丁后,我把代码贴出来。 1.补丁前DLL。 代码:

//tstDll.dll 补丁前
//By symanli
#include "stdafx.h"
#include "dll.h"
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                                         )
{
    return TRUE;
}
//原始函数
int testadd(int a,int b)
{
        ::MessageBox(NULL,"这是补丁前的DLL","TODO",MB_OK);
        return a+b;
}

2.补丁后代码:

//这是补丁代码。by symanli
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 头文件
#include <Windows.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 宏定义
#define EXTERNC extern "C"
#define NAKED __declspec(naked)
#define EXPORT __declspec(dllexport)

#define ALCPP EXPORT NAKED
#define ALSTD EXTERNC EXPORT NAKED void __stdcall
#define ALCFAST EXTERNC EXPORT NAKED void __fastcall
#define ALCDECL EXTERNC NAKED void __cdecl
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TESTDLLLIB 命名空间
namespace TESTDLLLIB
{
        HMODULE m_hModule = NULL;        // 原始模块句柄
        DWORD m_dwReturn[1] = {0};        // 原始函数返回地址
        
        
        // 加载原始模块
        inline BOOL WINAPI Load()
        {
                TCHAR tzPath[MAX_PATH];
                TCHAR tzTemp[MAX_PATH * 2];
                
                //将原始DLL名改成其他的名字,我们用LoadLibrary去加载他。
                lstrcpy(tzPath, TEXT("tstDllold.dll"));
                m_hModule = LoadLibrary(tzPath);
                if (m_hModule == NULL)
                {
                        wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。"), tzPath);
                        MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
                }
                
                return (m_hModule != NULL);        
        }
        
        // 释放原始模块
        inline VOID WINAPI Free()
        {
                if (m_hModule)
                {
                        FreeLibrary(m_hModule);
                }
        }
        
        // 获取原始函数地址
        FARPROC WINAPI GetAddress(PCSTR pszProcName)
        {
                FARPROC fpAddress;
                CHAR szProcName[16];
                TCHAR tzTemp[MAX_PATH];
                
                fpAddress = GetProcAddress(m_hModule, pszProcName);
                if (fpAddress == NULL)
                {
                        if (HIWORD(pszProcName) == 0)
                        {
                                wsprintf(szProcName, "%d", pszProcName);
                                pszProcName = szProcName;
                        }
                        
                        wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。"), pszProcName);
                        MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
                        ExitProcess(-2);
                }
                
                return fpAddress;
        }
}
using namespace TESTDLLLIB;

// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
        if (dwReason == DLL_PROCESS_ATTACH)
        {
                DisableThreadLibraryCalls(hModule);
                
                for (INT i = 0; i < sizeof(m_dwReturn) / sizeof(DWORD); i++)
                {
                        m_dwReturn[i] = TlsAlloc();
                }
                
                return Load();
        }
        else if (dwReason == DLL_PROCESS_DETACH)
        {
                for (INT i = 0; i < sizeof(m_dwReturn) / sizeof(DWORD); i++)
                {
                        TlsFree(m_dwReturn[i]);
                }
                
                Free();
        }
        
        return TRUE;
}
// 导出函数
ALCDECL TESTDLLLIB_testadd(void)
{
        ::MessageBox(NULL,"这是补丁后的DLL","TODO",MB_OK);
        // 保存返回地址到 TLS
        //__asm PUSH m_dwReturn[0 * TYPE long];
        //__asm CALL DWORD PTR [TlsSetValue];
        
        // 调用原始函数
        GetAddress("testadd");
        __asm JMP EAX;
        // 获取返回地址并返回

//         __asm PUSH EAX;
//         __asm PUSH m_dwReturn[0 * TYPE long];
//         __asm CALL DWORD PTR [TlsGetValue];
//         __asm XCHG EAX, [ESP];
//         __asm RET;

}
#pragma comment(linker, "/EXPORT:testadd=_TESTDLLLIB_testadd,@1")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

3.exe调用代码

//exe调用代码
#pragma  comment(lib,"tstDll.lib")//导入先前DLL的lib,就是最原始的LIB
void CTstExeDlg::OnButton1() 
{
        // TODO: Add your control notification handler code here
        int _sum =testadd(10,20);
        CString szSum;
        szSum.Format("结果是:[%d]",_sum);
        AfxMessageBox(szSum);
}

4.看看结果
1.补丁前:

2..补丁后:

别的我就不多了。我写了个例子程序,可以下载来研究下。大家通过这种原理可以做出类似劫持其他应用程序的程序。

【点击这里下载示例代码】

 

 

posted @ 2011-09-05 15:49  lpbolg  阅读(499)  评论(0)    收藏  举报