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