我写了一个读取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函数.

解决方案 »

  1.   

    DWORD dwOldProtected = NULL ;
    ::VirtualProtect((LPVOID)0x77e60000,dwSize,PAGE_EXECUTE_READWRITE,&dwOldProtected);
    就可以了(dwSize为你要修改的内存尺寸)
      

  2.   

    在使用指针指向那段内存之前和合适位置,我加入了这段:
    DWORD dwOldProtected = NULL ;
    VirtualProtect((LPVOID)PEimagebase, PNTHeader->OptionalHeader.SizeOfImage, PAGE_EXECUTE_READWRITE, &dwOldProtected);
    结果到了下面,还是出现一样的提示:PEExport.exe 中的 0x00412f5c 处未处理的异常: 0xC0000005: 读取位置 0x23919f00 时发生访问冲突 。
    跟没加的错误提示一样。。程序崩溃了,我也要崩溃了。。
      

  3.   

    将kernel32.dll复制到另一路径下,打开它,想怎么分析都行了。