Низкоуровневый кодинг Крис Касперски ака мыщъх Хакер, номер #076, стр. 076-116-3 Основные типы пересылок данных LEA EDX,b ;// регистр EDX содержит указатель на переменную b MOV EBX,a ;// регистр EBX содержит значение переменной a MOV ECX, offset a ;// регистр ECX содержит указатель на переменную a MOV [EDX],EBX ;// скопировать переменную a в b MOV b, EBX ;// скопировать переменную b в а MOV b, a ;// !!!ошибка!!! так делать нельзя!!! ;// оба аргумента команды MOV не могут быть в памяти! a DD 66h ;// long a = 0x66; b DD ? ;// long b; Теперь перейдем к условным переходам. Никакого "if" в обычном ассемблере нет, и эту операцию приходится осуществлять в два этапа. Первый – использование команды CMP, которая сравнит два числа и сохранит результат своей работы во флагах. Флаги, кстати - это биты специального регистра, описание которого заняло бы слишком много места и поэтому здесь не рассматривается. Достаточно запомнить три основных состояния флагов: меньше (bellow или less), больше (above или great) или равно (equal). Второй этап – это переход в нужную часть программы в зависимости от результатов сравнивания. Для этого существует семейство команд условного перехода Jxx. Команды проверяют условие «xx» и, если оно истинно, совершают прыжок по указанному адресу. Например, JE прыгает, если числа равны (Jump if Equal), а JNE если неравны (Jump if Not Equal). JB/JA работают с беззнаковыми числами, а с JL/JG - со знаковыми. Любые два не противоречащих друг другу условия могут быть скомбинированы друг с другом, например, JBE – переход в случае, если одно беззнаковое число меньше или равно другому. Безусловный же переход осуществляется командой JMP. Конструкция CMP/Jxx больше всего похожа на Бейсковское IF xxx GOTO, чем на Си. Вот несколько примеров ее использования: Основные типы условных переходов CMP EAX, EBX ;// сравнить EAX и EBX JZ xxx ;// если они равны переход на xxx CMP [ECX], EDX ;// сравнить *ECX и EDX JAE yyy ;// если беззнаковый *ECX >= EDX перейти на yyy Вызов функций на ассемблере реализуется намного сложнее, чем на Си. Во-первых, существует, по меньшей мере, два типа «соглашений» передачи функции параметров - Си и Паскаль. В Си-соглашении параметры передаются справа налево, а из стека их вычищает вызывающий функцию код. В Паскаль-соглашении все происходит наоборот! Аргументы передаются слева направо, а из стека их вычищает сама функция. Большинство API-функций Windows придерживаются комбинированного соглашения stdcall, при котором аргументы заносятся в соответствии с Си-соглашением, а из стека вычищаются по соглашению Паскаль. Возвращаемое функцией значение помещается в регистр EAX (для передачи 64-разрядных значений используется регистровая пара EDX:EAX). Разумеется, этих соглашений необходимо придерживаться только при вызове внешних функций (API, библиотек и т.д.). "Внутренние" функции им следовать не обязаны и могут передавать аргументы любым мыслимым способом (к примеру, через регистры). Вызов API-функции PUSH offset LibName ;// засылаем в стек смещение строки |