PE-导入表注入

admin 2024年5月13日01:56:47评论3 views字数 8803阅读29分20秒阅读模式
实现效果:

PE-导入表注入

// 滴水三期3.31导入表注入.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include <iostream>#include <Windows.h>#include <cstring>#include <iomanip>using namespace std;//向上取值函数size_t AlignUp(size_t value, size_t alignment) {    return (value + alignment - 1) & ~(alignment - 1);}//得到PE文件大小long GetSize(char* fileName) {    FILE* file = NULL;    errno_t err = fopen_s(&file, fileName, "rb");    if (err != 0) {        cout << "文件打开失败!" << endl;        fclose(file);        return 0;    }    long fileSize = 0;    fseek(file, 0, SEEK_END);    fileSize = ftell(file);    fseek(file, 0, SEEK_SET);    fclose(file);    return fileSize;}//RVA转FOADWORD RVA_TO_FOA(char* fileBuffer, long long RVAaddress) {    PIMAGE_DOS_HEADER fileDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;    PIMAGE_NT_HEADERS fileNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + fileDosHeader->e_lfanew);    if (fileNTHeader->Signature != IMAGE_NT_SIGNATURE) {        cout << "PE的NT头错误!" << endl;        return 0;    }    PIMAGE_FILE_HEADER fileFileHeader = &(fileNTHeader->FileHeader);    PIMAGE_OPTIONAL_HEADER fileOptionHeader = &(fileNTHeader->OptionalHeader);    PIMAGE_SECTION_HEADER fileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)fileOptionHeader + fileFileHeader->SizeOfOptionalHeader);    int sectionNum = 0;    for (int i = 0; i < fileFileHeader->NumberOfSections; i++) {        if (RVAaddress >= (fileSectionHeader + i)->VirtualAddress && RVAaddress < (fileSectionHeader + i)->VirtualAddress + (fileSectionHeader + i)->SizeOfRawData) {            sectionNum = i;            break;        }    }    long long offsetSize = RVAaddress - (fileSectionHeader + sectionNum)->VirtualAddress;    DWORD fileAdderss = (DWORD)((fileSectionHeader + sectionNum)->PointerToRawData + offsetSize);    //cout << hex <<"RVAaddress:"<< RVAaddress<<"转换====》" << "文件地址:" << fileAdderss << endl;    return fileAdderss;}//FOA转RVA//这里的FOA要减去fileBufferDWORD FOA_TO_RVA(char* fileBuffer, long long FOAaddress) {    PIMAGE_DOS_HEADER fileDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;    PIMAGE_NT_HEADERS fileNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + fileDosHeader->e_lfanew);    if (fileNTHeader->Signature != IMAGE_NT_SIGNATURE) {        cout << "PE的NT头错误X!" << endl;        return 0;    }    PIMAGE_FILE_HEADER fileFileHeader = &(fileNTHeader->FileHeader);    PIMAGE_OPTIONAL_HEADER fileOptionHeader = &(fileNTHeader->OptionalHeader);    PIMAGE_SECTION_HEADER fileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)fileOptionHeader + fileFileHeader->SizeOfOptionalHeader);    int sectionNum = 0;    for (int i = 0; i < fileFileHeader->NumberOfSections; i++) {        if (FOAaddress >= (fileSectionHeader + i)->PointerToRawData && FOAaddress < (fileSectionHeader + i)->PointerToRawData + (fileSectionHeader + i)->SizeOfRawData) {            sectionNum = i;            break;        }    }    long long offsetSize = FOAaddress - (fileSectionHeader + sectionNum)->PointerToRawData;    DWORD fileAdderss = (DWORD)((fileSectionHeader + sectionNum)->VirtualAddress + offsetSize);    //cout << hex <<"RVAaddress:"<< RVAaddress<<"转换====》" << "文件地址:" << fileAdderss << endl;    return fileAdderss;}//导入表注入,我们为了方便和一劳永逸,直接移动导入表到新节void ImportTableInjectDll(char* fileName) {    //先得到大小    long fileSize = GetSize(fileName);    //得到大小后,再申请内存 这里为了简单,我就不重新申请了内存了,所以,这里就直接将后面需要扩大的节的大小写进来    char* fileBuffer = (char*)malloc(fileSize + 0x1000);    if (!fileBuffer) {        cout << "RVA_TO_FOA---->fileBuffer内存申请失败!" << endl;        free(fileBuffer);        return;    }    //如果内存申请成功,那么就要读fileBuffer,读之前,先打开文件    FILE* file = NULL;    errno_t err = fopen_s(&file, fileName, "rb");    if (err != 0) {        cout << "文件打开失败!" << endl;        free(fileBuffer);        fclose(file);        return;    }    //如果打开也没问题,那么就需要真正的开始读了    fread(fileBuffer, 1, fileSize, file);    if ((*(PWORD)fileBuffer) != IMAGE_DOS_SIGNATURE) {        cout << "PE文件格式错误!" << endl;;        free(fileBuffer);        fclose(file);        return;    }    PIMAGE_DOS_HEADER fileDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;    PIMAGE_NT_HEADERS fileNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + fileDosHeader->e_lfanew);    if (fileNTHeader->Signature != IMAGE_NT_SIGNATURE) {        cout << "PE的NT头错误!" << endl;        free(fileBuffer);        fclose(file);        return;    }    PIMAGE_FILE_HEADER fileFileHeader = &(fileNTHeader->FileHeader);    PIMAGE_OPTIONAL_HEADER fileOptionHeader = &(fileNTHeader->OptionalHeader);    PIMAGE_SECTION_HEADER fileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)fileOptionHeader + fileFileHeader->SizeOfOptionalHeader);    //添加一个节,在这里,我们添加节就不复制添加了,根据实际大小来添加    int importTableSize = fileOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;    char* lastSection = (((char*)(fileSectionHeader + (fileFileHeader->NumberOfSections - 1))) + 40);    bool isZero = true;    for (int i = 0; i < 80; i++) {        if (*(lastSection + i) != 0x00) {            isZero = false;            break;        }    }    //isZero还为真时,就说明有两个节表80个字节的空间留给我们    if (isZero) {        cout << "可以添加一个节表!" << endl;        //这里解释一下,因为是指针,所以根据指针的特性,只需要从第一个节复制到最后一个节,大小是40        memcpy(lastSection, fileSectionHeader, 40);        //复制成功后,修改节表的属性        //为了方便理解,这里直接设置一个指针变量指向添加的节表,也可以不设置,都以fileSectionHeader+fileFileHeader->NumberOfSections这种解释        PIMAGE_SECTION_HEADER llastSectionHeader = (PIMAGE_SECTION_HEADER)((char*)(fileSectionHeader + (fileFileHeader->NumberOfSections - 1)) + 40);        PIMAGE_SECTION_HEADER lastSectionHeader = fileSectionHeader + (fileFileHeader->NumberOfSections - 1);        //修改内存大小为适合的大小        llastSectionHeader->Misc.VirtualSize = importTableSize;        //修改对齐后的大小为适当的大小,需要满足对齐后的大小        llastSectionHeader->SizeOfRawData = AlignUp(importTableSize, fileOptionHeader->SectionAlignment);        llastSectionHeader->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;        cout << "lastSectionHeader->SizeOfRawData:" << hex << lastSectionHeader->SizeOfRawData << "===" << AlignUp(lastSectionHeader->SizeOfRawData, fileOptionHeader->SectionAlignment) << endl;        //修改VirtualAddress的大小,要满足内存对齐        llastSectionHeader->VirtualAddress = AlignUp(lastSectionHeader->VirtualAddress + lastSectionHeader->SizeOfRawData,fileOptionHeader->SectionAlignment);        //修改VirtualAddress的大小,要满足磁盘对齐        llastSectionHeader->PointerToRawData = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;        //节表的其他属性不需要修改,现在再修改节表数量        fileFileHeader->NumberOfSections = fileFileHeader->NumberOfSections + 1;        //修改SizeOfImage,SizeOfImage等于原来的sizeOfImage加上新添加的节的对齐后的大小,满足内存对齐        fileOptionHeader->SizeOfImage = AlignUp(fileOptionHeader->SizeOfImage + llastSectionHeader->SizeOfRawData, fileOptionHeader->SectionAlignment);        //节表修改完毕,可以开始注入        //在之前,先把添加的节内容设置为0        memset(llastSectionHeader->PointerToRawData + fileBuffer, 0, 0x1000);        //设置为0之后,开始移动导出表,这里需要注意一下,导出表        PDWORD copyBeginDST = (PDWORD)(llastSectionHeader->PointerToRawData + (DWORD_PTR)fileBuffer);        DWORD exportFOA = RVA_TO_FOA(fileBuffer,fileOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);        cout << "exportFOA:" << exportFOA << endl;        PDWORD copyBeginSRC =(PDWORD) ((DWORD_PTR)fileBuffer + exportFOA);        //复制        memcpy(copyBeginDST, copyBeginSRC, importTableSize);        //因为都是0,直接在后面添加一个就行        PIMAGE_IMPORT_DESCRIPTOR exportTable = (PIMAGE_IMPORT_DESCRIPTOR)copyBeginSRC;        memcpy((char*)copyBeginDST + importTableSize - sizeof(IMAGE_IMPORT_DESCRIPTOR), copyBeginSRC, sizeof(IMAGE_IMPORT_DESCRIPTOR));        //添加完后,在修改里面的值        fileOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = llastSectionHeader->VirtualAddress;        PIMAGE_IMPORT_DESCRIPTOR newLastExport = (PIMAGE_IMPORT_DESCRIPTOR)((char*)copyBeginDST + importTableSize - sizeof(IMAGE_IMPORT_DESCRIPTOR));        newLastExport->OriginalFirstThunk = llastSectionHeader->VirtualAddress + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR);        PDWORD newINT = (PDWORD)(fileBuffer + llastSectionHeader->PointerToRawData + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR));        *newINT = llastSectionHeader->VirtualAddress + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR);        auto tmp = RVA_TO_FOA(fileBuffer, llastSectionHeader->VirtualAddress);        PIMAGE_IMPORT_BY_NAME newINTName =(PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)fileBuffer+ RVA_TO_FOA(fileBuffer, *newINT));        char functionName[] = "ExportFunction";        size_t functionNameLength = strlen(functionName) + 1;        cout << "functionNameLength:" << hex<<functionNameLength << endl;        memcpy(newINTName->Name, functionName, functionNameLength);        newLastExport->FirstThunk = llastSectionHeader->VirtualAddress + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR);        PDWORD newFirstThunk = (PDWORD)(fileBuffer + llastSectionHeader->PointerToRawData + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR));        *newFirstThunk = *newINT;        //修改名称        char name[] = "InjectDll.dll";        size_t nameLength = strlen(name) + 1;        memcpy(fileBuffer + llastSectionHeader->PointerToRawData + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR)+ sizeof(IMAGE_IMPORT_DESCRIPTOR), name, nameLength);        newLastExport->Name = llastSectionHeader->VirtualAddress + importTableSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR) + sizeof(IMAGE_IMPORT_DESCRIPTOR)+ sizeof(IMAGE_IMPORT_DESCRIPTOR);        fileOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = importTableSize + 20;    }    //好了之后,开始存盘    FILE* newFile = NULL;    errno_t newErr = fopen_s(&newFile, "C:\Users\zyjsuper\Desktop\test\IPMsgdll.exe", "wb");    if (newErr != 0) {        std::cout << "newFile创建失败!" << std::endl;        fclose(newFile);        fclose(file);        free(fileBuffer);        return;    }    fwrite(fileBuffer, 1, fileSize + 0x1000, newFile);    std::cout << "写入成功!" << std::endl;    fclose(newFile);    free(fileBuffer);    fclose(file);}int main(){    char fileName[] = "C:\Users\zyjsuper\Desktop\test\IPMsg.exe";    //PrintImportTable(fileName);    ImportTableInjectDll(fileName);    cout<<hex<<sizeof(IMAGE_IMPORT_DESCRIPTOR);}

原文始发于微信公众号(loochSec):PE-导入表注入

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月13日01:56:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PE-导入表注入https://cn-sec.com/archives/2073996.html

发表评论

匿名网友 填写信息