我写了一个读取pe引出表的小程序,单独工作正常,
#include <stdio.h>
#include <windows.h>
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva,
PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}void LocateExports(DWORD PEimagebase)
{
PIMAGE_DOS_HEADER PDOSHeader;
PIMAGE_NT_HEADERS PNTHeader;
PIMAGE_SECTION_HEADER PSHeader; PIMAGE_EXPORT_DIRECTORY ExportDir; DWORD exportsStartRVA, exportsEndRVA;
DWORD VirtualAddress, PointerToRawData; PDOSHeader = (PIMAGE_DOS_HEADER)PEimagebase; if(PDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("It isn't PE file.\n");
return;
} PNTHeader = (PIMAGE_NT_HEADERS)(PEimagebase + PDOSHeader->e_lfanew);
if(PNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
printf("It isn't PE file.\n");
return;
} DWORD NumberOfSections = PNTHeader->FileHeader.NumberOfSections; exportsStartRVA = PNTHeader->OptionalHeader.DataDirectory[0].VirtualAddress;
exportsEndRVA = exportsStartRVA + PNTHeader->OptionalHeader.DataDirectory[0].Size;
/*
PSHeader = new PIMAGE_SECTION_HEADER[NumberOfSections]; for(int i = 0; i < NumberOfSections; i++)
{
PSHeader[i] = (PIMAGE_SECTION_HEADER)((PBYTE)PNTHeader + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i);
printf("Section Name: %-10s VirtualAddress : 0x%-10p\nVirtualSize : 0x%-10pPointerToRawData: 0x%-10p\n", PSHeader[i]->Name, PSHeader[i]->VirtualAddress, PSHeader[i]->Misc.VirtualSize, PSHeader[i]->PointerToRawData);
if(exportsStartRVA >= PSHeader[i]->VirtualAddress && exportsStartRVA < PSHeader[i]->VirtualAddress + PSHeader[i]->Misc.VirtualSize)
{
printf("引入表RVA,在节表%s的RVA范围内。\n", PSHeader[i]->Name);
VirtualAddress = PSHeader[i]->VirtualAddress;
PointerToRawData = PSHeader[i]->PointerToRawData;
printf("引入表在文件的开始位置: 0x%p\n", exportsStartRVA - VirtualAddress + PointerToRawData);
}
}
delete [] PSHeader;
*/
PSHeader = GetEnclosingSectionHeader(exportsStartRVA, PNTHeader);
if(PSHeader == NULL)
return; VirtualAddress = PSHeader->VirtualAddress;
PointerToRawData = PSHeader->PointerToRawData; if(VirtualAddress == 0 || PointerToRawData == 0)
return; ExportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, PEimagebase, exportsStartRVA - VirtualAddress + PointerToRawData); PSTR filename = (PSTR)(ExportDir->Name + PEimagebase - VirtualAddress + PointerToRawData);
printf(" Name: %s\n", filename);
PDWORD functions = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + PEimagebase - VirtualAddress + PointerToRawData);
PWORD ordinals = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + PEimagebase - VirtualAddress + PointerToRawData);
PSTR *name = (PSTR *)((DWORD)ExportDir->AddressOfNames + PEimagebase - VirtualAddress + PointerToRawData); for ( int i =0; i < ExportDir->NumberOfFunctions; i++ )
{
DWORD entryPointRVA = functions[i];
DWORD j; if ( entryPointRVA == 0 ) // Skip over gaps in exported function
continue; // ordinals (the entrypoint is 0 for
// these functions). printf(" %08X %4u", entryPointRVA, i + ExportDir->Base ); // See if this function has an associated name exported for it.
for ( int j = 0; j < ExportDir->NumberOfNames; j++ )
if ( ordinals[j] == i )
printf(" %s", name[j] + PEimagebase - VirtualAddress + PointerToRawData); // Is it a forwarder? If so, the entry point RVA is inside the
// .edata section, and is an RVA to the DllName.EntryPointName
if ( (entryPointRVA >= exportsStartRVA)
&& (entryPointRVA <= exportsEndRVA) )
{
printf(" (forwarder -> %s)", entryPointRVA + PEimagebase - VirtualAddress + PointerToRawData );
}
printf("\n");
}
}void main(int argc, char *argv[])
{
if(argc != 2)
// return;
argv[1]= "c:\\routetab.dll";
HANDLE hFile;
HANDLE hFmap;
LPVOID lPoint;
DWORD FileSize; printf("PE Exports v 0.1\n");
hFile = CreateFile( argv[1],
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); if(hFile == INVALID_HANDLE_VALUE)
{
printf("Can't open file.\n");
CloseHandle(hFile);
return;
} hFmap = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, 0, 0); if(hFmap != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hFmap);
CloseHandle(hFile);
return;
} lPoint = MapViewOfFile(hFmap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); if(lPoint)
{
// 查找
LocateExports((DWORD)lPoint);
// LocateExports(0x77e60000);
} FileSize = GetFileSize(hFile, NULL); printf("file size: %d\n", FileSize);
CloseHandle(hFmap);
CloseHandle(hFile);
}可是当我直接指定内存地址,比如LocateExports(0x77e60000)时,(0x77e60000是我
的win2ksp4中kernel32.dll被系统加载在内存中的地址)却出错,原因是执行到
PSTR filename = (PSTR)(ExportDir->Name + PEimagebase - VirtualAddress + PointerToRawData);
PDWORD functions = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + PEimagebase - VirtualAddress + PointerToRawData);
PWORD ordinals = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + PEimagebase - VirtualAddress + PointerToRawData);
PSTR *name = (PSTR *)((DWORD)ExportDir->AddressOfNames + PEimagebase - VirtualAddress + PointerToRawData);
时候,报告指针无效。这我就不懂了,我把c:\winnt\system32\kernel32.dll mapping进内存却可以正常读取。。PS:我的目的是从内存中的kernel32.dll中搜出所有引出的api函数.
#include <stdio.h>
#include <windows.h>
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva,
PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}void LocateExports(DWORD PEimagebase)
{
PIMAGE_DOS_HEADER PDOSHeader;
PIMAGE_NT_HEADERS PNTHeader;
PIMAGE_SECTION_HEADER PSHeader; PIMAGE_EXPORT_DIRECTORY ExportDir; DWORD exportsStartRVA, exportsEndRVA;
DWORD VirtualAddress, PointerToRawData; PDOSHeader = (PIMAGE_DOS_HEADER)PEimagebase; if(PDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("It isn't PE file.\n");
return;
} PNTHeader = (PIMAGE_NT_HEADERS)(PEimagebase + PDOSHeader->e_lfanew);
if(PNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
printf("It isn't PE file.\n");
return;
} DWORD NumberOfSections = PNTHeader->FileHeader.NumberOfSections; exportsStartRVA = PNTHeader->OptionalHeader.DataDirectory[0].VirtualAddress;
exportsEndRVA = exportsStartRVA + PNTHeader->OptionalHeader.DataDirectory[0].Size;
/*
PSHeader = new PIMAGE_SECTION_HEADER[NumberOfSections]; for(int i = 0; i < NumberOfSections; i++)
{
PSHeader[i] = (PIMAGE_SECTION_HEADER)((PBYTE)PNTHeader + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i);
printf("Section Name: %-10s VirtualAddress : 0x%-10p\nVirtualSize : 0x%-10pPointerToRawData: 0x%-10p\n", PSHeader[i]->Name, PSHeader[i]->VirtualAddress, PSHeader[i]->Misc.VirtualSize, PSHeader[i]->PointerToRawData);
if(exportsStartRVA >= PSHeader[i]->VirtualAddress && exportsStartRVA < PSHeader[i]->VirtualAddress + PSHeader[i]->Misc.VirtualSize)
{
printf("引入表RVA,在节表%s的RVA范围内。\n", PSHeader[i]->Name);
VirtualAddress = PSHeader[i]->VirtualAddress;
PointerToRawData = PSHeader[i]->PointerToRawData;
printf("引入表在文件的开始位置: 0x%p\n", exportsStartRVA - VirtualAddress + PointerToRawData);
}
}
delete [] PSHeader;
*/
PSHeader = GetEnclosingSectionHeader(exportsStartRVA, PNTHeader);
if(PSHeader == NULL)
return; VirtualAddress = PSHeader->VirtualAddress;
PointerToRawData = PSHeader->PointerToRawData; if(VirtualAddress == 0 || PointerToRawData == 0)
return; ExportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, PEimagebase, exportsStartRVA - VirtualAddress + PointerToRawData); PSTR filename = (PSTR)(ExportDir->Name + PEimagebase - VirtualAddress + PointerToRawData);
printf(" Name: %s\n", filename);
PDWORD functions = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + PEimagebase - VirtualAddress + PointerToRawData);
PWORD ordinals = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + PEimagebase - VirtualAddress + PointerToRawData);
PSTR *name = (PSTR *)((DWORD)ExportDir->AddressOfNames + PEimagebase - VirtualAddress + PointerToRawData); for ( int i =0; i < ExportDir->NumberOfFunctions; i++ )
{
DWORD entryPointRVA = functions[i];
DWORD j; if ( entryPointRVA == 0 ) // Skip over gaps in exported function
continue; // ordinals (the entrypoint is 0 for
// these functions). printf(" %08X %4u", entryPointRVA, i + ExportDir->Base ); // See if this function has an associated name exported for it.
for ( int j = 0; j < ExportDir->NumberOfNames; j++ )
if ( ordinals[j] == i )
printf(" %s", name[j] + PEimagebase - VirtualAddress + PointerToRawData); // Is it a forwarder? If so, the entry point RVA is inside the
// .edata section, and is an RVA to the DllName.EntryPointName
if ( (entryPointRVA >= exportsStartRVA)
&& (entryPointRVA <= exportsEndRVA) )
{
printf(" (forwarder -> %s)", entryPointRVA + PEimagebase - VirtualAddress + PointerToRawData );
}
printf("\n");
}
}void main(int argc, char *argv[])
{
if(argc != 2)
// return;
argv[1]= "c:\\routetab.dll";
HANDLE hFile;
HANDLE hFmap;
LPVOID lPoint;
DWORD FileSize; printf("PE Exports v 0.1\n");
hFile = CreateFile( argv[1],
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); if(hFile == INVALID_HANDLE_VALUE)
{
printf("Can't open file.\n");
CloseHandle(hFile);
return;
} hFmap = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, 0, 0); if(hFmap != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hFmap);
CloseHandle(hFile);
return;
} lPoint = MapViewOfFile(hFmap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); if(lPoint)
{
// 查找
LocateExports((DWORD)lPoint);
// LocateExports(0x77e60000);
} FileSize = GetFileSize(hFile, NULL); printf("file size: %d\n", FileSize);
CloseHandle(hFmap);
CloseHandle(hFile);
}可是当我直接指定内存地址,比如LocateExports(0x77e60000)时,(0x77e60000是我
的win2ksp4中kernel32.dll被系统加载在内存中的地址)却出错,原因是执行到
PSTR filename = (PSTR)(ExportDir->Name + PEimagebase - VirtualAddress + PointerToRawData);
PDWORD functions = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + PEimagebase - VirtualAddress + PointerToRawData);
PWORD ordinals = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + PEimagebase - VirtualAddress + PointerToRawData);
PSTR *name = (PSTR *)((DWORD)ExportDir->AddressOfNames + PEimagebase - VirtualAddress + PointerToRawData);
时候,报告指针无效。这我就不懂了,我把c:\winnt\system32\kernel32.dll mapping进内存却可以正常读取。。PS:我的目的是从内存中的kernel32.dll中搜出所有引出的api函数.
::VirtualProtect((LPVOID)0x77e60000,dwSize,PAGE_EXECUTE_READWRITE,&dwOldProtected);
就可以了(dwSize为你要修改的内存尺寸)
DWORD dwOldProtected = NULL ;
VirtualProtect((LPVOID)PEimagebase, PNTHeader->OptionalHeader.SizeOfImage, PAGE_EXECUTE_READWRITE, &dwOldProtected);
结果到了下面,还是出现一样的提示:PEExport.exe 中的 0x00412f5c 处未处理的异常: 0xC0000005: 读取位置 0x23919f00 时发生访问冲突 。
跟没加的错误提示一样。。程序崩溃了,我也要崩溃了。。