Привіт і ласкаво просимо назад.
У цьому уроці ми продовжимо вивчення Windows API.
Цього разу ми напишемо програму під назвою String Echo, і ця програма, коли її буде запущено, чекатиме на ваше
введення.
Отже, якщо я наберу "Hello World" і натисну Enter, система відлунить у відповідь введений мною рядок: "Hello
World! А назва програми
у написаному вигляді звучить як 77-String-Echo. exe.
І ця програма використовує всі ці API:
GetStdHandle, ReadFile, WriteFile та ExitProcess.
Розглянемо кожну з них докладніше, і навіщо вони нам потрібні.
Отже, GetStdHandle використовується для отримання хендла для входу і для виходу.
Тепер ручка - це просто посилання на клавіатуру, а також посилання на термінал.
Отже, вам потрібно навчитися працювати з клавіатурою, тому що ви використовуєте її для введення даних.
Отже, GetStdHandle поверне вам дескриптор клавіатури.
Щоб використати його, ви натискаєте від'ємне число десять.
Параметр для GetStdHandle.
Потім ви викликаєте API GetStdHandle.
Потім він поверне хендл у -, і ви збережете - у цьому сегменті пам'яті BSS.
Отже, тепер у вас є ручка до клавіатури.
Далі ви повторюєте те саме, щоб отримати хендл для виводу.
Але цього разу ми натискаємо -11.
Це означає, що параметр функції дорівнює -11.
І це поверне хендл на вихід, який є вашим терміналом.
Ви можете отримати більше інформації, звернувшись до MSDN за цим посиланням.
GetStdHandle.
Якщо ваш параметр від'ємний, то ви отримуєте пристрій введення, яким зазвичай є клавіатура.
Якщо ваш параметр дорівнює -11, то ви отримуєте пристрій виводу, яким є ваш термінал.
Отже, як тільки ви отримали хендл і зберегли його у відповідному місці, яке знаходиться
у вашій пам'яті BSS тут і в цій пам'яті тут, пізніше ви можете використовувати ці дві області пам'яті
як параметри для ваших ReadFile і WriteFile.
Тепер перейдемо до ReadFile.
Мета ReadFile - зчитувати з клавіатури все, що вводить користувач, і має наступні параметри.
І давайте звернемося до MSDN, щоб краще зрозуміти.
Отже, ReadFile має всі ці параметри.
Ми використовуємо всі, окрім останнього.
Ми залишаємо його порожнім.
За це ми ставимо нуль.
Отже, перший параметр - це ваш хендл.
Отже, якщо ви читаєте з клавіатури, то вашим hFile тут буде те, що ви отримали у результаті виконання функції Get StdHandle
для введення.
Отже, ви повинні передати цю адресу пам'яті, яка містить дескриптор клавіатури.
Тож це буде передано тут.
А другий параметр - це буфер.
Отже, ваш буфер - це місце, де ви збираєтеся зберігати вхідні дані.
Як ви можете бачити тут, вказівник на буфер, який приймає дані, що зчитуються з пристрою.
Отже, це другий параметр.
Тоді третій параметр - це кількість байт для зчитування.
Отже, в цьому випадку тут ви ставите третій параметр.
NumberOfBytesToRead - максимальний розмір вхідних даних.
Отже, для нашої мети ми поставили гекс 20, що в десятковій системі числення дорівнює 32.
Наступним параметром буде кількість прочитаних байт.
Отже, це кількість байт, яку ви вводите.
Ось тут, якщо ви введете "Hello World", то кількість прочитаних байт дорівнюватиме 11.
Цей параметр.
Наступний параметр - overlapped, який ми залишимо нульовим.
Якщо ви реалізуєте це у збірці, вам доведеться виштовхувати його до стеку у зворотному порядку.
Це означає, що ви штовхаєте знизу вгору.
Ось як це виглядає, коли ви штовхаєте знизу вгору.
Спочатку ви натискаєте нуль для цього перекриття.
Нуль означає нуль.
Це означає, що ви не використовуєте цей параметр.
Далі ви виштовхуєте байт, який є цією адресою в пам'яті.
Далі ви натискаєте максимальний розмір вхідних даних, а саме цей.
Максимальний розмір вхідних даних - це кількість байт для читання.
Потім ви натискаєте рядок вводу.
Ваш вхідний рядок - це ваш буфер.
Це місце, де будуть зберігатися ваші дані.
Якщо ви введете "Hello World", його буде збережено тут, у цьому місці, у рядку
введення.
Потім ви натискаєте на пристрій введення, який є дескриптором файлу для вашої клавіатури.
Нарешті, ви викликаєте ReadFile API.
Зараз це ReadFile API, пізніше
я покажу вам, де його взяти.
Далі ви повторюєте те саме.
Тепер ви виведете на консоль все, що ввів користувач.
Отже, це API для цього, і давайте звернемося
до нього.
Він отримує ці параметри, і знову
ж таки, останній з них не використовується.
Тому ми ставимо нуль за це.
Перший параметр - це дескриптор на вихід, яким є ваш термінал.
І це буде стосуватися того, що ви отримаєте назад звідси.
Коли ви викликаєте GetStdHandle і передаєте -11, він поверне вам хендл терміналу, пристрою
виводу.
І це те, що ви передаєте тут.
Потім ви проходите буфер.
Буфер - це адреса, за якою ви зберігаєте рядок "Hello
World. І цей буфер
має бути таким самим, як і буфер, який ми використовуємо тут.
Далі ви передаєте кількість байт для запису, а кількість байт для запису - це фактично кількість байт,
яку ви тут зчитали.
Отже, це має бути та сама адреса, де ви зберігали це значення.
Після цього, кількість записаних байт - це кількість байт, яка фактично буде записана на екран.
І, нарешті, ви ставите нуль.
Якщо ви впроваджуєте це знову, вам потрібно виконати це у зворотному порядку.
Тож ти штовхаєш знизу вгору.
Отже, спочатку ви ставите нуль.
Потім ви натискаєте записані байти.
Ви натискаєте байти для запису, а байти для запису - це фактично та сама адреса, що й адреса для кількості прочитаних
байт, коли ви викликаєте
ReadFile.
Отже, коли ви викликаєте ReadFile, ви будете зберігати кількість прочитаних байт за цією адресою.
Отже, ця адреса має збігатися з цією адресою тут.
Ось цей.
Тут ви отримуєте доступ до кількості байт, які ви прочитали, щоб ви могли використати цю ж кількість для виведення.
Коли ви пишете файл, він має бути однаковим.
Припустимо, що кількість прочитаних байт дорівнює 11, оскільки ваш рядок "Hello World", а "Hello World"
має 11 байт.
Отже, сюди ви також повинні додати 11 байт, щоб WriteFile знав, скільки байт
очікувати, а це теж 11.
Ось чому тут ви отримуєте доступ до адреси; тут ви зберігаєте за адресою.
Гаразд.
Отже, тут адреса використовується викликаним API.
Коли ви викликаєте API, він записує кількість байт, прочитаних за цією адресою,
а тут ви отримуєте доступ до кількості байт, прочитаних
з цієї ж адреси.
Далі ви натискаєте вхідний рядок,
місце у пам'яті, де зберігається рядок "Hello World", і воно має збігатися з вхідним
рядком тут.
Ось цей.
Тож "Hello World" зберігається тут.
Коли ви читаєте файл, ви зберігаєте "Hello World" тут, і тепер функція WriteFile
має доступ до тієї самої ділянки пам'яті, щоб отримати рядок "Hello World".
Далі ви маєте вказати тип пристрою, на який ви виводите дані.
У цьому випадку це ваш термінал.
Отже, це буде ваше ім'я, яке ви отримаєте, коли зателефонуєте сюди.
А це адреса, за якою ви зберігаєте хендл виводу,
0x405050.
Отже, тут ви також повинні пройти те ж
саме, 0x405050.
Нарешті, ви викликаєте API WriteFile.
Гаразд, в наступному уроці ми розглянемо практикум, де все це буде виконано
в x64dbg.
Тож до наступної зустрічі.
Дякуємо за перегляд.