основыкнигиwin/dos*nixготовоелирикагостиФОРУМПОИСК
Lord Julus -- Основы программирования под Win32
    __________________________________________________________________________
   (__________________________________________________________________________)
   { __ }   { __ }        |                            |        { __ }   { __ }
    |\\|     |\\|    .----O----------------------------O----.    |//|     |//|
    |\\|     |\\|    |   Основы программирования под Win32  |    |//|     |//|
    |\\|     |\\|    `--------------------------------------'    |//|     |//|
   {____}   {____}                                              {____}   {____}

      Давайте немного поговорим об Win32 API функциях. Они представляют силу и, в основном, ядро всей ОС. Все действия, которые необходимо выполнить, должны и будут выполняться через эти самые API функции. API -- фактически функции, которые вызывает ваш код, чтобы, в конечном счете, использовать возвращенные значения. Microsoft утверждает, что каждая API, созданная ими, существует во всех и каждой Win32 платформе. Это только половина правды. Другая половина -- то, что они присутствуют УСЛОВНО. Ложь в том, что они не всегда делают то, что от них ожидается. Для примера: в Windows 95 существует много API, которые могут быть вызваны, поскольку они экспортируются, но возвращаемое ими значение -- всегда ноль, и никаких действий при этом не производится.
      Идея, возможно основная идея, в Win32 системе -- методы импорта и экспорта. Это позволяет больше чем одному приложению вызывать одни и те же функции, не вынуждая хранить их код внутри себя. Проще говоря, Win32 приложение будет хранить в себе только адреса этих функций, и вызывать их по мере надобности. Это, во-первых, делает Win32 приложения маленькими по размеру, а во-вторых, гарантирует, что все приложения будут использовать одни и те же версии этих функций. Импорт и экспорт будет объяснен гораздо лучше в одной из следующих статей. В этой статье я хочу показать, как сделать простое Win32 приложение.
      Как всегда, я буду рассчитывать только на синтаксис TASMа, поэтому то, что я пишу, не будет работать в MASM и других.
      Всякий раз, когда необходимо использовать некую API, необходимо создать описание, так линкер будет узнавать, что требуется импортировать для данного приложения. Описание выглядит примерно так:

extrn :proc

      Для примера возьмем API, используемую во всех Win32 приложениях:

extrn ExitProcess:proc

      Убедитесь, пожалуйста, в том, что вы добавили директиву ':proc'. Если вы этого не сделаете, ваша программа нормально скомпилируется и слинкуется, но будет выдавать "General Protection failure" -- общую ошибку защиты каждый раз, когда данная API будет вызываться. Чтобы понять почему, попробуйте скомпилировать файл обоими с обоими вариантами и проследить его работу в Turbo Debugger'е.
      Так же каждый раз при использовании API, ее необходимо импортировать, используя директиву "extrn". Но как мы узнаем, какая API нам нужна? Хороший вопрос. Самый лучший ответ на него -- "Microsoft Win32 Programmer's Refference" -- описание программирования под Win32, скачать которое можно с сайта Microsoft, и которое содержит полное описание всех Win32 API. В данном описании можно искать необходимые API вручную, интуитивно. Скажем, вы хотите открыть файл, но не знаете, какая API вам для этого необходима. Вы просто набираете "open" и ищете функцию, в которой есть эти символы. Вскоре вы найдете OpenFile API. Откройте справку, и вы получите все необходимые вам данные. Но это -- не все. Поскольку вы ищете информацию для одной или другой API, вы можете заинтересоваться, какие параметры необходимы при вызове и какие возвращаются. "Win32 Refference" только ищет API по имени, а какие должны при этом быть значения параметров? Ответ на этот вопрос находится в "Microsoft SDK". Это -- огромный файл, который можно скачать с сайта Microsoft, и который содержит все эти значения. Чтобы облегчит вам жизнь, я потратил время и написал несколько .inc файлов, которые вы сможете использовать в вашем коде. Файлы для включения в код тоже в этом выпуске и вы также можете их использовать. Теперь, когда вы знаете о связи между "Win32 Refference" и параметрами, вы можете пользоваться API функциями.
      Еще одна проблема... Как вы знаете, большая часть Windows, также как и большинство программ для Windows написано на С. Поэтому большинство документации рассчитано для программирования на С. Иногда это раздражает программиста- ассемблерщика. Например, вот кусок из "Win32 Refference":

HANDLE CreateFileA{
LPCTSTR               lpFileName
DWORD                 dwDesiredAccess
DWORD                 dwShareMode
LPSECURITY_ATTRIBUTES lpSecurityAttributes
DWORD                 dwCreationDistribution
DWORD                 dwFlagsAttributes
HANDLE                hTemplateFile
       }

      В синтаксисе С вышеуказанный вызов будет выглядеть так:

push <TEMPLATEFILE>
push <FLAGS>
push <CREATION>
push <SECURITY_ATTRIBS>
push <SHAREMODE>
push <ACCESS>
push offset <FILENAME>
call CreateFileA

      Я предполагаю, что все понятно. Если вы нашли API в "Win32 Refference", то при написании ассемблерных программ с использованием данной API, вы должны помещать параметры в стек справа налево. Вообще, каждый раз, когда у вас есть длинный или обычный указатель, вы должны помещать его смещение в стек. Изучите программу на С, чтобы убедиться в этом.
      Постепенно мы подходим к методу вызова API. Это выполняется, как вы видели, путем помещения в стек различных параметров и вызова API. Если произошла ошибка, ее код возвращается после вызова, как правило, в EAX. Если фактически код ошибки не возвращен, его можно получить при помощи API функции GetLastError. Она возвращает в EAX код последней произошедшей ошибки. Детализированный список кодов ошибок вы можете найти в файле w32er_lj.inc.
      Если линкер обнаруживает ошибку и сообщает:

Unresolved external link: <API name>

      Не пугайтесь, скорее всего, вы ошиблись в написании названия API. Откройте файл import32.lib в hex/ascii виде и посмотрите правильное написание функции. Например, распространенной ошибкой, которую я делал, было написание UnMapViewOfFile вместо UnmapViewOfFile.
      Ну что ж, начнем программировать наше первое win32 приложение.

.386p
.model flat, stdcall

      Вышеупомянутые директивы обязуют нас иметь как минимум 386ую машину (Windows NT не поддерживает 386 и меньшие модели PC). Затем мы должны сообщить линкеру, что наше приложение выполняется в модели памяти flat (никаких сегментов -- просто память).
      После этого мы можем указывать (через "extrn" и "proc") ниши функции:

extrn <API1>:proc
extrn <API2>:proc
  ...

      Данные, используемые нашей программой, должны быть помещены в секцию data:

.data
var1 dd ?
var2 dd ?
  ...

      После чего идет секция кода:

.code

start:
 ...

end start
end

      Обратите внимание, что вы можете помещать данные также внутри секции кода, но, по умолчанию, вы сможете их только ЧИТАТЬ (я объясню права доступа и их использование позже). Это очень важно для вируса, поскольку вирус не может позволить себе хранить свои данные в различных секциях. Весь код и все данные должны постоянно находиться в одной и той же секции. Для этого первое поколение должно быть изменено так, чтобы оно тоже могло работать. Это достигается утилитами, которые устанавливают флаг записи в секции кода. Сделайте это утилитами типа PEWRSEC и PEENABLE, и у вас не будет проблем при выполнении win32 приложений с данными внутри секции кода. При этом даже если у вас нет никаких ценных данных внутри секции кода, вы все равно не можете оставлять ее пустой, поскольку при этом TLINK32 будет выдавать ошибку. Теперь мы подошли к каркасу первого простейшего win32 приложения:

.386p
.model flat, stdcall
extrn ...
  ...
.data
dd 0
.code
start:
(здесь идет ваш код)
(здесь помещается код для выхода)
(здесь помещаются данные)
end start
end

      Поскольку вы знакомы с программами под Windows, вы могли бы предположить, что любая маленькая программка, типа этой, будут создавать окна, и ждать пока вы нажмете на кнопку выхода... Хрен... Это не так. Этот пример не будет делать ничего. Чтобы создать окно, мы должны потрудиться больше, гораздо больше. Но мы поговорим об этом чуть позже. Это называется Приложения Графического Интерфейса. У нас -- обычное Windows-приложение.
      ОК. После того, как мы приобрели некие базисные знания, давайте посмотрим, как мы можем изобразить окно сообщения и ждать нажатия на кнопку:


.386p                          ; 386я машина
.model flat, stdcall           ; модель памяти flat
                                           ;
extrn MessageBoxA:proc         ; импорт из user32
extrn ExitProcess:proc         ; импорт из kernel32
                                           ;
.data                          ; якобы раздел данных
dd 0                           ;
                                           ;
.code                          ;
start:                                     ;
push 1000h                     ; -T-> параметры для
push offset Window_Title       ; -+ MessageBoxA
push offset Window_Text        ; -+
push 0                         ; --
call MessageBoxA               ; вызвать API
                                           ;
push 0                         ; код выхода
call ExitProcess               ; вызвать API для выхода
                                           ;
Window_Title db "Message box example.",0   ; данные
Window_Text  db "Hello World !!",0         ;
                                           ;
end start                                  ;
end                                        ; конец

      Чтобы скомпилировать это приложение, мы должны выполнить следующие команды:

TASM32 -ml -mx program.asm
TLINK32 -Tpe -aa -c program,,,import32.lib

      Файл import32.lib очень важен. Он идет в комплекте с компилятором TASM и содержит имена всех API функций, которые вы должны использовать в ваших программах. Вы можете создавать ваши собственные .lib файлы, используя программу importlib, которая также идет в комплекте с TASM.
      Таким образом, вы сделали ваше первое win32-приложение, которое выводит окно сообщения. Я думаю, здесь все понятно.
      Изучите следующие статьи, чтобы глубже понять принцип программирования win32 вирусов.

                                               -----------------------
                                               | Lord Julus - 1999 - |
                                               -----------------------