PE头

DOS头

64个字节

image-20201214163418890

DOS-stub

image-20201214163457931

PE头

Signature

image-20201214163935399

FileHeader字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct _IMAGE_FILE_HEADER {

WORD Machine;//运行平台

WORD NumberOfSections;//文件的区块数目

DWORD TimeDateStamp;//文件创建的用时间戳标识的日期

DWORD PointerToSymbolTable;//指向符号表(用于调试)

DWORD NumberOfSymbols;//符号表中符号的个数

WORD SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32结构大小

WORD Characteristics;//文件属性

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

image-20201214164334091

OptionalHeader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
typedef struct _IMAGE_OPTIONAL_HEADER {  
WORD Magic; //标志字
BYTE MajorLinkerVersion; //链接器主版本号
BYTE MinorLinkerVersion; //链接器次版本号
DWORD SizeOfCode; //所有含有代码表的总大小
DWORD SizeOfInitializedData; //所有初始化数据表总大小
DWORD SizeOfUninitializedData; //所有未初始化数据表总大小
DWORD AddressOfEntryPoint; //程序执行入口RVA
DWORD BaseOfCode; //代码表其实RVA
DWORD BaseOfData; //数据表其实RVA
DWORD ImageBase; //程序默认装入基地址
DWORD SectionAlignment; //内存中表的对齐值
DWORD FileAlignment; //文件中表的对齐值
WORD MajorOperatingSystemVersion; //操作系统主版本号
WORD MinorOperatingSystemVersion; //操作系统次版本号
WORD MajorImageVersion; //用户自定义主版本号
WORD MinorImageVersion; //用户自定义次版本号
WORD MajorSubsystemVersion; //所需要子系统主版本号
WORD MinorSubsystemVersion; //所需要子系统次版本号
DWORD Win32VersionValue; //保留,通常设置为0
DWORD SizeOfImage; //映像装入内存后的总大小
DWORD SizeOfHeaders; //DOS头、PE头、区块表总大小
DWORD CheckSum; //映像校验和
WORD Subsystem; //文件子系统
WORD DllCharacteristics; //显示DLL特性的旗标
DWORD SizeOfStackReserve; //初始化堆栈大小
DWORD SizeOfStackCommit; //初始化实际提交堆栈大小
DWORD SizeOfHeapReserve; //初始化保留堆栈大小
DWORD SizeOfHeapCommit; //初始化实际保留堆栈大小
DWORD LoaderFlags; //与调试相关,默认值为0
DWORD NumberOfRvaAndSizes; //数据目录表的项数
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

image-20201214165709676

image-20201214164731994

节表

image-20201214170528006

调试

image-20201214185832377

找到程序入口点

image-20201214185939046

经过动调,发现在执行了005A17D5这条函数调用之后就弹出了notepad,所以我们在这里下断点,步入调用继续调试

image-20201214190837123

继续按照弹出程序与否继续调试,发现执行了0058D224之后弹出了程序,于是步入调试

image-20201214190956748

进入了窗口参数设置的代码,RegisterWindowMessageW函数定义一个新的窗口消息

image-20201214191234362

这里调用了CreatWindowExW函数创建一个窗口

image-20201214191534676

接下来的代码继续对窗口和进程的参数继续设置

image-20201214191625675

最后,在执行了ShowWindow函数调用之后,窗口弹出。

image-20201214192336512

这里获取了桌面进程,并且获取了当前线程的线程ID

程序执行结束

修改notepad.exe

image-20201215111618328

image-20201215111640753

image-20201215112658198

image-20201215112729136

找到系统SYSTEM32目录下的user32.dll文件,用UltraEdit打开并分析该文件导出表,找出 MessageBoxA的地址,并验证该地址是否正确。

用PEview打开user32.dll

image-20201221162949895

Name:保存了dll的名称

AddressOfFunctions:保存了所有导出函数的地址RVA

AddressOfNames:保存了所有按名称导出的函数的名称RVA

AddressOfNameOrdinals:保存了所有按名称导出的函数的序号

当我们要在导出表中查找某一个函数时,我们要先遍历AddressOfNames查找函数名称,记录当下的索引0。之后将索引0作为AddressOfNameOrdinals的索引值查找值,获得索引1,再将索引1作为AddressOfFunctions的索引找到函数地址的RVA

我们首先在AddressOfNames里面找到MessageBoxA

image-20201221163309974

image-20201221170208459

然后0x0864-0x05E0得到0x0284,即为AddressOfNames数组索引值

然后在AddressOfNameOrdinals中查找序号值,找第0x0284个表项

image-20201221170433781

MessageBoxA的序号为0x0286,然后在AddressOfFunctions中找到函数地址0x06C1C0即RVA

image-20201221171237971

然后加载user32.dll获得基址,基址为75B50000,加上RVA,等于75BBC1C0

image-20201221173014838

验证一下,结果正确

image-20201221172246224