在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得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 }