Lotus 1-2-3 สำหรับ Linux
(lock.cmpxchg8b.com)- สเปรดชีตกรรมสิทธิ์อายุ 30 ปี Lotus 1-2-3 ถูกรันแบบเนทีฟบน Linux ซึ่งยังไม่มีอยู่ในช่วงที่ซอฟต์แวร์เปิดตัว ผ่านข้อมูลที่กู้คืนมาโดยบังเอิญและการแฮ็กไบนารี
- จากแบ็กอัป BBS ในยุค 1990 พบ LPL add-in SDK ที่คิดว่าสูญหายไปแล้ว รวมถึง Lotus 1-2-3 for UNIX ทำให้สามารถ build ปลั๊กอินตัวอย่างและวิเคราะห์ไบนารี UNIX ได้
- ดิสทริบิวชัน UNIX มี Intel 80386 COFF object ที่ถูกบีบอัดชื่อ
123.oอยู่ภายใน และสัญลักษณ์ราว 20,000 รายการพร้อมข้อมูลดีบักช่วยเปิดเผยโครงสร้างภายใน - การพอร์ตไม่ได้จบแค่การแปลง COFF เป็น ELF แต่ต้องเลี่ยง ความแตกต่างของ system call และ ABI ของ struct ระหว่าง Linux กับ UNIX ด้วย
coffsyrupและฟังก์ชัน wrapper - ปัจจุบันพอร์ตนี้รันได้โดยไม่ crash และ ใช้งานได้ 100% แต่ยังมีปัญหาบางส่วนและการพอร์ต terminal driver ที่เหลืออยู่ ทำให้เวอร์ชันที่รันผ่าน DOS emulation ยังดูดีกว่า
จุดเริ่มต้นของการย้ายแอปกรรมสิทธิ์อายุ 30 ปีมายัง Linux
- Lotus 1-2-3 ยังคงเป็น abandonware อายุ 30 ปี แต่การค้นพบและการแฮ็กหลายอย่างทำให้เกิด พอร์ตแบบ Linux native ได้
- เป้าหมายการพอร์ตคือ Lotus 1-2-3 R3 แบบคลาสสิก ส่วน Lotus 1-2-3 เองยังมีการออก release จนถึงปี 2002
- โปรเจกต์นี้เริ่มจากงานดูแล driver lotusdrv เพื่อให้ Lotus 1-2-3 ทำงานได้ดีบนระบบสมัยใหม่
- driver API ถูกทำความเข้าใจด้วย reverse engineering และ driver เดิมทำงานได้ดีบนระบบสมัยใหม่
LPL SDK ที่สูญหายและแบ็กอัป BBS
- Lotus 1-2-3 ถูกออกแบบให้ขยายความสามารถได้ด้วยปลั๊กอิน หรือ add-in แต่ add-in ต้องเขียนด้วยภาษาพิเศษชื่อ LPL
- คอมไพเลอร์ LPL และ SDK สูญหายไปแล้ว และ Lotus ไม่ได้แจก SDK ฟรี แต่ขายในราคา 395 ดอลลาร์
- SDK ในรูปแบบ warez ถูกกู้คืนผ่านอดีต sysop ที่เก็บแบ็กอัปเทปของระบบ BBS ในยุค 1990 ไว้
- ADK ที่กู้คืนมาได้ดาวน์โหลดได้ที่ 123DADK.ZIP
- โปรแกรม LPL ตัวอย่างเผยแพร่เป็น modern.pl
- ในแบ็กอัป BBS ชุดเดียวกันยังมีสำเนา warez ของ Lotus 1-2-3 for UNIX ซึ่งเชื่อกันโดยทั่วไปว่าสูญหายไปแล้วด้วย
การวิเคราะห์ดิสก์อิมเมจ Lotus 1-2-3 for UNIX
- เวอร์ชัน UNIX เหลืออยู่เป็นชุด ไฟล์ TD0 ตั้งแต่
123UNIX1.TD0ถึง123UNIX5.TD0 - พบว่า TD0 เป็นฟอร์แมตดิสก์อิมเมจบีบอัดแบบเก่าจากยุค 1980 และใช้ samdisk แปลงเป็น raw disk image
- ในอิมเมจที่แปลงแล้ว ไฟล์แรกเป็น
tar archiveส่วนที่เหลือเป็น ASCII cpio archive แบบ pre-SVR4 หรือ odc - ดิสก์อิมเมจทั้งหมดถูกอัปโหลดไว้บน Internet Archive
- เมื่อแตกไฟล์ออกมา ใต้
lotus/123.v10พบ executable, help, keymap, ข้อมูล driver สำหรับ printer และ video, ไฟล์ตัวอย่าง, manual และอื่น ๆ- โครงสร้างทั้งหมดมีระดับ 35 ไดเรกทอรีและ 338 ไฟล์
123.o ที่กลายเป็นเบาะแสสำคัญ
- พบไฟล์ขนาดใหญ่ที่ถูกแบ่งเป็น
123.o.z_1และ123.o.z_2ในไดเรกทอรีsysV386/lib - เมื่อนำสองส่วนมาต่อกันและแตกไฟล์ พบว่า
123.oเป็น Intel 80386 COFF object file- object file ที่ไม่ได้ถูก stripped
- มี 5 section
- symbol offset
0x1efbdc -
มีสัญลักษณ์ 19,755 รายการ
- optional header size 28
- ไฟล์นี้มี private symbol และข้อมูลดีบัก จึงช่วยอย่างมากในการทำความเข้าใจโครงสร้างภายในของ Lotus 1-2-3
- คำตอบที่ได้รับจาก
alt.folklore.computersชี้ไปในทางว่าไฟล์นี้ไม่ได้ถูกใส่มาโดยผิดพลาด - เนื่องจาก
dlopen()ยังไม่ได้ถูกใช้อย่างแพร่หลายใน UNIX ช่วงต้นยุค 1990 จึงมีความเป็นไปได้สูงว่าเป็น partially linked object สำหรับลิงก์ซ้ำกับส่วนขยาย
โครงสร้างภายในที่ข้อมูลดีบักเปิดเผย
- เวอร์ชัน UNIX ใกล้เคียงกับ การพอร์ตซอร์สโดยตรง จากเวอร์ชัน DOS จึงทำงานด้วยวิธีเดียวกันเป็นส่วนใหญ่
- ข้อมูลดีบักที่รวมมาช่วยไขข้อสงสัยหลายอย่างเกี่ยวกับภายในของ Lotus 1-2-3
- เพื่อปรับปรุงการแสดงผลกราฟ ผู้พัฒนาต้องการ hook เข้ากับ rasterizer ใน driver แต่การทำความเข้าใจพฤติกรรมจากเอกสารเพียงอย่างเดียวทำได้ยาก
- ข้อมูลดีบักทำให้ทราบว่า rasterizer สร้าง โปรแกรม bytecode ขนาดเล็กแบบไดนามิก และ graphics engine จะตีความโปรแกรมนั้น
- หลังจากรู้ opcode แล้ว ก็สามารถ disassemble และแก้ไขมันใน raster.c เพื่อใช้ปรับปรุง output ได้
การแปลงจาก COFF เป็น ELF
objcopyสามารถแปลง COFF object file เป็นฟอร์แมต ELF ที่ใช้บน Linux ได้- ใช้คำสั่ง
objcopy -I coff-i386 -O elf32-i386 123.o 123elf.oเพื่อแปลง123.oเป็น123elf.o - ผลลัพธ์ที่แปลงแล้วระบุเป็น
ELF 32-bit LSB relocatable, Intel 803386, version 1 (SYSV), not stripped - ตาม
objdumpเวลาคอมไพล์ของ object file ต้นฉบับคือ 8 กันยายน 1990 เวลา 06:23:50 ซึ่งเป็นช่วงก่อน Linux เวอร์ชันแรกจะออกมา
การจัดการความแตกต่างของ ABI ระหว่าง Linux กับ UNIX
- ปัญหาแรกคือ Linux กับ UNIX ไม่ได้ใช้ อินเทอร์เฟซ system call ที่เข้ากันได้
- เวอร์ชัน UNIX ใช้อินเทอร์เฟซ
lcall7เช่นopen()เรียก callgate ในรูปแบบcall 0x7:0x0 - บน Linux ไม่มีการรองรับ callgate นี้ ดังนั้นหากรันตรง ๆ จะเกิด crash
- Linux เคยมีการรองรับความเข้ากันได้ของ
lcall7และlcall27อยู่ช่วงหนึ่ง แต่ปัจจุบันไม่มีแล้ว
- Linux เคยมีการรองรับความเข้ากันได้ของ
- เป้าหมายคือการลบการเรียกเหล่านี้ออก และ route ทุกการเรียกให้ผ่าน glibc
Relocation และ coffsyrup
- พยายามลบ symbol ด้วย
objcopy --strip-symbol openแบบง่าย ๆ แต่objcopyปฏิเสธ เพราะopenถูกใช้ใน relocation - relocatable object file มีการอ้างอิง symbol และข้อมูล relocation เพื่อให้ทำงานได้ไม่ว่าจะถูกโหลดที่ address ใด
- หากต้องการลบ symbol ต้องแก้ไข ข้อมูล relocation ที่อ้างถึง symbol นั้นไปพร้อมกัน
- เพื่อการนี้จึงเขียนเครื่องมือขนาดเล็ก coffsyrup ขึ้นมา
- สามารถลบ COFF symbol ที่
objcopyปฏิเสธได้ - ในตัวอย่างจะค้นหาและจัดการ symbol
openกับ relocation ที่เกี่ยวข้อง
- สามารถลบ COFF symbol ที่
ฟังก์ชัน UNIX ที่ไม่เข้ากันในระดับไบนารี
- ฟังก์ชัน UNIX มาตรฐานจำนวนมาก เข้ากันได้ในระดับซอร์ส แต่ ไม่เข้ากันในระดับไบนารี
- ตัวอย่างสำคัญคือ
struct stat- โค้ด C เดียวกันสามารถคอมไพล์ได้บน UNIX หลายตระกูล
- แต่ object file ที่คอมไพล์แล้วอาจพังบนระบบอื่น เพราะขนาดของ
struct statหรือ offset ของst_sizeต่างกัน
- ฟังก์ชันหลักที่ต้องจัดการ ได้แก่
stat(),times(),uname(),fcntl(),ioctl()เป็นต้น - แนวทางคือเปลี่ยนชื่อ symbol ด้วย
objcopyทำให้เป็น undefined ด้วยcoffsyrupแล้วเขียน ฟังก์ชัน wrapper ที่แปลง struct ของ Linux เป็น struct ของ UNIX termiosเป็นจุดที่ยากเป็นพิเศษ เพราะพฤติกรรมรายละเอียดต่างกันอย่างละเอียดระหว่างระบบ UNIX และไม่เข้ากัน ทำให้ดีบักยาก
การตรวจสอบไลเซนส์และผลการรัน
- หลังจากแฮ็กหลายอย่าง โปรแกรมรันได้โดยไม่ crash แต่จะไม่ทำงานหากไม่มี ไลเซนส์
- เมื่อตั้ง breakpoint ที่
exit()เพื่อตรวจสอบ พบว่า symbol ภายในที่ตรวจสอบไลเซนส์ที่ถูกต้องคือlic_init() - เมื่อตรวจโค้ดด้วย IDA พบว่าการตรวจไลเซนส์ทำโดยค้นหาไฟล์
LICENSE.000และตรวจว่าวันหมดอายุ ชื่อผู้ใช้ และชื่อระบบภายในไฟล์ตรงกับค่าที่ระบบรายงานหรือไม่ - ท้ายที่สุด Lotus 1-2-3 ก็ถูกพอร์ตมายังระบบปฏิบัติการใหม่อย่าง Linux
- สถานะปัจจุบันมีดังนี้
- รันได้โดยไม่ crash
-
ใช้งานได้ 100%
- ยังต้องเก็บรายละเอียดปัญหาบางอย่างเพิ่มเติม
- ยังเหลืองานพอร์ต terminal driver
- ตอนนี้เวอร์ชัน DOS ที่รันผ่าน emulation ยังดูดีกว่า แต่สามารถแก้ไขได้
- โค้ดพอร์ตเผยแพร่บน github
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
แทบไม่น่าเชื่อว่าเขากู้สำเนา warez ของ SDK จาก เทปแบ็กอัป ของระบบ BBS เก่า ๆ แล้วถึงขั้นบิลด์ปลั๊กอินตัวอย่างได้
ทำให้นึกถึง Why History Needs Software Piracy
อุปกรณ์พวกนี้เป็นฮาร์ดแวร์ที่จะยังคงอยู่ได้อีกหลายสิบปี ดังนั้นถ้ามีคลังเก็บแบบรวมศูนย์และคงทนที่ทั้งคอมมูนิตี้ใช้ได้ แทนที่จะเป็นแค่การเก็บไว้ในคลาวด์ส่วนตัวแยกตามผู้ผลิต ก็จะมีคุณค่าต่อสาธารณะมาก
เคยคิดถึงวิธีแจกจ่ายอาร์ไคฟ์ทุกปี หรือขาย archival Blu-ray ในรูปแบบสื่อกายภาพที่น่าจะอยู่ได้ราว 100 ปีด้วย
แบบนั้นโอกาสที่ใครสักคนจะมีไฟล์
.binหายากไฟล์สุดท้ายที่จำเป็นต่อการกู้เฟิร์มแวร์ที่เสียของโมดูล DSP Eurorack บน ARM ก็น่าจะเข้าใกล้ 1พ่อของผมเก็บ ไฟล์ Lotus 1-2-3 สำคัญไว้เต็มไปหมดในโน้ตบุ๊กสำรองที่ลง Windows รุ่นเก่า และบางครั้งยังต้องเปิดดู ทำให้สภาพนั้นค่อนข้างน่ากังวล
เมื่อไม่นานมานี้ผมรู้ว่า LibreOffice สามารถแปลงไฟล์ Lotus เป็น ODF/ODS ได้ แม้กระทั่งจากบรรทัดคำสั่ง เลยใช้สคริปต์ bash ง่าย ๆ แปลงทั้งหมด
ผมอัปโหลดไฟล์ที่แปลงแล้วขึ้น Nextcloud ที่มี Collabora แบบยกชุด แล้วให้บัญชีกับวิธีใช้งานสั้น ๆ แก่พ่อ ตอนนี้เขาดูไฟล์ออนไลน์ได้ และไฟล์ก็ถูกรวมอยู่ในรูทีนแบ็กอัปปกติของเซิร์ฟเวอร์ด้วย
ขอบคุณนักโบราณคดีข้อมูลแบบ OP และ ผู้ร่วมพัฒนา LibreOffice อย่างมาก
นึกถึงตอนอายุ 7 ขวบที่ขอให้พ่อซื้อ Nintendo ให้ แต่พ่อกลับซื้อ 286 PC พร้อม Lotus 1-2-3 และเกมผจญภัยข้อความ Indiana Jones มาให้แทน
ดังนั้นภาษาแรกของผมจึงไม่ใช่ LISP แต่เป็น BASIC และผมตั้งใจจะโทษโศกนาฏกรรมนี้สำหรับความล้มเหลวทั้งหมดในชีวิต โดยไม่รับฟังข้อโต้แย้งใด ๆ
ถึงตอนนั้น Spectrum จะอยู่ในช่วงขาลงแล้วก็ตาม
กำลังทำงานคล้าย ๆ กันอยู่ แต่เพิ่มขั้นตอนแปลงบางส่วนของโปรแกรมเป็น ออบเจ็กต์ไฟล์ ก่อน
ดังนั้นจึงไม่ถูกผูกกับออบเจ็กต์ไฟล์ที่ยังหลงเหลืออยู่เท่านั้น แต่ต้องทำ reverse engineering พอสมควรเพื่อให้มันทำงานได้
ผมทำ proof of concept ด้วย
alnซึ่งเป็นลิงเกอร์ของ Atari Jaguar โดยแยกไฟล์ปฏิบัติการ Linux x86a.outออกเป็นออบเจ็กต์ไฟล์ ELF แล้วลิงก์กลับเป็นไฟล์ปฏิบัติการ ELF x86 โดยเลี่ยงความต่างของ ABIhttps://forums.atariage.com/topic/354341-porting-the-original-atari-jaguar-sdk-to-elf/
น่าสนใจในหลายแง่
กระบวนการย้ายจาก ไบนารี UNIX ไปเป็นไบนารี Linux โดยไม่มีซอร์สโค้ด ไม่มีคอมไพเลอร์และภาษาต้นฉบับ ดูเจ๋งมาก และนี่แหละคือคอนเทนต์แบบ HN
ยังทำให้นึกได้ด้วยว่าในปี 2023 Usenet ยังถูกใช้เพื่ออย่างอื่นนอกจากการแจกไฟล์ rar
และทำให้นึกถึงวัฒนธรรม BBS ก่อนอินเทอร์เน็ตจะแพร่หลาย ที่ช่วยกระจายความหลงใหลและซอฟต์แวร์แชร์แวร์ดี ๆ ไปสู่คนทั่วไป
ยิ่งเห็นแนวโน้มที่ Twitter และโซเชียลมีเดียอื่น ๆ กำลังพังทลายก็ยิ่งรู้สึกแบบนั้น ส่วน Gen Z ที่อายุมากหน่อยก็หลงใหลความย้อนยุคยุค 80–90 ถึงขั้นดาวน์โหลดเสียงเจรจาของโมเด็มไปตั้งเป็นริงโทน
หลานวัย 23 ของผมก็เพิ่งทำแบบนั้น และผลงานอย่าง American Horror Story หรือ Stranger Things ก็ยิ่งหล่อเลี้ยงความถวิลหาอดีตนี้
เท่ากับว่าคำกล่าวเก่า ๆ ที่ว่าถ้ารอนานพอ ทุกอย่างจะกลับมาฮิตอีกครั้งนั้นถูกต้อง
เมื่อเดือนพฤษภาคม 2022 ปีที่แล้วก็มีการถกเถียงดี ๆ เช่นกัน
https://news.ycombinator.com/item?id=31455968
https://scenelist.org/ ที่ลิงก์ไว้ในบทความยอดเยี่ยมนี้ เป็น ระเบิดความคิดถึง ที่ผมต้องการพอดีเมื่อเช้านี้
เหมาะมากสำหรับการเดินทางย้อนความทรงจำ และขอแนะนำอย่างยิ่ง
ลิงก์ที่เกี่ยวข้อง
Lotus 1-2-3 for Linux - https://news.ycombinator.com/item?id=35807639 - พฤษภาคม 2023, 73 ความคิดเห็น
Lotus 1-2-3 - https://news.ycombinator.com/item?id=35872758 - พฤษภาคม 2023, 117 ความคิดเห็น
Lotus 1-2-3 For Linux - https://news.ycombinator.com/item?id=31455968 - พฤษภาคม 2022, 83 ความคิดเห็น
Lotus 1-2-3 arbitrary resolution - https://news.ycombinator.com/item?id=26316637 - มีนาคม 2021, 123 ความคิดเห็น
ผมลืม 1-2-3 ไปสนิท ทั้งที่เคยลองใช้อยู่พักหนึ่งเมื่อปีที่แล้ว
ไบนารี
123ยังรันได้ดีบน Linux และการที่ซอฟต์แวร์ซึ่งหายไปนานแล้วทำงานได้เฉย ๆ นั้นถือเป็นความสำเร็จที่น่าทึ่งทีเดียวผมอยากได้อะไรแบบนี้มาตลอด เพราะแทบไม่ได้ใช้ฟอนต์หรือรูปภาพในสเปรดชีตอยู่แล้ว สเปรดชีตบนเทอร์มินัล จึงเหมาะพอดี
ดีใจที่ในที่สุดก็ออกมาแล้ว และหวังว่าจะพอร์ตไปยัง Mac กับ Windows ด้วย
https://lock.cmpxchg8b.com/spreadsheet.html
ผมไม่เคยลองใช้ แต่ก็น่าตรวจสอบดู
อีกอย่าง Org-Mode ของ Emacs ก็เป็นเครื่องมือที่ขุดค้นได้ไม่รู้จบ และยังมีวิธีใช้เซลล์ตารางของ org-mode เหมือนสเปรดชีตร่วมกับฟีเจอร์
Calcของ Emacs ด้วยhttps://www.youtube.com/watch?v=15aDIvb5LJs
ดูทรงพลังทีเดียว และตามสไตล์ Emacs คือรันได้ทั้งในเทอร์มินัลและสภาพแวดล้อมแบบหน้าต่าง
scอยู่แล้ว: https://www.unix.com/man-page/linux/1/sc/