1、申 请 I D :IDK
2、个人邮箱:278580509@qq.com
VS 2013 MFC 64位环境下 解析64位PE文件
//导出表
CString m_ExputTable;
//导入表
CString m_ImportTable;
//资源表
CString m_ResourceTable;
//重定位表
CString m_RelocationeTable;
//TLS表
CString m_TLSTable;
//延迟输入表
CString m_DelayImportTable;
//区段表
CString m_SectionsTable;
//数据目录表
CString m_DataTable;
[C++] 纯文本查看 复制代码
CFile file;
BOOL bResult = file.Open(m_PEShowOpenPath, CFile::modeRead | CFile::shareDenyNone, NULL);
CFileStatus status;
file.GetStatus(status);
TmpCstr = status.m_ctime.Format(_T("创建时间:%Y-%m-%d %H:%M:%S \r\n"));
m_VaPEShowEdit += TmpCstr;
TmpCstr = status.m_mtime.Format(_T("修改时间:%Y-%m-%d %H:%M-%S\r\n"));
m_VaPEShowEdit += TmpCstr;
TmpCstr = status.m_atime.Format(_T("访问时间:%Y-%m-%d %H:%M-%S\r\n"));
m_VaPEShowEdit += TmpCstr;
TCHAR A[64] = { 0 };
_stprintf_s(A, L"%u KB", status.m_size);
TmpCstr = (_T("大小:"));
TmpCstr += A;
TmpCstr += (_T("\r\n"));
m_VaPEShowEdit += TmpCstr;
file.Close();
HANDLE hFile = INVALID_HANDLE_VALUE;
CString Error = _T("");
hFile = CreateFile(m_PEShowOpenPath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
Error.Format(_T("错误码:%d"), GetLastError());
m_ControlPEShow.SetWindowTextW(m_VaPEShowEdit);
MessageBox(Error);
m_ControlPEShow.SetWindowTextW(m_VaPEShowEdit);
return 0;
}
DWORD dwFileSize = GetFileSize(hFile, NULL);
pFileData = new BYTE[dwFileSize];
DWORD dwReadSize = 0;
if (!ReadFile(hFile, pFileData, dwFileSize, &dwReadSize, NULL))
{
Error.Format(_T("错误码:%d"), GetLastError());
m_ControlPEShow.SetWindowTextW(m_VaPEShowEdit);
MessageBox(Error);
return 0;
}
// 使用DOS头结构指向缓冲区
IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER*)pFileData;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
MessageBox(_T("没有MZ标记"));
m_ControlPEShow.SetWindowTextW(m_VaPEShowEdit);
return FALSE;
}
// 判断是否是有效的NT头
// 获取Nt头
IMAGE_NT_HEADERS* pNTHeader = (IMAGE_NT_HEADERS*)(pDosHeader->e_lfanew + (ULONG64)pDosHeader);
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) {
MessageBox(_T("没有PE标记"));
m_ControlPEShow.SetWindowTextW(m_VaPEShowEdit);
return FALSE;
}
m_VaPEShowEdit += _T("\r\n");
m_VaPEShowEdit += _T("********PE头解析***********");
m_VaPEShowEdit += _T("\r\n");
//获取PE头
IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(pDosHeader->e_lfanew + (ULONG64)pDosHeader + 4);
//CUP
if (pFileHeader->Machine == IMAGE_FILE_MACHINE_I386)
{
m_VaPEShowEdit += _T("运行平台:Intel 386");
m_VaPEShowEdit += _T("\r\n");
}
else if (pFileHeader->Machine == IMAGE_FILE_MACHINE_IA64)
{
m_VaPEShowEdit += _T("运行平台:Intel 64");
m_VaPEShowEdit += _T("\r\n");
}
else if (pFileHeader->Machine == IMAGE_FILE_MACHINE_AMD64)
{
m_VaPEShowEdit += _T("运行平台:AMD64 (K8)");
m_VaPEShowEdit += _T("\r\n");
}
else{
m_VaPEShowEdit += _T("运行平台:其他");
m_VaPEShowEdit += _T("\r\n");
}
TmpCstr.Format(_T("文件的区块数目:%d"), pFileHeader->NumberOfSections);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
tm createTime = { 0 };
errno_t nRet = _gmtime64_s(&createTime, (__time64_t *)&pFileHeader->TimeDateStamp);
if (nRet==0)
{
TCHAR tmp[50] = { 0 };
_wasctime_s(tmp, &createTime);
m_VaPEShowEdit += tmp;
m_VaPEShowEdit += _T("\r\n");
}
else
{
TmpCstr.Format(_T("获取时间出错错误代码:%d\r\n"), nRet);
m_VaPEShowEdit += TmpCstr;
}
TmpCstr.Format(_T("指向符号表:%d"), pFileHeader->PointerToSymbolTable);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("符号表中符号个数:%d"), pFileHeader->NumberOfSymbols);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("IMAGE_OPTIONAL_HEADER32大小:%d"), pFileHeader->SizeOfOptionalHeader);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("文件属性:%d"), pFileHeader->Characteristics);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
//区块表
// 得到第一个区段
IMAGE_SECTION_HEADER* pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader);
for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++) {
TCHAR tmpWchar[9] = { 0 };
CHAR_TO_WCHAR((CHAR*)&(pSectionHeader.Name), tmpWchar);
TmpCstr.Format(_T("区段名: %s"), tmpWchar);
m_SectionsTable += TmpCstr;
m_SectionsTable += _T("\r\n");
TmpCstr.Format(_T("区段数据的文件偏移:%x H"), pSectionHeader.PointerToRawData);
m_SectionsTable += TmpCstr;
m_SectionsTable += _T("\r\n");
TmpCstr.Format(_T("区段数据的RVA:%x H"), pSectionHeader.VirtualAddress);
m_SectionsTable += TmpCstr;
m_SectionsTable += _T("\r\n");
TmpCstr.Format(_T("区段数据的大小:%x H"), pSectionHeader.SizeOfRawData);
m_SectionsTable += TmpCstr;
m_SectionsTable += _T("\r\n");
m_SectionsTable += _T("\r\n");
m_SectionsTable += _T("\r\n");
}
CString File32Or64;
if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
File32Or64=_T("文件类型:32位\r\n");
m_VaPEShowEdit += File32Or64;
AnalysisOF32BitPE();
}
else if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC){
File32Or64 = _T("文件类型:64位\r\n");
m_VaPEShowEdit += File32Or64;
AnalysisOF64BitPE();
}
[C++] 纯文本查看 复制代码 DWORD PEShow::RvaToOffset(DWORD dwRva)
{
// TODO: 在此添加控件通知处理程序代码
IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER*)pFileData;
IMAGE_NT_HEADERS *pNtHeader = /*换行*/
(IMAGE_NT_HEADERS*)((ULONGLONG)pDosHeader + pDosHeader->e_lfanew);
// 得到区段个数
DWORD dwSectionNumber = pNtHeader->FileHeader.NumberOfSections;
// 得到第一个区段
IMAGE_SECTION_HEADER* pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
for (int i = 0; i < dwSectionNumber; ++i)
{
// 判断RVA是否在当前的区段中
DWORD dwSectionEndRva = /*换行*/
pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData;
if (dwRva >= pSectionHeader[i].VirtualAddress
&& dwRva <= dwSectionEndRva) {
// 计算出RVA对应的文件偏移
// 公式:
// 文件偏移 = RVA - 区段的起始RVA + 区段的起始文件偏移
DWORD dwTemp = dwRva - pSectionHeader[i].VirtualAddress;
DWORD dwOffset = dwTemp + pSectionHeader[i].PointerToRawData;
return dwOffset;
}
}
return -1;
} [C++] 纯文本查看 复制代码 //64位PE
void PEShow::AnalysisOF64BitPE()
{
CString TmpCstr;
// 得到DOS头
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pFileData;
// 得到Nt头(为了得到扩展头得先找到Nt头)
IMAGE_NT_HEADERS64* pNtHeader = /* 换行 */
(IMAGE_NT_HEADERS64*)(pDosHeader->e_lfanew + (ULONG64)(pDosHeader));
IMAGE_OPTIONAL_HEADER64* pOptionalHeader = &pNtHeader->OptionalHeader;
m_VaPEShowEdit += _T("\r\n");
m_VaPEShowEdit += _T("********扩展头解析***********");
m_VaPEShowEdit += _T("\r\n");
//获取 扩展头
//IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNTHeader->OptionalHeader;
TmpCstr.Format(_T("程序执行入口RVA:%x H"), pOptionalHeader->AddressOfEntryPoint);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("程序基址RVA:%x H"), pOptionalHeader->ImageBase);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("代码基址RVA:%x H"), pOptionalHeader->BaseOfCode);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
//TmpCstr.Format(_T("数据基址RVA:%x H"), pOptionalHeader->BaseOfData);
//m_VaPEShowEdit += TmpCstr;
//m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("内存中的区块的对齐大小:%x H"), pOptionalHeader->SectionAlignment);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("文件中的区块的对齐大小:%x H"), pOptionalHeader->FileAlignment);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("映像装入内存后的总尺寸:%x H"), pOptionalHeader->SizeOfImage);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
TmpCstr.Format(_T("所有头+区块表的尺寸大小:%x H"), pOptionalHeader->SizeOfHeaders);
m_VaPEShowEdit += TmpCstr;
m_VaPEShowEdit += _T("\r\n");
m_ControlPEShow.SetWindowText(m_VaPEShowEdit);
//数据目录表
for (int i = 0; i < pOptionalHeader->NumberOfRvaAndSizes; i++)
{
m_DataTable += _T("\r\n");
TmpCstr.Format(_T("数据的RVA:%x H "), pOptionalHeader[i].DataDirectory->Size);
m_DataTable += TmpCstr;
TmpCstr.Format(_T("数据大小:%x H "), pOptionalHeader[i].DataDirectory->VirtualAddress);
m_DataTable += TmpCstr;
m_DataTable += _T("\r\n");
}
//导出表
// 获取到数据目录表
IMAGE_DATA_DIRECTORY* pDataDirectory = pOptionalHeader->DataDirectory;
//获得导出表
DWORD dwExportTableRva = pDataDirectory[0].VirtualAddress;
//将多出表的RVA转换成文件偏移
if (dwExportTableRva == 0)
{
m_ExputTable = _T("没有数据");
}
else
{
ULONG64 dwExportTableOffset = RvaToOffset(dwExportTableRva);
IMAGE_EXPORT_DIRECTORY *pExportTable = (IMAGE_EXPORT_DIRECTORY*)(dwExportTableOffset + (ULONG64)pFileData);
ULONG64 dwNameOffset = RvaToOffset(pExportTable->Name);
char* pDllName = (char*)(dwNameOffset + (ULONG64)pFileData);
TCHAR ETname[50] = { 0 };
CHAR_TO_WCHAR(pDllName, ETname);
m_ExputTable = ETname;
m_ExputTable += _T("\r\n\r\n");
// 把所有的导出的函数地址打印出来。
// 并且,如果是以名称导出,则输出该名称
// 如果是以序号导出,则输出该序号。
// 将地址表的RVA转换文件偏移
DWORD dwAddressTableOffset = RvaToOffset(pExportTable->AddressOfFunctions);
// 得到导出地址表
ULONG64* pAddressTable = /*换行*/
(ULONG64*)(dwAddressTableOffset + (ULONG64)pFileData);
// 得到序号表的地址
WORD* pOrdinalTable = (WORD*)((ULONG64)pFileData + RvaToOffset(pExportTable->AddressOfNameOrdinals));
DWORD* pNameTable = (DWORD*)((ULONG64)pFileData + RvaToOffset(pExportTable->AddressOfNames));
BOOL bIndexIsExist = FALSE; //
for (int i = 0; i < pExportTable->NumberOfFunctions; ++i) {
// 打印地址
TmpCstr.Format(_T("虚序号[%d] "), i);
m_ExputTable += TmpCstr;
//RVA
TmpCstr.Format(_T("地址(RVA):%08X H "), pAddressTable[i]);
m_ExputTable += TmpCstr;
bIndexIsExist = FALSE;
int nNameIndex = 0;
for (; nNameIndex < pExportTable->NumberOfNames; ++nNameIndex) {
// 判断地址表的下标是否存在于序号表中
if (i == pOrdinalTable[nNameIndex]) {
bIndexIsExist = TRUE;
break;
}
}
if (bIndexIsExist == TRUE) {
// 得到名称表中的RVA
DWORD dwNameRva = pNameTable[nNameIndex];
// 将名称Rva转换成文件偏移
char* pFunName =
(char*)((ULONG64)pFileData + RvaToOffset(dwNameRva));
TCHAR ETname1[50] = { 0 };
CHAR_TO_WCHAR(pFunName, ETname1);
TmpCstr.Format(_T("函数名:%s "), ETname1);
m_ExputTable += TmpCstr;
}
else {
// 判断地址表当前索引到的袁术是否保存着地址
if (pAddressTable[i] != 0) {
// i : 是地址表中的索引号,也就是一个虚序号
// 真正的序号 = 虚序号 + 序号基数
TmpCstr.Format(_T("序号:[%d] "), pExportTable->Base);
m_ExputTable += TmpCstr;
}
}
m_ExputTable += _T("\r\n\r\n");
}
}
//导入表
//1.1获得导入表的RVA
DWORD dwImportTableRva = pDataDirectory[1].VirtualAddress;
// 1.2 将导入表的RVA转换成文件偏移
DWORD dwImportTableOffset = RvaToOffset(dwImportTableRva);
// 1.3 将导入表结构体指针指向缓冲区中的导入表
IMAGE_IMPORT_DESCRIPTOR* pImportTable =
(IMAGE_IMPORT_DESCRIPTOR*)((ULONG64)pFileData + dwImportTableOffset);
//2. 遍历导入表块
//2.1判断是否遍历到了最后一个结构体。
while (pImportTable->Name != 0) {
//3. 解析出导入的Dll的模块名
// 3.1 将Dll模块名的RVA转换成文件偏移
DWORD dwNameOffset = RvaToOffset(pImportTable->Name);
// 3.2 用一个char*指针指向dll名在内存中的位置
char* pDllName = (char*)(dwNameOffset + (ULONG64)pFileData);
TCHAR ITname[50] = { 0 };
CHAR_TO_WCHAR(pDllName, ITname);
m_ImportTable += ITname;
m_ImportTable += _T("\r\n\r\n");
// 4. 解析当前dll的导入函数名称
// 4.1 得到导入名称表的地址
pImportTable->OriginalFirstThunk; // 导入名称表
pImportTable->FirstThunk; // 导入地址表
// 上面说的两个表,在文件中保存的内容是完全相同的。
DWORD dwIATOffset = RvaToOffset(pImportTable->FirstThunk);
IMAGE_THUNK_DATA64 *pIAT = (IMAGE_THUNK_DATA64 *)((ULONG64)pFileData + dwIATOffset);
// 4.2 遍历IAT
// IAT是一个IMAGE_THUNK_DATA结构体数组,
// 数组是一个全0结尾。
while (pIAT->u1.AddressOfData != 0) {
// 5.1 判断最高位是否是1
if (IMAGE_SNAP_BY_ORDINAL64(pIAT->u1.Ordinal)) {
// 函数是以序号导入的。
// 序号都是WORD类型,所以,只取它低16的值
TmpCstr.Format(_T("导入序号:[%d] "), (pIAT->u1.Ordinal & 0xFFFF));
m_ImportTable += TmpCstr;
}
else {
// 函数是以名称方式导入的
// 字段保存着一个指向IMAGE_IMPORT_BY_NAME结构体的RVA
DWORD dwFunctionNameOffset = /*换行*/
RvaToOffset(pIAT->u1.AddressOfData);
IMAGE_IMPORT_BY_NAME* pImportName = /*换行*/
(IMAGE_IMPORT_BY_NAME*)((ULONG64)pFileData + dwFunctionNameOffset);
TCHAR FunName[50] = { 0 };
CHAR_TO_WCHAR(pImportName->Name, FunName);
TmpCstr.Format(_T("函数名称:[%s] "), FunName);
m_ImportTable += TmpCstr;
}
// 递增到下一个结构体
++pIAT;
m_ImportTable += _T("\r\n");
}
m_ImportTable += _T("\r\n\r\n");
// 递增下一个结构体
++pImportTable;
}
// 资源表
DWORD resourcesTableOffset = RvaToOffset(pDataDirectory[2].VirtualAddress);
IMAGE_RESOURCE_DIRECTORY* pRoot =
(IMAGE_RESOURCE_DIRECTORY*)(((ULONG64)pFileData) + resourcesTableOffset);
IMAGE_RESOURCE_DIRECTORY* pDir2;// 资源目录
IMAGE_RESOURCE_DIRECTORY* pDir3;// 资源目录
IMAGE_RESOURCE_DIRECTORY_ENTRY* pEntry1;//目录入口
IMAGE_RESOURCE_DIRECTORY_ENTRY* pEntry2;//目录入口
IMAGE_RESOURCE_DIRECTORY_ENTRY* pEntry3;//目录入口
IMAGE_RESOURCE_DATA_ENTRY* pDataEntry;// 资源数据入口
IMAGE_RESOURCE_DIR_STRING_U* pIdString; // 保存Id的字符串
/* 把第一层所有的目录入口都遍历出来 */
// 得到第一个目录入口的地址
pEntry1 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pRoot + 1);
for (int i = 0;
i < pRoot->NumberOfIdEntries + pRoot->NumberOfNamedEntries;
i++, pEntry1++) {
//获取第一层目录入口的ID(ID就是资源的类型)
if (pEntry1->NameIsString == 1) {
// NameOffset该字段的值是一个偏移
// 这个偏移是以资源表根目录的地址作为基址。
pIdString =
(IMAGE_RESOURCE_DIR_STRING_U*)(pEntry1->NameOffset + (ULONG64)pRoot);
m_ResourceTable += _T("资源类型:");
m_ResourceTable += pIdString->NameString;
m_ResourceTable += _T("\r\n\r\n");
//TmpCstr.Format(_T("资源类型:%s\r\n\r\n"), pIdString->NameString);
//m_RTEdit += TmpCstr;
}
else {
TCHAR* pType[] =
{
_T(""), // 0
_T("鼠标指针"), // 1
_T("位图"), // 2
_T("图标"), // 3
_T("菜单"), // 4
_T("对话框"), //5
_T("字符串列表"), //6
_T("字体目录"), //7
_T("字体"), //8
_T("快捷键"), //9
_T("非格式化资源"), //A
_T("消息列表"), //B
_T("鼠标指针组"), //C
_T(""), // D
_T("图标组"), //E
_T(""), // F
_T("版本信息")//10
};
if (pEntry1->Id > 16)
{
TmpCstr.Format(_T("资源类型:%d\r\n\r\n"), pEntry1->Id);
m_ResourceTable += TmpCstr;
}
else
{
TmpCstr.Format(_T("资源类型:%s\r\n\r\n"), pType[pEntry1->Id]);
m_ResourceTable += TmpCstr;
}
}
// 获取第二层目录
if (pEntry1->DataIsDirectory == 1) {
pDir2 = /*得到第二层资源目录*/
(IMAGE_RESOURCE_DIRECTORY*)(pEntry1->OffsetToDirectory + (ULONG64)pRoot);
// 遍历第二层资源目录的所有目录入口
pEntry2 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pDir2 + 1);
for (int j = 0;
j < pDir2->NumberOfIdEntries + pDir2->NumberOfNamedEntries;
++j, ++pEntry2) {
// 得到资源的ID
if (pEntry2->NameIsString == 1) {
// NameOffset该字段的值是一个偏移
// 这个偏移是以资源表根目录的地址作为基址。
pIdString =
(IMAGE_RESOURCE_DIR_STRING_U*)(pEntry2->NameOffset + (ULONG64)pRoot);
TmpCstr.Format(_T(" +资源ID:%s\r\n"), pIdString->NameString);
m_ResourceTable += TmpCstr;
}
else {
TmpCstr.Format(_T(" +资源ID:%d\r\n"), (DWORD)pEntry2->Id);
m_ResourceTable += TmpCstr;
}
// 判断第三层是目录还是数据
if (pEntry2->DataIsDirectory == 1) {
// 得到第三层目录的地址
pDir3 =
(IMAGE_RESOURCE_DIRECTORY*)(pEntry2->OffsetToDirectory + (ULONG64)pRoot);
// 得到第三层的第一个目录入库
pEntry3 =
(IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pDir3 + 1);
TmpCstr.Format(_T(" +id:%d\r\n"), pEntry3->Id);
m_ResourceTable += TmpCstr;
// 得到数据入口
pDataEntry =
(IMAGE_RESOURCE_DATA_ENTRY*)(pEntry3->OffsetToData + (ULONG64)pRoot);
TmpCstr.Format(_T(" +资源偏移(RVA):%x H\r\n"), pDataEntry->OffsetToData);
m_ResourceTable += TmpCstr;
TmpCstr.Format(_T(" +资源大小:%x H\r\n\r\n"), pDataEntry->Size);
m_ResourceTable += TmpCstr;
}
}
}
m_ResourceTable += _T("\r\n\r\n");
}
//重定位表
// 得到第一个重定位块的数组首地址(RVA)
DWORD dwRelcationBlockOffset =
RvaToOffset(pDataDirectory[5].VirtualAddress);
// 得到第一个重定位块的地址
IMAGE_BASE_RELOCATION* pRelcationBlock =
(IMAGE_BASE_RELOCATION*)((ULONG64)pFileData + dwRelcationBlockOffset);
while (TRUE)
{
// 判断是否是最后一个重定位块
if (pRelcationBlock->VirtualAddress == 0 && pRelcationBlock->SizeOfBlock == 0) {
break;
}
TmpCstr.Format(_T("块开始的RVA[%x H],字节数[%x H] \r\n\r\n"), pRelcationBlock->VirtualAddress, pRelcationBlock->SizeOfBlock);
m_RelocationeTable += TmpCstr;
// 遍历重定位类型和偏移的数据块
TypeOffset* pTypeOffset =
(TypeOffset*)((ULONG64)pRelcationBlock + sizeof(IMAGE_BASE_RELOCATION));
DWORD dwCount =
(pRelcationBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(TypeOffset);
for (int i = 0; i < dwCount; ++i) {
if (pTypeOffset[i].Type == 3)
{
TmpCstr.Format(_T("偏移[%x H] "), pTypeOffset[i].Offset);
m_RelocationeTable += TmpCstr;
}
// 得到需要重定位的数据
DWORD dwRva = pRelcationBlock->VirtualAddress + pTypeOffset[i].Offset;
DWORD dwData = RvaToOffset(dwRva);
DWORD* pRelData = (DWORD*)(dwData + (ULONG64)pFileData);
printf(" +要修改的地址:[0x%08X]\n", *pRelData);
TmpCstr.Format(_T("要修改的地址:[%08x H]\r\n"), *pRelData);
m_RelocationeTable += TmpCstr;
}
m_RelocationeTable += _T("\r\n\r\n");
// 递增到下一个重定位块
pRelcationBlock =
(IMAGE_BASE_RELOCATION*)((ULONG64)(pRelcationBlock)+pRelcationBlock->SizeOfBlock);
}
//延迟加载表
//获得导出表
DWORD dwDelayTableRVA = pDataDirectory[13].VirtualAddress;
if (dwDelayTableRVA == 0)
{
m_DelayImportTable += _T("没有数据");
}
else
{
//将多出表的RVA转换成文件偏移
DWORD dwDelayTableOffset = RvaToOffset(dwDelayTableRVA);
IMAGE_DELAYLOAD_DESCRIPTOR *pDelayTable = (IMAGE_DELAYLOAD_DESCRIPTOR*)(dwDelayTableOffset + (ULONG64)pFileData);
if (pDelayTable->DllNameRVA == 0x00000300)
{
m_DelayImportTable = _T("没有数据\r\n");
}
else
{
while (pDelayTable->DllNameRVA)
{
//DllName
WCHAR DllName[20] = { 0 };
DWORD dwDelayTableNameOffset = RvaToOffset(pDelayTable->DllNameRVA);
ULONG64 dwName = (dwDelayTableNameOffset + (ULONG64)pFileData);
CHAR_TO_WCHAR((char *)dwName, DllName);
TmpCstr.Format(_T("DLLNameRVA:%x H "), pDelayTable->DllNameRVA);
m_DelayImportTable += TmpCstr;
TmpCstr.Format(_T("DLLName:%s\r\n"), DllName);
m_DelayImportTable += TmpCstr;
//函数地址
TmpCstr.Format(_T("IAT(R)RVA:%x H "), pDelayTable->ImportAddressTableRVA);
m_DelayImportTable += TmpCstr;
//函数名称
TmpCstr.Format(_T("INT(R)RVA:%x H\r\n"), pDelayTable->ImportNameTableRVA);
m_DelayImportTable += TmpCstr;
DWORD dwFunNameOffset = RvaToOffset(pDelayTable->ImportNameTableRVA);
DWORD dwFunName = dwFunNameOffset + (ULONG64)pFileData;
m_DelayImportTable += _T("-----------------------\r\n");
IMAGE_THUNK_DATA *pIAT = (IMAGE_THUNK_DATA *)((ULONG64)pFileData + dwFunNameOffset);
// 4.2 遍历IAT
// n是一个IMAGE_THUNK_DATA结构体数组,
// 数组是一个全0结尾。
while (pIAT->u1.AddressOfData != 0) {
// 5.1 判断最高位是否是1
if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal)) {
// 函数是以序号导入的。
// 序号都是WORD类型,所以,只取它低16的值
TmpCstr.Format(_T("导入序号:%d\r\n"), (pIAT->u1.Ordinal & 0xFFFF));
m_DelayImportTable += TmpCstr;
}
else {
// 函数是以名称方式导入的
// 字段保存着一个指向IMAGE_IMPORT_BY_NAME结构体的RVA
DWORD dwFunctionNameOffset = /*换行*/
RvaToOffset(pIAT->u1.AddressOfData);
IMAGE_IMPORT_BY_NAME* pImportName = /*换行*/
(IMAGE_IMPORT_BY_NAME*)((ULONG64)pFileData + dwFunctionNameOffset);
TCHAR FunName[50] = { 0 };
CHAR_TO_WCHAR(pImportName->Name, FunName);
TmpCstr.Format(_T("函数名称:%s\r\n"), FunName);
m_DelayImportTable += TmpCstr;
}
// 递增到下一个结构体
++pIAT;
m_DelayImportTable += _T("\r\n");
}
++pDelayTable;
}
}
}
//TSL表
DWORD dwTLSRVA = pDataDirectory[9].VirtualAddress;
if (dwTLSRVA == 0)
{
m_TLSTable = _T("没有数据");
}
else{
//将多出表的RVA转换成文件偏移
DWORD dwTLSOffset = RvaToOffset(dwTLSRVA);
PIMAGE_TLS_DIRECTORY64 pTLS = PIMAGE_TLS_DIRECTORY64(dwTLSOffset + (ULONG64)pFileData);
TmpCstr.Format(_T("StartAddressOfRawData:%x H\r\n\r\n"), pTLS->StartAddressOfRawData);
m_TLSTable += TmpCstr;
TmpCstr.Format(_T("EndAddressOfRawData:%x H\r\n\r\n"), pTLS->EndAddressOfRawData);
m_TLSTable += TmpCstr;
TmpCstr.Format(_T("AddressOfIndex:%x H\r\n\r\n"), pTLS->AddressOfIndex);
m_TLSTable += TmpCstr;
TmpCstr.Format(_T("AddressOfCallBacks:%x H\r\n\r\n"), pTLS->AddressOfCallBacks);
m_TLSTable += TmpCstr;
TmpCstr.Format(_T("SizeOfZeroFill:%x H\r\n\r\n"), pTLS->SizeOfZeroFill);
m_TLSTable += TmpCstr;
TmpCstr.Format(_T("Characteristics:%x H\r\n\r\n"), pTLS->Characteristics);
m_TLSTable += TmpCstr;
}
}
|