首页
社区
课程
招聘
[原创]读取 PE 文件的问题
发表于: 2009-8-30 01:43 5900

[原创]读取 PE 文件的问题

2009-8-30 01:43
5900
// kuretrievefun.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "Windows.h"

int _tmain(int argc, _TCHAR* argv[])
{
        void *hFile = CreateFile("f:\\user32d.dll",GENERIC_ALL,0,0,OPEN_EXISTING,0,0);
        void *hMap = CreateFileMapping(hFile,0,PAGE_READWRITE,0,0,0);
        ULONG pFile = (ULONG)/*MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);//*/LoadLibrary("user32.dll");
        if(pFile == 0) {
                Beep(1000,100);
        }
        printf("%x\n",pFile);
        IMAGE_DOS_HEADER *dos_hdr;
        IMAGE_NT_HEADERS *nt_hdr;
        IMAGE_IMPORT_DESCRIPTOR *importdes;
        dos_hdr = (IMAGE_DOS_HEADER*)pFile;
        nt_hdr = (IMAGE_NT_HEADERS*)((ULONG)pFile + dos_hdr->e_lfanew);
        //printf("%x\n",nt_hdr->Signature);
        //printf("%x\n",nt_hdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
        importdes = (IMAGE_IMPORT_DESCRIPTOR*)(pFile + nt_hdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
        //printf("%s\n",importdes);
        while(importdes->FirstThunk) {
                char *ku = (char*)((ULONG)pFile + importdes->Name);
                printf("%s\n",ku);
                importdes++;
                //break;
        }
        return 0;
}

上面,如果用 LoadLibrary 的话就没有问题,但用 MapViewOfFile 的话就会说内存访问错误,请教请教....

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

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
2
你Map的时候非要AllAccess干啥?有的文件不能随便写,注意权限,需要多大就用多大~另外hFile检查了吗?hMap检查了吗?即使Map失败,你Beep一声之后不还是继续访问了那块内存?逻辑不严密,而且编程修养太差~
2009-8-30 07:34
0
雪    币: 342
活跃值: (55)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
hFile、hMap、都没问题,权限即使改成 FILE_MAP_READ 都会出错.....
上传的附件:
2009-8-30 09:43
0
雪    币: 251
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
LoadLibrary 默认是 Map as Image
MapViewOfFile 是 Map as Data File
文件对齐和节对齐很可能是不一样的,所以PE的文件布局和内存布局是不太一样的
所以各个节的访问应该进行调整
对文件结构直接访问时 应该先确定 IMPORT 在哪个节上,然后根据节的VirtualAddress 与PointerToRawData 计算出实际的虚拟地址
这是wrk里的,参考一下吧
PIMAGE_SECTION_HEADER
RtlSectionTableFromVirtualAddress (
IN PIMAGE_NT_HEADERS NtHeaders,
IN PVOID Base,
IN ULONG Address
)

/*++

Routine Description:

This function locates a VirtualAddress within the image header
of a file that is mapped as a file and returns a pointer to the
section table entry for that virtual address

Arguments:

NtHeaders - Supplies the pointer to the image or data file.

Base - Supplies the base of the image or data file.

Address - Supplies the virtual address to locate.

Return Value:

NULL - The file does not contain data for the specified directory entry.

NON-NULL - Returns the pointer of the section entry containing the data.

--*/

{
ULONG i;
PIMAGE_SECTION_HEADER NtSection;

NtSection = IMAGE_FIRST_SECTION( NtHeaders );
for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++) {
if ((ULONG)Address >= NtSection->VirtualAddress &&
(ULONG)Address < NtSection->VirtualAddress + NtSection->SizeOfRawData
) {
return NtSection;
}
++NtSection;
}

return NULL;
}


PVOID
RtlAddressInSectionTable (
IN PIMAGE_NT_HEADERS NtHeaders,
IN PVOID Base,
IN ULONG Address
)

/*++

Routine Description:

This function locates a VirtualAddress within the image header
of a file that is mapped as a file and returns the seek address
of the data the Directory describes.

Arguments:

NtHeaders - Supplies the pointer to the image or data file.

Base - Supplies the base of the image or data file.

Address - Supplies the virtual address to locate.

Return Value:

NULL - The file does not contain data for the specified directory entry.

NON-NULL - Returns the address of the raw data the directory describes.

--*/

{
PIMAGE_SECTION_HEADER NtSection;

NtSection = RtlSectionTableFromVirtualAddress( NtHeaders,
Base,
Address
);
if (NtSection != NULL) {
return( ((PCHAR)Base + ((ULONG_PTR)Address - NtSection->VirtualAddress) + NtSection->PointerToRawData) );
}
else {
return( NULL );
}
}


PVOID
RtlpImageDirectoryEntryToData32 (
IN PVOID Base,
IN BOOLEAN MappedAsImage,
IN USHORT DirectoryEntry,
OUT PULONG Size,
PIMAGE_NT_HEADERS32 NtHeaders
)
{
ULONG DirectoryAddress;

if (DirectoryEntry >= NtHeaders->OptionalHeader.NumberOfRvaAndSizes) {
return( NULL );
}

if (!(DirectoryAddress = NtHeaders->OptionalHeader.DataDirectory[ DirectoryEntry ].VirtualAddress)) {
return( NULL );
}

if (Base < MM_HIGHEST_USER_ADDRESS) {
if ((PVOID)((PCHAR)Base + DirectoryAddress) >= MM_HIGHEST_USER_ADDRESS) {
return( NULL );
}
}

*Size = NtHeaders->OptionalHeader.DataDirectory[ DirectoryEntry ].Size;
if (MappedAsImage || DirectoryAddress < NtHeaders->OptionalHeader.SizeOfHeaders) {
return( (PVOID)((PCHAR)Base + DirectoryAddress) );
}

return( RtlAddressInSectionTable((PIMAGE_NT_HEADERS)NtHeaders, Base, DirectoryAddress ));
}
2009-8-30 10:21
0
雪    币: 0
活跃值: (954)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
代码风格很乱,至少一般人看的都觉得很累。。
2009-8-30 10:46
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
6
4楼正解,LoadLibrary是按PE格式映射的,直接Map的话需要RavToRaw然后再访问
2009-8-30 13:03
0
雪    币: 107
活跃值: (172)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
用GetLastError获取错误代码.
2009-8-30 13:19
0
雪    币: 179
活跃值: (26)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
楼主没有搞清楚文件偏移和虚拟内存偏移的概念。
用文件映射的时候相当于直接把文件复制进内存,这时候进行相关操作的时候用的是文件偏移,而你用的是虚拟内存偏移,所以会出错,需要把虚拟内存偏移转换为文件偏移。
使用LoadLibrary的时候是PE加载器把模块加载到了内存,这时候进行相关操作用的就是虚拟内存偏移,所以不会出错。
2009-8-30 13:31
0
雪    币: 290
活跃值: (41)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
8樓正解
是讀文件,不是執行文件
RVA要轉RAW
不然就定位錯了
2009-8-30 17:11
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
10
楼主居然用了原创~
2009-8-30 18:19
0
游客
登录 | 注册 方可回帖
返回
//