/************************************************************************
* 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: UTF-8 | 0
|