unit Unit2; interface uses windows,JwaWinNT; const Shellcodesize :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