FAQ от FORUM WASM.RU

Тема в разделе "WASM.SITE", создана пользователем n0p, 5 авг 2005.

Статус темы:
Закрыта.
  1. n0p

    n0p 10010000b

    Публикаций:
    0
    Регистрация:
    7 май 2003
    Сообщения:
    256
    Адрес:
    Новосиbeerск
    FAQ от FORUM WASM.RU

    При составлении FAQ были использованы ответы участников форума.
    06.01.2010: спустя 5 лет добавлены комментарии, описывающие текущее положение дел

    Q: Какой компилятор выбрать, если я хочу начать программировать на ассемблере? Где их можно взять?

    A: В настоящее время наибольшую популярность имеет пакет MASM32. За ним идет молодой, но быстро развивающийся пакет FASM (скачать их можно из раздела "Компиляторы" на сайте WASM.RU). Для любителей ретро, подойдет старенький пакет TASM. А вот какой же из них выбрать - это решать вам!

    Сейчас (2010г.) FASM уже не такой уж и молодой и уже достаточно популярный. Умеет многое из того, что умеет MASM, + кучу своих фич (самое главное достоинство - макроязык). Рекомендуется, но не так прост в изучении.

    Q: С какой книги можно начать изучение ассемблера?

    A: Да с любой. Но в настоящее время наиболее популярными являются:

    С. В. Зубков "Assembler. Для DOS, Windows и Unix", изд. ДМК. - Книга популярна среди начинающих, но не дает фундаментального понимания языка и его особенностей.

    В. Юров "Assembler" - Учебник, изд. Питер, 2000 - Также популярна и также не очень хороша. Автор использует не совсем стандартную терминологию, примеры содержат ошибки, способные поставить новичка в тупик.

    В. Юров "Assembler" - Специальный справочник, изд. Питер, 2000 - Справочник. Изучить по нему ассемблер нельзя, можно подучить синтаксис основных команд и другие базовые моменты, но для этого надо уже понимать язык и уметь на нем писать хоть что-то.

    Абель "Ассемблер и программирование для IBM PC" - Хорошая, большая книжка. Старое издание изобилует ошибками, насчет более поздних переизданий ничего неизвестно.

    Вышеперечисленные книги рассматривают непосредственно язык ассемблера, но все они ориентированы на мертвый ныне DOS. Тем не менее, в Windows язык не изменился, а потому для базового знакомства с языком эти книги подойдут. Для основательного изучения потребуется более серьезная литература, которую на русском языке найти будет практически невозможно. Кроме того, для программирования под Windows будет не лишним прочитать туториалы Ichzelion'а (есть перевод by Aquila).


    Q: Как скомпилировать исходный текст программы в com, exe или dll?

    A: Итак, все по порядку:

    КОМПИЛЯЦИЯ В COM(MS DOS)

    TASM:
    tasm /m /ml /q /zn file_name.asm
    tlink /x /t file_name.obj

    MASM:
    ml /c file_name.asm
    link file_name.obj,,NUL,,,
    exe2bin file_name.exe file_name.com

    КОМПИЛЯЦИЯ В EXE(MS DOS)

    TASM:
    tasm /m /ml /q /zn file_name.asm
    tlink /x file_name.obj

    MASM:
    ml /c file_name.asm
    link file_name.obj

    отметим, что для сборки 16-битных программ MASM'ом нужен линкер соответствующей версии, который можно взять здесь или здесь. Более подробно тут.

    КОМПИЛЯЦИЯ В EXE(MS WINDOWS)

    TASM:
    (с файлом ресурса)
    tasm32.exe /ml /m /q /zn /kh32000 file_name.asm
    brcc32.exe file_name.rc
    tlink32.exe /Tpe /aa /c /x file_name.obj,,,,,file_name.res
    (без файла ресурсов)
    tasm32.exe /ml /m /q /zn /kh32000 file_name.asm
    tlink32.exe /Tpe /aa /c /x file_name.obj

    MASM:

    (с файлом ресурса)
    ml /c /coff "file_name.asm"
    rc file_name.rc
    Link /SUBSYSTEM:WINDOWS "file_name.obj" file_name.res
    (без файла ресурсов)
    ml /c /coff "file_name.asm"
    Link /SUBSYSTEM:WINDOWS "file_name.obj"

    КОМПИЛЯЦИЯ В EXE(MS WINDOWS(КОНСОЛЬ))

    TASM:
    tasm32.exe /ml /m /q /zn /kh32000 file_name.asm
    tlink32.exe /Tpe /ap /c /x file_name.obj

    MASM:
    ml /c /coff "file_name.asm"
    Link /SUBSYSTEM:CONSOLE "file_name.obj"

    КОМПИЛЯЦИЯ В DLL(MS WINDOWS)

    TASM:
    tasm32.exe /ml /m /q /zn /kh32000 file_name.asm
    implib file_name.lib file_name.dll
    tlink32 /Tpd /aa /z /c file_name.dll

    MASM:
    ml /c /coff file_name.asm
    Link /SUBSYSTEM:WINDOWS /DLL /DEF:file_name.def file_name.obj

    КОМПИЛЯЦИЯ В LIB(MS WINDOWS)

    MASM:
    ml /c /coff file_name.asm
    Lib file_name.obj

    В FASM компиляция предельна проста: FASM.EXE file_name.asm и дальше компилятор сам разберется что делать и как. Или же Ctrl-F9 в редакторе FASMW (входит в пакет).

    Q: Какой редактор лучше всего подходит для написания листингов программ на ассемблере?

    A: О, это риторический вопрос, и камень приткновения для многих программистов на ассемблере. Здесь нельзя ответить однозначно. Каждый решает этот вопрос по своему. Кто-то пользуется RadAsm'ом, кто-то AsmEd by AV(t)LAB, кому-то нравиться встроенный редактор Дос Навигатора. Попробуйте несколько наиболее приглянувшихся и выберите свое любимое IDE. Также прочитайте вот эту статью, может быть, она ответит на Ваш вопрос.


    Q: Каким отладчиком пользоваться при отладке своих и исследовании чужих программ?

    A: Самый лучший отладчик для операционной системы Windows это, конечно же, SoftIce (сейчас Driver Studio). Самый дЗенный инструмент, после Вашего любимого компилятора. Основная особенность - это возможность поставить бряк на любое событие в системе. Существует, так же, отладчик Win32 приложений под названием OllyDbg. Маленький, быстрый, удобный отладчик, а главное - бесплатный (SoftIce денег стоит, причем немалых). В наборе со своими плагинами может имитировать функции Soft Ice, такие как: бряк на функцию по ее имени и многое другое. Очень хороший инструмент!

    Увы, сейчас SI уже мертв - работает далеко не на всех машинах, что объясняется его несовместимостью с современными видеокартами и отсутствием поддержки (разработчики на него забили), а так же отсутствием поддержки под новые Windows и вообще отсутствием поддержки:dntknw:
    Популярность набирает отладчик Syser, который, впрочем, все еще сыроват и лично у меня не запустился, но у других работает.
    Так же хорошим, годным является WinDbg (как для ядра, так и для юзермода), но он совсем не прост в изучении.



    Q: Каким инструментом можно воспользоваться для того, чтобы посмотреть какие API функции использует то или иное приложение? Какие есть ресурсы (иконки, диалоги и пр.)?

    A: Существует множество приблуд позволяющих просматривать внуренности исплняемого файла. Это редакторы ресурсов. Я не возьмусь перечислять их все и определять кто из низ лучше делает свою работу. Лично мне нравиться инструмент под названием EXeScope. Его, а так же еще много других инструментов вы сможете найти на WASM.RU в разделе "Редакторы ресурсов".


    Q: Какой софт можно использывать для pедактиpования файлов в HEX-виде?

    A: Лучше всего подойдет HIEW by SEN (кстати, любимый инструмент нашего многоуважаемого критика молодых и неопытных посетителей форума WASM.RU - Володи), QView by Alexander Gazko, WinHex. Но существуют и дpугие pедактоpы.


    Q: Где можно взять справочник по API функциям?

    A: Если у Вас быстрый Интернет, то здесь есть почти всё, что надо: Microsoft MSDN Library

    Если поставить один из продуктов Borland (С++ Builder, Delphi), то с ним идет неплохой хэлп, написанный по MSDN-у. Файл находится: C:\Program Files\Common Files\Borland Shared\MSHelp\win32.hlp. Найти в гугле

    MSDN также можно купить на дисках, если Вы сможете найти его в Вашем городе.
    Сейчас можно заказывать MSDN бесплатно вместе с VS 2005 Beta.


    Q: Можно ли писать на ассемблере в одну строчку?

    A: Возникает встречный вопрос: "Зачем?". Но если Вам это необходимо, то можно воспользоваться способом описанным на когда-то существовавшем сайте "Assembler.ru". Нам потребуется написать макрос примерно следущего содержания:
    Код (Text):
    1.      @ macro p0,p1,p2,p3,...,pX
    2.         p0
    3.         p1
    4.         p2
    5.         p3
    6.         ...
    7.         ...
    8.         pX
    9.        endm
    Теперь используя макрос "@" мы можем записывать команды в строчку:
    @,,,...,


    Q: Как вызвать API функцию из программы на ассемблере?

    A: При вызове Win32 API функций используется STDCALL-конвенция. В ней параметры помещаются в стек в обратном порядке, а аргумент ы удаляет сама апи-функция. Для некоторых апи (wsprintf, DbgPrint) используется CDECL.

    Пример:

    на С:
    some_proc(a,b,c,d,e)

    на Ассемблере:
    (TASM32, MASM32, FASM)
    push e
    push d
    push c
    push b
    push a
    call some_proc

    либо
    call some_proc,a,b,c,d,e (TASM32)
    invoke some_proc,a,b,c,d,e (MASM32 & FASM)
    cinvoke wsprintf, buffer, format, a, b (FASM: cdecl invoke)


    Q: Что такое Stub программа?

    A: ""Stub" в переводе с английского - "пень, обломок, огрызок".

    Это в литературном переводе. В нелитературный перевод углубляться не будем. Скажем только, что это то самое, что показывает компьютер человеку, попытавшемуся запустить из-под DOS приложение, написанное для Windows. Обычно он показывает сообщение: "This program cannot be run in DOS mode". А вы что подумали?"


    Это вступление статьи "минимальная stub-программа", которую вы можете найти в OffLine версии сайта Assebmler.ru.


    Q: Где взять документацию по процессорам ?

    A: На сайте производителя.

    Процессоры Intel
    Процессоры AMD
    (Раньше можно было заказать бумажные Intel Manuals: http://www.wasm.ru/forum/viewtopic.php?id=27626)

    Offline версия форума: Документы WASM.RU
     
  2. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Q: Я получаю сообщение unresolved external symbol... Что делать?

    A:



    Читать документацию :)

    А если серьезно, то многие новички недостаточно четко представляют себе процесс создания исполняемого файла. Предельно упрощая, он происходит в две стадии:


    Код (Text):
    1. .asm -> .obj -> .exe/.dll




    Из ассемблерного (сишного) файла путем КОМПИЛЯЦИИ получаем объектный файл (при этом могут использоваться дополнительные файлы, такие как *.inc в ассемблере или *.h/*.hpp в С/С++). Если компилятор по какой-либо причине (неверно прописан путь к такому файлу или файл отсутствует) не может найти инклуд-файл, то выдается предупреждение и obj-файл получен не будет.



    На следующей стадии (.obj -> .exe) инклуд-файлы уже не причем. Эта стадия называется ЛИНКОВКОЙ и служит для замещения символьных имен, используемых программистом на реальные адреса (процесс сложнее, но замнем для ясности). Точно так же как и на стадии КОМПИЛЯЦИИ необходимо соблюдение двух условий:

    1) Линкер должен знать какие файлы требуются для того, чтобы получить exe из данного obj (это могут быть либо

    obj-файлы, либо lib-файлы, которые, по сути, содержат внутри себя множество obj-файлов)

    2) Линкер должен знать путь к этим файлам.



    Ошибка при неудовлетворении №2 узнается и устраняется очень просто.

    Ошибка при №1 порождает печальное "unresolved external symbol" и устраняется сложнее.

    Во-первых, вы должны знать какие obj/lib-файлы дополнительно требуются в вашем конкретном случае. Это самая распространенная ошибка. Когда такие файлы найдены, пропишите путь к ним в командной строке линкера и укажите сами файлы. Например:


    Код (Text):
    1. link /LIBPATH:"..\slri\visualbind\asnlib\bindlib\Debug" xncbi.lib xserial.lib
    2. bindlib.lib objects_biblio.lib objects_medline.lib objects_pub.lib objects_seq.lib
    3. objects_mmdb.lib objects_gbseq.lib xutil.lib xobjmgr.lib




    Как видим, в данном случае линкеру дано указание использовать xncbi.lib, xserial.lib и т.д., а искать их он будет в ..\slri\visualbind\asnlib\bindlib\Debug.



    Разумеется, эта ошибка - одна из самых простых. Иногда могут проявлятся куда более коварные случаи. Примером может служить т.н. замангление имен в С++ и использование

    С++-библиотек в С-программах и т.п.



    Еще парочку любопытных примеров можно найти тут:



    http://www.rsdn.ru/article/cpp/crt.xml



    Q : Ну хорошо, а что делать если я как раз столкнулся с замангленым именем? Как линковать тогда?

    A:



    Перед тем как объяснять, что делать, рассмотрим сначала, что такое замангление. Как известно, ЯВУ типа С++ позволяют ПЕРЕГРУЖАТЬ функции и операторы. Т.е. две функции (или больше) могут иметь одинаковые имена. Как в этом случае прикажете выкручиваться компилятору? А компилятор выкручивается тем, что на основе некоторого

    алгоритма уникально искажает имя функции, так, чтобы избежать коллизии.



    Алгоритм искажения имен у каждого компилятора разный. Алгоритм MS cl.exe может быть реверсирован, исследовав функцию __unDNameEx из msvcrt.dll.



    Теперь рассмотрим, что делать. Здесь возможно много вариантов. Рассмотрим два.



    Вариант первый: автор, написавший программу на С++, знал, что ее будут использовать из других языков, например, из С или ассемблера. В этом случае надо специально готовить исходный код. Например так, как это сделано в ImpRecLite - см. исходники. Весь внутренний код написан на С++, а "наружу" смотрят С-шные обертки вокруг С++-методов классов. Более подробно о самой методике написано в MSDN:

    "Export C++ Functions for Use in C-Language Executables".



    Пример:


    Код (Text):
    1. extern "C" __declspec(dllexport ) int MyFunc(long parm1);
    2.  




    В этом случае компилятор НЕ БУДЕТ манглить имя функции (т.е. добавлять всякие загогулины, соответствующие типу и кол-ву параметров и т.п.), однако, учтите, что таким образом объявленные функции нельзя будет и перегрузить.



    Вместо подобных объявлений прямо в исходном коде программы, можно использовать .def-файл. Подробнее о .def-файлах можно глянуть в MSDN.



    Вариант второй: автор, написавший dll на С++ и не думал, что ее будут использовать из какого-нибудь другого языка программирования. В этом случае MS рекомендует следующее:



    "However, certain situations require that you specify the name in its decorated form. You must specify the decorated name of C++ functions that are overloaded and special member functions, such as constructor and destructor functions, in order for LINK and other tools to be able to match the name. You must also use decorated

    names in assembly source files that reference a C or C++ function name."



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



    Пусть некая core.lib экспортирует функцию


    Код (Text):
    1. ?InitCustomControls@@YAXPAUHINSTANCE__@@@Z.
    2.  




    Тогда в ассемблерной программе ее стоит звать, например, так (информацию о параметрах можно взять либо из замангленого имени функции с помощью утилиты undname.exe, либо из документации):


    Код (Text):
    1. externdef
    2. _imp_?initCustomControls@@YAXPAUHINSTANCE__@@@Z:PTR
    3.  
    4. InitCustomControls equ
    5. <_imp_?InitCustomControls@@YAXPAUHINSTANCE__@@@Z>
    6.  
    7. invoke  InitCustomControls,hInst
    8.  




    Дополнительно в опциях линекра следует указать core.lib как библиотеку, содержащую код этой функции и путь к этой библиотеке:


    Код (Text):
    1. link /LIBPATH:"C:\3dmaxsdk" core.lib
    2.  
     
  3. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Q: Я поставил себе Soft-Ice и меня не работают bpx. И вообще у меня и Soft-Ice не работает. И Windows теперь больше не работает :dntknw:

    A:



    Форумы переполнены этими вопросами, которые, как правило, задают новички. Необходимо понимать, что айс - это драйвер, довольно часто напрямую работающий с железом и с внутренними структурами OS Windows. Поэтому он НЕВЕРОЯТНО чувствителен к изменениям hardware вашей машины, версиям SP, накатываемых на Windows и т.п. Очень

    глупы вопросы типа "я поставил Windows 2003, и у меня перестал работать Soft-Ice". Так и тянет ответить: "а ты бы еще Windows 2004 поставил, а лучше - 2005, чтоб обидно не было". Версия 2.7 вообще не предназначена для работы на операционках XP+! Вы бы еще чего-нибудь постарее выбрали бы!



    Айс опирается на структуры данных Windows, которые очень активно перетряхиваются, стоит ли удивляться, что что-то не работает? Авторы утилиты и так проделали изумительную работу. Точно так же и с железом. Ставите себе самые последние видюхи, а потом с воплями пляшете у экрана, матеря разработчиков почем свет стоит... Они же тоже спать хотят, а не бесконечно апдейты клепать!



    Теперь по делу. Если столкнулись с такой ситуацией, то действие номер 1: ИДИТЕ НА (хм, В и К) http://frontline.compuware.com/nashua/kb/ и ищите информацию по своему вопросу. Не так давно (с версии 2.7, если мне память не изменяет) разработчики отказались от идеи помещения структур прямо в код айса и вынесли их в отдельный файл - osinfo.dat. Перед тем как плакать на форуме, УБЕДИТЕСЬ, что у вас лежит САМЫЙ ПОСЛЕДНИЙ osinfo.dat: ftp://ftp.compuware.com/pub/driverstudio/outgoing/OsInfo/OSINFO.DAT



    Очень вероятно, что ваши bpx после этого придут в норму. Если нет - есть еще один трюк, описанный тут:

    http://frontline.compuware.com/nashua/kb/doc/1591.asp



    Смысл прост. Айс более не знает адресов внутренних структур Windows. Откуда их взять? Из pdb-файлов от самой MS сугубо для вашей версии OS. Скачиваете себе эти файлы с сайта MS



    http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx



    и в соответствии с инструкциями по линку выше, обрабатываете их и переписываете файл конфигурации айса. Все должно работать.



    Еще одна вещь - ВЕРСИЯ айса. Просто дико раздражает когда версию 2.6 ставят на 2003 и, естественно, получают BSOD. А чего вы еще ждали? Всегда ставьте последнюю версию. На данный момент (июнь 2004 года) - это версия 4.3.1.



    И еще одна вещь. Многие, скачав 4.3.1 c какого-нибудь варезного сайта в сети, тут же принимаются давить bpx MessageBoxA и это не срабатывает. После этого немедленно бегут в ближайший форум и вываливают на первой странице: "какого икса, игрека и еще какого-то неизвестного у меня не работает bpx?". А ответ прост: README надо читать! И активировать опцию "set BreakInSharedMods on"



    Также случилось знаменательное событие - выход SP2 под XP. В связи с чем Soft-Ice необходимо проапдейтить. Выглядит это так:



    Starting SoftICE after installing Windows XP SP2 will cause your machine to crash. This is not a problem with SoftICE but rather an internal layout change of the

    operating system. In addition the SoftICE universal video display will also need to be "found" again. To get around these issues:



    1. Boot your system without SoftICE. This can be done by

    pressing escape at the appropriate time in the boot process.

    2. Get the updated OSI data files as detailed below.

    3. Rerun the Settings application, go to the SoftICE Video page and click on both the "Detect" and "Test" buttons.

    4. Reboot your machine.



    Как всегда, сгружаете OSINFO.DAT:



    Для Visual Soft-Ice апдейты сгружать отсюда:



    ftp://ftp.compuware.com/pub/driverstudio/outgoing/patch/VSISP2Update.z ip



    Только если вы опробовали все, что тут написано и искали на сайте compuware, ТОЛЬКО тогда постите свой вопрос в форум!
     
  4. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Q: Как мне перехватить API-функцию?



    A:



    Невероятно популярный вопрос на очень многих форумах в последнее время.



    Ваше первое действие - ВЫПОЛНЯЙТЕ ПОИСК ПО ФОРУМУ. На данном форуме эта тема обсуждалась уже столько раз, что всем успела надоесть. Ключевые слова: "хук, hook, перехват, API, injection" и т.п.



    Обязательно загляните также на RSDN. Там есть пара очень хороших статей по теме. Также обязательно надо почитать Питрека (папа утилиты BoundsChecker). BC описан в книге Касперски "Техника и философия хакерских атак". Родоначальником BC был API monitor, который Питрек предельно подробно описал в "Win95 system programming secrets". Утилита распространялась с полным исходным кодом. Загляните на wheaty.net.



    Здесь же я осмелюсь предложить другое очень легкое и приятное решение - detours от Microsoft. detours - это библиотека перехвата API. Описание принципа действия и полный исходный код утилиты лежат на:



    http://research.microsoft.com/sn/detours/



    и дополнительно продублированы на wasm.ru в разделе "Утилиты" (4).



    Использование detours поначалу может немножко запутать, поэтому поясню подробнее. Как правило, целью является запуск exe-файла и перехват вызова этим exe-файлов тех или иных функций dll. Пусть наш подопытный exe-файл выглядит так:
    Код (Text):
    1. #include <windows.h>
    2.  
    3. void main()
    4. {
    5.     MessageBox(0, "HI", "WOW!", MB_OK);
    6. }
    7.  


    Код невероятно сложен, поэтому, если кто запутается окончательно, пусть топает и читает

    http://www.wasm.ru/article.php?article=1001002



    Наша цель: перехватить вызов MessageBox и подменить его на свой.



    Методика: мы создадим собственную dll при помощи detours и при помощи тех же самых detours запихнем эту dll в адресное пространство нашего процесса-жертвы.



    Теперь более детально. Код dll выглядит так:
    Код (Text):
    1.  
    2. #include <windows.h>
    3. #include <detours.h>
    4.  
    5. #pragma warning(disable:4100)  
    6. #pragma comment(lib,"detours.lib")
    7.  
    8. /**
    9.  *  int MessageBox(HWND hWnd,
    10.  *  LPCTSTR lpText,
    11.  *  LPCTSTR lpCaption,
    12.  *  UINT uType
    13.  *  );
    14.  **/
    15.  
    16. DETOUR_TRAMPOLINE(VOID WINAPI Real_MessageBox (HWND hWnd,
    17.             LPCTSTR lpText, LPCTSTR lpCaption, UINT uType), MessageBox);
    18.  
    19. BOOL WINAPI DetourMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
    20. {
    21.     Real_MessageBox(0, "He-he, MessageBox is detoured!", "Detours", MB_OK);
    22.     Real_MessageBox(hWnd, lpText, lpCaption, uType);
    23.     return true;
    24. }
    25.  
    26. BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
    27. {
    28.     if ( reason == DLL_PROCESS_ATTACH )
    29.         DetourFunctionWithTrampoline ( (PBYTE)Real_MessageBox, (PBYTE)DetourMessageBox );
    30.     else if ( reason == DLL_PROCESS_DETACH )
    31.         DetourRemove ( (PBYTE)Real_MessageBox, (PBYTE)DetourMessageBox );
    32.     return true;
    33. }
    34.  




    ИЗУЧИТЕ ЭТОТ КОД ОЧЕНЬ ВНИМАТЕЛЬНО!

    Большинство пояснений можно найти тут:

    http://codeproject.com/system/KamalDetours01.asp



    Предельно кратко, DETOUR_TRAMPOLINE падчит нужную функцию - туда передается сигнатура и имя функции, которую необходимо подменить на нащ вызов. Далее, DetourMessageBox будет вызываться вместо MessageBox. При загрузке нашей dll функция DetourFunctionWithTrampoline пропадчит нужную нам API адресом DetourMessageBox. Когда dll будет отгружена, DetourRemove уберет падч.



    Теперь осталось лишь вставить эту dll в адресное пространство процесса тем или иным образом. Сделать это несложно: либо ключом в реестре, либо с помощью withdll.exe, собранного из примеров, поставляемых вместе с detours (файл приаттачиваю). Кстати, примеры скомпилировать тоже непросто. makefiles, как всегда, не рабочие. Надо править common.mak и удалить там строчку "$(LIBD)\syelog.lib" (или собирать ее первой, если она нужна, что бывает редко) А далее лишь осталось набрать:
    Код (Text):
    1. withdll.exe /d:detours_MessageBox.dll MessageBox.exe




    Вуаля!

    Мы использовали DETOURS_TRAMPOLINE для т.н. "статического" перехвата кода. Для специфических dll используется "динамический" перехват кода. Разница несколько прозрачна, т.к. обе техники применяются динамически... Если запутались окончательно - читайте pdf о detours :) А я просто приведу пример исходного кода.



    Положим, нам надо перехватить функцию "CompareSerialNumber" в библиотеке "CheckSN.dll".

    Пусть прототип функции CompareSerialNumber будет таким:


    Код (Text):
    1. void CompareSerialNumber(char *)
    2.  


    Делается это так:
    Код (Text):
    1. void MyCompareSerialNumber(char *str)
    2. {
    3.         printf("SN is %s\n", str);
    4. }
    5.  
    6. BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
    7. {
    8.     if ( reason == DLL_PROCESS_ATTACH )
    9.     {
    10.         void *p = DetourFunction((PBYTE)DetourFindFunction("CheckSN.dll", "CompareSerialNumber"),
    11.             (PBYTE)MyCompareSerialNumber);
    12.     }
    13.  
    14.     return true;
    15. }
    16.  


    Заметьте, что сигнатура MyCompareSerialNumber должна В

    ТОЧНОСТИ соответствовать сигнатуре функции CompareSerialNumber.



    P.S. Detours - это великолепная библиотека. Однако и ей присущи некоторые ограничения. Например, как быть, если вы хотите трейсить не одну функцию API как в примере выше, а ВСЕ функции данной библиотеки или что-нибудь не менее масштабное (вдруг вам второй BC захотелось написать).



    Тут есть некоторые сложности, однако по этому линку дается решение и этих проблем:

    http://www.sumbera.com/ustation/research/mdlspy.htm



    Так же помните, что у движка есть и другие ограничения.
     
  5. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Часто задаваемые вопросы по использованию ассемблера в юниксах

    Составлено STAKANOV



    Q: Какие ассемблеры бывают в юникс и где их взять?

    A: Ассемблер as (GNU AS) считается стандартным, также очень популярен ассемблер NASM. Есть также хороший ассемблер FASM.



    AS: Во FreeBSD as и все утилиты из пакета binutils присутвуют в системе по умолчанию. В Linux потребуется дополнительно установить пакет binutils (формат пакета зависит от дистрибутива) или скачать его с ftp://ftp.gnu.org/gnu/binutils/ .



    NASM: Во FreeBSD установите порт /usr/ports/devel/nasm/. В Linux установите из соответвующего пакета или скачайте с сайта http://www.kernel.org/pub/software/devel/nasm/ (или http://sourceforge.net/projects/nasm).



    FASM: Скачайте с официального сайта http://www.flatassembler.net/



    Важно! AS использует синтаксис AT&T, а NASM и FASM синтаксис Intel.



    Q: У юникса есть API ?

    A: Да. Называется это системные вызовы (syscalls). Осуществляются они путем вызова прерывания номер 0x80. Кроме того, практически везде действует "lcall $7,$0" ("call 7:0" в синтаксисе интел) как его полный аналог. Так же в системе обязательно присутствует библиотека libc.



    Q: Как передаются параметры системных вызовов?

    A: Во FreeBSD параметры передаются через стек, сначала последний, затем предпоследний и первый параметр помещается в стек последним. Так же при испотьзовании прерывания необходимо поместить в стек любое 32-битное значение. В Linux через регистры по порядку первый в EBX, и тд - ECX, EDX, ESI, EDI, EBP. Если количество параметров больше 6, то в памяти формируется структура с параметрами и в EBP помещается адрес этой стурктуры. В EAX в обоих случаях номер системного вызова. Если хотите использовать функции из libc, то передача параметров при этом осуществляется так как принято в Си (в мире Windows такой способ известен как CDECL). Результат всегда возвращается в EAX.



    Q: Где узнать номера системных вызовов?

    A: Самый простой способ для FreeBSD(должны быть установлены исходники системы!) - смотреть файл /usr/srs/sys/kern/syscalls.master. Там и номера и параметры. Способ для Linux - /usr/src/linux/arch/i386/kernel/syscall_table.S или файл entry.S из того же каталога для версий 2.4 и 2.6.



    Предполгается что /usr/src/linux/ это каталог с исходными текстами ядра Linux



    Q: Где найти описания системный вызовов или функций libc?



    A: Как обычно в юникс - справочник man (например man 2 write) или info.



    Q: Покажите маленькую программку типа "Hello,world!"



    A:

    Вариант 1 (as,FreeBSD) hello.s:
    Код (Text):
    1.  
    2.   .data
    3. msg:
    4.   .asciz "Hello,world!\n"
    5.   msg_len= .-msg
    6.   .text
    7.   .global _start
    8. _start:
    9.  
    10.   pushl $msg_len   # константа, длинна строки
    11.   pushl $msg     # адрес строки "Hello,world!\n"
    12.   pushl $1     # дескриптор стандартного вывода
    13.   movl $4,%eax     # 4 - номер системного вызова write
    14.   push %eax     # здесь может быть любое 32х битное
    15.   int $0x80     # выполнить систменый вызов
    16.   addl $16,%esp     # восстанавливаем стек
    17.  
    18.   pushl $0     # код выхода
    19.   movl $1,%eax     # 1 - номер системного вызова sys_exit
    20.   push %eax
    21.   int $0x80
    22.  




    Вариант 2 (fasm,FreeBSD) hello.asm:
    Код (Text):
    1. format ELF
    2. section '.text' executable
    3. public _start
    4. _start:
    5.   push msg_len     ; size of message
    6.   push msg     ; offset of message
    7.   push 1     ; stdout
    8.   mov eax,4     ; 4 = sys_write
    9.   push eax
    10.   int 0x80
    11.   add esp,4*4     ; очищаем за собой стэк
    12.  
    13.   xor eax,eax
    14.   push eax     ; код выхода
    15.   inc eax     ; 1 = sys_exit
    16.   int 0x80
    17.  
    18. section '.data' writeable
    19.  
    20.   msg db "Hello world",0
    21.   msg_len = $-msg




    Вариант 3 (as, все платформы, используем libc) hello-world.s:
    Код (Text):
    1.   .data
    2. msg: .string "Hello world."
    3.   .text
    4.   .globl main
    5. main:   pushl $msg
    6.   call puts
    7.   xorl %eax, %eax
    8.   pushl %eax
    9.   call exit




    Вариант 4 (nasm, Linux) hello-nasm.asm:
    Код (Text):
    1. SECTION .data     ; секция данных
    2. msg: db "Hello World",10     ; строка для вывода, 10=cr
    3. len: equ $-msg     ; "$" означает "здесь"
    4.     ; len это значение, не адрес
    5.  
    6.   SECTION .text     ; секция код
    7.   global _start     ; делаем метку доступной для линкера
    8. _start:     ; стандартный вход
    9.  
    10.   mov edx,len     ; arg3, длинна строки для вывода
    11.   mov ecx,msg     ; arg2, адрес строки
    12.   mov ebx,1     ; arg1, стандартный вывод
    13.   mov eax,4     ; передаем команду sysout в int 80 hex
    14.   int 0x80     ; прерываение 80 hex, вызов kernel
    15.  
    16.   mov ebx,0     ; код выхода, 0=normal
    17.   mov eax,1     ; команда выход для kernel
    18.   int 0x80     ; прерывание 80 hex, вызов kernel




    Q: Как ее запустить (слинковать, ассемблировать)?



    A:

    Вариант 1:
    Код (Text):
    1. as hello.s -o hello.o
    2. ld -s hello.o -o hello
    3. ./hello


    Вариант 2:
    Код (Text):
    1. fasm hello.asm hello.o
    2. ld -s hello.o -o hello
    3. ./hello


    Вариант 3:
    Код (Text):
    1. as hello-world.s -o hello-world.o
    2. gcc -Wl,-s hello-world.o -o hello-world
    3. ./hello-world


    Вариант 4:
    Код (Text):
    1. nasm -f elf hello-nasm.asm
    2. ld -s hello-nasm.asm -o hello-nasm
    3. ./hello-nasm




    Q: А покажите "Hello,world!" с GUI



    A: Простейшие примеры:

    Вариант 1 (as, все платформы) hello-gui.s:
    Код (Text):
    1. # as hello-gui.s -o hello-gui.o
    2. # gcc -Wl,-s hello-gui.o -lX11 -L/usr/X11R6/lib -o hello-gui
    3. # ./hello-gui
    4.   .data
    5. prDisplay: .long 0 # указатель на структуру Display
    6. nScreenNum: .long 0 # номер экрана
    7. nWnd: .long 0 # ID окна
    8. rEvent: .space 96,0 # буфер для получения события (сообщения)
    9.   # вообщето все намного сложней
    10.   # но длинное слово (32бит)со смещением 0
    11.   # обычно содержит тип события
    12. prGC: .long 0
    13. msgHello: .asciz "Hello, world!" # какое-то непереводимое ругательство
    14.   msgHelloLen=.-msgHello-1
    15.  
    16.   .text
    17.   .global main # без libc мы обойтись не сможем!
    18. main:
    19.   # устанавлиываем связь с сервером
    20.   pushl $0
    21.   call XOpenDisplay
    22.   addl $4,%esp
    23.   movl %eax,prDisplay # теперь prDisplay содержит адресс структуры
    24.     # или равен 0 в случае ошибки
    25.     # получаем номер основного экрана
    26.   pushl %eax
    27.   call XDefaultScreen
    28.   addl $4,%esp
    29.   movl %eax,nScreenNum
    30.   # создаем окно
    31.   pushl nScreenNum
    32.   pushl prDisplay
    33.   call XWhitePixel
    34.   addl $8,%esp
    35.   pushl %eax # белый пиксел )
    36.   pushl nScreenNum
    37.   pushl prDisplay
    38.   call XBlackPixel
    39.   addl $8,%esp
    40.   pushl %eax # черный пиксел )
    41.   pushl $5 # толщина рамки
    42.   pushl $100 # высота окна
    43.   pushl $100 # ширина окна
    44.   pushl $0 # x
    45.   pushl $0 # y
    46.   pushl nScreenNum
    47.   pushl prDisplay
    48.   call XRootWindow
    49.   addl $8,%esp
    50.   pushl %eax # окно родитель
    51.   pushl prDisplay # дисплей
    52.   call XCreateSimpleWindow
    53.   addl $36,%esp
    54.   movl %eax,nWnd # номер окна
    55.   # устанавливаем события обрабатываемые прграммой
    56.   pushl $(1 | (1 << 15)) # это у нас ExposureMask OR KeyPressMask
    57.   pushl nWnd
    58.   pushl prDisplay
    59.   call XSelectInput
    60.   addl $12,%esp
    61.   # показываем окно (проще некуда ;-) )
    62.   pushl nWnd
    63.   pushl prDisplay
    64.   call XMapWindow
    65.   addl $8,%esp
    66.   # самое главное
    67.   # цикл получения и обработки сообщений
    68. wloop:
    69.   pushl $rEvent # адрес буфера
    70.   pushl prDisplay # дисплей
    71.   call XNextEvent
    72.   addl $8,%esp
    73.   movl rEvent,%eax # !!! так делать не стоит
    74.     # но здесь сойдет
    75.   cmpl $12,%eax
    76.   je _Expose
    77.   cmpl $2,%eax
    78.   je _KeyPress
    79.   jmp wloop
    80. _Expose:
    81.   # запрос на перерисовку
    82.   # получаем графический контекст
    83.   pushl $0
    84.   pushl $0
    85.   pushl nWnd
    86.   pushl prDisplay
    87.   call XCreateGC
    88.   addl $16,%esp
    89.   movl %eax,prGC
    90.   # а кто у на сегодня "черный"?
    91.   pushl $0
    92.   pushl prDisplay
    93.   call XBlackPixel
    94.   addl $8,%esp
    95.   # устанвливаем цвет которым рисуем
    96.   pushl %eax
    97.   pushl prGC
    98.   pushl prDisplay
    99.   call XSetForeground
    100.   addl $12,%esp
    101.   # рисуем текст
    102.   pushl $msgHelloLen
    103.   pushl $msgHello
    104.   pushl $50
    105.   pushl $10
    106.   pushl prGC
    107.   pushl nWnd
    108.   pushl prDisplay
    109.   call XDrawString
    110.   addl $28,%esp
    111.   # освобождаем графический контекст
    112.   pushl prGC
    113.   pushl prDisplay
    114.   call XFreeGC
    115.   addl $8,%esp
    116.   jmp wloop
    117. _KeyPress:
    118.   # кто-то нажал на кнопку
    119.   pushl prDisplay
    120.   call XCloseDisplay
    121.   call exit
    122.  




    Вариант 2 (fasm, все платформы) gui_fasm.asm:
    Код (Text):
    1. ; fasm gui_fasm.asm
    2. ; gcc -Wl,-s gui_fasm.o -lX11 -L/usr/X11R6/lib -o gui_fasm
    3. ; ./gui_fasm
    4. format ELF
    5. public main
    6. extrn XOpenDisplay
    7. extrn XDefaultScreen
    8. extrn XWhitePixel
    9. extrn XBlackPixel
    10. extrn XRootWindow
    11. extrn XCreateSimpleWindow
    12. extrn XSelectInput
    13. extrn XMapWindow
    14. extrn XNextEvent
    15. extrn XCreateGC
    16. extrn XSetForeground
    17. extrn XDrawString
    18. extrn XFreeGC
    19. extrn XCloseDisplay
    20. extrn exit
    21.  
    22. section '.data' writeable
    23. prDisplay dd 0 ; указатель на структуру Display
    24. nScreenNum dd 0 ; номер экрана
    25. nWnd dd 0 ; ID окна
    26. prGC dd 0
    27. rEvent rb 96 ;буфер для получения события (сообщения)
    28. msg db 'Hello,world!',0x0
    29. msg_size = $-msg
    30.  
    31. section '.text' executable
    32. main:
    33.   ;устанавлиываем связь с сервером
    34.   push 0
    35.   call XOpenDisplay
    36.   add esp,4
    37.   mov [prDisplay],eax ;prDisplay содержит адресс структуры
    38.   ; получаем номер основного экрана
    39.   push eax
    40.   call XDefaultScreen
    41.   add esp,4
    42.   mov [nScreenNum],eax
    43.   ; создаем окно
    44.   push [nScreenNum]
    45.   push [prDisplay]
    46.   call XWhitePixel
    47.   add esp,8
    48.   push eax ; белый пиксел
    49.   push [nScreenNum]
    50.   push [prDisplay]
    51.   call XBlackPixel
    52.   add esp,8
    53.   push eax ; черный пиксел
    54.   push 5 ; толщина рамки
    55.   push 100 ; высота окна
    56.   push 100 ; ширина окна
    57.   push 0 ; x
    58.   push 0 ; y
    59.   push [nScreenNum]
    60.   push [prDisplay]
    61.   call XRootWindow
    62.   add esp,8
    63.   push eax ; окно родитель
    64.   push [prDisplay]
    65.   call XCreateSimpleWindow
    66.   add esp,36
    67.   mov [nWnd],eax
    68.   ; устанавливаем события обрабатываемые прграммой
    69.   mov eax,1
    70.   shl eax,15
    71.   or eax,1
    72.   push eax
    73.   push [nWnd]
    74.   push [prDisplay]
    75.   call XSelectInput
    76.   add esp,12
    77.   ; показываем окно
    78.   push [nWnd]
    79.   push [prDisplay]
    80.   call XMapWindow
    81.   add esp,8
    82.   ; цикл получения и обработки сообщений
    83. wloop:
    84.   push rEvent ; адрес буфера
    85.   push [prDisplay] ; дисплей
    86.   call XNextEvent
    87.   add esp,8
    88.   mov eax,rEvent
    89.   mov eax,[eax]
    90.   cmp eax,12
    91.   je _Expose
    92.   cmp eax,2
    93.   je _KeyPress
    94.   jmp wloop
    95. _Expose:
    96.   ; запрос на перерисовку
    97.   ; получаем графический контекст
    98.   push 0
    99.   push 0
    100.   push [nWnd]
    101.   push [prDisplay]
    102.   call XCreateGC
    103.   add esp,16
    104.   mov [prGC],eax
    105.   ; "черный"
    106.   push 0
    107.   push [prDisplay]
    108.   call XBlackPixel
    109.   add esp,8
    110.   ; устанвливаем цвет которым рисуем
    111.   push eax
    112.   push [prGC]
    113.   push [prDisplay]
    114.   call XSetForeground
    115.   add esp,12
    116.   ; рисуем текст
    117.   push msg_size
    118.   push msg
    119.   push 50
    120.   push 10
    121.   push [prGC]
    122.   push [nWnd]
    123.   push [prDisplay]
    124.   call XDrawString
    125.   add esp,28
    126.   ; освобождаем графический контекст
    127.   push [prGC]
    128.   push [prDisplay]
    129.   call XFreeGC
    130.   add esp,8
    131.   jmp wloop
    132. _KeyPress:
    133.   push [prDisplay]
    134.   call XCloseDisplay
    135.   call exit




    Q: Как мне получить аргументы командной строки и переменные окружения?



    A: В точке входа в программу (_start:) в стеке содержатся следующие данные

    <ul type=disc>(%esp) aka dword [esp] - n, количество аргументов командной строки</ul>

    <ul type=disc>4(%esp) aka dword [esp+4]</ul> - адрес первого аргумента, имя программы

    <ul type=disc>4*2(%esp) aka dword [esp+4*2]</ul> - адрес второго аргумента

    <ul type=disc>...</ul>

    <ul type=disc>4*n(%esp) aka dword [esp+4*n]</ul> - адрес последнено аргумента

    <ul type=disc>4*n+4(%esp) aka dword [esp+4*n+4] - нулевой адрес (NULL)</ul>

    <ul type=disc>4*n+8(%esp) aka dword [esp+4*n+8] - ] адрес переменных окружения</ul>



    Q: Какие порекомендуете ссылки?



    A:

    GNU Binutils (англ) - http://www.gnu.org/software/binutils

    NASM (рус) - http://www.opennet.ru/docs/RUS/nasm

    GNU AS(рус) - http://www.opennet.ru/docs/RUS/gas

    FASM (рус) - http://mythrillus.land.ru/tajga-tut/index.html

    Справочник man (рус, англ) http://man.opennet.ru





    Тексты примеров можно скачать с http://stakanov.by.ru/articles/unixwasmfaq.zip



    Оригинальный текст расположен по http://stakanov.by.ru/articles/asm_unix_faq.html
     
Статус темы:
Закрыта.