最近刚刚开始看pe文件,有一个关于定位IAT的程序,其中的代码需要一段RVAToOffset的函数。
贴上我在qq群问的与别人的讨论的文字,大家看一下
====================================
我:21:57:08
问个问题把?pe分析软件分析pe文件和我直接运行pe文件有什么区别啊?
邪灵亡() 21:57:42
好问题
:21:57:55
我是被pe搞糊涂了
邪灵亡() 21:58:32
分析软件只是把pe读到内存里,并没有运行
邪灵亡() 21:58:52
直接运行pe文件,会读到内存里,并让cpu去执行
我:22:00:05
那这这个
映射完成后和我直接运行后在内存中的结构布局一样吗 ?
22:00:26
就是牵扯到IMAGE BASE之类的东西
邪灵亡() 22:00:56
image base只是个数字而已
我:22:01:48
哦
我:22:03:23
pe文件直接映射在内存 和 windows pe装载器装载pe文件 两种方式 对比,内存布局一样吗?
就是是不是都是4k对其之类的
邪灵亡() 22:05:43
我晕,太细节了,咱不懂
邪灵亡() 22:05:50
反正差不多就那4k撒的了
我:22:05:50
哦
邪灵亡() 22:06:20
关注的应该是那个virtualalign和filealign的区别,我还没搞懂那个关系
我:22:06:38
那个关系我明白
邪灵亡() 22:07:01
撒关系,讲解下
我:22:07:33
file应该是扇区的大小,512字节
我:22:07:49
vitual对其应该是内存的页文件大小
我:22:08:12
磁盘结构中512字节(一个扇区)是最小的存取单位(不同的操作系统可能不同,windows是以簇为单位的)
邪灵亡() 22:08:18
就是对一个文件,为撒virtualsize和rawsize不同
我:22:08:53
rawsize是对其后的,而那个vitualsize据试验应该是对其以前的大小
我:22:09:12
我在问个问题吧?
那你怎么理解“pe文件的结构和在内存中的数据结构是一致”的啊?
我:22:09:26
这里的数据结构你是怎么理解的啊?
邪灵亡() 22:10:58
它放在那里就是让你去用的
邪灵亡() 22:10:59
没怎么理解
我:22:11:05
哦
我:22:11:38
那你分析过一个分析导入表的程序吗?
邪灵亡() 22:11:39
那个virtualsize是对其前的? 为撒还弄个virtualalign?
我:22:11:50
这就不知道了
邪灵亡() 22:12:06
不过忘记了,要查的话,我记得起来
邪灵亡() 22:12:17
那个加密与解密上讲的很清楚
邪灵亡() 22:12:19
分析过
我:22:12:44
就是有一部分, RVAToOffset()函数,我不是很理解
我:22:13:05
为什么要RAV2文件偏移啊?
邪灵亡() 22:13:08
函数?
我:22:13:35
int main(int argc, char* argv[])
{
//打开文件
HANDLE hFile=CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
printf("CreateFile Failed\n");
return 0;
}
HANDLE hMap=CreateFileMapping(hFile,NULL,PAGE_READONLY,NULL,NULL,NULL);
if(hMap==INVALID_HANDLE_VALUE)
{
printf("CreateFileMapping Failed\n");
return 0;
}
LPVOID lpBase=MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);
if(lpBase==NULL)
{
printf("MapViewOfFile Failed\n");
return 0;
}
IMAGE_DOS_HEADER *dosHeader;
IMAGE_NT_HEADERS *ntHeader;
IMAGE_IMPORT_BY_NAME *ImportName;
dosHeader=(IMAGE_DOS_HEADER*)lpBase;
if (dosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
printf("This is not a windows file\n");
return 0;
}
//定位到PE header
ntHeader=(IMAGE_NT_HEADERS*)((BYTE*)lpBase+dosHeader->e_lfanew);
if(ntHeader->Signature!=IMAGE_NT_SIGNATURE)
{
printf("This is not a win32 file\n");
return 0;
}
//定位到导入表
IMAGE_IMPORT_DESCRIPTOR *ImportDec=(IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)lpBase+RVAToOffset(lpBase,ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
while(ImportDec->FirstThunk)
{
//得到DLL文件名
char *pDllName=(char*)((BYTE*)lpBase+RVAToOffset(lpBase,ImportDec->Name));
printf("\nDLL文件名:%s\n",pDllName);
我:22:13:45
char *pDllName=(char*)((BYTE*)lpBase+RVAToOffset(lpBase,ImportDec->Name));
printf("\nDLL文件名:%s\n",pDllName);
我:22:13:57
你只看这一段就行了
我:22:14:08
里面有一个RVAToOffset的函数
我:22:14:22
DWORD RVAToOffset(LPVOID lpBase,DWORD VirtualAddress)
{
IMAGE_DOS_HEADER *dosHeader;
IMAGE_NT_HEADERS *ntHeader;
IMAGE_SECTION_HEADER *SectionHeader;
int NumOfSections;
dosHeader=(IMAGE_DOS_HEADER*)lpBase;
ntHeader=(IMAGE_NT_HEADERS*)((BYTE*)lpBase+dosHeader->e_lfanew);
NumOfSections=ntHeader->FileHeader.NumberOfSections;
for (int i=0;i<NumOfSections;i++)
{
SectionHeader=(IMAGE_SECTION_HEADER*)((BYTE*)lpBase+dosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS))+i;
if(VirtualAddress>SectionHeader->VirtualAddress&&VirtualAddress<SectionHeader->VirtualAddress+SectionHeader->SizeOfRawData)
{
DWORD AposRAV=VirtualAddress-SectionHeader->VirtualAddress;
DWORD Offset=SectionHeader->PointerToRawData+AposRAV;
return Offset;
}
}
return 0;
}
邪灵亡() 22:14:25
RVAToOffset这是别人自己写的吧?
我:22:14:36
恩
我:22:14:44
罗云彬的那本书里面也有的
我:22:14:49
只是用汇编写的
我:22:14:58
我看了一下和这段代码是一个意思
我:22:15:39
我就是不明白为什么用映射文件分析(也就是pe分析软件的做法)为什么还要那个函数啊?
邪灵亡() 22:18:02
函数里面的参数是DWORD VirtualAddress,怎么传的时候是传的ImportDec->Name
我:22:18:43
那个name成员就是以RAV存在的啊
我:22:18:52
定义是这个样子的
我:22:19:33
有一片文章说是文件映射和文件中的数据结构是一致的。而那个RAV是在pe装载器装载后的结果,所以才需要地址转换
我:22:19:50
我想了好半天
邪灵亡() 22:20:29
是的,RVA就是装载后的结果
邪灵亡() 22:20:36
你的程序是想得到什么
我:22:20:43
文件映射也是把pe文件映射到内存中,数据结构怎么会和文件中的一样呢?至少对其大小是不一样的。
我:22:21:02
我就是不明白这里的地址转换的作用。
我:22:21:44
既然都是在内存中,一个是文件映射,一个是装载器装载,都是在内存中,为什么还需要地址换呢?
邪灵亡() 22:21:55
你说rva?
我:22:21:59
恩
我:22:22:37
我感觉应该不用那个地址转换的,但是我见到的用文件映射方式的文章貌似都是这样的
我:22:22:52
至少罗云彬和看雪的书中是这样的
邪灵亡() 22:23:06
rva是个偏移,你MapViewOfFile后得到一个地址,这个地址加偏移就是实际在内存中的地址
我:22:23:40
恩,确切的说应该是线性地址
我:22:24:07
这一点我理解
我:22:25:03
那那个地址转换你怎么理解呢?
我:22:25:23
就是那个函数完成的功能
我:22:25:34
都是在内存中,为什么还需要地址换呢?
=====================
有关疑问我已经用黑色字体标出来了。
都是在内存中,为什么还需要地址换呢?
大家帮帮忙解释一下吧?谢谢了
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)