1 26 package net.sf.javaguard; 27 28 29 import java.io.*; 30 import java.util.*; 31 import java.util.jar.*; 32 import java.security.DigestOutputStream ; 33 import java.security.MessageDigest ; 34 import java.security.NoSuchAlgorithmException ; 35 import net.sf.javaguard.classfile.*; 36 import net.sf.javaguard.log.*; 37 38 import org.apache.oro.text.MalformedCachePatternException; 39 import org.apache.oro.text.regex.MalformedPatternException; 40 41 42 47 public class GuardDB implements ClassConstants { 48 49 private static final String STREAM_NAME_MANIFEST = "META-INF/MANIFEST.MF"; 50 51 private static final String SIGNATURE_PREFIX = "META-INF/"; 52 53 private static final String SIGNATURE_EXT = ".SF"; 54 55 56 57 private Vector inputJars = null; 58 62 private Vector inputDirs = null; 63 67 private Vector inputFileFilters = null; 68 72 private Vector outputContainers = null; 73 74 private File outputFile; 75 76 private ClassTree classTree = null; 77 78 private ScriptFile scriptFile; 79 81 private Vector mappings = null; 82 83 84 private FileLogger logfile; 85 86 private ScreenLogger logger; 87 88 89 90 91 93 public GuardDB() { 94 logfile = FileLogger.getInstance(); 95 logger = ScreenLogger.getInstance(); 96 setScriptFile(null); 97 } 98 99 100 101 102 105 public void setScriptFile(ScriptFile scriptFile) { 106 this.scriptFile = scriptFile; 107 } 108 109 110 114 private ScriptFile getScriptFile() { 115 return scriptFile; 116 } 117 118 119 120 121 130 public void setInput(Vector jars, Vector dirs, Vector filters) 131 throws IllegalArgumentException { 132 inputJars = jars; 133 if ( (null==dirs && null!=filters) || (null!=dirs && null==filters) 134 || (null!=dirs && null!=filters && dirs.size()!=filters.size())) { 135 throw new IllegalArgumentException ("Directory and file filter vectors must have the same size"); 136 } 137 inputDirs = dirs; 138 inputFileFilters = filters; 139 } 140 141 142 143 144 148 private Vector getInputJars() { 149 if (null == inputJars) { 150 inputJars = new Vector(); 151 } 152 return inputJars; 153 } 154 155 156 160 private Vector getInputDirs() { 161 if (null == inputDirs) { 162 inputDirs = new Vector(); 163 } 164 return inputDirs; 165 } 166 167 168 173 private Vector getInputFileFilters() { 174 if (null == inputFileFilters) { 175 inputFileFilters = new Vector(); 176 } 177 return inputFileFilters; 178 } 179 180 181 182 183 186 public void setOutputFile(File file) { 187 outputFile = file; 188 } 189 190 191 195 private File getOutputFile() { 196 return outputFile; 197 } 198 199 200 201 202 210 public void obfuscate(boolean dump) 211 throws IOException, MalformedPatternException { 212 logger.log("Building the file containers..."); 213 214 OutputContainer oc = new OutputContainer(getOutputFile()); 216 217 Vector jars = getInputJars(); 219 for (int i=0; i<jars.size(); i++) { 220 FileContainer fc = new JarFileContainer( new JarFile( (File) jars.elementAt(i)) ); 221 oc.addFileContainer(fc); 222 } 223 224 Vector dirs = getInputDirs(); 226 Vector fileFilters = getInputFileFilters(); 227 for (int i=0; i<dirs.size(); i++) { 228 FileContainer fc = new LocalDirectoryFileContainer((File) dirs.elementAt(i), (String ) fileFilters.elementAt(i)); 229 oc.addFileContainer(fc); 230 } 231 232 Vector vec = oc.getFileContainers(); 234 for (int i=0; i<vec.size(); i++) { 235 FileContainer fc = (FileContainer) vec.elementAt(i); 236 for (int j=i+1; j<vec.size(); j++) { 237 FileContainer other = (FileContainer) vec.elementAt(j); 238 other.removeDuplicates(fc); 239 } 240 } 241 242 addOutputContainer(oc); 243 startObfuscate(getOutputContainers(), dump); 244 } 245 246 247 248 249 257 private void startObfuscate(Vector vec, boolean dump) 258 throws IOException, MalformedPatternException { 259 Iterator iter = vec.iterator(); 261 while (iter.hasNext()) { 262 ClassTree classTree = new ClassTree(); 264 ClassFile.resetDangerHeader(); 265 parseScriptFile(classTree); 266 267 OutputContainer oc = (OutputContainer) iter.next(); 268 Vector fileContainers = oc.getFileContainers(); 270 logger.log("Building the class tree..."); 271 for (int j=0; j<fileContainers.size(); j++) { 272 FileContainer fc = (FileContainer) fileContainers.elementAt(j); 273 logger.log(Log.INFO, "Reading the contents from '" + fc.getName() + "'"); 274 addClasses(classTree, fc, dump); 275 } 276 277 writeLogHeader(getOutputFile().getName(), fileContainers); 279 generateMappingTable(classTree); 281 writeMappingTable(classTree); 283 284 JarOutputStream jos = new JarOutputStream(new BufferedOutputStream( 286 new FileOutputStream(oc.getOutputFile()))); 287 jos.setComment(Version.getJarComment()); 288 289 for (int j=0; j<fileContainers.size(); j++) { 291 FileContainer fc = (FileContainer) fileContainers.elementAt(j); 292 obfuscateFiles(jos, classTree, fc, oc.getManifestContainer()); 293 } 294 295 JarEntry outEntry = new JarEntry(STREAM_NAME_MANIFEST); 297 jos.putNextEntry(outEntry); 298 DataOutputStream manifest = new DataOutputStream(new BufferedOutputStream(jos)); 299 oc.getManifestContainer().write(manifest); 300 jos.closeEntry(); 301 302 jos.close(); 304 305 logfile.printMethodWarnings(); 307 logfile.printWarnings(); 308 } 309 } 310 311 312 313 314 322 public void parseScriptFile(ClassTree classTree) 323 throws MalformedPatternException, IllegalArgumentException { 324 if (null != getScriptFile()) { 325 Iterator iterator = getScriptFile().iterator(); 326 while (iterator.hasNext()) { 328 ScriptEntry entry = (ScriptEntry) iterator.next(); 329 330 switch (entry.getType()) { 331 case ScriptConstants.TYPE_ATTRIBUTE: 332 case ScriptConstants.TYPE_RENAME: 333 case ScriptConstants.TYPE_PRESERVE: 334 classTree.retainAttribute(entry); 335 break; 336 337 case ScriptConstants.TYPE_PACKAGE: 338 case ScriptConstants.TYPE_PACKAGE_MAP: 339 case ScriptConstants.TYPE_CLASS: 340 case ScriptConstants.TYPE_CLASS_MAP: 341 case ScriptConstants.TYPE_METHOD: 342 case ScriptConstants.TYPE_METHOD_MAP: 343 case ScriptConstants.TYPE_FIELD: 344 case ScriptConstants.TYPE_FIELD_MAP: 345 addMapping(entry); 346 break; 347 348 case ScriptConstants.TYPE_IGNORE: 349 classTree.addIgnoreDefaultRegex(entry.getName()); 350 break; 351 352 case ScriptConstants.TYPE_IGNORE_PACKAGE: 353 classTree.addIgnorePackageRegex(entry.getName()); 354 break; 355 356 case ScriptConstants.TYPE_IGNORE_CLASS: 357 classTree.addIgnoreClassRegex(entry.getName()); 358 break; 359 360 case ScriptConstants.TYPE_IGNORE_METHOD: 361 classTree.addIgnoreMethodRegex(entry); 362 break; 363 364 case ScriptConstants.TYPE_IGNORE_FIELD: 365 classTree.addIgnoreFieldRegex(entry); 366 break; 367 368 case ScriptConstants.TYPE_OBFUSCATE: 369 classTree.addObfuscateDefaultRegex(entry.getName()); 370 break; 371 372 case ScriptConstants.TYPE_OBFUSCATE_PACKAGE: 373 classTree.addObfuscatePackageRegex(entry.getName()); 374 break; 375 376 case ScriptConstants.TYPE_OBFUSCATE_CLASS: 377 classTree.addObfuscateClassRegex(entry.getName()); 378 break; 379 380 case ScriptConstants.TYPE_OBFUSCATE_METHOD: 381 classTree.addObfuscateMethodRegex(entry); 382 break; 383 384 case ScriptConstants.TYPE_OBFUSCATE_FIELD: 385 classTree.addObfuscateFieldRegex(entry); 386 break; 387 388 default: 389 throw new IllegalArgumentException ("Illegal type in script file"); 391 } 392 } 393 } 394 } 395 396 397 398 399 406 private void addClasses(ClassTree classTree, FileContainer fc, boolean dump) { 407 Enumeration enumeration = fc.enumeration(); 408 while (enumeration.hasMoreElements()) { 409 FileEntry entry = (FileEntry) enumeration.nextElement(); 410 if (entry.isClassFile()) { 412 DataInputStream dis = entry.getInputStream(); 413 ClassFile cf = null; 414 try { 415 cf = ClassFile.create(classTree, dis); 416 } catch (IOException ioex) { 417 logger.println("Error: " + ioex.getMessage()); 418 logger.printStackTrace(ioex); 419 logfile.println("# ERROR - corrupt class file: " + entry.getName()); 420 logfile.printStackTrace(ioex); 421 } finally { 422 try { 423 dis.close(); 424 } catch (IOException ioex) { 425 } 427 } 428 429 cf.logDangerousMethods(); 431 classTree.addClassFile(cf); 432 if (dump) { 433 PrintWriter pw = new PrintWriter(System.out); 434 cf.dump(pw); 435 } 437 } 438 } 439 } 440 441 442 443 444 451 private void generateMappingTable(ClassTree classTree) 452 throws MalformedPatternException { 453 logger.log("Generating the mapping table for the whole class tree..."); 454 455 classTree.parseObfuscateAndIgnoreList(); 458 459 classTree.markRemoteClasses(); 461 462 classTree.retainMappings(getMappings()); 464 465 classTree.retainHardcodedReferences(); 467 classTree.retainSerializableElements(); 468 469 classTree.generateNames(); 472 473 classTree.retainRemoteClasses(); 475 476 classTree.resolveClasses(); 479 } 480 481 482 483 484 492 private void obfuscateFiles(JarOutputStream jos, ClassTree classTree, 493 FileContainer fileContainer, ManifestContainer manifestContainer) 494 throws IOException { 495 logger.log(Log.INFO, "Obfuscating the entries in the file container: " + fileContainer.getName()); 496 497 Enumeration enumeration = fileContainer.enumeration(); 503 while (enumeration.hasMoreElements()) { 504 FileEntry entry = (FileEntry) enumeration.nextElement(); 505 DataInputStream inStream = entry.getInputStream(); 507 try { 508 if (entry.isClassFile()) { 509 ClassFile cf = ClassFile.create(classTree, inStream); 511 cf.remap(classTree); 512 logger.log(Log.DEBUG, "Reading: " + entry.getName()); 513 logger.log(Log.DEBUG, " -> writing " + cf.getName() + CLASS_EXT); 514 JarEntry outEntry = new JarEntry(cf.getName() + CLASS_EXT); 515 jos.putNextEntry(outEntry); 516 517 MessageDigest shaDigest = MessageDigest.getInstance("SHA-1"); 519 MessageDigest md5Digest = MessageDigest.getInstance("MD5"); 520 DataOutputStream classOutputStream = new DataOutputStream( 521 new DigestOutputStream ( 522 new BufferedOutputStream( 523 new DigestOutputStream (jos, shaDigest)), 524 md5Digest)); 525 526 cf.write(classOutputStream); 528 classOutputStream.flush(); 529 jos.closeEntry(); 530 531 MessageDigest [] digests = {shaDigest, md5Digest}; 533 manifestContainer.updateManifest(entry.getName(), cf.getName() + CLASS_EXT, digests); 534 } else { 535 long size = entry.getSize(); 537 if (size != -1) { 538 byte[] bytes = new byte[(int)size]; 539 inStream.readFully(bytes); 540 String outName = classTree.getOutputFileName(entry.getName()); 541 if (!entry.getName().equals(outName)) { 542 logfile.log(Log.VERBOSE, "# renaming resource: " + entry.getName() + " -> " + outName); 543 } 544 logger.log(Log.DEBUG, "Reading: " + entry.getName()); 545 logger.log(Log.DEBUG, " -> writing " + outName); 546 JarEntry outEntry = new JarEntry(outName); 547 jos.putNextEntry(outEntry); 548 549 MessageDigest shaDigest = MessageDigest.getInstance("SHA"); 551 MessageDigest md5Digest = MessageDigest.getInstance("MD5"); 552 DataOutputStream dataOutputStream = new DataOutputStream( 553 new DigestOutputStream ( 554 new BufferedOutputStream( 555 new DigestOutputStream (jos, shaDigest)), 556 md5Digest)); 557 558 dataOutputStream.write(bytes, 0, bytes.length); 560 dataOutputStream.flush(); 561 jos.closeEntry(); 562 563 MessageDigest [] digests = {shaDigest, md5Digest}; 565 manifestContainer.updateManifest(entry.getName(), outName, digests); 566 } 567 } 568 } catch (NoSuchAlgorithmException nae) { 569 logger.println("Cannot find message digest algorithm:"); 570 logger.println(nae.getMessage()); 571 logger.printStackTrace(nae); 572 } finally { 574 if (inStream != null) { 575 inStream.close(); 576 } 577 } 578 } 579 } 580 581 582 583 584 588 private void writeLogHeader(String outName, Vector vec) { 589 logger.log(Log.INFO, "Writing log header..."); 590 logfile.println("# If this log is to be used for incremental obfuscation / patch generation, "); 591 logfile.println("# add any '.class', '.method', '.field' and '.attribute' restrictions here:"); 592 logfile.println(); 593 logfile.println(); 594 logfile.println("#-DO-NOT-EDIT-BELOW-THIS-LINE------------------DO-NOT-EDIT-BELOW-THIS-LINE--"); 595 logfile.println("#"); 596 logfile.println("# JavaGuard Bytecode Obfuscator, version " + Version.getVersion()); 597 logfile.println("#"); 598 logfile.println("# Logfile created on " + new Date().toString()); 599 logfile.println("#"); 600 if (null != vec) { 601 for (int i=0; i<vec.size(); i++) { 602 FileContainer fc = (FileContainer) vec.elementAt(i); 603 logfile.println("# Input taken for obfuscation: " + fc.getName()); 604 } 605 } 606 logfile.println("# Output Jar file: " + outName); 607 logfile.println("# JavaGuard script file used: " 608 + (null!=getScriptFile() ? getScriptFile().getName() : "(none, defaults used)")); 609 logfile.println("#"); 610 logfile.println(); 611 } 612 613 614 615 616 620 private void writeMappingTable(ClassTree classTree) { 621 Runtime rt = Runtime.getRuntime(); 623 rt.gc(); 624 logfile.println(); 625 logfile.println("#"); 626 logfile.println("# Memory in use after class data structure built: " + Long.toString(rt.totalMemory() - rt.freeMemory()) + " bytes"); 627 logfile.println("# Total memory available : " + Long.toString(rt.totalMemory()) + " bytes"); 628 logfile.println("#"); 629 630 logfile.println(); 632 classTree.dump(); 633 } 634 635 636 637 638 642 private Vector getMappings() { 643 if (null == mappings) { 644 mappings = new Vector(); 645 } 646 return mappings; 647 } 648 649 650 654 private void addMapping(ScriptEntry entry) { 655 getMappings().addElement(entry); 656 } 657 658 659 660 661 665 private Vector getOutputContainers() { 666 if (null == outputContainers) { 667 outputContainers = new Vector(); 668 } 669 return outputContainers; 670 } 671 672 673 678 private void addOutputContainer(OutputContainer oc) { 679 getOutputContainers().addElement(oc); 680 } 681 682 683 684 685 690 private static class OutputContainer { 691 692 private Vector fileContainers = new Vector(); 693 694 private ManifestContainer manifestContainer = new ManifestContainer(); 695 696 private File outputFile; 697 698 699 703 OutputContainer(File file) { 704 this.outputFile = file; 705 } 706 707 708 713 void addFileContainer(FileContainer fc) 714 throws IOException { 715 getFileContainers().addElement(fc); 716 getManifestContainer().addManifest(fc.getManifest()); 717 } 718 719 720 724 Vector getFileContainers() { 725 return fileContainers; 726 } 727 728 729 732 ManifestContainer getManifestContainer() { 733 return manifestContainer; 734 } 735 736 737 740 File getOutputFile() { 741 return outputFile; 742 } 743 } 744 } 745 | Popular Tags |