首页
社区
课程
招聘
[原创]PE基础之导入表注入
发表于: 2020-10-3 02:05 10857

[原创]PE基础之导入表注入

2020-10-3 02:05
10857

记录菜鸡学习PE结构的最后一个基础关,包括实现步骤,实现思路,排查问题的过程,若有不对之处,欢迎各位大佬指正

目前只懂得以下两种注入的原理

(1)导入表注入:当程序被加载时,系统会根据程序导入表信息来加载需要用到的dll,导入表注入的原理就是修改程序的导入表,将自己的dll添加到程序的导入表中,这样程序运行时可以将自己的DLL加载到程序的进程空间.

(2)特洛伊注入:也可以称之为dll劫持。导入表某些dll被其他的dll(与被替换的dll调用函数数量相同)替换,程序运行时可以加载替换的dll,进而可以通过替换后的dll进行一些危险操作.

结构图:

步骤指导
1.将要注入dll的程序写入到内存中,并新增一个节
2.拷贝原来的导入表到新节中
3.在新节拷贝的导入表后新增一个导入表_IMAGE_IMPORT_DESCRIPTOR
4.增加8字节的INT表和8字节的IAT表
5.存储要注入的dll的名称
6.增加一个_IMAGE_IMPORT_BY_NAME结构,并将函数名称存进结构体第一个变量后的内存中
7.将_IMAGE_IMPORT_BY_NAME结构的地址的RVA赋值给INT表和IAT表第一项
8.将dll名称所在位置的首地址的RVA赋值给新增导入表的Name
9.修改IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size
10.存盘
排雷提示:
1.根据IMAGE_DATA_DIRECTORY结构的size去拷贝导入表,将会多拷贝20字节的0,这也是导入表结束的标志,新增导入表的时候应该将此处的0进行覆盖,因为20字节的0,否则系统不会加载新增的导入表代表导入表结束了!!!鄙人当时完成这个代码的书写后很兴奋,但发现新增的dll始终无法加载,卡了很久,仔细调试了很久,对比原来的导入表所在内存区域和新节所在内存区域,才发现这里的问题,说明我对导入表理解的不够透彻,不能很好的排查问题
2.INT表和IAT表的8字节是因为这两张表至少包含一项内容,才会被系统加载,剩余的4字节为0标志着表的结束
3.结构体存储地址的变量存储都是RVA,使用时需要进行转换,有时是FOA转RVA,有时是RVA转FOA
4.新增节的属性(Characteristics)需要改为0xc0000040,否则会报0xc0000005错误

将要注入导入表的程序与用来注入dll放到同一级目录

相关函数:

主函数:

注入程序

启动程序

关闭程序:

 
 
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
 
 
#define EVERYSECTIONTABLELENGTH 0x28
#define DLLNAME "InjectDll.dll"
#define DLLNAMELENGTH 0xE
#define FUNCTIONNAME "ExportFunction"
#define FUNCTIONNAMELENGTH 0xF
#define SECTIONNAME ".import"
#define INPUTFILENAME "D:/inject/ipmsg.exe"
#define INPUTMODE "rb"
#define OUTPUTFILENAME "D:/inject/test.exe"
#define OUTPUTMODE "wb"
 
 
/*************************************************
函数功能:读取一个文件,将文件内容写入到内存中;
函数参数:无
函数返回值:pFileBuffer(LPVOID)
**************************************************/
LPVOID FileBuffer() {
    FILE* pFile = NULL;    //文件指针
    LPVOID pFileBuffer = NULL; //存放数据内存的首地址
    DWORD filesize = 0;//记录文件大小
    size_t result = 0;//记录写入的返回结果
 
    //打开一个文件
    pFile = fopen(INPUTFILENAME, INPUTMODE);
    if (pFile == NULL) {
        printf("打开文件失败!\n");
        return NULL;
    }
 
    //统计文件的大小
    fseek(pFile, 0, SEEK_END);
    filesize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
 
    //申请一块内存
    pFileBuffer = malloc(filesize);
    if (pFileBuffer == NULL) {
        printf("申请内存失败!\n");
        fclose(pFile);
        return NULL;
    }
 
    //将文件数据写入内存
    result = fread(pFileBuffer, 1, filesize, pFile);
    if (result != filesize) {
        printf("文件写入内存失败!\n");
        fclose(pFile);
        free(pFileBuffer);
        return NULL;
    }
 
    fclose(pFile);
    return pFileBuffer;
}
 
/*************************************************
函数功能:返回对齐后的大小;
函数参数:virtualsize(原有长度),alignment(对齐方式)
函数返回值:ret(int型)
**************************************************/
DWORD AlignSize(DWORD virtualsize, DWORD alignment) {
    DWORD ret = alignment;
    if (virtualsize <= alignment) {
        return ret;
    }
    else {
        ret = (virtualsize / alignment) * alignment + alignment;
        return ret;
    }
}
 
/*************************************************
函数功能:计算一个filebuffer的大小;
函数参数:pFileBuffer(LPVOID)
函数返回值:filesize(int)
**************************************************/
DWORD CountFileBufferSize(LPVOID pFileBuffer) {
    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;
    DWORD filesize = 0;//记录文件大小
 
    if (pFileBuffer == NULL) {
        printf("文件写入内存失败!\n");
        return NULL;
    }
 
    //判读是否具有MZ标志                                                                                           
    if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) {
        printf("不具有MZ标志!\n");
        free(pFileBuffer);
        return 0;
    }
 
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
 
    //判断是否具有PE标志                                                                                           
    if (*(PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE) {
        printf("不具有PE标志\n");
        free(pFileBuffer);
        return 0;
    }
 
    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);
 
    //最后一个节头地址 + 最后一节大小
     filesize = (DWORD)((pSectionHeader + pPEHeader->NumberOfSections - 1)->PointerToRawData + (pSectionHeader + pPEHeader->NumberOfSections - 1)->SizeOfRawData);
    return filesize;
}
 
/*************************************************
函数功能:计算一个文件大小;
函数参数:filename(文件的绝对路径,LPSTR),mode(读取文件的形式,LPSTR)
函数返回值:filesize(int)
**************************************************/
DWORD CountFileSize(LPSTR filename, LPSTR mode) {
    FILE* pFile = NULL;
    LPSTR pFileBuffer = NULL;
    DWORD filesize = 0;
 
    //打开文件
    pFile = fopen(filename, mode);
    if (pFile == NULL) {
        printf("打开文件失败!\n");
        return NULL;
    }
 
    //统计文件大小
    fseek(pFile, 0, SEEK_END);
    filesize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
 
    fclose(pFile);
    return filesize;
}
 
 
/*************************************************
函数功能:PE文件尾部新增一个节;
函数参数:pFileBuffer(LPVOID),sectionLength(DWORD)
函数返回值:pNewFileBuffer(LPVOID)
**************************************************/
LPVOID AddLastSection(LPVOID pFileBuffer, DWORD sectionLength) {
    LPVOID pNewFileBuffer = 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 + 0x4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + 0x14);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
 
    //判断节表空间是否足够,节表后需要预留一个节表空间的位置
    if (pSectionHeader->PointerToRawData - (DWORD)(pSectionHeader + pPEHeader->NumberOfSections) < 0x50) {
        printf("节表空间不够!\n");
        free(pFileBuffer);
        return NULL;
    }
 
    //开辟新的内存
    DWORD filesize = CountFileBufferSize(pFileBuffer);
    pNewFileBuffer = malloc(filesize + sectionLength);
    if (pNewFileBuffer == NULL) {
        printf("申请内存失败!\n");
        free(pFileBuffer);
        return NULL;
    }
 
    //新内存初始化为0
    memset(pNewFileBuffer, 0, filesize + sectionLength);
 
    //拷贝原来的文件内容到新内存并释放旧文件内存
    memcpy(pNewFileBuffer, pFileBuffer, filesize);
    free(pFileBuffer);
 
    //结构体指针再次初始化
    pDosHeader = (PIMAGE_DOS_HEADER)pNewFileBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pNewFileBuffer + 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);
 
    //修改sizeofimage
    pOptionHeader->SizeOfImage += sectionLength;
 
    //copy第一个节表内容
    memcpy(pSectionHeader + pPEHeader->NumberOfSections, pSectionHeader, EVERYSECTIONTABLELENGTH);
 
    //修改新增的节表的项目
    PIMAGE_SECTION_HEADER changeSection1 = pSectionHeader + pPEHeader->NumberOfSections;//新增节表首地址
    PIMAGE_SECTION_HEADER changeSection2 = pSectionHeader + pPEHeader->NumberOfSections - 1;//新增节表的前一个节表首地址
    changeSection1->Misc.VirtualSize = sectionLength;//修改内存中的尺寸
    changeSection1->SizeOfRawData = sectionLength;//修改文件中的尺寸
    changeSection1->Characteristics = 0xc0000040;
    memcpy(changeSection1, SECTIONNAME, 0x8);//修改名字
 
    changeSection1->PointerToRawData = changeSection2->PointerToRawData + changeSection2->SizeOfRawData;
    if (changeSection2->SizeOfRawData > changeSection2->Misc.VirtualSize){
        changeSection1->VirtualAddress = changeSection2->VirtualAddress + changeSection2->SizeOfRawData;
    }
    else{
        changeSection1->VirtualAddress = changeSection2->VirtualAddress + changeSection2->Misc.VirtualSize;
    }
 
    //修改NumberOfSections
    pPEHeader->NumberOfSections += 1;
 
    return pNewFileBuffer;
}
 
 
/*************************************************
函数功能:将RVA的值转换成FOA;
函数参数:pFileBuffer(LPVOID),virtualAddress(LPSTR)
函数返回值:fileAddress(LPVOID)
**************************************************/
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;
函数参数:pFileBuffer(LPVOID),virtualAddress(LPSTR)
函数返回值:fileAddress(LPVOID)
**************************************************/
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;
}
 
 
/*************************************************
函数功能:导入表注入;
函数参数:pFileBuffer(LPVOID)
函数返回值:无
**************************************************/
void MoveImportTable(LPVOID pFileBuffer){
    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;
    PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;//定位表目录
    PIMAGE_IMPORT_DESCRIPTOR importTableAddress = NULL;//定位导入表的真正位置
    LPVOID returnAddress = NULL;//记录RVAtoFOA的返回值
 
    if (pFileBuffer == NULL) {
        printf("文件写入内存失败!\n");
        return;
    }
 
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + 0x14);
    //定位导入表目录位置(第二个表)
    pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory;
    pDataDirectory += 0x1;
 
    //计算新增节的大小 = 原导入表大小 + 新增导入表大小 + INT + IAT + dllname + _IMAGE_IMPORT_BY_NAME大小
    DWORD sectionLength = pDataDirectory->Size + 0x28 +  + 0x10 + DLLNAMELENGTH + FUNCTIONNAMELENGTH + 0x2;
    sectionLength = AlignSize(sectionLength, pOptionHeader->FileAlignment);
 
    //新增一个节
    LPVOID pNewFileBuffer = AddLastSection(pFileBuffer, sectionLength);
 
    if (pNewFileBuffer == NULL){
        printf("新增节失败!\n");
        return;
    }
 
    pDosHeader = (PIMAGE_DOS_HEADER)pNewFileBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pNewFileBuffer + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + 0x14);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    //定位导入表目录位置(第二个表)
    pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory;
    pDataDirectory += 0x1;
 
    //定位到新节的位置和导入表的位置
    PDWORD pNewSection = (PDWORD)((pSectionHeader + pPEHeader->NumberOfSections - 1)->PointerToRawData + (DWORD)pNewFileBuffer);
    returnAddress = RvaToFoa(pNewFileBuffer, (LPSTR)pDataDirectory->VirtualAddress);
    importTableAddress = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)returnAddress + (DWORD)pNewFileBuffer);
 
    //复制原导入表
    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(pNewFileBuffer, (LPSTR)((DWORD)functionNameAddress - (DWORD)pNewFileBuffer));
    repairIatTable->u1.AddressOfData = repairIntTable->u1.Ordinal;
 
    //修正导入表Name、OriginalFirstThunk、FirstThunk
    importTableAddress->Name = (DWORD)FoaToRva(pNewFileBuffer, (LPSTR)((DWORD)dllNameAddress - (DWORD)pNewFileBuffer));
    importTableAddress->OriginalFirstThunk = (DWORD)FoaToRva(pNewFileBuffer, (LPSTR)((DWORD)repairIntTable - (DWORD)pNewFileBuffer));
    importTableAddress->FirstThunk = (DWORD)FoaToRva(pNewFileBuffer, (LPSTR)((DWORD)repairIatTable - (DWORD)pNewFileBuffer));
 
    //修正IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size
    pDataDirectory->VirtualAddress = (DWORD)FoaToRva(pNewFileBuffer, (LPSTR)((DWORD)pNewSection - (DWORD)pNewFileBuffer));
    pDataDirectory->Size += 0x14;
 
    //存盘
    FILE* pFile = NULL;
    DWORD newfilesize = 0;
    size_t newresult = 0;
 
    pFile = fopen(OUTPUTFILENAME, OUTPUTMODE);
    if (pFile == NULL) {
        printf("打开文件失败!\n");
        free(pNewFileBuffer);
        return;
    }
 
    newfilesize = CountFileSize(INPUTFILENAME, INPUTMODE) + sectionLength;
    newresult = fwrite(pNewFileBuffer, 1, newfilesize, pFile);
 
    if (newresult != newfilesize) {
        printf("写入文件失败!\n");
        fclose(pFile);
        free(pNewFileBuffer);
        return;
    }
 
    printf("存盘成功!\n");
    fclose(pFile);
    free(pNewFileBuffer);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
 
 
#define EVERYSECTIONTABLELENGTH 0x28
#define DLLNAME "InjectDll.dll"
#define DLLNAMELENGTH 0xE
#define FUNCTIONNAME "ExportFunction"
#define FUNCTIONNAMELENGTH 0xF
#define SECTIONNAME ".import"
#define INPUTFILENAME "D:/inject/ipmsg.exe"
#define INPUTMODE "rb"
#define OUTPUTFILENAME "D:/inject/test.exe"
#define OUTPUTMODE "wb"
 
 
/*************************************************
函数功能:读取一个文件,将文件内容写入到内存中;
函数参数:无
函数返回值:pFileBuffer(LPVOID)
**************************************************/
LPVOID FileBuffer() {
    FILE* pFile = NULL;    //文件指针
    LPVOID pFileBuffer = NULL; //存放数据内存的首地址
    DWORD filesize = 0;//记录文件大小
    size_t result = 0;//记录写入的返回结果
 
    //打开一个文件
    pFile = fopen(INPUTFILENAME, INPUTMODE);
    if (pFile == NULL) {
        printf("打开文件失败!\n");
        return NULL;
    }
 
    //统计文件的大小
    fseek(pFile, 0, SEEK_END);
    filesize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
 
    //申请一块内存
    pFileBuffer = malloc(filesize);
    if (pFileBuffer == NULL) {
        printf("申请内存失败!\n");
        fclose(pFile);
        return NULL;
    }
 
    //将文件数据写入内存
    result = fread(pFileBuffer, 1, filesize, pFile);
    if (result != filesize) {
        printf("文件写入内存失败!\n");
        fclose(pFile);
        free(pFileBuffer);
        return NULL;
    }
 
    fclose(pFile);
    return pFileBuffer;
}
 
/*************************************************
函数功能:返回对齐后的大小;
函数参数:virtualsize(原有长度),alignment(对齐方式)
函数返回值:ret(int型)
**************************************************/
DWORD AlignSize(DWORD virtualsize, DWORD alignment) {
    DWORD ret = alignment;
    if (virtualsize <= alignment) {
        return ret;
    }
    else {
        ret = (virtualsize / alignment) * alignment + alignment;
        return ret;
    }
}
 
/*************************************************
函数功能:计算一个filebuffer的大小;
函数参数:pFileBuffer(LPVOID)
函数返回值:filesize(int)
**************************************************/
DWORD CountFileBufferSize(LPVOID pFileBuffer) {
    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;
    DWORD filesize = 0;//记录文件大小
 
    if (pFileBuffer == NULL) {
        printf("文件写入内存失败!\n");
        return NULL;
    }
 
    //判读是否具有MZ标志                                                                                           
    if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) {
        printf("不具有MZ标志!\n");
        free(pFileBuffer);
        return 0;
    }
 
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
 
    //判断是否具有PE标志                                                                                           
    if (*(PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE) {
        printf("不具有PE标志\n");
        free(pFileBuffer);
        return 0;
    }
 
    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);
 
    //最后一个节头地址 + 最后一节大小
     filesize = (DWORD)((pSectionHeader + pPEHeader->NumberOfSections - 1)->PointerToRawData + (pSectionHeader + pPEHeader->NumberOfSections - 1)->SizeOfRawData);
    return filesize;
}
 
/*************************************************
函数功能:计算一个文件大小;
函数参数:filename(文件的绝对路径,LPSTR),mode(读取文件的形式,LPSTR)
函数返回值:filesize(int)
**************************************************/
DWORD CountFileSize(LPSTR filename, LPSTR mode) {
    FILE* pFile = NULL;
    LPSTR pFileBuffer = NULL;
    DWORD filesize = 0;
 
    //打开文件
    pFile = fopen(filename, mode);
    if (pFile == NULL) {
        printf("打开文件失败!\n");
        return NULL;
    }
 
    //统计文件大小
    fseek(pFile, 0, SEEK_END);
    filesize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
 
    fclose(pFile);
    return filesize;
}
 
 
/*************************************************
函数功能:PE文件尾部新增一个节;
函数参数:pFileBuffer(LPVOID),sectionLength(DWORD)
函数返回值:pNewFileBuffer(LPVOID)
**************************************************/
LPVOID AddLastSection(LPVOID pFileBuffer, DWORD sectionLength) {
    LPVOID pNewFileBuffer = 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 + 0x4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + 0x14);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
 
    //判断节表空间是否足够,节表后需要预留一个节表空间的位置
    if (pSectionHeader->PointerToRawData - (DWORD)(pSectionHeader + pPEHeader->NumberOfSections) < 0x50) {
        printf("节表空间不够!\n");
        free(pFileBuffer);
        return NULL;
    }
 
    //开辟新的内存
    DWORD filesize = CountFileBufferSize(pFileBuffer);
    pNewFileBuffer = malloc(filesize + sectionLength);
    if (pNewFileBuffer == NULL) {
        printf("申请内存失败!\n");
        free(pFileBuffer);
        return NULL;
    }
 
    //新内存初始化为0
    memset(pNewFileBuffer, 0, filesize + sectionLength);
 
    //拷贝原来的文件内容到新内存并释放旧文件内存
    memcpy(pNewFileBuffer, pFileBuffer, filesize);
    free(pFileBuffer);
 
    //结构体指针再次初始化
    pDosHeader = (PIMAGE_DOS_HEADER)pNewFileBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pNewFileBuffer + 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);
 
    //修改sizeofimage
    pOptionHeader->SizeOfImage += sectionLength;
 
    //copy第一个节表内容
    memcpy(pSectionHeader + pPEHeader->NumberOfSections, pSectionHeader, EVERYSECTIONTABLELENGTH);
 
    //修改新增的节表的项目
    PIMAGE_SECTION_HEADER changeSection1 = pSectionHeader + pPEHeader->NumberOfSections;//新增节表首地址
    PIMAGE_SECTION_HEADER changeSection2 = pSectionHeader + pPEHeader->NumberOfSections - 1;//新增节表的前一个节表首地址
    changeSection1->Misc.VirtualSize = sectionLength;//修改内存中的尺寸
    changeSection1->SizeOfRawData = sectionLength;//修改文件中的尺寸
    changeSection1->Characteristics = 0xc0000040;
    memcpy(changeSection1, SECTIONNAME, 0x8);//修改名字
 
    changeSection1->PointerToRawData = changeSection2->PointerToRawData + changeSection2->SizeOfRawData;
    if (changeSection2->SizeOfRawData > changeSection2->Misc.VirtualSize){
        changeSection1->VirtualAddress = changeSection2->VirtualAddress + changeSection2->SizeOfRawData;
    }
    else{
        changeSection1->VirtualAddress = changeSection2->VirtualAddress + changeSection2->Misc.VirtualSize;
    }
 
    //修改NumberOfSections
    pPEHeader->NumberOfSections += 1;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 5
支持
分享
最新回复 (8)
雪    币: 7379
活跃值: (4086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
虽然也写过,顶一下
2020-10-5 21:48
0
雪    币: 977
活跃值: (426)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
3
感谢大佬支持
2020-10-5 21:57
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
顶上了
2020-10-9 21:59
0
雪    币: 1657
活跃值: (291)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
希望多出精品,加油
2021-1-2 16:42
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
为啥我一个7MB的文件总是写入错误???尴尬了!
2021-1-2 23:39
0
雪    币: 197
活跃值: (209)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
你试试注入notepad.exe,我写的ipmsg和petool都能成功但是其他的软件都不成功
2021-7-2 21:29
0
雪    币: 391
活跃值: (355)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢分享~
2021-7-3 10:17
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
我现在有一个问题notepad.exe我成功注入了,在win10上可以成功弹窗,当我复制到win7后notepad不弹窗,但是可以正常打开。
2023-12-10 23:08
0
游客
登录 | 注册 方可回帖
返回
//