3 编程实现 //为了简化代码,下面程序中去掉了对出错处理的代码,实际应用中应考虑程序运行时可能的出错 #include "stdafx.h" static PIMAGE_NT_HEADERS nt_header; #define IMAGESIZE (nt_header->OptionalHeader.SizeOfImage) #define EXPORT_TABEL (nt_header->OptionalHeader.DataDirectory[0].VirtualAddress) #define RELOC_TABEL (nt_header->OptionalHeader.DataDirectory[5].VirtualAddress) static void RelocCode (PBYTE Image, LPBYTE InjectBase) // 完成代码的重定位 { DWORD Rva = 0, RvaCount = 0, RelocOffset=0; WORD *Offset = NULL; LPBYTE RelocTable = Image + RELOC_TABEL; //重定位表位置 PIMAGE_BASE_RELOCATION basereloc= (PIMAGE_BASE_RELOCATION) RelocTable; RelocOffset= (DWORD)InjectBase - nt_header ->OptionalHeader.ImageBase; //重定位表偏移 while(basereloc ->VirtualAddress != NULL)// 遍历重定位表,修正需要重定位的代码 { Offset = (WORD*)(RelocTable + sizeof(IMAGE_BASE_RELOCATION)); RvaCount = (basereloc ->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2; for(DWORD i=0; i<RvaCount; i++) { Rva = Offset[i]; if(( Rva & 0xf000) != 0x3000) continue;//高4位为03H表示需要修正 Rva &= 0x0fff;//取出低12位,即重定位代码的相对虚拟地址 Rva += basereloc ->VirtualAddress + (DWORD)Image; *(DWORD*)Rva += RelocOffset;//RVA加上修正量进行修正 } RelocTable += basereloc ->SizeOfBlock;//指向下一页重定位信息处 basereloc = (PIMAGE_BASE_RELOCATION) RelocTable; } } int LoadAPI(LPBYTE InjectBase)// 用于完成API函数的导入,参数为要插入代码处地址 { PIMAGE_DOS_HEADER dos_h = (PIMAGE_DOS_HEADER) InjectBase; PIMAGE_NT_HEADERS nt_h = (PIMAGE_NT_HEADERS)(InjectBase + dos_h->e_lfanew); PIMAGE_IMPORT_DESCRIPTOR import_d = (PIMAGE_IMPORT_DESCRIPTOR) (InjectBase + nt_h->OptionalHeader.DataDirectory[1].VirtualAddress); for( ; import_d->OriginalFirstThunk != 0; import_d++)//遍历导入表 { HMODULE hDll = LoadLibrary((LPCSTR)(InjectBase + import_d->Name)); //上面能直接引用LoadLibrary是由于本地和远程进程中该函数地址都是相同的 if(hDll == NULL) return 0; PIMAGE_THUNK_DATA Origin = (PIMAGE_THUNK_DATA)(InjectBase + import_d->OriginalFirstThunk); PIMAGE_THUNK_DATA First = (PIMAGE_THUNK_DATA)(InjectBase + import_d->FirstThunk); LPCSTR Name = NULL; PIMAGE_IMPORT_BY_NAME Import_name = NULL; for(; Origin->u1.Ordinal != 0; Origin++, First++) { if(Origin->u1.Ordinal & IMAGE_ORDINAL_FLAG) Name = (LPCSTR)IMAGE_ORDINAL(Origin->u1.Ordinal); else{ Import_name = (PIMAGE_IMPORT_BY_NAME)(InjectBase + (DWORD)( Origin->u1.AddressOfData)); Name = (LPCSTR)Import_name->Name; } First->u1.Function = (DWORD * )GetProcAddress(hDll, Name); //上面能直接引用GetProcAddress是由于本地和远程进程中该函数地址都是相同的 if(First->u1.Function == NULL) return 0; } } return 1; }
|