首页
社区
课程
招聘
关于64位win7系统读取PE文件函数导出表的问题,求大牛帮忙
发表于: 2015-2-25 21:07 6333

关于64位win7系统读取PE文件函数导出表的问题,求大牛帮忙

2015-2-25 21:07
6333
// PE导出表.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>

int main(void)
{
       
        PVOID64 ulModuleBase;

        ulModuleBase = GetModuleHandleW(TEXT("kernel32.dll"));  //得到"kernel32.dll"的基地址

        PIMAGE_DOS_HEADER pDosHeader; //dos头结构体
        PIMAGE_NT_HEADERS64 NtDllHeader; //nt结构头
        IMAGE_OPTIONAL_HEADER64 opthdr; //可选镜像头部

        IMAGE_EXPORT_DIRECTORY *pExportTable;

        ULONG_PTR* arrayOfFunctionAddresses;
        ULONG_PTR* arrayOfFunctionNames;
        WORD* arrayOfFunctionOrdinals;

        ULONG_PTR Base, x, functionAddress;

        ULONG_PTR functionOrdinal;
        char *functionName;

        __try
        {
                //得到dos头    PE内存映像从DOS头开始,也就是从IMAGE_DOS_HEADER结构体开始,文件在内存中的开始地址,也就是IMAGE_DOS_HEADER结构体开始的位置
                /*把这个值强制类型转换后,赋值给PIMAGE_DOS_HEADER类型指针,作为指向IMAGE_DOS_HEADER结构体的指针*/
                pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase;   //强制类型转换,将一个“PVOID64”转换为“PIMAGE_DOS_HEADER”
                if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)  //校验IMAGE_DOS_HEADER结构体的e_magic 是否符合预定义的数值5A4D
                {
                        printf("IMAGE_DOS_SIGNATURE failed\r\n");
                        return FALSE;
                }

                //得到NT文件头 NT结构体
                NtDllHeader = (PIMAGE_NT_HEADERS64)(ULONG_PTR)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
                if (NtDllHeader->Signature != IMAGE_NT_SIGNATURE)    //校验是否找到PE文件头,IMAGE_NT_SIGNATURE预定义为PE文件头,值为4550,DWORD型
                {
                        printf("IMAGE_NT_SIGNATURE failed\r\n");
                        return FALSE;
                }

                //得到可选镜像结构体
                opthdr = NtDllHeader->OptionalHeader;

                //得到内存的导出表结构
                pExportTable = (IMAGE_EXPORT_DIRECTORY*)((ULONG_PTR)ulModuleBase + opthdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); //得到导出表

                //地址
                arrayOfFunctionAddresses = (ULONG_PTR*)((ULONG_PTR)ulModuleBase + pExportTable->AddressOfFunctions);  //地址表

                /*NumberOfNames:被定义函数名称的导出函数的总数,显然只有这个数量的函数既可以用函数名方式导出。也可以用序号方式导出,剩*/
                /*下的NumberOfFunctions 减去NumberOfNames 数量的函数只能用序号方式导出。该字段的值只会小于或者等于NumberOfFunctions 字段*/
                /*的值,如果这个值是0,表示所有的函数都是以序号方式导出的。*/
                arrayOfFunctionNames = (ULONG_PTR*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames);         //函数名表
                if (IsBadReadPtr(arrayOfFunctionNames, pExportTable->NumberOfFunctions))
                {
                        printf("内存不可访问\n");
                        system("Pause");
                        return false;
                }
                arrayOfFunctionOrdinals = (WORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals);

                //得到导出表的起始地址
                Base = pExportTable->Base;

                //然后我们开始搜索整个导出表
                for (x = 0; x < pExportTable->NumberOfFunctions; x++) //在整个导出表里扫描
                {
                    functionName = (char*)((BYTE*)ulModuleBase + arrayOfFunctionNames[x]);

                        functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;

                        functionAddress = (ULONG_PTR)((BYTE*)ulModuleBase + arrayOfFunctionAddresses[functionOrdinal]);

                        printf("%s:0x%08X\r\n", functionName, functionAddress);

                }

        }
        _except(EXCEPTION_EXECUTE_HANDLER){
        }
        system("Pause");
        return 0;
}

这段代码问题到底出在那里,AddressOfNameOrdinals,AddressOfNames导出表结构体的这两个成员都是0,按照这个程序给出的代码导出表函数名的数组起始地址直接和DOS头文件重合,这绝对有问题,可是错在那里,如何改?求大牛指教

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

收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
有大神能解决,觉得金币不足联系我,知识无价,急求大牛帮忙
2015-2-25 21:22
0
雪    币: 52
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
没有试,但先看一下,你的编译平台是否是64位的。调试时看一下kernel32.dll的文件路径。
2015-2-26 08:35
0
雪    币: 1372
活跃值: (5343)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
4
搞清楚64位上 ULONG是多少字节 ULONG_PTR是多少字节,RVA几个字节 多用几个printf打印地址你就知道哪里错了
2015-2-26 08:49
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
C:\Windows\SysWOW64,用xuetu查看运行中的k32在这里,编译连接过程中也是去这个地方加载的
2015-2-26 08:50
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
用了无数printf函数,问题关键不在位数上面,关键问题所有的结构体的成员都能正常读取,但是哪两个都是0,这个很严重,网上说是符号加载失败,但是本质上为什么没有说,有大牛帮忙改改这个代码也行!
ULONG_PTR我查阅相关资料,是32位的,64为就会报警,几个相关的数组都没有超过32位,也许我认识不足!!!
2015-2-26 08:53
0
雪    币: 52
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
那你编译的是32位的exe,加载了x86的kernel32.dll,应该编译成64位的。
2015-2-26 08:54
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
教程本身是在32为上演示的一点儿问题都没有,上面的大哥说的应该有道理,为问题本身应该和位数是有关系的,突出反应的两个本来不该为0的成员值都是0,然后就是内存不能读.咋改能通过,谁指教一下啊!
2015-2-26 09:05
0
雪    币: 29340
活跃值: (7884)
能力值: ( LV15,RANK:3306 )
在线值:
发帖
回帖
粉丝
9
ULONG_PTR理解有问题
int _tmain(int argc, _TCHAR* argv[])
{
	printf("%d\n", sizeof(DWORD));
	ULONG_PTR ulModuleBase;

	ulModuleBase = (ULONG_PTR)GetModuleHandleW(TEXT("kernel32.dll"));  //得到"kernel32.dll"的基地址

	PIMAGE_DOS_HEADER pDosHeader; //dos头结构体
	PIMAGE_NT_HEADERS NtDllHeader; //nt结构头
	IMAGE_OPTIONAL_HEADER opthdr; //可选镜像头部


	IMAGE_EXPORT_DIRECTORY *pExportTable;


	DWORD* arrayOfFunctionAddresses;
	DWORD* arrayOfFunctionNames;
	WORD* arrayOfFunctionOrdinals;

	ULONG_PTR Base, x, functionAddress;

	ULONG_PTR functionOrdinal;
	char *functionName;

	__try
	{
		//得到dos头    PE内存映像从DOS头开始,也就是从IMAGE_DOS_HEADER结构体开始,文件在内存中的开始地址,也就是IMAGE_DOS_HEADER结构体开始的位置
		/*把这个值强制类型转换后,赋值给PIMAGE_DOS_HEADER类型指针,作为指向IMAGE_DOS_HEADER结构体的指针*/
		pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase;   //强制类型转换,将一个“PVOID64”转换为“PIMAGE_DOS_HEADER”
		if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)  //校验IMAGE_DOS_HEADER结构体的e_magic 是否符合预定义的数值5A4D
		{
			printf("IMAGE_DOS_SIGNATURE failed\r\n");
			return FALSE;
		}

		//得到NT文件头 NT结构体
		NtDllHeader = (PIMAGE_NT_HEADERS)(ULONG_PTR)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
		if (NtDllHeader->Signature != IMAGE_NT_SIGNATURE)    //校验是否找到PE文件头,IMAGE_NT_SIGNATURE预定义为PE文件头,值为4550,DWORD型
		{
			printf("IMAGE_NT_SIGNATURE failed\r\n");
			return FALSE;
		}

		//得到可选镜像结构体
		opthdr = NtDllHeader->OptionalHeader;

		//得到内存的导出表结构
		pExportTable = (IMAGE_EXPORT_DIRECTORY*)(ulModuleBase + opthdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); //得到导出表

		//地址
		arrayOfFunctionAddresses = (DWORD*)(ulModuleBase + pExportTable->AddressOfFunctions);  //地址表

		/*NumberOfNames:被定义函数名称的导出函数的总数,显然只有这个数量的函数既可以用函数名方式导出。也可以用序号方式导出,剩*/
		/*下的NumberOfFunctions 减去NumberOfNames 数量的函数只能用序号方式导出。该字段的值只会小于或者等于NumberOfFunctions 字段*/
		/*的值,如果这个值是0,表示所有的函数都是以序号方式导出的。*/
		arrayOfFunctionNames = (DWORD *)(ulModuleBase + pExportTable->AddressOfNames);         //函数名表
		if (IsBadReadPtr(arrayOfFunctionNames, pExportTable->NumberOfFunctions))
		{
			printf("内存不可访问\n");
			system("Pause");
			return false;
		}
		arrayOfFunctionOrdinals = (WORD*)(ulModuleBase + pExportTable->AddressOfNameOrdinals);

		//得到导出表的起始地址
		Base = pExportTable->Base;

		//然后我们开始搜索整个导出表
		for (x = 0; x < pExportTable->NumberOfFunctions; x++) //在整个导出表里扫描
		{
			functionName = (char*)(ulModuleBase + arrayOfFunctionNames[x]);

			functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;


			functionAddress = ulModuleBase + arrayOfFunctionAddresses[functionOrdinal];

			printf("%s:0x%08X\r\n", functionName, functionAddress);

		}

	}
	_except(EXCEPTION_EXECUTE_HANDLER){
	}
	system("Pause");
	return 0;
}
2015-2-26 09:23
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
[QUOTE=风间仁;1355324]ULONG_PTR理解有问题

int _tmain(int argc, _TCHAR* argv[])
{
        printf("%d\n", sizeof(DWORD));
        ULONG_PTR ulModuleBase;

        ulModuleBase = (ULONG_PTR)GetModuleH...[/QUOTE]

还是位数的问题,通过了,谢谢
2015-2-26 09:50
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
[QUOTE=风间仁;1355324]ULONG_PTR理解有问题

int _tmain(int argc, _TCHAR* argv[])
{
        printf("%d\n", sizeof(DWORD));
        ULONG_PTR ulModuleBase;

        ulModuleBase = (ULONG_PTR)GetModuleH...[/QUOTE]

大神能不能具体指导一下,让我偷个懒
2015-2-26 09:57
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
一切都是我自作聪明惹得祸!!!明明直到k32是32为的dll,却把  PIMAGE_NT_HEADERS64 NtDllHeader; //nt结构头
  IMAGE_OPTIONAL_HEADER64 opthdr; //可选镜像头部
这两个结构体改成64位的结构体,驴唇不对马嘴,当人读出来都是0
2015-2-26 11:01
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
代码本身没有问题,只要把那两个结构体改回去就完事大吉了
2015-2-26 11:04
0
雪    币: 37
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
谁有类似网络流量控制系统的源代码参考,谁有麻烦提供一下谢谢了~(追加高分)
我要做个网络监控即网络流量控制系统!但是没有类似的源代码参考,谁有麻烦提供一下谢谢了~
2015-2-26 11:08
0
游客
登录 | 注册 方可回帖
返回
//