Опыт дизассемблирования большой .com программы - Особенности и ошибки дизассемблера DisDoc 2.3
ОГЛАВЛЕНИЕ
Особенности и ошибки дизассемблера DisDoc 2.3
К сожалению, DisDoc 2.3 совершает ошибки, иногда регулярные, а иногда редкие, коварные и даже подлые. Самая противная ошибка - случайный пропуск данныхвстречается довольно редко. Начнем с того, что встречается очень часто.
1. EQU - кто тебя выдумал?
В коде, выданном дизассемблером, часто попадаются такие загадочные куски:
;<00465>
s12 proc near
d0046c equ 00046ch
cmp bx,5ah ;00465
Каков смысл присвоения d0046c equ 00046ch ? Чтобы выяснить это, нужно отыскать d0046c в тексте. В нашем случае элемент данных d0046c встречается очень далеко от своего первого появления - в подпрограмме s321
При виде этого текста возникает догадка, что здесь идет зваимодействие с областью данных BIOSa . Действительно, в регистр es засылается число 40, т.е. es будет указывать на адрес 400 - начало этой области. Тогда следующий вопрос - каков смысл адреса 046сh? Легко выяснить, что по этому адресу находится счетчик прерываний от таймера. Если это так, то фрагмент, приведенный на рис.6, обретает смысл - он дает задержку на число прерываний от таймера, заданное в регистре cx. Но если все сказанное верно, то d0046c должно быть равно не 46сh, а просто 6сh! И действительно, если посмотреть подпрограмму s321 отладчиком, то станет ясно, что вместо mov al,BYTE PTR es:d0046c в тексте должно стоять mov al,6ch.
Итак, чтобы исправить эту ошибку, необходимо:
Рассмотрим второй пример. В коде, выданном дизассемблером, встретился такой кусок:
;<0074e>
s22 proc near
d0076a equ 00076ah
d00771 equ 000771h
call s24 ;<00791> ;0074e
...............
b0076a: push cx ;0076a
call s25 ;<0086b> ;0076b
call s23 ;<00776> ;0076e
pop cx ;00771
dec bx ;00772
Поиск элемента данных d0076a окончился неудачей. А d00771 встретился в таком фрагменте:
.....................................
mov BYTE PTR ds:b0076a,51h ;0080b
mov BYTE PTR ds:d00771,59h ;00810
......................................
Здесь явно идет модификация кода подпрограммы s22. Значит, необходимо заменить d00771 на b00771, пометить этой меткой соответствующую инструкцию в s22 и удалить присвоения
d0076a equ 00076ah
d00771 equ 000771h
Исправленный фрагмент s22 будет выглядеть так:
;<0074e>
s22 proc near
call s24 ;<00791> ;0074e
......................................................
b0076a: push cx ;0076a
call s25 ;<0086b> ;0076b
call s23 ;<00776> ;0076e
b00771: pop cx ;00771
dec bx ;00772
..............................................
mov BYTE PTR ds:b0076a,51h ;0080b
mov BYTE PTR ds:b00771,59h ;00810
................................................
Рассмотрим еще один пример. В начале s32 встретились уже знакомые псевдооператоры:
;<00bf7>
s32 proc near
d00c1c equ 000c1ch
d00c1e equ 000c1eh
Если посмотреть в область со смещениями, близкими к с1с, то там окажется кусок повисшего кода, который может быть только данными:
.......................................
or al,BYTE PTR [bp+di] ;00c14
add WORD PTR [bx+di],ax ;00c16
add BYTE PTR [bx+si],al ;00c18
add BYTE PTR [bx+si],al ;00c1a
mov di,1306h ;00c1c
add ax,06c0h ;00c1f
......................................
Теперь нужно поискать идентификаторы d00c1c и d00c1e в тексте, выданном дизассемблером. Очень быстро можно найти фрагменты типа: mov WORD PTR ds:d00c1c,ax, mov WORD PTR ds:d00c1e,ax. Значит, ошибка дизассемблера состоит в том, что он перепутал данные и команды и на этой почве сделал два неправильных присваивания, equ, попавших в начало подпрограммы s32.
Исправления будут заключаться в следующем:
d00c14 db 0a,03,01,01,00,00,00,00 ;00c14
d00c1c db 0bf,06 ;00c1c
d00c1e db 13,05,0c0,06 ;00c1e
В заключение рассмотрим совсем простенький фрагмент кода:
;<01252>
s39 proc near
d0125d equ 00125dh
d0125f equ 00125fh
dec bh ;01252
jz b0124f ;01254 ;Jump if equal (ZF=1)
xor ah,ah ;01256
shl al,1 ;01258 ;Multiply by 2's
rcl ah,1 ;0125a ;CF<--[HI .. LO]<--CF
ret ;0125c
;-----------------------------------------------------
add BYTE PTR [bx+si],al ;0125d
add BYTE PTR [bx+si],al ;0125f
s39 endp
Укажем без комментариев, что подпрогромма s39 должна выглядеть так:
;<01252>
s39 proc near
dec bh ;01252
jz b0124f ;01254 ;Jump if equal (ZF=1)
xor ah,ah ;01256
shl al,1 ;01258 ;Multiply by 2's
rcl ah,1 ;0125a ;CF<--[HI .. LO]<--CF
ret ;0125c
;-----------------------------------------------------
d0125d db 00,00 ;0125d
d0125f db 00,00 ;0125f
s39 endp
В заключение этого пункта подведем итоги. Значки equ называют всевдооператорами. Если говорить о дизассемблере DisDoc 2.3, то это название удивительно точное. Если в тексте встретится equ - то ошибка рядом. Между тем, иногда DisDoc 2.3 употребляет equ вполне корректно. Так что будьте бдительны и не дайте себя обмануть.