-
-
[原创]调试器实现_获取PE结构信息
-
发表于:
2009-9-10 21:49
6495
-
实现调试器,本来可以直接用fopen或者文件流读取文件信息,检测是否是正常的PE文件,再获取入口地址等部分信息就可以了。但是,为了让大家在用调试器的时候不要开一个PE_Infomation之类的软件,所以,我在调试器里面完全获取所有pe信息。
实现方法比较简单,我就大概说下:
由于完全面向对象,所以,为了体现面向对象的优势,我做了如下处理:
先定义一个抽象类(做用户访问的接口)
class PE_interface{
public:
virtual PIMAGE_DOS_HEADER GetDosHeader()=0;
virtual PIMAGE_NT_HEADERS GetNtHeaders()=0;
virtual PIMAGE_SECTION_HEADER GetSHeader()=0;
virtual void GetDataDir_Ex_Im(PIMAGE_IMPORT_DESCRIPTOR& pIm,PIMAGE_EXPORT_DIRECTORY& pEx)=0;
};
然后定义一个类,实现PE信息获取的功能。
class PE_Implement{
public:
PE_Implement(const char *filename);
struct stMapFile{
stMapFile(){hFile=NULL;hMapping=NULL;ImageBase=NULL;}
HANDLE hFile;
HANDLE hMapping;
LPVOID ImageBase;
};
struct IM_TABLE{
DWORD address;
std::string function;
};
bool LoadFile();
void UnLoadFile();
bool IsPEFile();
LPVOID GetImageBase();
PIMAGE_DOS_HEADER GetDosHeader_I();
PIMAGE_NT_HEADERS GetNtHeaders_I();
PIMAGE_OPTIONAL_HEADER GetOpHeader_I();
PIMAGE_FILE_HEADER GetFHeader_I();
PIMAGE_SECTION_HEADER GetSHeader_I();
LPVOID GetDataDirEx_I();
LPVOID GetDataDirIm_I();
IM_TABLE *GetImportTable();
private:
stMapFile MapFile;
char szFilePath[MAX_PATH];
IM_TABLE ImportTable[200];
};
而后定义一个user类,多重继承于上面两个类。
class USER:public PE_Implement,public PE_interface{
public:
USER(const char *FN=NULL);
~USER();
PIMAGE_DOS_HEADER GetDosHeader();
PIMAGE_NT_HEADERS GetNtHeaders();
PIMAGE_SECTION_HEADER GetSHeader();
void GetDataDir_Ex_Im(PIMAGE_IMPORT_DESCRIPTOR& pIm,PIMAGE_EXPORT_DIRECTORY& pEx);
private:
char FilePath[MAX_PATH];
};
这样就可以直接用PE_interface *p=new USER。来对调用功能函数,但是,被调用的函数只能是接口抽象类PE_interface里面声明了的函数。实现与接口分开,减少模块之间的依赖性。为了避免命名空间的泛滥,我都用的std::string形式限定命名空间。
USER类是功能的实现,界面显示是另外的一个类实现的。由于所有的显示都是控制台,所有,也就没有想把代码发出来,等图形化后,一定分享代码。
写的过程中出现的问题:(希望对其他写PE分析软件的朋友有所帮助)
1,获取PE信息,可以直接镜像到内存或者打开文件直接操作,但是,所以,需要对RVA,VA,OFFSET这些不同状态下的偏移地址清楚划分。一般情况下,.text,,.rdata,.data段之间SizeOfRawData文件对齐大小就是内存里面占用的空间大小,所以他们之间的内存偏移之差就是SizeOfRawData,但是,一定不要被这个误导了,这个只是巧合(很多时候有这个巧合),不是真正的意义所在,在计算的时候,不要利用这些巧合。
2,如果文件里面,指令占用了0x300个字节,但是对齐大小后是0x400字节,加载到内存后是0x1000个字节,在反汇编的时候,如何辨别。这个IDA做的相当的好,我也仅仅实现后两个之间的辨别,所以,也就不好意思多说了,大家仔细看看pe结构的分析吧。
3,获取输入表信息确实是比较复杂的问题,如果你全部自己写代码的话。个人觉得麻烦的主要是关于OriginalFirstThunk和FirstThunk以及他们指向的结构IMAGE_IMPORT_BY_NAME,
由于编译器不同,本来改指向一个IMAGE_THUNK_DATA结构体数组的OriginalFirstThunk可能被设为0,这是,只有通过查找输入函数的信息。但是如果FirstThunk指向的IMAGE_THUNK_DATA的最高进位是1,那么函数是序号引入的,就应该从低位提取序号。如果不为1,就是应该读取指向的IMAGE_IMPORT_BY_NAME结构体。为了兼容不同系统,需要对各种情况进行解析,我只做了解析,没有做解析后的处理(精力有限哈)
其他还有许多小问题,上网搜索就okay了。
[注意]APP应用上架合规检测服务,协助应用顺利上架!