Source file: /~heha/hsn/borg.zip/DATA.CPP

/************************************************************************
*		  data.cpp						*
* - this is the set of functions which looks after segments/sections	*
* blocks of code or data can be added to the database, where they are	*
* kept and ordered and can be interrogated. functions should be segment *
* level functions in here. the possibleentrycode function was put here	*
* on this basis rather than being a disasm function as it simply	*
* looks for likely entry code and adds scheduler items			*
*									*
* NB segment address with segment=0 is treated as a special return	*
* value, and segments should not be created with this value		*
************************************************************************/

#include <windows.h>

#include "data.h"
#include "proctab.h"
#include "schedule.h"
#include "dasm.h"
#include "disasm.h"
#include "debug.h"

// save structure used in databases
struct dsegitemsave
{ lptr addr;
  dword size;
  dword fileoffset;
  segtype typ;
  bool name;
};

/************************************************************************
* global variables							*
* - total_data_size and current_data_pos are basically used to control	*
*   the vertical scroll bar. They are set up in here where the values	*
*   are first initialised as segments are added				*
************************************************************************/
unsigned long total_data_size;
//unsigned long current_data_pos;

/************************************************************************
* constructor function							*
* - we reset the global variables used to track data size and position	*
************************************************************************/
dataseg::dataseg()
{ total_data_size=0;
//  current_data_pos=0;
}

/************************************************************************
* destructor								*
* - null at present. the list destructor should handle all segment	*
*   destruction								*
************************************************************************/
dataseg::~dataseg()
{
}

/************************************************************************
* compare function							*
* this is the compare function for the inherited list class		*
* it determines how segments are ordered - by start address		*
************************************************************************/
int dataseg::compare(dsegitem *i,dsegitem *j)
{ if(i->addr==j->addr)
    return 0;
  if(i->addr>j->addr)
    return 1;
  return -1;
}

/************************************************************************
* deletion function							*
* this function is called for each list item (segment) and is used to	*
* delete the list items (dsegitem)					*
* - we delete any name which was created for the segment, and also any	*
*   data which was created for uninitdata types (we generate a memory	*
*   space for uninitdata for simplicity of analysis later)		*
* - overrides the standard listitem deletion function			*
************************************************************************/
void dataseg::delfunc(dsegitem *i)
{ if(i->name!=NULL)
    delete i->name;
  if(i->typ==uninitdata)
    delete i->data;
  delete i;
}

/************************************************************************
* insegloc								*
* returns true if loc is in the segment/section ds, otherwise false	*
************************************************************************/
bool dataseg::insegloc(dsegitem *ds,lptr loc)
{ if(ds==NULL)
    return false;
  if(loc.between(ds->addr,ds->addr+ds->size-1))
    return true;
  return false;
}

/************************************************************************
* addseg								*
* this adds a segment to the list of segments. It is called on loading	*
* the file, and segments should be setup before any analysis - here a	*
* segment is just a block of data of a single attribute, which will be	*
* referenced later. It could be a true segment, or just a PE section,	*
* or even just a single resource. Segments should not overlap		*
* the function checks for any overlaps, adds a task to the scheduler	*
* for a segment header comment block, keeps track of total data size	*
************************************************************************/
void dataseg::addseg(lptr loc,dword size,byte *dataptr,segtype t,char *name)
{ dsegitem *addit,*chker;
  char warning[100];
  dword tsize;
//  dword tmpnum;
#ifdef DEBUG
  DebugMessage("Addseg %04lx:%04lx Size %04lx",loc.segm,loc.offs,size);
#endif
  addit=new dsegitem;
  addit->addr=loc;
  addit->size=size;
  addit->data=dataptr;
  addit->typ=t;
  if(name!=NULL)
  { addit->name=new char [lstrlen(name)+1];
    lstrcpy(addit->name,name);
  }
  else
    addit->name=NULL;
  resetiterator();
  chker=nextiterator();
  while(chker!=NULL)
  { if(insegloc(addit,chker->addr))
    { //need to cut addit short.
     addit->size=chker->addr-addit->addr;
     if(!addit->size) {
      wsprintf(warning,"Warning : Unable to create segment %04lx:%04lx size :%04lx",
	loc.segm,loc.offs,size);
      MessageBox(MainWnd,warning,"Borg Warning",MB_ICONEXCLAMATION|MB_OK);
      return;
     }else{
      wsprintf(warning,"Warning : Segment overlap %04lx:%04lx size :%04lx"
	" reduced to size :%04lx",loc.segm,loc.offs,size,addit->size);
      MessageBox(MainWnd,warning,"Borg Warning",MB_ICONEXCLAMATION|MB_OK);
     }
    }
    if(insegloc(chker,addit->addr))
    { //need to cut chkit short.
      tsize=chker->size;
      chker->size=addit->addr-chker->addr;
      if(!chker->size) {
	wsprintf(warning,"Warning : Unable to create segment %04lx:%04lx size :%04lx",
	  chker->addr.segm,chker->addr.offs,tsize);
	MessageBox(MainWnd,warning,"Borg Warning",MB_ICONEXCLAMATION|MB_OK);
	delfrom(chker);
	resetiterator();
      }else{
       wsprintf(warning,"Warning : Segment overlap %04lx:%04lx size :%04lx"
	 " reduced to size :%04lx",
	 chker->addr.segm,chker->addr.offs,tsize,chker->size);
       MessageBox(MainWnd,warning,"Borg Warning",MB_ICONEXCLAMATION|MB_OK);
      }
    }
    chker=nextiterator();
  }
  addto(addit);
#ifdef DEBUG
  DebugMessage("Adding Seg %04lx:%04lx Size %04lx",loc.segm,loc.offs,size);
  if(name!=NULL)
    DebugMessage("Name:%s",name);
#endif
  scheduler.addtask(dis_segheader,priority_segheader,loc,NULL);
  total_data_size+=size;
}

/************************************************************************
* findseg								*
* - the segment locator takes a loc and searches for the segment	*
*   containing the loc. If its found then it returns a pointer to the	*
*   dsegitem. Note the iterator is changed, and will be left pointing	*
*   to the next segment.						*
************************************************************************/
dsegitem *dataseg::findseg(lptr loc)
{ dsegitem t1,*findd;
  t1.addr.assign(loc.segm,0);
  findnext(&t1);
  findd=nextiterator();
  while(findd!=NULL)
  { if(insegloc(findd,loc))
      return findd;
    findd=nextiterator();
  }
  return NULL;
}

/************************************************************************
* datagetpos								*
* - this simply calculates how far along the total data a loc is, which *
*   is used for the vertical scroll bar to determine how far down it	*
*   should be.								*
************************************************************************/
unsigned long dataseg::datagetpos(lptr loc)
{  dsegitem *findd;
   unsigned long ctr;
   resetiterator();
   findd=nextiterator();
   ctr=0;
   while(findd!=NULL)
   {  if(insegloc(findd,loc))
      {	 ctr+=(loc-findd->addr);
	 break;
      }
      ctr+=findd->size;
      findd=nextiterator();
   }
   return ctr;
}

/************************************************************************
* getlocpos								*
* - for a data position this returns the loc, treating all segments as	*
*   continous. It is the opposite function to datagetpos. It is used	*
*   when the vertical scroll bar is dragged to a position and stopped,	*
*   in order to calculate the new loc.					*
************************************************************************/
lptr dataseg::getlocpos(unsigned long pos)
{  dsegitem *findd;
   lptr ctr;
   resetiterator();
   findd=nextiterator();
   ctr=findd->addr;
   while(findd!=NULL)
   {  if(pos<findd->size)
      {	 ctr=findd->addr+pos;
	 break;
      }
      pos-=findd->size;
      ctr=findd->addr;
      if(findd->size)
	ctr+=(findd->size-1); // last byte in seg in case we dont find the addr
      findd=nextiterator();
   }
   return ctr;
}

/************************************************************************
* beyondseg								*
* - returns a bool value indicating whether the loc is outside a	*
*   segment. Used a lot to determine if we have moved outside a data	*
*   area. If two segments have the same segm value and are contiguous	*
*   then it will return false, not true					*
************************************************************************/
bool dataseg::beyondseg(lptr loc)
{ dsegitem *findd;
  resetiterator();
  findd=nextiterator();
  while(findd!=NULL)
  { if(insegloc(findd,loc))
      return false;
    findd=nextiterator();
  }
  return true;
}

/************************************************************************
* nextseg								*
* - this function takes a loc, and returns the next segment first loc	*
*   or a segm=0 if its not found					*
* mainly used in output and display routines				*
************************************************************************/
void dataseg::nextseg(lptr *loc)
{ dsegitem *findd;
  resetiterator();
  findd=nextiterator();
  while(findd!=NULL)
  { if(insegloc(findd,*loc))
    { findd=nextiterator();
      if(findd==NULL)
	loc->segm=0;
      else
	(*loc)=findd->addr;
      return;
    }
    findd=nextiterator();
  }
  loc->segm=0;
}

/************************************************************************
* lastseg								*
* - this function takes a loc, and returns the last segment last loc	*
*   or a segm=0 if its not found					*
* mainly used in output and display routines				*
************************************************************************/
void dataseg::lastseg(lptr *loc)
{ dsegitem *findd,*prevd;
  resetiterator();
  findd=nextiterator();
  prevd=NULL;
  while(findd!=NULL)
  { if(insegloc(findd,*loc))
    { if(prevd==NULL)
	loc->segm=0;
      else
	(*loc)=prevd->addr+prevd->size-1;
      return;
    }
    prevd=findd;
    findd=nextiterator();
  }
  loc->segm=0;
}

/************************************************************************
* possibleentrycode							*
* - this just scans a whole segment for possible routine entrycode, as	*
* defined by options, and adds scheduler items for proper analysis by	*
* disasm. currently all specific to the 80x86 processor			*
************************************************************************/
void dataseg::possibleentrycode(lptr loc)
{ dsegitem t1,*findd;
  dword length;
  if(options.processor==PROC_Z80)
    return;
  t1.addr=loc;
  findd=find(&t1);
  if(findd==NULL)
    return;
  length=findd->size;
  loc.offs=findd->addr.offs;
  if(options.codedetect&CD_AGGRESSIVE)
    scheduler.addtask(seek_code,priority_aggressivesearch,loc,NULL);
  while(length)
  { if((options.codedetect&CD_PUSHBP)&&(length>3))
    { if(findd->data[loc-findd->addr]==0x55)  // push bp
      { // two encodings of mov bp,sp
	if((findd->data[(loc-findd->addr)+1]==0x8b)&&(findd->data[(loc-findd->addr)+2]==0xec))
	  scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
	if((findd->data[(loc-findd->addr)+1]==0x89)&&(findd->data[(loc-findd->addr)+2]==0xe5))
	  scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
      }
    }
    if((options.codedetect&CD_EAXFROMESP)&&(length>4))
    { if(findd->data[loc-findd->addr]==0x55)  // push bp
      { if((findd->data[(loc-findd->addr)+1]==0x8b)&&(findd->data[(loc-findd->addr)+2]==0x44)&&(findd->data[(loc-findd->addr)+3]==0x24)) // mov ax,[sp+xx]
	  scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
      }
    }
    if((options.codedetect&CD_MOVEAX)&&(length>3))
    { if((findd->data[(loc-findd->addr)]==0x8b)&&(findd->data[(loc-findd->addr)+1]==0x44)&&(findd->data[(loc-findd->addr)+2]==0x24)) // mov ax,[sp+xx]
	scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
    }
    if((options.codedetect&CD_ENTER)&&(length>4))
    { if(findd->data[loc-findd->addr]==0xc8)  // enter
      { if(findd->data[(loc-findd->addr)+3]==0x00) // enter xx,00
	  scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
      }
    }
    if((options.codedetect&CD_MOVBX)&&(length>2)) // mov bx,sp
    { if((findd->data[loc-findd->addr]==0x8b)&&(findd->data[(loc-findd->addr)+1]==0xdc))
	scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
    }
    loc.offs++;
    length--;
  }
}

LPTSTR typ2name(segtype typ) {
 switch(typ) {
  case code16:		return T("16-bit Code");
  case code32:		return T("32-bit Code");
  case data16:		return T("16-bit Data");
  case data32:		return T("32-bit Data");
  case uninitdata:	return T("Uninit Data");
  case debugdata:	return T("Debug Data");
  case resourcedata:	return T("Resource Data");
 }
 return T("Unknown");
}

/************************************************************************
* segheader								*
* - here we add the segment header as a comment, to the disassembly	*
*  disasm adds the comment, we assemble the information here.		*
************************************************************************/
void dataseg::segheader(lptr loc) {
 static char divider[]="-----------------------------------------------------------------------";
 byte *tmpc,tmp2[30];
 dsegitem t1,*findd;
 dword t;
 t1.addr=loc;
 findd=find(&t1);
 if (!findd) return;
  tmpc=new byte[80];
  lstrcpy((char *)tmpc,divider);
  dsm->discomment(loc,dsmsegheader,tmpc);
  tmpc=new byte[80];
  t=loc.segm;
  wsprintf((char *)tmpc,"Segment: %02lxh",t);
  wsprintf((char *)tmp2,"     Offset: %02lxh",loc.offs);
  lstrcat((char *)tmpc,(char *)tmp2);
  wsprintf((char *)tmp2,"     Size: %02lxh",findd->size);
  lstrcat((char *)tmpc,(char *)tmp2);
  dsm->discomment(loc,(dsmitemtype)(dsmsegheader+1),tmpc);
  tmpc=new byte[80];
  lstrcpy((char *)tmpc,typ2name(findd->typ));
  if (findd->name) {
   lstrcat((char *)tmpc,": ");
   strncat((char *)tmpc,findd->name,60);
  }
  dsm->discomment(loc,(dsmitemtype)(dsmsegheader+2),tmpc);
  tmpc=new byte[80];
  lstrcpy((char *)tmpc,divider);
  dsm->discomment(loc,(dsmitemtype)(dsmsegheader+3),tmpc);
}

/************************************************************************
* write_item								*
* - writes a dataseg item to the savefile specified			*
*   uses the current item, and moves the iterator on			*
*   saving in borg is single pass and so stringlengths are saved before *
*   strings, etc. we use a similar structure item for the save		*
*   (dsegitem - dsegitemsave). As the data item is a pointer it is	*
*   converted into an offset for saving.				*
************************************************************************/
bool dataseg::write_item(savefile *sf,byte *filebuff)
{ dword nlen;
  dsegitemsave structsave;
  dsegitem *currseg;

  currseg=nextiterator();
  structsave.addr=currseg->addr;
  structsave.size=currseg->size;
  structsave.fileoffset=currseg->data-filebuff;
  structsave.typ=currseg->typ;
  if(currseg->name!=NULL)
    structsave.name=true;
  else
    structsave.name=false;
  if(!sf->Write(&structsave,sizeof(dsegitemsave)))
    return false;
  if(structsave.name) {
   nlen=lstrlen(currseg->name)+1;
   sf->Write(&nlen,sizeof(dword));
   if (!sf->Write(currseg->name,nlen)) return false;
  }
  return true;
}

/************************************************************************
* read_item								*
* - reads a dataseg item from the savefile specified			*
*   Note that addseg is not used here, since we have all the		*
*   information and just need to reconstruct the dsegitem. Hence we	*
*   also need to recalculate total_data_size in here. Also, for uninit	*
*   data segments we add a false data area.				*
************************************************************************/
bool dataseg::read_item(savefile *sf,byte *filebuff)
{ dword nlen;
  dsegitemsave structsave;
  dsegitem *currseg;

  currseg=new dsegitem;
  if (!sf->Read(&structsave,sizeof(dsegitemsave)))
    return false;
  currseg->addr=structsave.addr;
  currseg->size=structsave.size;
  currseg->data=structsave.fileoffset+filebuff;
  currseg->typ=structsave.typ;
  // total_data_size increased
  total_data_size+=currseg->size;
  if(structsave.name)
  { if(!sf->Read(&nlen,sizeof(dword)))
      return false;
    currseg->name=new char[nlen];
    if(!sf->Read(currseg->name,nlen))
      return false;
  }
  else currseg->name=NULL;
  // uninitdata - add false data area
  if(currseg->typ==uninitdata)
  { currseg->data=new byte[currseg->size];
    for(nlen=0;nlen<currseg->size;nlen++)
      (currseg->data)[nlen]=0;
  }
  addto(currseg);
  return true;
}

Detected encoding: ASCII (7 bit)2