第二章. Dump程式的改進
“發展才是硬道理”
----鄧小平
正如我們上面一節所做的,一個dump的雛形已經形成了,現在要做的是給它在原來的基礎上做進一步的改進。
一. 獲取Imageofsize
相信大家也感覺到了,在前面一章介紹的獲取ImageofSize的辦法實在很不可靠,對於一個加殼程式隨意的修改他載入了記憶體中的PE頭,是很稀疏平常的事情。所以用讀取目標程式中的PE頭並不是一個好主義。
現在我就來介紹一下一般的辦法。對於LordPE他的dump是採用什麼方法呢?它採用了對Module32Next來獲取dump的程式的基本資訊的。
BOOL WINAPI Module32First(
HANDLE hSnapshot, //這是先前的CreateToolhelp32Snapshot函式返回的快照
LPMODULEENTRY32 lpme //這個是指向MODULEENTRY32結構的指標
);
下面是MUDULEENTRY32結構:
typedef struct tagMODULEENTRY32 {
DWORD dwSize;
DWORD th32ModuleID;
DWORD th32ProcessID;
DWORD GlblcntUsage;
DWORD ProccntUsage;
BYTE *modBaseAddr;
DWORD modBaseSize; //這個是是我們要獲取的關鍵
HMODULE hModule;
TCHAR szModule[MAX_PATH];
TCHAR szExePath[MAX_PATH];
DWORD dwFlags;
} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32;
下面就給出重新寫的新的GetSizeOfImage的函式
int GetSizeOfImage(HWND hDlg,DWORD IDProcess)
{
//這個函式的作用是獲取SizeOfImage的數值
//當函式執行失敗返回的是0
//成功返回的是非0
HANDLE hModuleSnap = NULL;
MODULEENTRY32 stModE = {0};
stModE.dwSize = sizeof(MODULEENTRY32);
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,IDProcess); //快照,對本程式中所有的模組進行snap
if (hModuleSnap == INVALID_HANDLE_VALUE)
{
MessageBox(hDlg,TEXT("The Module snapshot can't get!"),TEXT("Error!"),MB_OK | MB_ICONSTOP);
return FALSE; //返回0
}
if (!Module32First(hModuleSnap, &stModE))
{
MessageBox(hDlg,TEXT("The Module32First can't work!"),TEXT("Error!"),MB_OK | MB_ICONSTOP);
CloseHandle (hModuleSnap);
return FALSE;
}
CloseHandle (hModuleSnap);
return stModE.modBaseSize;//初始化為0
}
二. 對齊節表
這個問題在上一節我們已經提出了,我們的程式不完善,現在要自動的實現RA=RVA ,RS=RVS這個功能。那麼我們就使用一個函式來完成它吧!我定義了下面這個函式:
BOOL ModifySectionFunc(HWND hDlg,LPCTSTR Dump_Name)
{
//此函式的將修改dump下來的exe,使其RA=RVA ,RS=RVS
//首先是開啟dump檔案
HANDLE hFile=CreateFile(Dump_Name,GENERIC_WRITE | GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
MessageBox(hDlg,TEXT("I can open the dump file..."),TEXT("Error!!"),MB_OK | MB_ICONWARNING);
return FALSE;
}
//下面移動到節表前面
IMAGE_DOS_HEADER myDosHeader;
DWORD NumberOfBytesRead;
ReadFile(hFile,(LPVOID)&myDosHeader,sizeof(IMAGE_DOS_HEADER),&NumberOfBytesRead,NULL);
SetFilePointer(hFile,myDosHeader.e_lfanew+sizeof(DWORD),NULL,FILE_BEGIN);
IMAGE_FILE_HEADER myNtHeader;
ReadFile(hFile,(LPVOID)&myNtHeader,sizeof(IMAGE_FILE_HEADER),&NumberOfBytesRead,NULL);
int nSectionCount;
nSectionCount = myNtHeader.NumberOfSections; // 儲存Section個數
// 過了IMAGE_NT_HEADERS結構就是IMAGE_SECTION_HEADER結構陣列了,注意是結構陣列,有幾個Section該結構就有幾個元素
// 這裡動態開闢NumberOfSections個記憶體來儲存不同的Section資訊
IMAGE_SECTION_HEADER *pmySectionHeader = (IMAGE_SECTION_HEADER *)calloc(nSectionCount, sizeof(IMAGE_SECTION_HEADER));
SetFilePointer(hFile,myDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS),NULL,FILE_BEGIN);
ReadFile(hFile,(LPVOID)pmySectionHeader,sizeof(IMAGE_SECTION_HEADER)*nSectionCount,
&NumberOfBytesRead,NULL);
//移動回到節表的開始,準備寫入
SetFilePointer(hFile,myDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS),NULL,FILE_BEGIN);
for (int i = 0; i < nSectionCount; i++, pmySectionHeader++)
{
//將RA=RVA ,RS=RVS
pmySectionHeader->SizeOfRawData=pmySectionHeader->Misc.VirtualSize;
pmySectionHeader->PointerToRawData=pmySectionHeader->VirtualAddress;
//將修改好的數值寫回
WriteFile(hFile,(LPVOID)pmySectionHeader,sizeof(IMAGE_SECTION_HEADER),&NumberOfBytesRead,NULL);
}
// 恢復指標
pmySectionHeader -=nSectionCount;
if (pmySectionHeader != NULL) // 釋放記憶體
{
free(pmySectionHeader);
pmySectionHeader = NULL;
}
// 最後不要忘記關閉檔案
CloseHandle(hFile);
return TRUE;
}
這個函式是在生成了一個新的dump檔案以後,然後在開啟它,找到節表。把裡面的資料修改過來。
三. 小節
這樣,一個改進型的程式就搞定了。現在當我們用他dump下新的程式的時候得到的就是一個有圖示的程式了。因為我們已經把節表修改過來了。下面一章我們將介紹anti-dump的技巧。
附件:例項下載