Хакер - Заплатка на асме. Создаем панель инструментов для Windows на Flat Assembler

Хакер - Заплатка на асме. Создаем панель инструментов для Windows на Flat Assembler

hacker_frei

https://t.me/hacker_frei

Игорь Орещенков 

Содержание статьи

  • Нет в мире совершенства
  • Выбор цели и средства
  • Что умеет Flat Assembler?
  • Создание обработчика сообщения WM_CREATE
  • Подготовка к использованию функции SHAppBarMessage
  • Резервирование площадки для панели
  • Настройка окна панели
  • Заключение

В этой статье я рас­ска­жу о том, как соз­дать прос­тое при­ложе­ние — заготов­ку панели инс­тру­мен­тов для рабоче­го сто­ла Windows. По ходу дела мы вспом­ним Win32 API, раз­берем­ся, как его исполь­зовать на язы­ке ассем­бле­ра, и поз­накомим­ся с Flat Assembler, который ста­нет для нас основным инс­тру­мен­том раз­работ­ки.

НЕТ В МИРЕ СОВЕРШЕНСТВА

На­род­ная мол­ва гла­сит, что в осно­ве мироз­дания лежит закон под­лости, из которо­го сле­дуют все осталь­ные фун­дамен­таль­ные законы при­роды. К таковым отно­сит­ся и закон неубы­вающей энтро­пии, в соот­ветс­твии с которым матери­аль­ные пред­меты со вре­менем при­ходят в негод­ность. На моем монито­ре этот закон про­явил­ся в виде горизон­таль­ных полос в вер­хней час­ти экра­на, которые выг­лядят как нот­ный стан, если под ними радикаль­но чер­ный фон, и как интерфе­рен­цион­ная кар­тина в двух­щелевом экспе­римен­те, если фон свет­лый.

Де­фект монито­ра в виде горизон­таль­ных полос

Оз­накомив­шись с обзо­рами ана­логич­ных проб­лем по роликам на YouTube, я сос­тавил для себя общее пред­став­ление об этом дефек­те. Он может быть выз­ван либо пло­хим кон­тактом шлей­фа, соеди­няюще­го мат­рицу монито­ра с кон­трол­лером, либо неис­прав­ностью в элек­трон­ных ком­понен­тах самого кон­трол­лера. Пос­коль­ку гаран­тий­ный срок уже закон­чился, я разоб­рал монитор и при­шел к выводу, что с отсутс­тви­ем опы­та и инс­тру­мен­тов шан­сы на успешный ремонт у меня при­мер­но 50 на 50: либо устра­ню дефект, либо испорчу все окон­чатель­но.

Ка­кие еще оста­ются вари­анты? Знаю по опы­ту, что офи­циаль­ный сер­вис, ско­рее все­го, выс­тавит заг­радитель­ную цену, а отда­вать боево­го товари­ща в очу­мелые руч­ки кус­таря‑оди­ноч­ки совесть не поз­воля­ет. Наибо­лее здра­вой кажет­ся мысль пой­ти в бли­жай­ший магазин, купить новый монитор и не дурить голову ни себе, ни читате­лям. Имен­но так я бы и пос­тупил, если бы монитор не работал сов­сем. Но он поч­ти работа­ет, и выб­расывать его поп­росту жал­ко.

А ведь если подумать, ремонт необя­затель­но пред­полага­ет вос­ста­нов­ление исходно­го качес­тва изде­лия — зачас­тую допус­кает­ся некото­рая утра­та пот­ребитель­ских свой­ств. Как, нап­ример, пос­тупа­ет хакер, обна­ружив в один прек­расный день дыру... нет, не в безопас­ности, а в любимых домаш­них брю­ках? Дос­тает свой тол­стый кошелек и спе­шит в бли­жай­ший бутик за новыми? Нет, он вспо­мина­ет уро­ки Марь­ван­ны и, при­меняя методо­логию «впе­ред игол­ка», нак­ладыва­ет зап­латку! Или дру­гой при­мер. В не менее прек­расный день ин­женеры NASA обна­ружи­ли, что основная антенна ради­освя­зи запущен­ного к Юпи­теру зон­да не рас­кры­лась пол­ностью. Раз­ве они бро­сили неис­прав­ное устрой­ство на про­извол судь­бы и обра­тились к пра­витель­ству за финан­сирова­нием нового? Нет, они про­яви­ли наход­чивость и тех­ничес­кую сме­кал­ку, в резуль­тате чего пусть и не без тру­да, но успешно про­вели мно­голет­нюю иссле­дова­тель­скую мис­сию.

ВЫБОР ЦЕЛИ И СРЕДСТВА

Рас­смат­рива­емая в статье ситу­ация находит­ся где‑то меж­ду эти­ми край­ними слу­чаями. Наиболь­шие неудобс­тва опи­сан­ный дефект дос­тавля­ет при исполь­зовании раз­верну­тых на весь экран прог­рамм, потому что попада­ет либо на адресную стро­ку бра­узе­ра, либо на глав­ное меню при­ложе­ния. Исполь­зование же прог­рамм в окон­ном режиме, с под­гонкой их мес­тополо­жения пос­ле каж­дого запус­ка, гро­зит нер­вным расс­трой­ством. Я готов пожер­тво­вать частью полез­ной пло­щади экра­на, если изоб­ражение не будет попадать на дефек­тную область.

Ос­новная опе­раци­онная сис­тема на моем компь­юте­ре — Windows. Как исклю­чить полосу в вер­хней час­ти экра­на из дос­тупно­го прос­транс­тва рабоче­го сто­ла, что­бы окна при­ложе­ний при раз­верты­вании не попада­ли на нее? Идею мне под­ска­зала панель задач: она монопо­лизи­рует ниж­нюю часть экра­на и никог­да не перек­рыва­ется окна­ми прог­рамм. Может быть, дос­таточ­но будет прик­репить ее к вер­хней час­ти экра­на? Нет, во‑пер­вых, она не сов­сем под­ходит по раз­меру, а во‑вто­рых, сама при­обре­тает неп­ригляд­ный вид из‑за дефек­та. А нель­зя ли сде­лать «зап­латку» с такими же свой­ства­ми, но что­бы поль­зователь мог кон­тро­лиро­вать ее раз­мер и цвет?

Ока­зыва­ется, мож­но, и ответ быс­тро нашел­ся в спра­воч­нике по Win32 API — это па­нель инс­тру­мен­тов рабоче­го сто­ла. Нап­равле­ние работы про­ясни­лось, оста­лось выб­рать под­ходящий инс­тру­мент для ее выпол­нения. Основное средс­тво раз­работ­ки с исполь­зовани­ем Win32 API — ком­пилятор С. Но для вызова нес­коль­ких фун­кций опе­раци­онной сис­темы хочет­ся вос­поль­зовать­ся чем‑то более прос­тым и изящ­ным. Поэто­му я отпра­вил­ся в тем­ную кла­довую сво­ей памяти и нашел там пыль­ную шка­тул­ку с плос­ким мон­тажни­ком. Если кто‑то еще не догадал­ся, то так зву­чит по‑рус­ски Flat Assembler в вари­анте Яндекс‑перевод­чика. Уди­витель­но, но про­дукт, с которым я поз­накомил­ся еще в середи­не 2000-х, про­дол­жает жить и здравс­тво­вать.

ЧТО УМЕЕТ FLAT ASSEMBLER?

Да­вай пря­мо сей­час раз­берем­ся со сре­дой, в которой будем работать. На стра­нице заг­рузки выбери архив с пос­ледней вер­сией сбор­ки для Windows, заг­рузи его и рас­пакуй куда‑нибудь на диск. В трех мегабай­тах пап­ки FASMW есть все, что нам пот­ребу­ется.

Соз­дай пус­тую пап­ку Appbar для рабоче­го про­екта и ско­пируй в нее исходный текст шаб­лона типово­го при­ложе­ния Windows FASMW\EXAMPLES\TEMPLATE\TEMPLATE.ASM. Запус­ти интегри­рован­ную сре­ду раз­работ­ки FASMW\FASMW.EXE и с помощью пун­кта меню File → Open... заг­рузи в нее этот файл. Обра­ти вни­мание, что в нашем рас­поряже­нии есть тек­сто­вый мно­гоокон­ный редак­тор с под­свет­кой син­такси­са ассем­бле­ра.

Тек­сто­вый редак­тор интегри­рован­ной сре­ды FASMW

Шаб­лон Windows-при­ложе­ния на ассем­бле­ре сос­тоит из сле­дующих основных час­тей:

  • за­голов­ка с ука­зани­ем фор­мата целево­го исполня­емо­го фай­ла и точ­ки вхо­да в при­ложе­ние;
  • сек­ции кода .text, где мет­ка start ука­зыва­ет коман­ду, с которой дол­жно начинать­ся выпол­нение прог­раммы;
  • сек­ции дан­ных .data, содер­жащей гло­баль­ные перемен­ные прог­раммы;
  • сек­ции импорта .idata, в которой перечис­лены исполь­зуемые прог­раммой динами­чес­кие биб­лиоте­ки и под­клю­чают­ся объ­явле­ния содер­жащих­ся в них фун­кций.

В целом текст прог­раммы дол­жен быть понятен любому, кто исполь­зовал Win32 API. Во‑пер­вых, сам API пре­дель­но прост. Парамет­ры всех фун­кций ожи­дают 32-бит­ных зна­чений аргу­мен­тов, а если дан­ные не укла­дыва­ются в этот раз­мер, то переда­ется 32-бит­ный ука­затель на мас­сив или струк­туру опять же 32-бит­ных зна­чений. Исклю­чение, пожалуй, толь­ко стро­ки. Воз­вра­щаемое фун­кци­ей зна­чение (нап­ример, код завер­шения) переда­ется через регистр EAX или, если оно пре­выша­ет 32 бита, через струк­туру, на которую ука­зывал один из аргу­мен­тов.

Во‑вто­рых, Flat Assembler на осно­ве сво­его набора мак­роинс­трук­ций пред­лага­ет син­такси­чес­кий сахар, который дела­ет исполь­зование API мак­сималь­но приб­лижен­ным к высоко­уров­невым язы­кам прог­рамми­рова­ния. Ска­жем, доволь­но слож­ный вызов фун­кции соз­дания окна опи­сыва­ется одной стро­кой:

invoke CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU,128,128,256,192,NULL,NULL,[wc.hInstance],NULL

Здесь invoke — это коман­да вызова под­прог­раммы в соот­ветс­твии с сог­лашени­ем STDCALL, CreateWindowEx — имя вызыва­емой API-фун­кции, а далее через запятую сле­дуют аргу­мен­ты в том поряд­ке, в котором они опи­саны в докумен­тации. С‑прог­раммис­ты могут счи­тать, что име­на всех перемен­ных здесь — это ука­зате­ли (_class_title), для разыме­нова­ния которых исполь­зуют­ся квад­ратные скоб­ки ([wc.hInstance]). Отме­тим при­выч­ную «точеч­ную» нотацию дос­тупа к эле­мен­там струк­туры.

Опи­сание окон­ной про­цеду­ры WindowProc тоже не дол­жно выз­вать зат­рудне­ний:

proc WindowProc uses ebx esi edi, hwnd,wmsg,wparam,lparam

...

ret

endp

Сог­лашение Win32 API тре­бует, что­бы пос­ле воз­вра­та из про­цедур обратно­го вызова (callback-про­цедур) зна­чения регис­тров EBXESI и EDI были такими же, как и перед вызовом. Для это­го в заголов­ке при­сутс­тву­ет ука­зание на сох­ранение этих регис­тров в виде фра­зы uses ebx esi edi. А даль­ше через запятую идет спи­сок фор­маль­ных парамет­ров про­цеду­ры, которые соот­ветс­тву­ют докумен­тации.

Те­перь ты можешь ском­пилиро­вать и выпол­нить эту прог­рамму. Но сна­чала ука­жи путь к пап­ке с под­клю­чаемы­ми дирек­тивой include фай­лами в пун­кте меню Options → Compiler setup так, что­бы он соот­ветс­тво­вал фак­тичес­кому мес­тополо­жению FASMW\INCLUDE. Пос­ле это­го выпол­ни пункт меню Run → Run или прос­то наж­ми кла­вишу F9. Если все было сде­лано пра­виль­но, то в рабочей пап­ке Appbar появит­ся све­жесоб­ранный файл TEMPLATE.EXE, а на экра­не отоб­разит­ся кро­шеч­ное окно Win32 program template.

Нас­трой­ка пути к под­клю­чаемым фай­лам

СОЗДАНИЕ ОБРАБОТЧИКА СООБЩЕНИЯ WM_CREATE

Со сре­дой раз­работ­ки разоб­рались, прис­тупим к работе над прог­раммой. Если рань­ше ты никог­да не прог­рамми­ровал панели рабоче­го сто­ла Windows, то сей­час самое вре­мя изу­чить докумен­тацию. Но перед этим хочу обра­тить вни­мание на основные момен­ты. Панель рабоче­го сто­ла не явля­ется каким‑то уни­каль­ным объ­ектом опе­раци­онной сис­темы. Роль панели может играть любое окно, соз­данное фун­кци­ей CreateWindowEx. Все средс­тва Windows, обес­печива­ющие фун­кци­они­рова­ние панели, сос­редото­чены в единс­твен­ной фун­кции SHAppBarMessage, с помощью которой мож­но:

  • уз­нать гра­ницы области рабоче­го сто­ла, в пре­делах которых мож­но раз­местить новую панель инс­тру­мен­тов;
  • за­резер­вировать на этой области учас­ток для раз­мещения новой панели;
  • ука­зать манипу­лятор (handle) окна с панелью, которо­му будут отправ­лять­ся сис­темные уве­дом­ления, свя­зан­ные с изме­нени­ем обста­нов­ки на рабочем сто­ле.

Пос­ле резер­вирова­ния новой области опе­раци­онная сис­тема зап­реща­ет ее исполь­зование окна­ми при­ложе­ний при их мак­симиза­ции, осво­бож­дает от знач­ков рабоче­го сто­ла (если таковые на ней были) — и, в общем‑то, всё. За внеш­ний вид панели отве­чает ассо­цииро­ван­ное с нею окно, которое теоре­тичес­ки дол­жно зак­рыть собой осво­бож­денное прос­транс­тво и при­нять соот­ветс­тву­ющий стиль. Но по боль­шому сче­ту может это­го и не делать.

С помощью пун­кта меню File → Save as... сох­рани откры­тый в редак­торе файл под име­нем appbar.asm. В нашей прог­рамме панелью будет глав­ное окно при­ложе­ния. Зарезер­виру­ем для нее полосу в вер­хней час­ти рабоче­го сто­ла. Это мож­но сде­лать в обра­бот­чике со­обще­ния WM_CREATE, которое отправ­ляет­ся опе­раци­онной сис­темой окну при­ложе­ния непос­редс­твен­но перед тем, как отоб­разить его на экра­не. Для это­го в начале окон­ной про­цеду­ры WindowProc вста­вим стро­ки перехо­да к обра­бот­чику сооб­щения:

cmp [wmsg],WM_CREATE

je .wmcreate

и напишем сам обра­бот­чик перед мет­кой .wmdestroy:

.wmcreate:

stdcall wmCreateProc, [hwnd]

jmp .finish

INFO

Мет­ки, которые начина­ются с точ­ки, явля­ются локаль­ными по отно­шению к про­цеду­ре, где они исполь­зуют­ся (в дан­ном слу­чае — WindowProc). Это еще одна фиш­ка Flat Assembler, которая поз­воля­ет не бес­поко­ить­ся о том, что в раз­ных про­цеду­рах име­на меток могут пов­торять­ся.

Наш обра­бот­чик вызыва­ет пока еще не сущес­тву­ющую про­цеду­ру wmCreateProc и переда­ет ей зна­чение манипу­лято­ра соз­данно­го окна. В этой про­цеду­ре надо опи­сать дей­ствия по резер­вирова­нию полосы и позици­они­рова­нию глав­ного окна, пос­ле чего обну­лить регистр EAX для сиг­нализи­рова­ния об успешном завер­шении про­цеду­ры. Если пос­ле обра­бот­ки сооб­щения WM_CREATE зна­чение регис­тра EAX будет рав­но (-1), опе­раци­онная сис­тема вос­при­мет это как сиг­нал о проб­леме, что при­ведет к завер­шению работы прог­раммы. Текст про­цеду­ры wmCreateProc мож­но раз­местить пос­ле опе­рато­ра endp, зак­рыва­юще­го блок опи­сания окон­ной про­цеду­ры WindowProc:

proc wmCreateProc,hwnd

invoke MessageBox,[hwnd],_title,_class,MB_OK+MB_ICONINFORMATION

xor eax,eax

ret

endp

INFO

Вот про­межу­точ­ный вари­ант прог­раммы, который выводит отла­доч­ное сооб­щение: appbar-ver1.asm.

Про­цеду­ра wmCreateProc в таком виде не дела­ет ничего полез­ного, но при запус­ке прог­раммы выводит окно с информа­цион­ным сооб­щени­ем, которое дает понять, что на этом эта­пе все работа­ет так, как ожи­дает­ся.

INFO

Вни­матель­но сле­ди за тем, что­бы количес­тво и порядок аргу­мен­тов в коман­де вызова про­цеду­ры всег­да соот­ветс­тво­вали количес­тву и поряд­ку парамет­ров в ее опи­сании. FASMW это не кон­тро­лиру­ет, и, если допус­тить неб­режность, мож­но получить труд­но обна­ружи­ваемые ошиб­ки.

ПОДГОТОВКА К ИСПОЛЬЗОВАНИЮ ФУНКЦИИ SHAPPBARMESSAGE

Прог­рамма и опе­раци­онная сис­тема догова­рива­ются о резер­вирова­нии прос­транс­тва для панели инс­тру­мен­тов с помощью фун­кции SHAppBarMessage через струк­туру APPBARDATA. Опре­деле­ние этой струк­туры отсутс­тву­ет в под­клю­чаемых фай­лах из пос­тавки FASMW, поэто­му при­дет­ся соз­дать его самому на осно­ве докумен­тации. Помес­тим его в отдель­ном фай­ле. Для это­го выбери пункт меню File → New и на открыв­шей­ся вклад­ке тек­сто­вого редак­тора набери сле­дующее:

struct APPBARDATA

cbSize dd ?

hWnd dd ?

uCallbackMessage dd ?

uEdge dd ?

rc RECT

lParam dd ?

ends

Так выг­лядит опи­сание типа струк­туры в Flat Assembler. Пос­ле наз­вания поля сле­дует спе­цифи­катор типа (dd озна­чает 4-бай­товое двой­ное сло­во, а знак воп­роса — неоп­ределен­ное зна­чение), в качес­тве которо­го, в свою оче­редь, может исполь­зовать­ся имя извес­тной струк­туры (нап­ример, RECT). Что­бы не воз­вра­щать­ся к дан­ному воп­росу еще раз, в этот же файл мож­но дописать опре­деле­ния кон­стант, которые исполь­зуют­ся фун­кци­ей SHAppBarMessage:

ABM_NEW = 0x0

ABM_REMOVE = 0x1

ABM_QUERYPOS = 0x2

ABM_SETPOS = 0x3

ABE_LEFT = 0

ABE_TOP = 1

ABE_RIGHT = 2

ABE_BOTTOM = 3

MSG_ABNOTIFY = WM_USER+1

APPBAR_THICKNESS = 64

Кон­стан­ты с пре­фик­сом ABM_ пред­став­ляют собой коды услуг, зап­рашива­емых у опе­раци­онной сис­темы, а с пре­фик­сом ABE_ озна­чают гра­ницы рабоче­го сто­ла, у которых пред­полага­ется раз­мещение панели. Кон­стан­та MSG_ABNOTIFY соот­ветс­тву­ет «поль­зователь­ско­му» (то есть нес­тандар­тно­му, выбира­емо­му прог­раммис­том) иден­тифика­тору сооб­щения, который мы пред­ложим исполь­зовать опе­раци­онной сис­теме при отправ­ке уве­дом­лений окну панели инс­тру­мен­тов. Тут же опре­делим кон­стан­ту APPBAR_THICKNESS с жела­емым зна­чени­ем ширины панели.

Сох­рани наб­ранный текст в фай­ле с име­нем appbar.inc с помощью пун­кта меню File → Save As...

INFO

Под­клю­чаемый файл с объ­явле­нием струк­туры APPBARDATA и опре­деле­ниями кон­стант: appbar.inc.

Те­перь вер­нись к редак­тирова­нию фай­ла appbar.asm с тек­стом прог­раммы (для это­го можешь нажать сочета­ние кла­виш Ctrl-Tab) и в его начале перед сек­цией кода вставь стро­ку под­клю­чения под­готов­ленных опи­саний:

include 'appbar.inc'

INFO

Пос­ле вне­сения в текст прог­раммы закон­ченной пор­ции изме­нений (как, нап­ример, сей­час) про­веряй, ком­пилиру­ется ли она. При этом сле­ди, что­бы активной в тек­сто­вом редак­торе была вклад­ка с основным тек­стом прог­раммы, а не под­клю­чаемым модулем. Если FASM сооб­щает об ошиб­ке, надо переп­роверить пос­ледние изме­нения и устра­нить ошиб­ку преж­де, чем дви­гать­ся даль­ше.

Сей­час, ког­да у нас есть объ­явле­ние типа APPBARDATA, мы можем опре­делить гло­баль­ную перемен­ную abd это­го типа, для чего в сек­цию дан­ных сле­дует добавить такую стро­ку:

abd APPBARDATA sizeof.APPBARDATA, 0, MSG_ABNOTIFY, ABE_TOP, <0, 0, 0, 0>, 0

Эта стро­ка сов­меща­ет опре­деле­ние перемен­ной (при котором резер­виру­ется память) с ее ини­циали­заци­ей (при которой полям прис­ваивают­ся началь­ные зна­чения). Обра­ти вни­мание, что ини­циали­затор поля вло­жен­ной струк­туры abd.rc зак­лючен в угло­вые скоб­ки. Мак­рооп­ределе­ния FASM поз­воля­ют ука­зать раз­мер струк­туры APPBARDATA с помощью конс­трук­ции sizeof.APPBARDATA.

Фун­кция SHAppBarMessage находит­ся в сис­темной динами­чес­кой биб­лиоте­ке Shell32.dll. Поэто­му пот­ребу­ется добавить стро­ки в сек­цию импорта, в резуль­тате чего она при­обре­тет сле­дующий вид:

section '.idata' import data readable writeable

library kernel32,'KERNEL32.DLL',\

user32,'USER32.DLL',\

shell32,'SHELL32.DLL'

include 'api\kernel32.inc'

include 'api\user32.inc'

include 'api\shell32.inc'

INFO

Что­бы узнать, в какой динами­чес­кой биб­лиоте­ке находит­ся фун­кция Win32 API, надо открыть на офи­циаль­ном сай­те Microsoft стра­ницу докумен­тации с опи­сани­ем этой фун­кции и бли­же к кон­цу стра­ницы отыс­кать сек­цию Requirements. Из этой сек­ции мож­но узнать минималь­ную под­держи­ваемую вер­сию Windows (Minimum supported client/server), имя заголо­воч­ного фай­ла для язы­ка прог­рамми­рова­ния С с объ­явле­нием этой фун­кции (Header, *.h), ста­тичес­кую биб­лиоте­ку, которую надо под­клю­чить к исполня­емо­му фай­лу для исполь­зования фун­кции (Library, *.lib), и, наконец, имя фай­ла динами­чес­кой биб­лиоте­ки (DLL, *.dll).

Убе­дись, что прог­рамма ком­пилиру­ется и работа­ет.

INFO

Про­межу­точ­ный вари­ант прог­раммы со все­ми пред­варитель­ными объ­явле­ниями и опре­деле­ниями: appbar-ver2.asm.

РЕЗЕРВИРОВАНИЕ ПЛОЩАДКИ ДЛЯ ПАНЕЛИ

Под­готови­тель­ные мероп­риятия закон­чены, мы на финиш­ной пря­мой. Не запус­кай прог­рамму, пока я не ска­жу. Для про­вер­ки син­такси­са можешь пери­оди­чес­ки ком­пилиро­вать исходный текст в исполня­емый файл через пункт меню Run → Compile, но прог­рамму не запус­кай!

Вер­немся к бло­ку с про­цеду­рой wmCreateProc, уда­лим из него стро­ку вывода отла­доч­ного сооб­щения и напол­ним при­ложе­ние смыс­лом. В соот­ветс­твии с докумен­таци­ей, сна­чала дек­лариру­ем желание соз­дать панель инс­тру­мен­тов рабоче­го сто­ла, для чего вызовем фун­кцию SHAppBarMessage с сооб­щени­ем ABM_NEW и струк­турой APPBARDATA, в которой запол­нены поля cbSizeuCallbackMessage (при ини­циали­зации перемен­ной) и hWnd (непос­редс­твен­но перед вызовом фун­кции):

proc wmCreateProc,hwnd

mov eax, [hwnd]

mov [abd.hWnd], eax

invoke SHAppBarMessage, ABM_NEW, abd

cmp eax, TRUE

je @f

mov eax, -1

ret

@@:

Здесь мы впер­вые стал­кива­емся с огра­ниче­нием ассем­бле­ра, которое не поз­воля­ет нап­рямую пересы­лать дан­ные из одной ячей­ки памяти в дру­гую, в резуль­тате чего нам приш­лось вос­поль­зовать­ся регис­тром EAX в качес­тве про­межу­точ­ного хра­нили­ща. Пос­ле вызова фун­кции про­веря­ем воз­вра­щен­ное ею зна­чение. Если опе­раци­онная сис­тема не воз­ража­ет про­тив исполь­зования окна в качес­тве панели, то регистр EAX будет содер­жать TRUE.

Flat Assembler пред­лага­ет удоб­ную сис­тему локаль­ных меток для корот­ких перехо­дов, которая поз­воля­ет «переп­рыгивать» через нес­коль­ко команд при подоб­ных про­вер­ках. Так, коман­да je @f совер­шит переход на бли­жай­шую сле­дующую мет­ку @@ в слу­чае получе­ния равенс­тва при пре­дыду­щем срав­нении cmp eax, TRUE. Если надо совер­шить переход на бли­жай­шую пре­дыду­щую мет­ку @@, то в коман­де перехо­да надо ука­зать @b.

Та­ким обра­зом, в слу­чае неравенс­тва в регистр EAX будет записа­но зна­чение (-1) и воз­вра­щено опе­раци­онной сис­теме. Она, как было отме­чено выше, вос­при­мет его в качес­тве приз­нака проб­лемы при обра­бот­ке сооб­щения WM_CREATE, что при­ведет к завер­шению работы при­ложе­ния.

Зап­росим у Windows гра­ницы рабоче­го сто­ла, в пре­делах которых мож­но раз­местить панель. Без лиш­ней скром­ности отпра­вим заяв­ку через abd.rc на весь раз­мер экра­на, а опе­раци­онная сис­тема при­ведет зна­чения полей струк­туры RECT в соот­ветс­твие реаль­ной обста­нов­ке. Для это­го узна­ем у сис­темы, а потом запишем в abd.rc.right ширину экра­на, умень­шен­ную на еди­ницу, а в abd.rc.bottom — умень­шен­ную на еди­ницу высоту экра­на, пос­ле чего вызовем фун­кцию SHAppBarMessage с сооб­щени­ем ABM_QUERYPOS.

invoke GetSystemMetrics, SM_CXSCREEN

dec eax

mov [abd.rc.right], eax

invoke GetSystemMetrics, SM_CYSCREEN

dec eax

mov [abd.rc.bottom], eax

invoke SHAppBarMessage, ABM_QUERYPOS, abd

Пос­ле воз­вра­та в струк­туре abd.rc будут находить­ся гра­ницы допус­тимой области. Нам же нуж­на толь­ко полоса шириной APPBAR_THICKNESS у вер­хне­го края рабоче­го сто­ла. Поэто­му под­тянем вверх ниж­нюю коор­динату и зат­ребу­ем у опе­раци­онной сис­темы получив­шуюся полосу через вызов фун­кции SHAppBarMessage с сооб­щени­ем ABM_SETPOS:

mov eax, [abd.rc.top]

add eax, APPBAR_THICKNESS

dec eax

mov [abd.rc.bottom], eax

invoke SHAppBarMessage, ABM_SETPOS, abd

xor eax,eax

ret

endp

В кон­це про­цеду­ры оставля­ем обну­ление регис­тра EAX коман­дой xor eax,eax и воз­врат это­го нулево­го зна­чения опе­раци­онной сис­теме, которое она вос­при­мет как успешное завер­шение обра­бот­чика WM_CREATE.

По­ка пред­положим, что мы все сде­лали пра­виль­но. Резуль­татом выпол­нения перечис­ленных дей­ствий дол­жно стать отре­зание полосы от вер­хней гра­ницы рабоче­го сто­ла. Если запус­тить прог­рамму в таком виде, то зарезер­вирован­ная область оста­нет­ся «не у дел» даже пос­ле ее завер­шения и при­дет­ся перезаг­ружать компь­ютер. Мы дол­жны явным обра­зом вер­нуть опе­раци­онной сис­теме получен­ную во вре­мен­ное поль­зование полосу, для чего допол­ним в окон­ной про­цеду­ре WindowProc блок обра­бот­ки сооб­щения WM_DESTROY сле­дующей стро­кой (ее надо вста­вить сра­зу пос­ле мет­ки .wmdestroy):

invoke SHAppBarMessage, ABM_REMOVE, abd

INFO

Про­межу­точ­ный вари­ант прог­раммы, который уме­ет резер­вировать и осво­бож­дать учас­ток рабоче­го сто­ла: appbar-ver3.asm.

А вот теперь мож­но и даже нуж­но запус­тить получив­шуюся прог­рамму и пос­мотреть, как она работа­ет. Про­буй переме­щать окна при­ложе­ний, раз­ворачи­вать их на весь экран и смот­ри, как они себя при этом ведут. Обра­ти вни­мание, что глав­ное окно получив­шей­ся прог­раммы сущес­тву­ет как буд­то отдель­но от зарезер­вирован­ной им на рабочем сто­ле полосы. При завер­шении прог­раммы ситу­ация на рабочем сто­ле дол­жна вос­ста­нав­ливать­ся. Если оста­ются какие‑то осо­бен­ности, то перезаг­рузи компь­ютер и вни­матель­но про­верь прог­рамму.

НАСТРОЙКА ОКНА ПАНЕЛИ

Ос­талось толь­ко при­вес­ти глав­ное окно нашего при­ложе­ния в соот­ветс­твие с его задачей. Для это­го, во‑пер­вых, под­пра­вим сти­ли окна в стро­ке с вызовом фун­кции CreateWindowEx сле­дующим обра­зом:

invoke CreateWindowEx,WS_EX_TOPMOST+WS_EX_TOOLWINDOW,_class,_title,WS_POPUP,128,128,256,192,NULL,NULL,[wc.hInstance],NULL

А во‑вто­рых, допол­ним про­цеду­ру wmCreateProc стро­ками, выпол­няющи­ми позици­они­рова­ние окна на зарезер­вирован­ной полосе рабоче­го сто­ла. Для это­го сра­зу пос­ле ее заголов­ка помес­тим стро­ку опре­деле­ния локаль­ных перемен­ных:

local width:DWORD, height:DWORD

Пос­ле име­ни перемен­ной через дво­ето­чие ука­зан ее тип (как в пас­кале). Ана­логич­ным обра­зом мож­но ука­зывать типы парамет­ров про­цедур. Мы это­го не делали, потому что нас устра­ивает 32-бит­ный тип, пред­полага­емый по умол­чанию. Стро­ки вычис­ления раз­меров и переме­щения окна надо раз­местить в кон­це про­цеду­ры перед фор­мирова­нием воз­вра­щаемо­го зна­чения в регис­тре EAX:

mov eax, [abd.rc.right]

sub eax, [abd.rc.left]

inc eax

mov [width], eax

mov eax, [abd.rc.bottom]

sub eax, [abd.rc.top]

inc eax

mov [height], eax

invoke SetWindowPos, [hwnd], HWND_TOP, [abd.rc.left], [abd.rc.top], [width], [height], SWP_NOACTIVATE+SWP_SHOWWINDOW

INFO

Окон­чатель­ный вари­ант прог­раммы: appbar.asm.

За­пус­ти получив­шееся при­ложе­ние. Мес­то зарезер­вирован­ной полосы рабоче­го сто­ла дол­жно занять серое окно без рамок и заголов­ка — наша зап­латка. Не пытай­ся завер­шить прог­рамму через дис­петчер задач, потому что зарезер­вирован­ная часть рабоче­го сто­ла в этом слу­чае не осво­бодит­ся. Вмес­то это­го щел­кни левой кноп­кой мыши по этой полосе и наж­ми ком­бинацию кла­виш Alt-F4. Прог­рамма завер­шится, а рабочий стол вер­нется в исходное сос­тояние.

ЗАКЛЮЧЕНИЕ

Так мне уда­лось устра­нить глав­ное неудобс­тво от дефек­та монито­ра при исполь­зовании раз­верну­тых на весь экран при­ложе­ний. Попут­но мы узна­ли о том, как соз­дать свою панель инс­тру­мен­тов для рабоче­го сто­ла Windows.

Раз­работан­ное при­ложе­ние мож­но взять в качес­тве заготов­ки для более фун­кци­ональ­ной панели, а не такой, которая, как кар­тина в муль­тфиль­ме про дядю Федора, «дыр­ку на обо­ях загора­жива­ет». В качес­тве панели исполь­зовано глав­ное окно при­ложе­ния, что поз­воля­ет добавить на него эле­мен­ты управле­ния, текст, рисун­ки... Но пер­вым делом я бы добавил защиту от пов­торно­го запус­ка прог­раммы (для это­го надо вос­поль­зовать­ся име­нован­ным мьютек­сом, который соз­дает­ся с помощью фун­кции CreateMutex). Не помеша­ет добавить и реаги­рова­ние на уве­дом­ления MSG_ABNOTIFY — их может отправ­лять нашему окну опе­раци­онная сис­тема (нап­ример, при запус­ке пол­ноэк­ранно­го при­ложе­ния или активнос­ти сосед­них панелей).

А вот выб­ранный инс­тру­мент раз­работ­ки Flat Assembler с ассем­бле­ром в качес­тве язы­ка прог­рамми­рова­ния оставля­ет про­тиво­речи­вые чувс­тва. К положи­тель­ным чер­там мож­но отнести:

  • ком­пак­тный раз­мер и быс­трое раз­верты­вание на любом Windows-компь­юте­ре;
  • воз­можность пол­ноцен­но исполь­зовать методо­логию струк­турно­го прог­рамми­рова­ния бла­года­ря мак­рооп­ределе­ниям, что прак­тичес­ки сни­мает огра­ниче­ние на слож­ность про­ектов;
  • оди­нако­вая работа при­ложе­ний на всей линей­ке Windows от Windows 2000 до Windows 10 x86-64 бла­года­ря исполь­зованию Win32 API;
  • ма­лый раз­мер генери­руемых EXE-фай­лов (раз­работан­ное в статье при­ложе­ние занима­ет 2,5 Кбайт на дис­ке).

Спор­ные момен­ты, на мой взгляд, сле­дующие:

  • жес­ткая при­вяз­ка к архи­тек­туре про­цес­соров Intel;
  • сла­бая «защита от дурака» (прак­тичес­ки отсутс­тву­ет кон­троль типов перемен­ных и соот­ветс­твия фак­тичес­ких аргу­мен­тов при вызове фун­кций объ­явленным фор­маль­ным парамет­рам).

Как бы то ни было, с исполь­зовани­ем Flat Assembler впол­не мож­но изу­чать осно­вы прог­рамми­рова­ния на ассем­бле­ре для архи­тек­туры х86. Этот инс­тру­мент поможет осво­ить син­таксис и основные конс­трук­ции язы­ка всем, кто еще не стал­кивал­ся с ассем­бле­ром, но жела­ет исполь­зовать его в будущем для соз­дания собс­твен­ных при­ложе­ний.

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page