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

uncc.c

/*
 * 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.
 * 
 */

#include "utils.h"
#include "labels.h"
#include "functions.h"
#include "expressions.h"
#include "registers.h"
#include "stack.h"
#include "source.h"
#include <getopt.h>

#define VERBOSE

Label *Wlabel = NULL;
Function *Wfunction = NULL;
Expr *Wstring = NULL;
Expr *Wcmp_l = NULL, *Wcmp_r = NULL;

void Wcmp_set_l( Expr *e ) {
      if ( Wcmp_l ) EXPR_free( Wcmp_l );
      Wcmp_l=e;
}
void Wcmp_set_r( Expr *e ) {
      if ( Wcmp_r ) EXPR_free( Wcmp_r );
      Wcmp_r=e;
}
Expr *Wcmp_get_l() { return Wcmp_l; }
Expr *Wcmp_get_r() { return Wcmp_r; }


void dump()
{
      printf("DUMP:");
      REGS_dump_all();
}


SourceLine *actual=NULL,*i=NULL;
#define goto_start i=SOURCE_start()
#define next i=SOURCE_next(i)
#define set_mark actual=i
#define goto_mark i=actual
#define is_op(x) SOURCE_is_opcode(i,x)
#define is_par1(x) SOURCE_is_parm(i,x,0)
#define is_par2(x) SOURCE_is_parm(i,x,1)
#define is_par3(x) SOURCE_is_parm(i,x,2)
#define is_par4(x) SOURCE_is_parm(i,x,3)
#define is_par5(x) SOURCE_is_parm(i,x,4)
#define is_par(x,z) SOURCE_is_parm(i,x,z-1)
#define get_op() SOURCE_get_opcode(i)
#define get_par1() SOURCE_get_parm(i,0)
#define get_par2() SOURCE_get_parm(i,1)
#define get_par3() SOURCE_get_parm(i,2)
#define get_par4() SOURCE_get_parm(i,3)
#define get_par5() SOURCE_get_parm(i,4)
#define get_par(x) SOURCE_get_parm(i,x-1)
#define s_eof (i==SOURCE_end())
#define verbose printf

#include "uncc_functions_search.h"

void decompile_function( Function *obj_function, FILE *target )
{

      Label *obj_label;
      Wfunction = obj_function;
      obj_label = FUNCTIONS_get_label(obj_function);

      for ( i=LABELS_source_line(obj_label); 
            SOURCE_get_function(i)==obj_function;
            next )
      {
            if (is_op("label"))
            {
                  Wlabel = LABELS_find(get_par1());
                  verbose("Label '%s' => Working label is now %s\n", get_par1(), get_par1() );
                  if (Wlabel!=obj_label)
                        FUNCTIONS_add_body_line( Wfunction, EXPR_new(get_par1(), EXPR_LABEL) );
            }
            else if (is_op("String"))
            {
                  if (Wstring) EXPR_free(Wstring);
                  Wstring = EXPR_new( get_par1(), EXPR_STRING );
                  verbose("String %s => Use this string for next operation\n", get_par1());
            }
            else if (is_op("movl-ri"))
            {
                  Register *r;
                  Expr *e;
                  r = REGS_find_or_new( get_par1() );
                  REGS_flush( r );
                  e = EXPR_new_int( atoi32(get_par2()) );
                  REGS_link( r, e );
                  verbose("movl %s,%s => Generate new tree for %s\n", get_par1(), get_par2(), get_par1());
            }
            else if (is_op("subl-rr"))
            {
                  Register *r1, *r2;
                  Expr *e;
                  r1 = REGS_find_or_new( get_par1() );
                  r2 = REGS_find_or_new( get_par2() );
                  e = EXPR_new_linked( NULL, EXPR_OP_SUB, REGS_expr(r1), EXPR_copy(REGS_expr(r2)));
                  REGS_link( r1, e );
                  verbose("subl %s,%s => Temporary register operation. Update tree for %s\n", get_par1(), get_par2(), get_par1() );
            }
            else if (is_op("movl-mi"))
            {
                  Expr *e, *f, *r;
                  r = EXPR_new_int( atoi32(get_par5()) );
                  fsearch_variable_offset2(i,0,&f);
                  e = EXPR_new_linked( NULL, EXPR_OP_ASSIGN, f, r);
                  FUNCTIONS_add_body_line( Wfunction, e );
                  verbose( "movl ... ,%s => Assignment.\n", get_par5() );
            }
            else if (is_op("movl-rr"))
            {
                  Register *r1, *r2;
                  r1 = REGS_find_or_new( get_par1() );
                  r2 = REGS_find_or_new( get_par2() );
                  REGS_flush( r1 );
                  REGS_link( r1, EXPR_copy(REGS_expr(r2)) );
                  verbose( "movl %s,%s => Temporary register operation. ", get_par1(), get_par2() );
                  verbose( "Create new tree for %s with %s\n", get_par1(), get_par2() );
            }
            else if (is_op("movl-rm"))
            {
                  Register *r;
                  Expr *f;
                  r = REGS_find_or_new( get_par1() );
                  REGS_flush(r);
                  fsearch_variable_offset2(i,1,&f);
                  REGS_link( r, f );
                  verbose( "movl %s, ... => Temporary register. ", get_par1());
                  verbose( "Create new tree for %s\n", get_par1() );
            }
            else if (is_op("movl-mr"))
            {
                  Register *reg;
                  Expr *e, *f, *r;
                  reg = REGS_find_or_new(get_par5());
                  r = EXPR_copy(REGS_expr(reg));
                  fsearch_variable_offset2(i,0,&f);
                  e = EXPR_new_linked( NULL, EXPR_OP_ASSIGN, f, r);
                  FUNCTIONS_add_body_line( Wfunction, e );
                  verbose( "movl ... ,%s => Assignment. ", get_par5() );
            }
            else if (is_op("addl-ri") || is_op("addb-ri") || is_op("addw-ri"))
            {
                  Register *r;
                  Expr *e, *f;
                  r = REGS_find_or_new(get_par1());
                  e = EXPR_new_int( atoi32(get_par2()) );
                  f = EXPR_new_linked( NULL, EXPR_OP_SUM, REGS_expr(r), e );
                  REGS_link( r, f);
                  verbose("addl %s,%s => Temporary register operation. Update tree for %s\n", get_par1(), get_par2(), get_par1() );
            }
            else if (is_op("addl-rm") || is_op("addb-rm") || is_op("addw-rm"))
            {
                  Register *r;
                  Variable *var;
                  Expr *f;
                  r = REGS_find_or_new( get_par1() );
                  fsearch_variable_offset2(i,1,&f);
                  f = EXPR_new_linked( NULL, EXPR_OP_SUM, REGS_expr(r), f );
                  REGS_link( r, f );
                  verbose( "addl %s, ... => Temporary register operation. ", get_par1());
                  verbose( "Update tree for %s, adding %s\n", get_par1(), FUNCTIONS_var_name(var) );
            }
            else if (is_op("addl-rr") || is_op("addb-rr") || is_op("addw-rr"))
            {
                  Register *r1, *r2;
                  r1 = REGS_find_or_new(get_par1());
                  r2 = REGS_find_or_new(get_par2());
                  REGS_link(
                        r1, 
                        EXPR_new_linked( NULL, EXPR_OP_SUM, 
                              REGS_expr(r1), 
                              EXPR_copy(REGS_expr(r2))
                        )
                  );
                  verbose("addl %s,%s => Temporary register operation. Update tree for %s\n", get_par1(), get_par2(), get_par1() );
            }
            else if (is_op("subl-ri") || is_op("subb-ri") || is_op("subw-ri"))
            {
                  Register *r;
                  r = REGS_find_or_new( get_par1() );
                  REGS_link( 
                        r,
                        EXPR_new_linked( NULL, EXPR_OP_SUB,
                              REGS_expr(r),
                              EXPR_new_int(atoi32(get_par2()))
                        )
                  );
                  verbose("subl %s,%s => Temporary register operation. Update tree for %s\n", get_par1(), get_par2(), get_par1() );
            }
            else if (is_op("incl-m"))
            {
                  Expr *e, *f;
                  fsearch_variable_offset2(i,0,&f);
                  e = EXPR_new_sx( NULL, EXPR_OP_INC, f );
                  FUNCTIONS_add_body_line( Wfunction, e );
                  verbose( "inc ... => Dereferenced increment." );
            }
            else if (is_op("andl-ri") || is_op("andb-ri") || is_op("andw-ri"))
            {
                  Register *r;
                  Expr *e, *f;
                  r = REGS_find_or_new( get_par1() );
                  e = EXPR_new_int( atoi32(get_par2()) );
                  f = EXPR_new_linked( NULL, EXPR_OP_AND, REGS_expr(r), e );
                  REGS_link( r, f );
                  verbose("andl %s,%s => Temporary register operation. Update tree for %s\n", get_par1(), get_par2(), get_par1() );
            }
            
            else if (is_op("cmpl-mi") || is_op("cmpb-mi") || is_op("cmpw-mi"))
            {
                  Expr *f;
                  fsearch_variable_offset2(i,0,&f);
                  Wcmp_set_l( f );
                  Wcmp_set_r( EXPR_new_int( atoi32(get_par5()) ) );
                  verbose("cmp ...,%s => Saved compare operands pair (...,%s)\n", get_par5(), get_par5() );
            }
            
            else if (is_op("je-d") || is_op("jz-d"))
            {
                  Expr *e;
                  Label *l;
                  l = LABELS_find(get_par1());
                  e = EXPR_new_linked( 0, EXPR_OP_EQUAL, EXPR_copy(Wcmp_get_l()), EXPR_copy(Wcmp_get_r()) );
                  e = EXPR_new_linked( 0, EXPR_IF, e, EXPR_new( LABELS_name(l), EXPR_STRING ) );
                  FUNCTIONS_add_body_line( Wfunction, e );
                  verbose("jne %s => Generating if line with condition !=\n", LABELS_name(l));
            }
            else if (is_op("jne-d") || is_op("jnz-d"))
            {
                  Expr *e;
                  Label *l;
                  l = LABELS_find(get_par1());
                  e = EXPR_new_linked( 0, EXPR_OP_NOT_EQUAL, EXPR_copy(Wcmp_get_l()), EXPR_copy(Wcmp_get_r()) );
                  e = EXPR_new_linked( 0, EXPR_IF, e, EXPR_new( LABELS_name(l), EXPR_STRING ) );
                  FUNCTIONS_add_body_line( Wfunction, e );
                  verbose("jne %s => Generating if line with condition !=\n", LABELS_name(l));
            }
            else if (is_op("jle-d") || is_op("jbe-d"))
            {
                  Expr *e;
                  Label *l;
                  l = LABELS_find(get_par1());
                  e = EXPR_new_linked( 0, EXPR_OP_LESS_EQUAL, EXPR_copy(Wcmp_get_l()), EXPR_copy(Wcmp_get_r()) );
                  e = EXPR_new_linked( 0, EXPR_IF, e, EXPR_new( LABELS_name(l), EXPR_STRING ) );
                  FUNCTIONS_add_body_line( Wfunction, e );
                  //
                  verbose("jne %s => Generating if line with condition <=\n", LABELS_name(l));
            }
            else if (is_op("jmp-d"))
            {
                  Expr *e;
                  Label *l;
                  l = LABELS_find(get_par1());
                  e = EXPR_new( LABELS_name(l), EXPR_GOTO );
                  FUNCTIONS_add_body_line( Wfunction, e );
                  //
                  verbose("jmp %s => Generating goto\n", LABELS_name(l));
            }
                  
            else if (is_op("pushl-i") || is_op("pushb-i") || is_op("pushw-i"))
            {
                  if (Wstring)
                  {
                        STACK_push(Wstring);
                        verbose("pushl %s => Pushing %s into stack\n", get_par1(), get_par1() );
                        Wstring=NULL;
                  }
                  else
                  {
                        Expr *e;
                        e = EXPR_new_int( atoi32(get_par1()) );
                        STACK_push(e);
                        verbose("pushl %s => Pushing %s into stack\n", get_par1(), get_par1() );
                  }
            }
            else if (is_op("pushl-r") || is_op("pushb-r") || is_op("pushw-r"))
            {
                  Register *r;
                  r = REGS_find_or_new(get_par1());
                  if (FUNCTIONS_get_frame_pointer(Wfunction) == r)
                        verbose( "pushl %s => Ignoring framepointer operations\n", get_par1() );
                  else
                  {
                        STACK_push(EXPR_copy(REGS_expr(r)));
                        //
                        verbose( "pushl %s => Pushing %s tree into stack\n", get_par1(), get_par1() );
                  }
            }
            else if (is_op("pushl-m") || is_op("pushb-m") || is_op("pushw-m"))
            {
                  Expr *e;
                  fsearch_variable_offset2(i,0,&e);
                  STACK_push(e);
                  verbose("pushl ... => Pushing into stack\n" );
            }
            else if (is_op("call-d"))
            {
                  Expr *ris, *e, *g;
                  Function *f;
                  Register *r;
                  int n,m;

                  f = FUNCTIONS_find_from_label(LABELS_find(get_par1()));
                  n = FUNCTIONS_count_arguments(f);
                  e = EXPR_new( FUNCTIONS_name(f), EXPR_STRING );
                  ris = e = EXPR_new_sx( "( ", EXPR_STRING, e );
                  for (m=0; m<n; m++)
                  {
                        if ( m<n-1 )
                              g = EXPR_new_sx( ", ", EXPR_STRING, STACK_pop() );
                        else
                              g = STACK_pop();

                        EXPR_link_dx(e,g);
                        e = g;
                  }
                  
                  EXPR_link_dx(e,EXPR_new( " )", EXPR_STRING ));
                  r = REGS_find_or_new("eax");
                  REGS_flush(r);
                  REGS_link(r,ris);
                  REGS_drop_to(r,Wfunction);
                  verbose("call => Generated call function taking argument from stack\n");
            }
            else if (is_op("leal-rm"))
            {
                  Register *r;
                  Expr *f;
                  r = REGS_find_or_new( get_par1() );
                  fsearch_variable_offset2(i,1,&f);
                  REGS_flush(r);
                  REGS_link(r,f);
                  verbose("leal %s, ... => Creating pointer address in %s\n", get_par1(), get_par1());
            }
            else if (is_op("leave"))
            {
                  verbose("leave => Ignored\n");
            }
            else if (is_op("ret"))
            {
                  Register *r;
                  Expr *e, *f;
                  r = REGS_find_or_new("eax");
                  e = EXPR_new( "return ", EXPR_STRING );
                  f = EXPR_new_linked( "", EXPR_STRING, e, EXPR_copy(REGS_expr(r)));
                  FUNCTIONS_add_body_line( Wfunction, f );
                  verbose("ret => Function exit. Generating return command\n");
            }
            else
            {
                  printf( "Unknown command '%s'!\n", get_op() ); 
                  return;
            }
            //REGS_dump_all();
      }
}

void decompile( FILE *target )
{
      Function *f;
      for ( f=FUNCTIONS_first(); f!=NULL; f=FUNCTIONS_next(f) )
            if (!FUNCTIONS_is_external(f))
                  decompile_function(f,target);
}

void render()
{
      FUNCTIONS_print(stdout);
}

void usage()
{
      fprintf(stderr, "Usage: uncc [-h] <file.dasm>\n\n");
      exit(0);
}

int main( int argc, char **argv )
{
      char *target_filename;
      FILE *target;
      static int opt_help = 0;

            while (1) {
            int c;
            int option_index = 0;
            static struct option long_options[] = {
                  {"help", 0, &opt_help, 1},
                  {0, 0, 0, 0}
            };

            c = getopt_long (argc, argv, "h", long_options, &option_index);
            if (c == -1)
                  break;
                        
            switch (c) {
                  case 0:
                        //printf ("option %s", long_options[option_index].name);
                        //if (optarg) printf (" with arg %s", optarg);
                        //printf ("\n");
                        break;
                  case 'h': 
                        opt_help=1; 
                        break;
                  case '?': 
                        exit(1); 
                        break;
                  default:
                        printf ("?? getopt returned code 0%o ??\n", c);
                        exit(1);
            }
            }

      if ( opt_help || argc-optind!=1 )
            usage();

      target_filename = argv[optind];
      target = fopen( target_filename, "r" );
      if (!target)
            fatal("Error opening file %s.", target_filename );

      SOURCE_load(target);
      functions_search(target);

      decompile(target);

      render();
      return 0;
}


Generated by  Doxygen 1.6.0   Back to index