Що робить ((void (*) ()) buf) (); означає?


59

Я вирішую завдання бінарної експлуатації на picoCTF і натрапив на цей фрагмент коду:

((void (*)())buf)();

де bufсимвольний масив.

Я вирішив завдання, але не можу зрозуміти, що саме це робить. Я подивився на цю нитку, але не зміг розібратися.

Що ((void (*)())buf)();означає?


14
Що ((void (*)())buf)();означає? Це означає, що автор не розуміє typedef. typedef void (*voidFuncPtrType)();зробить це зрозумілим.
Ендрю Генле

33
@AndrewHenle при розробці викликів CTF, чіткість насправді не є головною ціллю, і деякі затуманення можна навіть очікувати як частину проблеми. Швидше за все, автор усвідомлював, що це не самий читабельний спосіб робити речі.
ManfP

2
Це означає, що у вашій програмі є UB.
R .. GitHub СТОП ДОПОМОГАЙТЕ

4
Це означає, що правило "спірального" декларування типу С занадто складне. Існує причина практично у будь-якій іншій мові статичного типу, яка безпосередньо не походить із С, натомість використовує правила зліва направо.
Мейсон Уілер

2
@MasonWheeler "Спіраль" - міський міф. Декларація є такою ж або такою ж маленькою "спіраллю", як і відповідний вираз. Оператори просто застосовуються в порядку пріоритетності та вліво-вправо (не звісно вам тут нічого нового): "Мені потрібно його знеструмити, потім викликати, і результат має тип void": voila, вказівник на функцію void .
Пітер - Відновіть Моніку

Відповіді:


129

void (*)() це тип, тип - "вказівник на функцію, яка приймає невизначені аргументи і не повертає значення".

(void (*)()) являє собою типовий формат для вищевказаного типу.

(void (*)())bufкасти bufдо вищевказаного типу.

((void (*)())buf)() викликає функцію (не передаючи аргументів).

Коротше кажучи: він повідомляє компілятору трактувати bufяк вказівник на функцію та викликати цю функцію.


15
Я вважаю cdeclутиліту (або веб-сайт ) корисною для перекладу складніших виразів C на англійську мову.
бта

3
@bta cdecl тут не корисний, оскільки синтаксис не є декларацією. Це виклик функції через акторський
формат

3
@bolov - На всім заяві, немає, але це робить пояснити найбільш складну частину його. Звідти розшифровка решти досить проста.
бта

5
@AvD Якщо де bufабо copyзнаходиться знаходиться за виконаною адресою, а сам код не залежить від позиції, це буде працювати. Це, звичайно, не портативні, як це стає, але це повинно працювати в багатьох середовищах з голим металом, а також у старих ОС x86, які не встановлюють біт невиконання (NX) на стек і купу.
wrtlprnft

4
@AvD: Це не обов'язково вийде з ладу. Якщо область даних не захищена від виконання (що залежить від архітектури та середовища виконання), ви можете використовувати цей трюк, щоб скомпілювати функцію в масив під час виконання та зателефонувати на льоту. Я вперше застосував цю хитрість 35 років тому на DEC Vax, щоб скласти машини Тьюрінга для невдалого експерименту в еволюції машин Тьюрінга.
TonyK

11

покажчик bufперетворюється в покажчик на функцію недійсності, приймаючи невстановлене число параметрів, а потім дереферендує (тобто функція викликається).


9

Це набір тексту, за яким слід виклик функції. По-перше, bufпередається покажчику на функцію, яка повертається void. Остання пара дужок означає, що функція потім викликається.


7

Він передає символьний масив покажчику на функцію, яка не бере аргументів і не повертається void, а потім викликає її. Перенаправлення покажчика не потрібно через те, як працюють покажчики функцій.

Пояснення:

Цей "масив символів" - це фактично масив машинного коду. Коли ви кидаєте масив на a void (*)()і називаєте його, він запускає машинний код всередині масиву. Якщо ви надали вміст масиву, я міг би його розібрати для вас і розповісти, що він робить.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.