为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

exe文件加载过程

2011-05-26 50页 doc 569KB 95阅读

用户头像

is_754139

暂无简介

举报
exe文件加载过程Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的 Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。     直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导...
exe文件加载过程
Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入重定位,变量预处理之类的 Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。     直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导入表就被拖出来了。 #include "stdafx.h" 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]->SizeOfRawData);    if(peSecH[i]->Misc.VirtualSize < peSecH[i]->SizeOfRawData)                        Pt = (void *)((unsigned long)Pt + GetAlignedSize(peSecH[i]->SizeOfRawData, peH->OptionalHeader.SectionAlignment));    else // pt 定位到下一节开始位置                        Pt = (void *)((unsigned long)Pt + GetAlignedSize(peSecH[i]->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment));                } else {                    Pt = (void *)((unsigned long)Pt + GetAlignedSize(peSecH[i]->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment));                }         }     } 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下的处理请参考原文;-)    // http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03    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 | MEM_COMMIT, PAGE_EXECUTE_READWRITE);                } if((p == NULL) && HasRelocationTable(peH)){// 分配内存失败并且目标进程支持重定向                    p = MyVirtualAllocEx((unsigned long)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 = (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 APIENTRY WinMain(HINSTANCE hInstance,                         HINSTANCE hPrevInstance,                         LPSTR     lpCmdLine,    int       nCmdShow)    {        HANDLE hFile = 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);        DWORD dwFileSize = ::GetFileSize( hFile, NULL);        LPBYTE pBuf = new BYTE[dwFileSize];        memset( pBuf, 0, dwFileSize);        DWORD dwNumberOfBytesRead = 0;        ::ReadFile( hFile            , pBuf            , dwFileSize            , &dwNumberOfBytesRead            , NULL            );        ::CloseHandle(hFile);        unsigned long ulProcessId = 0;        MemExecute( pBuf, dwFileSize, "", &ulProcessId);    delete[] pBuf;    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; interface uses windows; function MemExecute(const ABuffer; Len: Integer; CmdParam: string; varProcessId: Cardinal): Cardinal; implementation {$R ExeShell.res} // 外壳程序模板(98下使用) type TImageSectionHeaders = array [0..0] of TImageSectionHeader; PImageSectionHeaders = ^TImageSectionHeaders; { 计算对齐后的大小 } function GetAlignedSize(Origin, Alignment: Cardinal): Cardinal; begin result := (Origin + Alignment - 1) div Alignment * Alignment; end; { 计算加载pe并对齐需要占用多少内存,未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0 } function CalcTotalImageSize(MzH: PImageDosHeader; FileLen: Cardinal; peH:PImageNtHeaders; peSecH: PImageSectionHeaders): Cardinal; var i: Integer; begin {计算pe头的大小} result := GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders,PeH.OptionalHeader.SectionAlignment); {计算所有节的大小} for i := 0 to peH.FileHeader.NumberOfSections - 1 do if peSecH[i].PointerToRawData + peSecH[i].SizeOfRawData > FileLen then // 超出文件范围 begin result := 0; exit; end else if peSecH[i].VirtualAddress <> 0 then //计算对齐后某节的大小 if peSecH[i].Misc.VirtualSize <> 0 then result := GetAlignedSize(peSecH[i].VirtualAddress +peSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment) else result := GetAlignedSize(peSecH[i].VirtualAddress + peSecH[i].SizeOfRawData,PeH.OptionalHeader.SectionAlignment) else if peSecH[i].Misc.VirtualSize < peSecH[i].SizeOfRawData then result := result + GetAlignedSize(peSecH[i].SizeOfRawData,peH.OptionalHeader.SectionAlignment) else result := result + GetAlignedSize(peSecH[i].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; var SrcMz: PImageDosHeader; // DOS头 SrcPeH: PImageNtHeaders; // PE头 SrcPeSecH: PImageSectionHeaders; // 节表 i: Integer; l: Cardinal; Pt: Pointer; begin result := 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 then exit; Mem := VirtualAlloc(nil, ImageSize, MEM_COMMIT,PAGE_EXECUTE_READWRITE); // 分配内存 if Mem <> nil then begin // 计算需要复制的PE头字节数 l := SrcPeH.OptionalHeader.SizeOfHeaders; for i := 0 to SrcPeH.FileHeader.NumberOfSections - 1 do if (SrcPeSecH[i].PointerToRawData <> 0) and (SrcPeSecH[i].PointerToRawData< l) then l := SrcPeSecH[i].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 do begin // 定位该节在内存中的位置 if PeSecH[i].VirtualAddress <> 0 then Pt := Pointer(Cardinal(Mem) + PeSecH[i].VirtualAddress); if PeSecH[i].SizeOfRawData <> 0 then begin // 复制数据到内存 Move(Pointer(Cardinal(SrcMz) + PeSecH[i].PointerToRawData)^, pt^,PeSecH[i].SizeOfRawData); if peSecH[i].Misc.VirtualSize < peSecH[i].SizeOfRawData then pt := pointer(Cardinal(pt) + GetAlignedSize(PeSecH[i].SizeOfRawData,PeH.OptionalHeader.SectionAlignment)) else pt := pointer(Cardinal(pt) + GetAlignedSize(peSecH[i].Misc.VirtualSize,peH.OptionalHeader.SectionAlignment)); // pt 定位到下一节开始位置 end else pt := pointer(Cardinal(pt) + GetAlignedSize(PeSecH[i].Misc.VirtualSize,PeH.OptionalHeader.SectionAlignment)); end; result := True; end; end; type TVirtualAllocEx = function (hProcess: THandle; lpAddress: Pointer; dwSize, flAllocationType: DWORD; flProtect: DWORD): Pointer; stdcall; var MyVirtualAllocEx: TVirtualAllocEx = nil; function IsNT: Boolean; begin result := Assigned(MyVirtualAllocEx); end; { 生成外壳程序命令行 } function PrepareShellExe(CmdParam: string; BaseAddr, ImageSize: Cardinal):string; var r, h, sz: Cardinal; p: Pointer; fid, l: Integer; buf: Pointer; peH: PImageNtHeaders; peSecH: PImageSectionHeaders; begin if IsNT then { NT 系统下直接使用自身程序作为外壳进程 } result := ParamStr(0)+CmdParam else 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); peH := Pointer(Integer(Buf) + PImageDosHeader(Buf)._lfanew); peSecH := Pointer(Integer(peH) + sizeof(TImageNtHeaders)); peH.OptionalHeader.ImageBase := BaseAddr; // 修改PE头重的加载基址 if peH.OptionalHeader.SizeOfImage < ImageSize then // 目标比外壳大,修改外壳程序运行时占用的内存 begin sz := Imagesize - peH.OptionalHeader.SizeOfImage; Inc(peH.OptionalHeader.SizeOfImage, sz); // 调整总占用内存数 Inc(peSecH[peH.FileHeader.NumberOfSections-1].Misc.VirtualSize, sz); // 调整最后一节占用内存数 end; // 生成外壳程序文件名, 为本程序改后缀名得到的 // 由于不想 uses SysUtils (一旦 use 了程序将增大80K左右), 而且偷懒,所以只支持最多运行11个进程,后缀名为.dat,
/
本文档为【exe文件加载过程】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索