• 标 题: 第二章.    Dump程序的改进
  • 作 者:Lenus
  • 时 间:2005-10-15 20:56

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

附件:实例下载