📄 unitpacker.~pas
字号:
pThunk: PDWORD;
pLocalVar: PDWORD;
begin
pLocalVar := LocalVar;
Inc(pLocalVar);
pThunk := PtrAdd(pImpDir, SizeOf(TImageImportDecriptor) * 2 );
pImpDir^.FirstThunk := NewThunk;
while pThunk^ <> 0 do
begin
pLocalVar^ := pThunk^; //更新LocalVar相应变量的值=pThunk的RVA
Inc(pThunk);
Inc(pLocalVar);
end;
end;
procedure PackSection(SrcPEPtr: Pointer);
//压缩section数据
//SrcPEPtr: 指向PE文件指针
var
i, l: Cardinal;
PkData: PPkData;
PkSectionBuf: Pointer;
PkSectionDir: PPkSectionDir;
FirstPkSectionDir: PPkSectionDir;
SectionCount: Cardinal;
Source, WorkMem: Pointer;
SourceLength: Cardinal;
SourceSectionSize: Cardinal;
PkDataOffset: Cardinal;
PkSectionDataSize: Cardinal;
begin
SectionCount := PEAnalyst.SectionCount;
SourceSectionSize := 0;
for i := 0 to SectionCount - 1 do
inc(SourceSectionSize, PEAnalyst.SectionHeaders[i]^.SizeOfRawData);
SourceSectionSize := _aP_max_packed_size(SourceSectionSize);
GetMem(PkSectionBuf, SizeOf(TPkDataHeader) + SectionCount * SizeOf(TPkSectionDir) +
SourceSectionSize);
GetMem(WorkMem, _aP_workmem_size(SourceSectionSize));
PkSectionDir := PkSectionBuf;
FirstPkSectionDir := PkSectionDir;
PkDataOffset := SectionCount * SizeOf(TPkSectionDir);
for i := 0 to SectionCount - 1 do
begin
Source := PtrAdd(SrcPEPtr, PEAnalyst.SectionHeaders[i]^.PointerToRawData);
SourceLength := PEAnalyst.SectionHeaders[i]^.SizeOfRawData;
Inc(PkSectionDataSize, SourceLength);
l := _aP_pack(Source^, PtrAdd(FirstPkSectionDir, PkDataOffset)^, SourceLength, WorkMem^, CallBack, @PkSectionDataSize);
PkSectionDir^.Length := SourceLength;
PkSectionDir^.Offset := PkDataOffset;
PkSectionDir^.RVA := PEAnalyst.SectionHeaders[i]^.VirtualAddress;
PkSectionDir^.VLength := PEAnalyst.SectionHeaders[i]^.Misc.VirtualSize;
PkSectionDir^.Prop := PAGE_EXECUTE_READWRITE; //保存section header的信息
Inc(PkDataOffset, l);
Inc(PkSectionDir);
end;
FreeMem(WorkMem);
PkData := PkDataQueue.Get('PkSectionData'); //存入列表
PkData^.Ptr := PkSectionBuf;
PkData^.Len := PkDataOffset;
end;
procedure PackImports(SrcPEPtr: Pointer; ClearImp: Bool);
//转换导入表为简单格式,然后压缩
//SrcPEPtr: 指向PE文件指针
var
PkData: PPkData;
PkImportBuf: Pointer;
PkImportDir: PImpDir;
PEImpDir: PImageImportDecriptor;
pFuncName: PImageImportByName;
pThunk: PDWORD;
pDllName: PChar;
pName: PChar;
lDll: DWORD;
lFunc: DWORD;
l: Cardinal;
PkImportTab, WorkMem: Pointer;
PkLen: Cardinal;
begin
PEImpDir := PtrAdd(SrcPEPtr, PEAnalyst.RVAtoOffset(PEAnalyst.DataDirectorys[IMAGE_DIRECTORY_ENTRY_IMPORT]^.VirtualAddress));
PkImportBuf := AllocMem(500 * 1024); //临时缓冲区,保存简单格式
PkImportDir := PkImportBuf;
PkImportDirLength := 0;
while PEImpDir^.FirstThunk <> 0 do
begin
pDllName := PtrAdd(SrcPEPtr, PEAnalyst.RVAtoOffset(PEImpDir^.Name));
lDll := Length(pDllName) + 1;
pName := @PkImportDir^.Name[0];
CopyMemory(pName, pDllName, lDll);
if ClearImp then
ZeroMemory(pDllName, lDll); //清除原导入表数据
PkImportDir^.ThunkRVA := PEImpDir^.FirstThunk;
if PEImpDir^.Union.OriginalFirstThunk <> 0 then
pThunk := PtrAdd(SrcPEPtr, PEAnalyst.RVAtoOffset(PEImpDir^.Union.OriginalFirstThunk))
else
pThunk := PtrAdd(SrcPEPtr, PEAnalyst.RVAtoOffset(PEImpDir^.FirstThunk));
pName := PtrAdd(pName, lDll);
lFunc := 0;
while pThunk^ <> 0 do
begin
if pThunk^ and $80000000 = $80000000 then
begin
PDWORD(pName)^ := pThunk^ and $0FFFFFFF;
if ClearImp then
pThunk^ := 0; //清除原导入表数据
l := 4;
end
else
begin
pFuncName := PImageImportByName(PtrAdd(SrcPEPtr, PEAnalyst.RVAtoOffset(pThunk^)));
l := Length(PChar(@pFuncName^.Name)) + 1;
CopyMemory(pName, @pFuncName^.Name, l);
if ClearImp then
ZeroMemory(@pFuncName^.Name, l); //清除原导入表数据
end;
inc(PkImportDir^.ImpFuncCount);
inc(lFunc, l);
pName := PtrAdd(pName, l);
inc(pThunk);
end;
inc(PEImpDir);
inc(PkImportDirLength, lFunc + lDll + 8);
//8 = TImpDir ThunkRVA: DWORD + ImpFuncCount: DWORD
PkImportDir := PtrAdd(PkImportDir, lFunc + lDll + 8);
end;
inc(PkImportDirLength, 4); //Null结尾
GetMem(PkImportTab, _aP_max_packed_size(PkImportDirLength));
GetMem(WorkMem, _aP_workmem_size(PkImportDirLength));
PkLen := _aP_pack(PkImportBuf^, PkImportTab^, PkImportDirLength, WorkMem^, nil, nil);
FreeMem(WorkMem); //压缩简单格式
FreeMem(PkImportBuf);
PkData := PkDataQueue.Get('PkImpData'); //存入列表
PkData^.Ptr := PkImportTab;
PkData^.Len := PkLen;
end;
procedure AssembleUnPacker(PEPtr: Pointer);
var
PkData: PPkData;
begin
PkData := PkDataQueue.Get('UnPacker'); //存入列表
PkData^.Ptr := @StartHere;
PkData^.Len := DWORD(@EndHere) - DWORD(@StartHere); //全部需写入文件的解压代码长度
PkData^.Characteristic := $FFFFFFFF; //表示列表不要释放Ptr指针
end;
procedure AssemblePkDataHeader;
//组装PkDataHeader
var
PkData: PPkData;
PkDataHeaderPtr: PPkDataHeader;
begin
GetMem(PkDataHeaderPtr, SizeOf(TPkDataHeader));
PkData := PkDataQueue.Get('PkDataHeader'); //存入列表
PkData^.Ptr := PkDataHeaderPtr;
PkData^.Len := SizeOf(TPkDataHeader);
PkDataHeaderPtr^.PkSectionDirCount := PEAnalyst.SectionCount - 1;
PkDataHeaderPtr^.PkSectionDirOffset := PkDataQueue.GetOffset('PkSectionData') -
PkDataQueue.GetOffset('PkDataHeader');
PkDataHeaderPtr^.PkImpDirOffset := PkDataQueue.GetOffset('PkImpData') -
PkDataQueue.GetOffset('PkDataHeader');
PkDataHeaderPtr^.ImpSize := PkImportDirLength;
PkDataHeaderPtr^.EPRVA := PEAnalyst.EntryPointRVA;
PkDataHeaderPtr^.ResRVA := PEAnalyst.DataDirectorys[2]^.VirtualAddress;
//保存资源
PkDataHeaderPtr^.ResSize := PEAnalyst.DataDirectorys[2]^.Size;
//保存DelayImport
PkDataHeaderPtr^.DelayImpRVA := PEAnalyst.DataDirectorys[13]^.VirtualAddress;
PkDataHeaderPtr^.DelayImpSize := PEAnalyst.DataDirectorys[13]^.Size;
//保存导出表
PkDataHeaderPtr^.ExpRVA := PEAnalyst.DataDirectorys[0]^.VirtualAddress;
PkDataHeaderPtr^.ExpSize := PEAnalyst.DataDirectorys[0]^.Size;
end;
procedure ProcTls(PEPtr: Pointer);
//处理tls表,将tls表的数据直接copy到加壳后的文件中,修正DataDirectorys的RVA
var
pTls: Pointer;
PkData: PPkData;
begin
if PEAnalyst.HasTls then //有TLS表
begin
PkData := PkDataQueue.Get('Tls');
pTls := PtrAdd(PEPtr, PEAnalyst.RVAtoOffset(PEAnalyst.DataDirectorys[9]^.VirtualAddress));
PkData^.Ptr := pTls;
PkData^.Len := $18;
PkData^.Characteristic := $FFFFFFFF; //表示列表不要释放Ptr指针
PEAnalyst.DataDirectorys[9]^.VirtualAddress := pPackerSection^.VirtualAddress +
PkDataQueue.GetOffset('Tls');
end;
end;
procedure AssembleMainIcon(hIcon: Cardinal);
var
PkData: PPkData;
IconStream: TMemoryStream;
ResBuf: Pointer;
ResRVA, ResSize: Cardinal;
begin
if hIcon = 0 then
exit;
IconStream := TMemoryStream.Create;
WriteIcon(IconStream, hIcon);
ResRVA := pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('MainIcon');
PoorCreateMainIcon(IconStream, ResRVA);
ResSize := IconStream.Size;
ResBuf := AllocMem(ResSize);
CopyMemory(ResBuf, IconStream.Memory, ResSize);
PkData := PkDataQueue.Get('MainIcon');
PkData^.Ptr := ResBuf;
PkData^.Len := ResSize;
IconStream.Free;
end;
procedure AddOverLayData(PEPtr: Pointer);
//处理OverLay数据,直接copy到加壳后的文件末尾
var
PkData: PPkData;
begin
if PEAnalyst.HasOverlay then //有OverLay数据
begin
PkData := PkDataQueue.Get('OverLayData');
PkData^.Ptr := PtrAdd(PEPtr, PEAnalyst.OverlayOffset);
PkData^.Len := PEAnalyst.OverlaySize;
PkData^.Characteristic := $FFFFFFFF;
end;
end;
procedure FinalProc(PEPtr: Pointer);
//最后的处理:
//修正导入表的RVA和Size
//修改Section Header,增加可写属性
//清理无用DataDirectorys
const
UselessDataDir: Array [1..7] of integer = (0, 5, 6, 10, 11, 12, 13);
//需清理的DataDirectorys
var
i: integer;
PkData: PPkData;
begin
PkData := PkDataQueue.Get('ImpTab'); //fix import DataDirectorys
PEAnalyst.DataDirectorys[1]^.VirtualAddress := pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('ImpTab');
PEAnalyst.DataDirectorys[1]^.Size := PkData.Len;
for i := 0 to PEAnalyst.SectionCount - 2 do //clear sectionheaders
begin //don't change the last(new) sectionheader
PEAnalyst.SectionHeaders[i]^.PointerToRawData := 0;
PEAnalyst.SectionHeaders[i]^.SizeOfRawData := 0;
if PEAnalyst.SectionHeaders[i]^.Characteristics and $80000000 <> $80000000 then
PEAnalyst.SectionHeaders[i]^.Characteristics := PEAnalyst.SectionHeaders[i]^.Characteristics + $80000000;
end;
//clear useless DataDirectorys
for i :=Low(UselessDataDir) to High(UselessDataDir) do
begin
PEAnalyst.DataDirectorys[UselessDataDir[i]]^.VirtualAddress := 0;
PEAnalyst.DataDirectorys[UselessDataDir[i]]^.Size := 0;
end;
PkData := PkDataQueue.Get('MainIcon');
if Assigned(PkData) then
begin
PEAnalyst.DataDirectorys[2]^.VirtualAddress := pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('MainIcon');
PEAnalyst.DataDirectorys[2]^.Size := PkData^.Len;
end;
PEAnalyst.UpdateImageSize;
end;
procedure SavePkFile(PkFn: String);
var
PkFile: TMemoryStream;
PkData: TPkData;
i: integer;
begin
PkFile := TMemoryStream.Create;
PkFile.Write(PEAnalyst.PEHeaderPtr^, PEAnalyst.HeaderSize);
for i := 0 to PkDataQueue.Count - 1 do
begin
PkData := PkDataQueue[i]^;
if not Assigned(PkData.Ptr) then
Continue;
PkFile.Write(PkData.Ptr^, PkData.Len);
end;
try
PkFile.SaveToFile(PkFn);
except
on EFCreateError do
Showmessage('');
end;
PkFile.Free;
end;
function CallBack(w0, w1, w2 : DWORD; cbparam : Pointer) : DWORD; cdecl;
begin
with Form1 do
begin
PB.Progress := Round(w1/ w0 * PDWORD(cbparam)^ / SectionDataSize * 100);
Application.ProcessMessages;
Result := aP_pack_continue;
end;
end;
function TForm1.BackupFile(const FileName: String): integer;
var
I: Integer;
begin
result := 0;
I := LastDelimiter('.' + PathDelim + DriveDelim, Filename);
if (I = 0) or (FileName[I] <> '.') then I := MaxInt;
BackFn := Copy(FileName, 1, I - 1) + '_BK' + ExtractFileExt(Filename);
if FileExists(BackFn) then
case MessageBox(0, PChar('文件' + ExtractFileName(BackFn) + ' 已存在, 覆盖吗?'),
'警告', MB_OKCANCEL) of
IDOK:
begin
DeleteFile(BackFn);
result := 1;
end;
end;
if not RenameFile(FileName, BackFn) then
result := 2;
end;
procedure TForm1.DoPack;
var
PEPtr: Pointer;
PkData: PPkData;
i: cardinal;
pLocalVar: PDWORD;
lBuf: Cardinal;
begin
PB.Progress := 0;
ShowMsg('工作线程启动...');
ShowMsg('正在合并节...');
ShowMsg('正在压缩所有数据...');
SrcPE := TMemoryStream.Create;
PkDataQueue := TPkDataQueue.Create;
PEAnalyst := TPEAnalyst.Create;
try
SrcPE.LoadFromFile(SrcFn);
PEPtr := SrcPE.Memory;
if cbBackup.Checked then
begin
case BackupFile(SrcFn) of
0:
ShowMsg('保存并从命名文件 ' + ExtractFileName(BackFn));
1:
ShowMsg('覆盖备份 ' + ExtractFileName(BackFn) + '!');
2:
ShowMsg('创建备份失败!');
end;
end;
PEAnalyst.Assign(PEPtr, SrcPE.Size);
SectionDataSize := 0;
for i := 0 to PEAnalyst.SectionCount - 1 do
Inc(SectionDataSize, PEAnalyst.SectionHeaders[i]^.SizeOfRawData);
VirtualProtect(@StartHere, DWORD(@EndHere) - DWORD(@StartHere), PAGE_EXECUTE_READWRITE, @i);
//使ShellCode部分代码可写,后面修改用
//顺序可以改变!
PkDataQueue.Add('ImpTab');
PkDataQueue.Add('UnPacker');
PkDataQueue.Add('Tls');
PkDataQueue.Add('PkDataHeader');
PkDataQueue.Add('PkSectionData');
PkDataQueue.Add('PkImpData');
PkDataQueue.Add('MainIcon');
PkDataQueue.Add('OverLayData'); //Must be the last
//顺序可以改变!
AssembleImpTab;
PackImports(PEPtr, cbClearImp.Checked);
PackSection(PEPtr);
AssembleUnPacker(PEPtr);
pPackerSection := PEAnalyst.AddSection(0); //Add section after PackSection!
CopyMemory(@pPackerSection^.Name[0], PChar(PkSectionName), 8);
pPackerSection^.PointerToRawData := PEAnalyst.HeaderSize;
ProcTls(PEPtr); //Must be called after AddSection
AssemblePkDataHeader;
if not PEAnalyst.IsDll then
AssembleMainIcon(ImgIcon.Picture.Icon.Handle); //Must be called in the last
AddOverLayData(PEPtr);
lBuf := PkDataQueue.Len; //壳及压缩数据的总长度
pPackerSection^.SizeOfRawData := lBuf - PkDataQueue.Get('OverLayData')^.Len;
pPackerSection^.Misc.VirtualSize := PEAnalyst.PEHeader.CalcSectionAilgnment(lBuf);
PEAnalyst.EntryPointRVA := pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('UnPacker') +
DWORD(@NewEnteryPoint) - DWORD(@StartHere);
//更新EP为NewEnteryPoint
pLocalVar := LocalVar;
pLocalVar^ := pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('PkDataHeader');
//save PkDataHeader's RVA to Shellcode
PkData := PkDataQueue.Get('ImpTab');
FixImpRVA(PkData.Ptr, pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('ImpTab'));
FixImpThunk(PkData.Ptr, pPackerSection^.VirtualAddress + PkDataQueue.GetOffset('UnPacker') +
DWORD(LocalVar) - DWORD(@StartHere) + SizeOf(DWORD));
//FixImpThunk
FinalProc(PEPtr);
SavePkFile(SrcFn);
finally
PEAnalyst.Free;
PkDataQueue.Free;
SrcPE.Free;
end;
ShowMsg('文件压缩完成!');
ShowMsg('请检测文件是否可运行!');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DragAcceptFiles(Handle, true);
end;
procedure TForm1.ShowMsg(Msg: String);
begin
RichEdit1.Lines.Add(Msg);
end;
procedure TForm1.WithDropFiles(var Msg: TMessage);
Var
Buffer: PChar;
i: integer;
begin
i := DragQueryFile(Msg.WParam, 0, nil, 0) + 1;
GetMem(Buffer, i);
try
DragQueryFile(Msg.WParam, 0, Buffer, i);
DragFinish(Msg.WParam);
SrcFn := Buffer;
UpdateUi;
SetForeGroundWindow(Handle);
finally
FreeMem(Buffer);
end;
end;
procedure TForm1.UpdateUi;
begin
leSrcFn.Text := SrcFn;
ShowMsg('Source file: ' + SrcFn);
PkSectionName := leSectionName.Text;
ImgIcon.Picture.Icon.Handle := ExtractIcon(Application.Handle, PChar(SrcFn), 0);
ImgIcon.Refresh;
Bitbtn1.Enabled := true;
PB.Progress := 0;
end;
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
close;
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
DoPack;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if Panel3.top>-Panel3.height then
Panel3.top:=Panel3.top-1
else
Panel3.top:=Panel2.height-35;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -