Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

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

А.Б.КРУПНИК

В данной статье мне хочется рассказать о дизассемблировании большой программы (графического редактора). Не будучи знатоком ассемблера, не зная до сих пор, как использовать большинство возможностей своего дизассемблера(DisDoc 2.3), я все же решился написать эту статью, так как прекрасно помню, в какой кромешной тьме начинал заниматься дизассемблированием.

Тогда, год назад, я попробовал дизассемблировать простенькую программу и был страшно удивлен тем, что дизассемблер делает это неправильно, и при повторном ассеблировании программа не работала так, как надо. Тогда же мне удалось поговорить со знающим человеком и, хотя я чувствовал себя наивным дурачком, мне удалось выяснить главное: ПОЛНОЕ,АВТОМАТИЧЕСКОЕ ДИЗАССЕМБЛИРОВАНИЕ НЕВОЗМОЖНО, над тем текстом, который выдает дизассемблер, нужно довольно долго работать, прежде чем ассемблирование этого текста даст работоспособную программу.

В дальнейшем я постараюсь рассказать о тех приемах, которые превращают "плохой" текст в "хороший" , т.е. в текст, который не только дает корректно работающую программу при ассемблировании, но и позволяет себя изменить, чтобы усовершенствовать исходную программу.

ПОЧЕМУ DisDoc?

SOURSER - это название знают все, кто хотя бы краем уха слышал о дизассеблировании. Считается, что это дизассеблер замечательный, мощный, не имеющий конкурентов. Я думаю, что слухи об огромных преимуществах SOURSERа силь но преувеличены. У меня сложилось такое впечатление, что при дизассемблирова нии небольших программ (до 7 кб.) SOURSER предпочтительнее. Когда программа велика (в моем случае - 58 кб ), SOURSER работает очень медленно и, на мой взгляд, не дает никаких преимуществ.

Выбор дизассемблера DisDoc 2.3 был для меня во многом случаен. Начиная работу, я получил тексты на ассемблере как с помощью SOURSERa (версия 3.07), так и с помощью дизассемблера DisDoc 2.3. Затем оба текста после устранения очевидных ошибок были ассемблированы. И вот, то, что было выдано SOURSERом, повисло сразу, а то, что выдал DisDoc 2.3, прежде чем повиснуть, вывело на экран несколько линий. Это и определило выбор. В процессе работы я не раз имел возможность оценить основное преимущество дизассемблера DisDoc - интуитивно понятный, неизощренный, удобный и компактный листинг.

Чтобы понять дальнейшее, необходимо познакомиться с отрывком из листинга, который выдает DisDoc 2.3

		mov	cx,WORD PTR ds:d02453	;02430 
b02430:		add	cx,bx			;02434 
		mov	bx,99e7h		;02436 
		mov	dx,WORD PTR ds:d02449	;02439 
		mov	al,BYTE PTR ds:d02446	;0243d 
		call	s383 ;<09060>		;02440 
		push	cs			;02443 
		pop	ds			;02444 
		ret				;02445 
 ;----------------------------------------------------- 
 d02446		db	00			;02446 . 
 d02447		db	00,00			;02447 .. 
 d02449		db	00,00			;02449 .. 

В поле комментариев указано смещение, которое имела данная инструкция в исходной программе. Например, если вы в исходной программе, подвергаемой дизассемблированию, посмотрите отладчиком смещение 02434, то там окажется инструкция add cx,bx - на это можно положиться! Очень хороши названия меток и элементов данных. По ним сразу можно понять, какое смещение они имели в исходной программе. Например, метка b02430 имела смещение 02430, элемент данных d02446 имел смещение 02446 и т.д. То же самое относится и к подпрограммам. После вызова подпрограммы в треугольных скобках указано смещение, которое имела эта подпрограмма в исходной программе. Например, подпрограмма s383 начиналась в исходной программе со смещения 09060. Такая организация листинга позволяет сохранить однозначное соответствие с исходной программой, что дает возможность проверить отладчиком сомнительные куски кода и данных, сравнить текст, выданный дизассемблером с тем, что есть на самом деле. Это поистине драгоценная возможность. Нужно сказать, что DisDoc имеет большие недостатки, о которых речь еще пойдет, и, следовательно, применение того или иного дизассемблера - дело вкуса.

В любом случае обязательно встретятся

Фундаментальные проблемы

1. Проблема OFFSETa

Предположим, что в тексте, который выдал дизаccемблер есть такой фрагмент:

	mov	ax,bx			;1 
	shl	ax,1 ;004bc		;2 
	mov	si,8429h		;3 
	add	si,ax			;4 
	push	WORD PTR [si]		;5 

Что засылается в регистр si в третьей строчке - число 8429h или смещение некой метки? На этот вопрос позволяет ответить пятая строчка, из которой видно, что регистр si используется для косвенной адресации. Значит, исправленный фрагмент должен выглядеть следующим образом:

	mov	ax,bx			;1 
	shl	ax,1 ;004bc		;2 
	mov	si,OFFSET d08429 ;3 
	add	si,ax			;4 
	push	WORD PTR [si]		;5 

	................................ 

d08429  db 0ff,0ff,0f6	 ;8429 
	db	0ff,0d8,0ff,0a6,0ff,60	;0842c .....` 

Возможно, здесь у многих возникнет сомнение - нужно ли заменять число на соответствующий OFFSET - ведь, казалось бы, в заново ассемблированной программе данные будут иметь то же смещение? К сожалению, это не так. Во первых, мы,как правило, не знаем, какой ассемблер применялся при транслировании оригинального текста, а коды, полученные с помощью разных ассемблеров будут иметь разную длину, что приведет к изменению смещений. Например, команда AND CX,0007h транслируется MASMом 5.1 и TASMом 1.01 как 83E107 и занимает 3 байтa. Но эта же команда может быть транслирована как 81E10700 и занимать 4 байта. Во-вторых, даже если смещение сохранится, программа не поддастся модификации, так как при вставке какого-либо фрагмента кода изменятся смещения и все "развалится". Итак, OFFSETы позволяют склеить программу, делают ее пригодной для модификации. Разобранный пример достаточно примитивен. Попробуем рассмотреть более сложные ситуации и первым делом исследуем фрагмент текста, выданный дизассемблером:

	mov	bx,9006h		;08f66 
b08f75:		mov	WORD PTR ds:d087d0,bx	;08f75 
	................................. 
	call	WORD PTR cs:d087d0	;08fc3 
	...................................... 
;----------------------------------------------------- 
	push	dx			;09006 
	call	s419 ;<099a3>		;09007 
	mov	al,BYTE PTR [si]	;0900a 
	mov	BYTE PTR [si],0ffh	;0900c 
	pop	dx			;0900f 
	ret				;09010 
;-----------------------------------------------------

Здесь возникает тот-же вопрос - что такое 9006h в первой строчке фрагмента - смещение или просто число? Ответить на этот вопрос помогает информация, помещенная дизассемблером в поле комментариев. Мы уже говорили о том что числа, помещенные в этом поле, представляют собой смещения, которые имела инструкция в исходной программе, подвергаемой дизассемблированию. Нетрудно догадаться, что в приведенном фрагменте осуществляется косвенный вызов подпрограммы, и, следовательно, 9006h - это смещение, а не число. Фрагмент должен быть исправлен так:

	mov	bx,OFFSET d09006 ;08f66 
	...................................... 
;----------------------------------------------------- 
d09006:	push	dx			;09006 
	...................................... 
	ret				;09010 

Рассмотрим еще один пример косвенного вызова подпрограммы, в котором OFFSET попадает в область данных.

  
s390 	proc near 
.......................................................... 
	mov	ax,WORD PTR [bx+8792h]	;092c7 
	mov	WORD PTR ds:d087d2,ax	;092cb 
........................................................... 
	call	WORD PTR cs:d087d2	;093c8 
	ret				;093d4 
;----------------------------------------------------- 
	ror	ah,1 ;093d5		;LO]-->[HI..LO]-->[HI 
	jb	b093da ;093d7		;Jump if < (no sign) 
	ret				;093d9 
b093da:	inc	si			;093da 
	ret				;093db 
............................................................ 

Чтобы выяснить, что представляет собой 8792h, нужно посмотреть в область со смещениями, близкими к этому числу. Приведем соответствующий фрагмент, выданный дизассемблером:

  
 d08790		db	00,00,0d5,93 	;08790 ...... 
 ............................................................. 

Видно, что смещению 08792 соответствует слово 0d5,93. Теперь остается заметить, что со смещения 093d5 в исходной программе начинается фрагмент повисшего кода

  
	ror	ah,1 ;093d5 !!!!!!	;LO]-->[HI..LO]-->[HI 
	jb	b093da ;093d7		;Jump if < (no sign) 
	ret				;093d9 
b093da:	inc	si			;093da 
	ret				;093db 

Следовательно,весь разобранный пример - это хитроумный косвенный вызов подпрограммы. Исправленный фрагмент должен выглядеть так:

 
s390	proc near 
.......................................................... 
	mov	ax,WORD PTR [bx+OFFSET d08792]	;092c7 
	mov	WORD PTR ds:d087d2,ax	;092cb 
........................................................... 
	call	WORD PTR cs:d087d2	;093c8 
	ret				;093d4 
;----------------------------------------------------- 
d093d5:	ror	ah,1 ;093d5		;LO]-->[HI..LO]-->[HI 
	jb	b093da ;093d7		;Jump if < (no sign) 
	ret				;093d9 
b093da:	inc	si			;093da 
	ret				;093db 
............................................................ 
 
d08790	db	00,00 	;08790 ...... 
d08792  dw OFFSET d093d5 ;08792 

Здесь я предвижу большие возражения. Мне скажут, что все это можно интерпретировать иначе, что мои доказательства неубедительны и т.д. С этим я совершенно согласен. Более того, эти доказательства неубедительны и для меня. Гораздо сильнее убеждает то, что программа после ассемблирования работает! Дизассемблирование, как и отладка программ - процесс интуитивный. Опытный человек испытывает особое удовольствие от того, что его немотивированные догадки впоследствии подтверждаются. Как часто мысль, пришедшая в автобусе, во сне, в компании, в самой неподходящей обстановке - оказывается верной! Завершим этот пункт еще одним достаточно хитрым примером. В тексте, который выдал дизассемблер, встретился такой фрагмент:

	mov	bx,4f71h 		;0522b 
b0522e:	pop	ax			;0522e 
	cmp	ax,bx			;0522f 
	jnz	b0522e ;05231		;Jump not equal(ZF=0) 
	mov	BYTE PTR ds:d041f4,00	;05233 
	push	ax			;05238 
	ret				;05239 
	................................. 
	call	s229 ;<04fc4>		;04f71

Возникает все тот же вопрос - что такое 4f71h - число или смещение? Чтобы ответить на этот вопрос, нужно понять, что делает этот участок программы. Давайте попробуем в этом разобраться. Очевидно, из стека выталкивается число, сравнивается с 4f71h и если нет равенства, выталкивается следующее число. Если число равно 4f71h, то оно снова заталкивается в стек и происходит возврат из подпрограммы. Но куда? Ясно, что в то место, смещение которого было в исходной программе равно 4f71h. Как видно из текста, в этом месте стоял вызов подпрограммы s229. Значит, таким странным образом вызывается подпрограмма и 4f71h - это смещение! Исправленный фрагмент должен выглядеть так:

	mov	bx, OFFSET d04f71 ;0522b 
b0522e:	pop	ax			;0522e 
	cmp	ax,bx			;0522f 
	jnz	b0522e ;05231		;Jump not equal(ZF=0) 
	mov	BYTE PTR ds:d041f4,00	;05233 
	push	ax			;05238 
	ret				;05239 
	................................. 
d04f71:		call	s229 ;<04fc4>		;04f71 

2.Как отличить данные от команд?

Любой дизассемблер путает данные и команды. Особенно это относится к .COM программам, где все перемешано. Рассмотрим простой пример:

	pop	cx			;03e56 
	ret				;03e57 
;----------------------------------------------------- 
	add	BYTE PTR [bx+si],al	;03e58 
	add	BYTE PTR [bx+si],al	;03e5a 
m03e5c:	mov	BYTE PTR ds:d05830,01	;03e5c 

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

	add	BYTE PTR [bx+si],al	;03e58
	add	BYTE PTR [bx+si],al	;03e5a

Сверху они ограничены инструкцией возврата из подпрограммы ret, а снизу - меткой m03e5c. Ясно, что эти инструкции могут быть только данными. После переделки приведенный фрагмент должен выглядеть так:

	pop	cx			;03e56 
	ret				;03e57 
;----------------------------------------------------- 
d03e58	dw 0  	;03e58 
d03e5a 	db 0  	;03e5a 
d03e5b  db 0 
m03e5c:	mov	BYTE PTR ds:d05830,01	;03e5c 

Тут возникает еще один вопрос: почему в одном случае стоит dw, а в другом - db? Ответ содержится в тексте, который выдал дизассемблер. Там можно найти такие инструкции:

 	mov	si,WORD PTR ds:d03e58	;03dd0
	mov	bl,BYTE PTR ds:d03e5a	;03dd4,

Откуда следует, что d03e58 рассматривается как слово, а d03e5a - как байт. Рассмотрим чуть более сложный, но, тем не менее, очень характерный пример.

b03f53:	cmp	al,05			;03f53 
	jnz	b03f6b ;03f55		;Jump not equal(ZF=0) 
..................................................... 
	ret				;03f69 
;----------------------------------------------------- 
	add	BYTE PTR [si],bh	;03f6a 
	push	es			;03f6c 
	jnz	b03f79 ;03f6d		;Jump not equal(ZF=0) 

В приведенном фрагменте текста метка b03f6b отсутствует. Между тем эта метка должна "разрубить" пополам инструкцию add BYTE PTR [si],bh , которая начинается в оригинальной программе, подвергаемой дизассемблированию, со смещения 03f6a. Выход здесь может быть только один - смещению 03f6a соответствует байт данных, а инструкция начинается со смещения 03f6b. Исправленный фрагмент должен выглядеть так:

b03f53:	cmp	al,05			;03f53 
	jnz	b03f6b ;03f55		;Jump not equal(ZF=0) 
...................................................... 
	ret				;03f69 
;----------------------------------------------------- 
d03f6a	db 0  	;03f6a 
b03f6b:	cmp al,06h			;03f6b 
	jnz	b03f79 ;03f6d		;Jump not equal(ZF=0) 

Путаница между данными и инструкциями возникает довольно часто. SOURSER способен выдавать целые метры бессмысленных инструкций. DisDoc 2.3 в этом отношении ведет себя лучше.

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 

Особенности и ошибки дизассемблера 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

	mov	ax,0040h		;06257 
;<es = 0040> 
	mov	es,ax			;0625a 
	mov	al,BYTE PTR es:d0046c	;0625c 
	sti	 ;06260			;Turn ON Interrupts 
b06261:	cmp	al,BYTE PTR es:d0046c	;06261 
	jz	b06261 ;06266		;Jump if equal (ZF=1) 
	mov	al,BYTE PTR es:d0046c	;06268 
	dec	cx			;0626c 
	jnz	b06261 ;0626d		;Jump not equal(ZF=0) 
	pop	ax			;0626f 
	out	61h,al ;06270		;060-067:8024 keybrd contrlr 
;<es = 0000> 
	pop	es			;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 equ 00046ch
  • Переписать приведенный на рис.6 фрагмент s321 следующим образом:
	mov	ax,0040h		;06257 
;<es = 0040> 
	mov	es,ax			;0625a 
	mov	al,BYTE PTR es:006ch	;0625c 
	sti	 ;06260			;Turn ON Interrupts 
b06261:	cmp	al,BYTE PTR es:006ch	;06261 
	jz	b06261 ;06266		;Jump if equal (ZF=1) 
	mov	al,BYTE PTR es:006ch	;06268 
	dec	cx			;0626c 
	jnz	b06261 ;0626d		;Jump not equal(ZF=0) 
	pop	ax			;0626f 
	out	61h,al ;06270		;060-067:8024 keybrd contrlr 
;<es = 0000> 
	pop	es			;06272 
	ret				;06273 
s321 	endp 

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

;<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 
	...................................... 
Рис.7

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

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

  • Убрать из начала подпрограммы s32 два псевдооператора equ.
  • Переписать коды на рисунке 7 следующим образом:
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 вполне корректно. Так что будьте бдительны и не дайте себя обмануть.

2. Дурные ошибки.

Иногда поведение дизассемблера трудно объяснить. Например, он выдает

	add	WORD PTR ds:d96be3,07	;038b6 
	shr	WORD PTR ds:d96be3,cl	;038bb ;Divide by 2's вместо 
	add	WORD PTR ds:d06bf3,07	;038b6 
	shr	WORD PTR ds:d06bf3,cl	;038bb ;Divide by 2's , 

теряет или искажает куски данных. К счастью, это происходит очень редко.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
Аноним
Мне нравитсяМне не нравится
24 октября 2005, 03:13:12
Потому что статья написана в каком-то там году, когда еще не было Ida Pro.
Например, ассоциативный дизассеблер ADAxx свободен от всех перечисленных в статье недостатков, к тому же может дизассемблировать модули, обработанные упаковщиками и протекторами.
2.
Аноним
Мне нравитсяМне не нравится
28 июня 2004, 09:30:37
А почему не Ida Pro?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог