package net.sourceforge.phpeclipse.mover.obfuscator; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; //import java.security.MessageDigest; //import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; import net.sourceforge.phpdt.core.compiler.InvalidInputException; import net.sourceforge.phpdt.internal.compiler.parser.Scanner; import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpeclipse.mover.DefaultMover; import net.sourceforge.phpeclipse.views.PHPConsole; import org.eclipse.jface.preference.IPreferenceStore; /** * Obfuscate the file with the PHP Scanner */ public class PHPObfuscatorMover extends DefaultMover implements ITerminalSymbols { private Scanner fScanner; private int fToken; // private MessageDigest fAlgorithm; private int fCounter; protected HashMap fIdentifierMap; /** * buffer, for obvious reasons access to this buffer must * be synchronized */ protected byte[] bytes = new byte[1024]; /** * Creates a PHPAnalyzer * @param console reports error to the PHPConsole */ public PHPObfuscatorMover(PHPConsole console, Scanner scanner, HashMap identifierMap) { super(console); this.fScanner = scanner; this.fIdentifierMap = identifierMap; this.fCounter = 0; // try { // this.fAlgorithm = MessageDigest.getInstance("MD5"); // } catch (NoSuchAlgorithmException e) { // System.out.println(e.toString()); // } } /** * Return the name the file would have after moving. In this case, * it's left unchanged. * @param file file the mover would have to move * @return the extension it would give the file in the target directory */ public String getTargetName(File file) { return file.getName(); } /** * gets the next token from input */ private void getNextToken() { try { fToken = fScanner.getNextToken(); if (Scanner.DEBUG) { int currentEndPosition = fScanner.getCurrentTokenEndPosition(); int currentStartPosition = fScanner.getCurrentTokenStartPosition(); System.out.print(currentStartPosition + "," + currentEndPosition + ": "); System.out.println(fScanner.toStringAction(fToken)); } return; } catch (InvalidInputException e) { } fToken = TokenNameERROR; } private boolean obfuscate(StringBuffer buf) { char[] ident; String identifier; PHPIdentifier value; int startPosition = 0; int lastPosition = 0; IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore(); try { while (fToken != TokenNameEOF && fToken != TokenNameERROR) { if (fToken == TokenNameVariable) { identifier = new String(fScanner.getCurrentIdentifierSource()); lastPosition = fScanner.startPosition; int len = lastPosition - startPosition; buf.append(fScanner.source, startPosition, len); value = (PHPIdentifier) fIdentifierMap.get(identifier); if (value != null) { String obfuscatedIdentifier = value.getIdentifier(); if (obfuscatedIdentifier == null) { buf.append("$v" + Integer.toString(fCounter)); value.setIdentifier("$v" + Integer.toString(fCounter++)); } else { buf.append(obfuscatedIdentifier); } // System.out.println(hexString.toString()); } else { buf.append(identifier); } startPosition = fScanner.currentPosition; getNextToken(); } else if (fToken == TokenNameIdentifier) { identifier = new String(fScanner.getCurrentIdentifierSource()); lastPosition = fScanner.startPosition; int len = lastPosition - startPosition; buf.append(fScanner.source, startPosition, len); value = (PHPIdentifier) fIdentifierMap.get(identifier); if (value != null) { String obfuscatedIdentifier = value.getIdentifier(); if (obfuscatedIdentifier == null) { buf.append("_" + Integer.toString(fCounter)); value.setIdentifier("_" + Integer.toString(fCounter++)); } else { buf.append(obfuscatedIdentifier); } // System.out.println(hexString.toString()); } else { buf.append(identifier); } startPosition = fScanner.currentPosition; getNextToken(); } else if (fToken == TokenNameCOMMENT_LINE || fToken == TokenNameCOMMENT_BLOCK || fToken == TokenNameCOMMENT_PHPDOC) { lastPosition = fScanner.startPosition; buf.append(fScanner.source, startPosition, lastPosition - startPosition); startPosition = fScanner.currentPosition; getNextToken(); } else if (fToken == TokenNameStringLiteral) { char currentCharacter; int i = fScanner.startPosition; ArrayList varList = new ArrayList(); lastPosition = fScanner.startPosition; int len = lastPosition - startPosition; buf.append(fScanner.source, startPosition, len); while (i < fScanner.currentPosition) { currentCharacter = fScanner.source[i++]; if (currentCharacter == '$' && fScanner.source[i-2]!='\\') { StringBuffer varName = new StringBuffer(); varName.append("$"); while (i < fScanner.currentPosition) { currentCharacter = fScanner.source[i++]; if (!Scanner.isPHPIdentifierPart(currentCharacter)) { break; // while loop } varName.append(currentCharacter); } varList.add(varName.toString()); } } StringBuffer stringLiteral = new StringBuffer(); stringLiteral.append(fScanner.source, fScanner.startPosition, fScanner.currentPosition - fScanner.startPosition); String stringIdent; String replacement; int index; for (int j = 0; j < varList.size(); j++) { stringIdent = (String) varList.get(j); len = stringIdent.length(); value = (PHPIdentifier) fIdentifierMap.get(stringIdent); if (value != null) { String obfuscatedIdentifier = value.getIdentifier(); if (obfuscatedIdentifier == null) { replacement = "$v" + Integer.toString(fCounter); value.setIdentifier("$v" + Integer.toString(fCounter++)); } else { replacement = obfuscatedIdentifier; } // System.out.println(hexString.toString()); } else { replacement = stringIdent; } index = stringLiteral.indexOf(stringIdent); if (index >= 0) { if (index > 0 && stringLiteral.charAt(index-1)!='\\') { stringLiteral.replace(index, index + stringIdent.length(), replacement); } else if (index==0) { stringLiteral.replace(index, index + stringIdent.length(), replacement); } } } buf.append(stringLiteral); startPosition = fScanner.currentPosition; getNextToken(); } if (fToken == TokenNameMINUS_GREATER) { // i.e. $this->var_name getNextToken(); if (fToken == TokenNameIdentifier) { // assuming this is a dereferenced variable identifier = new String(fScanner.getCurrentIdentifierSource()); lastPosition = fScanner.startPosition; int len = lastPosition - startPosition; buf.append(fScanner.source, startPosition, len); value = (PHPIdentifier) fIdentifierMap.get("$" + identifier); if (value != null && value.isVariable()) { String obfuscatedIdentifier = value.getIdentifier(); if (obfuscatedIdentifier == null) { // note: don't place a $ before the identifier buf.append("v" + Integer.toString(fCounter)); value.setIdentifier("$v" + Integer.toString(fCounter++)); } else { if (obfuscatedIdentifier.charAt(0) == '$') { buf.append(obfuscatedIdentifier.substring(1)); } else { buf.append(obfuscatedIdentifier); } } } else { buf.append(identifier); } startPosition = fScanner.currentPosition; getNextToken(); } } else { getNextToken(); } } if (startPosition < fScanner.source.length) { buf.append(fScanner.source, startPosition, fScanner.source.length - startPosition); } return true; } catch (SyntaxError sytaxErr) { // do nothing } return false; } public File copy(File sourceFile, File targetDir) { try { File targetFile = new File(targetDir, getTargetName(sourceFile)); // if (targetFile.exists()) // if (targetFile.lastModified() >= sourceFile.lastModified()) // return null; synchronized (bytes) { FileInputStream in = new FileInputStream(sourceFile); FileOutputStream out = new FileOutputStream(targetFile); for (int len = in.read(bytes); len != -1; len = in.read(bytes)) { out.write(bytes, 0, len); } in.close(); out.close(); } return targetFile; } catch (IOException e) { fConsole.write(e.toString()); } return null; } /** * Move one file. * @param sourceFile the file to move * @param targetDir the directory to copy the result to * @return file or null if the file was ignored */ public File move(File sourceFile, File targetDir) { try { String fileName = sourceFile.getAbsolutePath().toLowerCase(); if (fileName.endsWith(".php") || fileName.endsWith(".php3") || fileName.endsWith(".php4") || fileName.endsWith(".phtml") || fileName.endsWith(".inc")) { StringBuffer buf = new StringBuffer(); long filelen = sourceFile.length(); char[] charArray = new char[(int) filelen]; BufferedReader br = new BufferedReader(new FileReader(sourceFile.getAbsolutePath())); br.read(charArray, 0, (int) filelen); // int offset = 0; // String line; // while ((line = br.readLine()) != null) { // System.arraycopy(line.toCharArray(), 0, charArray, offset, line.length()); // offset += line.length(); // } br.close(); fScanner.setSource(charArray); fScanner.setPHPMode(false); fToken = TokenNameEOF; getNextToken(); buf = new StringBuffer(); if (!obfuscate(buf)) { return copy(sourceFile, targetDir); } else { File targetFile = new File(targetDir, getTargetName(sourceFile)); BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile)); bw.write(buf.toString()); bw.close(); return targetFile; } } else { return copy(sourceFile, targetDir); } } catch (IOException e) { fConsole.write(e.toString()); } return null; } }