Опыт дизассемблирования большой .com программы - Зависимость от транслятора

ОГЛАВЛЕНИЕ

 

3. Зависимость от транслятора

Программисты на ассемблере склонны пренебрегать правилами хорошего тона, нарушать все мыслимые табу, и это создает дополнительные трудности при дизассемблировании. В качестве примера приведем фрагмент кода, выданного дизассемблером

s25	proc near 
inc cx ;0086b
add di,bp ;0086c
adc si,00 ;0086e
add dx,si ;00871
push di ;00873
shl di,1 ;00874 ;Multiply by 2's
adc dx,00 ;00876
pop di ;00879
ret ;0087a

Этот фрагмент представляется совершенно невинным, и действительно, он дизассемблирован правильно. Вся беда в том, что программист задумал изменять этот фрагмент, то есть резать по живому. Оказывается, в программе есть еще такой кусок

	mov	di,086bh		;007f8 
......................................
mov BYTE PTR [di],4ah ;00800
mov BYTE PTR [di+07],0f1h ;00803
mov BYTE PTR [di+0ch],0d1h ;00807
......................................
ret ;00815
Рис.1

Так как di используется для косвенной адресации, нам прежде всего необходимо заменить 086bh на соответствующий OFFSET d0086b и пометить этой меткой начало подпрограммы s25:

s25 	proc near
d0086b: inc cx ;0086b
..............................................

Далее следует понять, что делают инструкции, приведенные на рис.1 с подпрограммой s25. Пусть эта подпрограмма асслемблирована с помощью TASM 1.01. Выданный ассемблером код будет таким, как показано на рисунке 2.

 41      INC CX       41       INC CX 
03FD ADD DI,BP 01EF ADD DI,BP
83D600 ADC SI,0000 83D600 ADC SI,0000
03D6 ADD DX,SI 01F2 ADD DX,SI
57 PUSH DI 57 PUSH DI
D1E7 SHL DI,1 D1E7 SHL DI,1
83D200 ADC DX,0000 83D2000 ADC DX,0000
5F POP DI 5F POP DI
C3 RET C3 RET
Рис.2 Рис.3

Но вся беда в том, что исходная программа была ассемблирована другим ассемблером и имеет вид, показанный на рисунке 3. Как видно из сравнения рисунков 2 и 3, TASM 1.01 и неизвестный ассемблер транслируют инструкции ADD по-разному, и это приводит к катастрофическим последствиям. Действительно, посмотрим, как воздействует участок кода, показанный на Рис.1 (перед этим заменим 086bh на OFFSET d0086b) на подпрограмму s25, транслируемую TASMом (рис.4) и неизвестным ассемблером (рис.5).

 4A      DEC DX          4A      DEC DX 
03FD ADD DI,BP 01EF ADD DI,BP
83D600 ADC SI,0000 83D600 ADC SI,0000
03F1 ADD SI,CX ;!!!! 01F1 ADD CX,SI ;!!!!
57 PUSH DI 57 PUSH DI
D1E7 SHL DI,1 D1E7 SHL DI,1
83D100 ADC CX,0000 83D100 ADC CX,0000
5F POP DI 5F POP DI
C3 RET C3 RET
Рис.4 Рис.5

Сравнение рисунков 4 и 5 показывает, что логика работы программы меняется в зависимости от того, какой ассемблер применялся. Как выкрутиться из этой ситуации, если нужного ассемблера нет под рукой? Самый простой, но не очень красивый путь - поставить "заплатку". Чтобы можно было использовать TASM, подпрогроамма s25 должна выглядеть так:

s25 	proc near 
d0086b: inc cx ;0086b
add di,bp ;0086c
adc si,00 ;0086e
db 01,0f2 ;add dx,si !!!!!! ;00871
push di ;00873
shl di,1 ;00874 ;Multiply by 2's
adc dx,00 ;00876
pop di ;00879
ret ;0087a