Logo Search packages:      
Sourcecode: uncc version File versions  Download package

uncc_functions_search.h

/*
 * uncc - The ultimate C decompiler
 * Copyright (C) 2003  Megabug <megabug@autistici.org>,
 *                     Little-John <littlejohn@autistici.org>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

void fsearch_load_labels()
{
      goto_start;

      for (goto_start; !s_eof; next)
      {
            if (is_op("label"))
            {
                  Label *l;
                  l = LABELS_new(get_par1(),i);
                  SOURCE_set_label(i,l);
                  verbose("Label detect: new label %s\n", get_par1());
            }
      }
}

void fsearch_fill_function( Function *f, SourceLine *i )
{
      while (!s_eof)
      {
            Label *d;

            if (SOURCE_get_function(i)!=NULL)
                  return;
            SOURCE_set_function(i,f);

            if (is_op("call-d"))
            {
                  d = LABELS_find(get_par1());

                  // External function?
                  if (d==NULL)
                  {
                        Function *f;
                        d = LABELS_new(get_par1(),NULL);
                        f = FUNCTIONS_new_from_label(d);
                        FUNCTIONS_set_external(f);
                  }
                  else if (FUNCTIONS_find_from_label(d)==NULL)
                  {
                        Function *f;
                        f = FUNCTIONS_new_from_label(d);
                        fsearch_fill_function( f, LABELS_source_line(d) );
                        verbose( "Function detect: New function %s\n", get_par1() );
                  }
            }

            if ( is_op("ja-d") || is_op("jae-d") || is_op("jb-d") || is_op("jbe-d") || is_op("jc-d") ||
                 is_op("jcc-d") || is_op("jcxz-d") || is_op("jecxz-d") || is_op("je-d") || is_op("jg-d") ||
                 is_op("jge-d") || is_op("jl-d") || is_op("jle-d") || is_op("jna-d") || is_op("jnae-d") ||
                 is_op("jnb-d") || is_op("jnbe-d") || is_op("jnc-d") || is_op("jne-d") || is_op("jng-d") ||
                 is_op("jnge-d") || is_op("jnl-d") || is_op("jnle-d") || is_op("jno-d") || is_op("jnp-d") ||
                 is_op("jns-d") || is_op("jnz-d") || is_op("jo-d") || is_op("jp-d") || is_op("jpe-d") ||
                 is_op("jpo-d") || is_op("js-d") || is_op("jz-d") )
            {
                  d = LABELS_find(get_par1());
                  fsearch_fill_function( f, LABELS_source_line(d) );
            }

            if (is_op("jmp-d"))
            {
                  d = LABELS_find(get_par1());
                  i = LABELS_source_line(d);
                  continue;
            }

            if (is_op("ret"))
                  return;
            next;
      }
}

void fsearch_detect_functions()
{
      Function *f;
      f = FUNCTIONS_new_from_label(LABELS_find("main"));
      verbose( "Function detect: New function main\n" );
      fsearch_fill_function( f, LABELS_source_line(LABELS_find("main")) );
}

void fsearch_detect_frame_pointer(Function *f)
{
      verbose( "Function: %s\n", FUNCTIONS_name(f));

      i = LABELS_source_line(FUNCTIONS_get_label(f));
      next;
      if (is_op("pushl-r"))
      {
            Register *r;
            r = REGS_find_or_new(get_par1());
            verbose("pushl-r %s : Possible frame pointer in %s\n", get_par1(), get_par1());

            next;

            if (is_op("movl-rr") && is_par2("esp"))
            {
                  Register *s;
                  s = REGS_find_or_new(get_par1());
                  if ( s != r )
                        fatal("movl-rr %s,%s : Strange prelude!\n", get_par2(), get_par1());
                  verbose("Found prelude: Frame pointer in %s (offset=0)\n", get_par1());
                  FUNCTIONS_set_frame_pointer(f,r);
            }
            else
            {
                  fatal("No movl-rr after pushl-r : Failed prelude!\n");
            }

            next;
            while (is_op("pushl-r"))
            {
                  verbose("Prelude: Saved register %s\n", get_par1());
                  next;
            }

            if (is_op("subl-ri") && is_par1("esp"))
            {
                  verbose("Prelude: Frame size=%s\n", get_par2());
                  FUNCTIONS_set_frame_size(f, atoi32(get_par2()));
                  return;
            }
            FUNCTIONS_set_frame_size(f, 0);
            verbose("Prelude: Frame size=0\n");
            return;
      }

      // NO Frame pointer. Search for offset of local parms in the stack.
      if (is_op("subl-ri"))
      {
            if (is_par1("esp"))
            {
                  verbose("Found prelude: Frame pointer in esp (offset=%s)\n", get_par2());
                  FUNCTIONS_set_frame_pointer(f, REGS_find_or_new("esp"));
                  verbose("Prelude: Frame size=%s\n", get_par2());
                  FUNCTIONS_set_frame_size(f, atoi32(get_par2()));
            }
      }
      else
      {
            verbose("Found prelude: Frame pointer in esp (offset=0)\n" );
            FUNCTIONS_set_frame_pointer(f, REGS_find_or_new("esp"));
            verbose("Prelude: Frame size=0\n");
            FUNCTIONS_set_frame_size(f, 0);
      }

}

int fsearch_variable_offset(SourceLine *l, int start_parm)
{
      Expr *ex_index;
      
      Function *f;
      Register *reg1, *reg2, *bp;
      int offset, bpoffset, parm, mult, res;
      parm = start_parm+1;

      f = SOURCE_get_function(l);
      bp = FUNCTIONS_get_frame_pointer(f);
      bpoffset = FUNCTIONS_get_frame_size(f);
      
      REGS_flush(REGS_find_or_new("esp"));
      REGS_link(REGS_find("esp"), EXPR_new_int(-bpoffset));
      REGS_flush(bp);
      REGS_link(bp,EXPR_new_int(0));

      offset = atoi32(get_par(parm));
      reg1 = NULL;
      reg2 = NULL;
      if (!is_par("0",parm+1)) {
            reg1 = REGS_find(get_par(parm+1));
            if ( !reg1 ) {
                  reg1 = REGS_new(get_par(parm+1));
                  REGS_link(reg1, EXPR_new_int(0));
            }
      }
      if (!is_par("0",parm+2)) {
            reg2 = REGS_find(get_par(parm+2));
            if ( !reg2 ) {
                  reg2 = REGS_new(get_par(parm+2));
                  REGS_link(reg2, EXPR_new_int(0));
            }
      }
      mult = atoi32(get_par(parm+3));

      verbose("VARIABLE DETECTION: Offset=%d, reg1=%s, reg2=%s, mult=%d\n", 
            offset, reg1?REGS_name(reg1):"-", reg2?REGS_name(reg2):"-", mult );

      if (reg2)
      {
            ex_index = EXPR_new_linked(0,EXPR_OP_MULT,
                  EXPR_copy(REGS_expr(reg2)),
                  EXPR_new_int(mult));
            if (reg1)
            {
                  ex_index = EXPR_new_linked(0,EXPR_OP_SUM,
                        EXPR_copy(REGS_expr(reg1)),
                        ex_index);
            }
            if (offset)
            {
                  ex_index = EXPR_new_linked(0,EXPR_OP_SUM,
                        EXPR_new_int(offset),
                        ex_index);
            }
            EXPR_print_tree(ex_index,stdout);
            if (! EXPR_eval(ex_index, &res) )
                  fatal("Cannot evaluate expression.");
            printf(" = %d\n",res);
            EXPR_free(ex_index);
            return res;
      }
      else // if (reg1)
      {
            ex_index= EXPR_copy(REGS_expr(reg1));
            if (offset)
            {
                  ex_index = EXPR_new_linked(0,EXPR_OP_SUM,
                        EXPR_new_int(offset),
                        ex_index);
            }
            EXPR_print_tree(ex_index,stdout);
            if ( !EXPR_eval(ex_index, &res) )
                  fatal("Cannot evaluate expression (2)");
            printf(" = %d\n",res);
            EXPR_free(ex_index);
            return res;
      }

}

void fsearch_variable_offset2(SourceLine *l, int start_parm, Expr **res)
{
      Function *f;
      Register *reg1, *reg2, *bp;
      Variable *var;
      int offset, bpoffset, parm, mult, a;
      parm = start_parm+1;

      f = SOURCE_get_function(l);
      bp = FUNCTIONS_get_frame_pointer(f);
      bpoffset = FUNCTIONS_get_frame_size(f);
      
      REGS_flush(REGS_find_or_new("esp"));
      REGS_link(REGS_find("esp"), EXPR_new_int(-bpoffset));
      REGS_flush(bp);
      REGS_link(bp,EXPR_new_int(0));

      // 0xffffffcb, eax, ebp, 1
      // 0xffffffcb, ebp,   0, 1
      // par0        par1 par2 par3

      // OFFSET
      offset = atoi32(get_par(parm));
      mult = atoi32(get_par(parm+3));
      reg1 = NULL; reg2 = NULL;
      if (!is_par("0",parm+1)) {
            reg1 = REGS_find(get_par(parm+1));
            if ( !reg1 ) fatal( "REG Inexistent???" );
      }
      if (!is_par("0",parm+2)) {
            reg2 = REGS_find(get_par(parm+2));
            if ( !reg2 ) fatal( "REG Inexistent???" );
      }

      if ( reg1 && reg2 && mult )
      {
            if ( EXPR_eval(REGS_expr(reg1), &a) ) {
                  Expr *r;

                  offset += a;
                  if ( EXPR_eval(REGS_expr(reg2), &a) ) {
                        offset += a*mult;
                        var = FUNCTIONS_find_var( f, offset, VAR_DWORD );
                        *res = EXPR_new( FUNCTIONS_var_name(var), EXPR_STRING );
                        return;
                  }

                  if ( mult==1 )
                        r = EXPR_copy(REGS_expr(reg2));
                  else
                        r = EXPR_new_linked( 0, EXPR_OP_MULT, EXPR_copy(REGS_expr(reg2)), EXPR_new_int(mult));

                  var = FUNCTIONS_find_var( f, offset, VAR_DWORD );
                  *res = EXPR_new( FUNCTIONS_var_name(var), EXPR_STRING );
                  *res = EXPR_new_sx( NULL, EXPR_OP_ADDRESS, *res ); // &(local1)
                  *res = EXPR_new_linked( NULL, EXPR_OP_SUM, *res, r ); // &(local) + displ
                  *res = EXPR_new_sx( NULL, EXPR_OP_DEREFERENCE, *res ); // *( &(local) + displ )
                  return;
            }

            if ( EXPR_eval(REGS_expr(reg2), &a) ) {
                  offset += a*mult;
                  var = FUNCTIONS_find_var( f, offset, VAR_DWORD );
                  *res = EXPR_new( FUNCTIONS_var_name(var), EXPR_STRING );
                  *res = EXPR_new_sx( NULL, EXPR_OP_ADDRESS, *res ); // &(local1)
                  *res = EXPR_new_linked( NULL, EXPR_OP_SUM, *res, EXPR_copy(REGS_expr(reg1)) ); // &(local) + displ
                  *res = EXPR_new_sx( NULL, EXPR_OP_DEREFERENCE, *res ); // *( &(local) + displ )
                  return;
            }

            *res = EXPR_copy(REGS_expr(reg2));
            *res = EXPR_new_linked( NULL, EXPR_OP_MULT, *res, EXPR_new_int(mult) );
            *res = EXPR_new_linked( NULL, EXPR_OP_SUM, *res, EXPR_copy(REGS_expr(reg1)) );
            *res = EXPR_new_sx( NULL, EXPR_OP_ADDRESS, *res );
            return;
      }

      if ( reg1 ) 
      {
            if ( EXPR_eval(REGS_expr(reg1), &a) ) {
                  offset += a;
                  var = FUNCTIONS_find_var( f, offset, VAR_DWORD );
                  *res = EXPR_new( FUNCTIONS_var_name(var), EXPR_STRING );
                  return;
            }

            *res = EXPR_copy(REGS_expr(reg1));
            return;
      } 

      if ( reg2 && mult )
      {
            if ( EXPR_eval(REGS_expr(reg2), &a) ) {
                  offset += a*mult;
                  var = FUNCTIONS_find_var( f, offset, VAR_DWORD );
                  *res = EXPR_new( FUNCTIONS_var_name(var), EXPR_STRING );
                  return;
            }
            
            if ( mult==1 )
                  *res = EXPR_copy(REGS_expr(reg2));
            else
                  *res = EXPR_new_linked( 0, EXPR_OP_MULT, EXPR_copy(REGS_expr(reg2)), EXPR_new_int(mult));
            return;
      }

      fatal("Strange opcode for memory access...");
}

void fsearch_add_variable( SourceLine *i, int offs )
{
      Function *f;
      f = SOURCE_get_function(i);
      if (offs>0)
      {
            // Function parameter
            FUNCTIONS_find_or_new_argument(f, offs, VAR_DWORD);
      }
      else
      {
            // Function variable
            FUNCTIONS_find_or_new_localvar(f, offs, VAR_DWORD);
      }
}


void fsearch_variable_discovery()
{
      Function *f;
      for ( f=FUNCTIONS_first(); f!=NULL; f=FUNCTIONS_next(f) )
      {
            if (!FUNCTIONS_is_external(f))
                  fsearch_detect_frame_pointer(f);
      }
      
      for (goto_start; !s_eof; next)
      {
            char *opcode;
            int l,offs;

            if ( !SOURCE_get_function(i) )
                  continue;

            opcode = get_op();
            l = strlen(opcode)-2;
            if ( opcode[l]=='-' )
            {
                  // Un parametro
                  if ( opcode[l+1]=='m' )
                  {
                        offs = fsearch_variable_offset(i,0);
                        fsearch_add_variable(i, offs); 
                  }
                  continue;
            }
            l--;
            if ( opcode[l]=='-' )
            {
                  int second;
                  // Due parametri
                  switch (opcode[l+1])
                  {
                        case 'm':
                              offs = fsearch_variable_offset(i,0);
                              fsearch_add_variable(i, offs); 
                              second=4;
                              break;
                        case 'r':
                              second=1;
                              break;
                        default:
                              fatal("Unknown opcode size.");
                  }
                  if ( opcode[l+2]=='m' )
                  {
                        offs = fsearch_variable_offset(i,second);
                        fsearch_add_variable(i, offs); 
                  }
            }
      }
}


void functions_search()
{
      fsearch_load_labels();
      fsearch_detect_functions();

      // Print asm code with Functions in front
      for (goto_start; !s_eof; next)
      {
            Function *f;
            int j;

            f = SOURCE_get_function(i);
            printf("%s\t => %s ", f==NULL? "": FUNCTIONS_name(f), get_op());
            for (j=0; j<SOURCE_get_parm_count(i)-1; j++)
                  printf("%s,", SOURCE_get_parm(i,j));
            printf("%s\n", SOURCE_get_parm(i,j));
      }

      fsearch_variable_discovery();

      FUNCTIONS_sort_arguments();
}


Generated by  Doxygen 1.6.0   Back to index