001
/*
002 Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。
003 直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导入表就被拖出来了。
004 */
005 #include "stdafx.h"
006 #include
007
008 typedef IMAGE_SECTION_HEADER (*PIMAGE_SECTION_HEADERS)[1];
009
010 // 计算对齐后的大小
011 unsigned long GetAlignedSize( unsigned long Origin, unsigned long Alignment)
012 {
013 return (Origin + Alignment - 1) / Alignment * Alignment;
014 }
015
016 // 计算加载pe并对齐需要占用多少内存
017 // 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0
018 unsigned long CalcTotalImageSize(PIMAGE_DOS_HEADER MzH,
019 unsigned long FileLen,
020 PIMAGE_NT_HEADERS peH,
021 PIMAGE_SECTION_HEADERS peSecH)
022 {
023 unsigned long res;
024 // 计算pe头的大小
025 res = GetAlignedSize( peH->OptionalHeader.SizeOfHeaders, peH->OptionalHeader.SectionAlignment);
026
027 // 计算所有节的大小
028 for( int i = 0; i < peH->FileHeader.NumberOfSections; ++i)
029 {
030 // 超出文件范围
031 if(peSecH[i]->PointerToRawData + peSecH[i]->SizeOfRawData > FileLen)
032 return 0;
033 else if(peSecH[i]->VirtualAddress) //计算对齐后某节的大小
034 {
035 if(peSecH[i]->Misc.VirtualSize)
036 {
037 res = GetAlignedSize( peSecH[i]->VirtualAddress + peSecH[i]->Misc.VirtualSize,
038 peH->OptionalHeader.SectionAlignment);
039 }
040 else
041 {
042 res = GetAlignedSize(peSecH[i]->VirtualAddress + peSecH[i]->SizeOfRawData,
043 peH->OptionalHeader.SectionAlignment);
044 }
045 }
046 else if( peSecH[i]->Misc.VirtualSize < peSecH[i]->SizeOfRawData )
047 {
048 res += GetAlignedSize( peSecH[i]->SizeOfRawData, peH->OptionalHeader.SectionAlignment);
049 }
050 else
051 {
052 res += GetAlignedSize( peSecH[i]->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment);
053 } // if_else
054 } // for
055
056 return res;
057 }
058
059
060
061
062 // 加载pe到内存并对齐所有节
063 BOOL AlignPEToMem( void *Buf,
064 long Len,
065 PIMAGE_NT_HEADERS &peH,
066 PIMAGE_SECTION_HEADERS &peSecH,
067 void *&Mem,
068 unsigned long &ImageSize)
069 {
070 PIMAGE_DOS_HEADER SrcMz; // DOS头
071 PIMAGE_NT_HEADERS SrcPeH; // PE头
072 PIMAGE_SECTION_HEADERS SrcPeSecH; // 节表
073
074 SrcMz = (PIMAGE_DOS_HEADER)Buf;
075
076 if( Len < sizeof(IMAGE_DOS_HEADER) )
077 return FALSE;
078
079 if( SrcMz->e_magic != IMAGE_DOS_SIGNATURE )
080 return FALSE;
081
082 if( Len < SrcMz->e_lfanew + ( long) sizeof(IMAGE_NT_HEADERS) )
083 return FALSE;
084
085 SrcPeH = (PIMAGE_NT_HEADERS)(( int)SrcMz + SrcMz->e_lfanew);
086 if( SrcPeH->Signature != IMAGE_NT_SIGNATURE )
087 return FALSE;
088
089 if( (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
090 (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0) ||
091 (SrcPeH->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
092 )
093 {
094 return FALSE;
095 }
096
097
098 SrcPeSecH = (PIMAGE_SECTION_HEADERS)(( int)SrcPeH + sizeof(IMAGE_NT_HEADERS));
099 ImageSize = CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH);
100
101 if( ImageSize == 0 )
102 return FALSE;
103
104 Mem = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存
105 if( Mem != NULL )
106 {
107 // 计算需要复制的PE头字节数
108 unsigned long l = SrcPeH->OptionalHeader.SizeOfHeaders;
109 for( int i = 0; i < SrcPeH->FileHeader.NumberOfSections; ++i)
110 {
111 if( (SrcPeSecH[i]->PointerToRawData) &&
112 (SrcPeSecH[i]->PointerToRawData < l) )
113 {
114 l = SrcPeSecH[i]->PointerToRawData;
115 }
116 }
117 memmove( Mem, SrcMz, l);
118 peH = (PIMAGE_NT_HEADERS)(( int)Mem + ((PIMAGE_DOS_HEADER)Mem)->e_lfanew);
119 peSecH = (PIMAGE_SECTION_HEADERS)(( int)peH + sizeof(IMAGE_NT_HEADERS));
120
121 void *Pt = ( void *)(( unsigned long)Mem + GetAlignedSize( peH->OptionalHeader.SizeOfHeaders,
122 peH->OptionalHeader.SectionAlignment));
123
124 for( i = 0; i < peH->FileHeader.NumberOfSections; ++i)
125 {
126 // 定位该节在内存中的位置
127 if(peSecH[i]->VirtualAddress)
128 Pt = ( void *)(( unsigned long)Mem + peSecH[i]->VirtualAddress);
129
130 if(peSecH[i]->SizeOfRawData)
131 {
132 // 复制数据到内存
133 memmove(Pt,
134 (const void *)(( unsigned long)(SrcMz) + peSecH[i]->PointerToRawData),
135 peSecH[i]->SizeOfRawData);
136
137 if(peSecH[i]->Misc.VirtualSize < peSecH[i]->SizeOfRawData)
138 {
139 Pt = ( void *)(( unsigned long)Pt + GetAlignedSize(peSecH[i]->SizeOfRawData,
140 peH->OptionalHeader.SectionAlignment));
141 }
142 else // pt 定位到下一节开始位置
143 {
144 Pt = ( void *)(( unsigned long)Pt + GetAlignedSize(peSecH[i]->Misc.VirtualSize,
145 peH->OptionalHeader.SectionAlignment));
146 }
147 }
148 else
149 {
150 Pt = ( void *)(( unsigned long)Pt + GetAlignedSize(peSecH[i]->Misc.VirtualSize,
151 peH->OptionalHeader.SectionAlignment));
152 }
153 }
154 }
155 return TRUE;
156 }
157
158
159
160 typedef void *( __stdcall *pfVirtualAllocEx)( unsigned long, void *, unsigned long, unsigned long, unsigned long);
161 pfVirtualAllocEx MyVirtualAllocEx = NULL;
162
163 BOOL IsNT()
164 {
165 return MyVirtualAllocEx!=NULL;
166 }
167
168 // 生成外壳程序命令行
169 char *PrepareShellExe( char *CmdParam, unsigned long BaseAddr, unsigned long ImageSize)
170 {
171 if(IsNT())
172 {
173 char *Buf = new char[256];
174 memset(Buf, 0, 256);
175 GetModuleFileName(0, Buf, 256);
176 strcat(Buf, CmdParam);
177 return Buf; // 请记得释放内存;-)
178 }
179 else
180 {
181 // Win98下的处理请参考原文;-)
182 // http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03
183 return NULL;
184 }
185 }
186
187 // 是否包含可重定向列表
188 BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH)
189 {
190 return (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
191 && (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
192 }
193
194
195
196
197 #pragma pack( push, 1)
198 typedef struct{
199 unsigned long VirtualAddress;
200 unsigned long SizeOfBlock;
201 }*PImageBaseRelocation;
202 #pragma pack( pop)
203
204 // 重定向PE用到的地址
205 void DoRelocation(PIMAGE_NT_HEADERS peH, void *OldBase, void *NewBase)
206 {
207 unsigned long Delta = ( unsigned long)NewBase - peH->OptionalHeader.ImageBase;
208 PImageBaseRelocation p = (PImageBaseRelocation)(( unsigned long)OldBase
209 + peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
210 while(p->VirtualAddress + p->SizeOfBlock)
211 {
212 unsigned short *pw = ( unsigned short *)(( int)p + sizeof(*p));
213 for( unsigned int i=1; i <= (p->SizeOfBlock - sizeof(*p)) / 2; ++i)
214 {
215 if((*pw) & 0xF000 == 0x3000)
216 {
217 unsigned long *t = ( unsigned long *)(( unsigned long)(OldBase) + p->VirtualAddress + ((*pw) & 0x0FFF));
218 *t += Delta;
219 }
220 ++pw;
221 }
222 p = (PImageBaseRelocation)pw;
223 }
224 }
225
226 // 卸载原外壳占用内存
227 BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr)
228 {
229 typedef unsigned long ( __stdcall *pfZwUnmapViewOfSection)( unsigned long, unsigned long);
230 pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
231 BOOL res = FALSE;
232 HMODULE m = LoadLibrary( "ntdll.dll");
233 if(m)
234 {
235 ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, "ZwUnmapViewOfSection");
236 if(ZwUnmapViewOfSection)
237 {
238 res = (ZwUnmapViewOfSection(( unsigned long)ProcHnd, BaseAddr) == 0);
239 }
240 FreeLibrary(m);
241 }
242 return res;
243 }
244
245 // 创建外壳进程并获取其基址、大小和当前运行状态
246 BOOL CreateChild( char *Cmd,
247 CONTEXT &Ctx,
248 HANDLE &ProcHnd,
249 HANDLE &ThrdHnd,
250 unsigned long &ProcId,
251 unsigned long &BaseAddr,
252 unsigned long &ImageSize)
253 {
254 STARTUPINFOA si;
255 PROCESS_INFORMATION pi;
256 unsigned long old;
257 MEMORY_BASIC_INFORMATION MemInfo;
258 memset(& si, 0, sizeof( si));
259 memset(&pi, 0, sizeof(pi));
260 si.cb = sizeof( si);
261
262 BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, & si, &pi); // 以挂起方式运行进程;
263 if(res)
264 {
265 ProcHnd = pi.hProcess;
266 ThrdHnd = pi.hThread;
267 ProcId = pi.dwProcessId;
268 // 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址
269 Ctx.ContextFlags = CONTEXT_FULL;
270 GetThreadContext(ThrdHnd, &Ctx);
271 ReadProcessMemory(ProcHnd, ( void *)(Ctx.Ebx+8), &BaseAddr, sizeof( unsigned long), &old); // 读取加载基址
272 void *p = ( void *)BaseAddr;
273 // 计算外壳进程占有的内存
274 while(VirtualQueryEx(ProcHnd, p, &MemInfo, sizeof(MemInfo)))
275 {
276 if(MemInfo.State = MEM_FREE) break;
277 p = ( void *)(( unsigned long)p + MemInfo.RegionSize);
278 }
279 ImageSize = ( unsigned long)p - ( unsigned long)BaseAddr;
280 }
281 return res;
282 }
283
284 // 创建外壳进程并用目标进程替换它然后执行
285 HANDLE AttachPE( char *CmdParam,
286 PIMAGE_NT_HEADERS peH,
287 PIMAGE_SECTION_HEADERS peSecH,
288 void *Ptr,
289 unsigned long ImageSize,
290 unsigned long &ProcId)
291 {
292 HANDLE res = INVALID_HANDLE_VALUE;
293 CONTEXT Ctx;
294 HANDLE Thrd;
295 unsigned long Addr, Size;
296 char *s = PrepareShellExe(CmdParam, peH->OptionalHeader.ImageBase, ImageSize);
297 if(s==NULL) return res;
298 if(CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size))
299 {
300 void *p = NULL;
301 unsigned long old;
302 if((peH->OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)) // 外壳进程可以容纳目标进程并且加载地址一致
303 {
304 p = ( void *)Addr;
305 VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE, &old);
306 }
307 else if(IsNT())
308 {
309 if(UnloadShell(res, Addr)) // 卸载外壳进程占有内存
310 {
311 p = MyVirtualAllocEx(( unsigned long)res,
312 ( void *)peH->OptionalHeader.ImageBase,
313 ImageSize,
314 MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
315 }
316 if((p == NULL) && HasRelocationTable(peH))
317 { // 分配内存失败并且目标进程支持重定向
318 p = MyVirtualAllocEx(( unsigned long)res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
319 if(p) DoRelocation(peH, Ptr, p); // 重定向
320 }
321 }
322 if(p)
323 {
324 WriteProcessMemory(res, ( void *)(Ctx.Ebx+8), &p, sizeof(DWORD), &old); // 重置目标进程运行环境中的基址
325 peH->OptionalHeader.ImageBase = ( unsigned long)p;
326 if(WriteProcessMemory(res, p, Ptr, ImageSize, &old)) // 复制PE数据到目标进程
327 {
328 Ctx.ContextFlags = CONTEXT_FULL;
329 if(( unsigned long)p == Addr)
330 {
331 Ctx.Eax = peH->OptionalHeader.ImageBase + peH->OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址
332 }
333 else
334 {
335 Ctx.Eax = ( unsigned long)p + peH->OptionalHeader.AddressOfEntryPoint;
336 }
337 SetThreadContext(Thrd, &Ctx); // 更新运行环境
338 ResumeThread(Thrd); // 执行
339 CloseHandle(Thrd);
340 }
341 else // 加载失败,杀掉外壳进程
342 {
343 TerminateProcess(res, 0);
344 CloseHandle(Thrd);
345 CloseHandle(res);
346 res = INVALID_HANDLE_VALUE;
347 }
348 }
349 else // 加载失败,杀掉外壳进程
350 {
351 TerminateProcess(res, 0);
352 CloseHandle(Thrd);
353 CloseHandle(res);
354 res = INVALID_HANDLE_VALUE;
355 }
356 }
357 delete[] s;
358 return res;
359 }
360
361
362
363
364 /**/ /**/ /**/ /*******************************************************
365 { ******************************************************* }
366 { * 从内存中加载并运行exe * }
367 { ******************************************************* }
368 { * 参数: }
369 { * Buffer: 内存中的exe地址 }
370 { * Len: 内存中exe占用长度 }
371 { * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)}
372 { * ProcessId: 返回的进程Id }
373 { * 返回值: 如果成功则返回进程的Handle(ProcessHandle), }
374 { 如果失败则返回INVALID_HANDLE_VALUE }
375 { ******************************************************* }
376 *******************************************************/
377 HANDLE MemExecute( void *ABuffer, long Len, char *CmdParam, unsigned long *ProcessId)
378 {
379 HANDLE res = INVALID_HANDLE_VALUE;
380 PIMAGE_NT_HEADERS peH;
381 PIMAGE_SECTION_HEADERS peSecH;
382 void *Ptr;
383 unsigned long peSz;
384 if(AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz))
385 {
386 res = AttachPE(CmdParam, peH, peSecH, Ptr, peSz, *ProcessId);
387 VirtualFree(Ptr, peSz, MEM_DECOMMIT);
388 }
389 return res;
390 }
391
392 // 初始化
393 class CInit
394 {
395 public:
396 CInit()
397 {
398 MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle( "Kernel32.dll"), "VirtualAllocEx");
399 }
400 }Init;
401
402
403
404
405 int main( int argc, char **argv)
406 {
407 HANDLE hFile = NULL;
408 hFile = ::CreateFile( "C://Windows//System32//cmd.exe",
409 FILE_ALL_ACCESS,
410 0, NULL, OPEN_EXISTING,
411 FILE_ATTRIBUTE_NORMAL, NULL
412 );
413 if( hFile == INVALID_HANDLE_VALUE )
414 return -1;
415
416 ::SetFilePointer( hFile, 0, NULL, FILE_BEGIN);
417 DWORD dwFileSize = ::GetFileSize( hFile, NULL);
418
419 LPBYTE pBuf = new BYTE[dwFileSize];
420 memset( pBuf, 0, dwFileSize);
421
422 DWORD dwNumberOfBytesRead = 0;
423 ::ReadFile( hFile,
424 pBuf,
425 dwFileSize,
426 &dwNumberOfBytesRead,
427 NULL );
428
429 ::CloseHandle(hFile);
430
431 unsigned long ulProcessId = 0;
432 MemExecute( pBuf, dwFileSize, "", &ulProcessId);
433 delete[] pBuf;
434
435
436 return 0;
437 }
002 Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。
003 直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导入表就被拖出来了。
004 */
005 #include "stdafx.h"
006 #include
007
008 typedef IMAGE_SECTION_HEADER (*PIMAGE_SECTION_HEADERS)[1];
009
010 // 计算对齐后的大小
011 unsigned long GetAlignedSize( unsigned long Origin, unsigned long Alignment)
012 {
013 return (Origin + Alignment - 1) / Alignment * Alignment;
014 }
015
016 // 计算加载pe并对齐需要占用多少内存
017 // 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0
018 unsigned long CalcTotalImageSize(PIMAGE_DOS_HEADER MzH,
019 unsigned long FileLen,
020 PIMAGE_NT_HEADERS peH,
021 PIMAGE_SECTION_HEADERS peSecH)
022 {
023 unsigned long res;
024 // 计算pe头的大小
025 res = GetAlignedSize( peH->OptionalHeader.SizeOfHeaders, peH->OptionalHeader.SectionAlignment);
026
027 // 计算所有节的大小
028 for( int i = 0; i < peH->FileHeader.NumberOfSections; ++i)
029 {
030 // 超出文件范围
031 if(peSecH[i]->PointerToRawData + peSecH[i]->SizeOfRawData > FileLen)
032 return 0;
033 else if(peSecH[i]->VirtualAddress) //计算对齐后某节的大小
034 {
035 if(peSecH[i]->Misc.VirtualSize)
036 {
037 res = GetAlignedSize( peSecH[i]->VirtualAddress + peSecH[i]->Misc.VirtualSize,
038 peH->OptionalHeader.SectionAlignment);
039 }
040 else
041 {
042 res = GetAlignedSize(peSecH[i]->VirtualAddress + peSecH[i]->SizeOfRawData,
043 peH->OptionalHeader.SectionAlignment);
044 }
045 }
046 else if( peSecH[i]->Misc.VirtualSize < peSecH[i]->SizeOfRawData )
047 {
048 res += GetAlignedSize( peSecH[i]->SizeOfRawData, peH->OptionalHeader.SectionAlignment);
049 }
050 else
051 {
052 res += GetAlignedSize( peSecH[i]->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment);
053 } // if_else
054 } // for
055
056 return res;
057 }
058
059
060
061
062 // 加载pe到内存并对齐所有节
063 BOOL AlignPEToMem( void *Buf,
064 long Len,
065 PIMAGE_NT_HEADERS &peH,
066 PIMAGE_SECTION_HEADERS &peSecH,
067 void *&Mem,
068 unsigned long &ImageSize)
069 {
070 PIMAGE_DOS_HEADER SrcMz; // DOS头
071 PIMAGE_NT_HEADERS SrcPeH; // PE头
072 PIMAGE_SECTION_HEADERS SrcPeSecH; // 节表
073
074 SrcMz = (PIMAGE_DOS_HEADER)Buf;
075
076 if( Len < sizeof(IMAGE_DOS_HEADER) )
077 return FALSE;
078
079 if( SrcMz->e_magic != IMAGE_DOS_SIGNATURE )
080 return FALSE;
081
082 if( Len < SrcMz->e_lfanew + ( long) sizeof(IMAGE_NT_HEADERS) )
083 return FALSE;
084
085 SrcPeH = (PIMAGE_NT_HEADERS)(( int)SrcMz + SrcMz->e_lfanew);
086 if( SrcPeH->Signature != IMAGE_NT_SIGNATURE )
087 return FALSE;
088
089 if( (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
090 (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0) ||
091 (SrcPeH->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
092 )
093 {
094 return FALSE;
095 }
096
097
098 SrcPeSecH = (PIMAGE_SECTION_HEADERS)(( int)SrcPeH + sizeof(IMAGE_NT_HEADERS));
099 ImageSize = CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH);
100
101 if( ImageSize == 0 )
102 return FALSE;
103
104 Mem = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存
105 if( Mem != NULL )
106 {
107 // 计算需要复制的PE头字节数
108 unsigned long l = SrcPeH->OptionalHeader.SizeOfHeaders;
109 for( int i = 0; i < SrcPeH->FileHeader.NumberOfSections; ++i)
110 {
111 if( (SrcPeSecH[i]->PointerToRawData) &&
112 (SrcPeSecH[i]->PointerToRawData < l) )
113 {
114 l = SrcPeSecH[i]->PointerToRawData;
115 }
116 }
117 memmove( Mem, SrcMz, l);
118 peH = (PIMAGE_NT_HEADERS)(( int)Mem + ((PIMAGE_DOS_HEADER)Mem)->e_lfanew);
119 peSecH = (PIMAGE_SECTION_HEADERS)(( int)peH + sizeof(IMAGE_NT_HEADERS));
120
121 void *Pt = ( void *)(( unsigned long)Mem + GetAlignedSize( peH->OptionalHeader.SizeOfHeaders,
122 peH->OptionalHeader.SectionAlignment));
123
124 for( i = 0; i < peH->FileHeader.NumberOfSections; ++i)
125 {
126 // 定位该节在内存中的位置
127 if(peSecH[i]->VirtualAddress)
128 Pt = ( void *)(( unsigned long)Mem + peSecH[i]->VirtualAddress);
129
130 if(peSecH[i]->SizeOfRawData)
131 {
132 // 复制数据到内存
133 memmove(Pt,
134 (const void *)(( unsigned long)(SrcMz) + peSecH[i]->PointerToRawData),
135 peSecH[i]->SizeOfRawData);
136
137 if(peSecH[i]->Misc.VirtualSize < peSecH[i]->SizeOfRawData)
138 {
139 Pt = ( void *)(( unsigned long)Pt + GetAlignedSize(peSecH[i]->SizeOfRawData,
140 peH->OptionalHeader.SectionAlignment));
141 }
142 else // pt 定位到下一节开始位置
143 {
144 Pt = ( void *)(( unsigned long)Pt + GetAlignedSize(peSecH[i]->Misc.VirtualSize,
145 peH->OptionalHeader.SectionAlignment));
146 }
147 }
148 else
149 {
150 Pt = ( void *)(( unsigned long)Pt + GetAlignedSize(peSecH[i]->Misc.VirtualSize,
151 peH->OptionalHeader.SectionAlignment));
152 }
153 }
154 }
155 return TRUE;
156 }
157
158
159
160 typedef void *( __stdcall *pfVirtualAllocEx)( unsigned long, void *, unsigned long, unsigned long, unsigned long);
161 pfVirtualAllocEx MyVirtualAllocEx = NULL;
162
163 BOOL IsNT()
164 {
165 return MyVirtualAllocEx!=NULL;
166 }
167
168 // 生成外壳程序命令行
169 char *PrepareShellExe( char *CmdParam, unsigned long BaseAddr, unsigned long ImageSize)
170 {
171 if(IsNT())
172 {
173 char *Buf = new char[256];
174 memset(Buf, 0, 256);
175 GetModuleFileName(0, Buf, 256);
176 strcat(Buf, CmdParam);
177 return Buf; // 请记得释放内存;-)
178 }
179 else
180 {
181 // Win98下的处理请参考原文;-)
182 // http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03
183 return NULL;
184 }
185 }
186
187 // 是否包含可重定向列表
188 BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH)
189 {
190 return (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
191 && (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
192 }
193
194
195
196
197 #pragma pack( push, 1)
198 typedef struct{
199 unsigned long VirtualAddress;
200 unsigned long SizeOfBlock;
201 }*PImageBaseRelocation;
202 #pragma pack( pop)
203
204 // 重定向PE用到的地址
205 void DoRelocation(PIMAGE_NT_HEADERS peH, void *OldBase, void *NewBase)
206 {
207 unsigned long Delta = ( unsigned long)NewBase - peH->OptionalHeader.ImageBase;
208 PImageBaseRelocation p = (PImageBaseRelocation)(( unsigned long)OldBase
209 + peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
210 while(p->VirtualAddress + p->SizeOfBlock)
211 {
212 unsigned short *pw = ( unsigned short *)(( int)p + sizeof(*p));
213 for( unsigned int i=1; i <= (p->SizeOfBlock - sizeof(*p)) / 2; ++i)
214 {
215 if((*pw) & 0xF000 == 0x3000)
216 {
217 unsigned long *t = ( unsigned long *)(( unsigned long)(OldBase) + p->VirtualAddress + ((*pw) & 0x0FFF));
218 *t += Delta;
219 }
220 ++pw;
221 }
222 p = (PImageBaseRelocation)pw;
223 }
224 }
225
226 // 卸载原外壳占用内存
227 BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr)
228 {
229 typedef unsigned long ( __stdcall *pfZwUnmapViewOfSection)( unsigned long, unsigned long);
230 pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
231 BOOL res = FALSE;
232 HMODULE m = LoadLibrary( "ntdll.dll");
233 if(m)
234 {
235 ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, "ZwUnmapViewOfSection");
236 if(ZwUnmapViewOfSection)
237 {
238 res = (ZwUnmapViewOfSection(( unsigned long)ProcHnd, BaseAddr) == 0);
239 }
240 FreeLibrary(m);
241 }
242 return res;
243 }
244
245 // 创建外壳进程并获取其基址、大小和当前运行状态
246 BOOL CreateChild( char *Cmd,
247 CONTEXT &Ctx,
248 HANDLE &ProcHnd,
249 HANDLE &ThrdHnd,
250 unsigned long &ProcId,
251 unsigned long &BaseAddr,
252 unsigned long &ImageSize)
253 {
254 STARTUPINFOA si;
255 PROCESS_INFORMATION pi;
256 unsigned long old;
257 MEMORY_BASIC_INFORMATION MemInfo;
258 memset(& si, 0, sizeof( si));
259 memset(&pi, 0, sizeof(pi));
260 si.cb = sizeof( si);
261
262 BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, & si, &pi); // 以挂起方式运行进程;
263 if(res)
264 {
265 ProcHnd = pi.hProcess;
266 ThrdHnd = pi.hThread;
267 ProcId = pi.dwProcessId;
268 // 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址
269 Ctx.ContextFlags = CONTEXT_FULL;
270 GetThreadContext(ThrdHnd, &Ctx);
271 ReadProcessMemory(ProcHnd, ( void *)(Ctx.Ebx+8), &BaseAddr, sizeof( unsigned long), &old); // 读取加载基址
272 void *p = ( void *)BaseAddr;
273 // 计算外壳进程占有的内存
274 while(VirtualQueryEx(ProcHnd, p, &MemInfo, sizeof(MemInfo)))
275 {
276 if(MemInfo.State = MEM_FREE) break;
277 p = ( void *)(( unsigned long)p + MemInfo.RegionSize);
278 }
279 ImageSize = ( unsigned long)p - ( unsigned long)BaseAddr;
280 }
281 return res;
282 }
283
284 // 创建外壳进程并用目标进程替换它然后执行
285 HANDLE AttachPE( char *CmdParam,
286 PIMAGE_NT_HEADERS peH,
287 PIMAGE_SECTION_HEADERS peSecH,
288 void *Ptr,
289 unsigned long ImageSize,
290 unsigned long &ProcId)
291 {
292 HANDLE res = INVALID_HANDLE_VALUE;
293 CONTEXT Ctx;
294 HANDLE Thrd;
295 unsigned long Addr, Size;
296 char *s = PrepareShellExe(CmdParam, peH->OptionalHeader.ImageBase, ImageSize);
297 if(s==NULL) return res;
298 if(CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size))
299 {
300 void *p = NULL;
301 unsigned long old;
302 if((peH->OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)) // 外壳进程可以容纳目标进程并且加载地址一致
303 {
304 p = ( void *)Addr;
305 VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE, &old);
306 }
307 else if(IsNT())
308 {
309 if(UnloadShell(res, Addr)) // 卸载外壳进程占有内存
310 {
311 p = MyVirtualAllocEx(( unsigned long)res,
312 ( void *)peH->OptionalHeader.ImageBase,
313 ImageSize,
314 MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
315 }
316 if((p == NULL) && HasRelocationTable(peH))
317 { // 分配内存失败并且目标进程支持重定向
318 p = MyVirtualAllocEx(( unsigned long)res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
319 if(p) DoRelocation(peH, Ptr, p); // 重定向
320 }
321 }
322 if(p)
323 {
324 WriteProcessMemory(res, ( void *)(Ctx.Ebx+8), &p, sizeof(DWORD), &old); // 重置目标进程运行环境中的基址
325 peH->OptionalHeader.ImageBase = ( unsigned long)p;
326 if(WriteProcessMemory(res, p, Ptr, ImageSize, &old)) // 复制PE数据到目标进程
327 {
328 Ctx.ContextFlags = CONTEXT_FULL;
329 if(( unsigned long)p == Addr)
330 {
331 Ctx.Eax = peH->OptionalHeader.ImageBase + peH->OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址
332 }
333 else
334 {
335 Ctx.Eax = ( unsigned long)p + peH->OptionalHeader.AddressOfEntryPoint;
336 }
337 SetThreadContext(Thrd, &Ctx); // 更新运行环境
338 ResumeThread(Thrd); // 执行
339 CloseHandle(Thrd);
340 }
341 else // 加载失败,杀掉外壳进程
342 {
343 TerminateProcess(res, 0);
344 CloseHandle(Thrd);
345 CloseHandle(res);
346 res = INVALID_HANDLE_VALUE;
347 }
348 }
349 else // 加载失败,杀掉外壳进程
350 {
351 TerminateProcess(res, 0);
352 CloseHandle(Thrd);
353 CloseHandle(res);
354 res = INVALID_HANDLE_VALUE;
355 }
356 }
357 delete[] s;
358 return res;
359 }
360
361
362
363
364 /**/ /**/ /**/ /*******************************************************
365 { ******************************************************* }
366 { * 从内存中加载并运行exe * }
367 { ******************************************************* }
368 { * 参数: }
369 { * Buffer: 内存中的exe地址 }
370 { * Len: 内存中exe占用长度 }
371 { * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)}
372 { * ProcessId: 返回的进程Id }
373 { * 返回值: 如果成功则返回进程的Handle(ProcessHandle), }
374 { 如果失败则返回INVALID_HANDLE_VALUE }
375 { ******************************************************* }
376 *******************************************************/
377 HANDLE MemExecute( void *ABuffer, long Len, char *CmdParam, unsigned long *ProcessId)
378 {
379 HANDLE res = INVALID_HANDLE_VALUE;
380 PIMAGE_NT_HEADERS peH;
381 PIMAGE_SECTION_HEADERS peSecH;
382 void *Ptr;
383 unsigned long peSz;
384 if(AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz))
385 {
386 res = AttachPE(CmdParam, peH, peSecH, Ptr, peSz, *ProcessId);
387 VirtualFree(Ptr, peSz, MEM_DECOMMIT);
388 }
389 return res;
390 }
391
392 // 初始化
393 class CInit
394 {
395 public:
396 CInit()
397 {
398 MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle( "Kernel32.dll"), "VirtualAllocEx");
399 }
400 }Init;
401
402
403
404
405 int main( int argc, char **argv)
406 {
407 HANDLE hFile = NULL;
408 hFile = ::CreateFile( "C://Windows//System32//cmd.exe",
409 FILE_ALL_ACCESS,
410 0, NULL, OPEN_EXISTING,
411 FILE_ATTRIBUTE_NORMAL, NULL
412 );
413 if( hFile == INVALID_HANDLE_VALUE )
414 return -1;
415
416 ::SetFilePointer( hFile, 0, NULL, FILE_BEGIN);
417 DWORD dwFileSize = ::GetFileSize( hFile, NULL);
418
419 LPBYTE pBuf = new BYTE[dwFileSize];
420 memset( pBuf, 0, dwFileSize);
421
422 DWORD dwNumberOfBytesRead = 0;
423 ::ReadFile( hFile,
424 pBuf,
425 dwFileSize,
426 &dwNumberOfBytesRead,
427 NULL );
428
429 ::CloseHandle(hFile);
430
431 unsigned long ulProcessId = 0;
432 MemExecute( pBuf, dwFileSize, "", &ulProcessId);
433 delete[] pBuf;
434
435
436 return 0;
437 }