Путеводитель по написанию вирусов: 12. Оптимизация — Архив WASM.RU
Есть два вида оптимизации: структурная и локальная. В этой маленькой главе я затрону оба эти вида. Hо, во-первых, вы должны понять одну вещь: никогда не оптимизируйте ваш код, пока ваш код не будет полностью работать. Если вы начнете оптимизировать код, который не работает, вы наворотите еще больше ошибок.
Структурная оптимизация
Это самая эффективная и самая сложная для воплощения и понимания. Этот вид оптимизации можно легко понять, используя бумагу для зарисовки алгоритма вашего вируса. Здесь у нас нет, поэтому давайте представим, что вы, вернее ваш вирус, сначала открываете файл только для чтения, закрываете, открываете снова для чтения/записи и закрываете снова. Все это - потеря байтов. При структурной оптимизации вы должны хорошо продумать, что должен делать ваш вирус и что нет, дабы не тратить место попусту. Решение будет отличаться в зависимости от конкретной ситуации.
Локальная оптимизация
Это самый простой вид, хотя и с его помощью можно сэкономить множество байтов. Метод состоит в изменении некоторых линий на другие, которые делают то же самое, но занимают меньшее количество байт.
¤ Очищение регистров:
Код (Text):
mov bx,0000h ; 3 байта xor bx,bx ; 2 байта sub bx,bx ; 2 байтаHикогда не используйте первый способ, а используйте второй или третий. Один регистр (DX) можно очищать еще одним способом. Давайте посмотрим:
Код (Text):
mov dx,0000h ; 3 байта xor dx,dx ; 2 байта sub dx,dx ; 2 байта cwd ; Конвертируем слово в двойное слово ; (1 байт)CWD будет работать, только если содержимое AX меньше, чем 8000h. Есть еще одни путь очистить AH за один байт: если AL < 80h, вы можете использовать инструкцию CBW.
¤ Сравнения:
Для сравнения, как известно, существует специальная инструкция. Для сравнения двух регистров вы можете использовать два способа:
Код (Text):
cmp ax,bx ; 2 байта xor ax,bx ; 2 байтаHо XOR мы можем использовать только, если мы хотим узнать, равны ли значения. Тем не менее, мы можем использовать XOR вместо CMP, чтобы сохранить байт, если сравниваем регистр с числом:
Код (Text):
cmp ax,0666h ; 3 байта xor ax,0666h ; 2 байтаНо в силу природы инструкции XOR мы не можем использовать ее для того, чтобы узнать, пусть ли регистр. Здесь нас спасет OR...
¤ Оптимизированный регистр - AX:Код (Text):
cmp ax,0000h ; 3 байта or ax,ax ; 2 байтаВы можете использовать его для сравнений:
Код (Text):
cmp bx,0666h ; 4 байта cmp ax,0666h ; 3 байтаИ вы можете перемещать содержимое AX в другой регистр оптимизированным образом:
Код (Text):
mov bx,ax ; 2 байта xchg ax,bx ; 1 байтВы можете это делать, если значения AX и BX для вас не важны. Это инструкция будет полезна для открытия файла, потому что файловый хэндл лучше держать в BX.
¤ Строковые операции:
Каждая из строковых команд (MOVS, STOS, SCAS...) - это оптимизированный способ выполнять определенные действия. Давайте посмотрим, для каких целей они могут пригодиться:
- MOVS: перемещение из позиции DS:[SI] в ES:[DI]
Код (Text):
les di,ds:[si] ; 3 байта movsb ; Если нам нужен байт (1 байт) movsw ; Если нам нужно слово (1 байт) movsd ; Если нам нужно двойное слово (2 ; байта) 386+- LODS: помещает в приемник значение в позиции DS:[SI]
Код (Text):
mov ax,ds:[si] ; 2 байта lodsb ; Если нам нужен байт (1 байт) lodsw ; Если нам нужно слово (1 байт) lodsd ; Если нам нужно двойное слово (2 ; байта) 386+- STOS: помещает в приемник значение позиции ES:[DI]
Код (Text):
les di,al ; Нельзя это сделать! les di,ax ; Нельзя это сделать! stosb ; Если нужен байт (1 байт) stosw ; Если нужно слово (1 байт) stosd ; Если нужно двойное слово (2 байта) ; 386+- CMPS: сравнивает значение в DS:[SI] со значением в ES:[DI]
Код (Text):
cmp ds:[si],es:[di] ; Не может быть два переопределения ; сегмента! cmpsb ; Если нужен байт (1 байт) cmpsw ; Если нужно слово (1 байт) cmpsd ; Если нужно двойное слово (2 байта) ; 386+- SCAS: сравнивает значение приемника с ES:[DI]
¤ 16-ти битные регистры:Код (Text):
cmp ax,es:[di] ; 3 байта scasb ; Если нужен байт (1 байт) scasw ; Если нам нужно слово (1 байт) scasd ; Если нам нужно двойное слово (2 байта) ; 386+Обычно использование 16-ти битных регистров в плане оптимизации лучше, чем использование 8-ми битных. Давайте посмотрим пример с инструкцией MOVЖ
Код (Text):
mov ah,06h ; 2 байта mov al,66h ; 2 байта (вместе 4 байта) mov ax,0666h ; 3 байтаТакже увеличение/понижение значения 16-ти битного регистра тоже более выгодно:
Код (Text):
inc al ; 2 байта inc ax ; 1 байт dec al ; 2 байта dec ax ; 1 байт¤ Базы и сегменты:
Перемещение из одного сегмента в другой нельзя сделать напрямую, поэтому мы должны сделать это одним из следующих способов:
Код (Text):
mov es,ds ; Это сделать нельзя! mov ax,ds ; 2 байта mov es,ax ; 2 байта (вместе 4 байта) push ds ; 1 байт pop es ; 1 байт (в сумме 2 байта)Использование DI/SI более выгодно, чем использование BP.
Код (Text):
mov ax,ds:[bp] ; 4 байта mov ax,ds:[si] ; 3 байта¤ Процедуры:
Если вы используете какой-то код много раз, подумайте о создании процедуры. Это может оптимизировать ваш код. Тем не менее, неправильное использование процедур может привести к обратному результату: размер кода возрастет. Поэтому если вы хотите знать, поможет ли вам создание процедуры, используйте эту маленькую формулу:
Код (Text):
X = [rout. size - (CALL size + RET size)] * number of calls - rout. sizeCALL size + RET size означают 4 байта. X будем количеством байт, которое мы сэкономим. Давайте посмотрим на типичный пример, перемещение файлового указателя:
Код (Text):
fpend: mov ax,4202h ; 3 bytes fpmov: xor cx,cx ; 2 bytes cwd ; 1 byte int 21h ; 2 bytes ret ; 1 byteУ нас есть 8 байт + размер CALL... 11 байт. Давайте посмотрим, соптимизирует ли это наш код:
Код (Text):
X = [ 7 - ( 3 + 1 ) ] * 3 - 7 X = 2 байта сэкономленоЭто, конечно, надуманные вычисления. Вы можете вызывать эту процедуру больше 3-х раз (или меньше), что изменит размер, а также могут оказать свое влияние другие факторы. ¤ Последние советы по локальной оптимизации:
- Используйте SFT. В этой структуре множество полезной информации, и вы можете манипулировать ими безо всяких проблем.
- Пусть ваш компилятор делает по крайней мере 3 прохода, чтобы удалить все ненужные NOP'ы и другой отстой.
- Используйте стек.
- Также во многих случаях выгодно использовать инструкцию LEA. © Billy Belcebu, пер. Aquila
Путеводитель по написанию вирусов: 12. Оптимизация
Дата публикации 3 сен 2002