Роем вглубь
Берем файл MSHTML.DLL (он находится в каталоге WINNT\System32) и загружаем его в IDA Pro или другой дизассемблер (но лучше, чем IDA Pro вы все равно ничего не найдете). Michal Zalewski в своем сообщении жаловался на отсутствие исходных текстов, серьезно затрудняющих анализ. Что ж, исходных текстов IE в нашем распоряжении действительно нет, но отладочные символы получить можно. В них содержатся имена всех неэкспортируемых функций и объявления объектов и структур.
Рисунок 7 основное окно дизассемблера IDA Pro 5.0 по умолчанию. ну и как с ним работать?! переход в нормальный режим осуществляется нажатием на пробел
IDA Pro 5.0 (см. рис. 7) автоматически сгружает отладочные символы всех системных файлов с msdl.microsoft.com, стоит только сказать: file à load file à PDB file. В более древних версиях это приходится делать вручную. Для начала нам потребуется пакет "Debugging Tools for Windows", бесплатно распространяемый Microsoft: www.microsoft.com/whdc/devtools/debugging/. Скачиваем версию для "своей" операционной системы, устанавливаем, заходим в каталог /bin, находим там утилиту symchk.exe и запускаем ее на следующий манер:
set src=C:\WINNT\SYSTEM32\MSHTML.DLL
symchk %src% /s srv*.\*http://msdl.microsoft.com/download/symbols -v
Листинг 7 ручная загрузка символьной информации
Программа лезет в сеть, возбужденно подмигивая огоньками модема, и вскоре (или не вскоре — это уж от вашего канала зависит!) на диске образуются два новых каталога: .\mshtml.dbg\38D12257243000 с файлом mshtml.dbg и .\mshtml.pdb\38051D9A2 c mshtml.pdb c размерами 2.8 Мбайт и 2.1 Мбайт соответственно. На самом деле, файлы передаются в сжатом виде, поэтому реально скачивается всего ~1,5 Мбайта. Ну, dbg-файл нам совершенно неинтересен (там содержатся адреса машинных команд, соответствующие номерам строк исходных текстов, которых у нас все равно нет), а вот pdb мы сейчас и загрузим в IDA Pro вместе со всей символьной информацией, которой решила поделиться с нами Microsoft.
Перед этим рекомендуется скопировать динамическую библиотеку dbghelp.dll из Debugging Tools в коревой каталог IDA Pro, иначе плагин pdb.plw может не сработать.
Но прежде, чем загружать символы, перейдем на место сбоя и посмотрим как выглядит оригинальный дизассемблерный текст. Нажимаем <G> (goto) и вводим адрес "75ACC4DA", сообщенный Др. Ватсоном. Мы оказываемся в уже знакомой нам процедуре (см. листинг 8), вызывающей безымянную функцию 75A9211Dh о назначении которой пока можно только гадать:
.text:75ACC4C0 sub_75ACC4C0 proc near ; CODE XREF: sub_75AB7EE6+1E2p
.text:75ACC4C0 ; sub_75AC4C20+2Ep ...
.text:75ACC4C0 push esi
.text:75ACC4C1 mov esi, ecx
.text:75ACC4C3 call sub_75A9211D
.text:75ACC4C8 mov si, [esi+6Ch]
.text:75ACC4CC test si, si
.text:75ACC4CF jz short loc_75ACC4E9
.text:75ACC4D1 movzx ecx, si
.text:75ACC4D4 imul ecx, 98h
.text:75ACC4DA mov eax, [eax+420h] ; ß место сбоя
.text:75ACC4E0 pop esi
.text:75ACC4E1 lea eax, [ecx+eax-98h]
.text:75ACC4E8 retn
.text:75ACC4E9 ; -------------------------------------------------------------------
.text:75ACC4E9
.text:75ACC4E9 loc_75ACC4E9: ; CODE XREF: sub_75ACC4C0+Fj
.text:75ACC4E9 mov eax, offset unk_75C8D1A0
.text:75ACC4EE pop esi
.text:75ACC4EF retn
.text:75ACC4EF sub_75ACC4C0 endp
.text:75ACC4EF
Листинг 8 дизассемблерный текст до загрузки символьной информации
После загрузки символьной информации (file à load file à PDB file) листинг радикально преображается (см. листинг 9) и мы получаем вполне осмысленные имена:
; struct INSTANTCLASSINFO * __thiscall COleSite::GetInstantClassInfo(void)
.text:75ACC4C0 ?GetInstantClassInfo@COleSite@@QAEPAUINSTANTCLASSINFO@@XZ
proc near
.text:75ACC4C0 push esi
.text:75ACC4C1 mov esi, ecx
.text:75ACC4C3 call ?GetDocPtr@CElement@@QBEPVCDoc@@XZ;CElement::GetDocPtr()
.text:75ACC4C8 mov si, [esi+6Ch]
.text:75ACC4CC test si, si
.text:75ACC4CF jz short loc_75ACC4E9
.text:75ACC4D1 movzx ecx, si
.text:75ACC4D4 imul ecx, 98h
.text:75ACC4DA mov eax, [eax+420h] ; ß место сбоя
.text:75ACC4E0 pop esi
.text:75ACC4E1 lea eax, [ecx+eax-98h]
.text:75ACC4E8 retn
.text:75ACC4E9 ; --------------------------------------------------------------------
.text:75ACC4E9
.text:75ACC4E9 loc_75ACC4E9:
.text:75ACC4E9 mov eax, offset ?g_ciNull@@3UCLASSINFO@@A;CLASSINFO g_ciNull
.text:75ACC4EE pop esi
.text:75ACC4EF retn
.text:75ACC4EF ?GetInstantClassInfo@COleSite@@QAEPAUINSTANTCLASSINFO@@XZ
endp
Листинг 9 тот же дизассемблерный текст после загрузки символьной информации
Теперь мы знаем, что сбой произошел в функции COleSite::GetInstantClassInfo(void), возвращающей указатель на структуру INSTANTCLASSINFO. К сожалению, описаний структур в pdb-файле нет (коварство Microsoft не знает границ!), но даже неполная символьная информация _намного_ лучше, чем совсем никакой!
Немного побурчав для приличия, займемся дизассемблированием функции CElement::GetDocPtr(void), возвратившей в регистре EAX ноль, и посмотрим кто ей сорвал крышу и почему (см. листинг 10):
.text:75A9211D ?GetDocPtr@CElement@@QBEPAVCDoc@@XZ proc near; CElement::GetDocPtr()
.text:75A9211D mov eax, [ecx+10h]
.text:75A92120 mov ecx, [ecx+1Ch]
.text:75A92123 test cl, 2
.text:75A92126 jz short loc_75A9212B
.text:75A92128 mov eax, [eax+0Ch]
.text:75A9212B
.text:75A9212B loc_75A9212B:
.text:75A9212B test cl, 1
.text:75A9212E jz short locret_75A92133
.text:75A92130 mov eax, [eax+2Ch]
.text:75A92133
.text:75A92133 locret_75A92133:
.text:75A92133 retn
.text:75A92133 ?GetDocPtr@CElement@@QBEPAVCDoc@@XZ endp
Листинг 10 дизассемблерный текст функции CElement::GetDocPtr(void)
Функция проста как провинциальная девушка, приехавшая покорять Москву. Используя регистр ECX, как указатель на объект, она извлекает из него еще один указатель, грузит его в EAX, а затем, используя полученный EAX как указатель, возвращает в том же самом EAX указатель на объект, который она должна возвратить, но в нашем случае возвращается ноль, что указывает на разрушение сложной иерархии структур данных.
Дизассемблер не позволяет сказать на каком этапе произошло разрушение. Может быть разрушен как базовый блок, на который указывает ECX, так и блок, расположенный по адресу *(ECX+10h). А, быть может, разрушение произошло еще раньше, но программа рухнула только сейчас. Чтобы не гадать на кофейной гуще, воспользуемся just-in-time отладчиком, в роли которого выступит популярный OllyDbg (http://www.ollydbg.de/).