首页
论坛
课程
招聘
[调试逆向] [系统底层] 导入表注入
2020-6-28 06:56 1287

[调试逆向] [系统底层] 导入表注入

2020-6-28 06:56
1287

最近正好复习到这里,顺便分享一下导入表注入dll的代码。
参考:滴水三期

 

如果代码中有错误的地方,还希望大牛指正。

#include<stdio.h>
#include<Windows.h>
#include "head.h"

DWORD NewSectionSize = 0x1000;

int main() {

    CHAR FilePath[] = ""; //读文件
    CHAR wFilePath[] = ""; //写文件
    FILE* fp = fopen(FilePath, "rb");
    FILE* wfp = fopen(wFilePath, "wb");
    //定义一个新增节的大小

    DWORD FileSize = _GetFileSize(fp)+ NewSectionSize;

    LPSTR ReadFile = (LPSTR)malloc(FileSize);
    memset(ReadFile, 0, FileSize);
    fread(ReadFile, FileSize, 1, fp);

    //初始化PE结构
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNtHeaders = NULL;
    PIMAGE_FILE_HEADER pFileHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pOptHeader = NULL;
    PIMAGE_SECTION_HEADER pSecHeader = NULL;
    PIMAGE_IMPORT_DESCRIPTOR pImpDes = NULL;

    pDosHeader = (PIMAGE_DOS_HEADER)((DWORD)ReadFile);
    pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
    pOptHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSecHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptHeader + pFileHeader->SizeOfOptionalHeader);

    //导入表注入
    ImpDesInj(pDosHeader, pFileHeader, pOptHeader, pSecHeader);

    fwrite(ReadFile, FileSize, 1, wfp);
    fclose(fp);
    fclose(wfp);
    return 0;

}

DWORD _GetFileSize(FILE* fp) {
    //获取文件大小
    fseek(fp, 0, SEEK_END);
    DWORD FileSize = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    return FileSize;
}

DWORD RvaToFoa(PIMAGE_DOS_HEADER pDosHeader, PIMAGE_FILE_HEADER pFileHeader, PIMAGE_OPTIONAL_HEADER pOptHeader, PIMAGE_SECTION_HEADER pSecHeader, DWORD Addr) {

    if (Addr < pOptHeader->SizeOfHeaders) {
        return (DWORD)pDosHeader + Addr;
    }

    PIMAGE_SECTION_HEADER pSecHeader2;

    for (int i = 0; i < pFileHeader->NumberOfSections; i++) {
        pSecHeader2 = (PIMAGE_SECTION_HEADER)((DWORD)pSecHeader + i * 40);
        if (Addr >= pSecHeader2->VirtualAddress && Addr < pSecHeader2->VirtualAddress + pSecHeader2->SizeOfRawData) {
            Addr -= pSecHeader2->VirtualAddress;
            Addr += pSecHeader2->PointerToRawData;
            return Addr + (DWORD)pDosHeader;
        }
    }

    return 0;
}

DWORD FoaToRva(PIMAGE_DOS_HEADER pDosHeader, PIMAGE_FILE_HEADER pFileHeader, PIMAGE_OPTIONAL_HEADER pOptHeader, PIMAGE_SECTION_HEADER pSecHeader, DWORD Addr) {

    Addr -= (DWORD)pDosHeader;

    if (Addr < pOptHeader->SizeOfHeaders) {
        return Addr;
    }
    PIMAGE_SECTION_HEADER pSecHeader2;

    for (int i = 0; i < pFileHeader->NumberOfSections; i++) {
        pSecHeader2 = (PIMAGE_SECTION_HEADER)((DWORD)pSecHeader + i * 40);
        if (Addr >= pSecHeader2->PointerToRawData && Addr < pSecHeader2->PointerToRawData + pSecHeader2->SizeOfRawData) {
            Addr += pSecHeader2->VirtualAddress;
            Addr -= pSecHeader2->PointerToRawData;
            return Addr;
        }
    }
    return 0;
}

VOID AddNewSection(PIMAGE_DOS_HEADER pDosHeader,PIMAGE_FILE_HEADER pFileHeader,PIMAGE_OPTIONAL_HEADER pOptHeader,PIMAGE_SECTION_HEADER pSecHeader,DWORD NewSectionSize) {

    /*
        增加一个新的节表,下面写一下添加节的基本步骤
            1、复制节添加到最后
            2、修改新增节表的属性
            3、修改PIMAGE_FILE_HEADER 属性
            4、修改PIMAGE_OPTIONAL_HEADER 属性

    */

    //复制第一个节到最后(注意最后一个节的后面还需要留出一个节大小的0地址空间,因为随便复习一下,没有进行判断) 
    PIMAGE_SECTION_HEADER pSecHeaderEnd = (PIMAGE_SECTION_HEADER)_GetSpecialSection(pFileHeader, pSecHeader, pFileHeader->NumberOfSections);

    memcpy((LPVOID)((DWORD)pSecHeaderEnd + 40), pSecHeader, 40);

    //修改PIMAGE_FILE_HEADER属性
    pFileHeader->NumberOfSections++;

    PIMAGE_SECTION_HEADER pSecHeaderNew = (PIMAGE_SECTION_HEADER)(_GetSpecialSection(pFileHeader, pSecHeader, pFileHeader->NumberOfSections));

    //修改新增节表属性
    strcpy((LPSTR)pSecHeaderNew->Name, ".new");
    pSecHeaderNew->VirtualAddress = (_GetAliAddr(pOptHeader, pSecHeaderEnd->VirtualAddress + pSecHeaderEnd->SizeOfRawData));
    pSecHeaderNew->PointerToRawData = pSecHeaderEnd->PointerToRawData + pSecHeaderEnd->SizeOfRawData;
    pSecHeaderNew->SizeOfRawData = NewSectionSize;
    pSecHeaderNew->Misc.VirtualSize = NewSectionSize;

    //修改PIMAGE_OPTIONAL_HEADER属性
    pOptHeader->SizeOfImage += NewSectionSize;

}

DWORD _GetSpecialSection(PIMAGE_FILE_HEADER pFileHeader,PIMAGE_SECTION_HEADER pSecHeader,DWORD SecNum) {
    //获取指定的节表
    SecNum--;
    if (SecNum<0 && SecNum>pFileHeader->NumberOfSections-1) {
        printf("GetSpecialSectionError\n");
        return 0;
    }
    return (DWORD)pSecHeader + SecNum * sizeof(IMAGE_SECTION_HEADER);
}

DWORD _GetAliAddr(PIMAGE_OPTIONAL_HEADER pOptHeader, DWORD Addr) {
    //添加新节的时候内存补齐
    if ((Addr % pOptHeader->SectionAlignment) == 0) {
        return Addr;
    }

    return ((Addr / pOptHeader->SectionAlignment) + 1) * pOptHeader->SectionAlignment;

}


VOID ImpDesInj(PIMAGE_DOS_HEADER pDosHeader,PIMAGE_FILE_HEADER pFileHeader,PIMAGE_OPTIONAL_HEADER pOptHeader,PIMAGE_SECTION_HEADER pSecHeader) {

    PIMAGE_IMPORT_DESCRIPTOR pImpDes = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pOptHeader->DataDirectory[1].VirtualAddress));

    //新增节表
    AddNewSection(pDosHeader, pFileHeader, pOptHeader, pSecHeader, NewSectionSize);

    //获取第一个导入表
    pImpDes = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pOptHeader->DataDirectory[1].VirtualAddress));

    //获取新加的节表
    PIMAGE_SECTION_HEADER pSecHeaderNew = (PIMAGE_SECTION_HEADER)((DWORD)_GetSpecialSection(pFileHeader, pSecHeader, pFileHeader->NumberOfSections));
    //新表开始地址(FOA)
    DWORD NewSectionAddr = (DWORD)pDosHeader + pSecHeaderNew->PointerToRawData;
    memset((LPSTR)NewSectionAddr, 0, pSecHeaderNew->SizeOfRawData);
    //复制导入表到新加的表中
    while (pImpDes->FirstThunk) {
        memcpy((LPSTR)NewSectionAddr, pImpDes, sizeof(IMAGE_IMPORT_DESCRIPTOR));
        NewSectionAddr += sizeof(IMAGE_IMPORT_DESCRIPTOR);
        pImpDes++;
    }

    pImpDes--;//这里是返回最后一个导入表
    memcpy((LPSTR)NewSectionAddr, pImpDes, sizeof(IMAGE_IMPORT_DESCRIPTOR));//复制最后一个导入表到最后(留出相应的空间即可)

    PIMAGE_IMPORT_DESCRIPTOR pImpDesNew = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)NewSectionAddr); //新加的导入表
    NewSectionAddr += sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2; //留出一个导入表大小的内存

    //到这里复制导入表的东西就完成了,下面复制INT、IAT表

    //将要添加IAT、INT 表的地址
    DWORD Addr_INT = NewSectionAddr;
    DWORD Addr_IAT = Addr_INT + sizeof(IMAGE_THUNK_DATA) * 2;

    NewSectionAddr += sizeof(IMAGE_THUNK_DATA) * 4;


    CHAR DllName[] = "DllName/DllPath";
    DWORD DllAddr = NewSectionAddr;

    strcpy((LPSTR)DllAddr, DllName);

    NewSectionAddr += strlen(DllName) + 1;

    DWORD AddressOfData = NewSectionAddr;

    CHAR FuncName[] = "DllFunc";
    memset((LPSTR)AddressOfData, 0, 2);//前面留出两个字节
    memcpy((LPSTR)AddressOfData + 2, FuncName, strlen(FuncName)+1);

    PIMAGE_THUNK_DATA pThuData_INT = NULL;
    PIMAGE_THUNK_DATA pThuData_IAT = NULL;

    pThuData_IAT = (PIMAGE_THUNK_DATA)((DWORD)Addr_IAT);
    pThuData_INT = (PIMAGE_THUNK_DATA)((DWORD)Addr_INT);

    //下面的地址要从FOA转为RVA
    pThuData_IAT->u1.AddressOfData = FoaToRva(pDosHeader, pFileHeader, pOptHeader, pSecHeader, AddressOfData);
    pThuData_INT->u1.AddressOfData = FoaToRva(pDosHeader, pFileHeader, pOptHeader, pSecHeader, AddressOfData);

    pImpDesNew->FirstThunk = FoaToRva(pDosHeader, pFileHeader, pOptHeader, pSecHeader, Addr_IAT);
    pImpDesNew->OriginalFirstThunk = FoaToRva(pDosHeader, pFileHeader, pOptHeader, pSecHeader, Addr_INT);
    pImpDesNew->Name = FoaToRva(pDosHeader, pFileHeader, pOptHeader, pSecHeader, DllAddr);

    pOptHeader->DataDirectory[1].VirtualAddress = pSecHeaderNew->VirtualAddress;
    pOptHeader->DataDirectory[1].Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);

    pImpDes = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pOptHeader->DataDirectory[1].VirtualAddress));

    pSecHeaderNew->Characteristics = 0xc0000020;

    PIMAGE_THUNK_DATA pThuData_IAT_TEST = NULL;
    PIMAGE_THUNK_DATA pThuData_INT_TEST = NULL;

    while (pImpDes->FirstThunk) {

        printf("%s\n", RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pImpDes->Name));
        pThuData_IAT_TEST = (PIMAGE_THUNK_DATA)((DWORD)RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pImpDes->FirstThunk));
        while (pThuData_IAT_TEST->u1.Function) {
            printf("\t%s\n", RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pThuData_IAT_TEST->u1.AddressOfData + 2));
            pThuData_IAT_TEST++;
        }

        pImpDes++;
    }
}

[培训]12月3日2020京麒网络安全大会《物联网安全攻防实战》训练营,正在火热报名中!地点:北京 · 新云南皇冠假日酒店

最后于 2020-6-28 11:13 被13l00m编辑 ,原因: 代码出现问题
收藏
点赞1
打赏
分享
最新回复 (5)
雪    币: 1993
活跃值: 活跃值 (186)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
mb_ldtiaylu 活跃值 2020-6-28 09:42
2
1
申请的内存没填0,while (pThuData_IAT_TEST->u1.Function)这句终止条件有问题
printf("\t%s\n", RvaToFoa(pDosHeader, pFileHeader, pOptHeader, pSecHeader, pThuData_IAT_TEST->u1.AddressOfData + 2)); 这句%s有问题
雪    币: 1302
活跃值: 活跃值 (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whitehack 活跃值 2020-6-28 09:51
3
1
感谢大佬分享
雪    币: 176
活跃值: 活跃值 (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13l00m 活跃值 2020-6-28 10:54
4
0
mb_ldtiaylu 申请的内存没填0,while (pThuData_IAT_TEST->u1.Function)这句终止条件有问题 printf("\t%s\n", RvaToFoa(pDo ...
代码已经更新,感谢大牛指正!终止条件有问题应该是内存没有初始化造成的,大牛如果有更好的方法可以说一下,学习学习
雪    币: 1993
活跃值: 活跃值 (186)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
mb_ldtiaylu 活跃值 2020-6-28 11:04
5
0
13l00m 代码已经更新,感谢大牛指正!终止条件有问题应该是内存没有初始化造成的,大牛如果有更好的方法可以说一下,学习学习
使用memcpy((LPSTR)NewSectionAddr, pImpDes, pOptHeader->DataDirectory[1].Size));  要省事多了吧
雪    币: 176
活跃值: 活跃值 (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13l00m 活跃值 2020-6-28 11:16
6
0
mb_ldtiaylu 使用memcpy((LPSTR)NewSectionAddr, pImpDes, pOptHeader->DataDirectory[1].Size)); 要省事多了吧
哈哈哈,确实
游客
登录 | 注册 方可回帖
返回