📄 unitpacker.~pas
字号:
unit Unitpacker;
interface
uses
windows,
JwaWinnt, JwaWinBase, JwaWintype, JwaWinUser,
Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShellAPI, ComCtrls, StdCtrls,
aplibu,
PkDataQueueUnit,
PEHeaderUnit,
UtilUnit, Gauges, ExtCtrls, Menus, Buttons, ImgList;
type
TForm1 = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
TabSheet3: TTabSheet;
RichEdit1: TRichEdit;
Panel1: TPanel;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
cbBackup: TCheckBox;
cbClearImp: TCheckBox;
leSrcFn: TLabeledEdit;
PB: TGauge;
imgIcon: TImage;
leSectionName: TLabeledEdit;
CheckBox1: TCheckBox;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
ImageList1: TImageList;
Panel2: TPanel;
Panel3: TPanel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Timer1: TTimer;
Label4: TLabel;
Label5: TLabel;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
SrcFn: String;
BackFn: String;
PkSectionName: String;
procedure WithDropFiles(var Msg: TMessage); message WM_DROPFILES;
procedure ShowMsg(Msg: String);
procedure UpdateUi;
function BackupFile(const FileName: String): integer;
procedure DoPack;
public
{ Public declarations }
end;
function CallBack(w0, w1, w2 : DWORD;
cbparam : Pointer) : DWORD;cdecl;
var
Form1: TForm1;
type
TPEAnalyst = class
private
FPEHeader: TPEHeader;
FFileSize: Cardinal;
FHasTls: Bool;
FHasOverlay: Bool;
FOverlayOffset: Cardinal;
FOverlaySize: Cardinal;
function GetHeaderSize: Cardinal;
function GetImageSize: Cardinal;
function GetSectionCount: Cardinal;
function GetSectionHeaders(Index: Cardinal): PImageSectionHeader;
function GetPEHeaderPtr: Pointer;
function GetImageBase: Cardinal;
procedure SetImageBase(const Value: Cardinal);
function GetEntryPointRVA: Cardinal;
procedure SetEntryPointRVA(const Value: Cardinal);
function GetDataDirectory(Index: Cardinal): PImageDataDirectory;
function GetDataDirectoryCount: Cardinal;
function LastRawDataOffset: Cardinal;
function HasDllFlag: Bool;
public
constructor Create;
destructor Destroy; override;
function Assign(PEPtr: Pointer; FileSize: Cardinal): Bool;
function AddSection(Length: Cardinal): PImageSectionHeader;
function OffsetInSection(Offset: Cardinal): Cardinal;
function OffsettoRVA(Offset: Cardinal): Cardinal;
function RVAInSection(RVA: Cardinal): Cardinal;
function RVAtoOffset(RVA: Cardinal): Cardinal;
function RVAtoPtr(RVA: Cardinal): Pointer;
procedure UpdateImageSize;
procedure DeleteSection(Index: Cardinal);
property PEHeader: TPEHeader read FPEHeader;
property PEHeaderPtr: Pointer read GetPEHeaderPtr;
property DataDirectorys[Index: Cardinal]: PImageDataDirectory read GetDataDirectory;
property SectionHeaders[Index: Cardinal]: PImageSectionHeader read GetSectionHeaders;
property ImageBase: Cardinal read GetImageBase write SetImageBase;
property ImageSize: Cardinal read GetImageSize;
property HeaderSize: Cardinal read GetHeaderSize;
property FileSize: Cardinal read FFileSize;
property EntryPointRVA: Cardinal read GetEntryPointRVA write SetEntryPointRVA;
property SectionCount: Cardinal read GetSectionCount;
property DataDirectoryCount: Cardinal read GetDataDirectoryCount;
property HasTls: Bool read FHasTls;
property HasOverlay: Bool read FHasOverlay;
property OverlayOffset: Cardinal read FOverlayOffset;
property OverlaySize: Cardinal read FOverlaySize;
property IsDll: Bool read HasDllFlag;
end;
implementation
{$R *.dfm}
function TPEAnalyst.AddSection(Length: Cardinal): PImageSectionHeader;
var
i: Cardinal;
LastOffset, LastSize: Cardinal;
begin
result := nil;
if not FPEHeader.AddSection(result) then exit;
if Length > 0 then
result.Misc.VirtualSize := FPEHeader.CalcSectionAilgnment(Length)
else
result.Misc.VirtualSize := FPEHeader.FA;
LastOffset := 0;
LastSize := 0;
if SectionCount > 1 then
for i := 0 to SectionCount - 2 do
if LastOffset < SectionHeaders[i]^.PointerToRawData then
begin
LastOffset := SectionHeaders[i]^.PointerToRawData;
LastSize := SectionHeaders[i]^.SizeOfRawData;
end
else if (LastOffset = SectionHeaders[i]^.PointerToRawData) and
(LastSize < SectionHeaders[i]^.SizeOfRawData) then
begin
LastOffset := SectionHeaders[i]^.PointerToRawData;
LastSize := SectionHeaders[i]^.SizeOfRawData;
end;
result.SizeOfRawData := Length;
result.PointerToRawData := LastOffset + FPEHeader.CalcFileAilgnment(LastSize);
if result.PointerToRawData = 0 then
result.PointerToRawData := HeaderSize;
UpdateImageSize;
end;
function TPEAnalyst.Assign(PEPtr: Pointer; FileSize: Cardinal): Bool;
begin
FFileSize := FileSize;
result := FPEHeader.Assign(PEPtr);
if not result then exit;
FHasTls := DataDirectorys[9].VirtualAddress <> 0;
FOverlayOffset := LastRawDataOffset;
FHasOverlay := FOverlayOffset < FileSize;
if FHasOverlay then
FOverlaySize := FileSize - FOverlayOffset
else
begin
FOverlayOffset := 0;
FOverlaySize := 0;
end;
end;
constructor TPEAnalyst.Create;
begin
inherited;
FPEHeader := TPEHeader.Create;
FFileSize := 0;
end;
destructor TPEAnalyst.Destroy;
begin
FPEHeader.Free;
inherited;
end;
function TPEAnalyst.GetDataDirectory(Index: Cardinal): PImageDataDirectory;
begin
result := FPEHeader.DataDirectorys[Index];
end;
function TPEAnalyst.GetEntryPointRVA: Cardinal;
begin
result := FPEHeader.OptionalHeader32.AddressOfEntryPoint;
end;
function TPEAnalyst.GetHeaderSize: Cardinal;
begin
result := FPEHeader.HeaderSize;
end;
function TPEAnalyst.GetImageBase: Cardinal;
begin
result := FPEHeader.OptionalHeader32.ImageBase;
end;
function TPEAnalyst.GetImageSize: Cardinal;
begin
result := FPEHeader.OptionalHeader32.SizeOfImage;
end;
function TPEAnalyst.GetPEHeaderPtr: Pointer;
begin
result := PEHeader.DosHeader;
end;
function TPEAnalyst.GetSectionHeaders(Index: Cardinal): PImageSectionHeader;
begin
result := PEHeader.Sections[Index];
end;
function TPEAnalyst.GetSectionCount: Cardinal;
begin
result := FPEHeader.SectionCount;
end;
function TPEAnalyst.OffsetInSection(Offset: Cardinal): Cardinal;
begin
result := FPEHeader.OffsetInSection(Offset);
end;
function TPEAnalyst.OffsettoRVA(Offset: Cardinal): Cardinal;
begin
result := FPEHeader.OffsettoRVA(Offset);
end;
function TPEAnalyst.RVAInSection(RVA: Cardinal): Cardinal;
begin
result := FPEHeader.RVAInSection(RVA);
end;
function TPEAnalyst.RVAtoOffset(RVA: Cardinal): Cardinal;
begin
result := FPEHeader.RVAtoOffset(RVA);
end;
function TPEAnalyst.RVAtoPtr(RVA: Cardinal): Pointer;
begin
result := FPEHeader.RVAtoPtr(RVA);
end;
procedure TPEAnalyst.SetEntryPointRVA(const Value: Cardinal);
begin
FPEHeader.OptionalHeader32.AddressOfEntryPoint := Value;
end;
procedure TPEAnalyst.SetImageBase(const Value: Cardinal);
begin
FPEHeader.OptionalHeader32.ImageBase := Value;
end;
procedure TPEAnalyst.UpdateImageSize;
begin
FPEHeader.UpdateImageSize;
end;
procedure TPEAnalyst.DeleteSection(Index: Cardinal);
var
i: Cardinal;
begin
for i := 0 to DataDirectoryCount - 1 do
if (DataDirectorys[i]^.VirtualAddress > SectionHeaders[Index]^.VirtualAddress) and
(DataDirectorys[i]^.VirtualAddress + DataDirectorys[i]^.Size >
SectionHeaders[Index]^.VirtualAddress + SectionHeaders[Index]^.Misc.VirtualSize) then
begin
DataDirectorys[i]^.VirtualAddress := 0;
DataDirectorys[i]^.Size := 0;
end;
FPEHeader.WipeSectionHeader(Index);
end;
function TPEAnalyst.GetDataDirectoryCount: Cardinal;
begin
result := FPEHeader.DirectoryCount;
end;
function TPEAnalyst.LastRawDataOffset: Cardinal;
var
i, j: Cardinal;
begin
result := 0;
for i := 0 to SectionCount - 1 do
begin
j := SectionHeaders[i]^.PointerToRawData + SectionHeaders[i]^.SizeOfRawData;
if result < j then
result := j;
end;
end;
function TPEAnalyst.HasDllFlag: Bool;
begin
result := FPEHeader.FileHeader.Characteristics and $2000 = $2000;
end;
type
PImpDir = ^TImpDir; //壳中保存的导入表数据的结构 pimpdir->指针类型
TImpDir = packed record //T型定类义符
ThunkRVA: DWORD;
ImpFuncCount: DWORD;
Name: Array [0..0] of Char;
//导入的函数名或序号,pchar格式,第1个为导入dll的文件名。
//如导入的是序号,则去掉二进制最高位的1(通过and $0FFFFFFF)
end;
PPkSectionDir = ^TPkSectionDir; //壳中保存的Section数据的信息
TPkSectionDir = packed record
Offset: Cardinal;
Length: Cardinal;
RVA: Cardinal;
VLength: Cardinal;
Prop: Byte;
end;
PPkDataHeader = ^TPkDataHeader; //壳中保存的压缩后数据的位置信息
TPkDataHeader = packed record
PkSectionDirCount: Cardinal; //原始Section的个数
PkSectionDirOffset: Cardinal; //PkSectionDir数据相对PkDataHeader的偏移
PkImpDirOffset: Cardinal; //ImpDir数据相对PkDataHeader的偏移
ImpSize: Cardinal;
EPRVA: Cardinal;
ResRVA: Cardinal;
ResSize: Cardinal;
DelayImpRVA: Cardinal;
DelayImpSize: Cardinal;
ExpRVA: Cardinal;
ExpSize: Cardinal;
end;
type
PRegs = ^TRegs;
TRegs = record
Edi: Cardinal;
Esi: Cardinal;
Ebp: Cardinal;
Esp: Cardinal;
Ebx: Cardinal;
Edx: Cardinal;
Ecx: Cardinal;
Eax: Cardinal;
end;
var
SrcPE: TMemoryStream;
PkDataQueue: TPkDataQueue;
PEAnalyst: TPEAnalyst;
pPackerSection: PImageSectionHeader;
SectionDataSize: Cardinal = 0;
PkImportDirLength: Cardinal;
//===========SHELLCODE==============
procedure StartHere;
asm
end;
function LocalVar: PDWORD; //一些数据,保存在壳中
asm
call @j
dd 0 //PkDataHeaderRVA
dd $12345678 //'GetModuleHandleA' Thunk
dd $12345678 //'LoadLibrary' Thunk
dd $12345678 //'GetProcAddress' Thunk
dd $feeeeeef //'VirtualAlloc' Thunk
dd $feeeeeef //'VirtualFree' Thunk
dd $feeeeeef //'VirtualProtect' Thunk
dd 0 //Null
@j:
pop result
end;
{$INCLUDE 'DePack.pas'}
procedure NewEnteryPoint; //壳的EP
asm
push ebp
mov ebp,esp
push -1
push ebx
push esi
push edi
pop eax
pop eax
pop ebx
pop eax
pop ebp
pushad
call NewEP
end;
procedure EndHere;
asm
end;
//===========SHELLCODE==============
procedure AssembleImpTab;
//组装壳的导入表
const
DllName: PChar = 'kernel32.dll';
FuncName: Array [1..6] of PChar = ('GetModuleHandleA', 'LoadLibraryA',
'GetProcAddress', 'VirtualAlloc', 'VirtualFree', 'VirtualProtect');
//壳需要导入的函数
var
PEImpPtr: Pointer;
PkData: PPkData;
PEImpPtrLen: Cardinal;
PEImpDir: PImageImportDecriptor;
pFuncName: PImageImportByName;
pDllName: PChar;
lImpDir, lDllName, lFuncName: Cardinal;
pThunk: PDWORD;
i, FuncCount, l, l2: Cardinal;
begin
lImpDir := SizeOf(TImageImportDecriptor) * 2;
lDllName := Length(DllName) + 1;
lFuncName := 0;
FuncCount := High(FuncName) - Low(FuncName) + 1;
for i := Low(FuncName) to High(FuncName) do
Inc(lFuncName, Length(FuncName[i]) + 1);
PEImpPtrLen := lImpDir + lDllName + lFuncName +
(SizeOf(WORD))* FuncCount +
SizeOf(DWORD) * (FuncCount + 1);
PEImpPtr := AllocMem(PEImpPtrLen);
PEImpDir := PEImpPtr;
PEImpDir^.Union.OriginalFirstThunk := 0;
PEImpDir^.TimeDateStamp := $FFFFFFFF;
PEImpDir^.ForwarderChain := $FFFFFFFF;
PEImpDir^.Name := lImpDir + SizeOf(DWORD) * (FuncCount + 1);
PEImpDir^.FirstThunk := lImpDir;
//Name, FirstThunk的值是Offset,不是RVA!
pDllName := PtrAdd(PEImpDir, PEImpDir^.Name);
CopyMemory(pDllName, DllName, lDllName);
pThunk := PtrAdd(PEImpDir, PEImpDir^.FirstThunk);
pFuncName := PtrAdd(pDllName, lDllName);
l := lImpDir + SizeOf(DWORD) * (FuncCount + 1) + lDllName;
for i := Low(FuncName) to High(FuncName) do
begin
pThunk^ := l;
//pThunk的值是Offset,不是RVA!
Inc(pThunk);
pFuncName^.Hint := 0;
CopyMemory(@pFuncName^.Name[0], FuncName[i], Length(FuncName[i]));
l2 := Length(FuncName[i]) + SizeOf(TImageImportByName) - 1;
pFuncName := PtrAdd(pFuncName, l2);
Inc(l, l2);
end;
PkData := PkDataQueue.Get('ImpTab'); //存入列表
PkData^.Ptr := PEImpPtr;
PkData^.Len := PEImpPtrLen;
end;
procedure FixImpRVA(pImpDir: PImageImportDecriptor; BaseRVA: Cardinal);
//将Name, FirstThunk, pThunk值修正为RVA!
//BaseRVA: 导入表的RVA
//pImpDir: 指向导入表的指针
var
pThunk: PDWORD;
begin
Inc(pImpDir^.Name, BaseRVA);
Inc(pImpDir^.FirstThunk, BaseRVA);
pThunk := PtrAdd(pImpDir, SizeOf(TImageImportDecriptor) * 2 );
while pThunk^ <> 0 do
begin
Inc(pThunk^, BaseRVA);
Inc(pThunk);
end;
end;
procedure FixImpThunk(pImpDir: PImageImportDecriptor; NewThunk: Cardinal);
//将导入表的FirstThunk指向LocalVar相应变量在加壳后程序中的RVA
//NewThunk: LocalVar第一个变量的RVA
//pImpDir: 指向导入表的指针
var
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -