Привіт і ласкаво просимо назад.
У цьому уроці ми розглянемо вкладені виклики функцій.
Вкладені виклики
функцій можна легко зрозуміти, подивившись на граф викликів функцій.
Припустимо, що у нас є головна функція, а всередині головної функції є два виклики інших функцій.
Таким чином, ви можете розглядати це наступним
чином: стрілка вліво вказує на перший виклик функції, в якому головна функція буде викликати функцію, що викликається
- наприклад.
Після цього, коли функція - повернеться, головна функція зробить наступний виклик іншої функції, яка називається
функція - плюс -.
Отже, це приклад того, як можна візуалізувати вкладені функції.
Тому ми говоримо, що і функція -, і функція - плюс - є вкладеними викликами функцій, оскільки вони вкладені
в головну функцію.
Щоб краще це зрозуміти, давайте розглянемо приклад практичної задачі:
y дорівнює mx плюс c.
Отже, це звичайний графік лінійного рівняння, який будує пряму лінію в системі координат y та x.
Спробуємо реалізувати наведене вище рівняння для m, що дорівнює п'яти, x, що дорівнює десяти, і c, що дорівнює трьом.
Отже, ми отримуємо y, що дорівнює п'ять помножити на десять плюс три.
Якщо ми збираємося розбити це на декілька викликів функцій, ми можемо помістити операцію mx всередину функції і
викликати її - функція -.
І ми будемо посилатися на цю частину.
А потім ми могли б розбити плюс три тут на ще одну окрему функцію, де ми додаємо результат
першої функції - з трьома.
Отже, ця функція має бути три - c - і вона буде називатися функція - плюс -, яка буде всередині цієї функції тут - функція - плюс
- - так що в кінцевому підсумку результат буде повернутий в головну функцію.
Ми хочемо отримати кінцевий результат, y, який є результатом - плюс -, тому код буде виглядати так: Функція Main буде містити весь цей
код тут, а потім всередині неї буде виклик функції, яка викличе функцію -, яка знаходиться
за цією адресою, в цьому рядку, а наступний виклик буде виклик другої функції, яка знаходиться
в цьому рядку.
І, як завжди, ми виштовхуємо регістри, які будемо використовувати у функції, щоб пізніше їх можна
було відновити, витягнувши зі стеку.
Отже, в цьому випадку ми привласнюємо п'ять до -, а потім привласнюємо десять до -. Потім ми робимо перший виклик - перший виклик
всередині функції.
Потім ми перемістимо - в -, а потім помножимо - на - і збережемо результат назад в -.
Таким чином, ми отримуємо результат m помножити на x.
Тоді ми повернемося.
Зауважте, що повернення є важливим, як ми вже вивчали раніше.
Коли - повертається, вона повернеться до інструкції після виклику, яка знаходиться тут.
Оскільки дзвінок був зроблений сюди, відповідь прийде на наступну після нього адресу, тобто сюди.
Тому можна перейти до наступної інструкції.
Наступна інструкція - ще один виклик другої вкладеної функції.
Отже, ця команда викликає функцію - плюс -.
Отже, в цьому виклику потрібно взяти три і додати до -.
Отже, три тут позначає c в нашому рівнянні - c тут.
Тому ми просто додаємо три до результату повернення попередньої функції.
Отже, результатом повернення попередньої функції є -, який зберігається в -.
Отже, тепер ми беремо це - і додаємо до трьох, і зберігаємо назад у -.
Отже, коли ця функція повернеться, кінцевий результат - плюс - буде всередині -.
Отже, коли ця річ повернеться, вона повернеться до інструкції після виклику, якою є цей рядок.
Тож тут ми просто натискатимемо - і натискатимемо - у зворотному порядку від поштовху, щоб відновити
регістри - і -.
І, нарешті, - буде містити результат y, після чого продовжиться виконання решти коду.
Інший спосіб візуалізувати це - використовувати вкладені подання.
Отже, коли програма виконується, вона викликає функцію -.
Функція - виконає, а коли
повернеться, то повернеться сюди.
Далі він викличе функцію - plus -. Він виконає це і повернеться до основної функції.
Отже, давайте спробуємо запустити це у x64dbg.
Тож створіть програму - нову програму - використовуючи шаблонну, як ми завжди це робили. Введіть весь цей код:
push -, push -.
Дозвольте мені перезапустити це знову.
Гаразд.
Отже, тепер ми маємо таке: натиснути -, натиснути -, пересунути п'ять - -, пересунути А на -, а потім два дзвінки.
Тож ці виклики знаходяться в печері коду, як ми завжди і робили.
Отже, перша функція знаходиться
тут: 402705.
Другий виклик функції знаходиться
за цією адресою: 40270B. Після цього просто поверніться до своєї основної функції і поставте точку зупинки.
Поставте точку переривання у потрібному місці.
Я розміщу свою точку зупинки тут і запущу точку зупинки.
Далі ми переходимо рядок за рядком, і тепер ми готові викликати першу функцію.
Ми входимо в неї, потім переступаємо через неї, потім повертаємося.
Отже, в цей момент тут - вже має результат -, а в гексі - дорівнює 32.
Тож давайте переступимо через це - повернемося до основної функції.
Тож тепер ми повернулися до основної функції.
Ми готові виконати другий виклик функції.
Давайте зробимо крок до цього.
А тепер ми переходимо до другої функції.
Отже, ми додамо три до результату -, тобто -.
Тож давайте переступимо через це.
Тепер додаємо три - отримуємо 35 в гексі - і повертаємося до основної функції.
Коли ми бачимо ключове слово -, це означає повернення до основної функції.
Потім ми повертаємося до - і -, початкових значень в них, і до цього часу ми матимемо остаточний
результат в -.
Отже, - зберігає результат - плюс -, що дорівнює 35 у гексі.
Так що ж таке 35 в гексі?
Давайте повернемося і подивимося.
Введіть 35 в гекс, і ви побачите, що в десятковому записі це 53.
Це саме те, що ми очікували
отримати: 53. Давайте подивимося: y дорівнює mx плюс c - це п'ять разів по десять - 50 - плюс три - 53.
Це відповідає нашому
результату: 53. Таким чином, ми можемо зрозуміти, що таке вкладені
функції і як їх можна візуалізувати за допомогою діаграми потоку - графа викликів функцій - ось так, а також як ми можемо зрозуміти
їх, розглядаючи її всередині x64dbg. Ви побачите, що багато програм використовують вкладені функції.
Насправді, майже всі програми матимуть вкладені функції.
На цьому відео все.
Дякуємо за перегляд.