451
451
virus magazine, issue #1
Функции      Структуры/Флаги
index

LDIZX
v 1.01
                             
 Дизассемблер является примером того,что сразу написать непросто .В процессе 
 работы с ним появляются новые потребности в чем-либо,которые не были 
 актуальными вчера, и приходится модифицировать дизассемблер для своих нужд 
 снова.Завтра ,может,понадобится еще более гибкая система - и история 
 повторится вновь.

 Как можно понять LDIZX - дизассемблирующий движок и является продуктом такой 
 вот невостребованности.

 Основные характеристики :

   * Достаточно полная информация ,получаемая на выходе для анализа/сборки 
     команды.
   * Использование в качестве только лишь дизассемблера длин	
   * Не содержит данных/абсолютных смещений
   * Использован универсальный C call т.е. может быть включен в какой-нибудь
     HLL
   * Обрабатывает int 20h (0CD20h) как 6-ти байтную команду, т.е. как VxDcall
     (win32-ориентация).Если необходимо перенести его куда-нибудь еще ,то это 
     достигается изменением 1-5 строк в исходнике.
Описание функций
 Т.к. использован C call,то тут дано описание ф-ций на C , хотя это просто 
 способ передачи параметров процедуре.

 Для работы движка необходимы таблицы. Процедура их распаковки:
 

 ldizx_init  ( VOID* TablePtr 		// Килобайтный буфер для таблиц
	     );

 
 После выполнения этой процедуры в память по адресу TablePtr распаковываются
 таблицы движка,которые используются при дизассемлировании.

 Главная функция (собственно дизассемблирующая код):
 
 ldizx       ( VOID* InPtr,		// Поинтер на входной код
               CMD*  OutPtr,            // Поинтер на структуру CMD
               VOID* TablePtr           // Поинтер на распакованые таблицы
	      ) 	
 
 После выполнения данной процедуры структура ,заданная вторым параметром 
 заполняется исходя из команды ,которая дизассемблируется.На выходе LDIZX
 передает длину команды в EAX либо FFFFFFFFh в случае ошибки. 

 Если при дизассемблировании не требуется информация о команде ,кроме ее 
 длины, то в качестве второго параметра передается 0 и LDIZX возвращает лишь
 длину команды в EAX.

 Процедура ассемблирования структуры cmd в команду не включена, т.к. почти
 всегда требуется специфичное конструирование команды или, наоборот, очень 
 простое и лучше писать ассемблирование отдельно.

Структуры и флаги
 Вторым параметром в движок передается поинтер на структуру CMD ,в которую
 после выполнения главной процедуры, записывается информация о команде.Ее 
 формат представлен ниже:
 
 typedef  struct {

                BYTE		lc_size;	// длина команды
                BYTE		lc_psize;	// длина префиксов

                DWORD		lc_flags;	// флаги
                BYTE		lc_tttn;	// tttn

                BYTE		lc_sib;		// sib
                BYTE		lc_modrm;	// modrm

		BYTE		lc_reg;		// reg
                BYTE		lc_mod;		// mod
                BYTE		lc_ro;		// r/o

                BYTE		lc_rm;		// r/m

                BYTE		lc_base;	// base
                BYTE		lc_index;	// index
                BYTE		lc_scale;	// scale

                DWORD		lc_offset;	// смещение

                BYTE		lc_operand[6];  // операнд

                BYTE		lc_soffset;	// длина смещения
                BYTE		lc_soperand;	// длина операнда

		BYTE		lc_mask1;	// маска
		BYTE		lc_mask2;       //
		} cmd;

 
 Содержание полей lc_sib,lc_modrm,lc_rm,lc_ro,lc_base,lc_index,lc_scale думаю 
 понятно из их названия , замечу ,что поле mod дано сдвинутым на 6 бит влево 
 т.к. его часто с целью восстановления команды так сдвигают и было бы разумно 
 его таким оставить,каким оно есть в команде (т.е. занимающем 6-й и 7-й биты)

 Операнд является 6-ти байтовым с учетом таких команд, как JMP FAR/CALL FAR,
 где есть и селектор и смещение,поэтому он пишется в порядке следования его 
 байтов в команде.Т.е. необходимо при обращении к полю lc_operand учитывать
 размер операнда ,содержащийся в поле lc_soperand.

 tttn имеет смысл в командах условного выполнения (JCC/SETCC и т.д.), для них
 это поле содержит условие выполнения команды.

 На lc_reg стоит смотреть только тогда,когда команда не имеет modr/m и 
 работает с регистром.Содержание этого поля и определяет использованный 
 регистр.

 Длина префиксов дана с целью выявления нестандартных команд,в которых по 
 нескольку одинаковых префиксов.

 В полях lc_mask1 и lc_mask2 содержится маска команды.Причем она дается в 
 полном виде включая 0F,если этот префикс у команды есть.Это поле полезно,
 когда надо найти определенную команду по ее маске.Т.е. движок сам определит 
 маску команды и занесет ее в эти поля.

 Наиболее важную информацию о команде содержат флаги (lc_flags),в зависимости 
 от их содержания трактуются большинство полей в структуре CMD, поэтому 
 следует прежде всего смотреть на флаги,а уже только потом на содержание 
 полей.

LF_PCS 0x00000001 Присутствует префикс CS
LF_PDS 0x00000002 Присутствует префикс DS
LF_PES 0x00000004 Присутствует префикс ES
LF_PSS 0x00000008 Присутствует префикс SS
LF_PFS 0x00000010 Присутствует префикс FS
LF_PGS 0x00000020 Присутствует префикс GS
LF_POP 0x00000040 Присутствует префикс замены разрядности операнда
LF_POF 0x00000080 Присутствует префикс замены разрядности адреса
LF_PLOCK 0x00000100 Присутствует префикс LOCK
LF_PREPZ 0x00000200 Присутствует префикс REPZ
LF_PREPNZ 0x00000400 Присутствует префикс REPNZ
LF_MODRM 0x80000000 Присутствует modr/m
LF_SIB 0x40000000 Присутствует sib
LF_OFFSET 0x20000000 Присутствует смещение
LF_OPERAND 0x10000000 Присутствует операнд
LF_REG 0x08000000 Присутствует reg (команда без modr/m)
LF_REG1 0x04000000 R/m является регистром и имеет смысл
LF_REG2 0x02000000 R/o является регистром и имеет смысл
LF_BASE 0x01000000 База в sib присутствует и имеет значение
LF_BASE 0x00800000 Индекс в sib присутствует и имеет значение
LF_MEM 0x00400000 Команда работает с памятью (т.е. mod <> 11b )
LF_TTTN 0x00200000 Присутствует tttn
LF_RAW 0x00100000 cmd не содержит полной информации
LF_D 0x00008000 В опкоде присутствует d
LF_S 0x00004000 В опкоде присутствует s
LF_SDV 0x00002000 s либо d равен 1 (в зависимосити от флагов LF_S и LF_S)
LF_W 0x00001000 В опкоде присутствует w
LF_WV 0x00000800 w равен 1
 Флаги LF_REG1,LF_REG2,LF_BASE,LF_INDEX показывают ,что r/m,r/o,base и index
 соответственно являются регистрами.Т.е. это значит ,что их необходимо 
 трактовать как регистры .Это сделано для того , чтобы отделить команды ,не 
 использующие эти поля как регистры.При прямой адресации команды типа :

	mov [12345678h],edx

 Имеют в r/m 101b т.е.регистр ebp и по идее должна быть использована 
 косвенная адресация, но по логике работы команды нет никакого регистра т.к. 
 это особенность строения команд. Тоже самое и с базой, индексом.В r/o может 
 быть и не регистр ,а уточняющий операцию код.Поэтому и введены эти флаги.