• Dll注入:修改PE文件 IAT注入


    PE原理就不阐述了, 这个注入是PE感染的一种,通过添加一个新节注入,会改变PE文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节。

    步骤:

    1.添加一个新节;映射PE文件,判断是否可以加一个新节,找到节的尾部,矫正偏移,对齐RVA

    填充新节PIMAGE_SECTION_HEADER,修改IMAGE_NT_HEADERS,将新节添加到文件尾部


    2.修改导入表:判断是否使用了绑定导入表,往新节中拷贝原导入表内容,继续构造新的导入表描述符PIMAGE_IMPORT_DESCRIPTOR,构造IAT结构体PIMAGE_THUNK_DATA,填充PIMAGE_THUNK_DATA,将PIMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk和FirstThunk指向PIMAGE_THUNK_DATA,name指向DllName
    最后修改导入表的VirtualAddress指向新节

      1 #include <windows.h>
      2 #include <iostream>
      3 #include <exception>
      4 #include <string>
      5 
      6 using namespace std;
      7 
      8 #define ERROR_MESSAGE(Msg) std::cout<<Msg<<std::endl;
      9 BOOL    AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
     10 BOOL    AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize);
     11 BOOL    AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
     12 DWORD   RVAToFOA(PIMAGE_NT_HEADERS pNtHeaders, DWORD dwRVA);
     13 ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign);
     14 
     15 int main()
     16 {
     17     AddImportTable("Target.exe", "Dll.dll", "InjectFunction");
     18 
     19     system("pause");
     20     return true;
     21 }
     22 
     23 BOOL AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
     24 {
     25     BOOL bOk = false;
     26     try
     27     {
     28         bOk = AddNewSection(strTargetFile, 256);
     29         if (!bOk)
     30         {
     31             ERROR_MESSAGE("AddImportTable:AddNewSection failed.");
     32             return false;
     33         }
     34 
     35         bOk = AddNewImportDescriptor(strTargetFile, strInjectDllName, strFunctionName);
     36         if (!bOk)
     37         {
     38             ERROR_MESSAGE("AddImportTable:AddNewImportDescriptor failed.");
     39             return false;
     40         }
     41     }
     42     catch (exception* e)
     43     {
     44         ERROR_MESSAGE((string("AddImportTable:") + e->what()).c_str());
     45         return false;
     46     }
     47 
     48     return true;
     49 }
     50 
     51 BOOL AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize)
     52 {
     53     BOOL bOk = true;
     54     HANDLE TargetFileHandle = nullptr;
     55     HANDLE MappingHandle = nullptr;
     56     PVOID FileData = nullptr;
     57 
     58     try
     59     {
     60         // 打开文件
     61         TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     62         if (TargetFileHandle == INVALID_HANDLE_VALUE)
     63         {
     64             ERROR_MESSAGE(string("AddNewSection:CreateFileA error with error code:" + GetLastError()).c_str());
     65             bOk = false;
     66             goto EXIT;
     67         }
     68 
     69         ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
     70 
     71         // 映射文件
     72         MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, 0, ulFileSize, NULL);
     73         if (MappingHandle == NULL)
     74         {
     75             ERROR_MESSAGE(string("AddNewSection:CreateFileMapping error with error code:" + GetLastError()).c_str());
     76             bOk = false;
     77             goto EXIT;
     78         }
     79 
     80         // 得到缓存头
     81         FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, ulFileSize);
     82         if (FileData == NULL)
     83         {
     84             ERROR_MESSAGE(string("AddNewSection:MapViewOfFile error with error code:" + GetLastError()).c_str());
     85             bOk = false;
     86             goto EXIT;
     87         }
     88 
     89         // 判断是否是PE文件
     90         if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
     91         {
     92             ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
     93             bOk = false;
     94             goto EXIT;
     95         }
     96 
     97         PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
     98         if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
     99         {
    100             ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
    101             bOk = false;
    102             goto EXIT;
    103         }
    104 
    105         // 判断是否可以增加一个新节
    106         if ((pNtHeaders->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER) > pNtHeaders->OptionalHeader.SizeOfHeaders/*三个部分的总大小*/)
    107         {
    108             ERROR_MESSAGE("AddNewSection:There is not enough space to add a new section.");
    109             bOk = false;
    110             goto EXIT;
    111         }
    112 
    113         // 得到新节的起始地址, 最后的起始地址
    114         PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1) + pNtHeaders->FileHeader.NumberOfSections;
    115         PIMAGE_SECTION_HEADER pLastSectionHeader = pNewSectionHeader - 1;
    116 
    117         // 对齐RVA和偏移
    118         DWORD FileSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.FileAlignment);
    119         DWORD FileOffset = PEAlign(pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData, pNtHeaders->OptionalHeader.FileAlignment);
    120         DWORD VirtualSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.SectionAlignment);
    121         DWORD VirtualOffset = PEAlign(pLastSectionHeader->VirtualAddress + pLastSectionHeader->Misc.VirtualSize, pNtHeaders->OptionalHeader.SectionAlignment);
    122 
    123         // 填充新节表
    124         memcpy(pNewSectionHeader->Name, "Inject", strlen("Inject"));
    125         pNewSectionHeader->VirtualAddress = VirtualOffset;
    126         pNewSectionHeader->Misc.VirtualSize = VirtualSize;
    127         pNewSectionHeader->PointerToRawData = FileOffset;
    128         pNewSectionHeader->SizeOfRawData = FileSize;
    129         pNewSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
    130 
    131         // 修改IMAGE_NT_HEADERS
    132         pNtHeaders->FileHeader.NumberOfSections++;
    133         pNtHeaders->OptionalHeader.SizeOfImage += VirtualSize;
    134         pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;            // 关闭绑定导入
    135         pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
    136 
    137         // 添加新节到文件尾部
    138         SetFilePointer(TargetFileHandle, 0, 0, FILE_END);
    139         PCHAR pNewSectionContent = new CHAR[FileSize];
    140         RtlZeroMemory(pNewSectionContent, FileSize);
    141         DWORD dwWrittenLength = 0;
    142         bOk = WriteFile(TargetFileHandle, pNewSectionContent, FileSize, &dwWrittenLength, nullptr);
    143         if (bOk == false)
    144         {
    145             ERROR_MESSAGE(string("AddNewSection:WriteFile error with error code:" + GetLastError()).c_str());
    146             bOk = false;
    147             goto EXIT;
    148         }
    149     }
    150     catch (exception* e)
    151     {
    152         ERROR_MESSAGE((string("AddNewSection:") + e->what()).c_str());
    153         bOk = false;
    154     }
    155 EXIT:
    156     if (TargetFileHandle != NULL)
    157     {
    158         CloseHandle(TargetFileHandle);
    159         TargetFileHandle = nullptr;
    160     }
    161     if (FileData != NULL)
    162     {
    163         UnmapViewOfFile(FileData);
    164         FileData = nullptr;
    165     }
    166     if (MappingHandle != NULL)
    167     {
    168         CloseHandle(MappingHandle);
    169         MappingHandle = nullptr;
    170     }
    171 
    172     return bOk;
    173 }
    174 
    175 ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign)
    176 {
    177     return(((dwNumber + dwAlign - 1) / dwAlign) * dwAlign);        //  想 dwAlign 对齐,加上 dwAlign - 1,这样就可以保证对齐后的值 >= dwNumber
    178 }
    179 
    180 BOOL AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
    181 {
    182     bool bOk = true;
    183     HANDLE TargetFileHandle = nullptr;
    184     HANDLE MappingHandle = nullptr;
    185     PVOID FileData = nullptr;
    186     PIMAGE_IMPORT_DESCRIPTOR pImportTable = nullptr;
    187 
    188     try
    189     {
    190         // 打开文件
    191         TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    192         if (TargetFileHandle == INVALID_HANDLE_VALUE)
    193         {
    194             ERROR_MESSAGE(string("AddNewImportDescriptor:CreateFileA error with error code:" + GetLastError()).c_str());
    195             bOk = false;
    196             goto EXIT;
    197         }
    198 
    199         ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
    200 
    201         // 映射文件
    202         MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, 0, ulFileSize, NULL);
    203         if (MappingHandle == NULL)
    204         {
    205             cout << "AddNewImportDescriptor:CreateFileMapping error with error code:" << std::to_string(GetLastError()).c_str();
    206             bOk = false;
    207             goto EXIT;
    208         }
    209 
    210         // 得到缓存头
    211         FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, ulFileSize);
    212         if (FileData == NULL)
    213         {
    214             ERROR_MESSAGE(string("AddNewImportDescriptor:MapViewOfFile error with error code:" + GetLastError()).c_str());
    215             bOk = false;
    216             goto EXIT;
    217         }
    218 
    219         // 判断是否是PE文件
    220         if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
    221         {
    222             ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
    223             bOk = false;
    224             goto EXIT;
    225         }
    226 
    227         PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
    228         if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
    229         {
    230             ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
    231             bOk = false;
    232             goto EXIT;
    233         }
    234 
    235         // 得到原导入表
    236         pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)FileData + RVAToFOA(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
    237         // 判断是否使用了绑定导入表
    238         bool bBoundImport = false;
    239         if (pImportTable->Characteristics == 0 && pImportTable->FirstThunk != 0)
    240         {
    241             // 桥一为0 桥二不是0 说明使用了绑定导入表
    242             bBoundImport = true;
    243             pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;    // 关闭绑定导入
    244             pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
    245         }
    246 
    247         // 找到自己添加的新节
    248         PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1) + pNtHeaders->FileHeader.NumberOfSections - 1;
    249         PBYTE pNewSectionData = pNewSectionHeader->PointerToRawData + (PBYTE)FileData;
    250         PBYTE pNewImportDescriptor = pNewSectionData;
    251         // 往新节中拷贝原导入表内容
    252         int i = 0;
    253         while (pImportTable->FirstThunk != 0 || pImportTable->Characteristics != 0)
    254         {
    255             memcpy(pNewSectionData + i * sizeof(IMAGE_IMPORT_DESCRIPTOR), pImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
    256             pImportTable++;
    257             pNewImportDescriptor += sizeof(IMAGE_IMPORT_DESCRIPTOR);
    258             i++;
    259         }
    260         // 复制最后一个描述符
    261         memcpy(pNewImportDescriptor, pNewImportDescriptor - sizeof(IMAGE_IMPORT_DESCRIPTOR), sizeof(IMAGE_IMPORT_DESCRIPTOR));
    262 
    263         // 计算修正值
    264         DWORD dwDelt = pNewSectionHeader->VirtualAddress - pNewSectionHeader->PointerToRawData;
    265 
    266         // pNewImportDescriptor 当前指向要构造的新描述符 再空出一个空描述符作为导入表的结束符 所以是 2 * 
    267         PIMAGE_THUNK_DATA pNewThunkData = PIMAGE_THUNK_DATA(pNewImportDescriptor + 2 * sizeof(IMAGE_IMPORT_DESCRIPTOR));
    268         PBYTE pszDllName = (PBYTE)(pNewThunkData + 2);
    269         memcpy(pszDllName, strInjectDllName.c_str(), strInjectDllName.length());
    270         // 确定 DllName 的位置
    271         pszDllName[strInjectDllName.length() + 1] = 0;
    272         // 确定 IMAGE_IMPORT_BY_NAM 的位置 
    273         PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllName + strInjectDllName.length() + 1);
    274         // 初始化 IMAGE_THUNK_DATA
    275         pNewThunkData->u1.Ordinal = (DWORD_PTR)pImportByName - (DWORD_PTR)FileData + /*加上修正值 - 这里应该填充在内存中的地址*/dwDelt;
    276         // 初始化 IMAGE_IMPORT_BY_NAME
    277         pImportByName->Hint = 1;
    278         memcpy(pImportByName->Name, strFunctionName.c_str(), strFunctionName.length());
    279         pImportByName->Name[strFunctionName.length() + 1] = 0;
    280         // 初始化 PIMAGE_IMPORT_DESCRIPTOR
    281         if (bBoundImport)
    282         {
    283             ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = 0;
    284         }
    285         else
    286         {
    287             ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
    288         }
    289         ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->FirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
    290         ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->Name = dwDelt + (DWORD_PTR)pszDllName - (DWORD_PTR)FileData;
    291         // 修改导入表入口
    292         pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = pNewSectionHeader->VirtualAddress;
    293         pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (i + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
    294     }
    295     catch (exception* e)
    296     {
    297         ERROR_MESSAGE((string("AddNewImportDescriptor:") + e->what()).c_str());
    298         bOk = false;
    299     }
    300 
    301 EXIT:
    302     {
    303         if (TargetFileHandle != NULL)
    304         {
    305             CloseHandle(TargetFileHandle);
    306             TargetFileHandle = nullptr;
    307         }
    308 
    309         if (FileData != NULL)
    310         {
    311             UnmapViewOfFile(FileData);
    312             FileData = nullptr;
    313         }
    314 
    315         if (MappingHandle != NULL)
    316         {
    317             CloseHandle(MappingHandle);
    318             MappingHandle = nullptr;
    319         }
    320     }
    321 
    322     return bOk;
    323 }
    324 
    325 PIMAGE_SECTION_HEADER GetOwnerSection(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
    326 {
    327     int i;
    328     PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pNTHeaders + 1);
    329     for (i = 0; i < pNTHeaders->FileHeader.NumberOfSections; i++)
    330     {
    331         if ((dwRVA >= (pSectionHeader + i)->VirtualAddress) && (dwRVA <= ((pSectionHeader + i)->VirtualAddress + (pSectionHeader + i)->SizeOfRawData)))
    332         {
    333             return ((PIMAGE_SECTION_HEADER)(pSectionHeader + i));
    334         }
    335     }
    336     return PIMAGE_SECTION_HEADER(NULL);
    337 }
    338 
    339 DWORD RVAToFOA(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
    340 {
    341     DWORD _offset;
    342     PIMAGE_SECTION_HEADER section;
    343     // 找到偏移所在节
    344     section = GetOwnerSection(pNTHeaders, dwRVA);
    345     if (section == NULL)
    346     {
    347         return(0);
    348     }
    349     // 修正偏移
    350     _offset = dwRVA + section->PointerToRawData - section->VirtualAddress;
    351     return(_offset);
    352 }
  • 相关阅读:
    【数据结构】堆栈
    【数据结构】线性表
    【算法】最大子列和问题
    【算法】复杂度的渐近表示
    【算法】什么是好的算法
    【算法】什么是算法
    【数据结构】什么是数据结构
    MySQL数据备份脚本
    二进制安装MySQL-5.7.28
    搭建zabbix+grafana监控
  • 原文地址:https://www.cnblogs.com/HsinTsao/p/7435137.html
Copyright © 2020-2023  润新知