在内存中运行可执行程序(转)
2016-05-26 16:50
218 查看
在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。
typedef IMAGE_SECTION_HEADER ( * PIMAGE_SECTION_HEADERS)[ 1 ]; // 计算对齐后的大小 unsigned long GetAlignedSize(unsigned long Origin, unsigned long Alignment) { return (Origin + Alignment - 1 ) / Alignment * Alignment; } // 计算加载pe并对齐需要占用多少内存 // 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0 unsigned long CalcTotalImageSize(PIMAGE_DOS_HEADER MzH , unsigned long FileLen , PIMAGE_NT_HEADERS peH , PIMAGE_SECTION_HEADERS peSecH) { unsigned long res; // 计算pe头的大小 res = GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders , peH -> OptionalHeader.SectionAlignment); // 计算所有节的大小 for ( int i = 0 ; i < peH -> FileHeader.NumberOfSections; ++ i) { // 超出文件范围 if (peSecH[i] -> PointerToRawData + peSecH[i] -> SizeOfRawData > FileLen) { return 0 ; } else if (peSecH[i] -> VirtualAddress) // 计算对齐后某节的大小 { if (peSecH[i] -> Misc.VirtualSize) { res = GetAlignedSize( peSecH[i] -> VirtualAddress + peSecH[i] -> Misc.VirtualSize , peH -> OptionalHeader.SectionAlignment); } else { res = GetAlignedSize( peSecH[i] -> VirtualAddress + peSecH[i] -> SizeOfRawData , peH -> OptionalHeader.SectionAlignment); } } else if ( peSecH[i] -> Misc.VirtualSize < peSecH[i] -> SizeOfRawData ) { res += GetAlignedSize( peSecH[i] -> SizeOfRawData , peH -> OptionalHeader.SectionAlignment); } else { res += GetAlignedSize( peSecH[i] -> Misc.VirtualSize , peH -> OptionalHeader.SectionAlignment); } // if_else } // for return res; } // 加载pe到内存并对齐所有节 BOOL AlignPEToMem( void * Buf , long Len , PIMAGE_NT_HEADERS & peH , PIMAGE_SECTION_HEADERS & peSecH , void *& Mem , unsigned long & ImageSize) { PIMAGE_DOS_HEADER SrcMz; // DOS头 PIMAGE_NT_HEADERS SrcPeH; // PE头 PIMAGE_SECTION_HEADERS SrcPeSecH; // 节表 SrcMz = (PIMAGE_DOS_HEADER)Buf; if ( Len < sizeof (IMAGE_DOS_HEADER) ) return FALSE; if ( SrcMz -> e_magic != IMAGE_DOS_SIGNATURE ) return FALSE; if ( Len < SrcMz -> e_lfanew + ( long ) sizeof (IMAGE_NT_HEADERS) ) return FALSE; SrcPeH = (PIMAGE_NT_HEADERS)(( int )SrcMz + SrcMz -> e_lfanew); if ( SrcPeH -> Signature != IMAGE_NT_SIGNATURE ) return FALSE; if ( (SrcPeH -> FileHeader.Characteristics & IMAGE_FILE_DLL) || (SrcPeH -> FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0 ) || (SrcPeH -> FileHeader.SizeOfOptionalHeader != sizeof (IMAGE_OPTIONAL_HEADER)) ) { return FALSE; } SrcPeSecH = (PIMAGE_SECTION_HEADERS)(( int )SrcPeH + sizeof (IMAGE_NT_HEADERS)); ImageSize = CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH); if ( ImageSize == 0 ) return FALSE; Mem = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存 if ( Mem != NULL ) { // 计算需要复制的PE头字节数 unsigned long l = SrcPeH -> OptionalHeader.SizeOfHeaders; for ( int i = 0 ; i < SrcPeH -> FileHeader.NumberOfSections; ++ i) { if ( (SrcPeSecH[i] -> PointerToRawData) && (SrcPeSecH[i] -> PointerToRawData < l) ) { l = SrcPeSecH[i] -> PointerToRawData; } } memmove( Mem, SrcMz, l); peH = (PIMAGE_NT_HEADERS)(( int )Mem + ((PIMAGE_DOS_HEADER)Mem) -> e_lfanew); peSecH = (PIMAGE_SECTION_HEADERS)(( int )peH + sizeof (IMAGE_NT_HEADERS)); void * Pt = ( void * )((unsigned long )Mem + GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders , peH -> OptionalHeader.SectionAlignment) ); for ( i = 0 ; i < peH -> FileHeader.NumberOfSections; ++ i) { // 定位该节在内存中的位置 if (peSecH[i] -> VirtualAddress) Pt = ( void * )((unsigned long )Mem + peSecH[i] -> VirtualAddress); if (peSecH[i] -> SizeOfRawData) { // 复制数据到内存 memmove(Pt, ( const void * )((unsigned long )(SrcMz) + peSecH[i] -> PointerToRawData), peSecH[i] -> SizeOfRawDat if (peSecH[i] -> Misc.VirtualSize < peSecH[i] -> SizeOfRawData) Pt = ( void * )((unsigned long )Pt + GetAlignedSize(peSecH[i] -> SizeOfRawData, peH -> OptionalHeader.SectionAligent)); else // pt 定位到下一节开始位置 Pt = ( void * )((unsigned long )Pt + GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlient)); } else { Pt = ( void * )((unsigned long )Pt + GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignm)); } } } return TRUE; } typedef void * (__stdcall * pfVirtualAllocEx)(unsigned long , void * , unsigned long , unsigned long , unsigned long ); pfVirtualAllocEx MyVirtualAllocEx = NULL; BOOL IsNT() { return MyVirtualAllocEx != NULL; } // 生成外壳程序命令行 char * PrepareShellExe( char * CmdParam, unsigned long BaseAddr, unsigned long ImageSize) { if (IsNT()) { char * Buf = new char [ 256 ]; memset(Buf, 0 , 256 ); GetModuleFileName( 0 , Buf, 256 ); strcat(Buf, CmdParam); return Buf; // 请记得释放内存;-) } else { // Win98 return NULL; } } // 是否包含可重定向列表 BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH) { return (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) && (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); } #pragma pack(push, 1 ) typedef struct { unsigned long VirtualAddress; unsigned long SizeOfBlock; } * PImageBaseRelocation; #pragma pack(pop) // 重定向PE用到的地址 void DoRelocation(PIMAGE_NT_HEADERS peH, void * OldBase, void * NewBase) { unsigned long Delta = (unsigned long )NewBase - peH -> OptionalHeader.ImageBase; PImageBaseRelocation p = (PImageBaseRelocation)((unsigned long )OldBase + peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while (p -> VirtualAddress + p -> SizeOfBlock) { unsigned short * pw = (unsigned short * )(( int )p + sizeof ( * p)); for (unsigned int i = 1 ; i <= (p -> SizeOfBlock - sizeof ( * p)) / 2 ; ++ i) { if (( * pw) & 0xF000 == 0x3000 ) { unsigned long * t = (unsigned long * )((unsigned long )(OldBase) + p -> VirtualAddress + (( * pw) & 0x0FFF )); * t += Delta; } ++ pw; } p = (PImageBaseRelocation)pw; } } // 卸载原外壳占用内存 BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr) { typedef unsigned long (__stdcall * pfZwUnmapViewOfSection)(unsigned long , unsigned long ); pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL; BOOL res = FALSE; HMODULE m = LoadLibrary( " ntdll.dll " ); if (m) { ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, " ZwUnmapViewOfSection " ); if (ZwUnmapViewOfSection) res = (ZwUnmapViewOfSection((unsigned long )ProcHnd, BaseAddr) == 0 ); FreeLibrary(m); } return res; } // 创建外壳进程并获取其基址、大小和当前运行状态 BOOL CreateChild( char * Cmd, CONTEXT & Ctx, HANDLE & ProcHnd, HANDLE & ThrdHnd, unsigned long & ProcId, unsigned long & BaseAddr, unsigned long & ImageSize) { STARTUPINFOA si; PROCESS_INFORMATION pi; unsigned long old; MEMORY_BASIC_INFORMATION MemInfo; memset( & si, 0 , sizeof (si)); memset( & pi, 0 , sizeof (pi)); si.cb = sizeof (si); BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, & si, & pi); // 以挂起方式运行进 if (res) { ProcHnd = pi.hProcess; ThrdHnd = pi.hThread; ProcId = pi.dwProcessId; // 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址 Ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(ThrdHnd, & Ctx); ReadProcessMemory(ProcHnd, ( void * )(Ctx.Ebx + 8 ), & BaseAddr, sizeof (unsigned long ), & old); // 读取加载基址 void * p = ( void * )BaseAddr; // 计算外壳进程占有的内存 while (VirtualQueryEx(ProcHnd, p, & MemInfo, sizeof (MemInfo))) { if (MemInfo.State = MEM_FREE) break ; p = ( void * )((unsigned long )p + MemInfo.RegionSize); } ImageSize = (unsigned long )p - (unsigned long )BaseAddr; } return res; } // 创建外壳进程并用目标进程替换它然后执行 HANDLE AttachPE( char * CmdParam, PIMAGE_NT_HEADERS peH, PIMAGE_SECTION_HEADERS peSecH, void * Ptr, unsigned long ImageSize, unsigned long & ProcId) { HANDLE res = INVALID_HANDLE_VALUE; CONTEXT Ctx; HANDLE Thrd; unsigned long Addr, Size; char * s = PrepareShellExe(CmdParam, peH -> OptionalHeader.ImageBase, ImageSize); if (s == NULL) return res; if (CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size)) { void * p = NULL; unsigned long old; if ((peH -> OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)) { // 外壳进程可以容纳目标进程并且加载地址一致 p = ( void * )Addr; VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE, & old); } else if (IsNT()) { if (UnloadShell(res, Addr)) { // 卸载外壳进程占有内存 p = MyVirtualAllocEx((unsigned long )res, ( void * )peH -> OptionalHeader.ImageBase, ImageSize, MEM_RESERVE | MECOMMIT, PAGE_EXECUTE_READWRITE); } if ((p == NULL) && HasRelocationTable(peH)) { // 分配内存失败并且目标进程支持重定向 p = MyVirtualAllocEx((unsigned long )res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRIT if (p) DoRelocation(peH, Ptr, p); // 重定向 } } if (p) { WriteProcessMemory(res, ( void * )(Ctx.Ebx + 8 ), & p, sizeof (DWORD), & old); // 重置目标进程运行环境中的基址 peH -> OptionalHeader.ImageBase = (unsigned long )p; if (WriteProcessMemory(res, p, Ptr, ImageSize, & old)) { // 复制PE数据到目标进程 Ctx.ContextFlags = CONTEXT_FULL; if ((unsigned long )p == Addr) Ctx.Eax = peH -> OptionalHeader.ImageBase + peH -> OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地 else Ctx.Eax = (unsigned long )p + peH -> OptionalHeader.AddressOfEntryPoint; SetThreadContext(Thrd, & Ctx); // 更新运行环境 ResumeThread(Thrd); // 执行 CloseHandle(Thrd); } else { // 加载失败,杀掉外壳进程 TerminateProcess(res, 0 ); CloseHandle(Thrd); CloseHandle(res); res = INVALID_HANDLE_VALUE; } } else { // 加载失败,杀掉外壳进程 TerminateProcess(res, 0 ); CloseHandle(Thrd); CloseHandle(res); res = INVALID_HANDLE_VALUE; } } delete[] s; return res; } /**/ /**/ /**/ /* ******************************************************\ { ******************************************************* } { * 从内存中加载并运行exe * } { ******************************************************* } { * 参数: } { * Buffer: 内存中的exe地址 } { * Len: 内存中exe占用长度 } { * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)} { * ProcessId: 返回的进程Id } { * 返回值: 如果成功则返回进程的Handle(ProcessHandle), } { 如果失败则返回INVALID_HANDLE_VALUE } { ******************************************************* } \****************************************************** */ HANDLE MemExecute( void * ABuffer, long Len, char * CmdParam, unsigned long * ProcessId) { HANDLE res = INVALID_HANDLE_VALUE; PIMAGE_NT_HEADERS peH; PIMAGE_SECTION_HEADERS peSecH; void * Ptr; unsigned long peSz; if (AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz)) { res = AttachPE(CmdParam, peH, peSecH, Ptr, peSz, * ProcessId); VirtualFree(Ptr, peSz, MEM_DECOMMIT); } return res; } // 初始化 class CInit { public : CInit() { MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle( " Kernel32.dll " ), " VirtualAllocEx " ); } } Init; int main( int argc, char * argv[]) { FILE * fp; fp = fopen( " E:\\CProject\\DBGVIEW.EXE " , " rb " ); if ( fp ) { fseek(fp, 0l ,SEEK_END); int file_size = ftell(fp); /**/ /* 获取文件长度 */ fseek(fp, 0l ,SEEK_SET); /**/ /* 回到文件头部 */ LPBYTE pBuf = new BYTE[file_size]; memset( pBuf, 0 , file_size); fread(pBuf,file_size, 1 ,fp); DWORD id = GetCurrentProcessId(); unsigned long ulProcessId = 0 ; MemExecute( pBuf, file_size, "" , & ulProcessId); delete[] pBuf; } return 0 ; }
相关文章推荐
- 手机号正则表达式 Javascript
- Hibernate:命名SQL查询
- CDH5.X安装配置kerberos认证过程
- caffe中Blob数据结构
- 2015年我国互联网行业概况及现状分析
- 2016年5月26日下午(妙味课堂js基础-1笔记四)
- Python 练习 12
- react native debugger 远程调试redux工具
- C# 常用的工具方法
- 网易、阿里健康
- 【android】:android之四大组件详解
- MyEclipse 安装 Vrapper 插件
- 滚烫!职场人加薪“潜规则”出炉
- 字符编码
- 二叉树的先序、中序、后序遍历等基本操作c++实现
- spring mybatis 多数据源读写分离实际应用
- django oracle 配置
- workerman和thinkphp完美结合使用
- POJ-3468-A Simple Problem with Integers(线段树区间维护 重写Lazy)
- Rxjava操作符compose()