第四课 通过修改PE加载DLL

下面通过实例来讲解

下面分析myhack3.dll的源码

首先看一下全部源码

#include "stdio.h"
#include "windows.h"
#include "shlobj.h"
#include "Wininet.h"
#include "tchar.h"

#pragma comment(lib, "Wininet.lib")

#define DEF_BUF_SIZE            (4096)
#define DEF_URL                 L"http://www.google.com/index.html"
#define DEF_INDEX_FILE          L"index.html"

HWND g_hWnd = NULL;

#ifdef __cplusplus
extern "C" {
#endif
// IDT 형식을 위한 dummy export function...
__declspec(dllexport) void dummy()
{
    return;
}
#ifdef __cplusplus
}
#endif

BOOL DownloadURL(LPCTSTR szURL, LPCTSTR szFile)
{
    BOOL            bRet = FALSE;
    HINTERNET	    hInternet = NULL, hURL = NULL;
    BYTE            pBuf[DEF_BUF_SIZE] = {0,};
    DWORD           dwBytesRead = 0;
    FILE            *pFile = NULL;
    errno_t         err = 0;

    hInternet = InternetOpen(L"ReverseCore", 
                             INTERNET_OPEN_TYPE_PRECONFIG, 
                             NULL, 
                             NULL, 
                             0);
    if( NULL == hInternet )
    {
        OutputDebugString(L"InternetOpen() failed!");
        return FALSE;
    }

    hURL = InternetOpenUrl(hInternet,
                           szURL,
                           NULL,
                           0,
                           INTERNET_FLAG_RELOAD,
                           0);
    if( NULL == hURL )
    {
        OutputDebugString(L"InternetOpenUrl() failed!");
        goto _DownloadURL_EXIT;
    }

    if( err = _tfopen_s(&pFile, szFile, L"wt") )
    {
        OutputDebugString(L"fopen() failed!");
        goto _DownloadURL_EXIT;
    }

    while( InternetReadFile(hURL, pBuf, DEF_BUF_SIZE, &dwBytesRead) )
    {
        if( !dwBytesRead )
            break;

        fwrite(pBuf, dwBytesRead, 1, pFile);
    }

    bRet = TRUE;

_DownloadURL_EXIT:
    if( pFile )
        fclose(pFile);

    if( hURL )
        InternetCloseHandle(hURL);

    if( hInternet )
        InternetCloseHandle(hInternet);

    return bRet;
}

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    DWORD dwPID = 0;

    GetWindowThreadProcessId(hWnd, &dwPID);

    if( dwPID == (DWORD)lParam )
    {
        g_hWnd = hWnd;
        return FALSE;
    }

    return TRUE;
}

HWND GetWindowHandleFromPID(DWORD dwPID)
{
    EnumWindows(EnumWindowsProc, dwPID);

    return g_hWnd;
}

BOOL DropFile(LPCTSTR wcsFile)
{
    HWND            hWnd = NULL;
    DWORD           dwBufSize = 0;
    BYTE            *pBuf = NULL; 
	DROPFILES		*pDrop = NULL;
    char            szFile[MAX_PATH] = {0,};
    HANDLE          hMem = 0;

    WideCharToMultiByte(CP_ACP, 0, wcsFile, -1,
                        szFile, MAX_PATH, NULL, NULL);

    dwBufSize = sizeof(DROPFILES) + strlen(szFile) + 1;
    
    if( !(hMem = GlobalAlloc(GMEM_ZEROINIT, dwBufSize)) )
    {
        OutputDebugString(L"GlobalAlloc() failed!!!");
        return FALSE;
    }

    pBuf = (LPBYTE)GlobalLock(hMem);

    pDrop = (DROPFILES*)pBuf; 
    pDrop->pFiles = sizeof(DROPFILES);
    strcpy_s((char*)(pBuf + sizeof(DROPFILES)), strlen(szFile)+1, szFile);

    GlobalUnlock(hMem);

    if( !(hWnd = GetWindowHandleFromPID(GetCurrentProcessId())) )
    {
        OutputDebugString(L"GetWndHandleFromPID() failed!!!");
        return FALSE;
    }

    PostMessage(hWnd, WM_DROPFILES, (WPARAM)pBuf, NULL);

    return TRUE;
}

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    TCHAR szPath[MAX_PATH] = {0,};
    TCHAR *p = NULL;

    OutputDebugString(L"ThreadProc() start...");

    GetModuleFileName(NULL, szPath, sizeof(szPath));
    
    if( p = _tcsrchr(szPath, L'\\') )
    {
        _tcscpy_s(p+1, wcslen(DEF_INDEX_FILE)+1, DEF_INDEX_FILE);

        OutputDebugString(L"DownloadURL()");
        if( DownloadURL(DEF_URL, szPath) )
        {
            OutputDebugString(L"DropFlie()");
            DropFile(szPath);
        }
    }

    OutputDebugString(L"ThreadProc() end...");

    return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH : 
            CloseHandle(CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL));
            break;
    }
   
    return TRUE;
}

下面看一下DropFile()

 

 

复习一下IID结构体的定义

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

    union {

        DWORD   Characteristics;     // 0 for terminating null import descriptor

        DWORD   OriginalFirstThunk; // RVA 指向INT (PIMAGE_THUNK_DATA)

    };

DWORD   TimeDateStamp;   

    DWORD   ForwarderChain;     // -1 if no forwarders

    DWORD   Name;            //dll 名称

    DWORD   FirstThunk;         //指向引入函数真实地址单元处的RVA  IAT

} IMAGE_IMPORT_DESCRIPTOR;

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

 

 

首先在空白位置创建新的IDT

删除绑定导入表

IAT中存储的函数地址是dll未加载的地址,当PE文件中不存在绑定导入表时,IAT就与INT一样,此时导入表中的时间戳就为0;否则导入表中的时间戳为-1时,dll的真正时间戳存放于绑定导入表中(绑定导入表地址存放在数据目录的第12项,IAT是第13项)。

现在大多数情况,导入表的TimeDateStamp都为0,而Windows早期的自带软件(如WinXP的notepad.exe)基本都采用了TimeDateStamp为-1的情况即包含绑定导入表的情况。PE中包含导入表的优点是程序启动快,但是其缺点也十分明显,当存在dll地址重定位和dll修改更新,则绑定导入表也需要修改更新。

//最后一个结构全0表示绑定导入表结束

typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {

    DWORD   TimeDateStamp;      //表示绑定的时间戳,如果和PE头中的TimeDateStamp不同则可能被修改过

    WORD    OffsetModuleName;   //dll名称地址

    WORD    NumberOfModuleForwarderRefs;    //依赖dll个数

// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows

} IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

NumberOfModuleForwarderRefs是指该dll自身依赖的dll的个数。值为n代表该结构后面紧跟了n个IMAGE_BOUND_FORWARDER_REF结构。之后才是导入表导入的下一个dll的结构。而IMAGE_BOUND_FORWARDER_REF结构体如下所示:

typedef struct _IMAGE_BOUND_FORWARDER_REF {

    DWORD   TimeDateStamp;  //时间戳,同样的作用检查更新情况

    WORD    OffsetModuleName;   //dll名称地址

    WORD    Reserved;   //保留

} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;

注意:这两个结构体中所有的OffsetModuleName均不是相对于ImageBaseRVA也不是FOA,而是相对于绑定导入表首地址的偏移地址,即:绑定导入表首地址 + OffsetModuleName= RVA

绑定导入表结构图解如下所示:

创建新的IDT:

先使用Hex Editor完全复制原IDT(RAW:76CC~772F),然后覆盖到IDT的新位置(RAW:7E80)

复制:

覆盖:

在7ED0处写入IID

详解如下图

修改IAT节区的属性

三天才整完这一课,中途在使用winhex的时候出了点小差错弄了很久,只要有耐心,成功之后会非常有成就感的

猜你喜欢

转载自blog.csdn.net/qq_41917908/article/details/81429911