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