通用ShellCode深入剖析(3)

发布时间:2021-06-05

什么吧!
e_lfanew就是一个文件偏移值,它指向PE header,它对我们来说非常重要.紧跟着DOS MZ header的是DOS stub它是linker为我们建立的这个16位DOS程序的代码实体部分,就是它输出了"This program cannot be run in DOS mode.".再后面就是PE header了,有人曾问过我PE头部相对于.exe文件的偏移是不是固定的?这个可不好说,不同的编译器生成的stub长度可能不一样(比如:它可能存储了这样一个字串来提示用户"The Currnet OS is not Win32,I want to run in Win32 Mode.",那么这个stub的长度将比前面的那个长),所以用一个固定值来定位PE header是不科学的,这个时候我们就用到了e_lfanew,它指向真正的PE header,它总是正确吗?那是当然的!linker总是会它赋予一个正确的值.所以我们要它精确定位PE header,同样的Win32 PELoader也根据e_lfanew来定位真正的PE header,并使用PE header中的不同的成员值进行初使化,PE还包涵了很多个"节"(Section),有用来存储数据的,有用来存可执行代码的,还有的是用来存资源的(如:程序图标,位图,声音,对话框模板等)
下面我只简单分析一下PE结构与编写ShellCode相关的部分,如果你对其它部分也比较感兴趣可以看看台港侯俊杰先生译的<Windows 95系统程序设计大奥秘>中的相关内容以及Iczelion的经典PE教程,我个人觉得将两者结合起来看要好一点.

2,引出表分析

在PE header结构(你可以Winnt.h中找到它)中包括一个DataDirectory结构成员数组,可以通过这样的方法来找到它的位置:
PE头部偏移=可执行文件内存映象基址+0x3c(e_lfanew)
PE基址=可执行文件内存映象基址+PE头部偏移
引出表目录指针(IMAGE_EXPORT_DIRECTORY*)=PE基址+0x78<=---DataDirectory
引出函数名称表首指针(char**)=引出表目录基址+0x20
引出函数地址表首指针(DWORD **)=引出表目录指针+0x1c它的结构定义是这样的:

typedef struct _Image_Data_Directory{
DWORD VirtualAddress;
DWORD isize;
}IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;

该结构数组共包括16成员,第一个成员的VirtualAddress存储了一个相对偏移量,它指向一个IMAGE_EXPORT_DIRECTORY结构,它的定义是这样的:

typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;//0x00
DWORD TimeDateStamp;//0x04
WORD MajorVersion;//0x08
WORD MinorVersion;//0x0a
DWORD Name;//0x0c
DWORD Base;//0x10
DWORD NumberOfFunctions;//0x14
DWORD NumberOfNames;//0x18
DWORD AddressOfFunctions;//0x1c RVA from base of image
DWORD AddressOfNames;//0x20 RVA from base of image
DWORD AddressOfNameOrdinals;//0x2
4 RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

其中AddressOfFunctions里又存储了一个二级指针,它指向一个DWORD型指针数组该数组成员所指就是函数地址值,但

精彩图片

热门精选

大家正在看