Страница 2 из 6 Фундаментальные проблемы 1. Проблема OFFSET'a Предположим, что в тексте, который выдал дизаccемблер есть такой фрагмент: movax,bx;1 shlax,1 ;004bc;2 movsi,8429h;3 addsi,ax;4 pushWORD PTR [si];5
Что засылается в регистр si в третьей строчке - число 8429h или смещение некой метки? На этот вопрос позволяет ответить пятая строчка, из которой видно, что регистр si используется для косвенной адресации. Значит, исправленный фрагмент должен выглядеть следующим образом: movax,bx;1 shlax,1 ;004bc;2 movsi,OFFSET d08429 ;3 addsi,ax;4 pushWORD PTR [si];5
................................
d08429 db 0ff,0ff,0f6 ;8429 db0ff,0d8,0ff,0a6,0ff,60;0842c .....`
Возможно, здесь у многих возникнет сомнение - нужно ли заменять число на соответствующий OFFSET - ведь, казалось бы, в заново ассемблированной программе данные будут иметь то же смещение? К сожалению, это не так. Во первых, мы,как правило, не знаем, какой ассемблер применялся при транслировании оригинального текста, а коды, полученные с помощью разных ассемблеров будут иметь разную длину, что приведет к изменению смещений. Например, команда AND CX,0007h транслируется MASMом 5.1 и TASMом 1.01 как 83E107 и занимает 3 байтa. Но эта же команда может быть транслирована как 81E10700 и занимать 4 байта. Во-вторых, даже если смещение сохранится, программа не поддастся модификации, так как при вставке какого-либо фрагмента кода изменятся смещения и все "развалится". Итак, OFFSETы позволяют склеить программу, делают ее пригодной для модификации. Разобранный пример достаточно примитивен. Попробуем рассмотреть более сложные ситуации и первым делом исследуем фрагмент текста, выданный дизассемблером: movbx,9006h;08f66 b08f75:movWORD PTR ds:d087d0,bx;08f75 ................................. callWORD PTR cs:d087d0;08fc3 ...................................... ;----------------------------------------------------- pushdx;09006 calls419 ;<099a3>;09007 moval,BYTE PTR [si];0900a movBYTE PTR [si],0ffh;0900c popdx;0900f ret;09010 ;-----------------------------------------------------
Здесь возникает тот-же вопрос - что такое 9006h в первой строчке фрагмента - смещение или просто число? Ответить на этот вопрос помогает информация, помещенная дизассемблером в поле комментариев. Мы уже говорили о том что числа, помещенные в этом поле, представляют собой смещения, которые имела инструкция в исходной программе, подвергаемой дизассемблированию. Нетрудно догадаться, что в приведенном фрагменте осуществляется косвенный вызов подпрограммы, и, следовательно, 9006h - это смещение, а не число. Фрагмент должен быть исправлен так: movbx,OFFSET d09006 ;08f66 ...................................... ;----------------------------------------------------- d09006:pushdx;09006 ...................................... ret;09010 Рассмотрим еще один пример косвенного вызова подпрограммы, в котором OFFSET попадает в область данных. s390 proc near .......................................................... movax,WORD PTR [bx+8792h];092c7 movWORD PTR ds:d087d2,ax;092cb ........................................................... callWORD PTR cs:d087d2;093c8 ret;093d4 ;----------------------------------------------------- rorah,1 ;093d5;LO]-->[HI..LO]-->[HI jbb093da ;093d7;Jump if < (no sign) ret;093d9 b093da:incsi;093da ret;093db ............................................................
Чтобы выяснить, что представляет собой 8792h, нужно посмотреть в область со смещениями, близкими к этому числу. Приведем соответствующий фрагмент, выданный дизассемблером: d08790db00,00,0d5,93 ;08790 ...... .............................................................
Видно, что смещению 08792 соответствует слово 0d5,93. Теперь остается заметить, что со смещения 093d5 в исходной программе начинается фрагмент повисшего кода rorah,1 ;093d5 !!!!!!;LO]-->[HI..LO]-->[HI jbb093da ;093d7;Jump if < (no sign) ret;093d9 b093da:incsi;093da ret;093db
Следовательно,весь разобранный пример - это хитроумный косвенный вызов подпрограммы. Исправленный фрагмент должен выглядеть так: s390proc near .......................................................... movax,WORD PTR [bx+OFFSET d08792];092c7 movWORD PTR ds:d087d2,ax;092cb ........................................................... callWORD PTR cs:d087d2;093c8 ret;093d4 ;----------------------------------------------------- d093d5:rorah,1 ;093d5;LO]-->[HI..LO]-->[HI jbb093da ;093d7;Jump if < (no sign) ret;093d9 b093da:incsi;093da ret;093db ............................................................ d08790db00,00 ;08790 ...... d08792 dw OFFSET d093d5 ;08792
Здесь я предвижу большие возражения. Мне скажут, что все это можно интерпретировать иначе, что мои доказательства неубедительны и т.д. С этим я совершенно согласен. Более того, эти доказательства неубедительны и для меня. Гораздо сильнее убеждает то, что программа после ассемблирования работает! Дизассемблирование, как и отладка программ - процесс интуитивный. Опытный человек испытывает особое удовольствие от того, что его немотивированные догадки впоследствии подтверждаются. Как часто мысль, пришедшая в автобусе, во сне, в компании, в самой неподходящей обстановке - оказывается верной! Завершим этот пункт еще одним достаточно хитрым примером. В тексте, который выдал дизассемблер, встретился такой фрагмент: movbx,4f71h ;0522b b0522e:popax;0522e cmpax,bx;0522f jnzb0522e ;05231;Jump not equal(ZF=0) movBYTE PTR ds:d041f4,00;05233 pushax;05238 ret;05239 ................................. calls229 ;<04fc4>;04f71
Возникает все тот же вопрос - что такое 4f71h - число или смещение? Чтобы ответить на этот вопрос, нужно понять, что делает этот участок программы. Давайте попробуем в этом разобраться. Очевидно, из стека выталкивается число, сравнивается с 4f71h и если нет равенства, выталкивается следующее число. Если число равно 4f71h, то оно снова заталкивается в стек и происходит возврат из подпрограммы. Но куда? Ясно, что в то место, смещение которого было в исходной программе равно 4f71h. Как видно из текста, в этом месте стоял вызов подпрограммы s229. Значит, таким странным образом вызывается подпрограмма и 4f71h - это смещение! Исправленный фрагмент должен выглядеть так: movbx, OFFSET d04f71 ;0522b b0522e:popax;0522e cmpax,bx;0522f jnzb0522e ;05231;Jump not equal(ZF=0) movBYTE PTR ds:d041f4,00;05233 pushax;05238 ret;05239 ................................. d04f71:calls229 ;<04fc4>;04f71 |