我们知道PE在运行的时候,为了安全起见,是不允许修改代码段的,但Windows并没有对不能修改代码段作真正的限制,只是在PE的头部使用了一个标记来表明是否允许修改代码段而已!
Delphi编译出来的EXE,其text段是代码段,修改text段的一个标记60为E0即可,参考下图:
下面的代码是演示如何修改代码段:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnTest: TButton;
btnCopyCode: TButton;
btnRestoreCode: TButton;
procedure btnTestClick(Sender: TObject);
procedure btnCopyCodeClick(Sender: TObject);
procedure btnRestoreCodeClick(Sender: TObject);
private
{ Private declarations }
Buf: PChar;
L : Integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses lyhTools;
{$R *.dfm}
function DlgError(const s: string): Integer;
begin
Result := MessageBox(GetActiveWindow, PCHAR(s), 'Error', MB_OK or MB_ICONERROR);
end;
procedure ErrorEnd;
begin
// 空的占位符号,用于计算DlgError的代码的大小!
end;
procedure TForm1.btnTestClick(Sender: TObject);
begin
DlgError('Error');
end;
procedure TForm1.btnCopyCodeClick(Sender: TObject);
var
P : Pointer;
begin
P := @DlgError; // 保存的代码的首地址
L := Integer(@ErrorEnd) - Integer(@DlgError); // 求代码段的大小
GetMem(Buf, L); // 申请内存块保存代码!
Move(P^, Buf^, L); // Copy代码段
WriteToFile(Buf, L, 'C:\Demo.dat', False); // 保存到文件
FillChar(P^, L, 0); // 把代码段置空
end;
procedure TForm1.btnRestoreCodeClick(Sender: TObject);
var
P : Pointer;
begin
P := @DlgError;
Move(Buf^, P^, L);
FreeMem(Buf);
end;
end.
上面的代码编译后,如果不修改60为E0,那么程序运行点击CopyCode按钮会出现AV错误,不能写入对应的地址;修改60为E0后,程序可以正常运行!