Pascal 手写PE结构的实现

来源:互联网 发布:mac怎么看不到移动硬盘 编辑:程序博客网 时间:2024/05/18 03:54
unit Unit2;interfaceuses  windows,JwaWinNT;constShellcodesize :dword = 391;           //shellcode的大小PEHandleSize :DWORD = 512;            //PE头总大小SectionSize :DWORD = 2000;data: array[0..390] of byte = (       //shellcode数组//自己加把。);procedure PackPE(lpszFileName2:PChar);implementation//DLL名,API名,缓存,RVA修正function NewImputHandle(DllName,APIName:PAnsiChar;var Pdata:Pointer;dwFVA:DWORD):DWORD;{输入表构建的思路×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××     IMAGE_IMPORT_DESCRIPTOR作为父结构,一共需要一个子结构 IMAGE_THUNK_DATA,IMAGE_THUNK_DATA中还需要一个IMAGE_IMPORT_BY_NAME 用于存放API信息 IMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk指向一个IMAGE_THUNK_DATA IMAGE_IMPORT_DESCRIPTOR的Name指向一个Pansichar IMAGE_IMPORT_DESCRIPTOR的FirstThunk同样指向一个IMAGE_THUNK_DATA 这里的所有指向全部使用rva 编写代码时一层一层构建,构建完后修正指针并复制到用于存放的Pdata指针中×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××}var  PDescriptor:PIMAGE_IMPORT_DESCRIPTOR;                //输入表父结构  PThunk:PIMAGE_THUNK_DATA;                            //api子结构  PNameHandle:PIMAGE_IMPORT_BY_NAME;                   //api名称结构  PNameHandleSize:DWORD;                               //API名称大小  PThunkSize:DWORD;                                    //api子结构大小  PDescriptorSize:DWORD;                               //输入表父结构大小const  ZeroData:DWORD = 50;      //每个结构之间的间隙大小begin  //计算大小  PNameHandleSize :=  SizeOf(IMAGE_IMPORT_BY_NAME) + Length(APIName) + ZeroData;  PThunkSize := SizeOf(IMAGE_THUNK_DATA) + ZeroData;  PDescriptorSize := SizeOf(IMAGE_IMPORT_DESCRIPTOR) + ZeroData;  Result :=  PNameHandleSize + PThunkSize + PDescriptorSize + Length(APIName) + Length(DLLName) + ZeroData;  GetMem(Pdata,Result);  ZeroMemory(Pdata,Result);  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //构建IMAGE_IMPORT_BY_NAME  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //申请内存  GetMem(PNameHandle,PNameHandleSize);  ZeroMemory(PNameHandle,PNameHandleSize);  //设置PIMAGE_IMPORT_BY_NAME  PNameHandle.Hint := 0;  //将API名称直接copy到结构中,Name是个不定长数组,需要在申请内存的时候多申请点空间  Move(APIName^,PNameHandle.Name[0],Length(APIName));  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //构建IMAGE_THUNK_DATA  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //申请内存  GetMem(PThunk,PThunkSize);  ZeroMemory(PThunk,PThunkSize);  //传说中的共用结构体,啊呸..  PThunk.ForwarderString := dwFVA + PDescriptorSize + PThunkSize;  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //构建IMAGE_IMPORT_DESCRIPTOR  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  GetMem(PDescriptor,PDescriptorSize);  ZeroMemory(PDescriptor,PDescriptorSize);  PDescriptor.Union.OriginalFirstThunk := dwFVA + PDescriptorSize;  PDescriptor.FirstThunk := PDescriptor.Union.OriginalFirstThunk;  PDescriptor.TimeDateStamp := 0;  PDescriptor.ForwarderChain := 0;  PDescriptor.Name := dwFVA + PNameHandleSize + PThunkSize + PDescriptorSize;  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //组装内存    PDescriptor PThunk PNameHandle  Move(PDescriptor^,Pdata^,PDescriptorSize);  Inc(DWORD(Pdata),PDescriptorSize);  Move(PThunk^,Pdata^,PThunkSize);  Inc(DWORD(Pdata),PThunkSize);  Move(PNameHandle^,Pdata^,PNameHandleSize);  Inc(DWORD(Pdata),PNameHandleSize);  Move(dllname^,Pdata^,Length(dllname));  //恢复指针  dec(DWORD(Pdata),PDescriptorSize);  dec(DWORD(Pdata),PThunkSize);  dec(DWORD(Pdata),PNameHandleSize);  //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  //释放内存  FreeMem(PNameHandle,PNameHandleSize);  FreeMem(PThunk,PThunkSize);  FreeMem(PDescriptor,PDescriptorSize);end;//缓存,缓存大小,区段名,文件位置,内存位置,区段大小procedure NewSection(Data:PIMAGE_SECTION_HEADER;Size:DWORD;Name:PAnsiChar;PointerToRawData,VirtualAddress,SizeOfRawData,vero:DWORD);var  Section:IMAGE_SECTION_HEADER;begin  //复制区节名  Move(Name^,Section.name,7);  //设置偏移、大小  Section.VirtualAddress := VirtualAddress;  Section.PointerToRawData := PointerToRawData;  Section.SizeOfRawData := SizeOfRawData;  Section.Misc.VirtualSize := SizeOfRawData;  //置零数据  Section.PointerToRelocations := 0;  Section.PointerToLinenumbers := 0; // Section.Misc.PhysicalAddress := 0;  //设置区节属性  if vero = 0 then           {代码节}  begin    Section.Characteristics := IMAGE_SCN_MEM_EXECUTE + IMAGE_SCN_CNT_CODE + IMAGE_SCN_MEM_READ;  //可执行代码节  end  else if vero = 1 then      {数据节}  begin    Section.Characteristics := IMAGE_SCN_CNT_INITIALIZED_DATA + IMAGE_SCN_MEM_READ + IMAGE_SCN_MEM_WRITE;//数据节  end  else if vero = 2 then      {资源节}  begin    Section.Characteristics := IMAGE_SCN_CNT_INITIALIZED_DATA + IMAGE_SCN_MEM_READ + IMAGE_SCN_MEM_SHARED; //资源节  end  else                       {未知ERROR}  begin    Section.Characteristics := 0;  end;  Move(Section,Data^,Size);end;procedure PackPE(lpszFileName2:PChar);var  PDosHeader:PIMAGE_DOS_HEADER;                   //dos头部结构  PNtHeader:PIMAGE_NT_HEADERS32;                  //nt头结构  hFile: THandle;                                 //文件指针  dwBytes: DWORD;                                 //无用  dwFVA:DWORD;                                    //文件偏移  SectionHeader:array of PIMAGE_SECTION_HEADER;   //节表数组  ZeroData:Pointer;                               //对齐数据指针  ZeroSize:DWORD;                                 //对齐数据大小  DosSize:DWORD;  i:Integer;                                      //for  imputData:Pointer;                              //输入表数据指针  imputsize:DWORD;                                //输入表数据大小const  ZeroMaxSize: DWORD = 65535;                     //预留的最大对齐数据  Vero :PAnsiChar = 'This program cannot be run in DOS mode.';  //win32信息begin   //初始化   dwFVA := 0;   DeleteFile(lpszFileName2);   //创建对齐用数据   GetMem(ZeroData,ZeroMaxSize);   ZeroMemory(ZeroData,ZeroMaxSize);   //构建dos头部   DosSize := SizeOf(IMAGE_DOS_HEADER) + Length(Vero) + 4;   GetMem(PDosHeader,DosSize);   ZeroMemory(PDosHeader,DosSize);   Inc(dword(PDosHeader),SizeOf(IMAGE_DOS_HEADER));   Move(Vero^,PDosHeader^,Length(Vero));   Dec(dword(PDosHeader),SizeOf(IMAGE_DOS_HEADER));   Inc(dwFVA,DosSize);   //复制PE头部   GetMem(PNtHeader,SizeOf(IMAGE_NT_HEADERS32));   ZeroMemory(PNtHeader,SizeOf(IMAGE_NT_HEADERS32));   PDosHeader.e_lfanew := dwFVA;   Inc(dwFVA,SizeOf(IMAGE_NT_HEADERS32));   //清零数据表   for i:= 0 to 15 do   begin     PNtHeader.OptionalHeader.DataDirectory[i].VirtualAddress := 0;     PNtHeader.OptionalHeader.DataDirectory[i].Size := 0;   end;   //设置代码段大小   PNtHeader.OptionalHeader.SizeOfCode := Shellcodesize;   //设置数据段位置   PNtHeader.OptionalHeader.BaseOfData := 0;   //设置映像位置   PNtHeader.OptionalHeader.ImageBase := $4000;   //节对齐大小   PNtHeader.OptionalHeader.SectionAlignment := 1000;   //设置PE结构大小   PNtHeader.FileHeader.SizeOfOptionalHeader := SizeOf(IMAGE_OPTIONAL_HEADER32);   //设置节区数量   pNTHeader.FileHeader.NumberOfSections := 1;   //申请节表数组   SetLength(SectionHeader,pNTHeader.FileHeader.NumberOfSections);   //复制节表   GetMem(SectionHeader[0],SizeOf(IMAGE_SECTION_HEADER));   ZeroMemory(SectionHeader[0],SizeOf(IMAGE_SECTION_HEADER));   //构建输入表   imputsize := NewImputHandle('Kernel32.dll','ExitProcess',imputData,PEHandleSize);   //shellcode的大小是391   //申请.data段,大小2000,类型为1(代码段类型)   NewSection(SectionHeader[0],SizeOf(IMAGE_SECTION_HEADER),'.test',PEHandleSize,PEHandleSize,SectionSize,0);   Inc(dwFVA,SizeOf(IMAGE_SECTION_HEADER));   //设置入口点信息   PNtHeader.OptionalHeader.AddressOfEntryPoint := PEHandleSize + imputsize;   //设置设置代码段起始位置   PNtHeader.OptionalHeader.BaseOfCode := PEHandleSize;   //设置导入表位置   PNtHeader.OptionalHeader.DataDirectory[1].VirtualAddress := PEHandleSize;   //设置输入表大小   PNtHeader.OptionalHeader.DataDirectory[1].Size := imputsize;   //计算对齐数据   ZeroSize := PEHandleSize - dwFVA;   //递增对齐数据   Inc(dwFVA,ZeroSize);   //初始化其他PE数据   PDosHeader.e_magic := $5A4D;                                   //MZ   PNtHeader.Signature := $4550;                                  //PE00   PNtHeader.FileHeader.Machine := $14C;                          //cpu标志   PNtHeader.OptionalHeader.Magic := $10B;                        //标志字   PNtHeader.OptionalHeader.Subsystem := $2;                      //子系统   PNtHeader.OptionalHeader.NumberOfRvaAndSizes := $10;           //项目个数   PNtHeader.OptionalHeader.FileAlignment := 200;                 //文件对齐   PNtHeader.OptionalHeader.SectionAlignment := 200;              //节对齐   PNtHeader.OptionalHeader.SizeOfImage := PEHandleSize;          //映像大小   PNtHeader.OptionalHeader.MajorOperatingSystemVersion := 5; //子系统版本   PNtHeader.FileHeader.Characteristics := $103;                  //DLL标志   //PE结构构建完毕...下面开始进行文件操作   //创建文件   hFile := CreateFile(lpszFileName2, GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);   //写入dos头部   WriteFile(hFile, PDosHeader^, DosSize, dwBytes, nil);   //写入NT头部   WriteFile(hFile, PNtHeader^, SizeOf(IMAGE_NT_HEADERS32), dwBytes, nil);   //写入节区信息   WriteFile(hFile, SectionHeader[0]^, SizeOf(IMAGE_SECTION_HEADER), dwBytes, nil);   //写入补齐数据   WriteFile(hFile, ZeroData^, ZeroSize, dwBytes, nil);   //写入输入表节   WriteFile(hFile, imputData^, imputsize, dwBytes, nil);   //写入shellcode   WriteFile(hFile, data, Shellcodesize, dwBytes, nil);   //计算节对齐,这里可以忽略   ZeroSize := SectionSize - Shellcodesize - imputsize;   //补齐节对齐数据   WriteFile(hFile, ZeroData^, ZeroSize + 10, dwBytes, nil);   //关闭文件   CloseHandle(hFile);   //释放Dos头   FreeMem(PDosHeader,DosSize);   //释放NT头   FreeMem(PNtHeader,SizeOf(IMAGE_NT_HEADERS32));   //释放节表信息   FreeMem(SectionHeader[0],SizeOf(IMAGE_SECTION_HEADER));   //释放对齐数据   FreeMem(ZeroData,ZeroMaxSize);   //释放输入表结构   FreeMem(imputData,imputsize);end;end.

 

转自:http://www.oschina.net/code/snippet_214684_7538


 

原创粉丝点击