Трудовая дисциплина Крис Касперски aka мыщъх Хакер, номер #088, стр. 088-114-3 32-режим характеризуется регистрами EAX/EBX/ECX. Это может быть как программа для Windows, так и для DOS/DPMI. Windows распознается по своим API-функциям, DOS/DPMI – по прерыванию INT 31h. Прерывание INT 2Fh свидетельствует о принадлежности к 9x, INT 2Fh/SYSENETR - о принадлежности к NT/XP. Через эти прерывания осуществляется доступ к низкоуровневому API операционной системы, что делает такие программы непереносимыми. Привилегированные инструкции защищенного режима или вызовы функций, экспортируемых ядром, например IoGetCurrentIrpStackLocation, говорят о том, что код - драйвер (или его фрагмент), совершенно не приспособленный к работе на прикладном режиме. Если листинг не вызывает никаких API-функций, не дергает прерываниями, не содержит привилегированных инструкций и не обращается к памяти по абсолютным адресам (типа mov eax,fs:[20h]), то он может работать в любой 32-разрядной операционной системе. 64-режим x86-64 распознается по регистрам RAX/RDX/RCX и с 32-разрядными трансляторами, естественно, не совместим. *nix-системы распознаются своим характерным AT&T синтаксисом. Программы, опирающиеся на библиотеку libc, легко переносятся в Windows, поскольку libc - это стандартная Си-библиотека, однако некоторые никсовые функции в ее Windows-версии не реализованы. В частности, отсутствует вызов fork, расщепляющий процесс на два. В общем, в ряде случаев перенос все-таки возможен. Особенно это относится к математическим функциями, абстрагированным от системного мира. Программы, работающие в обход libc через интерфейс INT 80h/call 0007h:00000000h (всякие вирусы и черви), практически непереносимы. Определить транслятор несколько сложнее. Признаком TASM'а являются директивы "jumps", "locals" в начале файла. FASM обычно определяется по директиве "format", например "format PE GUI 4.0", что, впрочем, не совсем надежно, и хроническому отсутствию ключевого слова offset. На долю MASM'а приходится все остальное. [метод ассемблерных вставок] В качестве боевого примера рассмотрим классический антиотладочный код, встречающийся во многих статьях и книгах: push offset my_she ; назначаем свой обработчик структурных исключений push dword ptr fs:[0] ; сохраняем старый обработчик в цепочке mov fs:[0],esp ; регистрируем новый обработчик pushf ; толкаем в стек флаги or dword ptr[esp],100h ; взводим трассировочный бит popf ; выталкиваем обновленный бит в регистр флагов, ; заставляя ЦП возбуждать исключение на каждой команде xor eax,eax ; без отладчика после xor возбуждается исключение и ; управление получает my_seh, а в eax будет не нуль ; под отладчиком исключение молчаливо "съедается" my_seh: test eax,eax ; если отладчика нет, то eax != 0 jnz debugger_is_present Как нам его откомпилировать? И главное - во что? На самостоятельную программу оно как-то не тянет... А давай попробуем заточить код под ассемблерную вставку. В большинстве Си компиляторов она оформляется как: "__asm{…ассемблерный код…}", однако непосредственно осуществить этот замысел не получится! Ведь наш ассемблерный листинг, как и большинство других демонстрационных программ, содранных с наглядно-агитационных пособий, представляет собой нечто промежуточное между псевдокодом и рабочей программой. |