จะล็อคคลาส Java ที่คอมไพล์แล้วเพื่อป้องกันการถอดรหัสได้อย่างไร?


98

ฉันจะล็อกคลาส Java ที่คอมไพล์แล้วเพื่อป้องกันการถอดรหัสได้อย่างไร

ฉันรู้ว่านี่จะต้องเป็นหัวข้อที่พูดคุยกันอย่างดีบนอินเทอร์เน็ต แต่ฉันไม่สามารถหาข้อสรุปใด ๆ ได้หลังจากอ้างอิงถึง

หลายคนแนะนำ obfuscator แต่พวกเขาแค่เปลี่ยนชื่อคลาสวิธีการและฟิลด์ด้วยลำดับอักขระที่ยากต่อการจดจำ แต่แล้วค่าคงที่ที่ละเอียดอ่อนล่ะ?

ตัวอย่างเช่นคุณได้พัฒนาองค์ประกอบการเข้ารหัสและการถอดรหัสโดยใช้เทคนิคการเข้ารหัสตามรหัสผ่าน ในกรณีนี้คน Java ทั่วไปสามารถใช้JADเพื่อถอดรหัสไฟล์คลาสและดึงค่ารหัสผ่าน (กำหนดเป็นค่าคงที่) รวมทั้งเกลือได้อย่างง่ายดายและในทางกลับกันสามารถถอดรหัสข้อมูลโดยการเขียนโปรแกรมอิสระขนาดเล็ก!

หรือควรสร้างส่วนประกอบที่ละเอียดอ่อนดังกล่าวในโค้ดเนทีฟ (เช่น VC ++) และเรียกใช้ผ่านJNI ?


แม้แต่โค้ดเนทีฟที่ถอดแยกชิ้นส่วนก็ยังสามารถอ่านได้สำหรับบางคนคุณอาจต้องใช้ obfuscator หรือแอสเซมบลีที่ทำด้วยมือเพื่อให้ไม่ชัดเจน (C ++ ทั่วไปที่คอมไพล์ด้วยการปรับให้เหมาะสมสามารถอ่านได้เพียงพอ) ไม่ว่าโค้ดใดก็ตามที่ทำงานบนอุปกรณ์ของผู้ใช้ก็สามารถถูกดักจับได้ แม้ว่าความต้องการด้านต้นทุน / ทักษะของการสกัดกั้นดังกล่าวอาจค่อนข้างสูงตัวอย่างเช่นการเจาะรหัสชิป "ป้องกันการงัดแงะ" แบบสมาร์ทการ์ดนั้นไม่ได้เป็นเรื่องเล็กน้อย แต่ทำได้ด้วยอุปกรณ์และทักษะชั้นยอดเท่านั้น ด้วยคลาส Java ... ฉันไม่ต้องกังวลมากนักคุณอาจเข้ารหัสได้มากพอที่จะทำให้เด็กสคริปต์หายไปไม่มาก
Ped7g

คำตอบ:


97

ตัวทำลายล้างของ Java bytecode ขั้นสูงบางตัวทำมากกว่าการแยกชื่อคลาส ตัวอย่างเช่นZelix KlassMasterยังสามารถช่วงชิงการไหลของโค้ดในลักษณะที่ทำให้ยากต่อการติดตามและทำงานเป็นเครื่องมือเพิ่มประสิทธิภาพโค้ดที่ยอดเยี่ยม ...

นอกจากนี้ obfuscators หลายตัวยังสามารถช่วงชิงค่าคงที่สตริงของคุณและลบโค้ดที่ไม่ได้ใช้ออกไป

อีกวิธีหนึ่งที่เป็นไปได้ (ไม่จำเป็นต้องยกเว้นการทำให้สับสน) คือการใช้ไฟล์ JAR ที่เข้ารหัสและ classloader แบบกำหนดเองที่ถอดรหัส (ควรใช้ไลบรารีรันไทม์ดั้งเดิม)

ประการที่สาม (และอาจให้การป้องกันที่แข็งแกร่งที่สุด) คือการใช้คอมไพเลอร์เนทีฟล่วงหน้าเช่นGCCหรือExcelsior JETตัวอย่างเช่นที่รวบรวมโค้ด Java ของคุณโดยตรงกับไบนารีเนทีฟเฉพาะแพลตฟอร์ม

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


14
+1 สำหรับ "ล็อคมีไว้สำหรับสัตว์" ฉันเดาว่าคำที่เหมาะสมที่นี่น่าจะเป็นสคริปต์ kiddies
Antimony

คุณหมายถึง GCJ และมันตายแล้ว
user207421

1
การเข้ารหัสไฟล์ Componio jar ก็ตายไปแล้วเช่นกัน ใช้JarProtectorแทน
J.Profi

16

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


13

ข้อจำกัดความรับผิดชอบ: ฉันไม่ใช่ผู้เชี่ยวชาญด้านความปลอดภัย

ฟังดูเหมือนเป็นความคิดที่ไม่ดี: คุณกำลังปล่อยให้ใครบางคนเข้ารหัสข้อมูลด้วยคีย์ 'ซ่อน' ที่คุณให้เขา ฉันไม่คิดว่าจะปลอดภัยขนาดนี้

บางทีปุ่มอสมมาตรอาจใช้งานได้:

  • ปรับใช้ใบอนุญาตที่เข้ารหัสด้วยคีย์สาธารณะเพื่อถอดรหัส
  • ให้ลูกค้าสร้างใบอนุญาตใหม่และส่งให้คุณเพื่อเข้ารหัส
  • ส่งใบอนุญาตใหม่กลับไปยังลูกค้า

ฉันไม่แน่ใจ แต่ฉันเชื่อว่าไคลเอนต์สามารถเข้ารหัสคีย์ใบอนุญาตด้วยคีย์สาธารณะที่คุณให้ไว้ได้ จากนั้นคุณสามารถถอดรหัสด้วยคีย์ส่วนตัวของคุณและเข้ารหัสใหม่ได้เช่นกัน

คุณสามารถเก็บคู่คีย์สาธารณะ / ส่วนตัวแยกกันต่อลูกค้าหนึ่งรายเพื่อให้แน่ใจว่าคุณได้รับของจากลูกค้าที่เหมาะสม - ตอนนี้คุณต้องรับผิดชอบคีย์ ...


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

12

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

จะทำอย่างไรกับเรื่องนี้?

พยายามอย่าจัดส่งคีย์เป็นค่าคงที่ที่เข้ารหัสในรหัสของคุณ: เก็บไว้เป็นการตั้งค่าต่อผู้ใช้ กำหนดให้ผู้ใช้รับผิดชอบในการดูแลคีย์นั้น


6

@jatanp: หรือดีกว่านั้นพวกเขาสามารถแยกคอมไพล์ลบรหัสลิขสิทธิ์และคอมไพล์ใหม่ได้ ด้วย Java ฉันไม่คิดว่าจะมีวิธีแก้ปัญหาที่เหมาะสมและป้องกันการแฮ็กสำหรับปัญหานี้ได้ แม้แต่ดองเกิลตัวเล็กที่ชั่วร้ายก็ไม่สามารถป้องกันสิ่งนี้ได้ด้วย Java

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

ดังนั้นฉันจึงต้องขอให้คุณทำจริงๆต้องป้องกันแข็งเหมือนที่คุณกำลังมองหาสำหรับการประยุกต์ใช้ของคุณหรือไม่ ฐานลูกค้าของคุณมีลักษณะอย่างไร? (องค์กรหรือกลุ่มเกมเมอร์วัยรุ่นที่ไหนจะเป็นปัญหามากกว่ากัน?)


ในความเป็นจริงมีวิธีการป้องกันการแฮ็กที่เหมาะสมซึ่ง btw ดูเหมือนดองเกิล: excelsior-usa.com/blog/excelsior-jet/…
Dmitry Leskov

@DmitryLeskov 'ทนต่อการแฮ็ก' อาจจะ แต่เป็นเพียงการเร่งความเร็วสำหรับทุกคนที่ต้องการรหัส ในตอนท้ายของวันรหัสไบต์จะต้องทำงานบนแพลตฟอร์มโฮสต์ที่ไม่ได้เข้ารหัส หยุดเต็ม
Stu Thompson

คุณยังไม่ได้อ่านโพสต์ที่ฉันลิงก์ไป bytecode คือแปลงเป็นรหัส CPU ของดองเกิลและเข้ารหัส เมื่อผู้ใช้เรียกใช้แอปที่มีการป้องกันรหัสที่เข้ารหัสนั้นจะถูกโอนไปยัง "ดองเกิล" ดองเกิลถอดรหัสและเรียกใช้บน CPU
Dmitry Leskov

2
นักเล่นเกมวัยรุ่นขององค์กร
odiszapc

3

หากคุณกำลังมองหาวิธีการแก้ปัญหาการออกใบอนุญาตคุณสามารถตรวจสอบTrueLicense API มันขึ้นอยู่กับการใช้คีย์แบบอสมมาตร อย่างไรก็ตามไม่ได้หมายความว่าแอปพลิเคชันของคุณไม่สามารถแตกได้ ทุกแอปพลิเคชันสามารถแตกได้ด้วยความพยายามที่เพียงพอ สิ่งที่สำคัญมากคือStu ตอบโดยหาว่าคุณต้องการการป้องกันที่รัดกุมเพียงใด


2

ฉันไม่คิดว่าจะมีวิธีการต่อต้านการละเมิดออฟไลน์ที่มีประสิทธิภาพ อุตสาหกรรมวิดีโอเกมพยายามที่จะพบว่าหลายครั้งและโปรแกรมของพวกเขามักจะแตก ทางออกเดียวคือต้องเรียกใช้โปรแกรมออนไลน์โดยเชื่อมต่อกับเซิร์ฟเวอร์ของคุณเพื่อให้คุณสามารถตรวจสอบคีย์ lincense ได้และมีการเชื่อมต่อที่ใช้งานเพียงครั้งเดียวโดยผู้รับใบอนุญาตในแต่ละครั้ง นี่คือวิธีการของ World of WarcraftหรือDiabloทำงาน แม้แต่เซิร์ฟเวอร์ส่วนตัวที่ยากก็มีการพัฒนาเพื่อหลีกเลี่ยงการรักษาความปลอดภัย

ต้องบอกว่าฉันไม่เชื่อว่า บริษัท ขนาดกลาง / ขนาดใหญ่ใช้ซอฟต์แวร์ที่คัดลอกอย่างผิดกฎหมายเพราะค่าใช้จ่ายของใบอนุญาตสำหรับพวกเขานั้นน้อยมาก (บางทีฉันไม่รู้ว่าคุณต้องเสียค่าใช้จ่ายเท่าไรสำหรับโปรแกรมของคุณ) เมื่อเทียบกับ ค่าใช้จ่ายของรุ่นทดลอง


2

คุณสามารถใช้การเข้ารหัสไบต์โค้ดได้โดยไม่ต้องกลัว

ความจริงก็คือกระดาษที่อ้างถึงด้านบน "การถอดรหัสการเข้ารหัสไบต์รหัส Java ของ Java" มีตรรกะที่ผิดพลาด ข้อเรียกร้องหลักของเอกสารคือก่อนที่จะรันคลาสทั้งหมดจะต้องถูกถอดรหัสและส่งต่อไปยังClassLoader.defineClass(...)เมธอดวิธีการแต่นี่ไม่เป็นความจริง

สมมติฐานที่พลาดที่นี่จะระบุว่าพวกเขากำลังทำงานอยู่ในแท้หรือมาตรฐานสิ่งแวดล้อม Java เวลาทำงาน ไม่มีอะไรสามารถบังคับให้แอปพลิเค Java การป้องกันไม่เพียง แต่จะเปิดชั้นเรียนเหล่านี้ ClassLoaderแต่แม้ถอดรหัสและผ่านไปยัง กล่าวอีกนัยหนึ่งคือหากคุณอยู่ใน JRE มาตรฐานคุณจะไม่สามารถสกัดกั้นdefineClass(...)เมธอดได้เนื่องจาก java มาตรฐานไม่มี API สำหรับจุดประสงค์นี้และหากคุณใช้ JRE ที่แก้ไขด้วยแพตช์ClassLoaderหรือ "เคล็ดลับแฮ็กเกอร์" อื่น ๆ คุณจะไม่สามารถทำได้เนื่องจากมีการป้องกัน แอพ java จะไม่ทำงานเลยดังนั้นคุณจะไม่มีอะไรมาขัดขวาง และไม่สำคัญว่าจะใช้ "โปรแกรมค้นหาโปรแกรมแก้ไข" ใดหรือแฮกเกอร์ใช้กลอุบายใด รายละเอียดทางเทคนิคเหล่านี้เป็นเรื่องราวที่ค่อนข้างแตกต่างกัน


คุณตั้งใจจะตรวจจับ JVM ที่ถูกแพตช์อย่างไร? อย่างไรก็ตามทั้งหมดนี้ทำให้สิ่งต่าง ๆ ยากขึ้นเล็กน้อย
Antimony

คุณไม่สามารถค้นหาการเรียกใช้ defineClass () ในตัวเรียกใช้งานแอปได้หรือไม่? เมื่อคุณโทรออกคุณจะต้องส่งอาร์เรย์ของไบต์ที่ถอดรหัสอยู่ดี นั่นไม่ใช่จุดอื่นที่อาจทำให้แหล่งกำเนิดเดิมรั่วไหล?
ลัคนา

4
ฉันไม่ค่อยเห็นด้วยกับคำตอบนี้ สำหรับฉันดูเหมือนว่า "คำถาม: วิธีที่ง่ายที่สุดในการหา Pi คืออะไรคำตอบ: เอา 2 * Pi แล้วหารด้วยสอง" ฉันไม่เห็นด้วยกับแนวคิดนี้ แต่ขอรายละเอียดเพิ่มเติมได้ไหม ตัวอย่างเช่นคุณคาดว่าโปรแกรมหลักจะเขียนด้วย java แท้หรือไม่? รวมถึงรหัสที่ต้องการแก้ไขหรือไม่
Patrick M

-1

ถาม: ถ้าฉันเข้ารหัสไฟล์. class ของฉันและใช้ classloader ที่กำหนดเองเพื่อโหลดและถอดรหัสในทันทีการดำเนินการนี้จะป้องกันการถอดรหัสหรือไม่

ตอบ: ปัญหาในการป้องกันการถอดรหัส Java byte-code นั้นเกือบจะเป็นภาษาเก่า แม้จะมีเครื่องมือทำให้งงงวยมากมายในตลาด แต่นักเขียนโปรแกรม Java มือใหม่ยังคงคิดหาวิธีใหม่ ๆ และชาญฉลาดในการปกป้องทรัพย์สินทางปัญญาของตน ในภาค Q&A ของ Java นี้ฉันจะปัดเป่าความเชื่อผิด ๆ เกี่ยวกับแนวคิดที่มักจะได้รับการแก้ไขในฟอรัมการสนทนา

ความสะดวกอย่างยิ่งที่ไฟล์ Java .class สามารถสร้างขึ้นใหม่ในซอร์ส Java ที่มีลักษณะใกล้เคียงกับต้นฉบับนั้นมีส่วนเกี่ยวข้องกับเป้าหมายการออกแบบไบต์โค้ด Java และการแลกเปลี่ยน เหนือสิ่งอื่นใดรหัส Java byte ได้รับการออกแบบมาเพื่อความกะทัดรัดความเป็นอิสระของแพลตฟอร์มความคล่องตัวของเครือข่ายและความสะดวกในการวิเคราะห์โดยตัวแปลรหัสไบต์และ JIT (คอมไพเลอร์แบบไดนามิกในเวลาเดียว) / HotSpot โดยทั่วไปแล้วไฟล์. class ที่คอมไพล์จะแสดงเจตนาของโปรแกรมเมอร์อย่างชัดเจนดังนั้นจึงสามารถวิเคราะห์ได้ง่ายกว่าซอร์สโค้ดเดิม

ทำได้หลายอย่างถ้าไม่ป้องกันการแยกส่วนอย่างสมบูรณ์อย่างน้อยก็ทำให้ยากขึ้น ตัวอย่างเช่นในขั้นตอนหลังการคอมไพล์คุณสามารถนวดข้อมูล. class เพื่อทำให้โค้ดไบต์อ่านได้ยากขึ้นเมื่อถอดรหัสคอมไพล์หรือถอดรหัสเป็นโค้ด Java ที่ถูกต้องได้ยากขึ้น (หรือทั้งสองอย่าง) เทคนิคเช่นการใช้ชื่อเมธอดที่มากเกินไปจะทำงานได้ดีสำหรับอดีตและการจัดการโฟลว์การควบคุมเพื่อสร้างโครงสร้างควบคุมที่ไม่สามารถแสดงผ่านไวยากรณ์ของ Java ได้ดี เครื่องกำจัดขยะเชิงพาณิชย์ที่ประสบความสำเร็จมากขึ้นใช้การผสมผสานระหว่างเทคนิคเหล่านี้และเทคนิคอื่น ๆ

น่าเสียดายที่ทั้งสองวิธีต้องเปลี่ยนรหัสจริง ๆ ที่ JVM จะทำงานและผู้ใช้หลายคนกลัว (อย่างถูกต้อง) ว่าการเปลี่ยนแปลงนี้อาจเพิ่มข้อบกพร่องใหม่ให้กับแอปพลิเคชันของตน นอกจากนี้วิธีการและการเปลี่ยนชื่อฟิลด์อาจทำให้การเรียกใช้การสะท้อนหยุดทำงาน การเปลี่ยนชื่อคลาสและแพ็กเกจจริงสามารถทำลาย Java API อื่น ๆ (JNDI (Java Naming and Directory Interface) ผู้ให้บริการ URL และอื่น ๆ ) นอกเหนือจากชื่อที่เปลี่ยนแปลงแล้วหากการเชื่อมโยงระหว่างออฟเซ็ตรหัสไบต์คลาสและหมายเลขบรรทัดต้นทางมีการเปลี่ยนแปลงการกู้คืนสแต็กเทรซข้อยกเว้นเดิมอาจทำได้ยาก

จากนั้นมีตัวเลือกในการทำให้ซอร์สโค้ด Java ต้นฉบับสับสน แต่โดยพื้นฐานแล้วสิ่งนี้ทำให้เกิดปัญหาที่คล้ายกัน เข้ารหัสไม่คลุมเครือ?

บางทีข้างต้นอาจทำให้คุณคิดว่า "ถ้าแทนที่จะจัดการรหัสไบต์ฉันจะเข้ารหัสคลาสทั้งหมดของฉันหลังจากการคอมไพล์และถอดรหัสทันทีภายใน JVM (ซึ่งสามารถทำได้ด้วย classloader ที่กำหนดเอง) จากนั้น JVM จะดำเนินการของฉัน รหัสไบต์ดั้งเดิมและยังไม่มีอะไรให้ถอดรหัสหรือทำวิศวกรรมย้อนกลับใช่ไหม "

น่าเสียดายที่คุณคิดผิดทั้งที่คิดว่าคุณเป็นคนแรกที่คิดไอเดียนี้และคิดว่ามันใช้งานได้จริง และเหตุผลนั้นไม่เกี่ยวข้องกับความแข็งแกร่งของรูปแบบการเข้ารหัสของคุณ

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