转: 加壳原理与简单实现加壳(delphi源码)


来自:http://bbs.pediy.com/showthread.php?t=57671

{*****************************************************************
AddShell()源自于前一段时间有写的addsection()新增区段代码,
在增加区段代码的基础上,追加了
1.修改启动入口点位置
2.增加一段壳头xor $50的代码function AttachStart-function AttachEnd
 这一段代码是先填充,再被修改成合适原EXE的壳头
3.修改原启动代码入口点所在区段的段属性可写并进行xor $50运算加密


不支持addshell()处理已经过addshell的exe
*****************************************************************
}

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 
= class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Button2: TButton;
    Button3: TButton;
    
procedure Button1Click(Sender: TObject);
    
procedure Button3Click(Sender: TObject);
    
procedure Button2Click(Sender: TObject);
  private
    
{ Private declarations }
  public
    
{ Public declarations }
  
end;

var
  Form1             : TForm1;

implementation

{$R *.dfm}
function AttachStart: dword; stdcall;   //我们定义的待填充数据
asm
       pushfd
       pushad
       mov eax,$
12345678      //将会被自动计算并修改为加密初始地址
       mov ebx,$
1234          //将会被自动计算并修改为加密大小
       mov ecx,
0
       @AA:
       xor byte ptr[eax],$
50
       inc eax
       inc ecx
       cmp ecx,ebx
       jbe @aa
       popad
       popfd
       push $
12345678        //将会被自动计算并修改为原OEP
       ret
end;

function AttachEnd: dword; stdcall;
begin
end;

{-------------------------增加区块并实现简易加壳--------------------------------}
procedure AddShell(lFileName: string; lBackup: boolean); //打开exe文件,是否备份
var
  hFile             : THandle;          
//文件句柄
  ImageDosHeader    : IMAGE_DOS_HEADER; 
//DOS部首
  ImageNtHeaders    : IMAGE_NT_HEADERS; 
//映象头
  ImageSectionHeader: IMAGE_SECTION_HEADER; 
//块表
  lPointerToRawData : dword;            
//指向文件中的偏移
  lVirtualAddress   : dword;            
//指向内存中的偏移
  i                 : integer;          
//循环变量
  BytesRead, ByteSWrite: Cardinal;      
//读写用参数
  AttachSize        : dword;            
//附加段大小
  AttachData, ChangeData: integer;      
//附加段填充数据
  OEP               : integer;          
//使用过程中用到的EP
  lpBuffer          : 
array[0..1024 * 400of byte; {待加密数据存储缓冲区}
  nNumberOfBytesToRead, lpNumberOfBytesRead: dword; 
//加密时用到的一些数据
  StartEN, SizeEN, StartCr: dword;      
//加密用的开始物理地址和大小
begin

  
//定义附加段填充数据
  AttachData :
= 0;

  
//打开文件
  hFile :
= CreateFile(PChar(lFileName), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

  
//校验
  
if hFile = INVALID_HANDLE_VALUE then
  
begin
    ShowMessage(
'打开文件失败');
    exit;
  
end;

  
//确认备份
  
if lBackup then CopyFile(PChar(lFileName), PChar(lFileName + '.bak'), False);
  try

    
//读取DOS部首到ImageDosHeader
    ReadFile(hFile, ImageDosHeader, SizeOf(ImageDosHeader), BytesRead, 
nil);

    
//校验
    
if ImageDosHeader.e_magic <> IMAGE_DOS_SIGNATURE then
    
begin
      ShowMessage(
'不是有效的PE文件!');
      exit;
    
end;

    
//指向映象头
    SetFilePointer(hFile, ImageDosHeader._lfanew, 
nil, FILE_BEGIN);

    
//读取映向头到ImageNtHeaders
    ReadFile(hFile, ImageNtHeaders, SizeOf(ImageNtHeaders), BytesRead, 
nil);

    
//校验
    
if ImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE then
    
begin
      ShowMessage(
'不是有效的PE文件');
      exit;
    
end;
    
{********************************}
    
{OEP=基址+原EP}
    OEP :
= ImageNtHeaders.OptionalHeader.ImageBase + ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;

    
{********************************}

    
//计算加入块对齐后大小
    AttachSize :
= ((integer(@AttachEnd) - integer(@AttachStart)) div ImageNtHeaders.OptionalHeader.FileAlignment + 1* ImageNtHeaders.OptionalHeader.FileAlignment;

    
//初始化文件中偏移和映象中偏移
    lPointerToRawData :
= 0;
    lVirtualAddress :
= 0;

    
for i := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
    
begin

      
//读取块表中信息
      ReadFile(hFile, ImageSectionHeader, SizeOf(ImageSectionHeader), BytesRead, 
nil);

      
{********************************}
       
{查找原EP所在区段(原EP所在区段),记录物理偏移(加密用初始地址),物理大小(加密用长度)}
      
if LPCSTR(@ImageSectionHeader.Name[0]) = '.EN' then
      
begin
        ShowMessage(
'已经过本addshell处理!');
        exit;
      
end;

      
if ImageNtHeaders.OptionalHeader.AddressOfEntryPoint > ImageSectionHeader.VirtualAddress then
      
begin
        StartEN :
= ImageSectionHeader.PointerToRawData;
        SizeEN :
= ImageSectionHeader.SizeOfRawData;
        StartCr :
= ImageNtHeaders.OptionalHeader.ImageBase + ImageSectionHeader.VirtualAddress;
      
end;

      
{********************************}

      
//计算文件中偏移
      
if lPointerToRawData < ImageSectionHeader.PointerToRawData + ImageSectionHeader.SizeOfRawData then
        lPointerToRawData :
= ImageSectionHeader.PointerToRawData + ImageSectionHeader.SizeOfRawData;

      
//计算映象中偏移
      
if lVirtualAddress < ImageSectionHeader.VirtualAddress + ImageSectionHeader.Misc.VirtualSize then
        lVirtualAddress :
= ImageSectionHeader.VirtualAddress + ImageSectionHeader.Misc.VirtualSize;
    
end;

    
{增加块,定义块各项属性}

    Move(
'.EN'#0, ImageSectionHeader.Name[0], 5);

    
//设置初始属性
    ImageSectionHeader.Misc.VirtualSize :
= AttachSize;
    ImageSectionHeader.VirtualAddress :
= lVirtualAddress;
    ImageSectionHeader.SizeOfRawData :
= AttachSize;
    ImageSectionHeader.PointerToRawData :
= lPointerToRawData;
    ImageSectionHeader.PointerToRelocations :
= 0;
    ImageSectionHeader.PointerToLinenumbers :
= 0;
    ImageSectionHeader.NumberOfRelocations :
= 0;

    
//校正新节物理偏移(物理区块对齐)
    
if ImageSectionHeader.VirtualAddress mod ImageNtHeaders.OptionalHeader.SectionAlignment > 0 then
      ImageSectionHeader.VirtualAddress :
= (ImageSectionHeader.VirtualAddress div ImageNtHeaders.OptionalHeader.SectionAlignment + 1* ImageNtHeaders.OptionalHeader.SectionAlignment;

    
//校正新节映象偏移(映象中区块对齐)
    
if ImageSectionHeader.Misc.VirtualSize mod ImageNtHeaders.OptionalHeader.SectionAlignment > 0 then
      ImageSectionHeader.Misc.VirtualSize :
= (ImageSectionHeader.Misc.VirtualSize div ImageNtHeaders.OptionalHeader.SectionAlignment + 1* ImageNtHeaders.OptionalHeader.SectionAlignment;

    
//设置区块属性
    ImageSectionHeader.Characteristics :
= $E00000E0;

    
//保存区块信息
    WriteFile(hFile, ImageSectionHeader, SizeOf(ImageSectionHeader), ByteSWrite, 
nil);

    
//校正内存映象大小
    ImageNtHeaders.OptionalHeader.SizeOfImage :
= ImageNtHeaders.OptionalHeader.SizeOfImage + ImageSectionHeader.Misc.VirtualSize;
    
//更新OEP
    ImageNtHeaders.OptionalHeader.AddressOfEntryPoint :
= ImageSectionHeader.VirtualAddress;

    
//校正块数目
    Inc(ImageNtHeaders.FileHeader.NumberOfSections);

    
//定位到映象头
    SetFilePointer(hFile, ImageDosHeader._lfanew, 
nil, FILE_BEGIN);

    
//保存校正过的映象头
    WriteFile(hFile, ImageNtHeaders, SizeOf(ImageNtHeaders), ByteSWrite, 
nil);

    
//定位到新节开始处
    SetFilePointer(hFile, ImageSectionHeader.PointerToRawData, 
nil, FILE_BEGIN);

    
//用00数据填充满新节
    
for i := 1 to AttachSize do
    
begin
      WriteFile(hFile, PByte(@AttachData)^, 
1, ByteSWrite, nil);
    
end;

    
{填充自定义数据}
      
//指向新节开始处
    SetFilePointer(hFile, ImageSectionHeader.PointerToRawData, 
nil, FILE_BEGIN);

    
//填充我们定义的数据
    WriteFile(hFile, PByte(@AttachStart)^, integer(@AttachEnd) 
- integer(@AttachStart), ByteSWrite, nil);
    
{********************************}
    
//修改所谓的外壳处大量数据
    ChangeData :
= ImageSectionHeader.PointerToRawData + 3;
    SetFilePointer(hFile, ChangeData, 
nil, FILE_BEGIN);
    WriteFile(hFile, StartCr, 
4, ByteSWrite, nil); //开始加密地址
    ChangeData :
= ChangeData + 5;
    SetFilePointer(hFile, ChangeData, 
nil, FILE_BEGIN);
    WriteFile(hFile, SizeEN, 
4, ByteSWrite, nil); //大小
    ChangeData :
= ChangeData + 21;
    SetFilePointer(hFile, ChangeData, 
nil, FILE_BEGIN);
    WriteFile(hFile, OEP, 
4, ByteSWrite, nil); //跳回OEP

    
{********************************}
    
//没有异常,显示增加区块成功!
    ShowMessage(
'增加区块成功!');


    SetFilePointer(hFile, StartEN, 
nil, FILE_BEGIN);
    ReadFile(hFile, lpBuffer, SizeEN, BytesRead, 
nil);
    
for i := 0 to SizeEN - 1 do
    
begin
      byte(pointer(integer(@lpBuffer) 
+ i)^) := byte(pointer(integer(@lpBuffer) + i)^) xor $50;
    
end;
    SetFilePointer(hFile, StartEN, 
nil, FILE_BEGIN);
    WriteFile(hFile, lpBuffer, SizeEN, ByteSWrite, 
nil);
    
//没有异常,显示变换成功!
    ShowMessage(
'变换数据成功!');



    
{********************************}
    SetFilePointer(hFile, (ImageDosHeader._lfanew 
+ SizeOf(ImageNtHeaders)), nil, FILE_BEGIN);

    
for i := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
    
begin

      
//读取块表中信息
      ReadFile(hFile, ImageSectionHeader, SizeOf(ImageSectionHeader), BytesRead, 
nil);
      
if ImageSectionHeader.PointerToRawData = StartEN then
      
begin
        ImageSectionHeader.Characteristics :
= $E00000E0;
        SetFilePointer(hFile, 
-SizeOf(ImageSectionHeader), nil, FILE_CURRENT);
        
//保存区块信息
        WriteFile(hFile, ImageSectionHeader, SizeOf(ImageSectionHeader), ByteSWrite, 
nil);
        Break;
      
end;
    
end;
    ShowMessage(
'修改区段属性成功!');
    
{********************************}


  finally

    
{8.退出}
        
//关闭文件
    CloseHandle(hFile);
  
end;

end;
{*************************Func end*********************************}

procedure TForm1.Button1Click(Sender: TObject);//addshell
begin

  AddShell(Edit1.text, true);
end;

procedure TForm1.Button3Click(Sender: TObject);//browser
begin
  
with TOpenDialog.Create(Self) do
  try
    Filter :
= '可执行文件 (*.exe)|*.exe';
    
if Execute then
    
begin
      Edit1.text :
= FileName;
    
end;
  finally
    Free;
  
end;
end;

procedure TForm1.Button2Click(Sender: TObject);//exit
begin
  close;
end;

end.
posted @ 2008-06-10 11:31 陆岛工作室 阅读(...) 评论(...) 编辑 收藏