Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

articles:ida2asm [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== ida2asm ======
 +<​sub>​{{ida2asm.odt|Original file}}</​sub>​
 +
 +====== секреты ассемблирования дизассемблерных листингов ======
 +
 +крис касперски,​ ака мыщъх, no-email
 +
 +**дизассемблер ****IDA Pro**** (как и любой другой) умеет генерировать ассемблерные листинги,​ однако,​ их непосредственная трансляция невозможна и прежде чем ассемблер проглотит наживку,​ приходится совершить немало телодвижений,​ о самых значимых из которых мыщъх и рассказывает в этой статье**
 +
 +===== введение =====
 +
 +Обычно дизассемблер используется для реконструкции алгоритма подопытной программы,​ который после этого переписывается на Си/Си++ или в двоичном файле правится тот нехороший jx, который не дает приложению работать,​ если не найден ключевой файл или демонстрационный период давно истек.
 +
 +Значительно реже дизассемблированную программу требуется оттранслировать заново. Например,​ хочется исправить множественные ошибки разработчиков,​ нарастить функционал или внести другие изменения… Конечно,​ все это можно сделать непосредственно в двоичном коде, наложив на программу "​заплатку",​ присобаченную с помощью jump'​ов. В большинстве случаев это самый короткий и самый _надежный_ пусть. Нет никаких гарантий,​ что программа дизассемблирована правильно. Существует по меньшей мере три фундаментальные проблемы дизассемблирования:​ а) синтаксическая неразличимость смещений от констант;​ б) неоднозначность соответствия ассемблерных мнемоник машинным командам;​ в) код ошибочно принятый за данные и данные,​ ошибочно принятые за код.
 +
 +Как следствие,​ откомпилированный дизассемблерный листинг в лучшем случае вообще не работает,​ зависая при запуске,​ в худшем же — периодически падать в разных местах. Но до этих проблем нам — как до Луны, а, может, еще и дальше. Для начала необходимо протащить дизассемблерный листинг сквозь ассемблер,​ устранив явные ошибки трансляции,​ а со всем остальным мы разберемся как ни будь потом (быть может, даже в следующей статье).
 +
 +===== первое боевое крещение =====
 +
 +Давайте создадим _простейшую_ консольную программку типа "​hello,​ world!",​ откомпилируем ее, а затем дизассемблируем с помощью IDA Pro и попытаемся ассемблировать полученный листинг.
 +
 +Исходный текст в нашем случае выглядит так:
 +
 +#include <​stdio.h>​
 +
 +main()
 +
 +{
 +
 +printf("​hello,​world!\n"​);​
 +
 +}
 +
 +Листинг 1 исходный текст программы demo_comsole.c
 +
 +Компилируем ее компилятором MicrosoftVisualC++ 6.0 с настойками по умолчанию ("​cl.exe demo_console.c"​) и загружаем полученный exe-файл в IDA Pro 4.7. Естественно,​ можно использовать и другие версии продуктов,​ но тогда результат будет несколько отличаться,​ что, впрочем,​ на ход повествования практически никак не повлияет.
 +
 +{{ida2asm_Image_0.png}}
 +
 +Рисунок 1 успешно дизассемблированный файл
 +
 +Дождавшись завершения дизассемблирования файла (когда экран IDA Pro будет выглядеть приблизительно как показано на рис. 1),​ попросим ее сгенерировать ассемблированный листинг. Порядочные дизассемблеры поддерживают несколько популярных синтаксисов:​ TASM, MASM и, учитывая,​ что IDA Pro недавно была перенесена на Linux, неплохо бы добавить к этому списку еще и AT&T, но… увы! В меню "​Options"​  "​Targetassembler"​ значиться только какой-то загадочный "​GenericforIntel 80x86",​ не совместимый ни MASM'​ом,​ ни с TASM'​ом (во всяком случае не с их последними версиями). В IDA Pro 5.0 в этом отношении сделан огромный шаг вперед и теперь нам предлагают выбор между "​GenericforIntel 80x86" и "​BorlandTASMinIdealmode"​ (см. рис. 2).
 +
 +{{ida2asm_Image_1.png}}
 +
 +Рисунок 2 ассемблеры,​ поддерживаемые IDA Pro 4.7 (слева),​ и IDA Pro 5.0 (справа)
 +
 +Очень своевременное решение,​ особенно в свете того, что TASM давно мертв — не "​переваривает"​ новых инструкций,​ не обновляется,​ не поддерживается и официально не распространяется. Borland уже давно забила на этот проект. И хотя есть несколько некоммерческих TASM-совместимых ассемблеров (см. статью "​обзор ассемблерных трансляторов"​) всех проблем они не решают и дизассемблерные листинги транслируются только после существенной переделки,​ а раз так — лучше остановить свой выбор на пакете MASM, входящим в состав NTDDK.
 +
 +Решено! Выбираем "​GenericforIntel 80x86" и говорим "​File"​  "​Produceoutputfile"​  "​ProduceASMfile"​ или просто нажимаем горячую клавишу <​Alt-F10>​. Даем файлу имя (например,​ "​demo_1.asm"​) и через несколько минут шуршания диском у нас образуется… нечто по имени ничто.
 +
 +Скармливаем эту штуку ассемблеру "​ml.exe /​c demo_1.asm"​ (версия 6.13.8204) для справки. Транслятор выдает свыше сотни ошибок,​ после чего прекращает свою работу,​ не видя никакого смысла ее продолжать (см. рис. 3).
 +
 +
 +
 +{{ida2asm_Image_2.png}}
 +
 +Рисунок 3 результат непосредственной трансляции дизассемблерного листинга
 +
 +Анализ показывает,​ что 90% ошибок связаны с неверным определением типа процессора "​instructionorregisternotacceptedincurrentCPUmode"​. Ах, да! По умолчанию IDA Pro выбирает "​MetaPC (disassembleall 32-bitopcodes)",​ но забывает поместить соответствующую директиву в дизассемблерный листинг,​ а транслятор по умолчанию устанавливает 8086 ЦП, совершенно не совместимый с 32-разрядным режимом.
 +
 +Материмся,​ лезем в начало листинга,​ вставляем директиву "​**.386**",​ после чего повторяет сеанс трансляции заново. И опять куча ошибок (правда,​ на этот раз чуть меньше ста, что не может не радовать). Смотрим,​ что не понравилось транслятору:​ "​demo_1.asm(34):​errorA2008:​syntaxerror:​flat"​. Хм?! Открываем demo_1.asm, переходим к строке 34 и видим: "model flat". А точка где?! Кто ее будет ставить?​ Абель что ли? Возвращаем точку на место, заодно добавляя квалификатор языка Си: "​.model flat,​C"​ и вновь прогоняем программу через транслятор. На этот раз MASM едет крышей настолько,​ что выпадает в soft-ice (если тот был предварительно запущен) или выбрасывает знаменитое сообщение о критической ошибке. ​
 +
 +{{ida2asm_Image_3.png}}
 +
 +Рисунок 4 критическая ошибка при попытке ассемблирования листинга,​ сгенерированного IDA Pro
 +
 +Ладно, положим,​ это ошибка самого транслятора,​ легко обходимая добавлением волшебного ключика "/​coff"​ к командной строке и следующая попытка трансляции проходит уже без ошибок:​ "​ml.exe /​c /​coff demo_1.asm"​. В смысле без _критических_ ошибок самого транслятора,​ а ошибок в листинге по прежнему предостаточно.
 +
 +Большинство из них относится к невозможности определения имен библиотечных функций,​ имен и меток:
 +
 +demo_1.asm(53) : error A2006: undefined symbol : _printf
 +
 +demo_1.asm(64) : error A2006: undefined symbol : __exit
 +
 +demo_1.asm(285) : error A2006: undefined symbol : _fclose
 +
 +demo_1.asm(297) : error A2006: undefined symbol : _free
 +
 +demo_1.asm(453) : error A2006: undefined symbol : off_403450
 +
 +demo_1.asm(490) : error A2006: undefined symbol : off_403450
 +
 +Листинг 2 транслятор не может найти имена библиотечных функций в листинге
 +
 +Черт! Как же мы могли забыть,​ что хитрая IDA Pro коллапсирует библиотечные функции,​ стремясь расчистить листинг от бесполезного мусора,​ не несущего никакой полезной нагрузки. Вернемся к рисунку 1 и сравним его со следующим фрагментом сгенерированного ассемблерного листинга:​
 +
 +; [00000031 BYTES: COLLAPSED FUNCTION _printf. PRESS KEYPAD "​+"​TO EXPAND]
 +
 +; [000000D4 BYTES: COLLAPSED FUNCTION start. PRESS KEYPAD "​+"​TO EXPAND]
 +
 +Листинг 3 сколлапсированные функции остаются сколлапсированными и в ассемблерном листинге!
 +
 +Это же какую ума палату нужно уметь, чтобы допустить такое?​! Интересно,​ тестировался ли ассемблерный генератор вообще или был написан в расчете на авось?​! Матерясь,​ возвращаемся в IDA Pro, в меню "​View"​ выбираем пункт "​Unhideall",​ наблюдая за тем как "​раскрываются"​ библиотечные функции.
 +
 +Генерируем новый ассемблерный файл, на этот раз "​demo_2.asm",​ не забыв вставить в его начало директивы "​.386"​ и "​.model flat,​C"​. Повторяем трансляцию. Просматривая протокол ошибок (ну куда же IDA Pro без ошибок) с удивлением обнаруживаем множественные ругательства на неопределенные символы StartupInfo и CPInfo, представляющие собой легко узнаваемые структуры:​
 +
 +demo_2.asm(2533) : error A2006: undefined symbol : _STARTUPINFOA
 +
 +demo_2.asm(4276) : error A2006: undefined symbol : _cpinfo
 +
 +Листинг 4 реакция транслятора на отсутствие объявления структур
 +
 +Куда же они могли подеваться?​! Открываем ассемблерный листинг в текстовом редакторе и… нет, в русском языке просто не существует подходящих слов, чтобы адекватно выразить наше состояние:​
 +
 +; [00000012 BYTES. COLLAPSED STRUCT _cpinfo. PRESS KEYPAD "​+"​ TO EXPAND]
 +
 +; [00000044 BYTES. COLLAPSED STRUCT _STARTUPINFOA. PRESS KEYPAD"​+"​ TO EXPAND]
 +
 +Листинг 5 сколлапсированные структуры в ассемблерном файле
 +
 +Ассемблерный генератор IDA Pro поместил структуры в целевой файл, даже не удосужившись их автоматически развернуть! Что же, придется это сделать самостоятельно. Возвращаемся в IDA Pro, в меню "​View"​ находим пункт "​Open Subview",​ а там — "​Structures"​ или просто жмем горячую клавишу <​Shift-F9>​. Перед нами появляется окно с перечнем всех структур и для их разворота достаточно дать команду "​View"​  "​Unhide all",​ после чего можно повторить генерацию ассемблерного файла, назвав его "​demo_3.asm"​ (про директивы .386/.model flat мы не забываем,​ да?).
 +
 +Поразительно,​ но количество ошибок трансляции совсем не уменьшается,​ а даже возрастает. И ассемблер по прежнему не может найти "​развернутые"​ структуры. Что же ему мешает?​ Присмотревшись к логу ошибок повнимательнее,​ мы видим, что ругательству на неопределенный символ предшествует ошибка типа "​operandmustbeamemoryexpression"​ (операнд должен быть выражением,​ адресующим память):​
 +
 +demo_3.asm(2561) : error A2027: operand must be a memory expression
 +
 +demo_3.asm(2596) : error A2006: undefined symbol : StartupInfo
 +
 +demo_3.asm(2599) : error A2006: undefined symbol : StartupInfo
 +
 +demo_3.asm(2601) : error A2006: undefined symbol : StartupInfo
 +
 +Листинг 6 транслятор по прежнему не может определить развернутые структуры
 +
 +Открываем ассемблерный файл в редакторе,​ переходим к строке 2561 и видим следующую картину маслом:​
 +
 +__ioinitproc near; CODE XREF: start+6Fp
 +
 +**StartupInfo= _STARTUPINFOAptr -44h**
 +
 +
 +
 +cmp[esp+54h+StartupInfo.cbReserved2],​ 0
 +
 +jzloc_4022E6
 +
 +moveax, [esp+54h+StartupInfo.lpReserved2]
 +
 +Листинг 7 камень преткновения всех структур
 +
 +Мыщъх не уверен на счет "​GenericforIntel 80x86",​ но транслятор MASM, начиная с версии >5.1, такого способа объявлений структур уже не поддерживает,​ и чтобы откомпилировать программу у нас есть по меньшей мере два пути: разрушить все структуры на хрен (все равно в ассемблерном листинге они нам несильно понадобятся),​ либо же использовать ключ командной строки **/Zm**, обеспечивающим обратную совместимость с MASM 5.1. Вот так, наверное,​ мы и поступим:​ "​ml.exe /​c /​coff /​Zmdemo_3.asm"​.
 +
 +Количество ошибок сразу же уменьшается чуть ли не в три раза и они свободно помешаются на экран, что не может не радовать!
 +
 +{{ida2asm_Image_4.png}}
 +
 +Рисунок 5 трансляция ассемблерного листинга в режиме совместимости с MASM 5.1
 +
 +Подавляющее большинство ошибок имеют тип "​missingoperatorinexpression"​ (в выражении отсутствует оператор) и чем скорее мы с ними разберемся,​ тем будет лучше как для нас самих, так и для транслируемой программы.
 +
 +Переходим к строке 141 и видим:
 +
 +******moveax,​ large fs:0**
 +
 +pusheax
 +
 +******movlarge fs:0, esp**
 +
 +Листинг 8 здесь возникает ошибка типа "​отсутствующий оператор"​
 +
 +Ну и зачем ассемблерному генератору было вставлять "​large"?​ Все равно MASM его не понимает и отродясь не понимал. Находясь во интегрированном редакторе FAR'​а,​ нажимаем <​Ctrl-F7>​ (replace) и заменяем все "​largefs"​ на просто "​fs"​ (см. рис. 6)
 +
 +{{ida2asm_Image_5.png}}
 +
 +Рисунок 6 автоматическая замена всех "​largefs"​ на "​fs"​ в FAR'e
 +
 +Теперь после трансляции остается совсем немного ошибок,​ на которые мы продолжим планомерно наступать:​
 +
 +demo_3.asm(70) : error A2015: segment attributes cannot change : Alignment
 +
 +demo_3.asm(8063) : error A2189: invalid combination with segment alignment : 2048
 +
 +demo_3.asm(12004) : error A2015: segment attributes cannot change : Alignment
 +
 +demo_3.asm(13742) : error A2005: symbol redefinition : cchMultiByte
 +
 +demo_3.asm(14176) : error A2005: symbol redefinition : Filename
 +
 +demo_3.asm(14200) : error A2005: symbol redefinition : Locale
 +
 +demo_3.asm(14215) : error A2005: symbol redefinition : CodePage
 +
 +demo_3.asm(142) : error A2206: missing operator in expression
 +
 +demo_3.asm(2860) : error A2206: missing operator in expression
 +
 +demo_3.asm(2888) : error A2206: missing operator in expression
 +
 +demo_3.asm(2924) : error A2006: undefined symbol : loc_402480
 +
 +demo_3.asm(3639) : error A2001: immediate operand not allowed
 +
 +demo_3.asm(4158) : error A2006: undefined symbol : loc_402D11
 +
 +**demo_3.asm(1257) : error A2006: undefined symbol : $NORMAL_STATE$1535**
 +
 +**demo_3.asm(1258) : error A2006: undefined symbol : loc_4012AA**
 +
 +**demo_3.asm(1259) : error A2006: undefined symbol : loc_4012C5**
 +
 +**demo_3.asm(1260) : error A2006: undefined symbol : loc_401311**
 +
 +**demo_3.asm(1261) : error A2006: undefined symbol : loc_401348**
 +
 +**demo_3.asm(1262) : error A2006: undefined symbol : loc_401350**
 +
 +**demo_3.asm(1263) : error A2006: undefined symbol : loc_401385**
 +
 +**demo_3.asm(1264) : error A2006: undefined symbol : loc_401418**
 +
 +Листинг 9 перечень ошибок,​ выявленных ассемблером при очередном сеансе трансляции
 +
 +Беглый взгляд на листинг обнаруживает целый каскад ошибок типа "​undefinedsymbol"​ (неопределенный символ). Так, посмотрим,​ что же у нас не определено на этот раз. Переходим к строке 1257, за которой тянется целый хвост ошибок в строках 1258, 1259, 1260, 1261, 1262, 1263 и 1264. Это настоящее осиное гнездо! Обитель зла, которую мыщъх собирается разбить одним взмахом хвоста:​
 +
 +1257:​off_401956 dd offset $NORMAL_STATE$1535
 +
 +1258:dd offset loc_4012AA
 +
 +1259:dd offset loc_4012C5
 +
 +1260:dd offset loc_401311
 +
 +Листинг 10 очередная обитель зла на подступах к успешной трансляции
 +
 +Хм, выглядит вполне обычно и _все_ метки без исключения обнаруживаются простым контекстным поиском:​
 +
 +$NORMAL_STATE$1535:​movecx,​ dword_406428
 +
 +
 +
 +loc_4012AA:​or[ebp+var_10],​ 0FFFFFFFFh
 +
 +
 +
 +loc_4012C5:​movsxeax,​ bl
 +
 +Листинг 11 "​потерянные метки"​ легко обнаруживаются контекстным поиском
 +
 +Почему же тогда ассемблерный транслятор их ни хрена не видит?​! Все дело в том, что IDA Pro неверно определила границы функции,​ поместив обращения к меткам _за_ границы функции в которой они упоминаются!!! А метки вообще-то локальны. Вот потому-то транслятор их и не находит!
 +
 +$NORMAL_STATE$1535:​
 +
 +
 +
 +loc_4012AA:
 +
 +
 +
 +loc_4012C5:
 +
 +
 +
 +loc_401311:
 +
 +
 +
 +**__outputendp ; ********конец****функции**
 +
 +; ───────────────────────────────────────────────────────────────────────────
 +
 +off_401956dd offset $NORMAL_STATE$1535
 +
 +dd offset loc_4012AA
 +
 +dd offset loc_4012C5
 +
 +dd offset loc_401311
 +
 +Листинг 12 IDA Pro поместила обращения к меткам после конца функции,​ удалив их из границ видимости транслятора
 +
 +Чтобы исправить ситуацию,​ необходимо переместить директиву "​__output endp"​ _за_ конец обращений к меткам. Так, чтобы они стали частью функции __output. После чего ассемблерный код будет выглядеть так:
 +
 +off_401956dd offset $NORMAL_STATE$1535
 +
 +dd offset loc_4012AA
 +
 +dd offset loc_4012C5
 +
 +__outputendp
 +
 +Листинг 13 исправленный вариант,​ позволяющий транслятору обнаружить "​недостающие метки"​
 +
 +После ассемблирования количество ошибок тает буквально на глазах и мы даже в порыве вдохновения едва удерживаемся от того, чтобы не закурить новый косяк:
 +
 +demo_3.asm(70) : error A2015: segment attributes cannot change : Alignment
 +
 +demo_3.asm(8064) : error A2189: invalid combination with segment alignment : 2048
 +
 +demo_3.asm(12005) : error A2015: segment attributes cannot change : Alignment
 +
 +demo_3.asm(13743) : error A2005: symbol redefinition : cchMultiByte
 +
 +demo_3.asm(14177) : error A2005: symbol redefinition : Filename
 +
 +demo_3.asm(14201) : error A2005: symbol redefinition : Locale
 +
 +demo_3.asm(14216) : error A2005: symbol redefinition : CodePage
 +
 +**demo_3.asm(2861) : error A2206: missing operator in expression**
 +
 +**demo_3.asm(2889) : error A2206: missing operator in expression**
 +
 +**demo_3.asm(2925) : error A2006: undefined symbol : loc_402480**
 +
 +demo_3.asm(3640) : error A2001: immediate operand not allowed
 +
 +**demo_3.asm(4159) : error A2006: undefined symbol : loc_402D11**
 +
 +Листинг 14 список ошибок,​ обнаруженных ассемблером после очередного сеанса трансляции (все ближе, ближе долгожданный миг победы!)
 +
 +В глаза бросается пара уже известных нам ошибок типа "​undefinedsymbol",​ первую из которых исправить достаточно легко:
 +
 +__NLG_Notify1:​
 +
 +pushebx
 +
 +pushecx
 +
 +movebx, offset unk_406364
 +
 +jmpshort **loc_402480**
 +
 +; ███████████████ S U B R O U T I N E ███████████████████████████████████████
 +
 +__NLG_Notifyproc near
 +
 +pushebx
 +
 +pushecx
 +
 +movebx, offset unk_406364
 +
 +movecx, [ebp+8]
 +
 +**loc_402480**:​
 +
 +mov[ebx+8], ecx
 +
 +mov[ebx+4], eax
 +
 +mov[ebx+0Ch],​ ebp
 +
 +__NLG_Dispatch:​
 +
 +popecx
 +
 +popebx
 +
 +retn4
 +
 +__NLG_Notifyendp
 +
 +Листинг 15 оригинальный код, сгенерированный IDA Pro, который не хочет транслироваться
 +
 +Достаточно "​завести"​ подпрограмму __NLG_Notify1 под "​retn 4"​ процедуры __NLG_Notyfy,​ но перед директивой __NLG_Notify endp,​ тогда она метка будет распознаваться как надо!
 +
 +__NLG_Notifyproc near
 +
 +pushebx
 +
 +pushecx
 +
 +movebx, offset unk_406364
 +
 +movecx, [ebp+8]
 +
 +**loc_402480**:​
 +
 +mov[ebx+8], ecx
 +
 +mov[ebx+4], eax
 +
 +mov[ebx+0Ch],​ ebp
 +
 +__NLG_Dispatch:​
 +
 +popecx
 +
 +popebx
 +
 +retn4
 +
 +**__NLG_Notify1:​**
 +
 +**pushebx**
 +
 +**pushecx**
 +
 +**movebx, offset unk_406364**
 +
 +**jmpshort loc_402480**
 +
 +__NLG_Notifyendp
 +
 +Листинг 16 исправленный вариант
 +
 +А вот со следующей ошибкой справиться уже сложение,​ поскольку функция strcpy совершает прыжок в середину функции strcat:
 +
 +**_strcpyproc near**
 +
 +arg_0= dword ptr 8
 +
 +pushedi
 +
 +movedi, [esp+arg_0]
 +
 +jmp**loc_402D11**
 +
 +**_strcpyendp**
 +
 +**_strcatproc near**
 +
 +arg_0= dword ptr 4
 +
 +arg_4= dword ptr 8
 +
 +movecx, [esp+arg_0]
 +
 +
 +
 +**loc_402D11:​**
 +
 +movecx, [esp+4+arg_4]
 +
 +testecx, 3
 +
 +jzloc_402D36
 +
 +
 +
 +retn
 +
 +_strcatendp
 +
 +Листинг 17 IDA Pro сгенерировала неработоспособный листинг для парной функции strcpy/​strcat
 +
 +Никаким ухищрениями у нас не получится перетасовать код так, чтобы метка loc_402D11 оказалась в границах видимости,​ но… ведь как то же это было запрограммировано?​! Обратившись к исходным текстам библиотеки LIBC.LIB (они поставляются вместе с компилятором) мы обнаружим волшебный ключик. Чтобы метка была видна отовсюду,​ после нее должен стоят не один знак ":",​ а целых два — "::"​.
 +
 +Самая трудная задача осталась позади и теперь нам предстоит разобраться с уже встречавшимися ошибками типа "​missingoperatorinexpression"​. На этот раз транслятору не понравились конструкции "​push large dword ptr fs:​0"​ и "​pop large dword ptr fs:​0"​. Убираем все лишнее,​ превращая их в "​push fs:​0"​ и "​pop fs:​0"​ и движемся дальше,​ где нас ждет ошибка "​immediateoperandnotallowed"​ (непосредственный операнд недозволен),​ затаившаяся в 3640 строке:​ "​cmp Locale,​0"​. Естественно,​ транслятор решил трактовать Locale как смещение,​ а не как содержимое ячейки,​ поэтому без явной расстановки квадратных скобок здесь не обойтись:​ "​cmp dword ptr ds:​[Locale],​0"​.
 +
 +Теперь на линии фронта остается лишь большой конгломерат ошибок типа "​symbolredefinition"​ (символ переопределен),​ против которых не пропрешь,​ ведь он действительно переопределен,​ вот например,​ взять тот же cchMultiByte:​
 +
 +___crtLCMapStringA procnear; CODE XREF: _setSBUpLow+BEp
 +
 +; _setSBUpLow+E6p
 +
 +Locale= dwordptr ​ 8
 +
 +lpMultiByteStr= dwordptr ​ 10h
 +
 +cchMultiByte= dwordptr ​ 14h
 +
 +
 +
 +___crtLCMapStringA endp
 +
 +
 +
 +cchMultiBytedd 1; DATA XREF: _wctomb+31r
 +
 +Листинг 18 дважды определенный символ Locale
 +
 +Ничего не остается как "​расщеплять"​ переменные вручную,​ давая им различные имена. Главное — не перепутать переменные местами. Впрочем,​ перепутать будет довольно трудно,​ поскольку,​ одна копия переменной — локальная и адресуется через стек, а другая — глобальная и обращение с ней происходит через непосредственную адресацию.
 +
 +Разобравшись с астральными переменными,​ нам остается только побороть три ошибки,​ связанные с выравниванием. Ну, ошибку в строке 8064 мы ликвидируем путем удаления директивы "​align 800h"​ (800h в десятичном представлении как раз и будет 2048). Две остальные ошибки требуют переименования сегментов _text и _data во что-нибудь другое,​ например,​ _text1 и _data1, только это переименование должно иди по всему тексту.
 +
 +Все! Теперь ассемблерный листинг,​ сгенерированный дизассемблером,​ и "​слегка"​ исправленный напильником,​ транслируется без ошибок! Добавим к командой строке MASM'​а ключ "/​Cp",​ чтобы он соблюдал регистр публичных имен и….
 +
 +===== заключение =====
 +
 +…и вот тут-то выясняется,​ что полученный obj наотрез отказывается линковаться,​ потому что линкер не может найти API-функции! Это не покажется удивительным,​ если вспоминать,​ что IDA Pro объявила их в "​удобочитаемом"​ виде, который совсем не совпадет с тем, как они объявлены в библиотеках. Но линковка (и последующая доводка программы до ума) — это уже тема совсем другого разговора,​ а, может быть, и целой статьи.
 +
 +