avatar

滴水逆向

6.25 ( 文件读写练习 )

  1. 用十六进制文本编辑器,打开一个记事本的.exe文件,再打开在内存中的记事本 进程,记录下这两个文件的不同.
  2. 将记事本的.exe文件读取到内存,并返回读取后在内存中的地址.
  3. 将内存中的数据存储到一个文件中,(.exe格式),然后双击打开,看是否能够使用.
  • 打开文件
  • 得到文件的大小
  • 申请内存
  • 把文件中的内容读取到内存中
  • 返回内存编号

1

image-20200625165111259

这个问题在之前研究过,在硬盘上我们是根据0x200进行对齐,而在内存中会根据0x1000进行对齐,那么中间的剩余部分用0进行补全说明我们硬盘上的数据会在内存中进行拉伸,我们的offset文件偏移也不同(大概后面PE会有个详细的说明)

2 and 3

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
/*
将记事本的.exe文件读取到内存,并返回读取后在内存中的地址.
将内存中的数据存储到一个文件中,(.exe格式),然后双击打开,看是否能够使用.
- 打开文件
- 得到文件的大小
- 申请内存
- 把文件中的内容读取到内存中
- 返回内存编号
*/
//fopen
//fclose
//ftell
//fseek
//fread
int open() {
int size = 0;
FILE* pa = NULL;
pa = fopen("C:\\Windows\\System32\\notepad.exe", "rb" );
FILE* pb = NULL;
pb = fopen("D:\\1.txt", "wb");
if (pa == NULL || pb == NULL) {
printf("文件打开失败\n");
return 0;
}
fseek(pa, 0, SEEK_END); //定义到文件末尾
size = ftell(pa);//文件大小
printf("文件大小 : %d", size);
char* A;
A = (char*)malloc(size);//分配文件大小的堆空间
if (A == NULL) {
return 0;
}
int b;
memset(A, 0, size);//初始化为0
fseek(pa, 0, SEEK_SET);//定义到文件首部
fread(A, 1, size, pa); //数据存储到A
fwrite(A, 1, size, pb);
fclose(pa);
fclose(pb);
free(A);
A == NULL;
return 0;
}
int main() {
open();
return 0;
}

大概了解到了fopen的用法 b是二进制打开,fseek将指针定位到哪个位置,SEEK_END是末尾,SEEK_SET是开头,fwrite将数组内容写在另一个文件中,fread读取流,将一个文件的内容读取到另一个位置,fclose关闭文件

6.26 (PE头解析,手动)

拖了个扫雷进去开始一个一个对

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
DOS头:
//64字节
word E_magic; * 5A 4D //MZ标记:用来标记是否为可执行文件
word e_cblp; 00 90
word e_cp; 00 03
word e_crlc; 00 00
word e_cparhdr; 00 04
word e_minalloc; 00 00
word e_maxalloc; FF FF
word e__ss; 00 00
word e_sp; 00 B8
word e_csum; 00 00
word e——IP; 00 00
word e_cs; 00 00
word e_ifarlc; 00 40
word e_ovno; 00 00
word e_res[4]; 00 00 00 00 00 00 00 00
word e_oemid; 00 00
word e_oeminfo; 00 00
word e_res2[10]; 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dword e_ifanew; * 00 00 00 D8 //定位PE文件,PE头相对于文件的偏移量

NT头
{
1.DWORD Signature; 00 00 45 50 //标记,判断是否为PE文件的第二个标志
2.FILE_HEADER (文件头-PE的基本信息)
//20字节
word MACHINE; * 01 4C //文件的运行平台
word NumberOfSections;* 00 03 //区段的数量
Dword TimeDateStamp;* 3B 7D 84 75 //文件创建的时间
Dword PointerToSymbolTable; 00 00 00 00
Dword NumberOfSymbols; 00 00 00 00
word SizeofOptionalHeader;* 00 E0 //扩展头的大小
word Characteristics;* 01 0F //PE文件的一些属性



3.OPTIONAL_HEADER (扩展头-PE文件加载的信息)
//
word MAGIC;* 01 0B //文件类型标志,32位一般是0x010b,64位的一般时0x020B
byte MajorLinkerVersion; 07
byte MinorLinkerVersion; 00
2字节
Dword SizeOfCode;* 00 00 3C 00 //代码区段总大小
Dword SizeOfInitializedData;* 00 01 94 00 //已经初始化数据总大小
Dword SizeOfUninitializedData;* 00 00 00 00 //未初始化数据的总大小
Dword AddressOfEntryPoint;* 00 00 3E 21 //程序开始执行的相对虚拟地址(RVA),也叫OEP,源入口
Dword BaseOfCode;* 00 00 10 00 //起始代码的相对虚拟地址
Dword BaseOfData;* 00 00 50 00 //起始数据的相对虚拟地址
Dword ImageBase;* 01 00 00 00 // 默认加载地址
Dword Section Alignment;* 00 00 10 00 //块对齐数 0x1000
Dword File Alignment;* 00 00 02 00 //文件对齐数 0x200
word MajorOperatingSystemVersion; 00 05
word MinorOperatingSystemVersion; 00 01
word MajorImageVersion; 00 05
word MinirImageVersion; 00 01
word MajorSubsystemVersion; 00 04
word MinirSubsystemVersiion; 00 00
Dword Win32Version Value; 00 00 00 00
16字节
Dword SizeofImage;* 00 02 00 00 //文件加载进内存,所需要的内存大小
Dword SizeofHeaders;* 00 00 04 00 //所有头部大小,Dos头,PE头,区段表的尺寸之和
Dword CheckSum;* 00 02 73 C4 //校验和
word Subsystem; 00 02
word DllCharacteristics; 80 00
4字节
Dword SizeOfStackReserve;* 00 04 00 00 //初始栈大小
Dword SizeOfStackCommit;* 00 00 40 00 //初始化时实际提交栈的大小
Dword SizeOfHeapReserve;* 00 10 00 00 //初始化时保留堆的大小
Dword SizeOfHeapCommit;* 00 00 10 00 //初始化时实际提交的堆的大小
Dword LoaderFlags; 00 00 00 00
Dword NumberOfRvaAndSizes; 00 00 00 10
...[16]

6.27 (PE头字段说明)

1、编写程序读取一个.exe文件,输出所有的PE头信息.

2、使用第三方的PE工具,对比如下信息,看是否一致:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<windows.h>
#pragma warning(disable : 4996)
/*编写程序读取一个.exe文件,输出所有的PE头信息*/
/*获取的是扫雷exe,PE头信息

*/
int PE() {
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOPtionHeader = NULL;
int A = 0;
FILE* pa = NULL; //文件指针
pa = fopen("C:\\Users\\28611\\Desktop\\桌面的文件\\初赛.ring3\\winmine.exe", "rb");
if (pa == NULL) {
printf("文件打开失败");
return 0;
}
fseek(pa, 0, SEEK_END);
A = ftell(pa);
char* pb; //堆指针
pb = (char*)malloc(A);
if (pb == NULL) {
printf("堆空间分配失败");
return 0;
}
memset(pb, 0, A);
fseek(pa, 0, SEEK_SET);
fread(pb, A, 1, pa);
fclose(pa);
pa = NULL;
//文件的二进制已经传到了堆空间中
if (*(short*)pb != IMAGE_DOS_SIGNATURE) {
printf("MZ标识失败");
free(pb);
pb = NULL;
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pb;
printf("DOS头: \n");
printf("E_magic: %x\n", pDosHeader->e_magic);
printf("E_lfanew: %x\n", pDosHeader->e_lfanew);
if (*(int*)(pb + (pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) {
printf("PE标识失败");
free(pb);
pb = NULL;
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)(pb + pDosHeader->e_lfanew);
printf("NT头: \n");
printf("Signature: %x\n", pNTHeader->Signature);
printf("标准PE头: \n");
pFileHeader = (PIMAGE_FILE_HEADER)(pb + pDosHeader->e_lfanew + 4);
printf("Machine: %x\n", pFileHeader->Machine);
printf("NumberOfSections: %x\n", pFileHeader->NumberOfSections);
printf("TimeDateStamp: %x\n", pFileHeader->TimeDateStamp);
printf("SizeOfOptionalheader: %x\n", pFileHeader->SizeOfOptionalHeader);
printf("Characteristics: %x\n", pFileHeader->Characteristics);
printf("扩展PE头: \n");
pOPtionHeader = (PIMAGE_OPTIONAL_HEADER32)(pb + pDosHeader->e_lfanew + 24);
printf("Magic: %x\n", pOPtionHeader->Magic);
printf("SizeOfCode: %x\n", pOPtionHeader->SizeOfCode);
printf("SizeOfInitializedData: %x\n", pOPtionHeader->SizeOfInitializedData);
printf("SizeOfUninitializedData: %x\n", pOPtionHeader->SizeOfUninitializedData);
printf("AddressOfEntryPoint: %x\n", pOPtionHeader->AddressOfEntryPoint);
printf("BaseOfCode: %x\n", pOPtionHeader->BaseOfCode);
printf("BaseOfData: %x\n", pOPtionHeader->BaseOfData);
printf("ImageBase: %x\n", pOPtionHeader->ImageBase);
printf("SectionAlignment: %x\n", pOPtionHeader->SectionAlignment);
printf("FileAlignment: %x\n", pOPtionHeader->FileAlignment);
printf("SizeOfImage: %x\n", pOPtionHeader->SizeOfImage);
printf("SizeOfHeaders: %x\n", pOPtionHeader->SizeOfHeaders);
printf("CheckSum: %x\n", pOPtionHeader->CheckSum);
printf("SizeOfStackReserve: %x\n", pOPtionHeader->SizeOfStackReserve);
printf("SizeOfStackCommit: %x\n", pOPtionHeader->SizeOfStackCommit);
printf("SizeOfHeapReserve: %x\n", pOPtionHeader->SizeOfHeapReserve);
printf("SizeOfHeapCommit: %x\n", pOPtionHeader->SizeOfHeapCommit);
free(pb);
pb = NULL;
}
int main() {
PE();
return 0;
}

image-20200627214520403

image-20200627214547470

Author: L0x1c
Link: https://l0x1c.github.io/2020/06/25/2020-6-26/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶