Windows的PE加载器在启动程序的时候

上传人:痛*** 文档编号:125926438 上传时间:2022-07-27 格式:DOC 页数:58 大小:674KB
返回 下载 相关 举报
Windows的PE加载器在启动程序的时候_第1页
第1页 / 共58页
Windows的PE加载器在启动程序的时候_第2页
第2页 / 共58页
Windows的PE加载器在启动程序的时候_第3页
第3页 / 共58页
点击查看更多>>
资源描述
Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。 直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导入表就被拖出来了。 #includestdafx.htypedefIMAGE_SECTION_HEADER(*PIMAGE_SECTION_HEADERS)1;/计算对齐后的大小unsignedlongGetAlignedSize(unsignedlongOrigin,unsignedlongAlignment)return(Origin+Alignment- 1)/Alignment*Alignment;/计算加载pe并对齐需要占用多少内存/未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0unsignedlongCalcTotalImageSize(PIMAGE_DOS_HEADERMzH,unsignedlongFileLen,PIMAGE_NT_HEADERSpeH,PIMAGE_SECTION_HEADERSpeSecH)unsignedlongres;/计算pe头的大小res=GetAlignedSize(peH-OptionalHeader.SizeOfHeaders,peH-OptionalHeader.SectionAlignment);/计算所有节的大小for(inti= 0;iFileHeader.NumberOfSections;+i)/超出文件范围if(peSecHi-PointerToRawData+peSecHi-SizeOfRawDataFileLen)return 0;else if(peSecHi-VirtualAddress)/计算对齐后某节的大小if(peSecHi-Misc.VirtualSize)res=GetAlignedSize(peSecHi-VirtualAddress+peSecHi-Misc.VirtualSize,peH-OptionalHeader.SectionAlignment);elseres=GetAlignedSize(peSecHi-VirtualAddress+peSecHi-SizeOfRawData,peH-OptionalHeader.SectionAlignment);else if(peSecHi-Misc.VirtualSizeSizeOfRawData)res+=GetAlignedSize(peSecHi-SizeOfRawData,peH-OptionalHeader.SectionAlignment);elseres+=GetAlignedSize(peSecHi-Misc.VirtualSize,peH-OptionalHeader.SectionAlignment);/if_else/forreturnres;/加载pe到内存并对齐所有节BOOLAlignPEToMem(void *Buf,longLen,PIMAGE_NT_HEADERS&peH,PIMAGE_SECTION_HEADERS&peSecH,void *&Mem,unsignedlong &ImageSize)PIMAGE_DOS_HEADERSrcMz;/DOS头PIMAGE_NT_HEADERSSrcPeH;/PE头PIMAGE_SECTION_HEADERSSrcPeSecH;/节表SrcMz=(PIMAGE_DOS_HEADER)Buf;if(Lene_magic!=IMAGE_DOS_SIGNATURE)returnFALSE;if(Lene_lfanew+(long)sizeof(IMAGE_NT_HEADERS)returnFALSE;SrcPeH=(PIMAGE_NT_HEADERS)(int)SrcMz+SrcMz-e_lfanew);if(SrcPeH-Signature!=IMAGE_NT_SIGNATURE)returnFALSE;if(SrcPeH-FileHeader.Characteristics&IMAGE_FILE_DLL)|(SrcPeH-FileHeader.Characteristics&IMAGE_FILE_EXECUTABLE_IMAGE= 0)|(SrcPeH-FileHeader.SizeOfOptionalHeader!=sizeof(IMAGE_OPTIONAL_HEADER)returnFALSE;SrcPeSecH=(PIMAGE_SECTION_HEADERS)(int)SrcPeH+sizeof(IMAGE_NT_HEADERS);ImageSize=CalcTotalImageSize(SrcMz,Len,SrcPeH,SrcPeSecH);if(ImageSize= 0)returnFALSE;Mem=VirtualAlloc(NULL,ImageSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);/分配内存if(Mem!=NULL)/计算需要复制的PE头字节数unsignedlongl=SrcPeH-OptionalHeader.SizeOfHeaders;for(inti= 0;iFileHeader.NumberOfSections;+i)if(SrcPeSecHi-PointerToRawData)&(SrcPeSecHi-PointerToRawDataPointerToRawData;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 *)(unsignedlong)Mem+GetAlignedSize(peH-OptionalHeader.SizeOfHeaders,peH-OptionalHeader.SectionAlignment);for(i= 0;iFileHeader.NumberOfSections;+i)/定位该节在内存中的位置if(peSecHi-VirtualAddress)Pt=(void *)(unsignedlong)Mem+peSecHi-VirtualAddress);if(peSecHi-SizeOfRawData)/复制数据到内存memmove(Pt,(constvoid *)(unsignedlong)(SrcMz)+peSecHi-PointerToRawData),peSecHi-SizeOfRawData);if(peSecHi-Misc.VirtualSizeSizeOfRawData)Pt=(void *)(unsignedlong)Pt+GetAlignedSize(peSecHi-SizeOfRawData,peH-OptionalHeader.SectionAlignment);else /pt定位到下一节开始位置Pt=(void *)(unsignedlong)Pt+GetAlignedSize(peSecHi-Misc.VirtualSize,peH-OptionalHeader.SectionAlignment);elsePt=(void *)(unsignedlong)Pt+GetAlignedSize(peSecHi-Misc.VirtualSize,peH-OptionalHeader.SectionAlignment);returnTRUE;typedefvoid *(_stdcall*pfVirtualAllocEx)(unsignedlong,void *,unsignedlong,unsignedlong,unsignedlong);pfVirtualAllocExMyVirtualAllocEx=NULL;BOOLIsNT()returnMyVirtualAllocEx!=NULL;/生成外壳程序命令行char *PrepareShellExe(char *CmdParam,unsignedlongBaseAddr,unsignedlongImageSize)if(IsNT()char *Buf= new char256;memset(Buf,0,256);GetModuleFileName(0,Buf,256);strcat(Buf,CmdParam);returnBuf;/请记得释放内存;-)else/Win98下的处理请参考原文;-)/ :/returnNULL;/是否包含可重定向列表BOOLHasRelocationTable(PIMAGE_NT_HEADERSpeH)return(peH-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC.VirtualAddress)&(peH-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC.Size);#pragmapack(push,1)typedefstructunsignedlongVirtualAddress;unsignedlongSizeOfBlock; *PImageBaseRelocation;#pragmapack(pop)/重定向PE用到的地址voidDoRelocation(PIMAGE_NT_HEADERSpeH,void *OldBase,void *NewBase)unsignedlongDelta=(unsignedlong)NewBase-peH-OptionalHeader.ImageBase;PImageBaseRelocationp=(PImageBaseRelocation)(unsignedlong)OldBase+peH-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC.VirtualAddress);while(p-VirtualAddress+p-SizeOfBlock)unsignedshort *pw=(unsignedshort *)(int)p+sizeof(*p);for(unsignedinti=1;iSizeOfBlock-sizeof(*p)/ 2;+i)if(*pw)& 0xF000 = 0x3000)unsignedlong *t=(unsignedlong *)(unsignedlong)(OldBase)+p-VirtualAddress+(*pw)& 0x0FFF);*t+=Delta;+pw;p=(PImageBaseRelocation)pw;/卸载原外壳占用内存BOOLUnloadShell(HANDLEProcHnd,unsignedlongBaseAddr)typedefunsignedlong(_stdcall*pfZwUnmapViewOfSection)(unsignedlong,unsignedlong);pfZwUnmapViewOfSectionZwUnmapViewOfSection=NULL;BOOLres=FALSE;HMODULEm=LoadLibrary(ntdll.dll);if(m)ZwUnmapViewOfSection=(pfZwUnmapViewOfSection)GetProcAddress(m,ZwUnmapViewOfSection);if(ZwUnmapViewOfSection)res=(ZwUnmapViewOfSection(unsignedlong)ProcHnd,BaseAddr)= 0);FreeLibrary(m);returnres;/创建外壳进程并获取其基址、大小和当前运行状态BOOLCreateChild(char *Cmd,CONTEXT&Ctx,HANDLE&ProcHnd,HANDLE&ThrdHnd,unsignedlong &ProcId,unsignedlong &BaseAddr,unsignedlong &ImageSize)STARTUPINFOAsi;PROCESS_INFORMATIONpi;unsignedlongold;MEMORY_BASIC_INFORMATIONMemInfo;memset(&si,0,sizeof(si);memset(&pi,0,sizeof(pi);si.cb=sizeof(si);BOOLres=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(unsignedlong),&old);/读取加载基址void *p=(void *)BaseAddr;/计算外壳进程占有的内存while(VirtualQueryEx(ProcHnd,p,&MemInfo,sizeof(MemInfo)if(MemInfo.State=MEM_FREE)break;p=(void *)(unsignedlong)p+MemInfo.RegionSize);ImageSize=(unsignedlong)p-(unsignedlong)BaseAddr;returnres;/创建外壳进程并用目标进程替换它然后执行HANDLEAttachPE(char *CmdParam,PIMAGE_NT_HEADERSpeH,PIMAGE_SECTION_HEADERSpeSecH,void *Ptr,unsignedlongImageSize,unsignedlong &ProcId)HANDLEres=INVALID_HANDLE_VALUE;CONTEXTCtx;HANDLEThrd;unsignedlongAddr,Size;char *s=PrepareShellExe(CmdParam,peH-OptionalHeader.ImageBase,ImageSize);if(s=NULL)returnres;if(CreateChild(s,Ctx,res,Thrd,ProcId,Addr,Size)void *p=NULL;unsignedlongold;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(unsignedlong)res,(void *)peH-OptionalHeader.ImageBase,ImageSize,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);if(p=NULL)&HasRelocationTable(peH)/分配内存失败并且目标进程支持重定向p=MyVirtualAllocEx(unsignedlong)res,NULL,ImageSize,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);if(p)DoRelocation(peH,Ptr,p);/重定向if(p)WriteProcessMemory(res,(void *)(Ctx.Ebx+8),&p,sizeof(DWORD),&old);/重置目标进程运行环境中的基址peH-OptionalHeader.ImageBase=(unsignedlong)p;if(WriteProcessMemory(res,p,Ptr,ImageSize,&old)/复制PE数据到目标进程Ctx.ContextFlags=CONTEXT_FULL;if(unsignedlong)p=Addr)Ctx.Eax=peH-OptionalHeader.ImageBase+peH-OptionalHeader.AddressOfEntryPoint;/重置运行环境中的入口地址elseCtx.Eax=(unsignedlong)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;deletes;returnres;/*/*从内存中加载并运行exe*参数:*Buffer:内存中的exe地址*Len:内存中exe占用长度*CmdParam:命令行参数(不包含exe文件名的剩余命令行参数)*ProcessId:返回的进程Id*返回值:如果成功则返回进程的Handle(ProcessHandle),如果失败则返回INVALID_HANDLE_VALUE*/HANDLEMemExecute(void *ABuffer,longLen,char *CmdParam,unsignedlong *ProcessId)HANDLEres=INVALID_HANDLE_VALUE;PIMAGE_NT_HEADERSpeH;PIMAGE_SECTION_HEADERSpeSecH;void *Ptr;unsignedlongpeSz;if(AlignPEToMem(ABuffer,Len,peH,peSecH,Ptr,peSz)res=AttachPE(CmdParam,peH,peSecH,Ptr,peSz,*ProcessId);VirtualFree(Ptr,peSz,MEM_DECOMMIT);returnres;/初始化classCInitpublic:CInit()MyVirtualAllocEx=(pfVirtualAllocEx)GetProcAddress(GetModuleHandle(Kernel32.dll),VirtualAllocEx);Init;intAPIENTRYWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow)HANDLEhFile=NULL;hFile=:CreateFile(f:SourceFromCsdn2.exe,FILE_ALL_ACCESS,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(hFile=INVALID_HANDLE_VALUE)return -1;:SetFilePointer(hFile,0,NULL,FILE_BEGIN);DWORDdwFileSize=:GetFileSize(hFile,NULL);LPBYTEpBuf= newBYTEdwFileSize;memset(pBuf,0,dwFileSize);DWORDdwNumberOfBytesRead= 0;:ReadFile(hFile,pBuf,dwFileSize,&dwNumberOfBytesRead,NULL);:CloseHandle(hFile);unsignedlongulProcessId= 0;MemExecute(pBuf,dwFileSize,&ulProcessId);deletepBuf;return 0;=DELPHI版本=windows似乎只提供了一种启动进程的方法:即必须从一个可执行文件中加载并启动。而下面这段代码就是提供一种可以直接从内存中启动一个exe的变通办法。用途嘛, 也许可以用来保护你的exe,你可以对要保护的 exe 进行任意切分、加密、存储,只要运行时能将exe的内容正确拼接到一块内存中,就可以直接从内存中启动,而不必不安全地去生成一个临时文件再从临时文件启动进程。另外这段代码也提供了一种自己写exe外壳的简单途径,如果能配合其它各种外壳技术就更好地保护你的exe文件。原理很简单:就是“借尸还魂”,启动一个僵尸进程(NT下可以是自身程序启动的另一个进程),然后在它运行前将其整个替换成内存中的exe内容,待正式运行后执行的就是你的目标代码了。不过代码中还有一些不尽人意的地方,比如在98下运行会留一个僵尸程序的壳在硬盘上(其实那个僵尸程序本身就是一个完整的可执行程序,直接运行的话只显示一条错误信息然后就退出了)。另外由于客观条件限制,代码没有经过充分测试,只在XP下进行了一些初步测试:普通exe都能正常运行,upx压缩过的exe绝大多数情况下都能运行,只有在不能卸载僵尸外壳时才有问题(upx压缩过的exe没有重定向表,无法加载到其它地址运行)。如果有bug望告之,如果有更好的方法特别是能解决98下的遗留尾巴的话希望不吝赐教。 Idle_ (阿呆) * * 从内存中加载并运行exe * * * 参数: * Buffer: 内存中的exe地址 * Len: 内存中exe占用长度 * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数) * ProcessId: 返回的进程Id * 返回值: 如果成功则返回进程的Handle(ProcessHandle), 如果失败则返回INVALID_HANDLE_VALUE * unit PEUnit;interfaceuses windows;function MemExecute(const ABuffer; Len: Integer; CmdParam: string; varProcessId: Cardinal): Cardinal;implementation$R ExeShell.res / 外壳程序模板(98下使用)typeTImageSectionHeaders = array 0.0 of TImageSectionHeader;PImageSectionHeaders = TImageSectionHeaders; 计算对齐后的大小 function GetAlignedSize(Origin, Alignment: Cardinal): Cardinal;beginresult := (Origin + Alignment - 1) div Alignment * Alignment;end; 计算加载pe并对齐需要占用多少内存,未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0 function CalcTotalImageSize(MzH: PImageDosHeader; FileLen: Cardinal; peH:PImageNtHeaders;peSecH: PImageSectionHeaders): Cardinal;vari: Integer;begin计算pe头的大小result := GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders,PeH.OptionalHeader.SectionAlignment);计算所有节的大小for i := 0 to peH.FileHeader.NumberOfSections - 1 doif peSecHi.PointerToRawData + peSecHi.SizeOfRawData FileLen then / 超出文件范围beginresult := 0;exit;endelse if peSecHi.VirtualAddress 0 then /计算对齐后某节的大小if peSecHi.Misc.VirtualSize 0 thenresult := GetAlignedSize(peSecHi.VirtualAddress +peSecHi.Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment)elseresult := GetAlignedSize(peSecHi.VirtualAddress + peSecHi.SizeOfRawData,PeH.OptionalHeader.SectionAlignment)else if peSecHi.Misc.VirtualSize peSecHi.SizeOfRawData thenresult := result + GetAlignedSize(peSecHi.SizeOfRawData,peH.OptionalHeader.SectionAlignment)elseresult := result + GetAlignedSize(peSecHi.Misc.VirtualSize,PeH.OptionalHeader.SectionAlignment);end; 加载pe到内存并对齐所有节 function AlignPEToMem(const Buf; Len: Integer; var PeH: PImageNtHeaders;var PeSecH: PImageSectionHeaders; var Mem: Pointer; var ImageSize:Cardinal): Boolean;varSrcMz: PImageDosHeader; / DOS头SrcPeH: PImageNtHeaders; / PE头SrcPeSecH: PImageSectionHeaders; / 节表i: Integer;l: Cardinal;Pt: Pointer;beginresult := false;SrcMz := Buf;if Len sizeof(TImageDosHeader) then exit;if SrcMz.e_magic IMAGE_DOS_SIGNATURE then exit;if Len SrcMz._lfanew+Sizeof(TImageNtHeaders) then exit;SrcPeH := pointer(Integer(SrcMz)+SrcMz._lfanew);if (SrcPeH.Signature IMAGE_NT_SIGNATURE) then exit;if (SrcPeH.FileHeader.Characteristics and IMAGE_FILE_DLL 0) or(SrcPeH.FileHeader.Characteristics and IMAGE_FILE_EXECUTABLE_IMAGE = 0)or (SrcPeH.FileHeader.SizeOfOptionalHeader SizeOf(TImageOptionalHeader) then exit;SrcPeSecH := Pointer(Integer(SrcPeH)+SizeOf(TImageNtHeaders);ImageSize := CalcTotalImageSize(SrcMz, Len, SrcPeH, SrcPeSecH);if ImageSize = 0 thenexit;Mem := VirtualAlloc(nil, ImageSize, MEM_COMMIT,PAGE_EXECUTE_READWRITE); / 分配内存if Mem nil thenbegin/ 计算需要复制的PE头字节数l := SrcPeH.OptionalHeader.SizeOfHeaders;for i := 0 to SrcPeH.FileHeader.NumberOfSections - 1 doif (SrcPeSecHi.PointerToRawData 0) and (SrcPeSecHi.PointerToRawData l) thenl := SrcPeSecHi.PointerToRawData;Move(SrcMz, Mem, l);PeH := Pointer(Integer(Mem) + PImageDosHeader(Mem)._lfanew);PeSecH := Pointer(Integer(PeH) + sizeof(TImageNtHeaders);Pt := Pointer(Cardinal(Mem) +GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders,PeH.OptionalHeader.SectionAlignment);for i := 0 to PeH.FileHeader.NumberOfSections - 1 dobegin/ 定位该节在内存中的位置if PeSecHi.VirtualAddress 0 thenPt := Pointer(Cardinal(Mem) + PeSecHi.VirtualAddress);if PeSecHi.SizeOfRawData 0 thenbegin/ 复制数据到内存Move(Pointer(Cardinal(SrcMz) + PeSecHi.PointerToRawData), pt,PeSecHi.SizeOfRawData);if peSecHi.Misc.VirtualSize peSecHi.SizeOfRawData thenpt := pointer(Cardinal(pt) + GetAlignedSize(PeSecHi.SizeOfRawData,PeH.OptionalHeader.SectionAlignment)elsept := pointer(Cardinal(pt) + GetAlignedSize(peSecHi.Misc.VirtualSize,peH.OptionalHeader.SectionAlignment);/ pt 定位到下一节开始位置endelsept := pointer(Cardinal(pt) + GetAlignedSize(PeSecHi.Misc.VirtualSize,PeH.OptionalHeader.SectionAlignment);end;result := True;end;end;typeTVirtualAllocEx = function (hProcess: THandle; lpAddress: Pointer;dwSize, flAllocationType: DWORD; flProtect: DWORD): Pointer; stdcall;varMyVirtualAllocEx: TVirtualAllocEx = nil;function IsNT: Boolean;beginresult := Assigned(MyVirtualAllocEx);end; 生成外壳程序命令行 function PrepareShellExe(CmdParam: string; BaseAddr, ImageSize: Cardinal):string;varr, h, sz: Cardinal;p: Pointer;fid, l: Integer;buf: Pointer;peH: PImageNtHeaders;peSecH: PImageSectionHeaders;beginif IsNT then NT 系统下直接使用自身程序作为外壳进程 result := ParamStr(0)+CmdParamelse begin/ 由于98系统下无法重新分配外壳进程占用内存,所以必须保证运行的外壳程序能容纳目标进程并且加载地址一致/ 此处使用的方法是从资源中释放出一个事先建立好的外壳程序,然后通过修改其PE头使其运行时能加载到指定地址并至少能容纳目标进程r := FindResource(HInstance, SHELL_EXE, RT_RCDATA);h := LoadResource(HInstance, r);p := LockResource(h);l := SizeOfResource(HInstance, r);GetMem(Buf, l);Move(p, Buf, l); / 读到内存FreeResource(h);p
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 成人自考


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!