
बहु-कार्यात्मक Java deobfuscation टूल सूट
Threadtear एक बहुक्रियाशील डीओबफस्केशन टूल है जो Java के लिए है। एंड्रॉइड एप्लिकेशन सपोर्ट जल्द ही आ रहा है (वर्तमान में एक डेल्विक से Java कन्वर्टर पर काम चल रहा है)।
ऑबफस्केशन के बारे में बहुत अधिक चिंता किए बिना कोड विश्लेषण को आसान बनाने के लिए उपयुक्त।
ZKM या Stringer जैसे सबसे महंगे ऑबफस्केटर भी शामिल हैं। आसान डिबगिंग के लिए अन्य टूल भी शामिल हैं।
एक्सेप्शन कहाँ से उत्पन्न होते हैं यह बेहतर समझने के लिए डीबग लाइन नंबर डालें, या कोड को पुनः संकलित किए बिना ट्राई-कैच ब्लॉक्स में .printStackTrace() जोड़ें।
रिवर्स संगतता अब कोई समस्या नहीं है, यदि संस्करण-विशिष्ट विधियों का उपयोग नहीं किया जाता है। ग्राफ़ में कोड प्रवाह का विश्लेषण करें, ताकि एल्गोरिदम को बेहतर ढंग से समझा जा सके।

एक "निष्पादन" एक कार्य है जो निष्पादित होता है और सभी लोडेड क्लास फ़ाइलों को संशोधित करता है। निष्पादन के कई प्रकार हैं, बाइटकोड क्लीनअप से लेकर स्ट्रिंग डीऑबफस्केशन तक। सुनिश्चित करें कि वे सही क्रम में हों। उदाहरण के लिए क्लीनअप निष्पादन को अंत में निष्पादित किया जाना चाहिए, लेकिन यदि पहले निष्पादित किया जाए तो यह अन्य निष्पादनों में भी मदद कर सकता है। यदि आप तैयार हैं, तो "Run" बटन पर क्लिक करें, और वे क्रम से निष्पादित होंगे।
इस टूल का उपयोग अपने जोखिम पर करें। कुछ निष्पादन JAR फ़ाइल से कोड चलाने के लिए कार्यान्वित ClassLoaders का उपयोग करते हैं। एक हमलावर बाइटकोड में इस तरह से बदलाव कर सकता है कि दुर्भावनापूर्ण कोड निष्पादित हो सके।
प्रभावित निष्पादन वर्ग me.nov.threadtear.asm.vm.VM का उपयोग करते हैं।
ये ज्यादातर स्ट्रिंग या संसाधन / एक्सेस ऑबफस्केशन को डीक्रिप्ट करने के लिए उपयोग होते हैं, क्योंकि डिक्रिप्शन विधियों को दूरस्थ रूप से निष्पादित करना बहुत आसान है।
Threadtear अपने स्वयं के SecurityManager का उपयोग करके आपको दुर्भावनापूर्ण कॉल (मनमाना कोड निष्पादन) से बचाने की पूरी कोशिश करता है, लेकिन कोई गारंटी नहीं है।
ZKM या Stringer जैसे डीऑबफस्केटर के लिए विशेष रूप से आपको बहुत सावधान रहना होगा, क्योंकि रिफ्लेक्शन की अनुमति देनी होती है, अन्यथा वे कार्य नहीं करेंगे।
यदि आप कोई ACE पाते हैं, तो कृपया एक इश्यू खोलें। मैं उन्हें जल्द से जल्द ठीक करने का प्रयास करूंगा।
सबसे पहले, gradle build चलाएँ, फिर gradle fatJar चलाएँ। builds/libs में एक चलाने योग्य jar फ़ाइल बन जानी चाहिए। यदि आप रिपोजिटरी डाउनलोड नहीं करना चाहते हैं, तो आप नवीनतम रिलीज़ का उपयोग कर सकते हैं।
आप आसानी से अपना स्वयं का निष्पादन कार्य बना सकते हैं। बस me.nov.threadtear.execution.Execution को विस्तारित करें:
public class MyExecution extends Execution {
public MyExecution() {
super(ExecutionCategory.CLEANING /* श्रेणी */, "My execution" /* नाम */,
"Executes something" /* विवरण, 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;
}
}
runtime पर 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 में ट्री में जोड़ना न भूलें!
कुछ तरकीबें हैं जो JAR फ़ाइलों की सफलतापूर्वक पहचान और डीऑबफस्केशन करने में आपकी सहायता कर सकती हैं। निष्पादन चलाने से पहले, यह पता लगाने के लिए कोड को डीकंपाइल करें कि क्या उपयोग करने की आवश्यकता है। इसके लिए आप कार्यान्वित डीकंपाइलर का उपयोग कर सकते हैं।
डीऑबफस्केशन के लिए सबसे अच्छा क्रम है generic executions > access deobfuscation > string deobfuscation > cleaning executions।
ऑबफस्केटर्स में पैटर्न होते हैं जिनका उपयोग आप ऑबफस्केटर्स की पहचान करने के लिए कर सकते हैं। ऑबफस्केटर की पहचान करने का सबसे आसान तरीका META-INF/MANIFEST.MF फ़ाइल को स्किम करना है।
यह संभव है कि इसमें Obfuscated-By: XXX या Protected-By: XXX एट्रीब्यूट हो।
अत्यधिक (फ्लो-) ऑबफस्केटेड कोड, जो अक्सर स्टैटिक इनिशियलाइज़र में स्विच वाली एक स्ट्रिंग डिक्रिप्शन विधि द्वारा ध्यान देने योग्य होता है, या बहुत लंबे स्विच ब्लॉक (लगभग 250 केस) वाली स्ट्रिंग डिक्रिप्शन विधियाँ।
ZKM Java के सबसे अच्छे (और सबसे पुराने) ऑबफस्केटर्स में से एक है, और बहुत महंगा है। जितना पुराना ऑबफस्केटर है, उतनी ही पुरानी उनकी वेबसाइट।

यदि आपकी JAR फ़ाइल में कुछ विशेष क्लासेस हैं जिनमें विशाल डिक्रिप्शन एल्गोरिदम हैं जो स्ट्रिंग ऑबफस्केशन और एक्सेस ऑबफस्केशन द्वारा उपयोग किए जाते हैं, तो यह संभवतः Stringer है।
सुरक्षा खराब नहीं है और Stringer सबसे महंगे ऑबफस्केटर्स में से एक है। सामान्य ऑबफस्केटर्स के विपरीत यह नाम ऑबफस्केशन के साथ नहीं आता है।
इसका उपयोग "दूसरी परत" के रूप में किया जाता है। संभवतः इस ऑबफस्केटर का उपयोग करने वाले 90% लोग क्रैक का उपयोग कर रहे हैं, क्योंकि इसकी कीमत एक कार से अधिक है।
यदि आपकी फ़ाइल को कई ऑबफस्केटर्स के साथ ऑबफस्केट किया गया है, और उनमें से एक Stringer है, तो आपको अपनी डीऑबफस्केशन Stringer से शुरू करनी चाहिए, क्योंकि Stringer ऑबफस्केशन को ओवरराइट नहीं किया जा सकता है।
(कस्टम JAR हस्ताक्षर और स्ट्रिंग डिक्रिप्शन के दौरान विधि नामों के उपयोग के कारण)

IiIlIlIiIl या aUx, cOn, PrX जैसे क्लास नाम Allatori ऑबफस्केशन का संकेत देते हैं।
Allatori ऑबफस्केटेड JAR फ़ाइलों में बहुत आम है, क्योंकि यह एक निःशुल्क डेमो प्रदान करता है जो कुछ ही क्लिक में उपलब्ध है। ऑबफस्केशन को रिवर्स करना इतना कठिन नहीं है।

Paramorphism Stringer के छोटे भाई जैसा है, क्योंकि यह समान दिखता है, लेकिन उतना अच्छा नहीं है। इसमें कुछ दिलचस्प विशेषताएं भी हैं जो रिवर्स इंजीनियरिंग टूल को क्रैश करने का लक्ष्य रखती हैं, जिन्हें आसानी से हटाया जा सकता है।
ऑबफस्केशन की ताकत Allatori के बराबर है।

अन्य ऑबफस्केटर्स के लिए आप जेनेरिक निष्पादन आज़मा सकते हैं या एक इश्यू खोल सकते हैं, और मैं देखूंगा कि मैं क्या कर सकता हूं।
किसी निष्पादन का चयन करने से पहले, होवर करते समय टूल-टिप टेक्स्ट देखें। उनमें इस बारे में एक छोटा विवरण होता है कि वे क्या करते हैं, लेकिन टैग भी होते हैं जो यह समझने में मदद करते हैं कि आपकी JAR फ़ाइल का व्यवहार कैसे बदलेगा।
Threadtear GNU जनरल पब्लिक लाइसेंस 3.0 के तहत लाइसेंस प्राप्त है
इस टूल पर बहुत काम किया गया है। यदि मैंने आपका समय बचाया है, और आप मुझे एक कॉफ़ी खरीदना चाहते हैं, तो आप यहाँ ऐसा कर सकते हैं: Donate with Bitcoin
Threadtear का उपयोग केवल कानूनी उद्देश्यों के लिए करें। Threadtear का उद्देश्य क्रैकिंग टूल नहीं है, बल्कि मैलवेयर विश्लेषण टूलकिट होना है।
यदि कोई ट्रांसफॉर्मर ठीक से काम नहीं करता है तो कृपया एक इश्यू खोलें या मुझे ईमेल करें और लॉग संलग्न करें।
ध्यान दें कि आउटपुट फ़ाइलें सबसे अधिक संभावना चलाने योग्य नहीं होंगी। यदि आप अभी भी उन्हें चलाने का प्रयास करना चाहते हैं तो JVM तर्क के रूप में -noverify का उपयोग करें!
यह टूल Java 8 के साथ उपयोग करने का इरादा रखता है, लेकिन यह उच्च संस्करणों पर भी चलेगा।