欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]元宵节献礼,用类的思想处理PE结构附源码

[原创]元宵节献礼,用类的思想处理PE结构附源码

最近在论坛里接了个业务,客户看了我的ID后说,我发的都是求助帖,对我的能力很质疑,我自己一看才发现,真是除了几年前发了个破解的帖子蒙混过关骗得一个邀请码之外,一直在做伸手党,于是翻出了之前给赏金论坛做过的一套《壳的编写》的教程,因为做的时候答应人家不能再出售,所以就不发教程了,只是把里面的源码拿来用下。
    一直以来我都是以开发为主,类的思想在我脑海里根深蒂固,几年前研究PE结构的时候发现,PE结构完全可以用类的思想处理,于是写了几个处理的代码,并用这个思想写了个简单的加壳程序,可以给notepad.exe加壳,仅供参考,现把代码贴上献丑。
---------------------------------第二次编辑---------------------------------------------------------
其实主要想法就是减少重复劳动,做到代码最大限度的重用,把功能模块化,比如得到NT头,这个功能很多数据都是通过这里开始的,这样就不用每次都重复这个代码,直接调用类中的这个代码就可以了,特别是利用C++的集成功能,可以在继承的子类中使用这部分代码,而对于子类这个代码是不可见的,功能可以用类区分开,代码非常容易管理。下面贴出个别核心代码供大家参考。

//基本的PE处理 可以得到dos头 NT头 节 等信息
class LPEFile  
{
public:
  BOOL LoadPEFile(BYTE* lpBuffer,DWORD dwSize);          //载入PE文件
  LPVOID RvaToPtr(DWORD dwRVA);                          //计算偏移
  LPVOID GetDirectoryEntryToData(USHORT DirectoryEntry);   
  PIMAGE_SECTION_HEADER GetSection(int nIndex);           //得到节的信息
  BOOL IsPEFile();
  PIMAGE_SECTION_HEADER GetFirstSectionHeader();         //得到第一个节
  int GetSectionCount();                                 //得到节的个数
  PIMAGE_DATA_DIRECTORY GetDataDirectory(int nIndex);     //得到数据目录
  PIMAGE_DATA_DIRECTORY GetDataDirectory();               //得到数据目录
  PIMAGE_OPTIONAL_HEADER GetNtOptionalHeader();           
  PIMAGE_FILE_HEADER GetNtFileHeader();
  PIMAGE_NT_HEADERS GetNtHeader();          
  PIMAGE_DOS_HEADER GetDosHeader();
  DWORD GetImageSize();
  BYTE* GetImage();
  bool Free();
  BOOL LoadPEFile(char* lpFilename);
  BOOL SetInfo(MAP_FILE_STRUCT *pMapFileMsg);
  MAP_FILE_STRUCT* GetInfo();
  void operator=(LPEFile& lPeFile);
  LPEFile();
  virtual ~LPEFile();
private:
  //用于标识文件的打开状态//用于标识文件的打开状态
    BYTE bLoadStact;    
    //用于存储打开的文件句柄,文件数据,文件大小
protected:
    MAP_FILE_STRUCT *pstMapFile;
};
//用于将文件载入内存
BOOL LPEFile::LoadPEFile(char *lpFilename)
{
	HANDLE hFile;
	HANDLE hMapping;
	LPVOID ImageBase;
    pstMapFile=new MAP_FILE_STRUCT;
	bLoadStact=LFILE_FROM_FILE;
	hFile=CreateFile(lpFilename,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,NULL);
	if (hFile==NULL)
	{
		return FALSE;
	}
	pstMapFile->dwFileSize=GetFileSize(hFile,NULL);
	hMapping=CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,pstMapFile->dwFileSize,NULL);
	if (hMapping==NULL)
	{
		CloseHandle(hFile);
		return FALSE;
	}
	ImageBase=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,pstMapFile->dwFileSize);
	if (ImageBase==NULL)
	{
		CloseHandle(hFile);
		CloseHandle(hMapping);
		return FALSE;
	}
	pstMapFile->hFile=hFile;
	pstMapFile->hMapping=hMapping;
	pstMapFile->ImageBase=ImageBase;
   return TRUE;
}
//得到文件的dos头
PIMAGE_DOS_HEADER LPEFile::GetDosHeader()
{
   return (PIMAGE_DOS_HEADER)GetImage();
}
//得到文件的NT头,这里就不需要从得到Dos开始了,直接调用编写好的类函数
PIMAGE_NT_HEADERS LPEFile::GetNtHeader()
{
    PIMAGE_DOS_HEADER pDH=GetDosHeader();
	if (pDH!=NULL)
	{
		return (PIMAGE_NT_HEADERS32)((DWORD)GetImage()+pDH->e_lfanew);
	}
	return NULL;
}
//得到文件头
PIMAGE_FILE_HEADER LPEFile::GetNtFileHeader()
{
   PIMAGE_NT_HEADERS pNth=GetNtHeader();
   if (pNth!=NULL)
   {
	   return (PIMAGE_FILE_HEADER)&pNth->FileHeader;
   }
   return NULL;
}
//得到可选头
PIMAGE_OPTIONAL_HEADER LPEFile::GetNtOptionalHeader()
{
	PIMAGE_NT_HEADERS pNth=GetNtHeader();
	if (pNth!=NULL)
	{
		return (PIMAGE_OPTIONAL_HEADER32)&pNth->OptionalHeader;
	}
   return NULL;
}
//得到数据目录
PIMAGE_DATA_DIRECTORY LPEFile::GetDataDirectory()
{
   PIMAGE_OPTIONAL_HEADER pOptionalHeader=GetNtOptionalHeader();
   if (pOptionalHeader!=NULL)
   {
	   return (PIMAGE_DATA_DIRECTORY) pOptionalHeader->DataDirectory;
   }
   return NULL;
}
PIMAGE_DATA_DIRECTORY LPEFile::GetDataDirectory(int nIndex)
{
    if (nIndex>=0&&nIndex<16)
    {
        PIMAGE_DATA_DIRECTORY pDataDir=GetDataDirectory();
		if (pDataDir!=NULL)
		{
				return &pDataDir[nIndex];
		}
    }
	return NULL;
}

有了基本的PE处理之后,就可以在类上做继承,扩展新功能,功能上独立,代码简洁。
//继承LPEFile里面基础处理功能并对  对节处理进行扩展
class LPESection : public LPEFile  
{
public:
  BOOL WriteSectionData(int nIndex,DWORD dwOffset,BYTE* lpBuffer,DWORD *dwSize);   //写入节数据
  BYTE* GetSectionData(int nIndex,DWORD* rdwSize);                                  //得到节数据
  BOOL AddSection(char* pSectionName,DWORD &dwSectionSize,DWORD dwSectionStact);     //添加一个节
  DWORD OffsetToRva(DWORD dwOffset);                                                 //计算偏移
  DWORD RvaToOffset(DWORD dwRva);                                                    //计算偏移
  DWORD GetVRk(int nSeciotnIndex);
  int OffsetToSectionIndex(DWORD dwOffset);
  int RvaToSectionIndex(DWORD dwRva);
  LPESection();
  virtual ~LPESection();
  void operator =(LPEFile& lPeFile);
};
//得到节的数据,代码非常简洁,因为很多功能来自父类
BYTE* LPESection::GetSectionData(int nIndex, DWORD *rdwSize)
{
      BYTE* lpBuffer=NULL;
      PIMAGE_SECTION_HEADER pSection=GetSection(nIndex);
	  if (pSection->SizeOfRawData>0)
	  {
		  DWORD dwFileOffset=pSection->PointerToRawData;
		  *rdwSize=pSection->SizeOfRawData;
		  lpBuffer=GetImage()+dwFileOffset;
	  }
	  return lpBuffer;
}
//写入节数据
BOOL LPESection::WriteSectionData(int nIndex, DWORD dwOffset, BYTE *lpBuffer, DWORD *dwSize)
{
   BOOL bIsOK=false;
   DWORD dwSectionSize;
   BYTE* lpMyBuffer=NULL;
   lpMyBuffer=GetSectionData(nIndex,&dwSectionSize);
   if (lpMyBuffer!=NULL&&dwSectionSize>=(*dwSize+dwOffset))
   {
	   lpMyBuffer=lpMyBuffer+dwOffset;
	   memcpy(lpMyBuffer,lpBuffer,*dwSize);
	   FlushViewOfFile(pstMapFile->hMapping,pstMapFile->dwFileSize);
	   bIsOK=TRUE;
   }
   return bIsOK;
}
//继承自LPEFile  对处理重定位表功能进行扩展
class LPEReLocal : public LPEFile  
{
public:
  BOOL RelocaltionVA(DWORD dwNewAddress, DWORD dwNewImageBase, DWORD &dwOldVA);    
  BOOL RelocationMySelf(DWORD dwNewSecAddress,DWORD dwImageBase);
  DWORD GetReLocaltionRVA(int nRelocalIndex,int nTypeOffsetIndex);
  WORD GetReLocationType(int nRelocalIndex,int nTypeOffsetIndex);
  WORD GetTypeOffset(int nRelocalIndex,int nOffsetIndex);
  int GetTypeOffsetCount(int nIndex);
  PIMAGE_BASE_RELOCATION GetReLocal(int nCount,DWORD *rdwOffset);
  int GetReLocalCount();
  PIMAGE_BASE_RELOCATION GetFirstReLocaltion();
  LPEReLocal();
  virtual ~LPEReLocal();
  void operator=(LPEFile& lPeFile);
};
//得到首个重定位表
PIMAGE_BASE_RELOCATION LPEReLocal::GetFirstReLocaltion()
{
    PIMAGE_BASE_RELOCATION pRelocalDesc=NULL;
	pRelocalDesc=(PIMAGE_BASE_RELOCATION)GetDirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_BASERELOC);
    if (pRelocalDesc==NULL)
    {
		return NULL;
    }
	return pRelocalDesc;
}
//得到重定位表的个数
int LPEReLocal::GetReLocalCount()
{
   int i=0;
   DWORD dwOffset;
   PIMAGE_DATA_DIRECTORY pDataDir=GetDataDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC);
   dwOffset=pDataDir->VirtualAddress;
   PIMAGE_BASE_RELOCATION pTempReLocal=GetFirstReLocaltion();
   while(pTempReLocal->VirtualAddress)
   {
	   ++i;
	   dwOffset=dwOffset+(pTempReLocal->SizeOfBlock);
	   pTempReLocal=(PIMAGE_BASE_RELOCATION)RvaToPtr(dwOffset);
   }
   return i;
}
//继承自LPEFile 对处理导入表功能进行扩展
class LPEImport : public LPEFile  
{
public:
  BOOL ReLocalImport(DWORD dwRVA);
  DWORD GetImportThunk(PIMAGE_IMPORT_DESCRIPTOR pImportDesc);
  void operator=(LPEFile& lPeFile);
  PIMAGE_IMPORT_BY_NAME GetImportFucByName(DWORD RavThunk);
  PIMAGE_IMPORT_DESCRIPTOR GetImportDesc(int index);
  int GetImportDesCount();
  PIMAGE_IMPORT_DESCRIPTOR GetFirstImportDesc();
  LPEImport();
  virtual ~LPEImport();
};
//得到整个首个导入表
PIMAGE_IMPORT_DESCRIPTOR LPEImport::GetFirstImportDesc()
{
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
	pImportDesc=(PIMAGE_IMPORT_DESCRIPTOR)GetDirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_IMPORT);
	if(!pImportDesc)
		return NULL;	 
	return  pImportDesc;
}
//得到共有多少个dll
int LPEImport::GetImportDesCount()
{
	int i=0;
	PIMAGE_IMPORT_DESCRIPTOR pTempImport=GetFirstImportDesc();
	while (pTempImport->FirstThunk)
	{
		++i;
		++pTempImport;
	}
	return i;
}
// 得到某个dll导入表
PIMAGE_IMPORT_DESCRIPTOR LPEImport::GetImportDesc(int index)
{
    int i=GetImportDesCount();
	if (index>=i)
	{
		return NULL;
	}
	PIMAGE_IMPORT_DESCRIPTOR pTempImport=GetFirstImportDesc();
	return &pTempImport[index];
}
//得到某个API 函数的名字
PIMAGE_IMPORT_BY_NAME LPEImport::GetImportFucByName(DWORD RavThunk)
{
	PIMAGE_NT_HEADERS     pNtH=NULL;
	PIMAGE_IMPORT_BY_NAME pApiName=NULL;
	pApiName=(PIMAGE_IMPORT_BY_NAME)RvaToPtr(RavThunk);
	return pApiName;
}
//继承自LPEFile对处理导出表功能进行扩展
class LPEExport : public LPEFile  
{
public:
  WORD GetNameOrdValue(int nIndex);
  DWORD GetNameOrd(int nIndex);
  DWORD GetFirstNameOrd();
  char* GetNameValue(int nIndex);
  DWORD GetName(int nIndex);
  DWORD GetFirstName();
  DWORD GetFuncValue(int nIndex);
  DWORD GetFunc(int nIndex);
  DWORD GetFirstFunc();
  int GetNameCount();
  int GetFuncCount();
  PIMAGE_EXPORT_DIRECTORY GetExportTab();
  LPEExport();
  virtual ~LPEExport();
  void operator=(LPEFile& lPeFile);
};
PIMAGE_EXPORT_DIRECTORY LPEExport::GetExportTab()
{
     PIMAGE_EXPORT_DIRECTORY pExportDesc;
	 pExportDesc=(PIMAGE_EXPORT_DIRECTORY)GetDirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_EXPORT);
     if (pExportDesc==NULL)
     {
         return NULL;
     }
	 return pExportDesc;
}
int LPEExport::GetFuncCount()
{
   PIMAGE_EXPORT_DIRECTORY pExportDesc=GetExportTab();
   if (pExportDesc)
   {
        return pExportDesc->NumberOfFunctions;
   }
   return -1;
}
int LPEExport::GetNameCount()
{
    PIMAGE_EXPORT_DIRECTORY pExportDesc=GetExportTab();
	if (pExportDesc)
	{
        return pExportDesc->NumberOfNames;
	}
   return -1;
}
DWORD LPEExport::GetFirstFunc()
{
	PIMAGE_EXPORT_DIRECTORY pExportDesc=GetExportTab();
	if (pExportDesc)
	{
       return pExportDesc->AddressOfFunctions;
	}
    return 0;
}
DWORD LPEExport::GetFunc(int nIndex)
{
   if (nIndex<GetFuncCount())
   {
       DWORD dwFirstFunc=GetFirstFunc();
	   return dwFirstFunc+nIndex*4;
   }
   return 0;
}

开源的加壳代码已经很多了,重要的不是介绍怎样加壳,而是给大家提供一种新的PE文件处理思路,本人小菜,不当之处请多包含!

上传的附件 Lang.7z

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功