ผลลัพธ์ที่แตกต่างกับสรุปย่อของ Java เทียบกับโปรแกรมอรรถประโยชน์ภายนอก


194

ฉันได้เขียนคลาส Java อย่างง่ายเพื่อสร้างค่าแฮชของไฟล์ Windows Calculator Windows 7 Professional with SP1ฉันใช้ ฉันได้พยายามและJava 6.0.29 Java 7.0.03มีคนบอกฉันได้หรือไม่ว่าทำไมฉันถึงได้รับค่าแฮชที่แตกต่างจาก Java กับยูทิลิตี้ภายนอกและ / หรือเว็บไซต์มากมาย ทุกอย่างตรงกับภายนอกซึ่งมีเพียง Java เท่านั้นที่ให้ผลลัพธ์ที่แตกต่างกัน

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.CRC32;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Checksum 
{
    private static int size = 65536;
    private static File calc = new File("C:/Windows/system32/calc.exe");

    /*
        C:\Windows\System32\calc.exe (verified via several different utilities)
        ----------------------------
        CRC-32b = 8D8F5F8E
        MD5     = 60B7C0FEAD45F2066E5B805A91F4F0FC
        SHA-1   = 9018A7D6CDBE859A430E8794E73381F77C840BE0
        SHA-256 = 80C10EE5F21F92F89CBC293A59D2FD4C01C7958AACAD15642558DB700943FA22
        SHA-384 = 551186C804C17B4CCDA07FD5FE83A32B48B4D173DAC3262F16489029894FC008A501B50AB9B53158B429031B043043D2
        SHA-512 = 68B9F9C00FC64DF946684CE81A72A2624F0FC07E07C0C8B3DB2FAE8C9C0415BD1B4A03AD7FFA96985AF0CC5E0410F6C5E29A30200EFFF21AB4B01369A3C59B58


        Results from this class
        -----------------------
        CRC-32  = 967E5DDE
        MD5     = 10E4A1D2132CCB5C6759F038CDB6F3C9
        SHA-1   = 42D36EEB2140441B48287B7CD30B38105986D68F
        SHA-256 = C6A91CBA00BF87CDB064C49ADAAC82255CBEC6FDD48FD21F9B3B96ABF019916B    
    */    

    public static void main(String[] args)throws Exception {
        Map<String, String> hashes = getFileHash(calc);
        for (Map.Entry<String, String> entry : hashes.entrySet()) {
            System.out.println(String.format("%-7s = %s", entry.getKey(), entry.getValue()));
        }
    }

    private static Map<String, String> getFileHash(File file) throws NoSuchAlgorithmException, IOException {
        Map<String, String> results = new LinkedHashMap<String, String>();

        if (file != null && file.exists()) {
            CRC32 crc32 = new CRC32();
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");

            FileInputStream fis = new FileInputStream(file);
            byte data[] = new byte[size];
            int len = 0;
            while ((len = fis.read(data)) != -1) {
                crc32.update(data, 0, len);
                md5.update(data, 0, len);
                sha1.update(data, 0, len);
                sha256.update(data, 0, len);
            }
            fis.close();

            results.put("CRC-32", toHex(crc32.getValue()));
            results.put(md5.getAlgorithm(), toHex(md5.digest()));
            results.put(sha1.getAlgorithm(), toHex(sha1.digest()));
            results.put(sha256.getAlgorithm(), toHex(sha256.digest()));
        }
        return results;
    }

    private static String toHex(byte[] bytes) {
        String result = "";
        if (bytes != null) {
            StringBuilder sb = new StringBuilder(bytes.length * 2);
            for (byte element : bytes) {
                if ((element & 0xff) < 0x10) {
                    sb.append("0");
                }
                sb.append(Long.toString(element & 0xff, 16));
            }
            result = sb.toString().toUpperCase();
        }
        return result;
    }

    private static String toHex(long value) {
        return Long.toHexString(value).toUpperCase();
    }

}

ฉันเดาว่าคุณเป็นใคร ถ้าคุณทำint newElement = ((int) element) & 0xffและใช้สิ่งนั้นแทนที่จะแก้ปัญหาของคุณ
zapl

64
ควบคู่ไปกับการคำนวณผลรวมตรวจสอบให้คัดลอกไฟล์ไปยังไฟล์ temp บางไฟล์เพื่อให้คุณสามารถเปรียบเทียบสิ่งที่ Java ได้รับกับสิ่งที่คุณได้รับเมื่อคุณใช้เครื่องมืออื่น ๆ Windows อาจแปลก ๆ อย่างนั้น ... ฉันไม่เคยเห็น Java ทำให้เกิดข้อผิดพลาดในการคำนวณแฮช ...
Pawel Veselov

3
โปรแกรมเมอร์ทุกคนควรเขียนโปรแกรมเช่นนี้! รหัสสะอาดและเรียบร้อยมาก
Martijn Courteaux

2
@ user567496: สิ่งที่คุ้มค่ารหัสของคุณให้แฮ็ก SHA-1 ที่ถูกต้องเมื่อเทียบกับการใช้งาน Java SHA-1 อื่น ๆ และเปรียบเทียบกับ commandline sha1sum util ... (ทดสอบกับไฟล์บน Linux ไม่ใช่กับ calc.exe)
TacticalCoder

1
@Fido: ในกรณีนี้มันไม่น่าจะเป็นปัญหาตัวอักษรเพราะ OP กำลังอ่านข้อมูลดิบ: เขาไม่ได้ถอดรหัสอักขระ
TacticalCoder

คำตอบ:


239

เข้าใจแล้ว ระบบไฟล์ Windows ทำงานแตกต่างกันไปขึ้นอยู่กับสถาปัตยกรรมของกระบวนการของคุณ นี้บทความอธิบายมันทั้งหมด - โดยเฉพาะใน:

แต่แอปพลิเคชันแบบ 32 บิตที่มีเส้นทางของฮาร์ดโค้ดและทำงานใน Windows 64 บิตหรือไม่ พวกเขาจะหาโฟลเดอร์ SysWOW64 ใหม่ได้อย่างไรโดยไม่มีการเปลี่ยนแปลงในรหัสโปรแกรมคุณอาจคิดว่า คำตอบก็คืออีมูเลเตอร์เปลี่ยนเส้นทางการเรียกไปยังโฟลเดอร์ System32 ไปยังโฟลเดอร์ SysWOW64 อย่างโปร่งใสดังนั้นแม้ว่าโฟลเดอร์จะฮาร์ดโค้ดไว้ที่โฟลเดอร์ System32 (เช่น C: \ Windows \ System32) อีมูเลเตอร์จะทำให้แน่ใจว่าใช้โฟลเดอร์ SysWOW64 แทน . ซอร์สโค้ดเดียวกับที่ใช้โฟลเดอร์ System32 สามารถคอมไพล์รหัสโปรแกรมทั้งแบบ 32- บิตและ 64- บิตโดยไม่มีการเปลี่ยนแปลงใด ๆ

ลองคัดลอกcalc.exeไปที่อื่น ... จากนั้นเรียกใช้เครื่องมือเดียวกันอีกครั้ง คุณจะได้รับผลลัพธ์เช่นเดียวกับ Java บางอย่างเกี่ยวกับระบบไฟล์ Windows กำลังให้ข้อมูลที่แตกต่างกับเครื่องมือมากกว่าที่มอบให้กับ Java ... ฉันแน่ใจว่ามันเป็นสิ่งที่ต้องทำเมื่ออยู่ในไดเรกทอรี Windows และอาจจัดการกับ "แตกต่าง"

นอกจากนี้ผมเคยทำซ้ำมันใน C # ... และพบว่ามันขึ้นอยู่กับสถาปัตยกรรมของกระบวนการที่คุณกำลังทำงาน ดังนั้นนี่คือโปรแกรมตัวอย่าง:

using System;
using System.IO;
using System.Security.Cryptography;

class Test
{
    static void Main()
    {
        using (var md5 = MD5.Create())
        {
            string path = "c:/Windows/System32/Calc.exe";
            var bytes = md5.ComputeHash(File.ReadAllBytes(path));
            Console.WriteLine(BitConverter.ToString(bytes));
        }
    }
}

และนี่คือเซสชั่นคอนโซล (ลบแช็ทจากคอมไพเลอร์):

c:\users\jon\Test>csc /platform:x86 Test.cs    

c:\users\jon\Test>test
60-B7-C0-FE-AD-45-F2-06-6E-5B-80-5A-91-F4-F0-FC

c:\users\jon\Test>csc /platform:x64 Test.cs

c:\users\jon\Test>test
10-E4-A1-D2-13-2C-CB-5C-67-59-F0-38-CD-B6-F3-C9

64
มีสองรุ่นcalc.exeคือ: 64 บิตในC:\Windows\system32` and 32bit in C: \ Windows \ SysWOW64` สำหรับความเข้ากันได้ในกระบวนการ 32 บิตC:\Windows\system32` is mapped to C: \ Windows \ SysWOW64` กระบวนการ 64 บิตจะเปิดตัวการคำนวณ 64 บิตโดยการประมวลผลแบบ 32 บิตนั้นจะเป็นการประมวลผลแบบ 32 บิต ไม่น่าแปลกใจที่ checksums ของพวกเขาจะแตกต่างกัน หากคุณเปิดไฟล์ค้างไว้และดูด้วยhandles.exeหรือ Process Explorer คุณจะเห็นเส้นทางที่แตกต่างกัน
Richard

25
@ จอนนั่นเป็นสิ่งที่รู้จักกันในชื่อ File System Redirector
David Heffernan

9
@DavidHeffernan ความคิดเห็นอาจแตกต่างกันไปพร้อมกับความหมายของ 'ทำงานได้' การจำลองเสมือนทั้งหมดนี้เป็นการละเมิดหลักการของความประหลาดใจน้อยที่สุดและเพิ่มค่าใช้จ่าย (การจัดสรรและรันไทม์) ระบบปฏิบัติการอื่น ๆ จัดการเพื่อให้การสนับสนุนทั้งแบบ 32-on-64 ที่ดีขึ้นและการจำลองเสมือนของแอปพลิเคชันที่ดีขึ้นโดยมีอุปสรรคน้อยลง / มีบทคัดย่อน้อยลง (ลองเรียกใช้โปรแกรมรวบรวมขยะใน Wow64 หรือลองเปรียบเทียบผลรวม md5 เช่น OP และกรณีเฉพาะอื่น ๆ )
sehe

5
บางครั้งผมสงสัยว่าคน upvote คุณเพราะคุณเป็นจอนสกีตไม่เพียงเพราะคำตอบ ฉันไม่ได้บอกว่าคำตอบนั้นไม่ดีหรืออะไร แต่ 145 upvotes เมื่อคำตอบคือ "มีอะไรบางอย่างเกิดขึ้นใน windows" (เพื่อความเป็นธรรมคุณให้ลิงค์ แต่ยัง) ดูเหมือนว่าคนกำลังพิจารณามากกว่าแล้วเพียงคำตอบของคุณเมื่อ พวกเขาโหวตขึ้น ฉันไม่ได้เกลียดคุณเลย แต่นี่ก็หมายความว่ามันจะต้องใช้เวลาสักพักก่อนที่ฉันจะตามหาคุณ: P
Jason Ridge

5
บล็อกเป็นวิธีที่ฉันพบ ฉันหวังว่าจะเป็นเวทย์มนตร์ของ Jon Skeet แต่ฉันรู้สึกเหมือน "เฮ้ฉันทำได้แล้ว" อาจจะไม่เกือบจะเร็ว แต่คุณก็ไป ตกลงบางทีฉันอาจจะไม่ได้ แต่ยังคง สำหรับหมวกนั้นมีการปลอบใจเพียงเล็กน้อยเพราะนั่นหมายถึงว่าในวันใดวันหนึ่งคุณจะไปถึงมันและฉันจึงไม่สามารถติดต่อคุณได้ โอ้ดี ...
เจสันริดจ์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.