在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。1 typedef IMAGE_SECTION_HEADER ( * PIMAGE_SECTION_HEADERS)[ 1 ]; 2 3 // 计算对齐后的大小 4 unsigned long GetAlignedSize(unsigned long Origin, unsigned long Alignment) 5 { 6 return (Origin + Alignment - 1 ) / Alignment * Alignment; 7 } 8 9 // 计算加载pe并对齐需要占用多少内存 10 // 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0 11 unsigned long CalcTotalImageSize(PIMAGE_DOS_HEADER MzH 12 , unsigned long FileLen 13 , PIMAGE_NT_HEADERS peH 14 , PIMAGE_SECTION_HEADERS peSecH) 15 { 16 unsigned long res; 17 // 计算pe头的大小 18 res = GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders , peH -> OptionalHeader.SectionAlignment); 19 20 // 计算所有节的大小 21 for ( int i = 0 ; i < peH -> FileHeader.NumberOfSections; ++ i) 22 { 23 // 超出文件范围 24 if (peSecH[i] -> PointerToRawData + peSecH[i] -> SizeOfRawData > FileLen) 25 { 26 return 0 ; 27 } 28 else if (peSecH[i] -> VirtualAddress) // 计算对齐后某节的大小 29 { 30 if (peSecH[i] -> Misc.VirtualSize) 31 { 32 res = GetAlignedSize( peSecH[i] -> VirtualAddress + peSecH[i] -> Misc.VirtualSize 33 , peH -> OptionalHeader.SectionAlignment); 34 } 35 else 36 { 37 res = GetAlignedSize( peSecH[i] -> VirtualAddress + peSecH[i] -> SizeOfRawData 38 , peH -> OptionalHeader.SectionAlignment); 39 } 40 } 41 else if ( peSecH[i] -> Misc.VirtualSize < peSecH[i] -> SizeOfRawData ) 42 { 43 res += GetAlignedSize( peSecH[i] -> SizeOfRawData 44 , peH -> OptionalHeader.SectionAlignment); 45 } 46 else 47 { 48 res += GetAlignedSize( peSecH[i] -> Misc.VirtualSize 49 , peH -> OptionalHeader.SectionAlignment); 50 } // if_else 51 } // for 52 53 return res; 54 } 55 56 57 58 59 // 加载pe到内存并对齐所有节 60 BOOL AlignPEToMem( void * Buf 61 , long Len 62 , PIMAGE_NT_HEADERS & peH 63 , PIMAGE_SECTION_HEADERS & peSecH 64 , void *& Mem 65 , unsigned long & ImageSize) 66 { 67 PIMAGE_DOS_HEADER SrcMz; // DOS头 68 PIMAGE_NT_HEADERS SrcPeH; // PE头 69 PIMAGE_SECTION_HEADERS SrcPeSecH; // 节表 70 71 SrcMz = (PIMAGE_DOS_HEADER)Buf; 72 73 if ( Len < sizeof (IMAGE_DOS_HEADER) ) 74 return FALSE; 75 76 if ( SrcMz -> e_magic != IMAGE_DOS_SIGNATURE ) 77 return FALSE; 78 79 if ( Len < SrcMz -> e_lfanew + ( long ) sizeof (IMAGE_NT_HEADERS) ) 80 return FALSE; 81 82 SrcPeH = (PIMAGE_NT_HEADERS)(( int )SrcMz + SrcMz -> e_lfanew); 83 if ( SrcPeH -> Signature != IMAGE_NT_SIGNATURE ) 84 return FALSE; 85 86 if ( (SrcPeH -> FileHeader.Characteristics & IMAGE_FILE_DLL) || 87 (SrcPeH -> FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0 ) || 88 (SrcPeH -> FileHeader.SizeOfOptionalHeader != sizeof (IMAGE_OPTIONAL_HEADER)) ) 89 { 90 return FALSE; 91 } 92 93 94 SrcPeSecH = (PIMAGE_SECTION_HEADERS)(( int )SrcPeH + sizeof (IMAGE_NT_HEADERS)); 95 ImageSize = CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH); 96 97 if ( ImageSize == 0 ) 98 return FALSE; 99 100 Mem = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存 101 if ( Mem != NULL ) 102 { 103 // 计算需要复制的PE头字节数 104 unsigned long l = SrcPeH -> OptionalHeader.SizeOfHeaders; 105 for ( int i = 0 ; i < SrcPeH -> FileHeader.NumberOfSections; ++ i) 106 { 107 if ( (SrcPeSecH[i] -> PointerToRawData) && 108 (SrcPeSecH[i] -> PointerToRawData < l) ) 109 { 110 l = SrcPeSecH[i] -> PointerToRawData; 111 } 112 } 113 memmove( Mem, SrcMz, l); 114 peH = (PIMAGE_NT_HEADERS)(( int )Mem + ((PIMAGE_DOS_HEADER)Mem) -> e_lfanew); 115 peSecH = (PIMAGE_SECTION_HEADERS)(( int )peH + sizeof (IMAGE_NT_HEADERS)); 116 117 void * Pt = ( void * )((unsigned long )Mem 118 + GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders 119 , peH -> OptionalHeader.SectionAlignment) 120 ); 121 122 for ( i = 0 ; i < peH -> FileHeader.NumberOfSections; ++ i) 123 { 124 // 定位该节在内存中的位置 125 if (peSecH[i] -> VirtualAddress) 126 Pt = ( void * )((unsigned long )Mem + peSecH[i] -> VirtualAddress); 127 128 if (peSecH[i] -> SizeOfRawData) 129 { 130 // 复制数据到内存 131 memmove(Pt, ( const void * )((unsigned long )(SrcMz) + peSecH[i] -> PointerToRawData), peSecH[i] -> SizeOfRawData); 132 if (peSecH[i] -> Misc.VirtualSize < peSecH[i] -> SizeOfRawData) 133 Pt = ( void * )((unsigned long )Pt + GetAlignedSize(peSecH[i] -> SizeOfRawData, peH -> OptionalHeader.SectionAlignment)); 134 else // pt 定位到下一节开始位置 135 Pt = ( void * )((unsigned long )Pt + GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignment)); 136 } 137 else 138 { 139 Pt = ( void * )((unsigned long )Pt + GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignment)); 140 } 141 } 142 } 143 return TRUE; 144 } 145 146 147 148 typedef void * (__stdcall * pfVirtualAllocEx)(unsigned long , void * , unsigned long , unsigned long , unsigned long ); 149 pfVirtualAllocEx MyVirtualAllocEx = NULL; 150 151 BOOL IsNT() 152 { 153 return MyVirtualAllocEx != NULL; 154 } 155 156 // 生成外壳程序命令行 157 char * PrepareShellExe( char * CmdParam, unsigned long BaseAddr, unsigned long ImageSize) 158 { 159 if (IsNT()) 160 { 161 char * Buf = new char [ 256 ]; 162 memset(Buf, 0 , 256 ); 163 GetModuleFileName( 0 , Buf, 256 ); 164 strcat(Buf, CmdParam); 165 return Buf; // 请记得释放内存;-) 166 } 167 else 168 { 169 // Win98 170 171 return NULL; 172 } 173 } 174 175 // 是否包含可重定向列表 176 BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH) 177 { 178 return (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) 179 && (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); 180 } 181 182 183 184 185 #pragma pack(push, 1 ) 186 typedef struct { 187 unsigned long VirtualAddress; 188 unsigned long SizeOfBlock; 189 } * PImageBaseRelocation; 190 #pragma pack(pop) 191 192 // 重定向PE用到的地址 193 void DoRelocation(PIMAGE_NT_HEADERS peH, void * OldBase, void * NewBase) 194 { 195 unsigned long Delta = (unsigned long )NewBase - peH -> OptionalHeader.ImageBase; 196 PImageBaseRelocation p = (PImageBaseRelocation)((unsigned long )OldBase 197 + peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); 198 while (p -> VirtualAddress + p -> SizeOfBlock) 199 { 200 unsigned short * pw = (unsigned short * )(( int )p + sizeof ( * p)); 201 for (unsigned int i = 1 ; i <= (p -> SizeOfBlock - sizeof ( * p)) / 2 ; ++ i) 202 { 203 if (( * pw) & 0xF000 == 0x3000 ) { 204 unsigned long * t = (unsigned long * )((unsigned long )(OldBase) + p -> VirtualAddress + (( * pw) & 0x0FFF )); 205 * t += Delta; 206 } 207 ++ pw; 208 } 209 p = (PImageBaseRelocation)pw; 210 } 211 } 212 213 // 卸载原外壳占用内存 214 BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr) 215 { 216 typedef unsigned long (__stdcall * pfZwUnmapViewOfSection)(unsigned long , unsigned long ); 217 pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL; 218 BOOL res = FALSE; 219 HMODULE m = LoadLibrary( " ntdll.dll " ); 220 if (m) { 221 ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, " ZwUnmapViewOfSection " ); 222 if (ZwUnmapViewOfSection) 223 res = (ZwUnmapViewOfSection((unsigned long )ProcHnd, BaseAddr) == 0 ); 224 FreeLibrary(m); 225 } 226 return res; 227 } 228 229 // 创建外壳进程并获取其基址、大小和当前运行状态 230 BOOL CreateChild( char * Cmd, CONTEXT & Ctx, HANDLE & ProcHnd, HANDLE & ThrdHnd, 231 unsigned long & ProcId, unsigned long & BaseAddr, unsigned long & ImageSize) 232 { 233 STARTUPINFOA si; 234 PROCESS_INFORMATION pi; 235 unsigned long old; 236 MEMORY_BASIC_INFORMATION MemInfo; 237 memset( & si, 0 , sizeof (si)); 238 memset( & pi, 0 , sizeof (pi)); 239 si.cb = sizeof (si); 240 241 BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, & si, & pi); // 以挂起方式运行进程; 242 if (res) { 243 ProcHnd = pi.hProcess; 244 ThrdHnd = pi.hThread; 245 ProcId = pi.dwProcessId; 246 // 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址 247 Ctx.ContextFlags = CONTEXT_FULL; 248 GetThreadContext(ThrdHnd, & Ctx); 249 ReadProcessMemory(ProcHnd, ( void * )(Ctx.Ebx + 8 ), & BaseAddr, sizeof (unsigned long ), & old); // 读取加载基址 250 void * p = ( void * )BaseAddr; 251 // 计算外壳进程占有的内存 252 while (VirtualQueryEx(ProcHnd, p, & MemInfo, sizeof (MemInfo))) 253 { 254 if (MemInfo.State = MEM_FREE) break ; 255 p = ( void * )((unsigned long )p + MemInfo.RegionSize); 256 } 257 ImageSize = (unsigned long )p - (unsigned long )BaseAddr; 258 } 259 return res; 260 } 261 262 // 创建外壳进程并用目标进程替换它然后执行 263 HANDLE AttachPE( char * CmdParam, PIMAGE_NT_HEADERS peH, PIMAGE_SECTION_HEADERS peSecH, 264 void * Ptr, unsigned long ImageSize, unsigned long & ProcId) 265 { 266 HANDLE res = INVALID_HANDLE_VALUE; 267 CONTEXT Ctx; 268 HANDLE Thrd; 269 unsigned long Addr, Size; 270 char * s = PrepareShellExe(CmdParam, peH -> OptionalHeader.ImageBase, ImageSize); 271 if (s == NULL) return res; 272 if (CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size)) { 273 void * p = NULL; 274 unsigned long old; 275 if ((peH -> OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)) { // 外壳进程可以容纳目标进程并且加载地址一致 276 p = ( void * )Addr; 277 VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE, & old); 278 } 279 else if (IsNT()) { 280 if (UnloadShell(res, Addr)) { // 卸载外壳进程占有内存 281 p = MyVirtualAllocEx((unsigned long )res, ( void * )peH -> OptionalHeader.ImageBase, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 282 } 283 if ((p == NULL) && HasRelocationTable(peH)) { // 分配内存失败并且目标进程支持重定向 284 p = MyVirtualAllocEx((unsigned long )res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 285 if (p) DoRelocation(peH, Ptr, p); // 重定向 286 } 287 } 288 if (p) { 289 WriteProcessMemory(res, ( void * )(Ctx.Ebx + 8 ), & p, sizeof (DWORD), & old); // 重置目标进程运行环境中的基址 290 peH -> OptionalHeader.ImageBase = (unsigned long )p; 291 if (WriteProcessMemory(res, p, Ptr, ImageSize, & old)) { // 复制PE数据到目标进程 292 Ctx.ContextFlags = CONTEXT_FULL; 293 if ((unsigned long )p == Addr) 294 Ctx.Eax = peH -> OptionalHeader.ImageBase + peH -> OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址 295 else 296 Ctx.Eax = (unsigned long )p + peH -> OptionalHeader.AddressOfEntryPoint; 297 SetThreadContext(Thrd, & Ctx); // 更新运行环境 298 ResumeThread(Thrd); // 执行 299 CloseHandle(Thrd); 300 } 301 else { // 加载失败,杀掉外壳进程 302 TerminateProcess(res, 0 ); 303 CloseHandle(Thrd); 304 CloseHandle(res); 305 res = INVALID_HANDLE_VALUE; 306 } 307 } 308 else { // 加载失败,杀掉外壳进程 309 TerminateProcess(res, 0 ); 310 CloseHandle(Thrd); 311 CloseHandle(res); 312 res = INVALID_HANDLE_VALUE; 313 } 314 } 315 delete[] s; 316 return res; 317 } 318 319 320 321 322 /**/ /**/ /**/ /* ******************************************************/ 323 { ******************************************************* } 324 { * 从内存中加载并运行exe * } 325 { ******************************************************* } 326 { * 参数: } 327 { * Buffer: 内存中的exe地址 } 328 { * Len: 内存中exe占用长度 } 329 { * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)} 330 { * ProcessId: 返回的进程Id } 331 { * 返回值: 如果成功则返回进程的Handle(ProcessHandle), } 332 { 如果失败则返回INVALID_HANDLE_VALUE } 333 { ******************************************************* } 334 /****************************************************** */ 335 HANDLE MemExecute( void * ABuffer, long Len, char * CmdParam, unsigned long * ProcessId) 336 { 337 HANDLE res = INVALID_HANDLE_VALUE; 338 PIMAGE_NT_HEADERS peH; 339 PIMAGE_SECTION_HEADERS peSecH; 340 void * Ptr; 341 unsigned long peSz; 342 if (AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz)) 343 { 344 res = AttachPE(CmdParam, peH, peSecH, Ptr, peSz, * ProcessId); 345 VirtualFree(Ptr, peSz, MEM_DECOMMIT); 346 } 347 return res; 348 } 349 350 // 初始化 351 class CInit 352 { 353 public : 354 CInit() 355 { 356 MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle( " Kernel32.dll " ), " VirtualAllocEx " ); 357 } 358 } Init; 359 360 361 362 363 364 365 366 int main( int argc, char * argv[]) 367 { 368 FILE * fp; 369 fp = fopen( " E://CProject//DBGVIEW.EXE " , " rb " ); 370 371 if ( fp ) 372 { 373 374 fseek(fp, 0l ,SEEK_END); 375 int file_size = ftell(fp); /**/ /* 获取文件长度 */ 376 fseek(fp, 0l ,SEEK_SET); /**/ /* 回到文件头部 */ 377 378 379 LPBYTE pBuf = new BYTE[file_size]; 380 memset( pBuf, 0 , file_size); 381 382 fread(pBuf,file_size, 1 ,fp); 383 384 DWORD id = GetCurrentProcessId(); 385 unsigned long ulProcessId = 0 ; 386 MemExecute( pBuf, file_size, "" , & ulProcessId); 387 delete[] pBuf; 388 389 } 390 391 return 0 ; 392 }
在内存中运行可执行程序
最新推荐文章于 2021-09-24 08:10:21 发布