[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/clayne/patchdiff2/master/pgraph.cpp [Back]  [Original]

/*
   Patchdiff2
   Portions (C) 2010 - 2011 Nicolas Pouvesle
   Portions (C) 2007 - 2009 Tenable Network Security, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2 as
   published by the Free Software Foundation.

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

#include "precomp.h"

#include "pgraph.h"
#include "sig.h"
#include "diff.h"
#include "actions.h"

#ifndef WOPN_MENU
#define WOPN_MENU 0
#endif

#if IDA_SDK_VERSION >= 700
typedef qlist siginfo_list_t;
static siginfo_list_t instances;

static slist_t *find_slist(graph_viewer_t *gv) {
   for (siginfo_list_t::iterator i = instances.begin(); i != instances.end(); i++) {
      if ((*i)->gv == gv) {
         return *i;
      }
   }
   return NULL;
}

static void add_slist(slist_t *sl) {
   instances.push_back(sl);
}

static bool remove_slist(slist_t *sl) {
   for (siginfo_list_t::iterator i = instances.begin(); i != instances.end(); i++) {
      if (*i == sl) {
         instances.erase(i);
         return true;
      }
   }
   return false;
}
#endif

static int find_node(slist_t *sl, ea_t ea) {
   size_t i;
   for (i = 0; i < sl->num; i++) {
      if (sl->sigs[i]->startEA == ea) {
         return i;
      }
   }
   return -1;
}

/*------------------------------------------------*/
/* function : menu_callback                       */
/* description: Menu callback                     */
/*------------------------------------------------*/

static bool idaapi menu_callback(void *ud) {
   int node;
   slist_t *sl = (slist_t *)ud;

   if (sl && sl->sigs && sl->sigs[0]->nfile == 1) {
      node = viewer_get_curnode(sl->gv);
      if (node >= 0) {
         jumpto(sl->sigs[node]->startEA);
      }
   }

   return true;
}

/*------------------------------------------------*/
/* function : graph_callback                      */
/* description: Graph callback                    */
/*------------------------------------------------*/
#if IDA_SDK_VERSION < 700
static int idaapi graph_callback(void *ud, int code, va_list va) {
#else
static ssize_t idaapi graph_callback(void *ud, int code, va_list va) {
#endif
   int result = 0;

   switch ( code ) {
   case grcode_layout_calculated: {
         mutable_graph_t *g = va_arg(va, mutable_graph_t *);
         slist_t *sl = (slist_t *)ud;

         if (sl->num != g->size()) {
            warning("Graph layout is too complex to be displayed.\n");
            g->reset();
         }
      }
      break;
#if IDA_SDK_VERSION < 740
   case grcode_changed_current: {
         graph_viewer_t *v   = va_arg (va, graph_viewer_t *);
         int node         = va_arg(va, int);

         if (node != -1) {
            slist_t *sl = (slist_t *)ud;
            sl->dclk = true;
         }
      }
      break;
#endif
   case grcode_clicked: {
         slist_t *sl = (slist_t *)ud;
         sl->dclk = false;
      }
      break;

   case grcode_dblclicked: {
         graph_viewer_t *v   = va_arg(va, graph_viewer_t *);
         selection_item_t *s = va_arg(va, selection_item_t *);
         slist_t *sl = (slist_t *)ud;

         if ( s && s->is_node) {
            viewer_center_on(v, s->node);

            if (sl->sigs[s->node]->msig != NULL && sl->msl->gv != NULL) {
               viewer_center_on(sl->msl->gv, find_node(sl->msl, sl->sigs[s->node]->matchedEA));
            }
            sl->dclk = false;
         }
         else if ( sl->dclk || s ) {
            int node;

            node = viewer_get_curnode(v);

            if (sl->sigs[node]->msig != NULL && sl->msl->gv != NULL) {
               viewer_center_on(sl->msl->gv, find_node(sl->msl, sl->sigs[node]->matchedEA));
            }
            sl->dclk = false;
         }
      }
      break;

   case grcode_user_refresh: {
         mutable_graph_t *g = va_arg(va, mutable_graph_t *);
         slist_t *sl = (slist_t *)ud;

         if ( g->empty() ) {
            g->resize(sl->num);
         }
         for (size_t i = 0; i< sl->num; i++) {
            fref_t *fref;

            if (sl->sigs[i]->srefs) {
               fref = sl->sigs[i]->srefs->list;
               while(fref) {
                  int pos = find_node(sl, fref->ea);

                  if (pos != -1) {
                     edge_info_t ed;
                     if (fref->type == 3) {
                        ed.color = 0xff0000;
                     }
                     else if (fref->type == 2) {
                        ed.color = 0x0000ff;
                     }
                     else {
                        ed.color = 0x006400;
                     }
                     g->add_edge(i, pos, &ed);
                  }

                  fref = fref->next;
               }
            }
         }

         result = 1;
      }
      break;

   case grcode_user_text: {
         mutable_graph_t *g = va_arg(va, mutable_graph_t *);
         int node           = va_arg(va, int);
         const char **text  = va_arg(va, const char **);
         bgcolor_t *bgcolor = va_arg(va, bgcolor_t *);

         slist_t *sl = (slist_t *)ud;

         *text = sl->sigs[node]->dl.lines;

         if ( bgcolor != NULL ) {
            *bgcolor = 0xFFFFFFFF;

            if (!sl->unique) {
               if (sl->sigs[node]->mtype == DIFF_UNMATCHED) {
                  *bgcolor = 0xcccccc;
               }
               else if (sl->sigs[node]->sig != sl->sigs[node]->msig->sig) {
                  *bgcolor = 0x33cc;
               }
               else if (sl->sigs[node]->id_crc) {
                  *bgcolor = 0x8cb4d2;
               }
            }
         }
         result = 1;
         qnotused(g);
      }
      break;

   case grcode_destroyed: {
         slist_t *sl = (slist_t *)ud;
         sl->gv = NULL;
#if IDA_SDK_VERSION >= 700
         remove_slist(sl);
#endif
      }
      break;
   }

   return result;
}

#if IDA_SDK_VERSION >= 700
//-------------------------------------------------------------------------
int idaapi pgraph_action_handler_t::activate(action_activation_ctx_t *ctx) {
   slist_t *sl = find_slist((graph_viewer_t *) ctx->widget);
   menu_callback(sl);
   return 0;
}

action_state_t idaapi pgraph_action_handler_t::update(action_update_ctx_t *ctx) {
   return find_slist((graph_viewer_t *) ctx->widget) != NULL
            ? AST_ENABLE_FOR_WIDGET
            : AST_DISABLE_FOR_WIDGET;
}

#endif

template
void create_form_name(char (&dst)[len], slist_t *sl, int num) {
   qsnprintf(dst, len, "IDB%d: %s", num, sl->sigs[0]->name.c_str());
}

#if IDA_SDK_VERSION < 730
#define WOPN_DP_TAB WOPN_TAB
#endif

/*------------------------------------------------*/
/* function : pgraph_create                       */
/* description: Creates s function graph          */
/* returns: true if the form was newly created    */
/*------------------------------------------------*/

#if IDA_SDK_VERSION < 700
static bool pgraph_create(slist_t *sl, int num) {
   char form_name[512];
   char node_name[512];
   TForm *form;
   bool form_is_new = true;

   create_form_name(form_name, sl, num);
   qsnprintf(node_name, sizeof(node_name), "$ %s", form_name);

   form = find_tform(form_name);

   netnode id;
   bool already_existed = !id.create(node_name);
   if (form && already_existed) {
      form_is_new = false;
      switchto_tform(form, true);
      sl->gv = get_graph_viewer(form);
   }
   else {
      HWND hwnd = NULL;
      form = create_tform(form_name, &hwnd);
      if (hwnd) {     //hwnd is non-null only when form did not previously exist
         sl->gv = create_graph_viewer(form, id, graph_callback, sl, 0);
         open_tform(form, FORM_TAB | FORM_MENU | FORM_QWIDGET);
         if (sl->gv) {
            viewer_fit_window(sl->gv);
            viewer_add_menu_item(sl->gv, "Jump to code", menu_callback, sl, NULL, 0);
         }
      }
   }
   return form_is_new;
}
#else   // >= IDA 7.0
static bool pgraph_create(slist_t *sl, int num) {
   char widget_name[512];
   char node_name[512];
   TWidget *widget;
   bool widget_is_new = true;

   create_form_name(widget_name, sl, num);
   qsnprintf(node_name, sizeof(node_name), "$ %s", widget_name);

   widget = find_widget(widget_name);

   netnode id;
   bool already_existed = !id.create(node_name);
   if (widget && already_existed) {
      widget_is_new = false;
      activate_widget(widget, true);
      sl->gv = get_graph_viewer(widget);
   }
   else {
      widget = create_empty_widget(widget_name);
      if (widget) {                 //maybe testing widget is fine in both cases?
         sl->gv = create_graph_viewer(widget_name, id, graph_callback, sl, 0, widget);
         add_slist(sl);
         display_widget(widget, WOPN_DP_TAB | WOPN_MENU);
         if (sl->gv) {
            viewer_fit_window(sl->gv);
            viewer_attach_menu_item(sl->gv, PGRAPH_NAME);
         }
      }
   }
   return widget_is_new;
}
#endif

/*------------------------------------------------*/
/* function : pgraph_display                      */
/* description: Displays function graph           */
/*------------------------------------------------*/

void pgraph_display(slist_t *sl1, slist_t *sl2) {
   graph_viewer_t *gv = NULL;

   sl1->msl = sl2;
   sl2->msl = sl1;

   sl1->unique = sl2->unique = false;

   bool sl1_new_form = pgraph_create(sl1, 1);
   bool sl2_new_form = pgraph_create(sl2, 2);
   if ((sl1_new_form || sl2_new_form) && sl1->gv && sl2->gv) {
      // Only perform the docking for forms that were just created
      char buf[512], buf2[512];
      create_form_name(buf, sl1, 1);
      create_form_name(buf2, sl2, 2);
      set_dock_pos(buf2, buf, DP_RIGHT);
   }
}

void pgraph_display_one(slist_t *sl) {
   sl->msl = NULL;
   sl->unique = true;

   pgraph_create(sl, sl->sigs[0]->nfile);
}

Web Proxy Viewer  |  New URL  |  Original Page