Apa yang ((void (*) ()) buf) (); berarti?

59

Saya memecahkan tantangan eksploitasi biner di picoCTF dan menemukan potongan kode ini:

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

dimana buf array karakter.

Saya memecahkan tantangan tetapi tampaknya tidak mengerti apa yang sebenarnya ia lakukan. Saya melihat ini utas tetapi saya tidak bisa keluar.

Apa ((void (*)())buf)();artinya

sh.3.ll
sumber
14
Apa ((void (*)())buf)();artinya Artinya penulis tidak mengerti typedef. typedef void (*voidFuncPtrType)();akan membuat kode ini jelas.
Andrew Henle
33
@AndrewHenle dalam merancang tantangan KKP, kejelasan sebenarnya bukan tujuan utama, dan beberapa kebingungan bahkan dapat diharapkan sebagai bagian dari tantangan. Lebih mungkin daripada tidak, penulis sadar bahwa ini bukan cara yang paling mudah dibaca dalam melakukan sesuatu.
ManfP
2
Ini berarti program Anda memiliki UB.
R .. GitHub BERHENTI MEMBANTU ICE
4
Ini berarti aturan deklarasi tipe "spiral" C terlalu rumit. Ada alasan mengapa setiap bahasa dengan ketikan statis lain yang tidak diturunkan langsung dari C menggunakan aturan kiri-ke-kanan.
Mason Wheeler
2
@MasonWheeler "Spiral" adalah mitos urban. Deklarasi ini sama atau "spiral" sebanyak ekspresi yang sesuai. Operator hanya diterapkan dalam prioritas dan urutan kiri-ke-kanan (tidak memberi tahu Anda sesuatu yang baru di sini, tentu saja): "Saya perlu melakukan dereferensi, lalu memanggilnya, dan hasilnya memiliki tipe batal": voila, pointer ke fungsi batal .
Peter - Pasang kembali Monica

Jawaban:

129

void (*)() adalah tipe, tipenya adalah "pointer ke fungsi yang mengambil argumen tak tentu dan tidak mengembalikan nilai".

(void (*)()) adalah tipe-cast untuk tipe di atas.

(void (*)())buf gips buf ke jenis di atas.

((void (*)())buf)() memanggil fungsi (tanpa argumen).

Singkatnya: Ini memberitahu kompiler untuk memperlakukan bufsebagai pointer ke suatu fungsi, dan memanggil fungsi itu.

Beberapa programmer dude
sumber
15
Saya menemukan cdeclutilitas (atau situs web ) bermanfaat untuk menerjemahkan ekspresi C yang lebih kompleks ke dalam bahasa Inggris.
bta
3
@bta cdecl tidak berguna di sini karena sintaksnya bukan deklarasi. Ini adalah panggilan fungsi melalui para pemain pada simbol yang dinyatakan sebelumnya
bolov
3
@bolov - Di seluruh pernyataan, tidak ada, tetapi tidak menjelaskan bagian paling kompleks dari itu. Dari sana, mendekode sisanya cukup mudah.
bta
5
@ AVD Jika di mana pun bufatau copyberada di alamat yang dapat dieksekusi dan kode itu sendiri adalah posisi-independen, ini akan berfungsi. Ini tentu saja sebagai non-portabel karena mendapat, tetapi ini harus bekerja di banyak lingkungan bare-metal serta OS x86 yang lebih tua yang tidak mengatur bit no-execute (NX) pada stack dan heap.
wrtlprnft
4
@ AVD: Itu tidak selalu crash. Kecuali area data dilindungi terhadap eksekusi (yang tergantung pada arsitektur dan lingkungan run-time), Anda dapat menggunakan trik ini untuk mengkompilasi fungsi ke dalam array pada saat run-time dan menyebutnya dengan cepat. Saya pertama kali menggunakan trik ini 35 tahun yang lalu pada DEC Vax untuk mengkompilasi mesin Turing untuk percobaan yang gagal dalam evolusi mesin Turing.
TonyK
11

pointer bufdikonversi ke fungsi pointer untuk membatalkan mengambil jumlah parameter yang tidak ditentukan dan kemudian dereferenced (yaitu fungsi yang disebut).

P__J__
sumber
9

Ini adalah typecast, diikuti oleh pemanggilan fungsi. Pertama, bufdilemparkan ke pointer ke fungsi yang mengembalikan void. Pasangan kurung terakhir berarti bahwa fungsi tersebut kemudian dipanggil.

lukeg
sumber
7

Itu melemparkan array karakter ke pointer ke fungsi tanpa argumen dan kembali void , dan kemudian memanggilnya. Dereferencing pointer tidak diperlukan karena cara kerja pointer fungsi.

Sebuah penjelasan:

"Larik karakter" itu sebenarnya adalah larik kode mesin. Ketika Anda melemparkan array ke void (*)()dan memanggilnya, itu menjalankan kode mesin di dalam array. Jika Anda memberikan konten array, saya bisa membukanya untuk Anda dan memberi tahu Anda apa yang dilakukannya.

SS Anne
sumber