直接运行内存中的exe

001#include "stdafx.h" 
002   
003   
004typedef IMAGE_SECTION_HEADER (*PIMAGE_SECTION_HEADERS)[1];  
005   
006// 计算对齐后的大小  
007unsigned 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  
014unsigned 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到内存并对齐所有节  
067BOOL 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   
155typedef void *(__stdcall *pfVirtualAllocEx)(unsigned long, void *, unsigned long, unsigned long, unsigned long);  
156pfVirtualAllocEx MyVirtualAllocEx = NULL;  
157   
158BOOL IsNT()  
159{  
160    return MyVirtualAllocEx!=NULL;  
161}  
162   
163// 生成外壳程序命令行  
164char *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// 是否包含可重定向列表  
183BOOL 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)  
193typedef struct{  
194    unsigned long VirtualAddress;  
195    unsigned long SizeOfBlock;  
196} *PImageBaseRelocation;  
197#pragma pack(pop)  
198   
199// 重定向PE用到的地址  
200void 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// 卸载原外壳占用内存  
221BOOL 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// 创建外壳进程并获取其基址、大小和当前运行状态  
237BOOL 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// 创建外壳进程并用目标进程替换它然后执行  
270HANDLE 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\*******************************************************/ 
342HANDLE 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// 初始化  
358class CInit  
359{  
360public:  
361    CInit()  
362    {  
363        MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle("Kernel32.dll"), "VirtualAllocEx");  
364    }  
365}Init;  
366   
367   
368   
369   
370int 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}

原文链接: 直接运行内存中的exe 版权所有,转载时请注明出处,违者必究。
注明出处格式:流沙团 ( https://gyarmy.com/post-605.html )

发表评论

0则评论给“直接运行内存中的exe”