首页
社区
课程
招聘
[原创]PE头分析详解和VC++代码实现。
发表于: 2019-11-27 17:01 4940

[原创]PE头分析详解和VC++代码实现。

2019-11-27 17:01
4940

软件安全这课快到期末了,我把之前写的山寨一个PE解析器代码整理复习一下,奈何菜鸟我不太会MFC编程,所以下面的程序主要是在命令行完成。


代码最后全部打包压缩上传。

PE结构百度图一堆一堆

  • 首先打开文件函数,设置完参数可以让它选择DLL或者EXE文件:
//取得文件路径部分
	TCHAR szFilePath[MAX_PATH];
	OPENFILENAME ofn = { 0 };
	memset(szFilePath, 0, MAX_PATH);
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = NULL;
	ofn.hInstance = GetModuleHandle(NULL);
	ofn.nMaxFile = MAX_PATH;
	ofn.lpstrInitialDir = L".";
	ofn.lpstrFile = szFilePath;
	ofn.lpstrTitle = L"选择PE文件";
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	ofn.lpstrFilter = L"(*.*)\0*.exe;*.dll\0";
	GetOpenFileName(&ofn);

//取得文件路径部分
	TCHAR szFilePath[MAX_PATH];
	OPENFILENAME ofn = { 0 };
	memset(szFilePath, 0, MAX_PATH);
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = NULL;
	ofn.hInstance = GetModuleHandle(NULL);
	ofn.nMaxFile = MAX_PATH;
	ofn.lpstrInitialDir = L".";
	ofn.lpstrFile = szFilePath;
	ofn.lpstrTitle = L"选择PE文件";
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	ofn.lpstrFilter = L"(*.*)\0*.exe;*.dll\0";
	GetOpenFileName(&ofn);

运行之后可以选择文件并得到文件绝对路径地址如图:
     



然后用内存映射文件打开文件(这里不能用openfile函数),然后得到映射基地址,那打开文件之后获得的地址是文件地址:
if (szFilePath == NULL)
	{
		MessageBox(NULL, L"打开文件错误", NULL, NULL);
		return 0;
	}
	//创建文件句柄

	HANDLE hFile = CreateFile(szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
		MessageBox(NULL, L"创建PE内核失败", NULL, NULL);
		return 0;
	}
	//创建文件映射内核对象
	HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	if (NULL == hMapping)
	{
		CloseHandle(hFile);
		hFile = NULL;
		return 0;
	}
	//获得映射基地址
	LPVOID ImageBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
	if (NULL == ImageBase)
	{
		CloseHandle(hMapping);
		CloseHandle(hFile);

		hMapping = NULL;
		hFile = NULL;
		return FALSE;
	}
  • 之后根据对应的指针对各个头赋值:
//下面是DOS头分析/////////////////////////////////////////////////
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	pDosHeader = (PIMAGE_DOS_HEADER)ImageBase; 
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}

	//下面是获得NT头/////////////////////////////////////////////////////
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)(pDosHeader->e_lfanew) + (DWORD)ImageBase);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	pFileHeader = &pNtHeader->FileHeader;

	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
	pOptionHeader = &pNtHeader->OptionalHeader;

	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);

if (szFilePath == NULL)
	{
		MessageBox(NULL, L"打开文件错误", NULL, NULL);
		return 0;
	}
	//创建文件句柄

	HANDLE hFile = CreateFile(szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
		MessageBox(NULL, L"创建PE内核失败", NULL, NULL);
		return 0;
	}
	//创建文件映射内核对象
	HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	if (NULL == hMapping)
	{
		CloseHandle(hFile);
		hFile = NULL;
		return 0;
	}
	//获得映射基地址
	LPVOID ImageBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
	if (NULL == ImageBase)
	{
		CloseHandle(hMapping);
		CloseHandle(hFile);

		hMapping = NULL;
		hFile = NULL;
		return FALSE;
	}
  • 之后根据对应的指针对各个头赋值:
//下面是DOS头分析/////////////////////////////////////////////////
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	pDosHeader = (PIMAGE_DOS_HEADER)ImageBase; 
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}

	//下面是获得NT头/////////////////////////////////////////////////////
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)(pDosHeader->e_lfanew) + (DWORD)ImageBase);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	pFileHeader = &pNtHeader->FileHeader;

	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
	pOptionHeader = &pNtHeader->OptionalHeader;

	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);

//下面是DOS头分析/////////////////////////////////////////////////
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	pDosHeader = (PIMAGE_DOS_HEADER)ImageBase; 
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}

	//下面是获得NT头/////////////////////////////////////////////////////
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)(pDosHeader->e_lfanew) + (DWORD)ImageBase);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	pFileHeader = &pNtHeader->FileHeader;

	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
	pOptionHeader = &pNtHeader->OptionalHeader;

	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);

//下面是DOS头分析/////////////////////////////////////////////////
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	pDosHeader = (PIMAGE_DOS_HEADER)ImageBase; 
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}

	//下面是获得NT头/////////////////////////////////////////////////////
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)(pDosHeader->e_lfanew) + (DWORD)ImageBase);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		MessageBox(NULL, TEXT("PE文件错误"), NULL, MB_OK);
	}
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	pFileHeader = &pNtHeader->FileHeader;

	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
	pOptionHeader = &pNtHeader->OptionalHeader;

	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);

  •    得到各个头文件针位置之后就可以打印出各个参数的值了:
  • 	/***************** 显示需要的数据部分 *******************/
    		cout << "所有需要的关键信息如下:" << endl;
    		cout << "_IMAGE_DOS_HEADER   RVA地址:" << hex << pDosHeader << endl;
    		cout << "e_magic值:" << hex << pDosHeader->e_magic << endl;
    		cout << "e_lfarlc值:" << hex << pDosHeader->e_lfarlc << endl << endl;
    
    		cout << "_IMAGE_NT_HEADERS   RVA地址:" << hex << pNtHeader << endl;
    		cout << "Signature 值:" << hex << pNtHeader->Signature << endl << endl;
    
    		cout << "_IMAGE_FILE_HEADERS   RVA地址:" << hex << pFileHeader << endl;
    		cout << "Machine 值:" << hex << pFileHeader->Machine << endl;
    		cout << "NumberOfSections 值:" << hex << pFileHeader->NumberOfSections << endl;
    		cout << "Characteristics 值:" << hex << pFileHeader->Characteristics << endl << endl;
    
    		cout << "_IMAGE_OPTION_HEADERS   RVA地址:" << hex << pOptionHeader << endl;
    		cout << "Magic 值:" << hex << pOptionHeader->Magic << endl;
    		cout << "SizeOfCode 值:" << hex << pOptionHeader->SizeOfCode << endl;
    		cout << "AddressOfEntryPoint 值" << hex << pOptionHeader->AddressOfEntryPoint << endl;
    		cout << "ImageBase 值:" << hex << pOptionHeader->ImageBase << endl;
    		cout << "SectionAlignment 值" << hex << pOptionHeader->SectionAlignment << endl;
    		cout << "FileAlignment 值" << hex << pOptionHeader->FileAlignment << endl;
    		cout << "SizeOfImage 值:" << hex << pOptionHeader->SizeOfImage << endl << endl;
    
    		cout << "_IMAGE_SECTION_HEADERS   RVA地址:" << pSectionHeader << endl;
    		for (int i = 0; i < pFileHeader->NumberOfSections; i++)      //循环打印各个区段的值
    		{
    			cout << "  Section Name:" << pSectionHeader->Name << endl;
    			cout << "  VirtualAddress:" << hex << pSectionHeader->VirtualAddress << endl;
    			cout << "  SizeOfRawData:" << hex << pSectionHeader->SizeOfRawData << endl;
    			cout << "  PointerToRelocations:" << hex << pSectionHeader->PointerToRelocations << endl;
    			cout << "  NumberOfLinenumbers:" << hex << pSectionHeader->NumberOfLinenumbers << endl;
    			cout << "  Characteristics:" << hex << pSectionHeader->Characteristics << endl;
    
    			++pSectionHeader;
    			cout << endl;
    		}


	/***************** 显示需要的数据部分 *******************/
		cout << "所有需要的关键信息如下:" << endl;
		cout << "_IMAGE_DOS_HEADER   RVA地址:" << hex << pDosHeader << endl;
		cout << "e_magic值:" << hex << pDosHeader->e_magic << endl;
		cout << "e_lfarlc值:" << hex << pDosHeader->e_lfarlc << endl << endl;

		cout << "_IMAGE_NT_HEADERS   RVA地址:" << hex << pNtHeader << endl;
		cout << "Signature 值:" << hex << pNtHeader->Signature << endl << endl;

		cout << "_IMAGE_FILE_HEADERS   RVA地址:" << hex << pFileHeader << endl;
		cout << "Machine 值:" << hex << pFileHeader->Machine << endl;
		cout << "NumberOfSections 值:" << hex << pFileHeader->NumberOfSections << endl;
		cout << "Characteristics 值:" << hex << pFileHeader->Characteristics << endl << endl;

		cout << "_IMAGE_OPTION_HEADERS   RVA地址:" << hex << pOptionHeader << endl;
		cout << "Magic 值:" << hex << pOptionHeader->Magic << endl;
		cout << "SizeOfCode 值:" << hex << pOptionHeader->SizeOfCode << endl;
		cout << "AddressOfEntryPoint 值" << hex << pOptionHeader->AddressOfEntryPoint << endl;
		cout << "ImageBase 值:" << hex << pOptionHeader->ImageBase << endl;
		cout << "SectionAlignment 值" << hex << pOptionHeader->SectionAlignment << endl;
		cout << "FileAlignment 值" << hex << pOptionHeader->FileAlignment << endl;
		cout << "SizeOfImage 值:" << hex << pOptionHeader->SizeOfImage << endl << endl;

		cout << "_IMAGE_SECTION_HEADERS   RVA地址:" << pSectionHeader << endl;
		for (int i = 0; i < pFileHeader->NumberOfSections; i++)      //循环打印各个区段的值
		{
			cout << "  Section Name:" << pSectionHeader->Name << endl;
			cout << "  VirtualAddress:" << hex << pSectionHeader->VirtualAddress << endl;
			cout << "  SizeOfRawData:" << hex << pSectionHeader->SizeOfRawData << endl;
			cout << "  PointerToRelocations:" << hex << pSectionHeader->PointerToRelocations << endl;
			cout << "  NumberOfLinenumbers:" << hex << pSectionHeader->NumberOfLinenumbers << endl;
			cout << "  Characteristics:" << hex << pSectionHeader->Characteristics << endl;

			++pSectionHeader;
			cout << endl;
		}


打印输入表和输出表,这里一定不要忘记这个头文件:
#include <imagehlp.h>
#pragma comment ( lib, "imagehlp.lib" )  //这里是关键,我是谷歌找到的,不然编译不了imagehlp.h
#include<iostream>
#include<CommCtrl.h>

#include <imagehlp.h>
#pragma comment ( lib, "imagehlp.lib" )  //这里是关键,我是谷歌找到的,不然编译不了imagehlp.h
#include<iostream>
#include<CommCtrl.h>

打印导入表,我用的是IAT表,这个比较保险,就算函数没有名字也有VA地址:
int showIAT(PIMAGE_IMPORT_DESCRIPTOR pImport, LPVOID ImageBase, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_OPTIONAL_HEADER pOptionHeader)
{
	char* szFuncName;
	DWORD  * pdwThunkRVA = NULL;
	PIMAGE_IMPORT_BY_NAME     pByName = NULL;
	pdwThunkRVA = (DWORD*)ImageRvaToVa(pNtHeader, ImageBase, pImport->FirstThunk, NULL);  //取出o指向的IAT地址,并转换成DWORD指针
	
	if (!pdwThunkRVA)
	{
		return 0;
	}
	while (*pdwThunkRVA)
	{
		if (HIWORD(*pdwThunkRVA) == 0x8000)
		{
			cout << "函数序号:" << hex << *pdwThunkRVA << endl;
		}
		else 
		{
		pByName = (PIMAGE_IMPORT_BY_NAME)ImageRvaToVa(pNtHeader, ImageBase, (DWORD)(*pdwThunkRVA), NULL);
		if (pByName)
		cout << "funName:" << (char*)pByName->Name << endl;
	    }
		++pdwThunkRVA;
	}
	return 0;
}


void showIIDandIED( LPVOID ImageBase, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_OPTIONAL_HEADER pOptionHeader)
{
	PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
	DWORD IIDRVA;
	IIDRVA = pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;  //记住是数组的第二项开始的,保存的是RVA值
	pImport = (PIMAGE_IMPORT_DESCRIPTOR)ImageRvaToVa(pNtHeader, ImageBase, IIDRVA,NULL);//调用	imagehlp中的ImageRvaToVA
	string name = "";
	

	if (!pImport)
	{
		int error = GetLastError();
		if (error == 0)		
		    MessageBox(NULL, TEXT("文件没有输入表"), NULL, MB_OK);
		else
		    MessageBox(NULL, TEXT("无法获得Import Directory"), NULL, MB_OK);     
		return;
	}
	while (pImport->FirstThunk)
	{
		cout << "  DLLName: " << (char*)ImageRvaToVa(pNtHeader, ImageBase, pImport->Name, NULL) << endl;  //四个参数
		cout << "  Characteristics:    " << hex << pImport->Characteristics << endl;
		cout << "  ForwarderChain:  " << hex << pImport->ForwarderChain << endl;
		cout << "  TimeDateStamp: " << hex << pImport->TimeDateStamp << endl;
		cout << "  OriginalFirstThunk(INT): " << hex << pImport->OriginalFirstThunk << endl;

		cout << "  FirstThunk(IAT):" << hex << pImport->FirstThunk << endl;
		showIAT(pImport, ImageBase, pNtHeader, pOptionHeader);
		cout << endl;
		++pImport;
	}

int showIAT(PIMAGE_IMPORT_DESCRIPTOR pImport, LPVOID ImageBase, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_OPTIONAL_HEADER pOptionHeader)
{
	char* szFuncName;
	DWORD  * pdwThunkRVA = NULL;
	PIMAGE_IMPORT_BY_NAME     pByName = NULL;
	pdwThunkRVA = (DWORD*)ImageRvaToVa(pNtHeader, ImageBase, pImport->FirstThunk, NULL);  //取出o指向的IAT地址,并转换成DWORD指针
	
	if (!pdwThunkRVA)
	{
		return 0;
	}
	while (*pdwThunkRVA)
	{
		if (HIWORD(*pdwThunkRVA) == 0x8000)
		{
			cout << "函数序号:" << hex << *pdwThunkRVA << endl;
		}
		else 
		{
		pByName = (PIMAGE_IMPORT_BY_NAME)ImageRvaToVa(pNtHeader, ImageBase, (DWORD)(*pdwThunkRVA), NULL);
		if (pByName)
		cout << "funName:" << (char*)pByName->Name << endl;
	    }
		++pdwThunkRVA;
	}
	return 0;
}


void showIIDandIED( LPVOID ImageBase, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_OPTIONAL_HEADER pOptionHeader)
{
	PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
	DWORD IIDRVA;
	IIDRVA = pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;  //记住是数组的第二项开始的,保存的是RVA值
	pImport = (PIMAGE_IMPORT_DESCRIPTOR)ImageRvaToVa(pNtHeader, ImageBase, IIDRVA,NULL);//调用	imagehlp中的ImageRvaToVA
	string name = "";
	

	if (!pImport)
	{
		int error = GetLastError();
		if (error == 0)		
		    MessageBox(NULL, TEXT("文件没有输入表"), NULL, MB_OK);
		else
		    MessageBox(NULL, TEXT("无法获得Import Directory"), NULL, MB_OK);     
		return;
	}
	while (pImport->FirstThunk)
	{
		cout << "  DLLName: " << (char*)ImageRvaToVa(pNtHeader, ImageBase, pImport->Name, NULL) << endl;  //四个参数
		cout << "  Characteristics:    " << hex << pImport->Characteristics << endl;
		cout << "  ForwarderChain:  " << hex << pImport->ForwarderChain << endl;
		cout << "  TimeDateStamp: " << hex << pImport->TimeDateStamp << endl;
		cout << "  OriginalFirstThunk(INT): " << hex << pImport->OriginalFirstThunk << endl;

		cout << "  FirstThunk(IAT):" << hex << pImport->FirstThunk << endl;
		showIAT(pImport, ImageBase, pNtHeader, pOptionHeader);
		cout << endl;
		++pImport;
	}

输出表部分IED:
////////////////////////////////////////IED/////////////////////////////////////////////////////
	cout << "//////////////////////////////文件导出表部分/////////////////////////////////////////" << endl;
	PIMAGE_EXPORT_DIRECTORY pExportDir = NULL;    //指向IED指针
	pExportDir = (PIMAGE_EXPORT_DIRECTORY)ImageRvaToVa(pNtHeader, ImageBase, pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,NULL);
	if (!pExportDir)
	{
		int error = GetLastError();
		if (error == 0)
			MessageBox(NULL, TEXT("文件没有输出表"), NULL, MB_OK);
		else
			MessageBox(NULL, TEXT("无法获得Export Directory"), NULL, MB_OK);
		return;
	}
	cout << "  AddressOfFunctions:    " << hex << pExportDir->AddressOfFunctions << endl;
	cout << "  AddressOfNameOrdinals: " << hex << pExportDir->AddressOfNameOrdinals << endl;
	cout << "  AddressOfNames:        " << hex << pExportDir->AddressOfNames << endl;
	cout << "  Base:                  " << hex << pExportDir->Base << endl;
	cout << "  MajorVersion:          " << hex << pExportDir->MajorVersion << endl;
	cout << "  MinorVersion:          " << hex << pExportDir->MinorVersion << endl;
	cout << "  Characteristics:       " << hex << pExportDir->Characteristics << endl;
	cout << "  Name:                  " << hex << pExportDir->Name << endl;
	cout << "  NumberOfFunctions:     " << hex << pExportDir->NumberOfFunctions << endl;
	cout << "  NumberOfNames:         " << hex << pExportDir->NumberOfNames << endl;
	cout << "  TimeDateStamp:         " << hex << pExportDir->TimeDateStamp << endl;


	//cout << " pExportDir->Name:         " << (char*)ImageRvaToVa(pNTH, LocalImageBase, pExportDir->Name, NULL) << endl;

	char* szFuncName;

	UINT                    NumOfName = 0;
	PDWORD                  pEAT, pENT;
	PWORD                   pEOT;
	UINT                    i = 0, j = 0, k = 0;
	pEOT = (PWORD)ImageRvaToVa(pNtHeader, ImageBase, pExportDir->AddressOfNameOrdinals,NULL);
	pEAT = (PDWORD)ImageRvaToVa(pNtHeader, ImageBase, pExportDir->AddressOfFunctions,NULL);
	pENT = (PDWORD)ImageRvaToVa(pNtHeader, ImageBase, pExportDir->AddressOfNames,NULL);
	NumOfName = pExportDir->NumberOfNames;  //函数名字数量
	if (!pEAT)
		return;
	for (i = 0; i < pExportDir->NumberOfFunctions; i++)
	{
		if (*pEAT)
		{
			for (j = 0; j < NumOfName; j++)
			{
				if (i == pEOT[j])
				{
					szFuncName = (char*)ImageRvaToVa(pNtHeader, ImageBase, pENT[j],NULL);
					cout <<"FunctioRVA:"<< pEAT[i] <<'\t'<<"FunctionName:"<< szFuncName<<endl;
				}
			}
		}
		++pEAT;
	}
}

////////////////////////////////////////IED/////////////////////////////////////////////////////
	cout << "//////////////////////////////文件导出表部分/////////////////////////////////////////" << endl;
	PIMAGE_EXPORT_DIRECTORY pExportDir = NULL;    //指向IED指针
	pExportDir = (PIMAGE_EXPORT_DIRECTORY)ImageRvaToVa(pNtHeader, ImageBase, pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,NULL);
	if (!pExportDir)
	{
		int error = GetLastError();
		if (error == 0)
			MessageBox(NULL, TEXT("文件没有输出表"), NULL, MB_OK);
		else
			MessageBox(NULL, TEXT("无法获得Export Directory"), NULL, MB_OK);
		return;
	}
	cout << "  AddressOfFunctions:    " << hex << pExportDir->AddressOfFunctions << endl;
	cout << "  AddressOfNameOrdinals: " << hex << pExportDir->AddressOfNameOrdinals << endl;
	cout << "  AddressOfNames:        " << hex << pExportDir->AddressOfNames << endl;
	cout << "  Base:                  " << hex << pExportDir->Base << endl;
	cout << "  MajorVersion:          " << hex << pExportDir->MajorVersion << endl;
	cout << "  MinorVersion:          " << hex << pExportDir->MinorVersion << endl;
	cout << "  Characteristics:       " << hex << pExportDir->Characteristics << endl;
	cout << "  Name:                  " << hex << pExportDir->Name << endl;
	cout << "  NumberOfFunctions:     " << hex << pExportDir->NumberOfFunctions << endl;
	cout << "  NumberOfNames:         " << hex << pExportDir->NumberOfNames << endl;
	cout << "  TimeDateStamp:         " << hex << pExportDir->TimeDateStamp << endl;


	//cout << " pExportDir->Name:         " << (char*)ImageRvaToVa(pNTH, LocalImageBase, pExportDir->Name, NULL) << endl;

	char* szFuncName;

	UINT                    NumOfName = 0;
	PDWORD                  pEAT, pENT;
	PWORD                   pEOT;
	UINT                    i = 0, j = 0, k = 0;
	pEOT = (PWORD)ImageRvaToVa(pNtHeader, ImageBase, pExportDir->AddressOfNameOrdinals,NULL);
	pEAT = (PDWORD)ImageRvaToVa(pNtHeader, ImageBase, pExportDir->AddressOfFunctions,NULL);
	pENT = (PDWORD)ImageRvaToVa(pNtHeader, ImageBase, pExportDir->AddressOfNames,NULL);
	NumOfName = pExportDir->NumberOfNames;  //函数名字数量
	if (!pEAT)
		return;
	for (i = 0; i < pExportDir->NumberOfFunctions; i++)
	{
		if (*pEAT)
		{
			for (j = 0; j < NumOfName; j++)
			{
				if (i == pEOT[j])
				{
					szFuncName = (char*)ImageRvaToVa(pNtHeader, ImageBase, pENT[j],NULL);
					cout <<"FunctioRVA:"<< pEAT[i] <<'\t'<<"FunctionName:"<< szFuncName<<endl;
				}
			}
		}
		++pEAT;
	}
}


之后老师要求写一个程序,可以找出加载一个程序起来之后调用的DLL  VA地址,代码也放进来,(备注应该比较详细)。里面写了一些函数处理,比如之前读取文件之后选择的是绝对路径,要把那些前缀什么的去掉。然后就是Tchar 转 STRING函数,char转tchar函数(当时搞这些编码转换头都疼)。这个程序的原理和一种反调试技术的实现差不多,就是遍历进程空间,找到对应的模块名,然后关掉它。代码中我也用了。
#include <iostream>
#include <iomanip>
#include <string>
#include <tchar.h>
#include <windows.h>
#include <TlHelp32.h>
#include<tlhelp32.h>
#include<wchar.h>
#include <cstring>
#include <imagehlp.h>
#pragma comment ( lib, "imagehlp.lib" )  //这里是关键,我是谷歌找到的,不然编译不了imagehlp.h
#include<CommCtrl.h>
#pragma comment (lib, "imagehlp.lib")
#pragma comment (lib, "advapi32.lib")
using namespace std;
string TCHAR2STRING(TCHAR* STR)  //tchar转string
{
	int iLen = WideCharToMultiByte(CP_ACP, 0, STR, -1, NULL, 0, NULL, NULL);
	char* chRtn = new char[iLen * sizeof(char)];
	WideCharToMultiByte(CP_ACP, 0, STR, -1, chRtn, iLen, NULL, NULL);
	std::string str(chRtn);
	return str;
}
HMODULE GetProcessModuleHandle(DWORD pid, CONST TCHAR* moduleName) {	// 根据 PID 、模块名(需要写后缀,如:".dll"),获取模块入口地址。
	MODULEENTRY32 moduleEntry;
	HANDLE handle = NULL;
	handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); //  获取进程快照中包含在th32ProcessID中指定的进程的所有的模块。
	if (!handle) {
		CloseHandle(handle);
		return NULL;
	}
	ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32));
	moduleEntry.dwSize = sizeof(MODULEENTRY32);
	if (!Module32First(handle, &moduleEntry)) {
		CloseHandle(handle);
		return NULL;
	}
	do {
		if (_tcscmp(moduleEntry.szModule, moduleName) == 0) { return moduleEntry.hModule; }
	} while (Module32Next(handle, &moduleEntry));
	CloseHandle(handle);
	return 0;
}
string NameOfexe(string name)  //自定义一个取出文件地址绝对路径剔除多余参数函数
{
	string exeName;
	int k=0;
	for (int i = 0; i< name.length(); i++)
	{
		if (name[i] == '\\'){
			k = i;
			for (int j = i; j < name.length() - i; j++)
			{
				if (name[j] == '\\')
					break;
		}
		}
	}
	int k2 = 0;
	int i = k+1;
	for(i; i < name.length(); i++)
	{
		exeName+= name[i];
		k2++;
	}
	return exeName;
}
TCHAR* char2TCAHR(const char* str)   //char*转tchar*

{

	int size = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);

	TCHAR* retStr = new TCHAR[size * sizeof(TCHAR)];

	MultiByteToWideChar(CP_ACP, 0, str, -1, retStr, size);

	return retStr;

}
void showAllImageBase(TCHAR *name, LPVOID ImageBase, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_OPTIONAL_HEADER pOptionHeader){
	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // 进程快照句柄
	PROCESSENTRY32 process = { sizeof(PROCESSENTRY32) };	// 存放进程快照的结构体

	/*下面这部分是取出导入表DLL名字,保存起来用来,和之前实验的一样。*/
	PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
	DWORD IIDRVA;
	IIDRVA = pOptionHeader->DataDirectory[1].VirtualAddress;  //记住是数组的第二项开始的,保存的是RVA值
	pImport = (PIMAGE_IMPORT_DESCRIPTOR)ImageRvaToVa(pNtHeader, ImageBase, IIDRVA, NULL);//调用	imagehlp中的ImageRvaToVA

	//  遍历进程
	char* a;
	int k = 0;
	while (Process32Next(hProcessSnap, &process)) {
		// .exe 进程
		string s_szExeFile = TCHAR2STRING(process.szExeFile); // char* 转 string
		if (s_szExeFile == NameOfexe(TCHAR2STRING(name))) 
		{
			cout << NameOfexe(TCHAR2STRING(name)) <<'\t'<<"基地址:"<< ImageBase << endl;
			HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); // 进程句柄
			while (pImport->FirstThunk) 
			{
				a= (char*)ImageRvaToVa(pNtHeader, ImageBase, pImport->Name,NULL) ;
				cout << a;
				cout <<'\t'<< "模块VA地址:" << GetProcessModuleHandle(process.th32ProcessID, char2TCAHR(a)) << endl;
				++pImport;
			}
			k = 1;
		}
	}
	if (k == 0)  //程序没有运行
	{
		STARTUPINFO si; //一些必备参数设置
		memset(&si, 0, sizeof(STARTUPINFO));
		si.cb = sizeof(STARTUPINFO);
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.wShowWindow = SW_SHOW;
		PROCESS_INFORMATION pi; //必备参数设置结束
		if (!CreateProcess(NULL, name, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) //
		{
			cout << "Create Fail!" << endl;
		}
	    Sleep(1000);
		HANDLE hProcessSnap1 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // 进程快照句柄
		PROCESSENTRY32 process1 = { sizeof(PROCESSENTRY32) };	// 存放进程快照的结构体
		char* a;
		
		while (Process32Next(hProcessSnap1, &process1)) {
			// .exe 进程
			string s_szExeFile = TCHAR2STRING(process1.szExeFile); // char* 转 string
			if (s_szExeFile == NameOfexe(TCHAR2STRING(name)))
			{
				cout << NameOfexe(TCHAR2STRING(name)) << ImageBase << endl;
				HANDLE hProcess1 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process1.th32ProcessID); // 进程句柄
				while (pImport->FirstThunk)                            
				{
					a = (char*)ImageRvaToVa(pNtHeader, ImageBase, pImport->Name, NULL);
					cout << a;
					cout <<'\t'<< "模块VA地址:" << GetProcessModuleHandle(process1.th32ProcessID, char2TCAHR(a)) << endl;
					++pImport;
				}
				k = 1;
			}
		}
	}

}

#include <iostream>
#include <iomanip>
#include <string>
#include <tchar.h>
#include <windows.h>
#include <TlHelp32.h>
#include<tlhelp32.h>
#include<wchar.h>
#include <cstring>
#include <imagehlp.h>
#pragma comment ( lib, "imagehlp.lib" )  //这里是关键,我是谷歌找到的,不然编译不了imagehlp.h
#include<CommCtrl.h>
#pragma comment (lib, "imagehlp.lib")
#pragma comment (lib, "advapi32.lib")
using namespace std;
string TCHAR2STRING(TCHAR* STR)  //tchar转string
{
	int iLen = WideCharToMultiByte(CP_ACP, 0, STR, -1, NULL, 0, NULL, NULL);
	char* chRtn = new char[iLen * sizeof(char)];
	WideCharToMultiByte(CP_ACP, 0, STR, -1, chRtn, iLen, NULL, NULL);
	std::string str(chRtn);
	return str;
}
HMODULE GetProcessModuleHandle(DWORD pid, CONST TCHAR* moduleName) {	// 根据 PID 、模块名(需要写后缀,如:".dll"),获取模块入口地址。
	MODULEENTRY32 moduleEntry;
	HANDLE handle = NULL;
	handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); //  获取进程快照中包含在th32ProcessID中指定的进程的所有的模块。
	if (!handle) {
		CloseHandle(handle);
		return NULL;
	}
	ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32));
	moduleEntry.dwSize = sizeof(MODULEENTRY32);
	if (!Module32First(handle, &moduleEntry)) {
		CloseHandle(handle);
		return NULL;
	}
	do {
		if (_tcscmp(moduleEntry.szModule, moduleName) == 0) { return moduleEntry.hModule; }
	} while (Module32Next(handle, &moduleEntry));
	CloseHandle(handle);
	return 0;
}
string NameOfexe(string name)  //自定义一个取出文件地址绝对路径剔除多余参数函数
{
	string exeName;
	int k=0;
	for (int i = 0; i< name.length(); i++)
	{
		if (name[i] == '\\'){
			k = i;
			for (int j = i; j < name.length() - i; j++)
			{
				if (name[j] == '\\')
					break;
		}
		}
	}
	int k2 = 0;
	int i = k+1;
	for(i; i < name.length(); i++)
	{
		exeName+= name[i];
		k2++;
	}
	return exeName;
}
TCHAR* char2TCAHR(const char* str)   //char*转tchar*

{

	int size = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);

	TCHAR* retStr = new TCHAR[size * sizeof(TCHAR)];

	MultiByteToWideChar(CP_ACP, 0, str, -1, retStr, size);

	return retStr;

}
void showAllImageBase(TCHAR *name, LPVOID ImageBase, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_OPTIONAL_HEADER pOptionHeader){
	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // 进程快照句柄
	PROCESSENTRY32 process = { sizeof(PROCESSENTRY32) };	// 存放进程快照的结构体

	/*下面这部分是取出导入表DLL名字,保存起来用来,和之前实验的一样。*/
	PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
	DWORD IIDRVA;
	IIDRVA = pOptionHeader->DataDirectory[1].VirtualAddress;  //记住是数组的第二项开始的,保存的是RVA值
	pImport = (PIMAGE_IMPORT_DESCRIPTOR)ImageRvaToVa(pNtHeader, ImageBase, IIDRVA, NULL);//调用	imagehlp中的ImageRvaToVA

	//  遍历进程
	char* a;
	int k = 0;
	while (Process32Next(hProcessSnap, &process)) {
		// .exe 进程
		string s_szExeFile = TCHAR2STRING(process.szExeFile); // char* 转 string
		if (s_szExeFile == NameOfexe(TCHAR2STRING(name))) 
		{
			cout << NameOfexe(TCHAR2STRING(name)) <<'\t'<<"基地址:"<< ImageBase << endl;
			HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); // 进程句柄
			while (pImport->FirstThunk) 
			{
				a= (char*)ImageRvaToVa(pNtHeader, ImageBase, pImport->Name,NULL) ;
				cout << a;
				cout <<'\t'<< "模块VA地址:" << GetProcessModuleHandle(process.th32ProcessID, char2TCAHR(a)) << endl;
				++pImport;
			}
			k = 1;
		}
	}
	if (k == 0)  //程序没有运行
	{
		STARTUPINFO si; //一些必备参数设置
		memset(&si, 0, sizeof(STARTUPINFO));
		si.cb = sizeof(STARTUPINFO);
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.wShowWindow = SW_SHOW;
		PROCESS_INFORMATION pi; //必备参数设置结束
		if (!CreateProcess(NULL, name, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) //
		{
			cout << "Create Fail!" << endl;
		}
	    Sleep(1000);
		HANDLE hProcessSnap1 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // 进程快照句柄
		PROCESSENTRY32 process1 = { sizeof(PROCESSENTRY32) };	// 存放进程快照的结构体
		char* a;
		
		while (Process32Next(hProcessSnap1, &process1)) {
			// .exe 进程
			string s_szExeFile = TCHAR2STRING(process1.szExeFile); // char* 转 string
			if (s_szExeFile == NameOfexe(TCHAR2STRING(name)))
			{
				cout << NameOfexe(TCHAR2STRING(name)) << ImageBase << endl;
				HANDLE hProcess1 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process1.th32ProcessID); // 进程句柄
				while (pImport->FirstThunk)                            
				{
					a = (char*)ImageRvaToVa(pNtHeader, ImageBase, pImport->Name, NULL);
					cout << a;
					cout <<'\t'<< "模块VA地址:" << GetProcessModuleHandle(process1.th32ProcessID, char2TCAHR(a)) << endl;
					++pImport;
				}
				k = 1;
			}
		}
	}

}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (3)
雪    币: 83
活跃值: (1087)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
感谢
2019-11-27 19:09
0
雪    币: 26205
活跃值: (63302)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
3
感谢分享~
2019-12-2 15:44
0
雪    币: 6102
活跃值: (5520)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
4
感谢分享!
2019-12-17 20:23
0
游客
登录 | 注册 方可回帖
返回
//