[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/idkwim/patchdiff2/master/display.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.hpp"

#include "diff.hpp"
#include "display.hpp"
#include "os.hpp"
#include "parser.hpp"
#include "pgraph.hpp"
#include "options.hpp"
#include "system.hpp"


static uint32 idaapi sizer_dlist(slist_t *sl)
{
	if (sl)
		return sl->num;

	return 0;
}


static uint32 idaapi sizer_match(void *obj)
{
	deng_t * d = (deng_t *)obj;

	return sizer_dlist(d ? d->mlist : NULL);
}


static uint32 idaapi sizer_identical(void *obj)
{
	deng_t * d = (deng_t *)obj;

	return sizer_dlist(d ? d->ilist : NULL);
}


static uint32 idaapi sizer_unmatch(void *obj)
{
	deng_t * d = (deng_t *)obj;

	return sizer_dlist(d ? d->ulist : NULL);
}


static void idaapi close_window(void *obj)
{
	deng_t * d = (deng_t *)obj;

	d->wnum--;
	if (!d->wnum)
		ipc_close();

	return;
}


/*------------------------------------------------*/
/* function : ui_access_sig                       */
/* description: Compensates for the zero index    */
/*         indicating the header row and performs */
/*         bounds checking in debug               */
/*------------------------------------------------*/

static psig_t *ui_access_sig(slist_t *sl, uint32 n)
{
#ifdef _DEBUG
	if (!sl || n == 0 || n > sl->num)
		error("ui attempted to access siglist out-of-bounds: %p %x\n", sl, n - 1);
	else
#endif
		return sl->sigs[n - 1];
}


static void idaapi desc_dlist(slist_t * sl,uint32 n,char * const *arrptr)
{
	int i;

	/* header */
	if (n == 0)
	{
		for (i = 0; i < qnumber (header_match); i++)
			qsnprintf(arrptr[i], MAXSTR, "%s", header_match[i]);
	}
	else
	{
		psig_t *sig = ui_access_sig(sl, n);
		qsnprintf(arrptr[0], MAXSTR, "%u", sig->mtype);
		qsnprintf(arrptr[1], MAXSTR, "%s", sig->name);
		qsnprintf(arrptr[2], MAXSTR, "%s", sig->msig->name);
		qsnprintf(arrptr[3], MAXSTR, "%" PRIea_t, sig->startEA);
		qsnprintf(arrptr[4], MAXSTR, "%" PRIea_t, sig->msig->startEA);
		qsnprintf(arrptr[5], MAXSTR, "%c", sig->id_crc ? '+' : '-');
		qsnprintf(arrptr[6], MAXSTR, "%lx", sig->crc_hash);
		qsnprintf(arrptr[7], MAXSTR, "%lx", sig->msig->crc_hash);
	}
}


/*------------------------------------------------*/
/* function : desc_match                          */
/* description: Fills matched list                */
/*------------------------------------------------*/

static void idaapi desc_match(void *obj,uint32 n,char * const *arrptr)
{
	deng_t * d = (deng_t *)obj;

	desc_dlist(d ? d->mlist : NULL, n, arrptr);
}


/*------------------------------------------------*/
/* function : desc_identical                      */
/* description: Fills identical list              */
/*------------------------------------------------*/

static void idaapi desc_identical(void *obj,uint32 n,char * const *arrptr)
{
	deng_t * d = (deng_t *)obj;

	desc_dlist(d ? d->ilist : NULL, n, arrptr);
}


/*------------------------------------------------*/
/* function : desc_unmatch                        */
/* description: Fills unmatched list              */
/*------------------------------------------------*/

static void idaapi desc_unmatch(void *obj,uint32 n,char * const *arrptr)
{
	int i;

	/* header */
	if (n == 0)
	{
		for (i = 0; i < qnumber (header_unmatch); i++)
			qsnprintf(arrptr[i], MAXSTR, "%s", header_unmatch[i]);
	}
	else
	{
		psig_t *sig = ui_access_sig(((deng_t *)obj)->ulist, n);
		qsnprintf(arrptr[0], MAXSTR, "%u", sig->nfile);
		qsnprintf(arrptr[1], MAXSTR, "%s", sig->name);
		qsnprintf(arrptr[2], MAXSTR, "%" PRIea_t, sig->startEA);
		qsnprintf(arrptr[3], MAXSTR, "%.8lX", sig->sig);
		qsnprintf(arrptr[4], MAXSTR, "%.8lX", sig->hash);
		qsnprintf(arrptr[5], MAXSTR, "%.8lX", sig->crc_hash);
	}
}


static void idaapi enter_list(slist_t * sl,uint32 n)
{
	jumpto(ui_access_sig(sl, n)->startEA);
	os_copy_to_clipboard(NULL);
}


/*------------------------------------------------*/
/* function : enter_match                         */
/* description: Jumps to code for element n in    */
/*              matched list                      */
/*------------------------------------------------*/

static void idaapi enter_match(void *obj,uint32 n)
{
	enter_list(((deng_t *)obj)->mlist, n);
}


/*------------------------------------------------*/
/* function : enter_match                         */
/* description: Jumps to code for element n in    */
/*              identical list                    */
/*------------------------------------------------*/

static void idaapi enter_identical(void *obj,uint32 n)
{
	enter_list(((deng_t *)obj)->ilist, n);
}


/*------------------------------------------------*/
/* function : enter_match                         */
/* description: Jumps to code for element n in    */
/*              unmatched list                    */
/*------------------------------------------------*/

static void idaapi enter_unmatch(void *obj,uint32 n)
{
	psig_t *sig = ui_access_sig(((deng_t *)obj)->ulist, n);

	if (sig->nfile == 1)
		jumpto(sig->startEA);
	else
		os_copy_to_clipboard(NULL);
}


static uint32 idaapi graph_list(slist_t * sl,uint32 n, options_t * opt)
{
	slist_t * sl1 = NULL;
	slist_t * sl2 = NULL;

	msg ("parsing second function...\n");
	sl2 = parse_second_fct(ui_access_sig(sl, n)->msig->startEA, sl->file, opt);
	if (!sl2)
	{
		msg("Error: FCT2 parsing failed.\n");
		return 0;
	}

	msg ("parsing first function...\n");
	sl1 = parse_fct(ui_access_sig(sl, n)->startEA, dto.graph.s_showpref);
	if (!sl1)
	{
		msg("Error: FCT1 parsing failed.\n");
		siglist_free(sl2);
		return 0;
	}

	sl1->sigs[0]->nfile = 1;
	sl2->sigs[0]->nfile = 2;

	msg ("diffing functions...\n");
	generate_diff(NULL, sl1, sl2, NULL, false, NULL);

	pgraph_display(sl1, sl2);

	msg ("done!\n");
	return 1;
}


/*------------------------------------------------*/
/* function : graph_match                         */
/* description: Draws graph from element n in     */
/*              matched list                      */
/*------------------------------------------------*/

static void idaapi graph_match(void *obj,uint32 n)
{
	slist_t * sl = ((deng_t *)obj)->mlist;
	options_t * opt = ((deng_t *)obj)->opt;

	graph_list(sl, n, opt);

	return;
}


/*------------------------------------------------*/
/* function : graph_identical                     */
/* description: Draws graph from element n in     */
/*              identical list                    */
/*------------------------------------------------*/

static void idaapi graph_identical(void *obj,uint32 n)
{
	slist_t * sl = ((deng_t *)obj)->ilist;
	options_t * opt = ((deng_t *)obj)->opt;

	graph_list(sl, n, opt);

	return;
}


/*------------------------------------------------*/
/* function : graph_unmatch                       */
/* description: Draws graph from element n in     */
/*              unmatched list                    */
/*------------------------------------------------*/

static void idaapi graph_unmatch(void *obj,uint32 n)
{
	slist_t * sl = NULL, * tmp = ((deng_t *)obj)->ulist;

	if (ui_access_sig(tmp, n)->nfile == 2)
	{
		msg ("parsing second function...\n");
		sl = parse_second_fct(ui_access_sig(tmp, n)->startEA, tmp->file, ((deng_t *)obj)->opt);
		if (!sl)
		{
			msg("Error: FCT2 parsing failed.\n");
			return;
		}

		sl->sigs[0]->nfile = 2;
	}
	else
	{
		msg ("parsing first function...\n");
		sl = parse_fct(ui_access_sig(tmp, n)->startEA, dto.graph.s_showpref);
		if (!sl)
		{
			msg("Error: FCT1 parsing failed.\n");
			return;
		}

		sl->sigs[0]->nfile = 1;
	}

	pgraph_display_one(sl);

	msg ("done!\n");
	return;
}


static uint32 idaapi res_unmatch(deng_t * d,uint32 n, int type)
{
	slist_t * sl;

	if (type == 0)
		sl = d->ilist;
	else
		sl = d->mlist;

	psig_t *sig = ui_access_sig(sl, n);
	
	sig->nfile = 1;
	sig->msig->nfile = 2;

	siglist_add(d->ulist, sig);
	siglist_add(d->ulist, sig->msig);

	sig->msig->msig = NULL;
	sig->msig = NULL;

	siglist_remove(sl, n - 1);

	refresh_chooser(title_unmatch);

	return 1;
}


/*------------------------------------------------*/
/* function : res_iunmatch                        */
/* description: Unmatches element n from identical*/
/*              list                              */
/*------------------------------------------------*/

static uint32 idaapi res_iunmatch(void *obj,uint32 n)
{
	return res_unmatch((deng_t *)obj, n, 0);
}


/*------------------------------------------------*/
/* function : res_munmatch                        */
/* description: Unmatches element n from matched  */
/*              list                              */
/*------------------------------------------------*/

static uint32 idaapi res_munmatch(void *obj,uint32 n)
{
	return res_unmatch((deng_t *)obj, n, 1);
}


/*------------------------------------------------*/
/* function : propagate_match                     */
/* description: Propagates new matched result if  */
/*              option is set in dialog box       */
/*------------------------------------------------*/

void propagate_match(deng_t * eng, psig_t * s1, psig_t * s2, int options)
{
	size_t i;
	deng_t * d = NULL;
	slist_t * l1, * l2;

	if (options)
	{
		show_wait_box ("PatchDiff is in progress ...");

		l1 = siglist_init(eng->ulist->num, eng->ulist->file);
		l2 = siglist_init(eng->ulist->num, eng->ulist->file);

		for (i=0; iulist->num; i++)
			if (!eng->ulist->sigs[i]->msig)
			{
				if (eng->ulist->sigs[i]->nfile == 1)
					siglist_add(l1, eng->ulist->sigs[i]);
				else
					siglist_add(l2, eng->ulist->sigs[i]);
			}

		generate_diff(&d, l1, l2, eng->ulist->file, false, NULL);

		siglist_partial_free(l1);
		siglist_partial_free(l2);

		hide_wait_box();
	}

	i = 0;
	while (iulist->num)
	{
		s1 = eng->ulist->sigs[i];
		s2 = s1->msig;

		if (!s2) 
			i++;
		else
		{
			if (s1->nfile == 1)
			{
				if (sig_equal(s1, s2, DIFF_EQUAL_SIG_HASH))
					siglist_add(eng->ilist, s1);
				else
					siglist_add(eng->mlist, s1);
			}

			siglist_remove(eng->ulist, i);
		}
	}
}


/*------------------------------------------------*/
/* function : res_match                           */
/* description: Matches 2 elements from unmatched */
/*              list                              */
/*------------------------------------------------*/

static uint32 idaapi res_match(void *obj,uint32 n)
{
	deng_t * eng = (deng_t *)obj;
	psig_t * s1, * s2;
	int option;
	ea_t ea = BADADDR;
	size_t i;

	const char format[] =
			"STARTITEM 0\n"

			"Set Match\n"
			"\n\n"

			"Options :\n" 
			">\n\n"
			;

	option = 1;
	if (AskUsingForm_c(format, &ea, &option))
	{
		s1 = ui_access_sig(eng->ulist, n);

		for (i=0; iulist->num; i++)
		{
			s2 = eng->ulist->sigs[i];

			if (s2->startEA != ea || (s2->nfile == s1->nfile))
				continue;

			sig_set_matched_sig(s1, s2, DIFF_MANUAL);
			propagate_match(eng, s1, s2, option);

			refresh_chooser(title_match);
			refresh_chooser(title_identical);

			return 1;
		}

		warning("Address '%" PRIea_t "' is not valid.", ea);
		return 0;
	}

	return 1;
}


/*------------------------------------------------*/
/* function : res_mtoi                            */
/* description: Switches element n from matched   */
/*              to identical list                 */
/*------------------------------------------------*/

static uint32 idaapi res_mtoi(void *obj,uint32 n)
{
	deng_t * d = (deng_t *)obj;
	psig_t *sig = ui_access_sig(d->mlist, n);

	sig->mtype = sig->msig->mtype = DIFF_MANUAL;

	siglist_add(d->ilist, sig);
	siglist_remove(d->mlist, n - 1);

	refresh_chooser(title_identical);

	return 1;
}


/*------------------------------------------------*/
/* function : res_itom                            */
/* description: Switches element n from identical */
/*              to matched list                   */
/*------------------------------------------------*/

static uint32 idaapi res_itom(void *obj,uint32 n)
{
	deng_t * d = (deng_t *)obj;
	psig_t *sig = ui_access_sig(d->ilist, n);

	sig->mtype = sig->msig->mtype = DIFF_MANUAL;

	siglist_add(d->mlist, sig);
	siglist_remove(d->ilist, n - 1);

	refresh_chooser(title_match);

	return 1;
}


/*------------------------------------------------*/
/* function : res_flagged                         */
/* description: Sets element as flagged/unflagged */
/*------------------------------------------------*/

static uint32 idaapi res_flagged(void *obj,uint32 n)
{
	psig_t *sig = ui_access_sig(((deng_t *)obj)->mlist, n);

	sig->flag = !sig->flag;

	refresh_chooser(title_match);

	return 1;
}


static void transfer_sym(psig_t *sig)
{
	psig_t *rhs = sig->msig;
	sig_set_name(sig, rhs->name);
	set_name(sig->startEA, rhs->name, SN_NOCHECK | SN_NON_AUTO);
}


static uint32 idaapi transfer_sym_match(void *obj, uint32 n)
{
	psig_t *sig = ui_access_sig(((deng_t *)obj)->mlist, n);

	transfer_sym(sig);

	return 1;
}


static uint32 idaapi transfer_sym_identical(void *obj, uint32 n)
{
	psig_t *sig = ui_access_sig(((deng_t *)obj)->ilist, n);

	transfer_sym(sig);

	return 1;
}

/*------------------------------------------------*/
/* function : display_matched                     */
/* description: Displays matched list             */
/*------------------------------------------------*/

static void display_matched(deng_t * eng)
{
	choose2(CH_ATTRS,
		-1, -1, -1, -1,       // position is determined by Windows
		eng,                  // pass the created function list to the window
		qnumber(header_match),// number of columns
		widths_match,		  // widths of columns
		sizer_match,          // function that returns number of lines
		desc_match,           // function that generates a line
		title_match,	      // window title
		-1,                   // use the default icon for the window
		1,                    // position the cursor on the first line
		NULL,                 // "kill" callback
		NULL,                 // "new" callback
		NULL,                 // "update" callback
		graph_match,          // "edit" callback
		enter_match,          // function to call when the user pressed Enter
		close_window,         // function to call when the window is closed
		popup_match,          // use default popup menu items
		NULL);  

	eng->wnum++;
	
	add_chooser_command(title_match, "Unmatch", res_munmatch, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
	add_chooser_command(title_match, "Set as identical", res_mtoi, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
	add_chooser_command(title_match, "Flag/unflag", res_flagged, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
	add_chooser_command(title_match, "Import Symbol", transfer_sym_match, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
}


/*------------------------------------------------*/
/* function : display_identical                   */
/* description: Displays identical list           */
/*------------------------------------------------*/

static void display_identical(deng_t * eng)
{
	choose2(0,
		-1, -1, -1, -1,       // position is determined by Windows
		eng,                  // pass the created function list to the window
		qnumber(header_match),// number of columns
		widths_match,		  // widths of columns
		sizer_identical,      // function that returns number of lines
		desc_identical,       // function that generates a line
		title_identical,	  // window title
		-1,                   // use the default icon for the window
		1,                    // position the cursor on the first line
		NULL,                 // "kill" callback
		NULL,                 // "new" callback
		NULL,                 // "update" callback
		graph_identical,      // "edit" callback
		enter_identical,      // function to call when the user pressed Enter
		close_window,         // function to call when the window is closed
		popup_match,          // use default popup menu items
		NULL);  

	eng->wnum++;
	
	add_chooser_command(title_identical, "Unmatch", res_iunmatch, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
	add_chooser_command(title_identical, "Set as matched", res_itom, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
	add_chooser_command(title_identical, "Import Symbol", transfer_sym_identical, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
}


/*------------------------------------------------*/
/* function : display_unmatched                   */
/* description: Displays unmatched list           */
/*------------------------------------------------*/

static void display_unmatched(deng_t * eng)
{
	choose2(0,
		-1, -1, -1, -1,       // position is determined by Windows
		eng,                  // pass the created function list to the window
		qnumber(header_unmatch),// number of columns
		widths_unmatch,		  // widths of columns
		sizer_unmatch,        // function that returns number of lines
		desc_unmatch,         // function that generates a line
		title_unmatch,	      // window title
		-1,                   // use the default icon for the window
		1,                    // position the cursor on the first line
		NULL,                 // "kill" callback
		NULL,                 // "new" callback
		NULL,                 // "update" callback
		graph_unmatch,        // "edit" callback
		enter_unmatch,        // function to call when the user pressed Enter
		close_window,         // function to call when the window is closed
		popup_unmatch,        // use default popup menu items
		NULL);                // use the same icon for all lines

	eng->wnum++;
	
	add_chooser_command(title_unmatch, "Set match", res_match, 0, -1, CHOOSER_POPUP_MENU | CHOOSER_MENU_EDIT);
}


/*------------------------------------------------*/
/* function : ui_callback                         */
/* description: Catchs lists to change bg color   */
/*------------------------------------------------*/

int idaapi ui_callback(void * data, int event_id, va_list va)
{
  if ( event_id == ui_get_chooser_item_attrs )  
  {
	  void * co = va_arg(va, void *);
	  uint32 n = va_arg(va, uint32);
	  chooser_item_attrs_t *attrs = va_arg(va, chooser_item_attrs_t *);
	  if (attrs != NULL)
	  {
		deng_t * d = (deng_t *)co;
		if (d && d->magic == 0x0BADF00D && n > 0)
			if (ui_access_sig(d->mlist, n)->flag == 1)
				attrs->color = 0x908070;
	  }
  }

  return 0;
}


/*------------------------------------------------*/
/* function : display_results                     */
/* description: Displays diff results             */
/*------------------------------------------------*/

void display_results(deng_t * eng)
{
	hook_to_notification_point(HT_UI, ui_callback, NULL);

	display_matched(eng);
	display_unmatched(eng);
	display_identical(eng);
}

Web Proxy Viewer  |  New URL  |  Original Page