方式一
思路把 pe 文件打开,然后通过ReadFile读到一个缓冲区里(内存上)
优点一直保存在那
缺点 得先读完(这一般不算什么读的速度非常快)
方式二(这里多了步打开文件管理器)
思路把pe 文件打开,然后通过MapViewOfFile映射到内存(返回首地址Return value
If the function succeeds, the return value is the starting address of the mapped view.)
优点动态加载
缺点 由于操作系统只能同时做一件事 因此如果你点击了其它地方他就停止加载。再次点击窗口又开始加载。
俩种方式都是首地址加加(第一种前辍加加报错,后辍加加不报错,然而MapViewOfFile的返回值做++不管你前后都会报错 这种方式就可以lpMemory = (char*)lpMemory + 1; 我理解不了,如果说返回是常量不能修改为什么这种方式就可以)注意在汇编与 c 语言里不会报错
c++版
// PE练习.cpp : 定义控制台应用程序的入口点。
//
#include<Windows.h>
#include<iostream>
using namespace std;
void _openFile();
DWORD dwStop;
DWORD dwFileSize;
BYTE* g_pFileImageBase = 0;
PIMAGE_NT_HEADERS g_pNt = 0;
void ReadFileToMem(char* szFilePath)
{
//打开文件获取文件句柄
HANDLE hFile = CreateFile((LPCTSTR)szFilePath, GENERIC_READ, FALSE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("文件打开失败\n");
return;
}
//获取文件大小
dwFileSize = GetFileSize(hFile, NULL);
g_pFileImageBase = new BYTE[dwFileSize]{};
DWORD dwRead;
//将文件读取到内存中
bool bRet =
ReadFile(hFile, g_pFileImageBase, dwFileSize, &dwRead, NULL);
if (!bRet)
{
delete[] g_pFileImageBase;
}
//关闭句柄
CloseHandle(hFile);
}
bool IsPEFile()
{
//使用PIMAGE_DOS_HEADER(占64字节)解释前64个字节
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)g_pFileImageBase;
//判断PE文件的标识是否正确,有一个不对,那么它就不是PE文件
if (pDos->e_magic != IMAGE_DOS_SIGNATURE)//0x5A4D('MZ')
{
return false;
}
g_pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_pFileImageBase);
if (g_pNt->Signature != IMAGE_NT_SIGNATURE)//0x00004550('PE')
{
return false;
}
return true;
}
void ShowNtImportance()
{
printf("入口点RVA:%08X", g_pNt->OptionalHeader.AddressOfEntryPoint);
printf("文件默认加载:%08X", g_pNt->OptionalHeader.ImageBase);
printf("文件区段个数:%d", g_pNt->FileHeader.NumberOfSections);
//....
}
void ShowDirTable()
{
//获取目录表个数
int nCountOfDirTable = g_pNt->OptionalHeader.NumberOfRvaAndSizes;
printf("数据目录表个数:%d", g_pNt->OptionalHeader.NumberOfRvaAndSizes);
for (int i = 0; i < nCountOfDirTable;i++)
{
//如果VirtualAddress不为0,说明此表存在
if (g_pNt->OptionalHeader.DataDirectory[i].VirtualAddress)
{
//....
}
}
}
void ShowSectionTable()
{
//获取区段个数
int nCountOfSection = g_pNt->FileHeader.NumberOfSections;
//得到首个区段的位置
PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt);
//保存区段名字(区段名字可能不是以0为结尾的)
char strName[9] = {};
for (int i = 0; i < nCountOfSection;i++)
{
memcpy(strName, pSec->Name, 8);
printf("第%d个区段名:%s", i + 1, strName);
printf("区段RVA:%08X", pSec->VirtualAddress);
//....
//下一个区段地址
pSec++;
}
}
DWORD RVAtoFOA(DWORD dwRVA)
{
//此RVA落在哪个区段中
//找到所在区段后,
//减去所在区段的起始位置,加上在文件中的起始位置
int nCountOfSection = g_pNt->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt);
DWORD dwSecAligment = g_pNt->OptionalHeader.SectionAlignment;
for (int i = 0; i < nCountOfSection; i++)
{
//求在内存中的真实大小
DWORD dwRealVirSize = pSec->Misc.VirtualSize % dwSecAligment ?
pSec->Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment
: pSec->Misc.VirtualSize;
if (dwRVA >= pSec->VirtualAddress &&
dwRVA < pSec->VirtualAddress + dwRealVirSize)
{
//FOA = RVA - 内存中区段的起始位置 + 在文件中区段的起始位置
return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData;
}
//下一个区段地址
pSec++;
}
}
// DWORD FOAtoRVA(DWORD dwFOA)
// {
//
// }
int main() {
//方式1--------------------------------------------------------------------------------
//ReadFileToMem("C:\\Users\\allenboy\\Desktop\\fun.exe");
//int i = 0;
//int j = 0;
//while (j<dwFileSize)
//{
// printf("%x ", *(char *)g_pFileImageBase);
// ++i;
// if (i == 16) {
// printf("\n");
// i = 0;
// }
// ++j;
// (char *)g_pFileImageBase++;
//}
//方式2--------------------------------------------------------------------------------
_openFile();
cin.get();
return 0;
}
/*
打开PE文件并处理
*/
void _openFile()
{
OPENFILENAME stOF;
HANDLE hFile, hMapFile;
DWORD totalSize; //文件大小
LPVOID lpMemory; //内存映像文件在内存的起始位置
char szFileName[MAX_PATH] = { 0 }; //要打开的文件路径及名称名
char bufTemp1[10]; //每个字符的十六进制字节码
char bufTemp2[20]; //第一列
char lpServicesBuffer[100]; //一行的所有内容
char bufDisplay[50]; //第三列ASCII码字符
DWORD dwCount; //计数,逢16则重新计
DWORD dwCount1; //地址顺号
DWORD dwBlanks; //最后一行空格数
char szExtPe[] = TEXT("PE Files\0*.exe;*.dll;*.scr;*.fon;*.drv\0All Files(*.*)\0*.*\0\0");
RtlZeroMemory(&stOF, sizeof(stOF));
stOF.lStructSize = sizeof(stOF);
//stOF.hwndOwner = (HWND)GetModuleHandle(NULL);
stOF.lpstrFilter = szExtPe;
stOF.lpstrFile = szFileName;
stOF.nMaxFile = MAX_PATH;
stOF.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&stOF)) //让用户选择打开的文件
{
hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
totalSize = GetFileSize(hFile, NULL);//获取文件大小
if (totalSize)
{
hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);//内存映射文件
if (hMapFile)
{
lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//获得文件在内存的映象起始位置
if (lpMemory)
{
//开始处理文件
//缓冲区初始化
RtlZeroMemory(bufTemp1, 10);
RtlZeroMemory(bufTemp2, 20);
RtlZeroMemory(lpServicesBuffer, 100);
RtlZeroMemory(bufDisplay, 50);
dwCount = 1;
//将第一列写入lpServicesBuffer
dwCount1 = 0;
sprintf(bufTemp2, "%08x ", dwCount1);
lstrcat(lpServicesBuffer, bufTemp2); //函数功能:该函数将一个字符串附加在另一个字符串后面。
dwBlanks = (16 - totalSize % 16) * 3;//求最后一行的空格数
while (TRUE)
{
if (totalSize == 0)//最后一行
{
while (dwBlanks)//填充空格
{
lstrcat(lpServicesBuffer, TEXT("#"));
--dwBlanks;
}
lstrcat(lpServicesBuffer, TEXT(" "));//第二列与第三列中间的空格
lstrcat(lpServicesBuffer, bufDisplay);//第三列内容
lstrcat(lpServicesBuffer, TEXT("\n"));//回车换行符号
break;
}
//翻译成可以显示的ascii码字,写入第三列的值
if (*(char *)lpMemory > 0x20 && *(char *)lpMemory < 0x7e)
{
bufDisplay[dwCount - 1] = *(char *)lpMemory;
}
else
{
bufDisplay[dwCount - 1] = 0x2e;//如果不是ASCII码值,则显示“.”
}
sprintf(bufTemp1, "%02X ", *(TBYTE *)lpMemory);//字节的十六进制字符串到@bufTemp1中
lstrcat(lpServicesBuffer, bufTemp1);//将第二列写入lpServicesBuffer
if (dwCount == 16)//已到16个字节,
{
lstrcat(lpServicesBuffer, TEXT(" "));//第二列与第三列中间的空格
lstrcat(lpServicesBuffer, bufDisplay);//显示第三列字符
lstrcat(lpServicesBuffer, TEXT("\n"));//回车换行
printf("%s",lpServicesBuffer);
RtlZeroMemory(lpServicesBuffer, 100);
if (dwStop == 1)
{
break;
}
sprintf(bufTemp2, "%08X ", (++dwCount1) * 16); // 显示下一行的地址
lstrcat(lpServicesBuffer, bufTemp2);
dwCount = 0;
RtlZeroMemory(bufDisplay, 50);
}
--totalSize;
++dwCount;
//((char *)lpMemory)++;
lpMemory = (char*)lpMemory + 1;
//break;
}
// _appendInfo(lpServicesBuffer); //添加最后一行
printf("%s", lpServicesBuffer);
UnmapViewOfFile(lpMemory);
}
CloseHandle(hMapFile);
}
}
CloseHandle(hFile);
}
}
}
--------------------------------------c版只能运行第二种第一种用的 c++写的在 c 里注释了
// PE练习.cpp : 定义控制台应用程序的入口点。
//
#include<Windows.h>
#include<stdio.h>
//#include<iostream>
//using namespace std;
void _openFile();
DWORD dwStop;
BYTE* g_pFileImageBase = 0;
PIMAGE_NT_HEADERS g_pNt = 0;
void ReadFileToMem(char* szFilePath)
{
//打开文件获取文件句柄
HANDLE hFile = CreateFile((LPCTSTR)szFilePath, GENERIC_READ, FALSE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("文件打开失败\n");
return;
}
//获取文件大小
DWORD dwFileSize = GetFileSize(hFile, NULL);
//g_pFileImageBase = new BYTE[dwFileSize]{};
DWORD dwRead;
//将文件读取到内存中
BOOL bRet =
ReadFile(hFile, g_pFileImageBase, dwFileSize, &dwRead, NULL);
if (!bRet)
{
//delete[] g_pFileImageBase;
}
//关闭句柄
CloseHandle(hFile);
}
BOOL IsPEFile()
{
//使用PIMAGE_DOS_HEADER(占64字节)解释前64个字节
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)g_pFileImageBase;
//判断PE文件的标识是否正确,有一个不对,那么它就不是PE文件
if (pDos->e_magic != IMAGE_DOS_SIGNATURE)//0x5A4D('MZ')
{
return FALSE;
}
g_pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_pFileImageBase);
if (g_pNt->Signature != IMAGE_NT_SIGNATURE)//0x00004550('PE')
{
return FALSE;
}
return TRUE;
}
void ShowNtImportance()
{
printf("入口点RVA:%08X", g_pNt->OptionalHeader.AddressOfEntryPoint);
printf("文件默认加载:%08X", g_pNt->OptionalHeader.ImageBase);
printf("文件区段个数:%d", g_pNt->FileHeader.NumberOfSections);
//....
}
void ShowDirTable()
{
//获取目录表个数
int nCountOfDirTable = g_pNt->OptionalHeader.NumberOfRvaAndSizes;
printf("数据目录表个数:%d", g_pNt->OptionalHeader.NumberOfRvaAndSizes);
for (int i = 0; i < nCountOfDirTable;i++)
{
//如果VirtualAddress不为0,说明此表存在
if (g_pNt->OptionalHeader.DataDirectory[i].VirtualAddress)
{
//....
}
}
}
void ShowSectionTable()
{
//获取区段个数
int nCountOfSection = g_pNt->FileHeader.NumberOfSections;
//得到首个区段的位置
PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt);
//保存区段名字(区段名字可能不是以0为结尾的)
//char strName[9] = {};
char strName[9];
for (int i = 0; i < nCountOfSection;i++)
{
memcpy(strName, pSec->Name, 8);
printf("第%d个区段名:%s", i + 1, strName);
printf("区段RVA:%08X", pSec->VirtualAddress);
//....
//下一个区段地址
pSec++;
}
}
DWORD RVAtoFOA(DWORD dwRVA)
{
//此RVA落在哪个区段中
//找到所在区段后,
//减去所在区段的起始位置,加上在文件中的起始位置
int nCountOfSection = g_pNt->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt);
DWORD dwSecAligment = g_pNt->OptionalHeader.SectionAlignment;
for (int i = 0; i < nCountOfSection; i++)
{
//求在内存中的真实大小
DWORD dwRealVirSize = pSec->Misc.VirtualSize % dwSecAligment ?
pSec->Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment
: pSec->Misc.VirtualSize;
if (dwRVA >= pSec->VirtualAddress &&
dwRVA < pSec->VirtualAddress + dwRealVirSize)
{
//FOA = RVA - 内存中区段的起始位置 + 在文件中区段的起始位置
return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData;
}
//下一个区段地址
pSec++;
}
}
// DWORD FOAtoRVA(DWORD dwFOA)
// {
//
// }
int main1() {
/*ReadFileToMem("C:\\Users\\allenboy\\Desktop\\fun.exe");
int i = 0;
while ((char *)g_pFileImageBase++)
{
printf("%x ", *(char *)g_pFileImageBase);
++i;
if (i == 16) {
printf("\n");
i = 0;
}
}*/
_openFile();
//cin.get();
getchar();
return 0;
}
/*
打开PE文件并处理
*/
void _openFile()
{
OPENFILENAME stOF;
HANDLE hFile, hMapFile;
DWORD totalSize; //文件大小
LPVOID lpMemory; //内存映像文件在内存的起始位置
char szFileName[MAX_PATH] = { 0 }; //要打开的文件路径及名称名
char bufTemp1[10]; //每个字符的十六进制字节码
char bufTemp2[20]; //第一列
char lpServicesBuffer[100]; //一行的所有内容
char bufDisplay[50]; //第三列ASCII码字符
DWORD dwCount; //计数,逢16则重新计
DWORD dwCount1; //地址顺号
DWORD dwBlanks; //最后一行空格数
char szExtPe[] = TEXT("PE Files\0*.exe;*.dll;*.scr;*.fon;*.drv\0All Files(*.*)\0*.*\0\0");
RtlZeroMemory(&stOF, sizeof(stOF));
stOF.lStructSize = sizeof(stOF);
//stOF.hwndOwner = (HWND)GetModuleHandle(NULL);
stOF.lpstrFilter = szExtPe;
stOF.lpstrFile = szFileName;
stOF.nMaxFile = MAX_PATH;
stOF.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&stOF)) //让用户选择打开的文件
{
hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
totalSize = GetFileSize(hFile, NULL);//获取文件大小
if (totalSize)
{
hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);//内存映射文件
if (hMapFile)
{
lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//获得文件在内存的映象起始位置
if (lpMemory)
{
//开始处理文件
//缓冲区初始化
RtlZeroMemory(bufTemp1, 10);
RtlZeroMemory(bufTemp2, 20);
RtlZeroMemory(lpServicesBuffer, 100);
RtlZeroMemory(bufDisplay, 50);
dwCount = 1;
//将第一列写入lpServicesBuffer
dwCount1 = 0;
sprintf(bufTemp2, "%08x ", dwCount1);
lstrcat(lpServicesBuffer, bufTemp2); //函数功能:该函数将一个字符串附加在另一个字符串后面。
dwBlanks = (16 - totalSize % 16) * 3;//求最后一行的空格数
while (TRUE)
{
if (totalSize == 0)//最后一行
{
while (dwBlanks)//填充空格
{
lstrcat(lpServicesBuffer, TEXT("#"));
--dwBlanks;
}
lstrcat(lpServicesBuffer, TEXT(" "));//第二列与第三列中间的空格
lstrcat(lpServicesBuffer, bufDisplay);//第三列内容
lstrcat(lpServicesBuffer, TEXT("\n"));//回车换行符号
break;
}
//翻译成可以显示的ascii码字,写入第三列的值
if (*(char *)lpMemory > 0x20 && *(char *)lpMemory < 0x7e)
{
bufDisplay[dwCount - 1] = *(char *)lpMemory;
}
else
{
bufDisplay[dwCount - 1] = 0x2e;//如果不是ASCII码值,则显示“.”
}
sprintf(bufTemp1, "%02X ", *(TBYTE *)lpMemory);//字节的十六进制字符串到@bufTemp1中
lstrcat(lpServicesBuffer, bufTemp1);//将第二列写入lpServicesBuffer
if (dwCount == 16)//已到16个字节,
{
lstrcat(lpServicesBuffer, TEXT(" "));//第二列与第三列中间的空格
lstrcat(lpServicesBuffer, bufDisplay);//显示第三列字符
lstrcat(lpServicesBuffer, TEXT("\n"));//回车换行
//_appendInfo(lpServicesBuffer);//写入内容 //一行的所有内容)
printf("%s", lpServicesBuffer);
RtlZeroMemory(lpServicesBuffer, 100);
if (dwStop == 1)
{
break;
}
sprintf(bufTemp2, "%08X ", (++dwCount1) * 16); // 显示下一行的地址
lstrcat(lpServicesBuffer, bufTemp2);
dwCount = 0;
RtlZeroMemory(bufDisplay, 50);
}
--totalSize;
++dwCount;
++((char *)lpMemory);
//break;
}
// _appendInfo(lpServicesBuffer); //添加最后一行
printf("%s", lpServicesBuffer);
UnmapViewOfFile(lpMemory);
}
CloseHandle(hMapFile);
}
}
CloseHandle(hFile);
}
}
}
转载于:https://blog.51cto.com/haidragon/2103932