导入表注入

导入表注入

思路

构造新的节表,存放导入表结构,在这之后构造INT、IAT、IMAGE_IMPORT_BY_NAME结构。同时注意FOA到RVA的转化。

导入表注入
1.创建新节表并移动导入表copy(不需要修复)
2.创建导入表之后添加一个新导入表(在新表之后添加一个导入表大小的0作为导入表的结束标志)
3.追加INT和IAT表
4.构造IMAGE_IMPORT_BY_NAME结构
5.赋值
6.修正IMAGE_DATA_DIRECTORY的VirtualAddress 和Size

需要的函数

RVATOFOA
1.定位节表
2. 判断是否在文件头中 RVA小于最后一个节表的 末尾

ReadPEFile
1.文件流读取
2.计算文件的大小
3.分配内存
4.文件读取到内存中

(AddNewSection)
1.定位节表位置
2.定位最后一个节表的末尾
3.判断是否足够两个节表位置
4.新增节表并修改节表的属性、节区后添加空白区
//5.分配空间得到新句柄并将内存复制

ImportInject
1.原来导入表全部copy到新增节//导入表的数量计算 需要ImportTable地址进行循环
2.追加一个导入表 追加导入表结束标志(一个导入表的大小)
3.追加INT和IAT表
4.IMAGE_IMPORT_BY_NAME结构
5.将IMAGE_IMPORT_BY_NAME结构的RVA赋值给INT和IAT表中的第一项(IAT有INT的值得到)
6.分配空间存储DLL名称字符串 并将该字符串的RVA赋值给Name属性
7.修正IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size

代码演示

#include 
#include 
#include 

DWORD RVATOFOA(DWORD RVA,LPVOID pFileBuffer)
{
        DWORD FOA = NULL;
        PIMAGE_DOS_HEADER pDosHeader = NULL;
        PIMAGE_NT_HEADERS pNtHeaders = NULL;
        PIMAGE_FILE_HEADER pFileHeader = NULL;
        PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
        PIMAGE_SECTION_HEADER pSectionHeader = NULL;

        pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
        pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
        pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
        pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
        pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);

        if(RVA <= pOptionalHeader->SizeOfHeaders)
                return RVA;
        for(;RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);pSectionHeader++);//定位到所在节
        FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
        return FOA;

}
DWORD FOATORVA(DWORD FOA,LPVOID pFileBuffer)
{
        DWORD RVA = NULL;

        PIMAGE_DOS_HEADER pDosHeader = NULL;
        PIMAGE_NT_HEADERS pNtHeaders = NULL;
        PIMAGE_FILE_HEADER pFileHeader = NULL;
        PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
        PIMAGE_SECTION_HEADER pSectionHeader = NULL;

        pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
        pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
        pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
        pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
        pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);

        if(FOA <= pOptionalHeader->SizeOfHeaders)
                return FOA;
        for(;FOA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);pSectionHeader++);//定位到所在节
        RVA = FOA - pSectionHeader->PointerToRawData + pSectionHeader->VirtualAddress ;
        return RVA;
}


LPVOID ReadPEFile(LPSTR lpszFile)//读取文件
{
    FILE *pFile = NULL;//文件流
    DWORD fileSize = 0;//文件大小
    LPVOID pFileBuffer = NULL;//文件存储的缓冲区

    //打开文件
    pFile  = fopen(lpszFile,"rb");
    if(!pFile)
    {
        printf("无法打开exe文件!");
        return NULL;
    }
    //读取文件的大小
    //SEEK_SET: 文件开头SEEK_CUR: 当前位置;SEEK_END: 文件结尾
    fseek(pFile,0L,SEEK_END);//fseek用于得到文件位置指针当前位置相对于文件首的偏移字节数
    fileSize = ftell(pFile);
    fseek(pFile,0L,SEEK_SET);
    //分配缓冲区 pFileBuffer缓冲区的
    pFileBuffer = malloc(fileSize);
    if(!pFileBuffer)
    {
        printf("分配文件失败!");
        fclose(pFile);
        return NULL;
    }

    //将文件读入缓冲区
    size_t n = fread(pFileBuffer,fileSize,1,pFile);
    if(!n)
    {
        printf("读取数据失败!");
        free(pFileBuffer);
        fclose(pFile);
        return NULL;
    }
    //关闭文件
    fclose(pFile);
    return pFileBuffer;
}

//导入表注入
VOID ImportInject(LPVOID pFileBuffer)
{
    PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头
    PIMAGE_NT_HEADERS pNtHeaders = NULL;//NT头
    PIMAGE_FILE_HEADER pFileHeader = NULL;//标准PE头
    PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;//拓展PE头
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节表
    PIMAGE_SECTION_HEADER pNewSec = NULL;//新节表结构
    PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; //导出表结构体
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
    pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
    DWORD dwNumberOfDll = 0;

    //判断是否有足够的空间添加节表
    if ((pOptionalHeader->SizeOfHeaders - ((DWORD)pSectionHeader - (DWORD)pFileBuffer + pFileHeader->NumberOfSections * 40)) < 80)
    {
            printf("空间不足");
            return FALSE;
    }

    //新增节表结构
    pNewSec = (PIMAGE_SECTION_HEADER)(pSectionHeader + pFileHeader->NumberOfSections);

    //修改节表内容
    memcpy(pNewSec->Name,".import",8);//修改节表名

    PIMAGE_SECTION_HEADER upSecHeader = (PIMAGE_SECTION_HEADER)(pSectionHeader + pFileHeader->NumberOfSections-1);

    if(upSecHeader->Misc.VirtualSize > upSecHeader->SizeOfRawData)//修改节表VrituallAddress
    {
            pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->Misc.VirtualSize;
    }else{
            pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->SizeOfRawData;
    }

    pNewSec->SizeOfRawData = 0x1000;//新增的节区的大小
    pNewSec->PointerToRawData = upSecHeader->PointerToRawData + upSecHeader->SizeOfRawData;//文件中的偏移
    pNewSec->Characteristics = 0xc0000040;//修改属性(可执行)
    //在新增节表后增加40个字节的空白区
    memset(pNewSec+1, 0, 40);
    //修改NT头属性

    pFileHeader->NumberOfSections += 1;//修改NumberOfSection数量
    pOptionalHeader->SizeOfImage += 0x1000;//修改SizeOfImage大小

    LPVOID NewBuffer = malloc(pOptionalHeader->SizeOfImage);//申请内存
    memset(NewBuffer, 0, pOptionalHeader->SizeOfImage);//初始化内存

    memcpy(NewBuffer, pFileBuffer,pOptionalHeader->SizeOfImage);//复制内存
    //遍历得到模块的个数
    PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + RVATOFOA(pOptionalHeader->DataDirectory[1].VirtualAddress,pFileBuffer));
    while(pImportTable->Name)
    {
        dwNumberOfDll++;//导入表的数量
        pImportTable++;

    }
    printf("导入表的数量:%d\n",dwNumberOfDll);
    pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + RVATOFOA(pOptionalHeader->DataDirectory[1].VirtualAddress,pFileBuffer));//指向导入表的位置
    //原来导入表copy到新增节
    LPVOID pNewSecAddr = (LPVOID)((DWORD)NewBuffer + pNewSec->PointerToRawData);//定位节表的位置
    /*memcpy(pNewSecAddr,pImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR)*dwNumberOfDll);//复制导入表的内容
    printf("%x\n",pNewSecAddr);*/
    PIMAGE_IMPORT_DESCRIPTOR ImportEnd = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewSecAddr + 20 * dwNumberOfDll);//定位复制后的导入表之后
    /*printf("%x\n",InsertImport);
    printf("%x\n",sizeof(PIMAGE_IMPORT_DESCRIPTOR));*/
    int i = 0;
    while((pImportTable+i) -> OriginalFirstThunk){
        memcpy(pNewSecAddr, (LPVOID)(pImportTable+i), 20);
        pNewSecAddr = (LPVOID)((DWORD)pNewSecAddr + 20);
        i++;
    }//复制两个导入表
    pNewSecAddr = (LPVOID)((DWORD)NewBuffer + pNewSec->PointerToRawData);//定位节表的位置
    //新增一个导入表
    memset(ImportEnd,0,20);
    //设置导入表的成员
    ImportEnd->ForwarderChain = 0;
    ImportEnd->TimeDateStamp = 0;
    //设置导入结束标记  为一个导入表结构的0
    LPVOID pInsertEnd = (LPVOID)((DWORD)ImportEnd + 20);
    memset(pInsertEnd,0,20);
    //追加INT
    PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)((DWORD)pInsertEnd + 20);
    //设置INT结束标志
    memset(pINT + 1,0,sizeof(PIMAGE_THUNK_DATA));
    //设置IMPORT_BY_NAME
    PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pINT + 8);//定位INT表之后  只需要一个函数
    pImportByName->Hint = 0;
    strcpy((char*)pImportByName->Name,"ExportFunction");//设置函数名
    //设置INT表中得到值
    *((PDWORD)pINT) = FOATORVA((DWORD)pImportByName - (DWORD)NewBuffer,NewBuffer);
    //设置IAT表
    PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)((DWORD)pImportByName + 3 + strlen("ExportFunction"));
    memcpy(pIAT,pINT,8);
    //dll名称字符串
    LPVOID DllName = (LPVOID)((DWORD)pIAT + 8);
    strcpy(DllName,"InjectDll.dll");
    //设置导入表属性
    ImportEnd->FirstThunk = FOATORVA((DWORD)pIAT - (DWORD)NewBuffer,NewBuffer);
    ImportEnd->OriginalFirstThunk = FOATORVA((DWORD)pINT - (DWORD)NewBuffer,NewBuffer);
    ImportEnd->Name = FOATORVA((DWORD)DllName - (DWORD)NewBuffer,NewBuffer);
    //更新目录表导入表的位置
    pDosHeader = (PIMAGE_DOS_HEADER)NewBuffer;
    pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
    pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
    pOptionalHeader->DataDirectory[1].VirtualAddress = FOATORVA((DWORD)pNewSecAddr - (DWORD)NewBuffer,NewBuffer);
    FILE* fp = fopen("D:\\test\\HelloWorld.exe","wb+");//读入w文件流
    fwrite(NewBuffer,pOptionalHeader->SizeOfImage,1,fp);
    fclose(fp);
    return;
}
int main()
{
    LPSTR lpszFile = "D:\\test\\HelloWorld.exe";
    LPVOID pFileBuffer = ReadPEFile(lpszFile);
    if(pFileBuffer)
    {
        printf("读取文件成功!\n");
    }
    ImportInject(pFileBuffer);
    return 0;
}

导入表注入_第1张图片
导入表注入_第2张图片
导入表注入_第3张图片
导入表注入_第4张图片

你可能感兴趣的:(导入表注入)