Obfuscator.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002     This file is part of PHP-AST Project by Romain Gaucher (http://rgaucher.info).
00003 
00004     PHP-AST is free software: you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation, either version 3 of the License, or
00007     (at your option) any later version.
00008 
00009     PHP-AST/ORACLE is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with PHP-AST.  If not, see <http://www.gnu.org/licenses/>.
00016 ------------------------------------------------------------------------------*/
00017 
00018 #include "AstNode.h"
00019 #include "tree.h"
00020 #include "AstContainer.h"
00021 #include "Obfuscator.h"
00022 #include "Utils.h"
00023 #include <cstdlib>
00024 #include <string>
00025 #include <map>
00026 #include <iostream>
00027 using namespace std;
00028 
00029 const unsigned length = 16;
00030 
00031 /**
00032     Generate a randome name
00033 */
00034 string generateName() {
00035     static const string ref = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
00036     static const unsigned refL = ref.length();
00037     string ret;
00038 #ifndef srand48
00039     #define srand48 srand
00040     #define lrand48 rand
00041 #endif
00042     srand48(time(NULL) + lrand48() % 65527);
00043     ret += ref[((lrand48() % (refL-36))) + 36];
00044     for (unsigned i=1; i < length; i++) {
00045         ret += ref[((lrand48() % refL))];
00046     }
00047     return ret;
00048 }
00049 
00050 
00051 /**
00052     Apply some modification to the current tree.
00053     This is used to load the external definition and change some names
00054 */
00055 void applyModification(Ast& ast) {
00056     tree<AstNode> *tr = ast.getTreePtr();
00057     map<string, string> randNames;
00058     string randName = "";
00059     string randFunc = "";
00060     for (tree<AstNode>::iterator iter=tr->begin(); iter!=tr->end(); ++iter) {
00061         string valueType = iter->getValue();
00062         if (utils::start_with(valueType,"$rand_name")
00063         ||  utils::start_with(valueType,"rand_func_name")
00064         ||  utils::start_with(valueType,"rand_class_name")) {
00065             string genValue = generateName();
00066             if (valueType[0] == '$')
00067                 genValue = "$" + genValue;
00068             if (randNames.find(valueType) == randNames.end())
00069                 randNames.insert(make_pair(valueType, genValue));
00070             iter->setValue(randNames[valueType]);
00071         }
00072         else if (utils::start_with(valueType,"$param_")) {
00073             string name = valueType;
00074             utils::replace(name, "param_","");
00075             iter->setValue(name);
00076         }
00077     }
00078 }
00079 
00080 /**
00081     Insert all sub-jt into the sub-it
00082 */
00083 void insert_branch(tree<AstNode>::iterator where, tree<AstNode>::iterator from, 
00084                    tree<AstNode>& tr_where, const tree<AstNode>& tr_from)
00085 {
00086     if (tr_from.number_of_children(from) == 0) {
00087         // simply add the node to it
00088         tr_where.append_child(where, *from);
00089     }
00090     else {
00091         where = tr_where.append_child(where, *from);
00092         tree<AstNode>::sibling_iterator cter;
00093         for (cter = tr_from.begin(from); cter != tr_from.end(from); ++cter) 
00094         {
00095             insert_branch(where, cter, tr_where, tr_from);
00096         }
00097     }
00098 }
00099 
00100 /**
00101     Copy for duplicating a branch
00102 */
00103 void copy_branch(tree<AstNode>::iterator where, tree<AstNode>::iterator from,  tree<AstNode>& tr_where)
00104 {
00105     if (tr_where.number_of_children(from) == 0) {
00106         // simply add the node to it
00107         tr_where.append_child(where, *from);
00108     }
00109     else {
00110         where = tr_where.append_child(where, *from);
00111         tree<AstNode>::sibling_iterator cter;
00112         for (cter = tr_where.begin(from); cter != tr_where.end(from); ++cter)
00113         {
00114             copy_branch(where, cter, tr_where);
00115         }
00116     }
00117 }
00118 
00119 /**
00120     Move all the branches from 'from' to 'where' on the tree 'tr_where'
00121 */
00122 void move_branch(const tree<AstNode>::iterator& where, const tree<AstNode>::iterator& from, tree<AstNode>& tr_where)
00123 {
00124     copy_branch(where, from, tr_where);
00125     tr_where.erase(from);
00126 }
00127 
00128 /**
00129     Rewind in a tree until the value
00130 */
00131 tree<AstNode>::iterator rewind(const tree<AstNode>::iterator& from, const string& untilStr, const tree<AstNode>& tr) {
00132     tree<AstNode>::iterator ret = from;
00133     while(ret->getType() != untilStr) { 
00134         ret = tr.parent(ret);
00135     }
00136     return ret;
00137 }
00138 
00139 /**
00140     Forward in a tree until the value
00141 */
00142 tree<AstNode>::iterator forward(const tree<AstNode>::iterator& from, const string& untilStr, const tree<AstNode>& tr) {
00143     tree<AstNode>::iterator ret = from;
00144     while(ret->getType() != untilStr) { 
00145         ret = tr.child(ret, 0);
00146     }
00147     return ret;
00148 }
00149 
00150 
00151 /**
00152     Clean the possible patterns annotations:
00153         $enter_new_statement ...
00154 */
00155 void clean_pattern(tree<AstNode>& tr)
00156 {
00157     for (tree<AstNode>::iterator iter=tr.begin(); iter!=tr.end(); ++iter) {
00158         if (iter->getType() == "text" && iter->getValue() == "$enter_the_new_statement") {
00159             iter = rewind(iter, "statement", tr);
00160             tr.erase(iter);
00161             break;
00162         }
00163     }
00164 }
00165 
00166 
00167 /**
00168     Insert a new statement.
00169     - Create a new inner_statement_list
00170     - Add the statement under it
00171 */
00172 bool insert_statement(const tree<AstNode>::iterator& where, const tree<AstNode>::iterator& what, tree<AstNode>& tr)
00173 {
00174     if (where->getType() == "text" && where->getValue() == "$enter_the_new_statement") {
00175         // rewind to the inner_statement_list
00176         tree<AstNode>::iterator top = where;
00177         do {
00178             top = tr.parent(top);
00179         } while (top->getType() != "inner_statement" && tr.child(top,0)->getType() != "statement");
00180         top = tr.parent(top);
00181         if (top->getType() != "inner_statement_list")
00182             return false;
00183         else {
00184             top = tr.append_child(top, AstNode("inner_statement_list"));
00185             top = tr.append_child(top, AstNode("inner_statement"));
00186             if (what->getType() == "statement") {
00187                 top = tr.append_child(top, AstNode("statement"));
00188                 //cout << "Seems to be okay..." << endl;
00189                 move_branch(top, what, tr);
00190             }
00191         }
00192         return true;
00193     }
00194     return false;
00195 }
00196 
00197 
00198 void RenameClass::operator()(tree<AstNode>& tr, MapClasses* classes, MapVariables* vars, MapFunctions *func) {
00199     // for every names in the class, generate a new *unique* name
00200     map<string, string> classNames;
00201     for (MapClasses::iterator iter = classes->begin(); iter != classes->end(); ++iter)
00202     {
00203         string newName = generateName();
00204         classNames.insert(make_pair(iter->first, newName));     
00205     }
00206     map<string, string>::iterator cter;
00207     tree<AstNode>::iterator parent;
00208     for (tree<AstNode>::iterator iter=tr.begin(); iter!=tr.end(); ++iter)
00209     {
00210         parent = tr.parent(iter);
00211         if (iter->getType() == "text" 
00212             && parent->getType() == "T_STRING"
00213             && (tr.parent(parent)->getType() == "unticked_class_declaration_statement"
00214                || tr.parent(parent)->getType() == "function_call" // constructor
00215                || tr.parent(parent)->getType() == "class_name_reference"
00216                || tr.parent(parent)->getType() == "fully_qualified_class_name"
00217                )
00218             && ((cter=classNames.find(iter->getValue())) != classNames.end())) {
00219             // rename the currenet node
00220             iter->setValue(cter->second);
00221         }           
00222     }       
00223 }
00224 
00225 
00226 void RenameFunction::operator()(tree<AstNode>& tr, MapClasses* classes, MapVariables* vars, MapFunctions *func) {
00227     // for every names in the class, generate a new *unique* name
00228     map<string, string> funcNames;
00229     for (MapFunctions::iterator iter = func->begin(); iter != func->end(); ++iter)
00230     {
00231         string newName = generateName();
00232         funcNames.insert(make_pair(iter->first, newName));      
00233     }
00234     map<string, string>::iterator cter;
00235     tree<AstNode>::iterator parent;
00236     for (tree<AstNode>::iterator iter=tr.begin(); iter!=tr.end(); ++iter)
00237     {
00238         parent = tr.parent(iter);
00239         if (iter->getType() == "text" 
00240             && parent->getType() == "T_STRING" 
00241             && (tr.parent(parent)->getType() == "unticked_function_declaration_statement" 
00242                 || tr.parent(parent)->getType() == "function_call")
00243             && ((cter=funcNames.find(iter->getValue())) != funcNames.end())) {
00244             // rename the currenet node
00245             iter->setValue(cter->second);
00246         }           
00247     }       
00248 }
00249 
00250 
00251 void RenameVariable::operator()(tree<AstNode>& tr, MapClasses* classes, MapVariables* vars, MapFunctions *func) {
00252 
00253     // for every names in the class, generate a new *unique* name
00254     map<string, string> varNames;
00255     for (MapVariables::iterator iter = vars->begin(); iter != vars->end(); ++iter)
00256     {
00257         string newName = "$" + generateName();
00258         varNames.insert(make_pair(iter->first, newName));       
00259     }
00260     map<string, string>::iterator cter;
00261     for (tree<AstNode>::iterator iter=tr.begin(); iter!=tr.end(); ++iter)
00262     {
00263         if (iter->getType() == "text" && ((cter=varNames.find(iter->getValue())) != varNames.end())) {
00264             // rename the currenet node
00265             iter->setValue(cter->second);
00266         }           
00267     }       
00268 }
00269 
00270 
00271 /**
00272     Generic control flow modification
00273 */
00274 void ControlFlow::operator()(tree<AstNode>& tr, MapClasses* classes, MapVariables* vars, MapFunctions *func) {
00275 
00276     // 1 - Detect which if modifiying (select all the unticked_statement grand children of top_statement)
00277     AstNodeIteratorList affectedNode;
00278     tree<AstNode>::iterator iter, parent, grandparent;
00279     for (iter=tr.begin(); iter!=tr.end();++iter)
00280     {
00281         if (iter->getType() == "statement"
00282         && tr.parent(iter)->getType() == "top_statement")
00283         {
00284             // We put the parent =? 'statement' in the list
00285             affectedNode.push_back(iter);
00286         }
00287     }
00288 
00289     // 2 - Let's study a little out resource...
00290     tree<AstNode>::iterator endStatement;
00291     AstNodeIteratorList branchs;
00292     AstNodeIteratorList br_func;
00293     AstNodeIteratorList br_classe;
00294 
00295     // 2+1/2 - Look for renaming? ($rand_name will be a generateName())
00296     applyModification(flowAST);
00297     tree<AstNode> def = *(flowAST.getTreeConstPtr());
00298 
00299     // 2+3/4 - Cut the external resource to implant it into the tree (get the nodes into the flowAST)
00300     for (tree<AstNode>::iterator iter=def.begin(); iter!=def.end(); ++iter)
00301     {
00302         if (iter->getValue() == "$enter_the_new_statement") {
00303             endStatement = iter;
00304             // rewind to the statement, not interesting by everything after this statement
00305             do { 
00306                 endStatement = def.parent(endStatement);
00307             } while (endStatement->getType() != "statement" && def.parent(endStatement)->getType() != "inner_statement");
00308             //endStatement = def.child(endStatement, 0);
00309         }
00310         else if (iter->getType() == "top_statement") {
00311             if (tr.child(iter,0)->getType() == "function_declaration_statement")
00312                 br_func.push_back(iter);
00313             else if (tr.child(iter,0)->getType() == "class_declaration_statement")
00314                 br_classe.push_back(iter);
00315             else
00316                 branchs.push_back(iter);
00317         }
00318     }
00319     //
00320     // 3 - Adding the nodes: merging the two trees
00321     tree<AstNode>::iterator topDeclarations = tr.begin();
00322     for (;topDeclarations!= tr.end(); ++topDeclarations) {
00323         if (topDeclarations->getType() == "top_statement_list")
00324         {
00325             for (tree<AstNode>::iterator tmp=topDeclarations;tmp->getType()=="top_statement_list";++tmp)
00326                 topDeclarations = tmp;
00327             break;
00328         }
00329     }
00330     // Insert the classes
00331     for (AstNodeIteratorList::iterator bter=br_classe.begin();bter!=br_classe.end();++bter)
00332         insert_branch(topDeclarations, *bter, tr, *(flowAST.getTreeConstPtr()));
00333 
00334     // Insert the functions
00335     for (AstNodeIteratorList::iterator bter=br_func.begin();bter!=br_func.end();++bter)
00336         insert_branch(topDeclarations, *bter, tr, *(flowAST.getTreeConstPtr()));
00337 
00338     // Insert the obfuscation template (empty)
00339     for (AstNodeIteratorList::iterator bter=branchs.begin();bter!=branchs.end();++bter)
00340         insert_branch(topDeclarations, *bter, tr, *(flowAST.getTreeConstPtr()));
00341 
00342     //Select the place to insert
00343     for (tree<AstNode>::iterator iter=tr.begin();iter!=tr.end();++iter)
00344     {
00345         if (iter->getType() == "text" && iter->getValue() == "$enter_the_new_statement") {
00346             // Let's Insert Here!!
00347             for (AstNodeIteratorList::iterator jter=affectedNode.begin(); jter!=affectedNode.end();++jter) {
00348                 insert_statement(iter, *jter ,tr);
00349             }
00350         }
00351     }
00352     clean_pattern(tr);
00353 }

Generated on Wed Feb 27 20:31:06 2008 for php.ast.svn.src. by  doxygen 1.5.3