0%

pe加载器

peloader加载器

1.创建数组来保存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
HANDLE X1(char* x, unsigned char** pbuf)
{
HANDLE X;
DWORD FileSize;
LPDWORD IFFileSize=0;
LPDWORD IFReadFile=0;
X = CreateFileA(x,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD err= GetLastError();
if (X == INVALID_HANDLE_VALUE)
{
printf("未能打开文件%d", err);
exit(0);
}
FileSize = GetFileSize(X, IFFileSize);
if (IFFileSize == -1)
{
printf("未能得到文件尺寸");
exit(0);
}
*pbuf =(unsigned char *)malloc(sizeof(unsigned char)* FileSize);
ZeroMemory(*pbuf, FileSize);//清零
ReadFile(X, *pbuf, FileSize, IFReadFile, NULL);
if (IFReadFile == -1)
{
printf("未能复制文件");
exit(0);
}
}

2.申请内存将DOS头NT头写入

1
2
3
4
5
6
7
8
9
10
PIMAGE_DOS_HEADER DOS = (PIMAGE_DOS_HEADER)pbuf;
PIMAGE_NT_HEADERS64 NT = (PIMAGE_NT_HEADERS64)(pbuf + DOS->e_lfanew);
DWORD SizeOfImage = NT->OptionalHeader.SizeOfImage;
LPVOID Alloc;
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
Alloc = VirtualAlloc(NULL, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
else
Alloc = VirtualAlloc(NT->OptionalHeader.ImageBase, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
ZeroMemory(Alloc, SizeOfImage);
CopyMemory(Alloc, pbuf, NT->OptionalHeader.SizeOfHeaders);//申请dos,nt空间

3.将节区循环写入申请内存

1
2
3
4
5
6
7
8
9
10
11
DWORD SectionNumber = NT->FileHeader.NumberOfSections;
for (DWORD n=0; n < SectionNumber; n++)//复制节区
{
PIMAGE_SECTION_HEADER SectionHead = (PIMAGE_SECTION_HEADER)((char*)NT+sizeof(IMAGE_NT_HEADERS64)+ sizeof(IMAGE_SECTION_HEADER)*n);
if (SectionHead->PointerToRawData!=0)//.bss节区(需要初始化)
CopyMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, pbuf + SectionHead->PointerToRawData, SectionHead->SizeOfRawData);
else
{
ZeroMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, SectionHead->Misc.VirtualSize);//清零
}
}

4.加载重定位表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
{
PIMAGE_BASE_RELOCATION ReLoc = (PIMAGE_BASE_RELOCATION)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (PCHAR)Alloc);
while (ReLoc->SizeOfBlock != 0)
{
PCHAR ReV = ReLoc->VirtualAddress + (PCHAR)Alloc;//每页的虚拟地址
int NumberOfBlock = (ReLoc->SizeOfBlock - 8) / 2;//每页有多少需要修改的值
for (int n = 0; n < NumberOfBlock; n++)
{
PWORD ChangByte = (PWORD)(ReLoc + 1);
char Type = ChangByte[n] >> 12;//获得标志位
if (Type == 10)
{
PDWORD64 Offest = (PDWORD64*)((ChangByte[n] & 0xfff) + ReV);//这页当中需要修改的具体位置
*Offest = *Offest + (ULONGLONG)Alloc - NT->OptionalHeader.ImageBase;//加上基址
}
}
ReLoc = (PIMAGE_SECTION_HEADER)((PCHAR)ReLoc + ReLoc->SizeOfBlock);//下一页
}
}

相关加载重定位表的理解可以看这篇文章:https://blog.csdn.net/Apollon_krj/article/details/77370452

5.填充IAT表

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
PIMAGE_IMPORT_DESCRIPTOR IntImport = (PIMAGE_IMPORT_DESCRIPTOR)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (PCHAR)Alloc);
while (IntImport->Name!=0)//循环dll库
{
HMODULE DllHandle;
char DllName[50];
strncpy(DllName,IntImport->Name+(PCHAR)Alloc,49);
DllHandle = LoadLibraryA(DllName);
PIMAGE_THUNK_DATA64 INT = IntImport->OriginalFirstThunk + (PCHAR)Alloc;
PIMAGE_THUNK_DATA64 IAT = IntImport->FirstThunk + (PCHAR)Alloc;
while (INT->u1.AddressOfData != 0)//循环dll中每个函数
{
if (INT->u1.Ordinal & IMAGE_ORDINAL_FLAG64)//通过序号查找函数
{
IAT->u1.AddressOfData = GetProcAddress(DllHandle, INT->u1.Ordinal);
}
else//通过名字查找函数
{
PIMAGE_IMPORT_BY_NAME Fcn = (PIMAGE_IMPORT_BY_NAME)(INT->u1.AddressOfData + (PCHAR)Alloc);
IAT->u1.AddressOfData = GetProcAddress(DllHandle, Fcn->Name);//填充IAT表
int l = 1;
}
INT++;
IAT++;
}
IntImport++;
}

相关填充IAT表的理解可以看这篇文章:https://blog.csdn.net/qq_35289660/article/details/107329444

6.修改程序入口

1
2
3
4
5
6
FARPROC EOP = (FARPROC)((LPBYTE)Alloc + NT->OptionalHeader.AddressOfEntryPoint);//修改程序入口点
EOP();

free(pbuf);
free(Alloc);
return 0;

汇总

peloader的加载原理就是将pe文件的内容读取后根据当中的VirtualAddress将内容分配到申请空间里,然后执行。(下面是所有代码)

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include <stdbool.h>
#include<winnt.h>

HANDLE X1(char* x, unsigned char** pbuf)
{
HANDLE X;
DWORD FileSize;
LPDWORD IFFileSize=0;
LPDWORD IFReadFile=0;
X = CreateFileA(x,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD err= GetLastError();
if (X == INVALID_HANDLE_VALUE)
{
printf("未能打开文件%d", err);
exit(0);
}
FileSize = GetFileSize(X, IFFileSize);
if (IFFileSize == -1)
{
printf("未能得到文件尺寸");
exit(0);
}
*pbuf =(unsigned char *)malloc(sizeof(unsigned char)* FileSize);
ZeroMemory(*pbuf, FileSize);
ReadFile(X, *pbuf, FileSize, IFReadFile, NULL);
if (IFReadFile == -1)
{
printf("未能复制文件");
exit(0);
}
}
VOID MAIN1(unsigned char* pbuf) {
printf("这是个64进制文件\n");
Sleep(500);
PIMAGE_DOS_HEADER DOS = (PIMAGE_DOS_HEADER)pbuf;
PIMAGE_NT_HEADERS64 NT = (PIMAGE_NT_HEADERS64)(pbuf + DOS->e_lfanew);
DWORD SizeOfImage = NT->OptionalHeader.SizeOfImage;
LPVOID Alloc;
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
Alloc = VirtualAlloc(NULL, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
else
Alloc = VirtualAlloc(NT->OptionalHeader.ImageBase, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
ZeroMemory(Alloc, SizeOfImage);
CopyMemory(Alloc, pbuf, NT->OptionalHeader.SizeOfHeaders);//申请dos,nt空间
DWORD SectionNumber = NT->FileHeader.NumberOfSections;
for (DWORD n=0; n < SectionNumber; n++)//复制节区
{
PIMAGE_SECTION_HEADER SectionHead = (PIMAGE_SECTION_HEADER)((char*)NT+sizeof(IMAGE_NT_HEADERS64)+ sizeof(IMAGE_SECTION_HEADER)*n);
if (SectionHead->PointerToRawData!=0)//.bss特殊
CopyMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, pbuf + SectionHead->PointerToRawData, SectionHead->SizeOfRawData);
else//.bss特殊
{
ZeroMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, SectionHead->Misc.VirtualSize);
}
}
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
{
PIMAGE_BASE_RELOCATION ReLoc = (PIMAGE_BASE_RELOCATION)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (PCHAR)Alloc);
while (ReLoc->SizeOfBlock != 0)
{
PCHAR ReV = ReLoc->VirtualAddress + (PCHAR)Alloc;
int NumberOfBlock = (ReLoc->SizeOfBlock - 8) / 2;
for (int n = 0; n < NumberOfBlock; n++)
{
PWORD ChangByte = (PWORD)(ReLoc + 1);
char Type = ChangByte[n] >> 12;
//PDWORD64 Offest = 0;
if (Type == 10)
{
// 找到目标地址
// 修改目标地址的值:方法是原来的值+偏移
PDWORD64 Offest = (PDWORD64*)((ChangByte[n] & 0xfff) + ReV);
*Offest = *Offest + (ULONGLONG)Alloc - NT->OptionalHeader.ImageBase;
}
}
ReLoc = (PIMAGE_SECTION_HEADER)((PCHAR)ReLoc + ReLoc->SizeOfBlock);
}
}
PIMAGE_IMPORT_DESCRIPTOR IntImport = (PIMAGE_IMPORT_DESCRIPTOR)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (PCHAR)Alloc);
while (IntImport->Name!=0)//引入表
{
HMODULE DllHandle;
char DllName[50];
strncpy(DllName,IntImport->Name+(PCHAR)Alloc,49);
DllHandle = LoadLibraryA(DllName);
PIMAGE_THUNK_DATA64 INT = IntImport->OriginalFirstThunk + (PCHAR)Alloc;
PIMAGE_THUNK_DATA64 IAT = IntImport->FirstThunk + (PCHAR)Alloc;
while (INT->u1.AddressOfData != 0)
{
if (INT->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
{
IAT->u1.AddressOfData = GetProcAddress(DllHandle, INT->u1.Ordinal);
}
else
{
PIMAGE_IMPORT_BY_NAME Fcn = (PIMAGE_IMPORT_BY_NAME)(INT->u1.AddressOfData + (PCHAR)Alloc);
IAT->u1.AddressOfData = GetProcAddress(DllHandle, Fcn->Name);
int l = 1;
}
INT++;
IAT++;
}
IntImport++;
}
FARPROC EOP = (FARPROC)((LPBYTE)Alloc + NT->OptionalHeader.AddressOfEntryPoint);
EOP();

free(pbuf);
free(Alloc);
return 0;
}//64文件处理
int main(int argc,char* argv[])
{
unsigned char* pbuf=NULL;
X1(argv[1],&pbuf);
PIMAGE_DOS_HEADER DOS = (PIMAGE_DOS_HEADER)pbuf;
if (*(PWORD)pbuf == 0x5A4D)
printf("这是个PE文件\n");
WORD Magic = *(WORD*)(pbuf + (DOS->e_lfanew + 6 * 4));
if (Magic == 0x20b)
MAIN1(pbuf);
}