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 }