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: https://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