DLL注入之修改PE靜態注入
0x00 前言
我們要注入的的力量功能是下載baidu首頁數據。代碼如下:
#include "stdio.h"
#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.baidu.com/index.html"
#define DEF_INDEX_FILE L"index.html"
HWND g_hWnd = NULL;
#ifdef __cplusplus
extern "C" {
#endif
__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);
}
/*
_ACRTIMP size_t __cdecl fwrite(
_In_reads_bytes_(_ElementSize * _ElementCount) void const* _Buffer,
_In_ size_t _ElementSize,
_In_ size_t _ElementCount,
_Inout_ FILE* _Stream
);
*/
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;
}
編譯生成名為myhack3.dll的released文件。如下圖:
被注入的文件是一個名為TextView.exe的文件。如下圖:
0x01 修改PE文件注入思路
通過修改IID數組添加myhack3.dll,修改INT,IAT,以及字段NAME。
0x02 實施步驟
1)修改IID數組。
我們先找到IID數組所在,3ch找到PE頭,值位E0,通過E0+80=160H
找到IID地址。如下圖:
可知RVA為84CC大小為64h。
2)通過lordPE查找區段信息,確定84CC的FileOffset值。如下圖:
通過上圖區段信息可得到84CC位於.rdata區段。轉換為FileOffset=84CC-6000+5200=76CC。當然也可以使用LordPE自帶的位置計算器計算,如下圖:
和我計算的結果一致。
使用HexWorkShop跳轉至76cc處。76cc至772F處為IID數組的值。如下圖:
顯然,再在這個位置添加myhack的IID結構肯定已經放不下了。所以我們得將整體的IID數組搬遷至新位置。
3)確定IID數組的新位置。有三種方式一是找一塊空白區域吧,二是增加最后一個節區大小,然后把IID數組搬過去。三是添加新的節區,然后把IID裝進去。顯然,第一種方式最省事,而且IID數組也不是很大。我們仔細分析區段信息,如下圖:
顯然區段.rdata磁盤中的大小為2E00而映射到內存中的大小2C56。也就是在2C56至2E00有一塊大小為1AA大小的空白區域,這塊區域全是用0填充的。我們選定IID數組從RAV=8C80
開始。
4)將原先IID數組的數據復制,在新地址8C80處填充。如下圖:
隨后在7ED0后面填寫自己構造的IID結構。
5)為了方便,我們就干脆將myhack3.dll的IID的值構造在.rdata的剩余區域。
構造值在下表:(無關緊要的字段設置為0)
|
RVA |
RAW |
INT地址 |
8d00 |
7F00 |
Name地址 |
8d10 |
7F10 |
IAN地址 |
8d20 |
7F20 |
一次將值填入如下圖:
6)根據上表填寫THUN_DATA結構,我們myhack.dll的被調用函數放置在803D處。Name處指向的IMAGE_IMPORT_BY_NAME結構的填入myhack.dll。如下圖:
最后修改160處的IID入口地址和大小,改為808c和78。如下圖:
至此,重構輸入表完成。
7)還有一點值得特別注意的是。我們在在.rdata區段修改了IID數組,其中IAT表也會隨之改變,這就要求.rdata區域能夠有讀寫權限,不然,IAT無法重構。我們來查看.rdata的讀取權限,如下圖:
顯然,只讀。所以我們要添加寫權限。我們就在原來值40000040加上寫入權限值c00000000。
加完之后值為c00000040。我們將此值寫入224處。
8)另存為TextView5.exe。點擊運行。記得把myhack.dll放在同一文件目錄,不然無法注入。打開processexploer。查看師是否注入成功。下如圖:
顯然已經成功注入。下圖是運行后下載的index.html
0x03 另一種方法
在上面的方法中,我們注意到IAT和INT的地址寫的是一樣的,且而后面要更改.rdata區塊的讀出權限。其實我們可以另辟蹊徑。用PEview再次打開修改后的文件TextView5。沃恩打開存放在.data區塊的IAT表,如下圖:(注意下面的圖我都是切換了RVA模式)
我們可以更改上圖中的IAT表的大小,增加八個字節存放myhack.dll的地址8D30。即6154存放myhack.dll函數地址。這樣無需修改權限也能正常載入。
步驟如下:
1)更改myhack.dll的IID結構中的FristThunK值,使它指向地址6154。
如下圖:
2)IAT表末尾6154處填入myhack3.dll函數dummy的地址8D30 。如下圖:
3)更改IAT表的大小和.rdata的讀取權限(恢復原來的只讀權限)
如下圖:
保存。運行並查看IAT的變化如下圖: