อะไร ((เป็นโมฆะ (*) ()) buf) (); หมายความว่าอย่างไร


59

ฉันกำลังแก้ไขปัญหาการแสวงหาผลประโยชน์แบบไบนารีบน picoCTF และพบกับโค้ดชิ้นนี้:

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

ที่bufเป็นอาร์เรย์ตัวอักษร

ฉันแก้ไขความท้าทาย แต่ดูเหมือนจะไม่เข้าใจว่ามันทำอะไรอยู่ ฉันดูที่กระทู้นี้แต่ฉันไม่สามารถทำให้มันออกมาได้

อะไร((void (*)())buf)();หมายถึง?


14
อะไร((void (*)())buf)();หมายถึง? typedefมันหมายถึงการที่ผู้เขียนไม่เข้าใจ typedef void (*voidFuncPtrType)();จะทำให้รหัสนี้ชัดเจน
Andrew Henle

33
@AndrewHenle ในการออกแบบความท้าทาย CTF ความชัดเจนไม่ใช่เป้าหมายสูงสุดและอาจทำให้สับสนได้แม้จะเป็นส่วนหนึ่งของความท้าทาย มีแนวโน้มมากกว่าที่ผู้เขียนไม่ทราบว่านี่ไม่ใช่วิธีที่ง่ายที่สุดในการทำสิ่งต่าง ๆ
ManfP

2
หมายความว่าโปรแกรมของคุณมี UB
. GitHub หยุดช่วยน้ำแข็งใน

4
หมายความว่ากฎการประกาศชนิด "เกลียว" ของ C นั้นซับซ้อนเกินไป มีเหตุผลเกือบทุกภาษาที่พิมพ์แบบคงที่ที่ไม่ได้สืบทอดโดยตรงจาก C ใช้กฎจากซ้ายไปขวาแทน
Mason Wheeler

2
@MasonWheeler "Spiral" เป็นตำนานเมือง การประกาศเป็น "เกลียว" มากหรือน้อยตามที่การแสดงออกที่สอดคล้องกันจะเป็น ตัวดำเนินการถูกนำไปใช้ในลำดับความสำคัญและลำดับจากซ้ายไปขวา (ไม่ได้บอกอะไรคุณใหม่ที่นี่แน่นอน): "ฉันต้องตรวจสอบมันแล้วเรียกมันและผลที่ได้คือประเภทโมฆะ": voila ตัวชี้ไปยังฟังก์ชันโมฆะ .
Peter - Reinstate Monica

คำตอบ:


129

void (*)() เป็นชนิดชนิดที่เป็น "ตัวชี้ไปยังฟังก์ชันที่รับอาร์กิวเมนต์ที่ไม่กำหนดและส่งคืนค่าใด ๆ "

(void (*)()) เป็นประเภทหล่อประเภทข้างต้น

(void (*)())bufปลดเปลื้องbufกับประเภทข้างต้น

((void (*)())buf)() เรียกใช้ฟังก์ชัน (ไม่มีการขัดแย้ง)

ในระยะสั้น: มันบอกคอมไพเลอร์ให้ถือว่าbufเป็นตัวชี้ไปยังฟังก์ชั่นและการเรียกใช้ฟังก์ชั่นนั้น


15
ฉันพบว่าcdeclยูทิลิตี้ (หรือเว็บไซต์ ) มีประโยชน์สำหรับการแปลนิพจน์ C ที่ซับซ้อนยิ่งขึ้นเป็นภาษาอังกฤษ
bta

3
@bta cdecl ไม่มีประโยชน์ที่นี่เนื่องจากไวยากรณ์ไม่ใช่การประกาศ มันเป็นฟังก์ชั่นการโทรผ่านตัวละครบนสัญลักษณ์ที่ประกาศไว้ก่อนหน้านี้
bolov

3
@bolov - ในคำสั่งทั้งหมดไม่ แต่จะอธิบายส่วนที่ซับซ้อนที่สุดของมัน จากตรงนั้นการถอดรหัสที่เหลือนั้นค่อนข้างตรงไปตรงมา
bta

5
@AvD หากที่ใดก็ตามbufหรือcopyอยู่ที่ที่อยู่ที่สามารถเรียกทำงานได้และรหัสนั้นเป็นตำแหน่งที่ไม่ขึ้นกับใคร แน่นอนว่ามันไม่สามารถพกพาได้ แต่ควรทำงานในสภาพแวดล้อมที่เป็นโลหะเปลือยเช่นเดียวกับระบบปฏิบัติการ x86 รุ่นเก่าที่ไม่ได้ตั้งค่าบิตที่ไม่ทำงาน (NX) บนสแต็กและกอง
wrtlprnft

4
@AvD: มันไม่จำเป็นต้องผิดพลาด ยกเว้นว่าพื้นที่ข้อมูลได้รับการปกป้องจากการดำเนินการ (ซึ่งขึ้นอยู่กับสถาปัตยกรรมและสภาพแวดล้อมแบบรันไทม์) คุณสามารถใช้เคล็ดลับนี้เพื่อรวบรวมฟังก์ชั่นเป็นอาร์เรย์ในขณะใช้งานและเรียกใช้ทันที ฉันใช้เคล็ดลับนี้เมื่อ 35 ปีก่อนใน DEC Vax เพื่อรวบรวมเครื่องทัวริงสำหรับการทดลองที่ล้มเหลวในวิวัฒนาการของเครื่องจักรทัวริง
TonyK

11

ตัวชี้bufจะถูกแปลงเป็นตัวชี้ไปยังฟังก์ชั่นโมฆะโดยใช้จำนวนพารามิเตอร์ที่ไม่ระบุและจากนั้นยกเลิกการอ้างอิง (เช่นเรียกใช้ฟังก์ชัน)


9

มันเป็น typecast ตามด้วยการเรียกใช้ฟังก์ชัน ประการแรกคือการส่งข้อมูลไปยังตัวชี้ไปยังฟังก์ชั่นที่ส่งกลับbuf voidวงเล็บคู่สุดท้ายหมายถึงฟังก์ชันถูกเรียกใช้


7

มัน casts อาร์เรย์ตัวละครไปยังตัวชี้ไปยังฟังก์ชั่นที่ไม่มีข้อโต้แย้งและกลับมาvoidแล้วเรียกมัน ไม่จำเป็นต้องทำการลงทะเบียนตัวชี้อีกครั้งเนื่องจากตัวชี้ฟังก์ชันทำงานอย่างไร

คำอธิบาย:

"อาเรย์อักขระ" นั้นเป็นอาร์เรย์ของรหัสเครื่อง เมื่อคุณส่งอาเรย์ไปที่ a void (*)()และเรียกมันจะเรียกใช้รหัสเครื่องภายในอาเรย์ หากคุณให้เนื้อหาของอาเรย์ฉันจะแยกมันให้คุณและบอกคุณว่ามันกำลังทำอะไรอยู่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.