З поверненням.
Тепер давайте розглянемо наш практичний посібник з реалізації всіх цих API.
Тож давайте перейдемо до місця, де я зберігав цю програму, 77-String-Echo, і спочатку запустимо її, щоб ви зрозуміли,
як вона працює.
Тому я просто клацну правою кнопкою миші тут, відкрию термінал.
І тепер, якщо ви введете dir, ви побачите всі файли в цьому каталозі.
І це та програма, яку ми збираємося запустити.
Дозвольте мені спочатку очистити екран, а потім запустити програму.
Натисніть 77 і натисніть Tab для автозавершення.
Потім натисніть Enter.
Програма запущена і чекає на ваше введення.
Тож я набираю "Hello World. Космос.
Тепер я натисну Enter, і він відлунням повернеться до набраного мною рядка: "Hello
World. Отже, ось як
це працює, а тепер
давайте запустимо його в x64dbg.
Отже, відкриваємо x64dbg.
Відкриваємо файл.
І давайте подивимося на місце, де я це написав.
Перед тим, як щось робити, потрібно спочатку спланувати.
Якщо ви збираєтесь писати програму самостійно, вам потрібно спочатку спланувати, де ви збираєтесь використовувати
пам'ять, яку саме.
Всю цю пам'ять, яку я тут використовую, перейдіть на Карту пам'яті і натисніть на сегмент BSS, неініціалізовані дані.
Тут зберігаються всі ваші змінні.
Тож двічі клацніть на цьому, і ви перейдете до цієї сторінки.
Тож ви повинні планувати заздалегідь, гаразд?
Припустимо, я хочу використати одну пам'ять для зберігання результату виклику GetStdHandle.
Тому я мушу використовувати цю локацію.
Потім, коли я викликаю GetStdHandle вдруге, я хочу зберегти його в іншому місці.
Я використаю це місце тут.
Потім, коли я викликаю ReadFile, я буду використовувати все це розташування.
Я буду використовувати наступну адресу тут,
все це.
Тож саме так ми повинні планувати наперед.
Коли ви пишете код, завжди плануйте наперед.
По-перше, візьміть аркуш блокноту і запишіть всі ці комірки пам'яті у вашому сегменті BSS.
Тоді починай кодувати.
Отже, для першої функції я використаю GetStdHandle, щоб отримати дескриптор до клавіатури.
Тепер, якщо ви повернетесь до PowerPoint,
ви помітите, що тут двічі викликається GetStdHandle.
Перший раз - це прикласти ручку до клавіатури.
І за це я ставлю мінус десять.
Отже, в гексі все це позначається від'ємною десяткою.
Тепер, коли ви вводите це число, все, що вам потрібно зробити, це натиснути від'ємне число десять, і воно автоматично перетвориться
на шістнадцяткове. Бачиш?
Тож вам не доведеться вигадувати, що написати для від'ємного
десятка.
Те ж саме тут.
Якщо ви хочете ввести -11, просто введіть -11.
Коли ви збираєте його, він автоматично перетворюється на гекс для вас.
Гаразд.
Тож повертаємося до першого.
Отже, коли ви натискаєте від'ємне число десять, це означає, що ви хочете отримати пристрій введення.
Тоді при виклику GetStdHandle ви отримаєте хендл пристрою введення і збережете його в -.
Гаразд.
Кожна функція повертає результат у вигляді -.
Пам'ятай про це. Тепер вам потрібно десь зберігати цю ручку, так?
Тож ви зберігаєте його в цьому місці.
Тож давайте запустимо його. Тепер, коли ви біжите, я ставлю там точку зупинки і біжу, переступаю, виштовхую в стек від'ємні
десять.
І коли я називаю це, переступаю через це, я натискаю на ручку -.
Тепер мені потрібно зберегти цей хендл у змінній.
Тому я зберігатиму його
тут, 0x405040. Бачиш?
0x405040, так.
Тож я переступаю, і тепер цей B4 зберігається тут,
0x405040, B4.
Це буде моя ручка для клавіатури.
Далі я відкладаю у стек від'ємні одинадцять.
А потім я знову викличу GetStdHandle, щоб отримати дескриптор виводу.
Таким чином, дескриптор виводу знову буде повернуто у -.
Тож давайте подивимось на -.
А тепер у мене B8.
Це буде ручка для вашого терміналу.
Тепер тобі треба десь його зберігати, гаразд?
Тому я виберу 0x405050, яка є наступною адресою після цієї.
Отже, коли я переступаю через нього, цей дескриптор виводу B8 зберігається тут, B8, як ви можете бачити.
Далі, я готовий
зателефонувати.
Я збираюся викликати ReadFile, і я збираюся виштовхнути всі параметри для ReadFile в стек.
Отже, параметри ReadFile виглядають наступним чином.
Як бачите.
Тож я штовхаю нуль до стеку.
Я натискаю 0x405060, тобто кількість записаних байт.
Вибач.
Це WriteFile.
Гаразд. Наступний.
Я натискаю 0x405060 - це прочитані байти.
Тож я штовхаю це до стопки.
Потім я натискаю максимальну кількість байт на вході, яка дорівнює hex 20, що фактично дорівнює 32 в десятковій системі числення.
Потім я натисну 0x405070, який є вашим вхідним рядком.
Тож я використовую всі ці доступні місця послідовно.
Ви можете побачити 0x405060 тут.
0x405070 - наступний, і так далі.
Тож я переступив через це.
Тепер я натисну
ось це, 0x405040. Отже, 0x405040 - це ваш пристрій введення, який є ручкою клавіатури.
Отже, коли я переступаю через нього, він отримає це з цієї адреси.
0x405040 насправді є B4.
Так.
Отже, він виштовхне B4 до стеку.
Ви бачите, що B4 тепер у стеку.
Потім ви викликаєте ReadFile.
Отже, ReadFile буде читати з пристрою введення, яким є ваша клавіатура.
Отже, коли ви переступите через нього, він викличе ReadFile
і збереже ваш вхідний рядок у файлі 0x405070, який знаходиться тут.
Тож тепер, коли я переступаю через нього, він переходить у стан
запуску і чекає, поки я кудись ввійду.
Тож тепер вона чекає, поки я щось введу.
Тож я натискаю сюди і набираю "Hello World. І я натискаю Enter.
Коли я натисну Enter, керування
повернеться до нашого відладчика.
А тепер ми повернулися до нашого налагоджувача.
Якщо ви подивитеся у лівий нижній кут, то побачите, що налагоджувач перебуває у стані паузи.
Тепер він чекає на продовження налагодження.
Тож зараз я збираюся перейти до печери коду, щоб продовжити роботу з WriteFile, тому що тут у мене закінчилося місце.
Отже, я двічі клацаю на цьому, і ось мій код в печері коду, де я реалізую API WriteFile.
Отже, API WriteFile реалізує цей код ось тут.
І ви можете бачити, що я спочатку виштовхую параметри до стеку для виклику.
Тож я натиснув на нуль.
Потім я натискаю 0x405040, тобто записані байти.
Як я вже пояснював раніше, ці записані байти - це кількість байт, які насправді будуть виведені.
А тепер тут, наступний параметр, гаразд.
Дозвольте мені переступити через це.
Далі я натисну ось це, 0x405060,
тобто байти, які були прочитані раніше.
Отже, кількість прочитаних раніше байт була 11, яка зберігається за цією
адресою 0x405060. Ви можете побачити тут, 0xD.
0xD - це гекс на 13, ясно?
Зараз не 11.
Це 13, тому що у вас є повернення каретки та переведення рядка.
Коли ви натиснете клавішу Enter, буде вставлено два додаткових символи.
Це повернення каретки, що становить один байт, і переведення рядка, що становить ще один байт.
Тож додайте 2 до 11.
Зрозуміло.
Таким чином ми отримуємо 13, 0xD.
Отже, "Hello World" складається з Hello, Space, World і двох додаткових символів - повернення каретки, переведення рядка.
Отже, 0x405060 насправді містить кількість символів, які було прочитано раніше.
Коли ви викликаєте ReadFile, ви зберігаєте тут фактичну кількість прочитаних байт, 0x405060.
Тому ви зберігаєте його тут як 0xD.
Отже, тепер, коли ви викликаєте WriteFile, WriteFile має отримати доступ до кількості прочитаних байт.
Ось чому він зчитує цю локацію.
Тут вона роздиференціює його, щоб отримати 0xD, кількість прочитаних байт.
Далі ви виштовхуєте його до стеку, щоб отримати 0xD у стеку.
Далі ви натиснете рядок 0x405070. Отже, 0x405070 тут.
Як бачите, він містить рядок "Hello World".
Тож він також виштовхує його до стеку.
І ви отримуєте нитку на стопці.
А тепер він викличе функцію, функцію API, WriteFile, яка запише у вихідний файл.
Тож коли ви переступаєте через це, переступайте через це зараз, і повертайтеся до своєї консолі.
Отже, коли ви підходите до консолі, то бачите на екрані напис "Hello World".
Тож давайте продовжимо переступати.
Тепер він натисне нуль і викличе ExitProcess.
Отже, натискання нуля означає, що помилки немає.
Отже, це параметр для ExitProcess.
Це означає, що помилки немає.
Переступи через це.
А потім ми переходимо до виклику ExitProcess.
Він припинить своє існування.
Ось так.
Отже, ось як ми можемо реалізувати API всередині x64dbg.
На цьому відео все.
Дякуємо за перегляд.