เขียนโค้ด java เพื่อตรวจหาเวอร์ชัน JVM


17

วัตถุประสงค์คือการเขียนโค้ดจาวาที่ตรวจจับเวอร์ชัน JVM โดยอาศัยการเปลี่ยนแปลงความเข้ากันได้ผลข้างเคียงข้อบกพร่องและ / หรือพฤติกรรมที่ไม่ได้กำหนดซึ่งทำงานในลักษณะหนึ่งเวอร์ชันและอีกวิธีในเวอร์ชันอื่น นอกจากนี้โค้ดควรมีอย่างน้อยอ่านได้เล็กน้อยโดยไม่เสียสละช่องว่างและชื่อตัวแปรที่ชัดเจน

เพื่อให้มั่นใจว่าวัตถุประสงค์กฎอย่างเป็นทางการที่แน่นอนคือ:

  1. รหัสจะต้องเขียนใน java และควรส่งออกรุ่น JRE ที่มันกำลังทำงานอยู่

  2. รหัสจะต้องไม่ใช้ JDK หรือ JRE API ใด ๆ ที่จัดไว้ให้โดยเฉพาะสำหรับการตรวจจับเวอร์ชันจาวาหรือซึ่งให้รุ่น JDK หรือ JRE ฟรี

  3. รหัสจะต้องไม่ใช้การสะท้อน

  4. รหัสจำเป็นต้องใช้เพื่อทำงานใน Hotspot Java SE 5, 6 และ 7 แต่อาจทำงานใน JVM อื่น ๆ

  5. รหัสต้องไม่ใช้ไลบรารีบุคคลที่สามใด ๆ ใน classpath

  6. รหัสจะต้องไม่เริ่มกระบวนการอื่นใด java หรือไม่

  7. รหัสจะต้องไม่ใช้ตัวแปรสภาพแวดล้อม

  8. รหัสจะต้องไม่ค้นหาระบบไฟล์เพื่อค้นหาไฟล์หรือโฟลเดอร์ที่มีอยู่แล้ว

  9. รหัสจะต้องอยู่ในไฟล์เดียวและจะเรียกว่าผ่านหรือpublic static void main(String[] args)public static void main(String... args)

  10. รหัสจะต้องไม่ใช้ API ที่ไม่ใช่แบบสาธารณะใด ๆ ที่มีอยู่ใน JRE

  11. รหัสต้องไม่สร้าง NoClassDefFoundError, NoSuchMethodError, ClassNotFoundException หรือ NoSuchMethodException ใด ๆ ระหว่างการดำเนินการ

  12. รหัสควรทำงานในระบบที่ถูกตัดการเชื่อมต่อจากอินเทอร์เน็ตหรือจากเครือข่ายท้องถิ่นใด ๆ

  13. คุณควรให้คำอธิบายว่าทำไมมันมีพฤติกรรมในทางเดียวในรุ่นและอีกวิธีหนึ่งในรุ่นอื่น

เกณฑ์การให้คะแนน

วิธีที่ใช้ในการวัดทางออกที่ดีที่สุดคือ max (n / s) โดยที่ n คือจำนวนเวอร์ชันจาวาที่แตกต่างกันที่ตรวจพบโดยไม่ละเมิดกฎเหล่านี้ (อย่างน้อยรุ่น 5, 6 และ 7) และ s คือจำนวนโทเค็นศัพท์ ในการแก้ปัญหา


ไม่พบแท็กที่ดีกว่านี้และฉันต้องระบุในสองครั้งล่าสุด เพิ่มเติมฉันไม่มีตัวแทนเพียงพอที่จะสร้างแท็กใหม่ เหตุผลของจาวาคือเพราะมันเป็นภาษาที่พกพาได้ดีดังนั้นการเขียนที่น่าสนใจมาก นอกจากนี้เวอร์ชันจาวาถูกกำหนดในลักษณะที่เราสามารถเปรียบเทียบรายการที่ตรวจจับสภาพแวดล้อมด้วยความสม่ำเสมอโดยไม่ต้องสิ้นสุดเพื่อเปรียบเทียบส้มกับแอปเปิ้ล
Victor Stafusa

คุณสามารถพิจารณา [underhanded] ยืนยันว่าการตรวจสอบรุ่นของ VM เป็นขั้นตอนในการโจมตีระบบ ฉันไม่สามารถพูดได้ว่าฉันมีข้อเสนอแนะอื่น
dmckee

@dmckee วางแท็ก [code-golf] เพิ่มแท็ก [underhanded] คุณช่วยสร้างแท็ก [java] ได้ไหม
Victor Stafusa

4
ฉันลงคะแนนให้ปิดคำถามนี้เป็นหัวข้อนอกเพราะความท้าทายที่ไม่ได้อยู่ในหัวข้อบนเว็บไซต์นี้อีกต่อไป meta.codegolf.stackexchange.com/a/8326/20469
cat

@cat คุณควรลบแท็กออกเนื่องจากไม่ตรงกับคำถาม
ปีเตอร์เทย์เลอร์

คำตอบ:


9

6/102 = 0.0588

ตรวจจับได้ 6 เวอร์ชั่น มี 102 ราชสกุลศัพท์ (ลดลงจาก 103 หลังจากที่ผมลบpublicในpublic class)

import java.security.Signature;

class GuessVersion {
        public static void main(String[] args) {
                String version = "Java 1.1";
                try {
                        "".getBytes("ISO8859_13");
                        version = "Java 1.3";

                        "".getBytes("ISO8859_15");
                        version = "Java 1.4";

                        Signature.getInstance("SHA256withRSA");
                        version = "Java 5";

                        "".getBytes("KOI8_U");
                        version = "Java 6";

                        Signature.getInstance("SHA256withECDSA");
                        version = "Java 7";
                } catch(Exception e) {}
                System.out.println(version);
        }
}

Java 1.1แนะนำการเข้ารหัสตัวอักษรและอัลกอริทึมการเข้ารหัสลับกับ Java รุ่นต่อมาเพิ่มการเข้ารหัสและอัลกอริทึมมากขึ้น โปรแกรมนี้พยายามใช้การเข้ารหัสและอัลกอริทึมจนกว่าจะได้รับการยกเว้น ผมคาดว่าจะมีการเข้ารหัสที่ขาดหายไปจะโยนและอัลกอริทึมไปโยนjava.io.UnsupportedEncodingExceptionjava.security.NoSuchAlgorithmException

ฉันมี PowerPC Macintosh รุ่นเก่าที่มี Java รุ่นเก่าสี่รุ่น เครื่อง OpenBSD ของฉันมีอีกสองรุ่นดังนั้นฉันจึงทดสอบหกรุ่นเหล่านี้:

  • Java 1.1.8 ใน MRJ 2.2.6 สำหรับ Mac OS 9.2.2
  • Java 1.3.1_16 สำหรับ Mac OS X Panther
  • Java 1.4.2_21 สำหรับ Mac OS X Tiger
  • Java 1.5.0_19 สำหรับ Mac OS X Tiger
  • OpenJDK 1.6.0_32 สำหรับ OpenBSD 5.5
  • OpenJDK 1.7.0_21 สำหรับ OpenBSD 5.5

โปรแกรมนี้สามารถทำงานใน JamVM 1.5.4 และ gcj 4.8.2 สำหรับ OpenBSD แต่ไม่ได้ระบุว่าเป็นการใช้งานที่แตกต่างกัน มันพิมพ์เฉพาะ "Java 5"

Mac OS Runtime สำหรับ Java

ขอบคุณที่ "เขียนครั้งเดียวทำงานได้ทุกที่!" ฉันอาจเขียนโปรแกรมนี้ครั้งเดียวรวบรวมหนึ่งครั้งและเรียกใช้หนึ่ง GuessVersion.class ในเครื่องเสมือนทั้งแปด ฉันต้องการคอมไพเลอร์สำหรับ Java 1.1 ซึ่งเป็นรุ่นที่เก่าที่สุดในคอลเล็กชันของฉัน

คอมไพเลอร์ของฉันเป็นjavacเครื่องมือจาก MRJ SDK 2.2 เนื่องจาก Classic Mac OS ไม่มีบรรทัดคำสั่งjavacเป็นเครื่องมือกราฟิกสวยที่ฉันเลือกไฟล์และตัวเลือกและคลิก "Do Javac" หลังจากที่ฉันแก้ไขรหัสฉันเพียงคลิก "ทำ Javac" อีกครั้ง

javac จาก MRJ SDK 2.2 สำหรับ Classic Mac OS

วิธีที่ง่ายที่สุดในการเรียกใช้ GuessVersion.class คือเปิดใน JBindery ซึ่งเป็นเครื่องมืออื่นจาก MRJ SDK 2.2 รันไทม์คือ MRJ 2.2.6 การใช้งาน Java 1.1.8


22

ฉันไม่แน่ใจว่าคะแนนของฉันคืออะไรเพราะมันขึ้นอยู่กับสิ่งที่คุณคิดว่าเป็นโทเค็นคำศัพท์ แต่ฉันพยายามที่จะใช้ระบบการนับที่ผิดมากที่สุดเท่าที่เป็นไปได้ด้วยสตริงที่ยาว ...

นอกจากนี้ยังขึ้นอยู่กับว่าคุณนับว่าเป็นการระบุ 7 รุ่นที่แตกต่างกันหรือ 16 ... (อาจขยายได้ถึง 190 เล็กน้อย)

class V extends ClassLoader
{
    public static void main(String[]args)
    {
        for(byte b=60;;)
            try {
                byte[]buf="\u00ca\u00fe\u00ba\u00be\u0000\u0000\u00002\u0000\u0005\u0007\u0000\u0003\u0007\u0000\u0004\u0001\u0000\u0001A\u0001\u0000\u0010java/lang/Object\u0006\u0000\u0000\u0001\u0000\u0002\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000".getBytes("ISO-8859-1");
                buf[7]=b--;
                new V().defineClass(buf,0,53);
                System.out.println(b-43);
                break;
            }
            catch(Throwable t){}
    }
}

มันทำงานได้โดยพยายามที่จะกำหนดอินเทอร์เฟซใน classloader ที่กำหนดเองด้วยการลดจำนวนรุ่นที่สำคัญของรูปแบบคลาส คนแรกที่ไม่ได้โยนjava.lang.UnsupportedClassVersionErrorสอดคล้องกับเวอร์ชันของ VM


นับ 84 โทเค็น ยังไม่ได้ทดสอบ
Victor Stafusa

คำตอบของคุณคือใจดี สามารถลดได้ถึง 83 โทเค็นString... argsเล็กน้อยโดยใช้
Victor Stafusa

@Victor ที่จะทำให้คำถามซับซ้อนขึ้นว่าจะรองรับ 7 รุ่นที่แตกต่างกันหรือไม่ ฉันไม่ทราบถึงคอมไพเลอร์ใด ๆ ที่รองรับไวยากรณ์ Java 5 และคอมไพล์ไฟล์คลาสที่เข้ากันได้กับ Java 1
Peter Taylor

จุดดี. ฉันลืมเรื่องนั้นไป
Victor Stafusa

1
Java 1.1.8 (ใน MRJ 2.2.6) ล้มเหลวในการรวบรวมนี้จนกว่าฉันจะเพิ่ม 17 protected Class loadClass(String name, boolean resolve) { return Object.class; }ราชสกุลเพิ่มเติมได้ที่: เอกสาร API ปัจจุบันละเลยที่จะพูดถึงว่านี่เป็นวิธีนามธรรมก่อน Java 1.2 ฉันกลับ Object.class เพราะวิธีการได้รับหนึ่งสายสำหรับ "java.lang.Object"
kernigh

8
class Evil {
    public static void main(String... args) {
        String s1 = "Good";
        s1 += "morning";
        int a = 7;
        if (s1 != s1.intern())
            try {
                a--;
                javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar().equals(null);
            } catch (Throwable e) {
                a--;
            }
        System.out.println(a);
    }
}

อัลกอริทึมการฝึกงานเปลี่ยนไประหว่าง Java 6 และ 7 ดูที่/programming//a/7224864/540552

XMLGregorianCalendar.equals (null) ใช้ในการโยน NullPointerException ใน java 5 แต่สิ่งนี้ได้รับการแก้ไขใน java 6 ดูhttp://bugs.sun.com/view_bug.do?bug_id=6285370

100 96 92 87 85 โทเค็นที่นี่ ขอบคุณ Peter Taylor ที่ลดโทเค็น 7 ครั้ง


1
คุณสามารถบันทึกโทเค็นได้ 3 รายการโดยเก็บหมายเลขเวอร์ชันไว้ใน s1 คุณสามารถประหยัดอีก 2 โดยการจับ Throwable โดยตรงบนสมมติฐานที่DatatypeConfigurationExceptionจะไม่ถูกโยน
Peter Taylor

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