for 发表于 2021-9-24 00:09

申请会员ID:LoveCpp【申请通过】

1、申 请ID:LoveCpp
2、个人邮箱:lg224@foxmail.com
3、2020年8月的时候就看了一下滴水的视频,后来太枯燥就没看下去,期间换了一份工作。2021年06月17重新开始捡起来学习,平时每天下班比较晚,十点多到家学一两个小时,生活琐事也比较多,基础也不是很扎实一直到09月21号才学完PE。

关于导入表就不总结了:

      大佬讲的很详细了:https://www.52pojie.cn/forum.php?mod=viewthread&tid=1413220&highlight=%B5%BC%C8%EB%B1%ED,我是边看视频边看帖子学习的

导入表注入原理:

            当Exe被加载时,系统会根据Exe导入表信息来加载需要用到的DLL,导入表注入的原理就是修改exe导入表,将自己的DLL添加到exe的导入表中,这样exe运行时可以将自己的DLL加载到exe的进程空间.

   

上图是一个导入表的结构,存放着user32这个dll里面用到了那些函数,程序运行时候就会找到user32.dll然后把函数加载,我们需要做的就是复制一个一样的结构

导入表注入的实现步骤:

第一步:定位导出表

根据目录项(第二个就是导入表)得到导入表信息:
```
      //定义PE头的信息
      PIMAGE_DOS_HEADER pDosHeader = NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER pPEHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      LPVOID pTempBuffer = NULL;
      bool Ssize = false;
      if(!pFilebuff)
      {
                printf("读取到内存的pfilebuffer无效!\n");
                return 0;
      }
      //判断是不是exe文件
      if(*((PWORD)pFilebuff) != IMAGE_DOS_SIGNATURE)
      {
                printf("不含MZ标志,不是exe文件!\n");
                return 0;
      }
      pDosHeader = (PIMAGE_DOS_HEADER)pFilebuff;
      if(*((PDWORD)((BYTE *)pFilebuff + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
                printf("无有效的PE标志\n");
                return 0;
      }
      
      //读取pFileBuffer 获取DOS头,PE头,节表等信息
      pDosHeader =(PIMAGE_DOS_HEADER)pFilebuff;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFilebuff + pDosHeader->e_lfanew);
      //打印NT头      
      pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
      
      printf("===导出表====\n");
      
      printf("内存地址%x\n",pOptionHeader->DataDirectory.VirtualAddress);
      
printf("内存大小%x\n",pOptionHeader->DataDirectory.Size);`

第二步:移动导出表

然后我们需要把这个移动到一个地方,海哥的步骤是先计算原先的导出表的大小和要新增的导出表的大小一共有多大,看放在那里,我这就直接偷懒新增一个节来存放

新增节代码:
PIMAGE_DOS_HEADER pDosHeader = NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER pPEHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      LPVOID pTempBuffer = NULL;
      bool Ssize = false;
      if(!pFilebuff)
      {
                printf("读取到内存的pfilebuffer无效!\n");
                return 0;
      }
      //判断是不是exe文件
      if(*((PWORD)pFilebuff) != IMAGE_DOS_SIGNATURE)
      {
                printf("不含MZ标志,不是exe文件!\n");
                return 0;
      }
      pDosHeader = (PIMAGE_DOS_HEADER)pFilebuff;
      if(*((PDWORD)((BYTE *)pFilebuff + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
                printf("无有效的PE标志\n");
                return 0;
      }
      
      //读取pFileBuffer 获取DOS头,PE头,节表等信息
      pDosHeader =(PIMAGE_DOS_HEADER)pFilebuff;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFilebuff + pDosHeader->e_lfanew);
      //打印NT头      
      pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

      //移动导入表
      
      //获取剩余大小 //SizeOfHeaders(总的大小)4096 -   ( pSectionHeader(一个地址,文件开始的地方偏移了pSectionHeader的大小的字节)-    (文件偏移+pPEHeader->NumberOfSections * 40)一个地址 文件开始的地方偏移了节的大小的字节 并不是节在文件中的偏移地址,所以会比 pSectionHeader小)
      DWORD whiteSpaceSize = pOptionHeader->SizeOfHeaders - ((DWORD)pSectionHeader - (DWORD)pFilebuff + pPEHeader->NumberOfSections * 40);
      
      if (whiteSpaceSize < 80)
      {
                printf("空间不足");
                return false;
    }
      //新增一个节来存放导入表
      //1.修改SizeOfImage大小
      pOptionHeader->SizeOfImage +=0x1000;

      
      LPVOID NewBuffer = malloc(pOptionHeader->SizeOfImage);//申请内存
      memset(NewBuffer, 0, pOptionHeader->SizeOfImage);//初始化内存
      //修改节表NumberOfSection数量
      
      for (int i=0;i<80;i++)
      {
                if (*((char*)pFilebuff +whiteSpaceSize + i) !=0 )
                {
                     
                        pTempBuffer=malloc(pOptionHeader->SizeOfImage);
                     
                        //如果空间足,但是节最后的80个字节不等于0 就需要将PE头往上移动,把垃圾数据清空
                        memset(pTempBuffer, 0, pOptionHeader->SizeOfImage);
                     
                        //把整个原来的pImageBuffer 复制到新的imagefile
                        memcpy(pTempBuffer,pFilebuff,pOptionHeader->SizeOfImage);

                        DWORD e_lfanew = sizeof(IMAGE_DOS_HEADER);
                        //计算PE-到节表有多少个字节
                        DWORD moveSize = pOptionHeader->SizeOfHeaders - whiteSpaceSize -pDosHeader->e_lfanew;
                        //printf("垃圾数据开始的地方%x\n",(char*)pTempImageBuffer+e_lfanew);
                        //printf("PE开始的地方%x\n",(char*)pTempImageBuffer+pDosHeader->e_lfanew);
                        //把PE到节的数据移动到DOSSUB区域
                        memcpy((char*)pTempBuffer+e_lfanew,(char*)pTempBuffer+pDosHeader->e_lfanew,moveSize);
                        //然后将PE-到节表然后到之前的数据清0 //计算大小 总大小 = pOptionHeader->SizeOfHeaders- whiteSpaceSize - DOS头的大小 - PE到节表的大小
                        DWORD setZeroSzie = pOptionHeader->SizeOfHeaders - whiteSpaceSize - e_lfanew - moveSize;
                        //之前的数据清0
                        memset((char*)pTempBuffer+e_lfanew+moveSize,0,setZeroSzie);
                        //修正e_lfanew
                        memcpy((char*)pTempBuffer+sizeof(IMAGE_DOS_HEADER)-4,&e_lfanew,1);
                     
                        //重新从pTempImageBuffer 获取DOS头,PE头,节表等信息
                        pDosHeader =(PIMAGE_DOS_HEADER)pTempBuffer;
                        pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempBuffer + pDosHeader->e_lfanew);
                        //打印NT头      
                        pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
                        pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
                        pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
                     
                        pFilebuff = pTempBuffer;

                }      
      }
      


      PIMAGE_SECTION_HEADER pNewSec = (PIMAGE_SECTION_HEADER)(pSectionHeader + pPEHeader->NumberOfSections);
      
    memcpy(pNewSec->Name,".addSec",8);//修改节表名
      
      //获取最后一个节
      PIMAGE_SECTION_HEADER EndSection = (PIMAGE_SECTION_HEADER)(pSectionHeader + pPEHeader->NumberOfSections-1);
      
      //内存对齐
      pNewSec->VirtualAddress = EndSection->VirtualAddress + (DWORD)(ceil(max(EndSection->Misc.VirtualSize, EndSection->SizeOfRawData)/ pOptionHeader->SectionAlignment) * pOptionHeader->SectionAlignment);
      //内存大小
      pNewSec->Misc.VirtualSize = 0x1000;
      //文件大小
      pNewSec->SizeOfRawData = 0x1000;//新增的节区的大小
      //文件偏移
      pNewSec->PointerToRawData = EndSection->PointerToRawData + EndSection->SizeOfRawData;
      //pNewSec->Characteristics = 0xC0000040;//修改属性(可执行)
      pNewSec->Characteristics |= IMAGE_SCN_MEM_EXECUTE |IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_READ;
      pPEHeader->NumberOfSections += 1;
      //在新增节表后增加40个字节的空白区
    memset(pNewSec+1, 0, 40);

新增节之后我们可以获取到新增节的地址,然后把导出表直接复制到新增节的起始位置:

   memcpy(NewBuffer, pFilebuff,pOptionHeader->SizeOfImage);//复制内存
      if (!pOptionHeader->DataDirectory.VirtualAddress)
      {
                printf("(DLLInject)This program has no import table.\n");
                return 0;
      }
      //定位新节表的地址
      LPVOID pNewSecAddr = (LPVOID)((DWORD)NewBuffer+pNewSec->PointerToRawData);
      
      pDosHeader =(PIMAGE_DOS_HEADER)NewBuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)NewBuffer + pDosHeader->e_lfanew);
      //打印NT头      
      pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

      //定位导入表      
      PIMAGE_IMPORT_DESCRIPTOR ImportExtable = (PIMAGE_IMPORT_DESCRIPTOR)((char*)NewBuffer + RvaToFileOffset(NewBuffer,pOptionHeader->DataDirectory.VirtualAddress));

      //复制新的导入表
      memcpy(pNewSecAddr,ImportExtable,pOptionHeader->DataDirectory.Size);

复制完之后的的PE文件在内存的样子:



我们要在原先的导出表之后追加一个导入表,但是这个表需要在一堆0000之前加上,所以我们需要计算pNewSecAddr到000之前的大小

      //复制完在循环获取大小,这个大小就是有多少个导出表,然后乘以导出表的大小
      int j =0;
      while(ImportExtable->FirstThunk !=0 &&ImportExtable->OriginalFirstThunk !=0){
                ImportExtable++;
                j++;
      }
   //新的导入表结构的地址,因为是新增节的方式,复制filebuff的时候把新的内存都设置为0了,所以整个绿色块到不是很绿的拿一块区域里面的内存都是0,我们可以直接使用一个PIMAGE_IMPORT_DESCRIPTOR结构
      PIMAGE_IMPORT_DESCRIPTOR NewImportExtable= (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewSecAddr + j * (sizeof(IMAGE_IMPORT_DESCRIPTOR)));
因为每个导出表对应一张IAT表和INT表,这两个表又同时指向一个存放函数命的结构,PIMAGE_IMPORT_BY_NAME所以我们为这两个表和名字表申请内存空间:

   //设置IAT表 IAT表的地址 = 自己新增的导入表的地址 + 2个自己结构的大小第一个结构存放新增的导入表,第二个结构做为导入表的结束标记
      PIMAGE_THUNK_DATA32 IatTable = (PIMAGE_THUNK_DATA32)(NewImportExtable +2);
      //设置InT表
      PIMAGE_THUNK_DATA32 IntTable = (PIMAGE_THUNK_DATA32)(IatTable+2);   
      //设置IMAGE_IMPORT_BY_NAME
      PIMAGE_IMPORT_BY_NAME ImageName = (PIMAGE_IMPORT_BY_NAME)(IntTable+2);
此时的结构如下:



对应海哥的图,A部分为NEWimporEXtable,B部分为iAT,INAT表    D部分为名字表,C部分为DLL名称



然后我们需要这些地址对应起来,也就是把地址修正

      DWORD FuncNameSzie = strlen("ExportFunction") + 1;

      memcpy(ImageName->Name,"ExportFunction",FuncNameSzie);

      //获取存放DLL名称的地址      这个地址保证在PIMAGE_IMPORT_BY_NAME的结构后面就行
      
      DWORD* DllName= (DWORD*)((DWORD)ImageName + FuncNameSzie+10);//
      
      memcpy(DllName,"InjectDll.dll",strlen("InjectDll.dll")+1);
      //修正IAT,INT表地址
      DWORD InAtFoa = (FoaToImageOffset(NewBuffer,(DWORD)ImageName -(DWORD)NewBuffer));
      memcpy(IatTable,&InAtFoa,4);
      memcpy(IntTable,&InAtFoa,4);

然后在修正目录中的地址,然后存盘

//修导出表地址
NewImportExtable->FirstThunk = FoaToImageOffset(NewBuffer,(DWORD)IntTable - (DWORD)NewBuffer);
NewImportExtable->OriginalFirstThunk = FoaToImageOffset(NewBuffer,(DWORD)IatTable- (DWORD)NewBuffer);
//修正dll名称的地址
NewImportExtable->Name =FoaToImageOffset(NewBuffer,(DWORD)DllName - (DWORD)NewBuffer);
//新导出表的地址 新导出表的地址= NewExport_Directory 内存地址 - 文件开始的位置 = 偏移
pOptionHeader->DataDirectory.VirtualAddress = FoaToImageOffset(NewBuffer,(DWORD)pNewSecAddr-(DWORD)NewBuffer);
pOptionHeader->DataDirectory.Size = pOptionHeader->DataDirectory.Size + 40;

FILE* fp = fopen("C://project/notepadiat1.exe","wb+");
size_t n =         fwrite(NewBuffer,pOptionHeader->SizeOfImage,1,fp);
if(!n){
printf("fwrite数据写入失败...\n");
fclose(fp);
return ERROR;
}

free(pFilebuff);
free(NewBuffer);

printf("存盘成功...\n");

fclose(fp);
      

使用ipmsg.exe正常能注入,但是使用notepad发现无法正常注入,查看输入表也加载了dll,但是打开notepad就是无法弹出dll加载时候的函数


后来用工具添加和代码添加的结构对比了一下,发现工具将原先的绑定表请了,加了两行代码:

pOptionHeader->DataDirectory.VirtualAddress= 0;
pOptionHeader->DataDirectory.Size= 0;

最后整体代码如下:

//导入表注入
DWORD InjectDll(LPVOID pFilebuff){
      //定义PE头的信息
      PIMAGE_DOS_HEADER pDosHeader = NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER pPEHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      LPVOID pTempBuffer = NULL;
      bool Ssize = false;
      if(!pFilebuff)
      {
                printf("读取到内存的pfilebuffer无效!\n");
                return 0;
      }
      //判断是不是exe文件
      if(*((PWORD)pFilebuff) != IMAGE_DOS_SIGNATURE)
      {
                printf("不含MZ标志,不是exe文件!\n");
                return 0;
      }
      pDosHeader = (PIMAGE_DOS_HEADER)pFilebuff;
      if(*((PDWORD)((BYTE *)pFilebuff + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
                printf("无有效的PE标志\n");
                return 0;
      }
      
      //读取pFileBuffer 获取DOS头,PE头,节表等信息
      pDosHeader =(PIMAGE_DOS_HEADER)pFilebuff;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFilebuff + pDosHeader->e_lfanew);
      //打印NT头      
      pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

      //移动导入表
      
      //获取剩余大小 //SizeOfHeaders(总的大小)4096 -   ( pSectionHeader(一个地址,文件开始的地方偏移了pSectionHeader的大小的字节)-    (文件偏移+pPEHeader->NumberOfSections * 40)一个地址 文件开始的地方偏移了节的大小的字节 并不是节在文件中的偏移地址,所以会比 pSectionHeader小)
      DWORD whiteSpaceSize = pOptionHeader->SizeOfHeaders - ((DWORD)pSectionHeader - (DWORD)pFilebuff + pPEHeader->NumberOfSections * 40);
      
      if (whiteSpaceSize < 80)
      {
                printf("空间不足");
                return false;
    }
      //新增一个节来存放导入表
      //1.修改SizeOfImage大小
      pOptionHeader->SizeOfImage +=0x1000;

      
      LPVOID NewBuffer = malloc(pOptionHeader->SizeOfImage);//申请内存
      memset(NewBuffer, 0, pOptionHeader->SizeOfImage);//初始化内存
      //修改节表NumberOfSection数量
      
      for (int i=0;i<80;i++)
      {
                if (*((char*)pFilebuff +whiteSpaceSize + i) !=0 )
                {
                     
                        pTempBuffer=malloc(pOptionHeader->SizeOfImage);
                     
                        //如果空间足,但是节最后的80个字节不等于0 就需要将PE头往上移动,把垃圾数据清空
                        memset(pTempBuffer, 0, pOptionHeader->SizeOfImage);
                     
                        //把整个原来的pImageBuffer 复制到新的imagefile
                        memcpy(pTempBuffer,pFilebuff,pOptionHeader->SizeOfImage);

                        DWORD e_lfanew = sizeof(IMAGE_DOS_HEADER);
                        //计算PE-到节表有多少个字节
                        DWORD moveSize = pOptionHeader->SizeOfHeaders - whiteSpaceSize -pDosHeader->e_lfanew;
                        //printf("垃圾数据开始的地方%x\n",(char*)pTempImageBuffer+e_lfanew);
                        //printf("PE开始的地方%x\n",(char*)pTempImageBuffer+pDosHeader->e_lfanew);
                        //把PE到节的数据移动到DOSSUB区域
                        memcpy((char*)pTempBuffer+e_lfanew,(char*)pTempBuffer+pDosHeader->e_lfanew,moveSize);
                        //然后将PE-到节表然后到之前的数据清0 //计算大小 总大小 = pOptionHeader->SizeOfHeaders- whiteSpaceSize - DOS头的大小 - PE到节表的大小
                        DWORD setZeroSzie = pOptionHeader->SizeOfHeaders - whiteSpaceSize - e_lfanew - moveSize;
                        //之前的数据清0
                        memset((char*)pTempBuffer+e_lfanew+moveSize,0,setZeroSzie);
                        //修正e_lfanew
                        memcpy((char*)pTempBuffer+sizeof(IMAGE_DOS_HEADER)-4,&e_lfanew,1);
                     
                        //重新从pTempImageBuffer 获取DOS头,PE头,节表等信息
                        pDosHeader =(PIMAGE_DOS_HEADER)pTempBuffer;
                        pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempBuffer + pDosHeader->e_lfanew);
                        //打印NT头      
                        pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
                        pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
                        pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
                     
                        pFilebuff = pTempBuffer;

                }      
      }
      


      PIMAGE_SECTION_HEADER pNewSec = (PIMAGE_SECTION_HEADER)(pSectionHeader + pPEHeader->NumberOfSections);
      
    memcpy(pNewSec->Name,".addSec",8);//修改节表名
      
      //获取最后一个节
      PIMAGE_SECTION_HEADER EndSection = (PIMAGE_SECTION_HEADER)(pSectionHeader + pPEHeader->NumberOfSections-1);
      
      //内存对齐
      pNewSec->VirtualAddress = EndSection->VirtualAddress + (DWORD)(ceil(max(EndSection->Misc.VirtualSize, EndSection->SizeOfRawData)/ pOptionHeader->SectionAlignment) * pOptionHeader->SectionAlignment);
      //内存大小
      pNewSec->Misc.VirtualSize = 0x1000;
      //文件大小
      pNewSec->SizeOfRawData = 0x1000;//新增的节区的大小
      //文件偏移
      pNewSec->PointerToRawData = EndSection->PointerToRawData + EndSection->SizeOfRawData;
      //pNewSec->Characteristics = 0xC0000040;//修改属性(可执行)
      pNewSec->Characteristics |= IMAGE_SCN_MEM_EXECUTE |IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_READ;
      pPEHeader->NumberOfSections += 1;
      //在新增节表后增加40个字节的空白区
    memset(pNewSec+1, 0, 40);
      


      memcpy(NewBuffer, pFilebuff,pOptionHeader->SizeOfImage);//复制内存

      
      if (!pOptionHeader->DataDirectory.VirtualAddress)
      {
                printf("(DLLInject)This program has no import table.\n");
                return 0;
      }
      
      
      //定位新节表的地址
      LPVOID pNewSecAddr = (LPVOID)((DWORD)NewBuffer+pNewSec->PointerToRawData);
      
      pDosHeader =(PIMAGE_DOS_HEADER)NewBuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)NewBuffer + pDosHeader->e_lfanew);
      //打印NT头      
      pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);//加4个字节到了标准PE头
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
      


      //定位导入表      
      PIMAGE_IMPORT_DESCRIPTOR ImportExtable = (PIMAGE_IMPORT_DESCRIPTOR)((char*)NewBuffer + RvaToFileOffset(NewBuffer,pOptionHeader->DataDirectory.VirtualAddress));

      //复制新的导入表
      memcpy(pNewSecAddr,ImportExtable,pOptionHeader->DataDirectory.Size);

      //复制完在循环获取大小

      int j =0;
      while(ImportExtable->FirstThunk !=0 &&ImportExtable->OriginalFirstThunk !=0){
                ImportExtable++;
                j++;
      }      
      
      //新的导入表结构的地址,因为是新增节的方式,所以移动完导出表之后这个地方会为0,可以直接使用一个PIMAGE_IMPORT_DESCRIPTOR结构
      PIMAGE_IMPORT_DESCRIPTOR NewImportExtable= (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewSecAddr + j * (sizeof(IMAGE_IMPORT_DESCRIPTOR)));

      
      //设置IAT表 IAT表的地址 = 自己新增的导入表的地址 + 2个自己结构的大小第一个结构存放新增的导入表,第二个结构做为导入表的结束标记
      PIMAGE_THUNK_DATA32 IatTable = (PIMAGE_THUNK_DATA32)(NewImportExtable +2);

      //设置InT表
      PIMAGE_THUNK_DATA32 IntTable = (PIMAGE_THUNK_DATA32)(IatTable+2);

      //设置IMAGE_IMPORT_BY_NAME

      PIMAGE_IMPORT_BY_NAME ImageName = (PIMAGE_IMPORT_BY_NAME)(IntTable+2);
      

      DWORD FuncNameSzie = strlen("ExportFunction") + 1;

      memcpy(ImageName->Name,"ExportFunction",FuncNameSzie);

      //获取存放DLL名称的地址      这个地址保证在PIMAGE_IMPORT_BY_NAME的结构后面就行
      
      DWORD* DllName= (DWORD*)((DWORD)ImageName + FuncNameSzie+10);//
      
      memcpy(DllName,"InjectDll.dll",strlen("InjectDll.dll")+1);


      //修正IAT表地址
      DWORD InAtFoa = (FoaToImageOffset(NewBuffer,(DWORD)ImageName -(DWORD)NewBuffer));
      memcpy(IatTable,&InAtFoa,4);
      memcpy(IntTable,&InAtFoa,4);
      

      //修导出表地址
      NewImportExtable->FirstThunk = FoaToImageOffset(NewBuffer,(DWORD)IntTable - (DWORD)NewBuffer);
      NewImportExtable->OriginalFirstThunk = FoaToImageOffset(NewBuffer,(DWORD)IatTable- (DWORD)NewBuffer);
      //修正dll名称的地址
      NewImportExtable->Name =FoaToImageOffset(NewBuffer,(DWORD)DllName - (DWORD)NewBuffer);
      //新导出表的地址 新导出表的地址= NewExport_Directory 内存地址 - 文件开始的位置 = 偏移
      pOptionHeader->DataDirectory.VirtualAddress = FoaToImageOffset(NewBuffer,(DWORD)pNewSecAddr-(DWORD)NewBuffer);
      pOptionHeader->DataDirectory.Size = pOptionHeader->DataDirectory.Size + 40;


      pOptionHeader->DataDirectory.VirtualAddress= 0;
      pOptionHeader->DataDirectory.Size= 0;

      FILE* fp = fopen("C://project/notepadiat1.exe","wb+");
      size_t n =         fwrite(NewBuffer,pOptionHeader->SizeOfImage,1,fp);
      if(!n){
                printf("fwrite数据写入失败...\n");
                fclose(fp);
                return ERROR;
      }

      free(pFilebuff);
      free(NewBuffer);

      printf("存盘成功...\n");

      fclose(fp);

      
      

      return 1;
}

实现效果:

启动



结束:

Hmily 发表于 2021-9-24 18:27

I D:LoveCpp
邮箱:lg224@foxmail.com

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

ps:登陆报道后可以把文章重新编辑发布到编程区。

LoveCpp 发表于 2021-9-24 20:50

Hmily 发表于 2021-9-24 18:27
I D:LoveCpp
邮箱:



感谢通过

李浩宇 发表于 2021-9-25 11:39

    @Hmily老哥 审核一下我的改名贴吧

zoiitylj 发表于 2021-11-12 21:14

很好的文章,我喜欢带代码的讲解
页: [1]
查看完整版本: 申请会员ID:LoveCpp【申请通过】