Опыт дизассемблирования большой .com программы
Страница 5. Особенности и ошибки дизассемблера DisDoc 2.3


 

Особенности и ошибки дизассемблера DisDoc 2.3

К сожалению, DisDoc 2.3 совершает ошибки, иногда регулярные, а иногда редкие, коварные и даже подлые. Самая противная ошибка - случайный пропуск данныхвстречается довольно редко. Начнем с того, что встречается очень часто.

1. EQU - кто тебя выдумал?

В коде, выданном дизассемблером, часто попадаются такие загадочные куски:

;<00465>
s12 proc near
d0046cequ00046ch
cmpbx,5ah;00465

Каков смысл присвоения d0046c equ 00046ch ? Чтобы выяснить это, нужно отыскать d0046c в тексте. В нашем случае элемент данных d0046c встречается очень далеко от своего первого появления - в подпрограмме s321

movax,0040h;06257 ;<es = 0040> moves,ax;0625a moval,BYTE PTR es:d0046c;0625c sti ;06260;Turn ON Interrupts b06261:cmpal,BYTE PTR es:d0046c;06261 jzb06261 ;06266;Jump if equal (ZF=1) moval,BYTE PTR es:d0046c;06268 deccx;0626c jnzb06261 ;0626d;Jump not equal(ZF=0) popax;0626f out61h,al ;06270;060-067:8024 keybrd contrlr ;<es = 0000> popes;06272 ret;06273 s321 endp Рис.6

При виде этого текста возникает догадка, что здесь идет зваимодействие с областью данных BIOSa . Действительно, в регистр es засылается число 40, т.е. es будет указывать на адрес 400 - начало этой области. Тогда следующий вопрос - каков смысл адреса 046сh? Легко выяснить, что по этому адресу находится счетчик прерываний от таймера. Если это так, то фрагмент, приведенный на рис.6, обретает смысл - он дает задержку на число прерываний от таймера, заданное в регистре cx. Но если все сказанное верно, то d0046c должно быть равно не 46сh, а просто 6сh! И действительно, если посмотреть подпрограмму s321 отладчиком, то станет ясно, что вместо mov al,BYTE PTR es:d0046c в тексте должно стоять mov al,6ch.

Итак, чтобы исправить эту ошибку, необходимо:

  • Удалить из начала подпрограммы s12 присвоение d0046c equ00046ch
  • Переписать приведенный на рис.6 фрагмент s321 следующим образом: movax,0040h;06257 ;<es = 0040> moves,ax;0625a moval,BYTE PTR es:006ch;0625c sti ;06260;Turn ON Interrupts b06261:cmpal,BYTE PTR es:006ch;06261 jzb06261 ;06266;Jump if equal (ZF=1) moval,BYTE PTR es:006ch;06268 deccx;0626c jnzb06261 ;0626d;Jump not equal(ZF=0) popax;0626f out61h,al ;06270;060-067:8024 keybrd contrlr ;<es = 0000> popes;06272 ret;06273 s321 endp

    Рассмотрим второй пример. В коде, выданном дизассемблером, встретился такой кусок:

    ;<0074e> 
    s22 proc near
    d0076aequ00076ah
    d00771equ000771h
    calls24 ;<00791>;0074e
    ...............
    b0076a:pushcx;0076a
    calls25 ;<0086b>;0076b
    calls23 ;<00776>;0076e
    popcx;00771
    decbx;00772

    Поиск элемента данных d0076a окончился неудачей. А d00771 встретился в таком фрагменте:

    ..................................... 
    movBYTE PTR ds:b0076a,51h;0080b
    movBYTE PTR ds:d00771,59h;00810
    ......................................

    Здесь явно идет модификация кода подпрограммы s22. Значит, необходимо заменить d00771 на b00771, пометить этой меткой соответствующую инструкцию в s22 и удалить присвоения

     d0076a equ00076ah
    d00771 equ000771h

    Исправленный фрагмент s22 будет выглядеть так:

    ;<0074e> 
    s22 proc near
    calls24 ;<00791>;0074e
    ......................................................
    b0076a:pushcx;0076a
    calls25 ;<0086b>;0076b
    calls23 ;<00776>;0076e
    b00771:popcx;00771
    decbx;00772
    ..............................................
    movBYTE PTR ds:b0076a,51h;0080b
    movBYTE PTR ds:b00771,59h;00810
    ................................................

    Рассмотрим еще один пример. В начале s32 встретились уже знакомые псевдооператоры:

    ;<00bf7> 
    s32 proc near
    d00c1cequ000c1ch
    d00c1eequ000c1eh

    Если посмотреть в область со смещениями, близкими к с1с, то там окажется кусок повисшего кода, который может быть только данными:

    ....................................... 
    oral,BYTE PTR [bp+di];00c14
    addWORD PTR [bx+di],ax;00c16
    addBYTE PTR [bx+si],al;00c18
    addBYTE PTR [bx+si],al;00c1a
    movdi,1306h;00c1c
    addax,06c0h;00c1f
    ......................................

    Теперь нужно поискать идентификаторы d00c1c и d00c1e в тексте, выданном дизассемблером. Очень быстро можно найти фрагменты типа: mov WORD PTR ds:d00c1c,ax, mov WORD PTR ds:d00c1e,ax. Значит, ошибка дизассемблера состоит в том, что он перепутал данные и команды и на этой почве сделал два неправильных присваивания, equ, попавших в начало подпрограммы s32.

    Исправления будут заключаться в следующем:

  • Убрать из начала подпрограммы s32 два псевдооператора equ.
  • Переписать коды на рисунке 7 следующим образом:
    d00c14db 0a,03,01,01,00,00,00,00 ;00c14 
    d00c1cdb 0bf,06 ;00c1c
    d00c1e db 13,05,0c0,06 ;00c1e

    В заключение рассмотрим совсем простенький фрагмент кода:

    ;<01252> 
    s39 proc near
    d0125dequ00125dh
    d0125fequ00125fh
    decbh;01252
    jzb0124f ;01254;Jump if equal (ZF=1)
    xorah,ah;01256
    shlal,1 ;01258;Multiply by 2's
    rclah,1 ;0125a;CF<--[HI .. LO]<--CF
    ret;0125c
    ;-----------------------------------------------------
    addBYTE PTR [bx+si],al;0125d
    addBYTE PTR [bx+si],al;0125f
    s39 endp

    Укажем без комментариев, что подпрогромма s39 должна выглядеть так:

    ;<01252> 
    s39 proc near
    decbh;01252
    jzb0124f ;01254;Jump if equal (ZF=1)
    xorah,ah;01256
    shlal,1 ;01258;Multiply by 2's
    rclah,1 ;0125a;CF<--[HI .. LO]<--CF
    ret;0125c
    ;-----------------------------------------------------
    d0125ddb 00,00 ;0125d
    d0125fdb 00,00 ;0125f
    s39 endp

    В заключение этого пункта подведем итоги. Значки equ называют всевдооператорами. Если говорить о дизассемблере DisDoc 2.3, то это название удивительно точное. Если в тексте встретится equ - то ошибка рядом. Между тем, иногда DisDoc 2.3 употребляет equ вполне корректно. Так что будьте бдительны и не дайте себя обмануть.

  •  
    « Предыдущая статья   Следующая статья »