目录
//将文件读入FileBuffer函数 To_FileBuffer
//函数名查找函数 GetFunctionAddrByName
//函数序号查找函数 GetFunctionAddrByOrdinals
//计算文件在硬盘上的大小 computer_buffersize
//imagebuffer存盘到电脑硬盘上 Save_to_disk
//向第一个节注入代码 add_shellcode_to_first_section
//向任意节注入代码 add_shellcode_to_specific_section
//在imagebuffer中新增一个节add_a_section_in_imagebuffer
//在filebuffer中新增一个节add_a_section_in_filebuffer
//添加shellcode到新增的地方 add_shellcode_to_expanded_section
//定义函数,能够返回对齐后的大小 aligement_size
#define _CRT_SECURE_NO_DEPRECATE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned char BYTE;
#define IMAGE_SIZEOF_SHORT_NAME 8
#define MessageBox 0x76250D80
BYTE shellcode[] = { 0x6A,02,0x6A,00, 0x6A,00, 0x6A,00,
0xE8,00,00,00,00,
0xE9,00,00,00,00 };
//DOS头
struct _IMAGE_DOS_HEADER {
WORD e_magic; //MZ标记
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
DWORD e_lfanew; //PE文件真正开始的偏移地址
};
//标准PE头
struct _IMAGE_FILE_HEADER {
WORD Machine; //文件运行平台
WORD NumberOfSections; //节数量
DWORD TimeDateStamp; //时间戳
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader; //可选PE头大小
WORD Characteristics; //特征值
};
//数据目录
struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; //内存偏移,必须有
DWORD Size; //大小,破坏了也不会影响程序运行
};
//可选PE头
struct _IMAGE_OPTIONAL_HEADER {
WORD Magic; //文件类型
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode; //代码节文件对齐后的大小
DWORD SizeOfInitializedData; //初始化数据文件对齐后的大小
DWORD SizeOfUninitializedData; //未初始化数据文件对齐后大小
DWORD AddressOfEntryPoint; //程序入口点(偏移量)
DWORD BaseOfCode; //代码基址
DWORD BaseOfData; //数据基址
DWORD ImageBase; //内存镜像基址
DWORD SectionAlignment; //内存对齐粒度
DWORD FileAlignment; //文件对齐粒度
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage; //文件装入虚拟内存后大小
DWORD SizeOfHeaders; //DOS、NT头和节表大小
DWORD CheckSum; //校验和
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve; //预留堆栈大小
DWORD SizeOfStackCommit; //实际分配堆栈大小
DWORD SizeOfHeapReserve; //预留堆大小
DWORD SizeOfHeapCommit; //实际分配堆大小
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes; //目录项数目
_IMAGE_DATA_DIRECTORY DataDirectory[16]; //这个先不管
};
//NT头
struct _IMAGE_NT_HEADERS {
DWORD Signature; //PE签名
_IMAGE_FILE_HEADER FileHeader;
_IMAGE_OPTIONAL_HEADER OptionalHeader;
};
//节表
struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //节表名
union {
DWORD PhysicalAddress;
DWORD VirtualSize; //内存中未对齐大小
}Misc;
DWORD VirtualAddress; //该节在内存中偏移地址
DWORD SizeOfRawData; //该节在硬盘上文件对齐后大小
DWORD PointerToRawData; //该节在硬盘上文件对齐后偏移地址
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics; //该节特征属性
};
//导出表
struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; //未使用
DWORD TimeDateStamp; //时间戳
WORD MajorVersion; //未使用
WORD MinorVersion; //未使用
DWORD Name; //指向该导出表文件名字符串 *
DWORD Base; //导出函数起始序号 *
DWORD NumberOfFunctions; //所有导出函数的个数 *
DWORD NumberOfNames; //以函数名字导出的函数个数 *
DWORD AddressOfFunctions; //导出函数地址表RVA *
DWORD AddressOfNames; //导出函数名称表RVA *
DWORD AddressOfNameOrdinals; //导出函数序号表RVA *
};
//重定位表
struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
//具体项
};
//导入表
struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk; //RVA,指向IMAGE_THUNK_DATA结构数组(INT表)
};
DWORD TimeDateStamp; //时间戳 (用于判断是否有绑定导入表/IAT表中是否已经绑定绝对地址)
DWORD ForwarderChain;
DWORD Name; //RVA,指向dll名字字符串存储地址
DWORD FirstThunk; //RVA,指向IMAGE_THUNK_DATA结构数组(IAT表)
};
struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //可能为空(编译器决定);如果不为空,表示函数在导出表中的索引
BYTE Name[1]; //函数名称,以0结尾
};
struct _IMAGE_THUNK_DATA32
{
union
{
BYTE ForwarderString;
DWORD Function;
DWORD Ordinal; //序号。最高位为1,代表以序号导出,为0则以名称导出
_IMAGE_IMPORT_BY_NAME* AddressOfData; //RVA,指向IMAGE_IMPORT_BY_NAME
};
};
//将文件读入FileBuffer函数
char* To_FileBuffer(char* FilePath)
{
FILE* fp = fopen(FilePath, "rb");
//printf("fp %p",fp);
if (fp == NULL)
{
printf("open the file error");
exit(0);
}
fseek(fp, 0, 2);
DWORD size = ftell(fp);
fseek(fp, 0, 0);
char* mp = (char*)malloc(sizeof(char) * size);
if (mp == NULL)
{
printf("malloc error");
fclose(fp);//失败了就关闭打开的文件
exit(0);
}
int succeed = fread(mp, size, 1, fp);//fread的返回值是读取成功的数字。
if (succeed == 0)
{
printf("file read to filebuffer error");
fclose(fp);
free(mp);
exit(0);
}
fclose(fp);
return mp;
}
//打印各种头
void PE_header_print(char* FilePath)
{
char* filebuffer = To_FileBuffer(FilePath);
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
printf("-------DOS--头\n");
printf("e_magic:%X\n", dos_header->e_magic);
printf("e_lfanew:%X\n", dos_header->e_lfanew);
printf("-------NT--头\n");
printf("Signature:%X\n", nt_header->Signature);
printf("-------file--头\n");
printf("NumberOfSections:%X\n", file_header->NumberOfSections);
printf("SizeOfOptionalHeader:%X\n", file_header->SizeOfOptionalHeader);
printf("-------optional--头\n");
printf("FileAlignment:%X\n", optional_header->FileAlignment);
printf("AddressOfEntryPoint:%X\n", optional_header->AddressOfEntryPoint);
printf("Magic:%X\n", optional_header->Magic);
printf("ImageBase:%X\n", optional_header->ImageBase);
printf("SizeOfImage:%X\n", optional_header->SizeOfImage);
_IMAGE_DATA_DIRECTORY* data_directory = optional_header->DataDirectory;//目录项地址
printf("data_directory:%p\n", data_directory);
printf("optional_header->NumberOfRvaAndSizes:%X\n", optional_header->NumberOfRvaAndSizes);
char* arr[16] = { (char*)"IMAGE_DIRECTORY_ENTRY_EXPORT(导出表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_IMPORT(导入表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_RESOURCE(资源表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_EXCEPTION(异常信息表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_SECURITY(安全证书表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_BASERELOC(重定位表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_DEBUG(调试信息表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_COPYRIGHT(版权所有表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_GLOBALPTR(全局指针表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_TLS(TLS表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(加载配置表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(绑定导入表)",
(char*)"IMAGE_DIRECTORY_ENTRY_IAT(IAT表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT(延迟导入表)",
(char*)"IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR(COM信息表)",
(char*)"保留 "
};
for (DWORD i = 0; i < optional_header->NumberOfRvaAndSizes; i++)
{
printf("%s VirtualAddress:%08X Size:%08X\n", arr[i], data_directory->VirtualAddress, data_directory->Size);
data_directory++;
}
}
//目录项打印
void data_dictory_print(char* filepath)
{
char* filebuffer = To_FileBuffer(filepath);
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
data_directory = (_IMAGE_DATA_DIRECTORY*)optional_header->DataDirectory;//目录项首地址
char* arr[16] = { (char*)"IMAGE_DIRECTORY_ENTRY_EXPORT(导出表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_IMPORT(导入表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_RESOURCE(资源表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_EXCEPTION(异常信息表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_SECURITY(安全证书表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_BASERELOC(重定位表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_DEBUG(调试信息表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_COPYRIGHT(版权所有表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_GLOBALPTR(全局指针表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_TLS(TLS表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(加载配置表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(绑定导入表)",
(char*)"IMAGE_DIRECTORY_ENTRY_IAT(IAT表) ",
(char*)"IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT(延迟导入表)",
(char*)"IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR(COM信息表)",
(char*)"保留 "
};
for (DWORD i = 0; i < optional_header->NumberOfRvaAndSizes; i++)
{
printf("%s VirtualAddress:%08X Size:%08X\n", arr[i], data_directory->VirtualAddress, data_directory->Size);
data_directory++;
}
}
DWORD RVA_to_FOA(char* filebuffer, DWORD RVA)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//先判断address这个地址在那个节中。
bool flag = 0;
if (section_header->VirtualAddress > RVA)//说明addres在头里面;
return RVA;
for (int i = 0; i < file_header->NumberOfSections; i++)//判断address是否在空白区,如果是空白区,那么filebuffer里面就不会保存,就不存在转FOA了。
{
if (RVA >= section_header->VirtualAddress && RVA < section_header->VirtualAddress + section_header->Misc.VirtualSize)
{
flag = 1;
break;
}
else
section_header++;
}
if (flag == 0)
{
printf("地址不在文件中\n");
return 0;
}
DWORD RVA_offset_to_viturladdress = RVA - section_header->VirtualAddress;//这个vadd距离节起始位置的偏移
return section_header->PointerToRawData + RVA_offset_to_viturladdress;
}
DWORD FOA_to_RVA(char* filebuffer, DWORD FOA)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//先判断address这个地址在那个节中。
bool flag = 0;
if (FOA < section_header->PointerToRawData)//说明addres在头里面;
return FOA;
for (int i = 0; i < file_header->NumberOfSections; i++)//判断address是否在节中。在哪一个节中
{
DWORD tempSize = section_header->Misc.VirtualSize < section_header->SizeOfRawData ? section_header->Misc.VirtualSize : section_header->SizeOfRawData;//谁小返回谁(例子 a<b?a:b)。 谁大返回谁(a>b?a:b)
if (FOA >= section_header->PointerToRawData && FOA < section_header->PointerToRawData + tempSize)
{
flag = 1;
break;
}
else
section_header++;
}
if (flag == 0)
{
printf("FOA地址不在imagebuffer文件中\n");
return 0;
}
DWORD FOA_offset_to_pointrawdata = FOA - section_header->PointerToRawData;//这个FOA距离节起始位置的偏移
return section_header->VirtualAddress + FOA_offset_to_pointrawdata;
}
//导出表打印
void ExportTable_print(char* filepath)
{
char* filebuffer = To_FileBuffer(filepath);
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
_IMAGE_EXPORT_DIRECTORY* export_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
data_directory = (_IMAGE_DATA_DIRECTORY*)(optional_header->DataDirectory+0);//指向导出表的目录项地址:导出表为目录项的第0项,目录项指针+0为起始地址;
if (data_directory->VirtualAddress == 0)
{
printf("该PE没有导出表\n");
exit(0);
}
//因为是在filebuffer中,这里全部都是vitaladdress,需要转换为OFA;
export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(filebuffer, data_directory->VirtualAddress) + (DWORD)filebuffer);
printf("-----------导出表------------------\n");
char* name = (char*)(RVA_to_FOA(filebuffer, export_directory->Name) + (DWORD)filebuffer);//export_directory->Name指向的是name的字符串地址,必须要用一个指针接收后打印
printf("Base:%08X\n", export_directory->Base);
printf("NumberOfFunctions:%08X\n", export_directory->NumberOfFunctions);
printf("NumberOfNames:%08X\n", export_directory->NumberOfNames);
printf("AddressOfFunctions:%08X\n", export_directory->AddressOfFunctions);
printf("AddressOfNames:%08X\n", export_directory->AddressOfNames);
printf("AddressOfNameOrdinals:%08X\n", export_directory->AddressOfNameOrdinals);
printf("-----------函数地址表------------------\n");
DWORD* functions = (DWORD*)(RVA_to_FOA(filebuffer, export_directory->AddressOfFunctions) + (DWORD)filebuffer);
for (DWORD i = 0; i < export_directory->NumberOfFunctions; i++)
{
printf("函数地址%02d: %08X\n", i + 1, *(functions + i));
}
printf("-----------函数名称表------------------\n");
DWORD* names = (DWORD*)(RVA_to_FOA(filebuffer, export_directory->AddressOfNames) + (DWORD)filebuffer);//先获得导出表名称表的首地址
for (DWORD i = 0; i < export_directory->NumberOfNames; i++)
{
printf("函数名%02d: %08X %s\n", i + 1, *(names + i), (char*)(RVA_to_FOA(filebuffer, *(names + i)) + (DWORD)filebuffer));//将名称表所指向的函数地址转换为FOA地址后 输出。
}
printf("-----------函数序号表------------------\n");
WORD* AddressOfNameOrdinals = (WORD*)(RVA_to_FOA(filebuffer, export_directory->AddressOfNameOrdinals) + (DWORD)filebuffer);
for (DWORD i = 0; i < export_directory->NumberOfFunctions; i++)
{
printf("函数序号%02d: %08X\n", i + 1, *(AddressOfNameOrdinals + i));
}
}
//重定位表打印
void Relocation_print(char* filepath)
{
char* filebuffer = To_FileBuffer(filepath);
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
_IMAGE_BASE_RELOCATION* relocation_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
data_directory = (_IMAGE_DATA_DIRECTORY*)(optional_header->DataDirectory + 5);//指向目录项地址,重定位表为目录项的第6项,结构体指针只需要+5;
if (data_directory->VirtualAddress == 0)
{
printf("该PE没有重定位表\n");
exit(0);
}
_IMAGE_BASE_RELOCATION* relocation = (_IMAGE_BASE_RELOCATION*)(RVA_to_FOA(filebuffer, data_directory->VirtualAddress) + (DWORD)filebuffer);//指针指向重定位表
printf("-----------重定位表--------------\n");
for (int i = 0; relocation->VirtualAddress != 0; i++)
{
printf("第%d块 VirtualAaaress: %08X SizeOfBlock: %08X\n", i + 1, relocation->VirtualAddress, relocation->SizeOfBlock);
for (DWORD j = 0; j < (relocation->SizeOfBlock - 8) / 2; j++)
{
//高四位 //低12位
printf("索引:%03d 高4位:%02d 地址:%08X\n", j + 1, *((WORD*)((char*)relocation + 8 + j * 2)) >> 12, relocation->VirtualAddress + (*((WORD*)((char*)relocation + 8 + j * 2)) & 0X0FFF));
}
relocation = (_IMAGE_BASE_RELOCATION*)((char*)relocation + relocation->SizeOfBlock);
}
}
void Import_table_print(char* filebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
_IMAGE_BASE_RELOCATION* relocation_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
data_directory = (_IMAGE_DATA_DIRECTORY*)(optional_header->DataDirectory + 1);//指向目录项地址,导入表为目录项的第2项,结构体指针只需要+1;
if (data_directory->VirtualAddress == 0)
{
printf("该PE没有导入表\n");
exit(0);
}
_IMAGE_IMPORT_DESCRIPTOR* import_table=(_IMAGE_IMPORT_DESCRIPTOR*)(RVA_to_FOA(filebuffer,data_directory->VirtualAddress)+filebuffer);
while (1)
{
int i = 0;
for (i = 0; i < sizeof(*import_table); i++)
{
if (*((char*)import_table + i) != 0)
{
//printf("当前dll导入表结构不全为0\n");
break;
}
}
if (i == sizeof(*import_table))
{
printf("导入表结构内容全部为0,停止打印导入表\n");
break;
}
/*打印导出表*/
printf("********************导出表***********************\n");
printf("INT表的RVA:%08X\n", import_table->OriginalFirstThunk);
printf("IAT表的RVA:%08X\n", import_table->FirstThunk);
printf("TimeDateStamp:%08X\n", import_table->TimeDateStamp);
printf("Name的RVA:%08X\n", import_table->Name);
printf("ForwarderChain:%08X\n", import_table->ForwarderChain);
/*打印INT表*/
printf("********************INT表***********************\n");
if (import_table->OriginalFirstThunk != 0)
{
_IMAGE_THUNK_DATA32* INT_table = (_IMAGE_THUNK_DATA32*)(RVA_to_FOA(filebuffer, import_table->OriginalFirstThunk) + filebuffer);
while (INT_table->Ordinal != 0)
{
if ((INT_table->Ordinal & 0x80000000) == 0x80000000)//表示这个值最高位为1,以序号导出
{
printf("(以序号导出)%d\n", INT_table->Ordinal & 0x7FFFFFFF);
}
else
{
_IMAGE_IMPORT_BY_NAME* names = (_IMAGE_IMPORT_BY_NAME*)(RVA_to_FOA(filebuffer, INT_table->Ordinal) + filebuffer);
printf("(以名字导出)Hint--> %X %s\n", names->Hint,names->Name);
}
INT_table++;
}
}
else
{
printf("此dll无INT表\n");
}
/*打印IAT表*/
printf("********************IAT表***********************\n");
_IMAGE_THUNK_DATA32* IAT_table = (_IMAGE_THUNK_DATA32*)(RVA_to_FOA(filebuffer, import_table->FirstThunk) + filebuffer);
while (IAT_table->Ordinal != 0)
{
if ((IAT_table->Ordinal & 0x80000000) == 0x80000000)//表示这个值最高位为1,以序号导出
{
printf("(以序号导出)%d\n", IAT_table->Ordinal & 0x7FFFFFFF);
}
else
{
_IMAGE_IMPORT_BY_NAME* names = (_IMAGE_IMPORT_BY_NAME*)(RVA_to_FOA(filebuffer, IAT_table->Ordinal) + filebuffer);
printf("(以名字导出)Hint--> %X %s\n", names->Hint, names->Name);//错误, 分别是2个字节的。
}
IAT_table++;
}
import_table++;
}
}
DWORD GetFunctionAddrByName(char* filebuffer, char* funcName)
{
_IMAGE_DOS_HEADER* _image_dos_header = NULL;
_IMAGE_FILE_HEADER* _image_file_header = NULL;
_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
_IMAGE_EXPORT_DIRECTORY* _image_export_directory = NULL;
_image_dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
_image_file_header = (_IMAGE_FILE_HEADER*)(filebuffer + _image_dos_header->e_lfanew + 4);
_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
_image_data_directory = (_IMAGE_DATA_DIRECTORY*)_image_optional_header->DataDirectory;
if (_image_data_directory->VirtualAddress == 0) {
printf("此PE文件没有导出表,没有函数导出");
exit(0);
}
//1.先获取导出表指针????????????????????????目录项指向的vitualaddreess 就是导出表指针开始的位置
_image_export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(filebuffer, _image_data_directory->VirtualAddress) + (DWORD)filebuffer);
//2.在获取导出表->函数名表 指针
DWORD* add_of_functionsnames = (DWORD*)(RVA_to_FOA(filebuffer, _image_export_directory->AddressOfNames) + (DWORD)filebuffer);
DWORD index = 0;
int flag = 0;
for (index = 0; index < _image_export_directory->NumberOfNames; index++)
{
char* temp = (char*)(RVA_to_FOA(filebuffer, *(add_of_functionsnames)) + (DWORD)filebuffer);
if (strcmp(temp, funcName) == 0)
{
flag = 1;
break;
}
add_of_functionsnames++;
}
if (flag == 0)
{
printf("没有此导出函数");
exit(0);
}
//3.在获取导出表->函数序号表 指针 ///(序号表是2字节,用word 这里易错!!!!!!!!!!。)
WORD* add_of_NameOrdinals = (WORD*)(RVA_to_FOA(filebuffer, _image_export_directory->AddressOfNameOrdinals) + (DWORD)filebuffer);
WORD funindex = *(add_of_NameOrdinals + index);
//在获取导出表->函数序号表 指针
DWORD* add_of_Functions = (DWORD*)(RVA_to_FOA(filebuffer, _image_export_directory->AddressOfFunctions) + (DWORD)filebuffer);
return *(add_of_Functions + funindex);
}
DWORD GetFunctionAddrByOrdinals(char* filebuffer, DWORD ordinal)
{
_IMAGE_DOS_HEADER* _image_dos_header = NULL;
_IMAGE_FILE_HEADER* _image_file_header = NULL;
_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
_IMAGE_EXPORT_DIRECTORY* _image_export_directory = NULL;
_image_dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
_image_file_header = (_IMAGE_FILE_HEADER*)(filebuffer + _image_dos_header->e_lfanew + 4);
_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
_image_data_directory = (_IMAGE_DATA_DIRECTORY*)_image_optional_header->DataDirectory;
if (_image_data_directory->VirtualAddress == 0) {
printf("此PE文件没有导出表,没有函数导出");
exit(0);
}
//1.先获取导出表指针 目录项指向的vitualaddreess 就是导出表指针开始的位置
_image_export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(filebuffer, _image_data_directory->VirtualAddress) + (DWORD)filebuffer);
//判断是否在函数序号表范围内。 函数序号= ordinal-base
if ((ordinal - _image_export_directory->Base) > _image_export_directory->NumberOfFunctions - 1)
{
printf("导出序号有误");
exit(0);
}
DWORD* add_of_functions = (DWORD*)(RVA_to_FOA(filebuffer, _image_export_directory->AddressOfFunctions) + (DWORD)filebuffer);
//易错。 传入序号还需要减去base
return *(add_of_functions + (ordinal - _image_export_directory->Base));
}
char* FileBuffer_TO_Imagebuffer(char* filebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//计算imagebuffer大小。
DWORD size = optional_header->SizeOfImage;
char* Imagebuffer = (char*)malloc(sizeof(char) * size);
if (Imagebuffer == NULL)
{
printf("Imagebuffer malloc error");
exit(0);
}
//初始化0 ,Iimagebuffer
for (DWORD i = 0; i < size; i++)
{
*(Imagebuffer + i) = 0x00;
}
//拷贝头
for (DWORD i = 0; i < optional_header->SizeOfHeaders; i++)
{
*(Imagebuffer + i) = *((char*)filebuffer + i);
}
//拷贝节表
for (DWORD i = 0; i < file_header->NumberOfSections; i++)
{
for (DWORD j = 0; j < section_header->SizeOfRawData; j++)
{
*(Imagebuffer + section_header->VirtualAddress + j) = *(filebuffer + section_header->PointerToRawData + j);
}
section_header++;
}
//printf("Imagebuffer:%X", Imagebuffer);
return Imagebuffer;
}
int computer_buffersize(char* buffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_SECTION_HEADER* last_section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)buffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
last_section_header = section_header + file_header->NumberOfSections - 1;
//newbuffer的大小=最后一个节的poiontorawdata+sizeofrawdata
int newbufferSize = last_section_header->PointerToRawData + last_section_header->SizeOfRawData;
return newbufferSize;
}
char* Imagebuffer_TO_Newbuffer(char* Imagebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_SECTION_HEADER* last_section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
last_section_header = section_header + file_header->NumberOfSections - 1;
//newbuffer的大小=最后一个节的poiontorawdata+sizeofrawdata
DWORD newbufferSize = computer_buffersize(Imagebuffer);
char* NewBuffer = (char*)malloc(sizeof(char) * newbufferSize);
if (NewBuffer == NULL)
{
printf("newbuffer malloc error");
exit(0);
}
//初始化0 ,Iimagebuffer
for (DWORD i = 0; i < newbufferSize; i++)
{
*(NewBuffer + i) = 0x00;
}
//拷贝头
for (DWORD i = 0; i < optional_header->SizeOfHeaders; i++)
{
*(NewBuffer + i) = *((char*)Imagebuffer + i);
}
//拷贝节表
for (DWORD i = 0; i < file_header->NumberOfSections; i++)
{
for (DWORD j = 0; j < section_header->SizeOfRawData; j++)
{
*(NewBuffer + section_header->PointerToRawData + j) = *(Imagebuffer + section_header->VirtualAddress + j);
}
section_header++;
}
return NewBuffer;
}
int Save_to_disk(char* buffer, char* diskpath, int size)
{
FILE* fp = fopen(diskpath, "wb");
if (fp == NULL)
{
printf("打开存盘文件失败");
return 0;
}
int succeed = fwrite(buffer, 1, size, fp);
if (succeed == 0)
{
free(buffer);
fclose(fp);
return 0;
}
fclose(fp);
return 1;
}
//向第一个节中注入代码。
int add_shellcode_to_first_section(char* Imagebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_SECTION_HEADER* last_section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//首先判断节中的空白区是否能放的下shellcoded的代码大小。假定sizeofrawdata>vituralsize
if (section_header->SizeOfRawData - section_header->Misc.VirtualSize < sizeof(shellcode) / sizeof(shellcode[0]))
{
printf("第一个节的空白区不足");
return 0;
}
//空白区足够的话,就拷贝数据过去,拷贝到虚拟地址中去, 从imagebuffer+sec_>vituraladd+vtsize的地方开始,拷贝shellcode个字节。
char* shellcodeP = Imagebuffer + section_header->VirtualAddress + section_header->Misc.VirtualSize;
char* New_OEP = shellcodeP;
//拷贝代码到shellcodeP,从shellcode开始,拷贝N个字节。
memcpy(shellcodeP, shellcode, sizeof(shellcode) / sizeof(shellcode[0]));
//修改E8后面4个字节的地址。
//E8的地址=messagebox的地址-(E8当前地址+5)
//E8的地址=messagebox的地址-(shellcodeP+8+5)这个地址是错误的,因为imagebuffer是mallco的,需要切换到运行的地址imagebase。
//E8的地址=messagebox的地址-(shellcodeP-imagebuffer+imagebase+8+5);
DWORD E8_address = MessageBox - (shellcodeP - Imagebuffer + optional_header->ImageBase + 8 + 5);
//把E8的地方放到shellcodeP往后9个字节(4个6A 00+e8)里面去
*((DWORD*)(shellcodeP + 9)) = E8_address;
//e9的地址=真正跳转的地址(oep+imagebase)-E9当前的地址的下一条地址(shellcodeP+9+5-Imagebuffer)
//
DWORD E9_address = (optional_header->AddressOfEntryPoint + optional_header->ImageBase) - (shellcodeP + 8 + 5 + 5 - Imagebuffer + optional_header->ImageBase);
*((DWORD*)(shellcodeP + 9 + 5)) = E9_address;
//EOP还没有修改的。eop=shellcodeP-imagebuffer
optional_header->AddressOfEntryPoint = DWORD(New_OEP - Imagebuffer);
return 1;
}
//向任意节中注入代码
int add_shellcode_to_specific_section(char* Imagebuffer, int section_num)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_SECTION_HEADER* last_section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
if (section_num <= 0 || section_num > file_header->NumberOfSections)
{
printf("您所输入的节不存在");
return 0;
}
//要注入内容所在节的指针
_IMAGE_SECTION_HEADER* target_section_header = section_header + section_num - 1;
//首先判断节中的空白区是否能放的下shellcoded的代码大小。假定sizeofrawdata>vituralsize
if (target_section_header->SizeOfRawData - target_section_header->Misc.VirtualSize < sizeof(shellcode) / sizeof(shellcode[0]))
{
printf("注入的空白区不足");
return 0;
}
//空白区足够的话,就拷贝数据过去,拷贝到虚拟地址中去, 从imagebuffer+sec_>vituraladd+vtsize的地方开始,拷贝shellcode个字节。
char* shellcodeP = Imagebuffer + target_section_header->VirtualAddress + target_section_header->Misc.VirtualSize;
char* New_OEP = shellcodeP;
//拷贝代码到shellcodeP,从shellcode开始,拷贝N个字节。
memcpy(shellcodeP, shellcode, sizeof(shellcode) / sizeof(shellcode[0]));
//修改E8后面4个字节的地址。
//E8的地址=messagebox的地址-(E8当前地址+5)
//E8的地址=messagebox的地址-(shellcodeP+8+5)这个地址是错误的,因为imagebuffer是mallco的,需要切换到运行的地址imagebase。
//E8的地址=messagebox的地址-(shellcodeP-imagebuffer+imagebase+8+5);
DWORD E8_address = MessageBox - (shellcodeP - Imagebuffer + optional_header->ImageBase + 8 + 5);
//把E8的地方放到shellcodeP往后9个字节(4个6A 00+e8)里面去
*((DWORD*)(shellcodeP + 9)) = E8_address;
//e9的地址=真正跳转的地址(oep+imagebase)-E9当前的地址的下一条地址(shellcodeP+9+5-Imagebuffer)
//
DWORD E9_address = (optional_header->AddressOfEntryPoint + optional_header->ImageBase) - (shellcodeP + 8 + 5 + 5 - Imagebuffer + optional_header->ImageBase);
*((DWORD*)(shellcodeP + 9 + 5)) = E9_address;
//EOP还没有修改的。eop=shellcodeP-imagebuffer
optional_header->AddressOfEntryPoint = DWORD(New_OEP - Imagebuffer);
//任意节修改的话, 还需要将属性修改, 否则只可读的节不能写入。用|运算解决。
target_section_header->Characteristics = target_section_header->Characteristics | 0x60000020;
return 1;
}
//求最小公倍数
int least_common_multiple(int a, int b)
{
if (a <= 0 || b <= 0)
{
return -1;
}
int max = a > b ? a : b;
while (1)
{
if (max % a == 0 && max % b == 0)
{
break;
}
max++;
}
return max;
}
//文件最后新增一个节
char* add_a_section_in_imagebuffer(char* Imagebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_SECTION_HEADER* last_section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//malloc一个空间,大小为新增节大小+原来的sizeofimage;并且初始化为0;
DWORD expand_value = least_common_multiple(optional_header->FileAlignment, optional_header->SectionAlignment);
char* NewImageBuffer = (char*)malloc(optional_header->SizeOfImage + expand_value);
if (NewImageBuffer == NULL)
{
printf("新增节malloc失败");
exit(0);
}
for (DWORD i = 0; i < optional_header->SizeOfImage + expand_value; i++)
{
*(NewImageBuffer + i) = 0x00;
}
//接下来,把原来filebuffer的文件拷贝到Newbuffer里面来。
memcpy(NewImageBuffer, Imagebuffer, optional_header->SizeOfImage);
//拷贝完成后,把各种头指向新的Newbuffer.进行各种操作。
dos_header = (_IMAGE_DOS_HEADER*)NewImageBuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//判断一下 是否可以新增节表。
if (optional_header->SizeOfHeaders - (dos_header->e_lfanew + 24 + file_header->SizeOfOptionalHeader + file_header->NumberOfSections * 40) < 80)
{
printf("节表空白区不足,无法新增节");
exit(0);
}
//判断节表的后面需要有80个字节的大小的数据必须为0.
for (DWORD i = 0; i < 80; i++)
{
if (*((char*)(section_header + file_header->NumberOfSections) + i) != 0)
{
printf("节表后80字节数据不全为0x00,有文件数据,无法新增节表");
exit(0);
}
}
//新增节表
DWORD old_sizeofimage = optional_header->SizeOfImage;
//修改sizeofimage;
optional_header->SizeOfImage += expand_value;
_IMAGE_SECTION_HEADER* new_section_header = NULL;
//上面声明的newsection_header
new_section_header = section_header + file_header->NumberOfSections;
//复制第一个节表的信息到新增的节表中去
for (int i = 0; i < 40; i++)
{
*((char*)new_section_header + i) = *((char*)section_header + i);
}
file_header->NumberOfSections++;
//节表添加完成后,修改新增节表信息;
char* name = (char*)new_section_header->Name;
char* newname = (char*)".newsec";
strncpy(name, newname, IMAGE_SIZEOF_SHORT_NAME);
new_section_header->VirtualAddress = old_sizeofimage;
new_section_header->Misc.VirtualSize = expand_value;
//PointerToRawData=上一个节表的pointrawdata+sizorawdata
new_section_header->PointerToRawData = (new_section_header - 1)->PointerToRawData + (new_section_header - 1)->SizeOfRawData;
new_section_header->SizeOfRawData = expand_value;
new_section_header->Characteristics = 0x60000020;
return NewImageBuffer;
}
char* add_a_section_in_filebuffer(char* filebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_SECTION_HEADER* last_section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//malloc一个空间,大小为新增节大小+原来的sizeofimage;并且初始化为0;
DWORD expand_value = 0x3000;
//原来的buffersize.
DWORD filebuffersize = (section_header + file_header->NumberOfSections - 1)->PointerToRawData + (section_header + file_header->NumberOfSections - 1)->SizeOfRawData;
char* NewFileBuffer = (char*)malloc(filebuffersize + expand_value);
if (NewFileBuffer == NULL)
{
printf("filebuffer新增节malloc失败");
exit(0);
}
for (DWORD i = 0; i < filebuffersize + expand_value; i++)
{
*(NewFileBuffer + i) = 0x00;
}
//接下来,把原来filebuffer的文件拷贝到Newbuffer里面来。
memcpy(NewFileBuffer, filebuffer, filebuffersize);
//拷贝完成后,把各种头指向新的Newbuffer.进行各种操作。
dos_header = (_IMAGE_DOS_HEADER*)NewFileBuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//判断一下 是否可以新增节表。
if (optional_header->SizeOfHeaders - (dos_header->e_lfanew + 24 + file_header->SizeOfOptionalHeader + file_header->NumberOfSections * 40) < 80)
{
printf("节表空白区不足,无法新增节");
exit(0);
}
//判断节表的后面需要有80个字节的大小的数据必须为0.
for (DWORD i = 0; i < 80; i++)
{
if (*((char*)(section_header + file_header->NumberOfSections) + i) != 0)
{
printf("节表后80字节数据不全为0x00,有文件数据,无法新增节表");
exit(0);
}
}
//新增节
DWORD old_sizeofimage = optional_header->SizeOfImage;
//修改sizeofimage;
optional_header->SizeOfImage += expand_value;
_IMAGE_SECTION_HEADER* new_section_header = NULL;
//上面声明的newsection_header
new_section_header = section_header + file_header->NumberOfSections;
//新增节表。复制第一个节表的信息到新增的节表中去
for (int i = 0; i < 40; i++)
{
*((char*)new_section_header + i) = *((char*)section_header + i);
}
file_header->NumberOfSections++;
//节表添加完成后,修改新增节表信息;
char* name = (char*)new_section_header->Name;
char* newname = (char*)".newsec";
strncpy(name, newname, IMAGE_SIZEOF_SHORT_NAME);
new_section_header->VirtualAddress = old_sizeofimage;
new_section_header->Misc.VirtualSize = expand_value;
//PointerToRawData=上一个节表的pointrawdata+sizorawdata
new_section_header->PointerToRawData = filebuffersize;
new_section_header->SizeOfRawData = expand_value;
new_section_header->Characteristics = 0x00000000;
for (int i = 0; i < file_header->NumberOfSections; i++)
{
new_section_header->Characteristics = new_section_header->Characteristics | (section_header + i)->Characteristics;
}
return NewFileBuffer;
}
//扩大最后一个节
char* expand_last_section(char* Imagebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//malloc一个空间,大小为扩大节大小+原来的sizeofimage;并且初始化为0;
DWORD expand_value = least_common_multiple(optional_header->FileAlignment, optional_header->SectionAlignment);
char* NewImageBuffer = (char*)malloc(optional_header->SizeOfImage + expand_value);
if (NewImageBuffer == NULL)
{
printf("expand_last_section error");
exit(0);
}
for (DWORD i = 0; i < optional_header->SizeOfImage + expand_value; i++)
{
*(NewImageBuffer + i) = 0x00;
}
//接下来,把原来Imagebuffer的文件拷贝到NewImageBuffer里面来。
memcpy(NewImageBuffer, Imagebuffer, optional_header->SizeOfImage);
//拷贝完成后,把各种头指向新的Newbuffer.进行各种操作。
dos_header = (_IMAGE_DOS_HEADER*)NewImageBuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//扩大节表
DWORD old_sizeofimage = optional_header->SizeOfImage;
//修改sizeofimage;
optional_header->SizeOfImage += expand_value;
_IMAGE_SECTION_HEADER* last_section_header = section_header + file_header->NumberOfSections - 1;
//上面声明的修改的最后一个节表 ,指针指向的是节表的最前,所以要-1;
//节表扩大完成后,修改节表信息;
last_section_header->Misc.VirtualSize = old_sizeofimage - last_section_header->VirtualAddress + expand_value;
last_section_header->SizeOfRawData = last_section_header->Misc.VirtualSize;
last_section_header->Characteristics = last_section_header->Characteristics | 0x60000020;
return NewImageBuffer;
}
//添加shellcode到新增的地方。
int add_shellcode_to_expanded_section(char* Imagebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
if (least_common_multiple(optional_header->SectionAlignment, optional_header->FileAlignment) < (sizeof(shellcode) / sizeof(shellcode[0])))
{
printf("扩大节中的空白区不足");
return 0;
}
char* shellcodeP = Imagebuffer + optional_header->SizeOfImage - least_common_multiple(optional_header->SectionAlignment, optional_header->FileAlignment);
char* New_OEP = shellcodeP;
//拷贝代码到shellcodeP,从shellcode开始,拷贝N个字节。
memcpy(shellcodeP, shellcode, sizeof(shellcode) / sizeof(shellcode[0]));
//修改E8后面4个字节的地址。
//E8的地址=messagebox的地址-(E8当前地址+5)
//E8的地址=messagebox的地址-(shellcodeP+8+5)这个地址是错误的,因为imagebuffer是mallco的,需要切换到运行的地址imagebase。
//E8的地址=messagebox的地址-(shellcodeP-imagebuffer+imagebase+8+5);
DWORD E8_address = MessageBox - (shellcodeP - Imagebuffer + optional_header->ImageBase + 8 + 5);
//把E8的地方放到shellcodeP往后9个字节(4个6A 00+e8)里面去
*((DWORD*)(shellcodeP + 9)) = E8_address;
//e9的地址=真正跳转的地址(oep+imagebase)-E9当前的地址的下一条地址(shellcodeP+9+5-Imagebuffer)
//
DWORD E9_address = (optional_header->AddressOfEntryPoint + optional_header->ImageBase) - (shellcodeP + 8 + 5 + 5 - Imagebuffer + optional_header->ImageBase);
*((DWORD*)(shellcodeP + 9 + 5)) = E9_address;
//EOP还没有修改的。eop=shellcodeP-imagebuffer
optional_header->AddressOfEntryPoint = DWORD(New_OEP - Imagebuffer);
return 1;
}
//合并节
char* merge_section(char* Imagebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
dos_header = (_IMAGE_DOS_HEADER*)Imagebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
//修改节表信息,要最后修改节表数目,因为前面会用到。
section_header->Misc.VirtualSize = optional_header->SizeOfImage - section_header->VirtualAddress;
section_header->SizeOfRawData = section_header->Misc.VirtualSize;
for (int i = 1; i < file_header->NumberOfSections; i++)//如果一个节表,就不执行,如果两个节表, 就执行1次,如果3个节表,就或两次。
{
section_header->Characteristics = section_header->Characteristics | (section_header + i)->Characteristics;
}
for (int i = 0; i < (40 * file_header->NumberOfSections); i++)
{
*((char*)(section_header + 1) + i) = 0x00;//把第一个节表后面所有节表信息归零。
}
file_header->NumberOfSections = 1;
return Imagebuffer;
}
//定义函数,能够返回对齐后的大小
int aligement_size(int size, int aligment)
{
if (size < 0 || aligment <= 0)
{
printf("所求的对齐的数据不合法");
}
return aligment * (size / aligment + 1);
}
char* move_export_table(char* filebuffer)//移动导出表。
{
char* newfilebuffer = add_a_section_in_filebuffer(filebuffer);
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
_IMAGE_EXPORT_DIRECTORY* export_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)newfilebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
data_directory = (_IMAGE_DATA_DIRECTORY*)optional_header->DataDirectory;
if (data_directory->VirtualAddress == 0)
{
printf("此PE没有导出表");
free(newfilebuffer);//也不知道需不需要free.
exit(0);
}
export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(newfilebuffer, data_directory->VirtualAddress) + newfilebuffer);//指针指向导出表。//我犯了个错误。用pointrawdata+sizeofrawdata,指针指向文件最后了,应该用pointrawdata+newfilebuffer才对。
char* CopyStart = (section_header + file_header->NumberOfSections - 1)->PointerToRawData + newfilebuffer;//新增节开始的地方。
/*复制函数地址表*/
char* fun_add = RVA_to_FOA(filebuffer, export_directory->AddressOfFunctions) + filebuffer;//原节表中的函数地址表。
memcpy(CopyStart, fun_add, export_directory->NumberOfFunctions * 4);
char* fun_add_in_newsection = CopyStart; //新增节函数地址表。
CopyStart = CopyStart + export_directory->NumberOfFunctions * 4; //新增节待copy目的地指针。
/*复制函数序号表*/
char* orditiona_add = RVA_to_FOA(newfilebuffer, export_directory->AddressOfNameOrdinals) + newfilebuffer; // 原节表中的函数序号表。
memcpy(CopyStart, orditiona_add, export_directory->NumberOfNames * 2);
char* orditiona_add_in_newsection = CopyStart; //新增节函数序号表。
CopyStart = CopyStart + export_directory->NumberOfFunctions * 2;
/*复制函数名称表*/
char* names_add = RVA_to_FOA(newfilebuffer, export_directory->AddressOfNames) + newfilebuffer;//原节表中的函数名称表。
memcpy(CopyStart, names_add, export_directory->NumberOfNames * 4);
DWORD* names_add_in_newsection = (DWORD*)CopyStart; //新增节函数名称表。
CopyStart = CopyStart + export_directory->NumberOfFunctions * 4;
/*挨个复制函数名字*/
for (DWORD i = 0; i < export_directory->NumberOfNames; i++)
{
char* name = RVA_to_FOA(newfilebuffer, *(DWORD*)names_add) + newfilebuffer;
memcpy(CopyStart, name, strlen(name) + 1);
*names_add_in_newsection = FOA_to_RVA(newfilebuffer, (DWORD)(CopyStart - newfilebuffer));
CopyStart += (strlen(name) + 1);//新增节copy的指针后移;
names_add = (char*)((DWORD*)names_add + 1); //原函数名称表指向下一个函数名称地址。
names_add_in_newsection++; //新增节h函数名称表指向下一个函数名称地址。
}
/*复制导出表*/
memcpy(CopyStart, (char*)export_directory, 40);//此时copystart指针指向的就是导出表的地址
/*修改导出表三个地址参数*/
export_directory->AddressOfFunctions = FOA_to_RVA(newfilebuffer, (DWORD)(fun_add_in_newsection - newfilebuffer));
export_directory->AddressOfNameOrdinals = FOA_to_RVA(newfilebuffer, (DWORD)(orditiona_add_in_newsection - newfilebuffer));
export_directory->AddressOfNames = FOA_to_RVA(newfilebuffer, (DWORD)((char*)names_add_in_newsection - newfilebuffer));
/*修改目录项vitualaddress地址参数*/
data_directory->VirtualAddress = FOA_to_RVA(newfilebuffer, (DWORD)(CopyStart - newfilebuffer));
return newfilebuffer;
}
char* move_relocation_table(char* filebuffer)
{
char* newfilebuffer = add_a_section_in_filebuffer(filebuffer);
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)newfilebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
data_directory = (_IMAGE_DATA_DIRECTORY*)(optional_header->DataDirectory + 5);//指向重定位表。 这里指针指向的是目录项[16]的首个元素地址。
if (data_directory->VirtualAddress == 0)
{
printf("此PE没有重定位表");
free(newfilebuffer);//也不知道需不需要free.
exit(0);
}
_IMAGE_BASE_RELOCATION* relocaltion_table = (_IMAGE_BASE_RELOCATION*)(RVA_to_FOA(newfilebuffer, data_directory->VirtualAddress) + newfilebuffer);//重定位表在FOA中的地址。
_IMAGE_BASE_RELOCATION* relocaltion_table_temp = relocaltion_table;//定义一个新的指针用来计算重定位表的大小。原来的指针要指向被复制的地方,用来复制内容。
char* CopyStart = (section_header + file_header->NumberOfSections - 1)->PointerToRawData + newfilebuffer;//新增节指针开始的地方。
int size = 0;
for (int i = 0; relocaltion_table_temp->VirtualAddress != 0; i++)
{
size += relocaltion_table_temp->SizeOfBlock;
relocaltion_table_temp = (_IMAGE_BASE_RELOCATION*)((char*)relocaltion_table_temp + relocaltion_table_temp->SizeOfBlock);//指针指向下一个块的vitualaddress;
}
size += 8;//最后为0的vitualaddress和sizeofblock,共8字节。
memcpy(CopyStart, (char*)relocaltion_table, size);//copy结束了之后指针不能往后移动,因为后面没有再复制其他内容了。指针还是指向开始的地方。
data_directory->VirtualAddress = FOA_to_RVA(newfilebuffer, (DWORD)(CopyStart - newfilebuffer));//修复目录项中的vitualaddress;
return newfilebuffer;
}
void repair_relocation(char* filebuffer)
{
_IMAGE_DOS_HEADER* dos_header = NULL;
_IMAGE_FILE_HEADER* file_header = NULL;
_IMAGE_OPTIONAL_HEADER* optional_header = NULL;
_IMAGE_NT_HEADERS* nt_header = NULL;
_IMAGE_SECTION_HEADER* section_header = NULL;
_IMAGE_DATA_DIRECTORY* data_directory = NULL;
dos_header = (_IMAGE_DOS_HEADER*)filebuffer;
nt_header = (_IMAGE_NT_HEADERS*)((char*)dos_header + dos_header->e_lfanew);
file_header = (_IMAGE_FILE_HEADER*)((char*)nt_header + 4);
optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)file_header + 20);
section_header = (_IMAGE_SECTION_HEADER*)((char*)optional_header + file_header->SizeOfOptionalHeader);
data_directory = (_IMAGE_DATA_DIRECTORY*)(optional_header->DataDirectory + 5);//指向重定位表。 这里指针指向的是目录项[16]的首个元素地址。
if (data_directory->VirtualAddress == 0)
{
printf("此PE无重定位表");
exit(0);
}
_IMAGE_BASE_RELOCATION* relocation_table = (_IMAGE_BASE_RELOCATION*)(RVA_to_FOA(filebuffer, data_directory->VirtualAddress) + filebuffer);//重定位表地址
//修改imagebase
DWORD old_imagebase = optional_header->ImageBase;
optional_header->ImageBase = 0x02600000;
int offset = (int)(optional_header->ImageBase - old_imagebase);
//修改重定位表,挨个进行遍历
while (relocation_table->VirtualAddress != 0)
{
for (DWORD i = 0; i < (relocation_table->SizeOfBlock - 8) / 2; i++)//遍历的具体项个数为 (sizeofblock-8个字节)/2 ;注 每个具体项占两个字节。
{
//如果具体项的高四位==0;那么指针往后移动2字节,
if (*((WORD*)((char*)relocation_table + 8 + i * 2)) >> 12 == 0)
{
continue; //continue 不在执行循环的下面的语句,而是返回上面的i++。
}
//具体项的低12位+reloccation->vituraladdress, (206+2000)找到他在文件中的位置的偏移,+filebuffer(1600000) 就是该具体项在文件中的偏移。
DWORD* repaiAddress = (DWORD*)(RVA_to_FOA(filebuffer, (relocation_table->VirtualAddress + (*((WORD*)((char*)relocation_table + 8 + i * 2)) & 0x0FFF))) + filebuffer);//重定位表所指向的偏移指针
*repaiAddress += offset;//重定位表所指向的偏移的值
}
relocation_table = (_IMAGE_BASE_RELOCATION*)((char*)relocation_table + relocation_table->SizeOfBlock);//具体项循环结束后,指针指向下一个块。
}
}
int main()
{
//char* FilePath = (char*)"C:\\Windows\\notepad.exe";
char* FilePath = (char*)"C:\\Users\\Administrator\\Desktop\\NOTEPAD.EXE";
//char* disk_path= (char*)"C:\\Users\\Administrator\\Desktop\\PETool 1.0.0.5副本.exe";
//char* FilePath = (char*)"C:\\Users\\Administrator\\Desktop\\Win网络播放器N5-1214.exe";
//char* FilePath = (char*)"C:\\Users\\Administrator\\Desktop\\16Edit.DLL";
//char* disk_path = (char*)"C:\\Users\\Administrator\\Desktop\\16Edit副本.DLL";
char* filebuffer = To_FileBuffer(FilePath);
Import_table_print(filebuffer);
//repair_relocation(filebuffer);
// char* newbuffer = move_export_table(filebuffer);
//filebuffer =add_a_section_in_filebuffer(filebuffer);
//char* funname = (char*)"dbkFCallWrapperAddr";
//Relocation_print(FilePath);
//DWORD XXXX=GetFunctionAddrByName(filebuffer, funname);
//DWORD XXXX = GetFunctionAddrByOrdinals(filebuffer, 1);
//printf("%x", XXXX);
//ExportTable_print(FilePath);
//char* filebuffer=To_FileBuffer(FilePath);
//char*Imagebuffer=FileBuffer_TO_Imagebuffer(filebuffer);
//Imagebuffer = expand_last_section(Imagebuffer);
//Imagebuffer = merge_section(Imagebuffer);
//add_shellcode_to_expanded_section(Imagebuffer);
//add_shellcode_to_specific_section(Imagebuffer,3);
//char* NewBuffer = Imagebuffer_TO_Newbuffer(Imagebuffer);
//int size = computer_buffersize(filebuffer);
//int chenggong = Save_to_disk(filebuffer, disk_path, size);
//int ccc=aligement_size(1001,400);
//printf("aligement_size:%d", ccc);
return 0;
}