QQ_93B2B7 发表于 2021-2-22 21:13

申请会员ID:存钱买板子【申请通过】

1.申请ID:存钱买板子
2.个人邮箱:yuan6900956@163.com
3.原创技术文章:PE导入表注入DLL

分享一下32位PE文件如何利用导入表注入DLL,以及原创C代码。

1.原理:
   当一个程序启动的时候,它所依赖的各种DLL也会被加载,而当一个DLL被加载或者销毁的时候,系统会调用这个DLL的DllMain函数。
   而这些个需要加载的DLL都是什么,都提供了哪些函数,都被记录在了导入表里面。所以我们可以在导入表里面新加一个要被注入的DLL信息,以此达到我们的目的。

2.实现步骤:
       1>把PE文件加载到FileBuffer:       2>遍历一下原来有多少个DLL,后面复制的时候会它求尺寸:(注意:一个PE文件可能有多个导入表结构,最后有一个全0结构标志结束)
       3>新增一个节:(注意:新增节必须有可执行的属性)
   4>给DLL名字字符串和导入函数名字字符串赋值:(注意:不要忘了字符串末尾的0)
   5>给_IMAGE_THUNK_DATA32结构(INT表和IAT所指向的)赋值(这个结构最高位为1说明是以序号导出,否则以名字导出,此时为IMAGE_IMPORT_BY_NAME结构的RVA):
   6>拷贝原导入表到新增节:(注意:不要忘了最后那个全0结构)
   7>给新导入表赋值:(注意:这里面的地址都为RVA)
   8>修正目录项第二个的RVA:
   9>存盘

      注入后新增节的内存图:


3.注入后效果:


       把加载时弹窗的DLL注入到CE里效果:



4.完整C代码:(VS2010)
Inject.cpp:
#include "InjectH.h"
#define InPutPath "E:\\测试区\\ce.exe"                                                //输入文件目录
#define OutPutPath "E:\\测试区\\ce_new.exe"                                        //输出文件目录
#define SizeOfNewSection 0x1000                                                                //新增节尺寸

_PIMAGE_DOS_HEADER DosHeader = NULL;                                                      //DOS头指针
_PIMAGE_NT_HEADER NtHeader = NULL;                                                                //NT头指针
_PIMAGE_FILE_HEADER FileHeader = NULL;                                                      //标准PE头指针
_PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;                                        //可选PE头指针
_PIMAGE_SECTION_HEADER pSectionHeader = NULL;                                        //节表指针
_PIMAGE_IMPORT_DESCRIPTOR pImportDesriptor = NULL;                              //导入表指针

BYTE DllName[] = "InjectDll.dll";                        //要注入的DLL名字
BYTE ImportFunName[] = "ExportFunction";      //DLL中函数名
BYTE NewSectionName[] = "Fly";                              //新增节名字

//加载PE,加载到FileBuffer
size_t LoadPE(STR Path , PBYTE* Buffer)
{
      //打开文件
      FILE* fp = fopen(Path,"rb");
      if(!fp)
      {
                printf("文件打开失败\n");
                return 0;
      }

      //获取文件尺寸
      fseek(fp,0,SEEK_END);
      size_t FileSize = ftell(fp);
      fseek(fp,0,SEEK_SET);

      //申请文件缓冲区
      BYTE* pFileBuffer = (BYTE*)malloc(FileSize);
      if( !pFileBuffer )
      {
                printf("内存申请失败!\n");
                fclose(fp);
                return 0;
      }
      //内存拷贝
      memset(pFileBuffer,0,FileSize);

      if(!fread(pFileBuffer,FileSize,1,fp))
      {
                printf("写入缓冲区失败!\n");
                free(pFileBuffer);
                fclose(fp);
                return 0;
      }
      *Buffer = pFileBuffer;

      //判断是否是PE文件
      if(*((WORD*)pFileBuffer) != 0x5A4D)
      {
                printf("不是有效的MZ标志\n");
                free(pFileBuffer);
                fclose(fp);
                return 0;
      }
      DosHeader = (_PIMAGE_DOS_HEADER)pFileBuffer;
      pFileBuffer = pFileBuffer + ((_PIMAGE_DOS_HEADER)pFileBuffer)->e_lfanew;      //偏移到NT头
      if(((_PIMAGE_NT_HEADER)pFileBuffer)->Signature != 0x4550)
      {
                printf("不是有效的PE标志\n");
                free(*Buffer);
                fclose(fp);
                return 0;
      }
      NtHeader = (_PIMAGE_NT_HEADER)pFileBuffer;      //获取NT头
      pFileBuffer = pFileBuffer + 0x4;      //偏移到标准PE头
      FileHeader = (_PIMAGE_FILE_HEADER)pFileBuffer;      //获取标准PE头
      pFileBuffer = pFileBuffer + 0x14;      //偏移到可选PE头
      OptionalHeader = (_PIMAGE_OPTIONAL_HEADER)pFileBuffer;      //获取可选PE头
      pFileBuffer = pFileBuffer + FileHeader->SizeOfOptionalHeader;      //偏移到节表
      pSectionHeader = (_PIMAGE_SECTION_HEADER)pFileBuffer;      //获取节表

      fclose(fp);
      return FileSize;
}

//获取对齐后的值
int Align(int Value,int align)
{
      if(Value % align == 0)
      {
                return Value;
      }
      return ((Value / align) + 1) * align;
}

//RVA->FOA
DWORD RvaToFoa(DWORD dwRva)
{
      DWORD dwFoa = 0;

      //判断是否在头+节表中
      if(dwRva <= OptionalHeader->SizeOfHeaders)
      {
                dwFoa = dwRva;
                return dwFoa;
      }
      
      //判断在是否在节中
      int i;
      for(i = 0; i < FileHeader->NumberOfSections; i++)
      {
                if(dwRva >= pSectionHeader.VirtualAddress && dwRva <= (pSectionHeader.VirtualAddress + pSectionHeader.SizeOfRawData))
                {
                        dwFoa = dwRva - pSectionHeader.VirtualAddress;
                        return dwFoa + pSectionHeader.PointerToRawData;
                }
      }
}

//FOA->RVA
DWORD FoaToRva(DWORD dwFoa)
{
      DWORD dwRva = 0;

      //判断是否在头+节表中
      if(dwFoa <= OptionalHeader->SizeOfHeaders)
      {
                dwRva = dwFoa;
                return dwRva;
      }
      
      //判断是否在节中
      int i = 0;
      for(i = 0; i < FileHeader->NumberOfSections; i++)
      {
                if(dwFoa >= pSectionHeader.PointerToRawData && dwFoa <= (pSectionHeader.PointerToRawData + pSectionHeader.SizeOfRawData))
                {
                        dwRva = dwFoa - pSectionHeader.PointerToRawData;
                        return dwRva + pSectionHeader.VirtualAddress;
                }
      }
}

// 存盘
STAUS SaveData(PBYTE buffer,STR Path,size_t FileSize)
{
      FILE* fp = fopen(Path,"wb+");
      if(!fp)
      {
                printf("文件打开失败\n");
                return FALSE;
      }

      //写入文件
      if(!fwrite(buffer,FileSize,1,fp))
      {
                printf("文件写入失败!\n");
                return FALSE;
      }

      fclose(fp);
      return TRUE;
}

//提升所有头+节表
STAUS PromoteHeaders(PBYTE FileBuffer)
{
      PBYTE pFileBuffer = FileBuffer;
      DWORD SizeOfCopy = (DWORD)(&pSectionHeader) - (DWORD)(FileBuffer + DosHeader->e_lfanew);
      DWORD FillSize = (DWORD)(&pSectionHeader) - (DWORD)FileBuffer - 0x40 - SizeOfCopy;
      //拷贝所有头+节表
      for(DWORD i = 0; i < SizeOfCopy; i++)
      {
                (FileBuffer + 0x40) = (FileBuffer + DosHeader->e_lfanew);
      }
      //填充
      memset((FileBuffer + 0x40 + SizeOfCopy),0x0,FillSize);
      //修正e_lfanew
      DosHeader->e_lfanew = 0x40;
      //重新修正所有头+节表指针
      pFileBuffer = pFileBuffer + DosHeader->e_lfanew;      //偏移到NT头
      NtHeader = (_PIMAGE_NT_HEADER)pFileBuffer;      //获取NT头
      pFileBuffer = pFileBuffer + 0x4;      //偏移到标准PE头
      FileHeader = (_PIMAGE_FILE_HEADER)pFileBuffer;      //获取标准PE头
      pFileBuffer = pFileBuffer + 0x14;      //偏移到可选PE头
      OptionalHeader = (_PIMAGE_OPTIONAL_HEADER)pFileBuffer;      //获取可选PE头
      pFileBuffer = pFileBuffer + FileHeader->SizeOfOptionalHeader;      //偏移到节表
      pSectionHeader = (_PIMAGE_SECTION_HEADER)pFileBuffer;      //获取节表
      return TRUE;
}

//新增节
STAUS AddSectionPlus(PBYTE FileBuffer,PBYTE* NewBuffer,size_t FileSize)
{
      //申请一块新的FileBuffer
      *NewBuffer = (BYTE*)malloc(FileSize + SizeOfNewSection);
      memset(*NewBuffer,0x0,SizeOfNewSection + FileSize);
      //把原来的内容拷贝过来
      for(int i = 0; i < FileSize; i++)
                (*NewBuffer) = FileBuffer;
      //更新所有指针
      PBYTE pNewBuffer = *NewBuffer;
      DosHeader = (_PIMAGE_DOS_HEADER)pNewBuffer;      //获取DOS头
      pNewBuffer = pNewBuffer + DosHeader->e_lfanew;      //偏移到NT头
      NtHeader = (_PIMAGE_NT_HEADER)pNewBuffer;      //获取NT头
      pNewBuffer = pNewBuffer + 0x4;      //偏移到标准PE头
      FileHeader = (_PIMAGE_FILE_HEADER)pNewBuffer;      //获取标准PE头
      pNewBuffer = pNewBuffer + 0x14;      //偏移到可选PE头
      OptionalHeader = (_PIMAGE_OPTIONAL_HEADER)pNewBuffer;      //获取可选PE头
      pNewBuffer = pNewBuffer + FileHeader->SizeOfOptionalHeader;      //偏移到节表
      pSectionHeader = (_PIMAGE_SECTION_HEADER)pNewBuffer;      //获取节表
      //判断节表空间是否充足
      if( OptionalHeader->SizeOfHeaders - (DWORD)(&(pSectionHeader) - (DWORD)(*NewBuffer)) < 0x50 )
      {
                printf("节表空间不足!\n");
                PromoteHeaders(*NewBuffer);      //提升所有头+节表
      }
      //偏移到要添加节表的位置
      pNewBuffer = *NewBuffer + (DWORD)(&pSectionHeader) - (DWORD)(*NewBuffer);
      //后面填充一个全0结构
      memset(pNewBuffer + 0x28,0x0,0x28);
      //设置节表内容
      for(int i = 0; i< strlen((char*)NewSectionName); i++)      //设置节表名字
                ((PBYTE)((_PIMAGE_SECTION_HEADER)pNewBuffer)->Name) = NewSectionName;
      ((PBYTE)((_PIMAGE_SECTION_HEADER)pNewBuffer)->Name) = 0x0;
      ((_PIMAGE_SECTION_HEADER)pNewBuffer)->Misc.VirtualSize = (DWORD)SizeOfNewSection;      //设置内存中大小
      DWORD MaxSize = pSectionHeader.SizeOfRawData > pSectionHeader.Misc.VirtualSize ?
                pSectionHeader.SizeOfRawData : pSectionHeader.Misc.VirtualSize;
      DWORD SizeOfData = Align(MaxSize,OptionalHeader->SectionAlignment);
      ((_PIMAGE_SECTION_HEADER)pNewBuffer)->VirtualAddress = pSectionHeader.VirtualAddress + SizeOfData;      //设置内存中偏移
      ((_PIMAGE_SECTION_HEADER)pNewBuffer)->SizeOfRawData = SizeOfNewSection;      //设置文件中大小
      ((_PIMAGE_SECTION_HEADER)pNewBuffer)->PointerToRawData = pSectionHeader.PointerToRawData + SizeOfData;      //设置文件中偏移
      for(int i = 0; i < FileHeader->NumberOfSections - 1; i++)
      {
                ((_PIMAGE_SECTION_HEADER)pNewBuffer)->Characteristics = ((_PIMAGE_SECTION_HEADER)pNewBuffer)->Characteristics | pSectionHeader.Characteristics;      //设置属性
      }
      //修改节表的数量
      FileHeader->NumberOfSections++;
      //设置节的内容
      memset(*NewBuffer + pSectionHeader.PointerToRawData,0x7,SizeOfNewSection);
      //修改SizeOfImage
      OptionalHeader->SizeOfImage = OptionalHeader->SizeOfImage + SizeOfNewSection;
      return TRUE;
}

//取字符串长度(不包括0)
int strlen(char* s)
{
      int ret = 0;
      while(*s++) ret++;
      return ret;
}      

//导入表注入
STAUS ImportInject()
{
      int flag = 1;      //标记所有导入表结束
      int sum = 0;      //统计DLL个数时候用
      PBYTE pTemp = NULL;                //游走指针
      PBYTE poTemp = NULL;
      PBYTE BeginOfNewSection = NULL;      //新增节开始位置
      PBYTE BeginOfINT = NULL;      //INT表开始位置
      PBYTE BeginOfImportName = NULL;      //名字导入结构开始位置
      PBYTE BeginOfDLLName = NULL;      //DLL名字开始位置
      DWORD NewBeginAddr = 0;                //保存新节开始位置
      int NumberOfImport = 0;                //记录原来的导入表个数
      
      //加载PE文件
      PBYTE FileBuffer = NULL;
      PBYTE NewBuffer = NULL;
      size_t FileSize = LoadPE(InPutPath,&FileBuffer);
      if( !FileSize )
      {
                printf("加载PE文件失败!\n");
                return FALSE;
      }
      //统计一共有多少个DLL
      pTemp = (PBYTE)(RvaToFoa(OptionalHeader->DataDirectory.VirtualAddress) + (DWORD)FileBuffer);
      while(flag)
      {
                flag = 0;
                //判断导入表结束
                for(int j = 0; j < sizeof(_IMAGE_IMPORT_DESCRIPTOR); j++)
                {
                        if(((PBYTE)pTemp) != 0 )
                        {
                              flag = 1;
                              break;
                        }
                }
                if( sum == 0x14 )
                {
                        NumberOfImport++;
                        sum = 0;
                }
                sum++;
                pTemp++;
      }
      //新增一个节
      if( !AddSectionPlus(FileBuffer , &NewBuffer , FileSize) )
      {
                printf("新增节失败!\n");
                return FALSE;
      }
      BeginOfNewSection = NewBuffer + pSectionHeader.PointerToRawData;      //获取新增节开始位置
      //获取导入表指针
      pImportDesriptor = (_PIMAGE_IMPORT_DESCRIPTOR)(RvaToFoa(OptionalHeader->DataDirectory.VirtualAddress) + (DWORD)NewBuffer);
      pTemp = (PBYTE)BeginOfNewSection;
      //先拷贝DLL名字
      BeginOfDLLName = pTemp;
      for(int i = 0; i < strlen((char*)DllName); i++)
      {
                *(pTemp + i) = DllName;
      }
      *(pTemp + strlen((char*)DllName)) = 0x0;
      //再拷贝导入名字结构(前俩字节为0)
      pTemp = pTemp + strlen((char*)DllName) + 0x1;
      BeginOfImportName = pTemp;
      *((PWORD)pTemp) = 0x0;
      for(int i = 0; i < strlen((char*)ImportFunName); i++)
      {
                *(pTemp + 0x2 + i) = ImportFunName;
      }
      *(pTemp + 0x2 + strlen((char*)ImportFunName)) = 0x0;
      //再拷贝INT表和IAT表所指向的那个结构
      pTemp = pTemp + strlen((char*)ImportFunName) + 0x2 + 0x1;
      BeginOfINT = pTemp ;
      *((PDWORD)BeginOfINT) = FoaToRva( (DWORD)BeginOfImportName - (DWORD)NewBuffer);      //指向名字导出位置
      *((PDWORD)BeginOfINT + 1) = 0x0;      //后四个字节为0
      //再拷贝原导入表到新增节
      pTemp = pTemp + 0x8;
      NewBeginAddr = (DWORD)pTemp;
      for(int i = 0; i < (NumberOfImport + 2) * 0x14; i++)
      {
                pTemp = ((PBYTE)pImportDesriptor);
      }
      //先把pTemp指针偏移到全0结构
      flag = 1;
      while(flag)
      {
                flag = 0;
                //判断导入表结束
                for(int j = 0; j < sizeof(_IMAGE_IMPORT_DESCRIPTOR); j++)
                {
                        if(((PBYTE)pTemp) != 0 )
                        {
                              flag = 1;
                              break;
                        }
                }
                pTemp++;
      }
      //全0结构,后40个字节再补充全0结构
      memset(pTemp + 0x14,0x0,0x14);
      //填充新增导入表
      ((_PIMAGE_IMPORT_DESCRIPTOR)pTemp)->OriginalFirstThunk = FoaToRva( BeginOfINT - NewBuffer );
      ((_PIMAGE_IMPORT_DESCRIPTOR)pTemp)->TimeDateStamp = 0x0;      
      ((_PIMAGE_IMPORT_DESCRIPTOR)pTemp)->ForwarderChain = 0x0;      
      ((_PIMAGE_IMPORT_DESCRIPTOR)pTemp)->Name = FoaToRva( BeginOfDLLName - NewBuffer );      
      ((_PIMAGE_IMPORT_DESCRIPTOR)pTemp)->FirstThunk = FoaToRva( BeginOfINT - NewBuffer );
      //修改目录项
      OptionalHeader->DataDirectory.VirtualAddress = FoaToRva( (DWORD)NewBeginAddr - (DWORD)NewBuffer );
      //存盘
      SaveData(NewBuffer,OutPutPath,pSectionHeader.PointerToRawData + SizeOfNewSection);
      return TRUE;
}

int main(int argc, char* argv[])
{
      if( ImportInject() )
      {
                printf("导入表注入成功!\n");
      }

      getchar();
      return 0;
}
InjectH.h:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>

#if !defined(AFX_GLOBE_H__9815AEC8_DF43_478B_8D19_5BAB2B5BD840__INCLUDED_)
#define AFX_GLOBE_H__9815AEC8_DF43_478B_8D19_5BAB2B5BD840__INCLUDED_

#define WORD unsigned short
#define DWORD unsigned int
#define BYTE unsigned char
#define STR char*
#define PWORD unsigned short*
#define PDWORD unsigned int*
#define PBYTE unsigned char*
#define IMAGE_SIZEOF_SHORT_NAME                8
#define STAUS int
#define TRUE 1
#define FALSE 0


//DOS头结构
typedef struct dos
{
      WORD      e_magic;      //MZ标志
      WORD      e_cblp;
      WORD         e_cp;
      WORD         e_crlc;
      WORD         e_cparhdr;
      WORD         e_minalloc;
      WORD         e_maxalloc;
      WORD         e_ss;
      WORD         e_sp;
      WORD         e_csum;      
      WORD         e_ip;
      WORD         e_cs;
      WORD         e_lfarlc;
      WORD         e_ovno;
      WORD         e_res;
      WORD         e_oemid;
      WORD         e_oeminfo;
      WORD         e_res2;
      DWORD         e_lfanew;      //真正PE起始点
}_IMAGE_DOS_HEADER,*_PIMAGE_DOS_HEADER;

//目录项结构
typedef struct dataDirectory
{
      DWORD VirtualAddress;
      DWORD Size;
}_IMAGE_DATA_DIRECTORY,_PIMAGE_DATA_DIRECTORY;

//标准PE头结构
typedef struct filePE
{
      WORD         Machine;
      WORD      NumberOfSections;
      DWORD      TimeDataStamp;
      DWORD      PointerToSymbolTable;
      DWORD      NumberOfSymbols;
      WORD      SizeOfOptionalHeader;
      WORD      Characteristics;
}_IMAGE_FILE_HEADER,*_PIMAGE_FILE_HEADER;

//可选PE头结构
typedef struct optionalPE
{
      WORD      Magic;
      BYTE      MajrLinkerVersion;
      BYTE      MinorLinkerVersion;
      DWORD      SizeOfCode;
      DWORD      SizeOfInitializedData;
      DWORD      SizeOfUninitializedData;
      DWORD      AddressOfEntryPoint;
      DWORD      BaseOfCode;
      DWORD      BaseOfData;
      DWORD      ImageBase;
      DWORD      SectionAlignment;
      DWORD      FileAlignment;
      WORD      MajorOperatingSystemVersion;
      WORD      MinorOperatingSystemVersion;
      WORD      MajorImageVersion;
      WORD      MinorImageVersion;
      WORD      MajorSubsystemVersion;
      WORD      MinorSubsystemVersion;
      DWORD      Win32VersionValue;
      DWORD      SizeOfImage;
      DWORD      SizeOfHeaders;
      DWORD      CheckSum;
      WORD      Subsystem;
      WORD      DllCharacteristics;
      DWORD      SizeOfStackReserve;
      DWORD      SizeOfStackCommit;
      DWORD      SizeOfHeapReserve;
      DWORD      SizeOfHeapCommit;
      DWORD      LoaderFlags;
      DWORD      NumberOfRvaAndSizes;
      _IMAGE_DATA_DIRECTORY DataDirectory;
}_IMAGE_OPTIONAL_HEADER,*_PIMAGE_OPTIONAL_HEADER;

//NT头结构
typedef struct nt
{
      DWORD Signature;
      _IMAGE_FILE_HEADER FileHeader;
      _IMAGE_OPTIONAL_HEADER OptionalHeader;
      
}_IMAGE_NT_HEADER,*_PIMAGE_NT_HEADER;

//节表结构
typedef struct section
{                                       
    BYTE    Name;                                       
    union {                                       
            DWORD   PhysicalAddress;                                       
            DWORD   VirtualSize;                                       
    } Misc;                                       
    DWORD   VirtualAddress;                                       
    DWORD   SizeOfRawData;                                       
    DWORD   PointerToRawData;                                       
    DWORD   PointerToRelocations;                                       
    DWORD   PointerToLinenumbers;                                       
    WORD    NumberOfRelocations;                                       
    WORD    NumberOfLinenumbers;                                       
    DWORD   Characteristics;                                       
}_IMAGE_SECTION_HEADER, *_PIMAGE_SECTION_HEADER;

//导入表结构
typedef struct import_descriptor {                              
    union {                              
      DWORD   Characteristics;                                          
      DWORD   OriginalFirstThunk;                                       
    };                              
    DWORD   TimeDateStamp;                                             
    DWORD   ForwarderChain;                                             
    DWORD   Name;                              
    DWORD   FirstThunk;                                                
}_IMAGE_IMPORT_DESCRIPTOR,*_PIMAGE_IMPORT_DESCRIPTOR;               

//函数以名字导出结构
typedef struct import_by_name {                                       
    WORD    Hint;                                       
    BYTE    Name;                                       
}_IMAGE_IMPORT_BY_NAME, *_PIMAGE_IMPORT_BY_NAME;                                                                                       

#endif // !defined(AFX_GLOBE_H__9815AEC8_DF43_478B_8D19_5BAB2B5BD840__INCLUDED_)

4.用到的DLL:


                链接:https://pan.baidu.com/s/10eJc1cTJa2GPZ23aPt1-GQ
               提取码:ru18

Hmily 发表于 2021-2-23 15:03

I D:存钱买板子
邮箱:yuan6900956@163.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。

存钱买板子 发表于 2021-2-24 09:24

我来报道啦,谢谢H大。
页: [1]
查看完整版本: 申请会员ID:存钱买板子【申请通过】