ชุมชนนักพัฒนา Java กำลังมองย้อนกลับไปที่มรดกของ Stiver ผู้สร้าง Fernflower หลังจากที่ JetBrains ได้ทำการเคารพรำลึกถึงนักพัฒนาท่านนี้เมื่อเร็วๆ นี้ Fernflower ได้กลายเป็นแกนหลักของการ decompile Java ใน IntelliJ IDEA แต่นักพัฒนาหลายคนเพิ่งจะได้เรียนรู้เกี่ยวกับแนวทางที่เป็นนวัตกรรมที่ทำให้สิ่งนี้เป็นไปได้
สิ่งที่ทำให้ Fernflower แตกต่าง
แตกต่างจาก decompiler แบบดั้งเดิมที่เพียงแค่ reverse-engineer คำสั่ง bytecode Fernflower ใช้แนวทางการวิเคราะห์ที่เปลี่ยนแปลงพื้นฐานของการทำงานของ Java decompilation ความแตกต่างหลักอยู่ที่วิธีการประมวลผลโค้ด decompiler แบบดั้งเดิมทำงานเหมือนนักแปล โดยแปลงคำสั่ง bytecode แต่ละคำสั่งกลับไปเป็น Java ที่เป็นไปได้ สิ่งนี้มักจะสร้างโค้ดที่ยุ่งเหยิงและอ่านยากซึ่งสะท้อนถึงการปรับปรุงของ compiler มากกว่าซอร์สโค้ดต้นฉบับ
Fernflower เลือกเส้นทางที่ฉลาดกว่า มันสร้าง control-flow graph ในรูปแบบ static single-assignment หลังจากอ่าน bytecode สิ่งนี้ทำให้สามารถเข้าใจโครงสร้างและตรรกะของโปรแกรม แทนที่จะเพียงแปลคำสั่งทีละคำสั่ง ผลลัพธ์ที่ได้คือโค้ดที่สะอาดและอ่านง่ายกว่าซึ่งแสดงถึงสิ่งที่โปรแกรมเมอร์มนุษย์อาจจะเขียนได้ดีกว่า
Static single-assignment form: วิธีการจัดระเบียบโค้ดที่แต่ละตัวแปรจะถูกกำหนดค่าเพียงครั้งเดียว ทำให้ง่ายต่อการวิเคราะห์โฟลว์ของโปรแกรมและความสัมพันธ์ระหว่างส่วนต่างๆ ของโค้ด
เกินกว่าการแปลแบบง่ายๆ
แนวทางการวิเคราะห์ช่วยให้ Fernflower สามารถจัดการกับสถานการณ์ที่ซับซ้อนที่ทำให้ decompiler อื่นๆ สะดุดได้ มันสามารถจดจำรูปแบบที่สร้างขึ้นโดยการปรับปรุงของ compiler และนำเสนอในลักษณะที่เป็นธรรมชาติมากกว่า ตัวอย่างเช่น เมื่อ IntelliJ IDEA คอมไพล์โค้ดด้วย @NotNull annotations มันจะเพิ่มการตรวจสอบ runtime ที่โยน exception หากพบค่า null analytical decompiler สามารถจดจำรูปแบบเหล่านี้และอาจจะนำเสนอได้อย่างชัดเจนกว่าการย้อนกลับแบบคำสั่งต่อคำสั่ง
ความสามารถนี้ขยายไปถึงการจัดการกับ obfuscated code ที่ผู้ไม่หวังดีจงใจทำให้ bytecode เข้าใจยากขึ้น ลักษณะการวิเคราะห์ของ Fernflower ช่วยให้มันสามารถมองทะลุเทคนิค obfuscation บางอย่างได้โดยไม่ต้องมีการสนับสนุนแต่ละวิธีอย่างชัดเจน
ตัวเลือกบรรทัดคำสั่งหลักของ Fernflower
| ตัวเลือก | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|
| hes | 1 | ซ่อนการเรียก super ที่ว่างเปล่า |
| hdc | 1 | ซ่อน constructor เริ่มต้นที่ว่างเปล่า |
| dgs | 0 | แปลงรหัส generic signatures |
| ren | 0 | เปลี่ยนชื่อคลาสที่คลุมเครือ/ถูกปิดบัง |
| mpm | 0 | เวลาประมวลผลสูงสุดต่อเมธอด (วินาที) |
| din | 1 | แปลงรหัส inner classes |
| udv | 1 | สร้างชื่อตัวแปรใหม่จากข้อมูล debug |
การประยุกต์ใช้สมัยใหม่และนวัตกรรมของชุมชน
ภูมิทัศน์ของ decompiler ยังคงพัฒนาต่อไป โดยสมาชิกชุมชนกำลังสำรวจแนวทางใหม่ๆ เพื่อปรับปรุงความสามารถในการอ่านโค้ด นักพัฒนาบางคนกำลังทดลองกับ large language model เพื่อกำหนดชื่อที่มีความหมายให้กับตัวแปรและฟังก์ชันที่ถูก obfuscate ผลลัพธ์เบื้องต้นแสดงให้เห็นความหวัง โดยเฉพาะในการจดจำรูปแบบการเขียนโปรแกรมทั่วไปที่อาจจะไม่ชัดเจนสำหรับ reverse engineer มนุษย์
โปรเจกต์ทางเลือกอย่าง Vineflower ได้เกิดขึ้นเป็น fork ของ Fernflower โดยมุ่งเน้นเฉพาะการปรับปรุงความสามารถในการอ่านโค้ดที่ถูก decompile ความพยายามเหล่านี้สร้างขึ้นบนงานพื้นฐานของ Stiver ขณะเดียวกันก็จัดการกับกรณีการใช้งานเฉพาะและความต้องการของชุมชนนักพัฒนา
ตัวอย่างการใช้งาน Fernflower
การ decompile พื้นฐานพร้อมการอ้างอิง library
java -jar fernflower.jar -hes=0 -hdc=0 c:\Temp\binary -e=c:\Java\rt.jar c:\Temp\source\
Decompile โดยเปิดใช้งาน generic signatures
java -jar fernflower.jar -dgs=1 c:\Temp\binary\library.jar c:\Temp\binary\Boot.class c:\Temp\source\
รูปแบบไฟล์ที่รองรับ: ไฟล์ .class, .zip, .jar ใบอนุญาต: Apache License Version 2.0
ผลกระทบที่ยั่งยืน
การรวม Fernflower เข้ากับ IntelliJ IDEA หมายความว่านักพัฒนา Java หลายล้านคนใช้งานของ Stiver ทุกวัน โดยมักจะไม่รู้ตัว ทุกครั้งที่มีคนเปิดไฟล์ .class ใน IDE และเห็นซอร์สโค้ด Java ที่อ่านได้ พวกเขากำลังเห็นแนวทางการ decompile แบบวิเคราะห์ในการทำงาน การรวมเข้าด้วยกันอย่างไร้รอยต่อนี้แสดงถึงหนึ่งในตัวอย่างที่ประสบความสำเร็จมากที่สุดของการวิจัย compiler แบบวิชาการที่ได้เข้ามาในเครื่องมือพัฒนาที่ใช้ในชีวิตประจำวัน
โปรเจกต์ยังคงดำเนินต่อไปในรูปแบบโอเพนซอร์สภายใต้ Apache License เพื่อให้แน่ใจว่าแนวทางที่เป็นนวัตกรรมของ Stiver ยังคงพร้อมใช้งานสำหรับนักพัฒนาและนักวิจัยรุ่นต่อไปที่จะสร้างต่อยอด
อ้างอิง: Fernflower
