roger 发表于 2020-9-1 10:58:26

【windows代码注入教程】第四课 通过修改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 = {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 = {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 = {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;         //指向引入函数真实地址单元处的RVAIAT
  } 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均不是相对于ImageBase的RVA也不是FOA,而是相对于绑定导入表首地址的偏移地址,即:绑定导入表首地址 + OffsetModuleName= RVA
  绑定导入表结构图解如下所示:
  创建新的IDT:
  先使用Hex Editor完全复制原IDT(RAW:76CC~772F),然后覆盖到IDT的新位置(RAW:7E80)
  复制:
  覆盖:
  在7ED0处写入IID
  详解如下图
  修改IAT节区的属性
  三天才整完这一课,中途在使用winhex的时候出了点小差错弄了很久,只要有耐心,成功之后会非常有成就感的
            
页: [1]
查看完整版本: 【windows代码注入教程】第四课 通过修改PE加载DLL