
مجموعة أدوات متعددة الوظائف لفك تشويش جافا
Threadtear هي أداة متعددة الوظائف لإزالة التعتيم عن كود جافا. قريبًا سيتم دعم تطبيقات أندرويد (أعمل حاليًا على محول من دالفيك إلى جافا). مناسبة لتحليل الكود بسهولة دون القلق كثيرًا بشأن التعتيم. تشمل حتى أغلى أدوات التعتيم مثل ZKM أو Stringer. لتسهيل التصحيح، توجد أدوات أخرى مضمنة. يمكن إدراج أرقام أسطر التصحيح لفهم أفضل لمصدر الاستثناءات، أو إضافة .printStackTrace() إلى الكتل try catch دون إعادة ترجمة الكود. لم يعد التوافق العكسي مشكلة، إذا لم تُستخدم طرق خاصة بالإصدار. حلل تدفق الكود في رسم بياني لفهم الخوارزميات بشكل أفضل.

التنفيذ هو مهمة يتم تشغيلها وتعديل جميع ملفات الكلاس المحملة. هناك أنواع متعددة من التنفيذات، تتراوح من تنظيف البايت كود إلى إزالة تعتيم السلاسل النصية. تأكد من ترتيبها بشكل صحيح. على سبيل المثال، يجب تنفيذ التنفيذات الخاصة بالتنظيف في النهاية، ولكنها يمكن أن تساعد أيضًا التنفيذات الأخرى إذا تم تنفيذها أولاً. عندما تكون مستعدًا، انقر على زر "Run"، وستُنفذ بالترتيب.
استخدم هذه الأداة على مسؤوليتك الخاصة. بعض التنفيذات تستخدم مُحمّلات كلاس (ClassLoaders) منفّذة لتشغيل كود من ملف الجار. قد يقوم مهاجم بتعديل البايت كود بحيث يتم تنفيذ كود خبيث. التنفيذات المتأثرة تستخدم الكلاس me.nov.threadtear.asm.vm.VM. تُستخدم هذه في الغالب لفك تشفير السلاسل النصية أو تعتيم الوصول/الموارد، لأنه من الأسهل بكثير تنفيذ طرق فك التشفير عن بُعد.
يبذل Threadtear قصارى جهده لحمايتك من المكالمات الخبيثة (تنفيذات الكود التعسفية) باستخدام SecurityManager الخاص به، ولكن لا يوجد ضمان. خاصة مع أدوات إزالة التعتيم مثل ZKM أو Stringer، عليك أن تكون حذرًا جدًا، حيث يجب السماح بالانعكاس (reflection)، وإلا فلن تعمل. إذا اكتشفت ثغرة ACE، يرجى فتح مشكلة (issue). سأحاول إصلاحها في أقرب وقت ممكن.
أولاً، قم بتشغيل gradle build، ثم gradle fatJar. في builds/libs سيتم إنشاء ملف جار قابل للتشغيل. إذا كنت لا تريد تنزيل المستودع، يمكنك استخدام أحدث إصدار.
يمكنك بسهولة إنشاء مهمة تنفيذ خاصة بك. فقط قم بتوسيع me.nov.threadtear.execution.Execution:
public class MyExecution extends Execution {
public MyExecution() {
super(ExecutionCategory.CLEANING /* category */, "My execution" /* name */,
"Executes something" /* description, can use html */);
}
/**
* This method is invoked when the user clicks on the Run button
* @return true if success, false if failure
*/
@Override
public boolean execute(Map<String, Clazz> classes, boolean verbose) {
classes.values().stream().map(c -> c.node).forEach(c -> {
//transform the classes here using the tree-API of ASM
});
return false;
}
}
لتحميل ClassNodes في وقت التشغيل، استخدم الكلاس me.nov.threadtear.asm.vm.VM وقم بتطبيق me.nov.threadtear.asm.vm.IVMReferenceHandler:
public class MyExecution extends Execution implements IVMReferenceHandler {
public MyExecution() {
super(ExecutionCategory.GENERIC, "My execution", "Loads ClassNodes at runtime");
}
@Override
public boolean execute(Map<String, Clazz> classes, boolean verbose) {
classes.values().stream().map(c -> c.node).forEach(c -> {
VM vm = VM.constructVM(this);
//transform bytecode to java.lang.Class
Class<?> loadedClass = vm.loadClass(c.name.replace('/', '.'), true);
//do stuff with your class here
loadedClass.getMethods()[0].invoke(...);
return true;
});
}
/**
* Will get invoked by VM, when VM.loadClass is called
*/
@Override
public ClassNode tryClassLoad(String name) {
//try to find the class to be loaded in open jar archive
return classes.containsKey(name) ? classes.get(name).node : null;
}
}
باستخدام ConstantTracker (me.nov.threadtear.analysis.stack.ConstantTracker) يمكنك تحليل الطرق وتتبع قيم المكدس غير المتغيرة. على سبيل المثال، إذا تم دفع iconst_0 إلى المكدس، فإن القيمة نفسها لا تُفقد كما في محلل ASM الأساسي، ويمكنك استخدامها لتوقع الأشياء لاحقًا في الكود.
public class MyExecution extends Execution implements IConstantReferenceHandler {
public MyExecution() {
super(ExecutionCategory.GENERIC, "My execution", "Performs stack analysis and replaces code.");
}
@Override
public boolean execute(Map<String, Clazz> classes, boolean verbose) {
classes.values().stream().map(c -> c.node).forEach(this::analyzeAndRewrite);
return true;
}
public void analyzeAndRewrite(ClassNode cn) {
cn.methods.forEach(m -> {
// this analyzer keeps known stack values, e.g. can be useful for jump prediction
Analyzer<ConstantValue> a = new Analyzer<ConstantValue>(new ConstantTracker(this, Access.isStatic(m.access), m.maxLocals, m.desc, new Object[0]));
try {
a.analyze(cn.name, m);
} catch (AnalyzerException e) {
logger.severe("Failed stack analysis in " + cn.name + "." + m.name + ":" + e.getMessage());
return;
}
Frame<ConstantValue>[] frames = a.getFrames();
InsnList rewrittenCode = new InsnList();
Map<LabelNode, LabelNode> labels = Instructions.cloneLabels(m.instructions);
// rewrite method instructions
for (int i = 0; i < m.instructions.size(); i++) {
AbstractInsnNode ain = m.instructions.get(i);
Frame<ConstantValue> frame = frames[i];
// replace / modify instructions, etc...
if (frame.getStackSize() > 0) {
ConstantValue top = frame.getStack(frame.getStackSize() - 1);
if (top.isKnown() && top.isInteger()) {
int knownTopStackValue = top.getInteger();
// use the known stack to remove jumps, simplify code, etc...
// if(...) { rewrittenCode.add(...); }
continue;
}
}
rewrittenCode.add(ain.clone(labels));
}
// update instructions and fix try catch blocks, local variables, etc...
Instructions.updateInstructions(m, labels, rewrittenCode);
});
}
/**
* Use this method to predict stack values if fields are loaded
*/
@Override
public Object getFieldValueOrNull(BasicValue v, String owner, String name, String desc) {
return null;
}
/**
* Use this method to predict stack values if methods are invoked on known objects
*/
@Override
public Object getMethodReturnOrNull(BasicValue v, String owner, String name, String desc, List<? extends ConstantValue> values) {
if (name.equals("toCharArray") && owner.equals("java/lang/String")) {
if (!values.get(0).isKnown()) {
// invocation target is not known, we can't compute the return
return null;
}
return ((String) values.get(0).getValue()).toCharArray();
}
return null;
}
}
لا تنس إضافة تنفيذك إلى الشجرة في me.nov.threadtear.execution.ExecutionLink!
هناك بعض الحيل التي يمكن أن تساعدك في تحديد ملفات الجار وإزالة تعتيمها بنجاح. قبل تشغيل التنفيذات، قم بفك ترجمة الكود لمعرفة ما يجب استخدامه. يمكنك استخدام أداة فك الترجمة المضمنة لذلك.
أفضل ترتيب لإزالة التعتيم هو التنفيذات العامة > إزالة تعتيم الوصول > إزالة تعتيم السلاسل النصية > تنفيذات التنظيف.
تظهر أدوات التعتيم أنماطًا يمكنك استخدامها لتحديدها. أسهل طريقة للتعرف على أداة تعتيم هي تصفح ملف META-INF/MANIFEST.MF. من الممكن أن يكون هناك سمة Obfuscated-By: XXX أو Protected-By: XXX.
كود شديد التعتيم (في التدفق)، غالبًا ما يلاحظ وجود طريقة فك تشفير سلاسل نصية في المُهيئ الثابت (static initializer) تحتوي على تحويلات (switches)، أو طرق فك تشفير سلاسل ذات كتلة تحويل طويلة جدًا (حوالي 250 حالة). ZKM هي واحدة من أفضل (وأقدم) أدوات التعتيم لجافا، وهي باهظة الثمن. موقعها الإلكتروني قديم قدم الأداة نفسها.

إذا كان ملف الجار الخاص بك يحتوي على بعض الكلاسات الخاصة مع خوارزميات فك تشفير ضخمة تُستخدم لتعتيم السلاسل النصية وتعتيم الوصول، فمن المحتمل أنه Stringer. الحماية ليست سيئة و Stringer هي واحدة من أغلى أدوات التعتيم. على عكس أدوات التعتيم العادية، لا تأتي مع تعتيم الأسماء. بل تُستخدم كـ "طبقة ثانية". ربما 90% من الأشخاص الذين يستخدمون هذه الأداة يستخدمون كراك (crack)، لأنها تكلف أكثر من سيارة. إذا تم تعتيم ملفك بعدة أدوات تعتيم، وكان Stringer واحدًا منها، فيجب أن تبدأ إزالة التعتيم بـ Stringer، لأن تعتيم Stringer لا يمكن الكتابة فوقه (بسبب توقيع JAR المخصص واستخدام أسماء الطرق أثناء فك تشفير السلاسل).

أسماء الكلاسات مثل IiIlIlIiIl أو aUx, cOn, PrX تشير إلى تعتيم Allatori. Allatori شائع جدًا بين ملفات الجار المعتمة، لأنها توفر عرضًا تجريبيًا مجانيًا يمكن الوصول إليه ببضع نقرات. ليس من الصعب عكس تعتيمها.

Paramorphism هي مثل الأخ الأصغر لـ Stringer، حيث تبدو مشابهة لكنها ليست بنفس جودتها. كما أن لديها بعض الميزات المثيرة التي تهدف إلى تعطيل أدوات الهندسة العكسية، والتي يمكن إزالتها بسهولة. قوة التعتيم مشابهة لـ Allatori.

بالنسبة لأدوات التعتيم الأخرى، يمكنك تجربة التنفيذات العامة أو فتح مشكلة (issue)، وسأرى ما يمكنني فعله.
قبل اختيار تنفيذ، تحقق من نصوص التلميحات عند التمرير (tool-tip). تحتوي على وصف صغير لما تفعله، ولكن أيضًا علامات (tags) تساعدك على فهم كيف سيتغير سلوك ملف JAR الخاص بك.
Threadtear مرخصة بموجب رخصة جنو العمومية العامة 3.0
كانت هذه الأداة جهدًا كبيرًا. إذا وفرت لك وقتًا، وتريد شراء فنجان قهوة لي، يمكنك فعل ذلك هنا: تبرع بالبيتكوين
استخدم Threadtear للأغراض القانونية فقط. لا تهدف Threadtear إلى أن تكون أداة كراك (cracking)، بل بالأحرى مجموعة أدوات لتحليل البرامج الضارة. يرجى فتح مشكلة (issue) أو مراسلتي عبر البريد الإلكتروني إذا لم يعمل محول (transformer) بشكل صحيح، وإرفاق السجل (log). لاحظ أن ملفات الإخراج على الأرجح غير قابلة للتشغيل. إذا كنت لا تزال تريد محاولة تشغيلها، استخدم -noverify كوسيط JVM! تم تصميم هذه الأداة للاستخدام مع Java 8، ولكنها ستعمل على الأرجح على الإصدارات الأعلى أيضًا.