第二章.    Dump程式的改進

看雪資料發表於2015-11-15

第二章.    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的技巧。

附件:例項下載

相關文章