PE文件-分析vc示范所有代码[不包含EXPORT TABLE]

#include <windows.h>

#include <iostream>

#define PE_FILE_NAME TEXT("C:\\WINDOWS\\system32\\notepad.exe")
#define CREATE_FILE_FAILURE "创建文件失败"
#define CREATE_MAPPING_FILE "创建文件映射对象失败"
#define MAP_VIEW_FAILURE "映射文件到调用进程的地址空间失败"
#define VALID_DOS_SIGNATURE "这个文件的DOS签名是有效的"
#define VALID_PE_SIGNATURE "这个文件的PE签名是有效的"
#define VALID_PE_FILE "这是一个有效的PE文件"
#define INVALID_PE_FILE "这是一个无效的PE文件"

#define WRITE_LINE(msg) std::cout << TEXT(msg) << std::endl;
#define WRITE_LINE_EX(msg1,msg2) std::cout << TEXT(msg1) << TEXT(msg2) << std::endl;
#define WRITE(msg) std::cout << TEXT(msg);
#define PROCESS_FAILURE(msg) WRITE_LINE(msg)\
		return FALSE;

#define PE_PARSE_NT_HEADER_CALLBACK void (*PARSE_NT_HEADER_CALLBACK)(IMAGE_NT_HEADERS*)=NULL
#define PE_PARSE_SECTION_HEADER_CALLBACK void (*PARSE_SECTION_HEADER_CALLBACK)(IMAGE_SECTION_HEADER*,INT)=NULL
#define PE_PARSE_IMPORT_TABLE_CALLBACK void (*PARSE_IMPORT_TABLE_CALLBACK)(IMAGE_DATA_DIRECTORY*,PVOID)

/* 根据文件头获得文件节表头 */
#define GET_IMAGE_SECTION_HEADER(lpNtHeader) ((IMAGE_SECTION_HEADER *)((byte*)lpNtHeader+sizeof(*lpNtHeader)))
/* 根据文件头获得文件节数量 */
#define GET_IMAGE_NUMBER_OF_SECTIONS(lpNtHeader) (lpNtHeader->FileHeader.NumberOfSections)
/* 虚拟地址到文件偏移量 */
#define RVA_TO_OFFSET(pImageBase,rva) ((PVOID)((byte*)pImageBase+rva))


/* 映射文件到内存映像 */
PVOID MapFileToView(LPCSTR filename);
/* 获得PE文件头 */
IMAGE_NT_HEADERS* GetPeHeader(LPVOID pMapping);
/* 验证PE合法性函数 */
BOOL Validate(LPVOID pMapping);
/* 分析PE头函数 */
void PARSE_NT_HEADER_CALLBACK(IMAGE_NT_HEADERS* lpNtHeader);
/* 分析PE节表函数 */
void PARSE_SECTION_HEADER_CALLBACK(IMAGE_SECTION_HEADER* lpSectionHeader,INT numberOfSections);
/* 分析引入表 */
void PARSE_IMPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase);
/* 将相对虚拟地址转换为文件偏移地址 */
DWORD RVAToFileOffset(PVOID,DWORD);
/* 显示DLL的所有引入函数 */
void PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(PVOID,IMAGE_THUNK_DATA*);


void main()
{
	//将文件映射到内存
	PVOID pMapping = MapFileToView(PE_FILE_NAME);
	//获取文件头
	IMAGE_NT_HEADERS* lpImageNtHeader = GetPeHeader(pMapping);
	
	if (lpImageNtHeader)
	{
		//显示文件头信息
		PARSE_NT_HEADER_CALLBACK(lpImageNtHeader);
		//显示文件节头信息
		PARSE_SECTION_HEADER_CALLBACK(GET_IMAGE_SECTION_HEADER(lpImageNtHeader),GET_IMAGE_NUMBER_OF_SECTIONS(lpImageNtHeader));
		//分析导入表
		PARSE_IMPORT_TABLE_CALLBACK(&(lpImageNtHeader->OptionalHeader.DataDirectory[1]),pMapping);		
	}
	
	//取消映射
	UnmapViewOfFile(pMapping);
	pMapping = NULL;

}

/* 映射文件到内存映像 */
PVOID MapFileToView(LPCSTR filename)
{
	HANDLE fHandle = ::CreateFile(filename,
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
		);
	if (fHandle==INVALID_HANDLE_VALUE)
	{		
		PROCESS_FAILURE(CREATE_FILE_FAILURE);		
	}
	
	HANDLE hMapping = ::CreateFileMapping(
		fHandle,
		NULL,
		PAGE_READONLY,
		NULL,
		NULL,
		NULL
		);
	if (hMapping==NULL)
	{
		CloseHandle(fHandle);
		PROCESS_FAILURE(CREATE_MAPPING_FILE);
	}
	
	LPVOID pMapping = ::MapViewOfFile(hMapping,FILE_MAP_READ,NULL,NULL,NULL);
	if (pMapping==NULL)
	{
		
		PROCESS_FAILURE(MAP_VIEW_FAILURE);
	}
	CloseHandle(hMapping);
	CloseHandle(fHandle);
	hMapping = NULL;
	fHandle = NULL;
	return pMapping;
}

/* 验证PE入口函数 */
BOOL Validate(LPVOID pMapping)
{

	//1.validate IMAGE_DOS_HEADER
	IMAGE_DOS_HEADER * dosHeader = (IMAGE_DOS_HEADER*)pMapping;
// 	if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
// 	{
// 		WRITE_LINE(VALID_DOS_SIGNATURE);
// 	}
	
	IMAGE_NT_HEADERS * nt_header=(IMAGE_NT_HEADERS*)((byte*)pMapping+dosHeader->e_lfanew);
// 	if (nt_header->Signature == IMAGE_NT_SIGNATURE)
// 	{
// 		WRITE_LINE(VALID_PE_SIGNATURE);
// 	}
	
	
// 	WRITE_LINE(
// 		(
// 		dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE?
// 		TEXT(VALID_PE_FILE):
// 	TEXT(INVALID_PE_FILE)
// 		)
// 		);	
	
	return dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE;
}

IMAGE_NT_HEADERS* GetPeHeader(LPVOID pMapping)
{
	IMAGE_DOS_HEADER * dosHeader = (IMAGE_DOS_HEADER*)pMapping;
	IMAGE_NT_HEADERS * nt_header=(IMAGE_NT_HEADERS*)((byte*)pMapping+dosHeader->e_lfanew);
	//检查PE有效性
	if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE)//如果PE头有效则返回PE头
	{
		return nt_header;
	}
	//PE头无效则取消内存映射释放资源并返回NULL
	UnmapViewOfFile(pMapping);
	pMapping = NULL;
	return NULL;
}

/* 分析NT_HEADER回调函数 */
void PARSE_NT_HEADER_CALLBACK(IMAGE_NT_HEADERS* lpNtHeader)
{
	WRITE_LINE(TEXT("----------------------------------FILE HEADER------------------------------------------------"));
	WRITE_LINE((lpNtHeader->FileHeader.Machine==IMAGE_FILE_MACHINE_I386?TEXT("该程序运行所在机器:Intel 386"):TEXT("该程序运行所在机器:非Intel 386")));
	WRITE(TEXT("该程序的块数量:"));
	WRITE_LINE(lpNtHeader->FileHeader.NumberOfSections);
	WRITE_LINE(TEXT("----------------------------------FILE OPTIONAL HEADER--------------------------------------"));
	std::cout.setf(std::ios::hex,std::ios::basefield);//设置输出格式为16进制
	std::cout << TEXT("PE装载器准备运行的PE文件的第一个指令的RVA:") << lpNtHeader->OptionalHeader.AddressOfEntryPoint << std::endl;
	std::cout << TEXT("PE文件的优先装载地址:") << lpNtHeader->OptionalHeader.ImageBase << std::endl;
	std::cout << TEXT("内存中节对齐的粒度:") << lpNtHeader->OptionalHeader.SectionAlignment << std::endl;
	std::cout << TEXT("文件中节对齐的粒度:") << lpNtHeader->OptionalHeader.FileAlignment << std::endl;
	std::cout << TEXT("win32子系统版本[若PE文件是专门为Win32设计的,该子系统版本必定是4.0否则对话框不会有3维立体感]:") << lpNtHeader->OptionalHeader.MajorOperatingSystemVersion << "." << lpNtHeader->OptionalHeader.MinorOperatingSystemVersion << std::endl;
	std::cout << TEXT("内存中整个PE映像体的尺寸[它是所有头和节经过节对齐处理后的大小]:") << lpNtHeader->OptionalHeader.SizeOfImage << std::endl;
	std::cout << TEXT("所有头+节表的大小[也就等于文件尺寸减去文件中所有节的尺寸。可以以此值作为PE文件第一节的文件偏移量]:") << lpNtHeader->OptionalHeader.SizeOfHeaders << std::endl;
	std::cout << TEXT("PE文件属于子系统:") << (lpNtHeader->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_GUI?TEXT("图形用户界面"):TEXT("字符界面")) << std::endl;
	WRITE_LINE(TEXT("----------------------------------FILE SECTION TABLE--------------------------------------"));
	//定位节表位置
	IMAGE_SECTION_HEADER *lpSectionHeader = (IMAGE_SECTION_HEADER *)((byte*)lpNtHeader+sizeof(*lpNtHeader));
//	PARSE_SECTION_HEADER_CALLBACK(lpSectionHeader,lpNtHeader->FileHeader.NumberOfSections);
	
	
// 	for (int i=0;i<lpNtHeader->FileHeader.NumberOfSections;i++)
// 	{		
// 		std::cout << lpSectionHeader->Name << "\0" << std::endl;
// 		std::cout << TEXT("\t本节的RVA(相对虚拟地址):") << lpSectionHeader->VirtualAddress << std::endl;
// 		std::cout << TEXT("\t经过文件对齐处理后节尺寸:") << lpSectionHeader->SizeOfRawData << std::endl;
// 		std::cout << TEXT("\t本节基于文件的偏移量:") << lpSectionHeader->PointerToRawData << std::endl;
// 		lpSectionHeader++;
// 	}

}





/* 分析IMAGE_SECTION_HEADER回调函数 */
void PARSE_SECTION_HEADER_CALLBACK(IMAGE_SECTION_HEADER* lpSectionHeader,INT numberOfSections)
{
	if (lpSectionHeader && numberOfSections)
	{
		for (int i=0;i<numberOfSections;i++)
		{		
			std::cout << lpSectionHeader->Name << "\0" << std::endl;
			std::cout << TEXT("\t本节的RVA(相对虚拟地址):") << lpSectionHeader->VirtualAddress << std::endl;
			std::cout << TEXT("\t经过文件对齐处理后节尺寸:") << lpSectionHeader->SizeOfRawData << std::endl;
			std::cout << TEXT("\t本节基于文件的偏移量:") << lpSectionHeader->PointerToRawData << std::endl;
			lpSectionHeader++;
			
		}
	}
}



/* 分析PE导入表函数 

IMAGE_DATA_DIRECTORY.VirtualAddress												-->
IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk/IMAGE_IMPORT_DESCRIPTOR.FirstThunk	-->//IMAGE_IMPORT_DESCRIPTOR 数组以一个全0域元素结尾
IMAGE_THUNK_DATA																-->
IMAGE_IMPORT_BY_NAME.Name
*/
void PARSE_IMPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase)
{
	if (!lpImageDataDirectory)
		return;
	
	WRITE_LINE(TEXT("----------------------------------PARSE IMPORT TABLE----------------------------------------"));
	int dllcounter = 0;
	IMAGE_IMPORT_DESCRIPTOR* lpImageImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)((byte*)pImageBase+RVAToFileOffset(pImageBase,lpImageDataDirectory->VirtualAddress));
	while (lpImageImportDescriptor->Name!=NULL)//如果不是空元素
	{
		dllcounter++;
		WRITE_LINE((char*)((byte*)pImageBase+RVAToFileOffset(pImageBase,lpImageImportDescriptor->Name)));//输出当前的DLL名字
		DWORD thunk = (lpImageImportDescriptor->OriginalFirstThunk==NULL?lpImageImportDescriptor->FirstThunk:lpImageImportDescriptor->OriginalFirstThunk);
		PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(pImageBase,(IMAGE_THUNK_DATA *)((byte*)pImageBase+RVAToFileOffset(pImageBase,thunk)));
		WRITE_LINE(TEXT("-------------------------------------------"));
		lpImageImportDescriptor++;
	}
	WRITE_LINE_EX(TEXT("导出DLL数目:"),TEXT(dllcounter));
}

/* 分析PE引出表函数 */
void PARSE_EXPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase)
{
	//尚未完成
}

void PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(PVOID pImageBase,IMAGE_THUNK_DATA *lpImageThunkData)
{
	
	WRITE_LINE(TEXT("\t\tHint\t\tFunction"));
	while (lpImageThunkData->u1.Ordinal!=NULL)
	{
		//对于每个数组元素,我们比对元素值是否等于IMAGE_ORDINAL_FLAG32。
		//如果该元素值的最高二进位为1,那么函数是由序数引入的,可以从该值的低字节提取序数。 
		//如果元素值的最高二进位为0,就可将该值作为RVA转入 IMAGE_IMPORT_BY_NAME 数组,跳过 Hint 就是函数名字了
		if(lpImageThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG32)//如果该元素值的最高二进位为1,那么函数是由序数引入的
		{
			WORD ordinal = (lpImageThunkData->u1.Ordinal & 0xFFFF);//从该值的低字节提取序数
			WRITE_LINE_EX(TEXT("\t\t"),ordinal);//输出该函数编号
		}
		else
		{
			IMAGE_IMPORT_BY_NAME* lpImageImportByName = (IMAGE_IMPORT_BY_NAME*)((byte*)pImageBase+RVAToFileOffset(pImageBase,lpImageThunkData->u1.Ordinal));
			WRITE(TEXT("\t\t0x"));
			WRITE(lpImageImportByName->Hint);
			WRITE(TEXT("\t\t"));
			WRITE_LINE((char*)(lpImageImportByName->Name));
			
		}
		lpImageThunkData++;
	}
	
}


/* 将相对虚拟地址转换为文件偏移地址 */
DWORD RVAToFileOffset(PVOID pMappping,DWORD rva)
{
	//定位到DOS头
	IMAGE_DOS_HEADER* lpImageDosHeader = (IMAGE_DOS_HEADER*)pMappping;
	//定位到PE头
	IMAGE_NT_HEADERS* lpImageNtHeader = (IMAGE_NT_HEADERS*)((byte*)pMappping+lpImageDosHeader->e_lfanew);
	//定位到节表
	IMAGE_SECTION_HEADER* lpSectionTable = (IMAGE_SECTION_HEADER*)((byte*)lpImageNtHeader+sizeof(IMAGE_NT_HEADERS));
	//用节数量作循环次数
	int i = lpImageNtHeader->FileHeader.NumberOfSections;
	while(i>0)//检查所有块
	{
		if (rva>=lpSectionTable->VirtualAddress)//如果传入的rva大于等于当前节的虚拟地址
		{
			DWORD sectionEndAddr = lpSectionTable->VirtualAddress+lpSectionTable->SizeOfRawData;//当前节结束地址=当前节的虚拟地址+文件对齐处理后节尺寸
			if (rva<sectionEndAddr)//如果这个rva地址在这个块里面
			{
				DWORD r_rva = rva-lpSectionTable->VirtualAddress;//这个rva地址-当前节的虚拟地址[rva距离节的开始地址的距离]
				return lpSectionTable->PointerToRawData+r_rva;//当前节基于文件的偏移量+rva距离节的开始地址的距离
			}
		}
		lpSectionTable++;
		i--;
	}
	return rva;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
发行者的描述: Neuron PE Disassembler 是一个可视化工具,探讨PE内部,反汇编 DLL,OCX和EXE文件,并查看他们的代码和资源. 查看DLL和EXE代码作为Intel ASM和/或结构化 pseudo ASM/C/C++。 查看LIB和obj内部。 查看DBG文件和使用Codeview调试数据。 查看Linux A 和 O 文件。 查看PE输入和输出情况。 查看PE的调用树,导出和导入函数,以及内部函数。 unmangle Visual C++导出名称。 查看内部二进制结构的PE文件,请执行以下操作:COFF和标准头文件,PE目录、区段,导入和导出表,IAT、资源。 查看和提取资源从PE文件。 转换菜单、对话框、字符串和消息表,Java源代码进行编译。 查看和从当前文件提取资源 RES、APS(Visual Studio 的资源),ICO,CUR文件。 Publisher's Description: Neuron PE Disassembler is a visual tool for exploring PE internals. Disassemble DLL, OCX and EXE files and view their code and resources. View DLL and EXE code as Intel ASM and/or structured pseudo ASM/C/C++. View LIB and OBJ internals. View DBG files and CodeView debug data. View Linux A and O files. View PE imports and exports. View PE call and caller trees for exported and imported functions as well as internal functions. Unmangle Visual C++ export names. View the internal binary structure of PE files: COFF and Standard headers, PE directory, sections ,import and export tables, IAT, resources. View and extract resources from PE files. Convert menus, dialog boxes, string and message tables to Java source code ready to be compiled. View and extract resources from RES, APS (Visual Studio resources), ICO, CUR files.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值