Make your own free website on Tripod.com
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

code.cpp

Go to the documentation of this file.
00001 /*
00002 PeRdr - PE file disassembler
00003 Copyright (C) 1999-2003 Frediano Ziglio
00004 -----
00005 
00006 This program is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 -----
00020 
00021 INFORMATION
00022   www: http://freddy77.tripod.com/perdr/
00023   e-mail: freddy77@angelfire.com
00024 */
00025 #include "global.h"
00026 #ifdef HAVE_HDRSTOP
00027 #pragma hdrstop
00028 #endif
00029 
00030 #include "signfile.hpp"
00031 #include "module.h"
00032 #include "code.h"
00033 #include "codeglob.h"
00034 #include "x86istr.h"
00035 #include "heuristic.h"
00036 #include "codescan.h"
00037 #ifdef DEBUG
00038 #include <cctype>
00039 #endif
00040 #include "utils/f77auto_ptr"
00041 
00042 using namespace std;
00043 
00044 #ifdef DEBUG
00045 static unsigned long int bytes;           // bytes processati
00046 static unsigned long int jumps;           // salti ancora da processare
00047 static unsigned long int calls;           // chiamate da processare
00048 static unsigned long int loopCount;       // contatore ciclo per non visualizzare
00049                               // continuamente valori
00050 #endif
00051 
00052 void WriteInstruction(const Instruction& instruction,FILE* file)
00053 {
00054   char buffer[80];
00055   instruction.Write(buffer);
00056   fprintf(file,"%s\n",buffer);
00057 }
00058 
00059 // verifica se esiste un riferimento a dati o codice
00060 void CodeParser::CheckForAddress(vma_t instAddress,const Instruction& instruction,enum ByteInfo::TPriority priority)
00061 {
00062   for (int n=0; n < instruction.numArg; ++n)
00063   {
00064     const Param *param = &instruction.Args[n];
00065     switch (param->type)
00066     {
00067     case Param::t_literal:
00068           if (param->GetLiteralSize() != addr_bytes)
00069           break;
00070       // testa indirizzo
00071       if (!ContainValidAddress(*param))
00072         break;
00073       // inserisci indirizzo corrente
00074                   addrGeneral.insert(param->literal);
00075       break;
00076     case Param::t_memory:
00077       // testa indirizzo
00078       if (!ContainValidAddress(*param))
00079         break;
00080       // testa indirizzamento diretto
00081       if (param->mem_reg1 == null_reg && param->mem_reg2 == null_reg)
00082       {
00083         // verifica che la memoria punti effettivamente a qualcosa,
00084         // altrimenti e' solo un riferimento
00085         if ( param->GetMemSize() != 0 )
00086         {
00087           varReferences.Add(instAddress,param->literal,FLOW_NONE);
00088 
00089           // !!! se priorita' piu alta ?
00090           if (!byteInfo.IsOccupied(param->literal,param->GetMemSize()))
00091           {
00092             ByteInfo& info = byteInfo[param->literal];
00093             if (info.GetPriority() < priority)
00094             {
00095               info.len = param->GetMemSize();
00096               // !!! not only Integer, can be float or a structure (for save state)
00097               info.SetType(ByteInfo::typeInteger);
00098               info.SetPriority(priority);
00099               info.SetIsLabel();
00100             }
00101           }
00102           break;
00103         }
00104       }
00105       // inserisci indirizzo corrente
00106                   addrGeneral.insert(param->literal);
00107       break;
00108     }
00109   }
00110 }
00111 
00112 // verifica se esiste una costante che punta a del codice
00113 void CodeParser::CheckImmediateCodeAddress(const Instruction& instruction)
00114 {
00115   vma_t address;
00116   const Param *param;
00117   switch(instruction.instruction)
00118   {
00119   // solo mov e push dato che il parametro non e' usato per operazioni
00120   // (presuppongono assegnazione o copia)
00121   // !!! non portatile
00122   case istr_mov:
00123     _PRG_ASSERT(instruction.numArg >= 2);
00124     _PRG_ASSERT(instruction.Args[1].type != Param::t_literal || instruction.Args[1].GetLiteralSize() != 0);
00125         param = &instruction.Args[1];
00126     goto addr_ok;
00127   case istr_push:
00128         param = &instruction.Args[0];
00129   addr_ok:
00130     // verifica dimensione e
00131         if ( param->type != Param::t_literal || param->GetLiteralSize() != addr_bytes )
00132         break;
00133     address = param->literal;
00134 
00135     // testa codice
00136     if (!ContainValidAddress(*param))
00137       break;
00138     // inserisci indirizzo corrente
00139                 addrConstants.insert(address);
00140         break;
00141   }
00142 }
00143 
00144 void CodeParser::AddTempFlow(enum FlowTypes flow,vma_t from,vma_t to,
00145   enum ByteInfo::TPriority priority)
00146 {
00147   if (flow == FLOW_NONE || flow == FLOW_RET)
00148     return;
00149 
00150   // non aggiungere se usato solo per check
00151 #ifdef DEBUG
00152   int inc = (priority == ByteInfo::priCheckOnly)?0:1;
00153 #endif
00154 
00155   TempReference tempRef;
00156   tempRef.from     = from;
00157   tempRef.type     = flow;
00158   tempRef.to       = to;
00159   tempRef.priority = static_cast<uchar>(priority);
00160 
00161   if (istrReferences.IsPresent(tempRef.from,tempRef.to))
00162     return;
00163 
00164         switch(flow)
00165   {
00166   case FLOW_CALL:
00167         pTempRefs->push(tempRef);
00168 #ifdef DEBUG
00169         calls += inc;
00170 #endif
00171         break;
00172   case FLOW_CJUMP:
00173   case FLOW_JUMP:
00174         pTempRefs->push(tempRef);
00175 #ifdef DEBUG
00176         jumps += inc;
00177 #endif
00178         break;
00179   }
00180 }
00181 
00182 // !!! convertire TempRefs in contenitore per poterlo usare con STL ??
00183 bool CodeParser::AddTempFlow(enum FlowTypes flow,vma_t from,
00184   const Instruction& instruction,vma_t instAddress,
00185   enum ByteInfo::TPriority priority,bool bAddComplex)
00186 {
00187   if (flow == FLOW_NONE || flow == FLOW_RET)
00188     return true;
00189 
00190   const Param &param = instruction.Args[0];
00191   if (param.type != Param::t_literal)
00192   {
00193     // se memoria e solo offset registra indirizzo, vedi se chiamata DLL
00194     if (param.type == Param::t_memory)
00195       if (param.mem_reg1 == null_reg && param.mem_reg2 == null_reg)
00196       {
00197         if ( ContainValidAddress(param) )
00198         {
00199           pair<Symbols::iterator,Symbols::iterator> sym = module->GetSymbols()[param.literal];
00200           if ( sym.first != sym.second )
00201           {
00202             if (flow == FLOW_JUMP)
00203             {
00204               apiAlias[from] = param.literal;
00205             }
00206             return true; // ok! chiamata/salto a DLL
00207           }
00208         }
00209       }
00210 
00211     // !!! finish
00212     // se registro scandire indietro e vedere possibili valori
00213     //   (se costanti o variabili caricate)
00214     // se memoria del tipo [4*reg+const] provare tabella
00215     if (bAddComplex && priority != ByteInfo::priCheckOnly)
00216       complexReference.insert(instAddress);
00217 #if 0
00218 #ifdef DEBUG
00219     fprintf(stderr,"Debug: (Flow) ");
00220     WriteInstruction(instruction,stderr);
00221 #endif
00222 #endif
00223     return false;
00224   }
00225 
00226   // !!! check relocation ??
00227   // !!! se codice a 16 bit e chiamata far dovrebbe esserci rilocazione
00228 
00229   AddTempFlow(flow,from,instruction.Args[0].literal,priority);
00230   return true;
00231 }
00232 
00233 void CodeParser::AddExportTempFlow(vma_t to,enum ByteInfo::TPriority priority)
00234 {
00235   _PRG_ASSERT(pTempRefs != NULL);
00236 
00237   // !!! funzione ??
00238   if ( istrReferences.beginReferenceTo(to) !=
00239        istrReferences.endReferenceTo(to) )
00240     return;
00241 
00242         TempReference tempRef;
00243   tempRef.from     = 0; // !!!
00244   tempRef.type     = FLOW_NONE;
00245   tempRef.to       = to;
00246   tempRef.priority = static_cast<uchar>(priority);
00247 
00248   pTempRefs->push(tempRef);
00249 }
00250 
00251 // Estrae un riferimento dallo stack temporaneo e lo salva definitivamente
00252 bool CodeParser::ExtractTempRef(TempReference& tempRef)
00253 {
00254         // assicurati che riferimenti sia inizializzato
00255   _PRG_ASSERT((pTempRefs!=NULL));
00256 
00257         if (pTempRefs->empty())
00258         return false;
00259 
00260   // estrae elemento
00261   tempRef = pTempRefs->top();
00262   pTempRefs->pop();
00263 
00264   // non aggiungere se usato solo per check
00265   if (tempRef.priority == ByteInfo::priCheckOnly)
00266     return true;
00267 
00268   // decrementa contatori e aggiungere reference fissi
00269   switch(tempRef.type)
00270   {
00271   case FLOW_CALL:
00272     istrReferences.Add(tempRef.from,tempRef.to,tempRef.type);
00273 #ifdef DEBUG
00274         --calls;
00275 #endif
00276         break;
00277   case FLOW_CJUMP:
00278   case FLOW_JUMP:
00279     istrReferences.Add(tempRef.from,tempRef.to,tempRef.type);
00280 #ifdef DEBUG
00281         --jumps;
00282 #endif
00283         break;
00284   }
00285 
00286   return true;
00287 }
00288 
00289 // !!! passare solo param ?? portatile ??
00290 bool CodeParser::IsApiReference(const Param& arg) const
00291 {
00292   // !!! aggiungere parametro *string e se valido e true settarlo
00293     if (arg.type == Param::t_memory)
00294     {
00295       // !!! function
00296       if (ContainValidAddress(arg))
00297                           if (arg.mem_reg1 == null_reg && arg.mem_reg2 == null_reg)
00298         {
00299           _PRG_ASSERT(module!=NULL);
00300           if (module->GetSymbols().IsValid(arg.literal))
00301             return true;
00302         }
00303       return false;
00304     }
00305     if (arg.type == Param::t_literal)
00306     {
00307       // salti a jmp ad api
00308       TApiAlias::const_iterator i = apiAlias.find(arg.literal);
00309                         if (i != apiAlias.end())
00310       {
00311         _PRG_ASSERT(module!=NULL);
00312         if (module->GetSymbols().IsValid((*i).second))
00313           return true;
00314       }
00315 //
00316 //      // salti a funzioni esportate
00317 //      _PRG_ASSERT(exportedApi!=NULL);
00318 //      std::string func = (*exportedApi)[arg.literal];
00319 //      if (func != "")
00320 //      {
00321 //        printf("\n* Reference to %s\n|\n",func.c_str());
00322 //      }
00323     }
00324   return false;
00325 }
00326 
00327 #ifdef DEBUG
00328 static bool printIstr = false;
00329 #endif
00330 
00331 // Scandisce il codice iniziando da address
00332 // Si ferma se trova un RET o un JUMP
00333 // Ritorna un codice che ne determina l'errore
00334 // La priorita' serve per settare le informazioni
00335 // address al ritorno contiene l'indirizzo dell'ultima istruzione
00336 //  (valida o no a seconda del risultato)
00337 // bFirst vera se c'e' un'istruzione precedente
00338 // !!! ottimizzare usi di inst_address
00339 enum CodeParser::TScanCodeResult CodeParser::ScanCode(vma_t& address,ByteInfo::TPriority priority,bool bSetLabel)
00340 {
00341   InstructionDecoder decoder(module->GetRelocationInfos());
00342 
00343   // verifica se la prima istruzione e' sovrapposta
00344   if ( priority != ByteInfo::priMax && byteInfo.GetIstrLen(address)==0
00345          && byteInfo.IsOccupied(address) )
00346   {
00347     return scanCodeOverlapped;
00348   }
00349 
00350   bool bFirst = true;
00351         ObjectModule::DataReader reader = module->GetDataReader(address);
00352   for(;;)
00353   {
00354 #ifdef DEBUG
00355 //    fprintf(stderr,"%08lX\t",address);
00356 //    printIstr = (address >= 0x7FAC699Alu);
00357 #endif
00358 
00359     ByteInfo &info = byteInfo[address];
00360 
00361     // !!! a volte e' utile non settare label anche se si analizza
00362     // setta label iniziale
00363     if (bFirst && bSetLabel)
00364       info.SetIsLabel();
00365 
00366     // check se l'istruzione e' gia' stata attraversata
00367     if ( info.len != 0 && priority <= info.GetPriority() )
00368     {
00369       // setta istruzione precedente
00370       // !!! priorita' per bCheckOnly
00371       if (!bFirst && priority != ByteInfo::priCheckOnly)
00372         info.SetIsPrevInstruction();
00373       if (bFirst)
00374         return scanCodeAlreadyProcessed;
00375                         if (info.GetType() != ByteInfo::typeInstruction)
00376                                 return scanCodeInvalid;
00377         break; // !!! ritornare un valore diverso ??
00378     }
00379 
00380     // leggi successiva istruzione
00381     Instruction currInstruction;
00382     int result = decoder.Decode(currInstruction,reader);
00383 
00384     // !!!
00385 //    if (result == 0 && priority == ByteInfo::priMax)
00386 //      throw std::runtime_error("Unknown code in max priority");
00387 
00388     if (!result)
00389       return scanCodeInvalid;
00390 
00391 #ifdef DEBUG
00392     if (printIstr)
00393       WriteInstruction(currInstruction);
00394 #endif
00395 
00396     // non sovraporre a codice gia' esistente
00397     if ( priority != ByteInfo::priMax && byteInfo.GetIstrLen(address)==0
00398          && byteInfo.IsOccupied(address+result-1) )
00399     {
00400       // !!! sicuro di questo ? non invalidare precedenti ?
00401       return scanCodeOverlapped;
00402     }
00403 
00404     // calcola tipo istruzione
00405     enum FlowTypes flow = currInstruction.GetFlowType();
00406 
00407     // verifica che il salto sia corretto
00408     // !!! verificare solo che il codice sia esatto ??
00409     if ( priority <= ByteInfo::priConstant )
00410       if ( flow == FLOW_JUMP || flow == FLOW_CJUMP || flow == FLOW_CALL )
00411         if ( currInstruction.Args[0].type == Param::t_literal )
00412         {
00413           if (!module->GetSection(currInstruction.Args[0].literal)->IsCode())
00414             return scanCodeInvalidJump;
00415         }
00416 
00417     // aggiornamento processo
00418 #ifdef DEBUG
00419     if ( ((++loopCount) & 0x3f) == 0 )
00420       fprintf(stderr,"Process: (Code) bytes: %lu calls: %lu jumps: %lu\n",
00421               bytes,calls,jumps);
00422 #endif
00423 
00424       // aggiunge dati sulla lunghezza
00425       info.len      = (uchar)result;
00426 
00427       // setta priorita' massima
00428       if (info.GetPriority() < priority)
00429       {
00430           info.SetPriority(priority);
00431 #ifdef DEBUG
00432         bytes += result;
00433 #endif
00434       }
00435 
00436       // prima di questa esiste un'istruzione
00437       if (!bFirst)
00438         info.SetIsPrevInstruction();
00439 
00440       //bytes += result;
00441 
00442             // aggiungi istruzione di flusso
00443       // !!! un po' strano, o no ?
00444       AddTempFlow(flow,address,currInstruction,address,priority);
00445 
00446       // salva costanti che possano puntare al codice
00447       // !!!
00448       if (priority != ByteInfo::priCheckOnly)
00449       {
00450               CheckImmediateCodeAddress(currInstruction);
00451         CheckForAddress(address,currInstruction,priority);
00452       }
00453 
00454     // fermati se salto incondizionale o ritorno
00455     if (flow == FLOW_JUMP || flow == FLOW_RET)
00456     {
00457        break;
00458     }
00459 
00460     // va avanti
00461     address += result;
00462     bFirst = false;
00463   }
00464   return scanCodeNoError;
00465 }
00466 
00467 void CodeParser::ResetCodeRange(const range<vma_t>& r)
00468 {
00469   for(vma_t address = r.begin;;)
00470   {
00471     _PRG_ASSERT(address <= r.end);
00472     ByteInfo& info = byteInfo[address];
00473     _PRG_ASSERT(info.len != 0 || address == r.end);
00474     _PRG_ASSERT(info.GetPriority() == ByteInfo::priCheckOnly || address == r.end);
00475     int len = info.len;
00476     if (info.GetPriority() == ByteInfo::priCheckOnly)
00477     {
00478       // se errore leva marcatura
00479       info.Reset();
00480     }
00481     if (address == r.end)
00482       break;
00483     address += len;
00484   }
00485 }
00486 
00487 void CodeParser::SetCodeRange(const range<vma_t>& r,ByteInfo::TPriority priority,bool bSetLabel)
00488 {
00489   vma_t begin = r.begin;
00490 #ifdef DEBUG
00491   // TScanCodeResult res =
00492 #endif
00493   ScanCode(begin,priority,bSetLabel);
00494 
00495   // !!! per procedure che non ritornano puo' accadere un errore
00496   //_PRG_ASSERT(res <= scanCodeNoError);
00497   // !!! si processano prima export e poi heuristic,
00498   // ma priorita heuristic > priorita export
00499   //_PRG_ASSERT(begin == (*i).end);
00500 }
00501 
00502 // verifica il codice usando ScanCode
00503 // address alla fine punta all'ultimo codice corretto
00504 // !!! questo codice dovrebbe essere usato solo per la scansione di filler
00505 // !!! in quanto non gestisce i salti dentro al codice scandito
00506 bool CodeParser::CheckCode(vma_t& address,ByteInfo::TPriority priority,bool bSetLabel)
00507 {
00508   _PRG_ASSERT(pTempRefs->size() == 0);
00509   TScanCodeResult lastResult = scanCodeNoError;
00510 
00511   // testa se il codice e' corretto
00512   vma_t start = address;
00513   vma_t scanAddress;
00514   try
00515   {
00516     scanAddress = start;
00517     lastResult = ScanCode(scanAddress,ByteInfo::priCheckOnly,bSetLabel);
00518   }
00519   catch(const ObjectModule::OutOfAddress&)
00520   {
00521     lastResult = scanCodeInvalid;
00522   }
00523   for (TempReference tempRef;ExtractTempRef(tempRef););
00524 
00525   // setta o resetta codice
00526   if (lastResult <= scanCodeNoError)
00527     SetCodeRange(range<vma_t>(start,scanAddress),priority,bSetLabel);
00528   else
00529     ResetCodeRange(range<vma_t>(start,scanAddress));
00530   {for (TempReference tempRef;ExtractTempRef(tempRef););}
00531 
00532   address = scanAddress;
00533 
00534   return (lastResult <= scanCodeNoError);
00535 }
00536 
00537 //class CodeCheck
00538 //{
00539 //public:
00540 //  CodeCheck() {};
00541 //  bool AddCheck(vma_t address,bool bOneLevel=false);
00542 //  void ResetAddress();
00543 //  void SetAddress();
00544 //private:
00545 //  range_set<vma_t> ranges;
00546 //};
00547 
00548 // verifica il codice ricorsivamente usando ScanCode
00549 bool CodeParser::CheckCodeRecursively(vma_t address,ByteInfo::TPriority priority,bool _bSetLabel)
00550 {
00551   _PRG_ASSERT(pTempRefs->size() == 0);
00552 
00553   // insieme di codice scannato
00554   range_set<vma_t> ranges;
00555   // handle one instruction (jmp/ret) process
00556   TAddresses addresses;
00557   TScanCodeResult lastResult = scanCodeNoError;
00558   bool bSetLabel = _bSetLabel;
00559 
00560   // scandisci a partire dall'entry
00561   AddExportTempFlow(address,ByteInfo::priCheckOnly);
00562   for (;;)
00563   {
00564     TempReference tempRef;
00565     if (!ExtractTempRef(tempRef))
00566       break;
00567 
00568     // scandisci il codice
00569     vma_t address = tempRef.to;
00570     try
00571     {
00572       lastResult = ScanCode(address,ByteInfo::priCheckOnly,bSetLabel);
00573     }
00574     catch(const ObjectModule::OutOfAddress&)
00575     {
00576       lastResult = scanCodeInvalid;
00577     }
00578 
00579     // solo al primo non marcare label
00580     bSetLabel = true;
00581 
00582     // marca il codice scandito
00583     _PRG_ASSERT(tempRef.to <= address);
00584     if ( tempRef.to == address)
00585       addresses.insert(tempRef.to);
00586     else
00587       ranges.insert(range<vma_t>(tempRef.to,address));
00588 
00589     // se errore fermati
00590     if (lastResult > scanCodeNoError)
00591       break;
00592   }
00593 
00594   // scandisce tutti i range possibili
00595   {
00596   typedef range_set<vma_t>::iterator iterator;
00597   iterator i   = ranges.begin();
00598   iterator end = ranges.end();
00599   for(;i!=end;++i)
00600   {
00601     if (lastResult <= scanCodeNoError)
00602       SetCodeRange(*i,priority,_bSetLabel || (*i).begin != address);
00603     else
00604       // !!! se il codice e' scandito con successo setta priorita' anche
00605       // nella cella end. Non inserisce inst_offset+1 in ranges altrimenti
00606       // se e' un ret ScanCode successivo si ferma a meta' range
00607       ResetCodeRange(*i);
00608   }
00609   }
00610 
00611   // scandisce tutti gli indirizzi possibili
00612   {
00613   typedef TAddresses::iterator iterator;
00614   iterator i   = addresses.begin();
00615   iterator end = addresses.end();
00616   for(;i!=end;++i)
00617   {
00618     if (lastResult <= scanCodeNoError)
00619       SetCodeRange(range<vma_t>(*i,*i),priority,_bSetLabel || (*i) != address);
00620     else
00621       // !!! se il codice e' scandito con successo setta priorita' anche
00622       // nella cella end. Non inserisce inst_offset+1 in ranges altrimenti
00623       // se e' un ret ScanCode successivo si ferma a meta' range
00624       ResetCodeRange(range<vma_t>(*i,*i));
00625   }
00626   }
00627 
00628   // estrae tutti i reference temporanei
00629   for (TempReference tempRef;ExtractTempRef(tempRef););
00630 
00631   return (lastResult <= scanCodeNoError);
00632 }
00633 
00634 int GetInstruction(ObjectModule& module,vma_t address,Instruction& instruction)
00635 {
00636   // legge l'istruzione
00637   InstructionDecoder decoder(module.GetRelocationInfos());
00638         ObjectModule::DataReader reader = module.GetDataReader(address);
00639   return decoder.Decode(instruction,reader);
00640 }
00641 
00642 void CodeParser::ExcludeFileRange(CSignFile& _file,const RVAFileTranslator& rva,uint32_t imageBase)
00643 {
00644   range_set<long> excludeRange = _file.GetRanges();
00645   range_set<long>::iterator i   = excludeRange.begin();
00646   range_set<long>::iterator end = excludeRange.end();
00647   for( ;i!= end; ++i)
00648   {
00649     // !!! troppo dipendente da formato Pe
00650     vma_t start;
00651     vma_t finish;
00652     try
00653     {
00654       start  = rva.File2RVASafe((*i).begin) + imageBase;
00655       finish = rva.File2RVASafe((*i).end-1) + imageBase;
00656     }
00657     catch(std::runtime_error&)
00658     { continue; }
00659 
00660 //    _DEBUG_(fprintf(stderr,"start: %08lX end: %08lX\n",start,finish));
00661 
00662     range<long> r = *i;
00663 
00664     // !!! bug finire
00665     // testa per piu' sezioni
00666     while( (finish-start+1) != static_cast<unsigned long>(r.end - r.begin) )
00667     {
00668       // trova prima sezione
00669       const PeSection *p;
00670       for(unsigned n=0;; ++n)
00671       {
00672         p = rva.GetSection(n);
00673         if (p == NULL)
00674         {
00675           throw runtime_error("I think there is a bug inside");
00676         }
00677         if ((unsigned long)r.begin >= p->RawAddress && ((unsigned long)r.begin-p->RawAddress) < p->RawSize)
00678         {
00679           // elimina questa sezione
00680           ByteInfo& info = byteInfo[start];
00681           info.SetPriority(ByteInfo::priMax);
00682           info.SetType(ByteInfo::typeLoader);
00683           // setta la lunghezza lunga
00684 //          _DEBUG_(fprintf(stderr,"len setted: %lX\n",p->RawSize - (r.begin-p->RawAddress)));
00685           byteInfo.SetLen(start,p->RawSize - (r.begin-p->RawAddress) );
00686 
00687           // vai alla prossima sezione
00688           r.begin = p->RawAddress+p->RawSize;
00689           start = rva.File2RVASafe(r.begin) + imageBase;
00690           break;
00691         }
00692       }
00693     }
00694 
00695     // setta informazioni
00696     ByteInfo& info = byteInfo[start];
00697     info.SetPriority(ByteInfo::priMax);
00698     info.SetType(ByteInfo::typeLoader);
00699     // setta la lunghezza lunga
00700 //    _DEBUG_(fprintf(stderr,"len setted: %lX\n",finish-start+1));
00701     byteInfo.SetLen(start,finish-start+1);
00702   }
00703 }
00704 
00705 // imageBase, entryPoint, api, exportedApi servono solo per inizializzazioni
00706 void CodeParser::Parse(CSignFile& _file,uint32_t imageBase,vma_t _entryPoint,
00707   const RVAFileTranslator& rva,const Symbols& _symbols,const Symbols& _exportedSymbols,
00708   bool hasRelocation,const RelocationInfos& relocationInfos)
00709 {
00710 //  istrReferences.insert(IstrReference(10,20,true,FLOW_CALL));
00711 //  istrReferences.insert(IstrReference(10,20,false,FLOW_CALL));
00712 //  if ( !(*istrReferences.begin()).direct )
00713 //    printf("0\n");
00714 //  istrReferences.insert(IstrReference(11,20,true,FLOW_CALL));
00715 //  if (istrReferences.lower_bound(IstrReference(10,0)) ==
00716 //      istrReferences.lower_bound(IstrReference(11,0)))
00717 //    printf("1\n");
00718 //  if (istrReferences.lower_bound(IstrReference(9,0)) !=
00719 //      istrReferences.lower_bound(IstrReference(10,0)))
00720 //    printf("2\n");
00721 //  if (istrReferences.lower_bound(IstrReference(11,0)) ==
00722 //      istrReferences.lower_bound(IstrReference(12,0)))
00723 //    printf("3\n");
00724 //  if (istrReferences.lower_bound(IstrReference(12,0)) !=
00725 //      istrReferences.lower_bound(IstrReference(13,0)))
00726 //    printf("4\n");
00727 //  if (istrReferences.lower_bound(IstrReference(12,0)) !=
00728 //      istrReferences.end())
00729 //    printf("5\n");
00730 //  if (!IsPresent(istrReferences,IstrReference(10,20)))
00731 //    printf("6\n");
00732 
00733 #ifdef DEBUG
00734   unsigned maxStringInCode = 0;
00735   unsigned currStringLen = 0;
00736   unsigned istrCount[num_instructions];
00737   memset(&istrCount,0,sizeof(istrCount));
00738 #endif
00739 
00740   // escludi bytes letti da file
00741   ExcludeFileRange(_file,rva,imageBase);
00742 
00743   ObjectModule _module(_file,rva,imageBase,hasRelocation,relocationInfos,
00744                 _symbols,_exportedSymbols,_entryPoint);
00745   // !!! creare interno classe
00746   this->module = &_module;
00747 
00748         vma_t end;
00749 
00750   // verifica che ci sia qualcosa da disassemblare
00751   int numCodeSections = 0;
00752   FOR_EACH_SECTION_CODE_BEGIN(module,p)
00753     if ( (*p).IsCode() )
00754       ++numCodeSections;
00755   FOR_EACH_SECTION_CODE_END(module,p)
00756   if (numCodeSections == 0)
00757     return;
00758 
00759 #ifdef DEBUG
00760   bytes = 0;
00761   bytes = jumps = calls = 0;
00762   loopCount = 0;
00763 #endif
00764   pTempRefs = new TTempRefs;
00765 
00766   // prima scansione, entrypoint ed Export
00767   // !!! solo se punta a codice
00768   for(vma_t address = module->GetExportSymbols().GetNextValid(0); !IsNullAddress(address); address = module->GetExportSymbols().GetNextValid(address))
00769     if (module->GetSection(address)->IsCode())
00770     {
00771       // scandisce testando (elimina export a dati)
00772       CheckCodeRecursively(address,ByteInfo::priExport);
00773     }
00774   if (!IsNullAddress(module->GetEntryPoint()))
00775           AddExportTempFlow(module->GetEntryPoint(),ByteInfo::priEntryPoint);
00776 
00777   bool bProcessed = false;  // processato del codice ?
00778   // ha scandito altro codice dal controllo dei reference??
00779   bool bFlowChangedSinceReference = false;
00780   // ha scandito altro codice dal controllo api??
00781   bool bFlowChangedSinceApi       = false;
00782   // c'e' qualcosa di incognito (reference, api) ?
00783   bool bSomeUnknown               = false;
00784   bool bUseConstantPrinted        = false;
00785 
00786   freddy77::auto_delete_ptr<THeuristicMotor> heuristics;
00787 
00788 
00789   // esegui finche' c'e' qualcos'altro da fare
00790   for(;;)
00791   {
00792     // !!! se processati heuristico o costanti i reference sono gia' eliminati,
00793     // non riprocessa jump complessi e API
00794     // scandisci codici da salti/chiamate incontrate
00795 //    bProcessed = false;
00796     for(;;)
00797     {
00798       // estrae un reference
00799       TempReference tempRef;
00800       if (!ExtractTempRef(tempRef))
00801         break;
00802 
00803       // processa reference
00804       vma_t address = tempRef.to;
00805 
00806       if (ScanCode(address,static_cast<ByteInfo::TPriority>(tempRef.priority)) !=
00807           scanCodeAlreadyProcessed && address != tempRef.to)
00808 //                      if (CheckCode(address,static_cast<ByteInfo::TPriority>(tempRef.priority)) && address != tempRef.to)
00809         bProcessed = true;
00810     }
00811 
00812     // se processato forza riscansione
00813     if (bProcessed)
00814     {
00815       bFlowChangedSinceApi       = true;
00816       bFlowChangedSinceReference = true;
00817       bSomeUnknown               = false;
00818     }
00819 
00820         // cerca di usare chiamate/salti complessi (indirizzo in memoria o registro)
00821                 if (bFlowChangedSinceReference && !bSomeUnknown) for(bProcessed = false;;)
00822     {
00823       bFlowChangedSinceReference = false;
00824 
00825         // !!! la dimensione del container puo' variare dentro il loop
00826         // estrae reference complessi (non leverli dal container??)
00827       if ( complexReference.empty() )
00828         break;
00829 
00830 #if 0
00831 #ifdef DEBUG
00832       {
00833       TTempComplexReference::iterator i = complexReference.begin();
00834       for(int n=1;i != complexReference.end();++i,++n)
00835       {
00836         if ( (n%6) == 1 )
00837           fprintf(stderr,"Debug: (Complex) ");
00838         fprintf(stderr,(n%6==0)?"%08lX\n":"%08lX ",unsigned(*i));
00839       }
00840       fprintf(stderr,"\n");
00841       }
00842 #endif
00843 #endif
00844 
00845       // cerca di "eseguire" reference
00846       TTempComplexReference::iterator i = complexReference.begin();
00847 #ifdef DEBUG
00848       unsigned numUnknown = 0;
00849       unsigned numKnown   = 0;
00850 #endif
00851       for(;i != complexReference.end();++i)
00852       {
00853         if (!ExecuteComplexReference(*i))
00854         {
00855           // se non riuscito a processare tutti i salti possibili
00856           // segnalo
00857           bSomeUnknown = true;
00858           _DEBUG_(++numUnknown);
00859         }
00860         else
00861         {
00862           // se trova altri salti da fare aggiungili alla lista
00863           bProcessed = true;
00864           _DEBUG_(++numKnown);
00865         }
00866       }
00867 #ifdef DEBUG
00868       if ( (numKnown+numUnknown) != 0 )
00869         fprintf(stderr,"Debug: (Complex) Perc %f\n",
00870           float(((double)numKnown*100)/(numKnown+numUnknown)));
00871 #endif
00872 
00873       // se eseguito segna esecuzione e togli
00874       // !!! no, potrebbe variare il flusso del codice
00875       break;
00876     }
00877     if (bProcessed)
00878     {
00879       // !!! fa schifo
00880       bProcessed = false;
00881         continue;
00882     }
00883 
00884     // !!! finish !!!
00885     // cerca di avere tutte le info per il codice delle chiamate alle api
00886     // se c'e' gia' qualcosa di sbagliato alla fine ce ne sara' comunque
00887                 if (bFlowChangedSinceApi && !bSomeUnknown) for(bProcessed = false;;)
00888     {
00889       bFlowChangedSinceApi = false;
00890         bSomeUnknown = true; // !!!
00891         // !!! la dimensione del container puo' variare dentro il loop
00892         // estrae reference complessi (non leverli dal container??)
00893       break;
00894 
00895       // cerca di "eseguire" api
00896 /*
00897       // se trova altri indirizzi codice aggiungili alla lista
00898         bProcessed = true;
00899 
00900       // se non tolti tutti
00901         // segnalo
00902         bSomeUnknown = true;
00903 */
00904     }
00905     if (bProcessed)
00906     {
00907       // !!! fa schifo
00908       bProcessed = false;
00909         continue;
00910     }
00911 
00912 /*
00913     // Il programma non e' abbastanza preciso per questo!!
00914     // non c'e' niente antro da scandire
00915     // !!! e le costanti puntate dal codice sopra ???
00916     if (!bSomeUnknown)
00917     {
00918 #ifdef DEBUG
00919       {
00920       unsigned bytes = 0;
00921       FOR_EACH_SECTION_CODE_BEGIN(module,p)
00922               vma_t address = (*p).begin;
00923             end            = (*p).end;
00924               for(; address<end; )
00925         {
00926           int len = byteInfo.GetIstrLen(address);
00927           if (len != 0)
00928           {
00929             bytes += len;
00930             address += len;
00931           }
00932           else
00933             ++address;
00934         }
00935       FOR_EACH_SECTION_CODE_END(module,p)
00936       unsigned codeSize = 0;
00937       FOR_EACH_SECTION_CODE_BEGIN(module,p)
00938         codeSize += (*p).end - (*p).begin;
00939       FOR_EACH_SECTION_CODE_END(module,p)
00940       if (codeSize)
00941         fprintf(stderr,"\"Secure code\" %.1f%%\n",
00942           float(((double)bytes*100)/codeSize) );
00943       }
00944 #endif
00945         break;
00946     }
00947 */
00948 
00949     // metodo euristico, migliore degli export
00950     // !!! solo se non processato tutto, fa un test globale
00951     if (!&*heuristics)
00952       heuristics = new THeuristicMotor(*this);
00953 //      heuristics.reset(new THeuristicMotor());
00954     if ( (bProcessed=heuristics->ProcessSecure(*this)) != false )
00955       continue;
00956 
00957                 if (!bUseConstantPrinted)
00958     {
00959 #ifdef DEBUG
00960       {
00961       unsigned bytes = 0;
00962       FOR_EACH_SECTION_CODE_BEGIN(module,p)
00963               vma_t address = (*p).begin;
00964             end            = (*p).end;
00965               for(; address<end; )
00966         {
00967           int len = byteInfo.GetIstrLen(address);
00968           if (len != 0)
00969           {
00970             bytes += len;
00971             address += len;
00972           }
00973           else
00974             ++address;
00975         }
00976       FOR_EACH_SECTION_CODE_END(module,p)
00977       unsigned codeSize = 0;
00978       FOR_EACH_SECTION_CODE_BEGIN(module,p)
00979         codeSize += (*p).end - (*p).begin;
00980       FOR_EACH_SECTION_CODE_END(module,p)
00981       if (codeSize)
00982         fprintf(stderr,"\"Secure code\" %.1f%%\n",
00983           float(((double)bytes*100)/codeSize) );
00984       }
00985 #endif
00986         // !!! log windows ??
00987         fprintf(stderr,"Warning: Constant processed\n");
00988       if (complexReference.empty())
00989         fprintf(stderr,"Wow: complex reference is empty\n");
00990       if (addrConstants.empty())
00991         fprintf(stderr,"Wow: Constants address empty\n");
00992         bUseConstantPrinted = true;
00993     }
00994 
00995     // unsafe heuristic code process
00996 // !!! commented for priority reason purpose (less safe than constant??)
00997 //    if ( (bProcessed=heuristics->ProcessUnsecure(*this)) != false )
00998 //      continue;
00999 
01000           // cerca altro codice date le costanti salvate
01001           // questa e' l'ultima risorsa per riempire i buchi
01002           // testa prima che il codice sia valido
01003         for(;;)
01004           {
01005       if ( addrConstants.begin() == addrConstants.end() )
01006         break;
01007 
01008       vma_t address = *addrConstants.begin();
01009       addrConstants.erase(addrConstants.begin());
01010 
01011       // !!! aggiungere caso per indirizzo a dati non inizializzati
01012 
01013       // prova a vedere se e' una stringa
01014       unsigned len,printable;
01015       GetStringStats(address,len,printable);
01016 
01017       // se caratteri stampabili >= 75% assumi stringa
01018       if ( len >0 && printable>2 && printable*100 > (len-1)*75 )
01019       {
01020         ByteInfo& info = byteInfo[address];
01021         //info.len = len;
01022         info.SetPriority(ByteInfo::priConstant);
01023         info.SetType(ByteInfo::typeASCIIZ);
01024         // setta la lunghezza lunga
01025         byteInfo.SetLen(address,len);
01026         continue;
01027       }
01028 
01029       // prova a vedere se array di puntatori
01030       PointerArrayStat pStat;
01031       GetPointerArrayStats(address,pStat);
01032       // piu' di due puntatori non nulli, assumi array puntatori
01033       if ( pStat.nFirstNull >= 2 ) // !!! constant
01034       {
01035         // testa se puntatori a codice
01036         // !!! module non ammette Seek al byte subito dopo end
01037         if (pStat.nCodePointer >= pStat.nFirstNull)
01038         {
01039           for(unsigned n=0; n<pStat.nPointer;++n,address+=addr_bytes)
01040           {
01041             // marca come DWORD
01042             ByteInfo& info = byteInfo[address];
01043             info.len = addr_bytes;
01044             info.SetType(ByteInfo::typePointer);
01045             info.SetPriority(ByteInfo::priConstant);
01046 
01047             // "esegui" puntatore
01048                                                 ObjectModule::DataReader reader = module->GetDataReader(address);
01049             vma_t addr = reader.ReadDword();
01050             if (IsNullAddress(addr)) // fermarsi a ptr nullo
01051             {
01052               // fermati al primo indirizzo non al codice
01053               if (!module->GetSection(addr)->IsCode())
01054                 break;
01055               // !!! prima dovrebbe testarli tutti
01056               if (CheckCodeRecursively(addr,ByteInfo::priConstant))
01057                 bProcessed = true;
01058             }
01059           }
01060         }
01061         continue;
01062       }
01063 
01064       // !!! aggiungere parte check bit & range
01065       //BitStat bitStat;
01066       //GetBitStat(address,16*11,bitStat);
01067 
01068       // !!! assume sia codice
01069       if (module->GetSection(address)->IsCode())
01070         if (CheckCodeRecursively(address,ByteInfo::priConstant))
01071         {
01072           bProcessed = true;
01073         }
01074           }
01075 
01076           if (bProcessed)
01077                 continue;
01078 
01079     _PRG_ASSERT(pTempRefs->empty());
01080     _PRG_ASSERT(addrConstants.empty());
01081 
01082           // !!! testa istruzioni sovrapposte
01083     // !!! test overlapped instruction
01084 
01085     break;
01086   }
01087 
01088   // scandisce tutto il codice alla ricerca di codice non decompilato
01089   // salta bytes tutti a 0
01090   // scan all code for undisassembled code
01091   // skip zeroes bytes
01092   FOR_EACH_SECTION_CODE_BEGIN(module,p)
01093     vma_t address = (*p).begin;
01094     end            = (*p).end;
01095     for(; address<end; )
01096     {
01097                         ObjectModule::DataReader reader = module->GetDataReader(address);
01098 
01099       int len = byteInfo.GetIstrLen(address);
01100 
01101       // se gia' passato salta istruzione
01102             if (len != 0)
01103       {
01104 #ifdef DEBUG
01105                                 // capture some statistics on code
01106         // parse instruction
01107             Instruction currInstruction;
01108         int result = GetInstruction(*module,address,currInstruction);
01109         if (result)
01110         {
01111           _PRG_ASSERT(currInstruction.instruction>=0);
01112           _PRG_ASSERT(currInstruction.instruction<=num_instructions);
01113           ++istrCount[currInstruction.instruction];
01114                                         ObjectModule::DataReader reader = module->GetDataReader(address);
01115           for (int i=0;i<len;++i)
01116           {
01117             int c = reader.ReadByte();
01118             if (isprint(c))
01119             {
01120               ++currStringLen;
01121               if ( currStringLen > maxStringInCode )
01122               {
01123                 maxStringInCode = currStringLen;
01124               }
01125             }
01126             else
01127               currStringLen = 0;
01128           }
01129 
01130         }
01131 #endif
01132                 address += len;
01133           continue;
01134           }
01135       _DEBUG_(currStringLen = 0);
01136 
01137                         // if relocation it must be a pointer to somewhere
01138                         const Relocation *rel = 
01139                                 module->GetRelocationInfos().GetRelocation(address,addr_bytes);
01140                         if (rel && rel != &RelocationInfos::relError)
01141                         {
01142                                 ByteInfo& info = byteInfo[address];
01143                                 info.len = addr_bytes;
01144                                 info.SetType(ByteInfo::typeInteger);
01145                                 info.SetPriority(ByteInfo::priFiller);
01146 
01147                                 address += addr_bytes;
01148                                 continue;
01149                         }
01150                         
01151             // read next byte
01152           int c;
01153                         try {
01154                 c = reader.ReadByte();
01155                         }
01156                         catch (ObjectModule::OutOfAddress&)
01157                         {
01158           return; // !!!
01159                         }
01160 
01161       // se 0 leggi fino a che sono zeri o istruzione occupata
01162                         _PRG_ASSERT(len ==0);
01163             if ( c==0 )
01164           {
01165         _DEBUG_(currStringLen = 0);
01166         do
01167               {
01168                                         try {
01169                                 c = reader.ReadByte();
01170                                         }
01171                                         catch (ObjectModule::OutOfAddress&)
01172                                         {
01173                         c = -1;
01174                                         }
01175                   len = byteInfo.GetIstrLen(++address);
01176             } while ( c==0 && len==0 
01177                                                                 && !module->GetRelocationInfos().GetRelocation(address) 
01178                                                                 && address<end );
01179         continue;
01180       }
01181 
01182           // tutto ok , posso scandire il codice da qui
01183       vma_t checkAddr = address;
01184       if ( !CheckCode(checkAddr,ByteInfo::priFiller) )
01185       {
01186                                 // try on next byte
01187                                 // skipping all code that seam valid 
01188                                 // (doing address = checkAddr+1) can skip relocation
01189                                 ++address;
01190       }
01191 
01192         // se trova qualcosa di meglio da scandire ben venga
01193       // !!! non serve cercare la logica nell'illogico
01194     }
01195   FOR_EACH_SECTION_CODE_END(module,p)
01196 
01197   // estrae tutti i reference temporanei
01198   for (TempReference tempRef;ExtractTempRef(tempRef););
01199 
01200 #ifdef DEBUG
01201   fprintf(stderr,"Stat: (Code) MaxStringLenInCode: %u\n",maxStringInCode);
01202   for (unsigned ni=0; ni<num_instructions; ++ni)
01203     if (istrCount[ni])
01204       fprintf(stderr,"Stat: (Instr) %s: %u\n",
01205         x86instructions_names[ni],istrCount[ni]);
01206 #endif
01207 
01208   WriteCode();
01209 
01210   // mettere nel distruttore !!!
01211   delete pTempRefs;
01212   pTempRefs = NULL;
01213   // !!!
01214   this->module = NULL;
01215 }
01216 
01217 void ParseCode(CSignFile& file,uint32_t imageBase,vma_t entryPoint,const RVAFileTranslator& rva,const Symbols& symbols,const Symbols& exportedSymbols,bool hasRelocation,const RelocationInfos& relocationInfos)
01218 {
01219   CodeParser* p = new CodeParser;
01220   p->Parse(file,imageBase,entryPoint,rva,symbols,exportedSymbols,hasRelocation,relocationInfos);
01221   delete p;
01222 }
01223 
01224 // vim:tabstop=2:mouse=a:
01225 

Generated on Mon Jan 13 22:20:33 2003 for perdr by doxygen1.2.15