📄 mainunit.pas
字号:
unit MainUnit;
interface
(*
V2Packer
code by tt.t with almost pure delphi
first build @ 2006.4.15
看到过许多别人写的壳,大多是asm,也有的是c。早就想试一试用比较“纯”的delphi
写会是什么样子,于是就有了V2Packer。
V2Packer断断续续写了半个月的时间,资源部分代码写的很垃圾,只算是能用。PEAnalyst类
由于改变了思路,去掉了一些东西,现在成了PEHeader类的再包装。
代码中的{$INCLUDE 'DePack.pas'}是因为d6的ide不支持代码折叠,就把一些代码移到了
单独的单元。
DePack.pas中用了一个非常简单而且不安全的anti-debug trick,很可能有危险,不过
姑且放在那里吧。
代码中肯定有bug,不过测试中没发现大问题,作为自娱自乐的产物就算说得过去了。
程序写的思路比较清晰,如果对感兴趣,可以从DoPack函数看起。
希望能对为数不多的用delphi写这累东西的初学者有一些帮助。
!请不要将这些代码用于非法用途!
Todo:
1. OverLay data Done: 15, Apr.
2. Add app icon Done: 18, Apr.
3. Move header Data
4. Delay import support Done: 15, Apr.
5. Relocation support
6. Dll support
7. anti-debug tricks
8. ...
*)
uses
JwaWinnt, JwaWinBase, JwaWintype, JwaWinUser,
Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShellAPI, ComCtrls, StdCtrls,
aplibu,
PkDataQueueUnit,
PEAnalystUnit,
UtilUnit, Gauges, ExtCtrls, Menus;
type
TForm1 = class(TForm)
PB: TGauge;
Panel1: TPanel;
Bevel1: TBevel;
RichEdit1: TRichEdit;
leSrcFn: TLabeledEdit;
GroupBox2: TGroupBox;
cbClearImp: TCheckBox;
cbBackup: TCheckBox;
leSectionName: TLabeledEdit;
imgIcon: TImage;
Button1: TButton;
Button2: TButton;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(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
end;
function CallBack(w0, w1, w2 : DWORD;cbparam : Pointer) : DWORD;cdecl;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
PImpDir = ^TImpDir; //壳中保存的导入表数据的结构
TImpDir = packed record
ThunkRVA: DWORD;
ImpFuncCount: DWORD;
Name: Array [0..0] of Char;
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;
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 $87654321 //'LoadLibrary' Thunk
dd $feeffeef //'GetProcAddress' Thunk
dd $feeffeef //'VirtualAlloc' Thunk
dd $feeffeef //'VirtualFree' Thunk
dd $feeffeef //'VirtualProtect' Thunk
dd $feeffeef //'HeapCreate' Thunk
dd $feeffeef //'HeapAlloc' Thunk
dd 0 //Null
@j:
pop result
end;
{$INCLUDE 'DePack.pas'}
procedure NewEnteryPoint; //壳的EP
asm
pushad
call DelphiEP
end;
procedure EndHere;
asm
end;
//===========SHELLCODE==============
procedure AssembleImpTab;
//组装壳的导入表
const
DllName: PChar = 'kernel32.dll';
FuncName: Array [1..8] of PChar = ('GetModuleHandleA', 'LoadLibraryA',
'GetProcAddress', 'VirtualAlloc', 'VirtualFree', 'VirtualProtect', 'HeapCreate',
'HeapAlloc');
//壳需要导入的函数
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
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -