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

/************************************************************************
*		   exeload.cpp						*
* Contains the executable file load routines and setting up of the	*
* disassembly for the files..						*
************************************************************************/

#include <windows.h>
#include <stdio.h>

#include "dasm.h"
#include "exeload.h"
#include "data.h"
#include "disio.h"
#include "disasm.h"
#include "schedule.h"
#include "relocs.h"
#include "gname.h"
#include "debug.h"

/************************************************************************
* constructor function							*
* - resets file details.						*
************************************************************************/
fileloader::fileloader(void) {
 efile=INVALID_HANDLE_VALUE;
 exetype=0;
 fbuff=NULL;
}

/************************************************************************
* destructor function							*
* - closes and file that is open.					*
************************************************************************/
fileloader::~fileloader(void) {
 if (fbuff) delete fbuff;
 CloseHandle(efile);
}

/************************************************************************
* fileoffset								*
* - function which returns the offset in a file of a given location,	*
*   this is to enable file patching given a location to patch		*
* - added in Borg v2.19							*
************************************************************************/
dword fileloader::fileoffset(lptr loc)
{ dsegitem *ds;
  ds=dta->findseg(loc);
  if(ds==NULL)
    return 0;
  return (loc-ds->addr)+(ds->data-fbuff);
}

/************************************************************************
* patchfile								*
* - writes to the currently open file (does not check it is opened with *
*   write access), given the number of bytes, data, and file offset to	*
*   write to.								*
* - added in Borg v2.19							*
************************************************************************/
void fileloader::patchfile(dword file_offs,dword num,byte *dat)
{ dword written;
  if(efile==INVALID_HANDLE_VALUE)
  { MessageBox(MainWnd,"File I/O Error - Invalid Handle for writing","Borg Message",MB_OK);
    return;
  }
  SetFilePointer(efile,file_offs,NULL,FILE_BEGIN);
  WriteFile(efile,dat,num,&written,NULL);
}

/************************************************************************
* reloadfile								*
* - reads part of a file back in, given the file offset, number of	*
*   bytes and data buffer to read it in to. Used in the decryptor when	*
*   reloading a database file.						*
************************************************************************/
void fileloader::reloadfile(dword file_offs,dword num,byte *dat)
{ dword rd;
  if(efile==INVALID_HANDLE_VALUE)
  { MessageBox(MainWnd,"File I/O Error - Invalid Handle for reading","Borg Message",MB_OK);
    return;
  }
  SetFilePointer(efile,file_offs,NULL,FILE_BEGIN);
  ReadFile(efile,dat,num,&rd,NULL);
}

/************************************************************************
* readcomfile								*
* - one of the simpler exe format loading routines, we just need to	*
*   load the file and disassemble from the start with an offset of	*
*   0x100								*
************************************************************************/
void fileloader::readcomfile(dword fsize)
{ options.loadaddr.offs=0x100;
  options.dseg=options.loadaddr.segm;
  dta->addseg(options.loadaddr,fsize,fbuff,code16,NULL);
  dta->possibleentrycode(options.loadaddr);
  options.mode16=true;
  options.mode32=false;
  cvd->setcuraddr(options.loadaddr);
  scheduler.addtask(dis_code,priority_definitecode,options.loadaddr,NULL);
  scheduler.addtask(nameloc,priority_nameloc,options.loadaddr,"start");
  scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
* readsysfile								*
* - very similar to the com file format, but the start offset is 0x00	*
* - detailed sys format below: (since so few documents seem to give the *
*   information correctly)						*
*									*
* Device Header								*
*									*
* The device header is an extension to what is described in the MS-PRM. *
*									*
* DevHdr DD -1 ; Ptr to next driver in file or -1 if last driver	*
* DW ? ; Device attributes						*
* DW ? ; Device strategy entry point					*
* DW ? ; Device interrupt entry point					*
* DB 8 dup (?) ; Character device name field				*
* DW 0 ; Reserved							*
* DB 0 ; Drive letter							*
* DB ? ; Number of units						*
*									*
* A device driver requires a device header at the beginning of the	*
* file.									*
*									*
* POINTER TO NEXT DEVICE HEADER FIELD					*
*									*
* The device header field is a pointer to the device header of the next *
* device driver. It is a doubleword field that is set by DOS at the	*
* time the device driver is loaded. The first word is an offset and the *
* second word is the segment. If you are loading only one device	*
* driver, set the device header field to -1 before loading the device.	*
* If you are loading more than one device driver, set the first word of *
* the device driver header to the offset of the next device driver's	*
* header. Set the device driver header field of the last device driver	*
* to -1.								*
*									*
* ATTRIBUTE FIELD							*
*									*
* The attribute field is a word field that describes the attributes of	*
* the device driver to the system. The attributes are:			*
*									*
* word bits (decimal)							*
*  15	1   character device						*
*	0   block device						*
*  14	1   supports IOCTL						*
*	0   doesn't support IOCTL					*
*  13	1   non-IBM format (block only)					*
*	0   IBM format							*
*  12	    not documented - unknown					*
*  11	1   supports removeable media					*
*	0   doesn't support removeable media				*
*  10	    reserved for DOS						*
*    through								*
*   4	    reserved for DOS						*
*   3	1   current block device					*
*	0   not current block device					*
*   2	1   current NUL device						*
*	0   not current NUL device					*
*   1	1   current standard output device				*
*	0   not current standard output device				*
*									*
* BIT 15 is the device type bit. Use it to tell the system the that	*
* driver is a block or character device.				*
*									*
* BIT 14 is the IOCTL bit. It is used for both character and block	*
* devices. Use it to tell DOS whether the device driver can handle	*
* control strings through the IOCTL function call 44h.			*
* If a device driver cannot process control strings, it should set bit	*
* 14 to 0. This way DOS can return an error is an attempt is made	*
* through the IOCTL function call to send or receive control strings to *
* the device. If a device can process control strings, it should set	*
* bit 14 to 1. This way, DOS makes calls to the IOCTL input and output	*
* device function to send and receive IOCTL strings.			*
* The IOCTL functions allow data to be sent to and from the device	*
* without actually doing a normal read or write. In this way, the	*
* device driver can use the data for its own use, (for example, setting *
* a baud rate or stop bits, changing form lengths, etc.) It is up to	*
* the device to interpret the information that is passed to it, but the *
* information must not be treated as a normal I/O request.		*
*									*
* BIT 13 is the non-IBM format bit. It is used for block devices only.	*
* It affects the operation of the Get BPB (BIOS parameter block) device *
* call.									*
*									*
* BIT 11 is the open/close removeable media bit. Use it to tell DOS if	*
* the device driver can handle removeable media. (DOS 3.x only)		*
*									*
* BIT 3 is the clock device bit. It is used for character devices only. *
* Use it to tell DOS if your character device driver is the new CLOCK$	*
* device.								*
*									*
* BIT 2 is the NUL attribute bit. It is used for character devices	*
* only. Use it to tell DOS if your character device driver is a NUL	*
* device. Although there is a NUL device attribute bit, you cannot	*
* reassign the NUL device. This is an attribute that exists for DOS so	*
* that DOS can tell if the NUL device is being used.			*
*									*
* BIT 0 are the standard input and output bits. They are used for	*
* character & devices only. Use these bits to tell DOS if your		*
* character device							*
*									*
* BIT 1 driver is the new standard input device or standard output	*
* device.								*
*									*
* POINTER TO STRATEGY AND INTERRUPT ROUTINES				*
*									*
* These two fields are pointers to the entry points of the strategy and *
* input routines. They are word values, so they must be in the same	*
* segment as the device header.						*
*									*
* NAME/UNIT FIELD							*
*									*
* This is an 8-byte field that contains the name of a character device	*
* or the unit of a block device. For the character names, the name is	*
* left-justified and the space is filled to 8 bytes. For block devices, *
* the number of units can be placed in the first byte. This is optional *
* because DOS fills in this location with the value returned by the	*
* driver's INIT code.							*
************************************************************************/
void fileloader::readsysfile(dword fsize)
{ lptr t;
  bool done;
  word devhdr,devlength;
  options.loadaddr.offs=0x00;
  options.dseg=options.loadaddr.segm;
  dta->addseg(options.loadaddr,fsize,fbuff,code16,NULL);
  dta->possibleentrycode(options.loadaddr);
  options.mode16=true;
  options.mode32=false;
  cvd->setcuraddr(options.loadaddr);
  done=false;
  devhdr=0;
  while(!done)
  { t.assign(options.loadaddr.segm,devhdr);
    scheduler.addtask(dis_dataword,priority_data,t,NULL);
    scheduler.addtask(dis_dataword,priority_data,t+2,NULL);
    scheduler.addtask(dis_dataword,priority_data,t+4,NULL);
    scheduler.addtask(dis_dataword,priority_data,t+6,NULL);
    scheduler.addtask(dis_dataword,priority_data,t+8,NULL);
    scheduler.addtask(dis_dataword,priority_data,t+18,NULL);
    if((((word *)(fbuff+devhdr))[3])&&((dword)(((word *)(fbuff+devhdr))[3])<fsize))
    { t.assign(options.loadaddr.segm,((word *)(fbuff+devhdr))[3]+devhdr);
      if(t.offs)
      { scheduler.addtask(dis_code,priority_definitecode,t,NULL);
	scheduler.addtask(nameloc,priority_nameloc,t,"strategy");
      }
    }
    if((((word *)(fbuff+devhdr))[4])&&((dword)(((word *)(fbuff+devhdr))[4])<fsize))
    { t.assign(options.loadaddr.segm,((word *)(fbuff+devhdr))[4]);
      if(t.offs)
      { scheduler.addtask(dis_code,priority_definitecode,t,NULL);
	scheduler.addtask(nameloc,priority_nameloc,t,"interrupt");
      }
    }
    scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
    devlength=((word *)(fbuff+devhdr))[0];
    if((devlength==0xffff)||(!devlength)||((dword)(devhdr+devlength)>fsize-10))
      done=true;
    devhdr+=(word)devlength;
  }
}

/************************************************************************
* readpefile								*
* - the main file loader in Borg is for PE files. The routines here are *
*   fairly complete, and lack only proper analysis of debug sections.	*
* - needs rewriting for clarity at some point in the future, as it has	*
*   sprawled out to 360 lines now.					*
* - some further resource tree analysis is done in other routines which *
*   follow								*
************************************************************************/
void fileloader::readpefile(dword peoffs)
{ peheader *peh;
  peobjdata *pdata;
  byte *pestart,*impname,*expname;
  unsigned char *chktable;
  lptr lef,leo,len,start_addr;
  dword *fnaddr,*nnaddr;
  word *onaddr,*rdata;
  dword numsymbols,numitems,numrelocs;
  char impbuff[100],inum[10],*newimpname;
  lptr sseg,t;
  dword j;
  int i,k,k1,clen;
  peimportdirentry *impdir;
  byte *uinit;
  peexportdirentry *expdir;
  perelocheader *per;
  dword thunkrva,*imphint,impaddr,impaddr2,numtmp;
  bool peobjdone;
  perestable *resdir;
  perestableentry *rentry;
  start_addr=nlptr;
  options.dseg=options.loadaddr.segm;
  sseg.segm=options.loadaddr.segm;
  sseg.offs=0;
  pestart=&fbuff[peoffs];
  peh=(peheader *)pestart;
  options.loadaddr.offs=peh->image_base; // bugfix build 14
  // this is not right - ver 2.19 bugfix below
  //  pdata=(peobjdata *)(pestart+sizeof(peheader)+(peh->numintitems-0x0a)*8);
  // 24=standard header size and add nt_hdr_size to it.
  pdata=(peobjdata *)(pestart+24+peh->nt_hdr_size);
  for(i=0;i<peh->objects;i++)
  { peobjdone=false;
    if((pdata[i].rva==peh->exporttable_rva)  // export info
      ||((peh->exporttable_rva>pdata[i].rva)&&(peh->exporttable_rva<pdata[i].rva+pdata[i].phys_size)))
    { expdir=(peexportdirentry *)&fbuff[pdata[i].phys_offset+peh->exporttable_rva-pdata[i].rva];
      t.assign(options.loadaddr.segm,peh->image_base+peh->exporttable_rva);
      scheduler.addtask(dis_datadword,priority_data,t,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+4,NULL);
      scheduler.addtask(dis_dataword,priority_data,t+8,NULL);
      scheduler.addtask(dis_dataword,priority_data,t+10,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+12,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+16,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+20,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+24,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+28,NULL);
      for(k1=0;k1<peh->objects;k1++)
      { if((expdir->namerva>=pdata[k1].rva)&&(expdir->namerva<pdata[k1].rva+pdata[k1].phys_size))
	{ expname=&fbuff[expdir->namerva-pdata[k1].rva+pdata[k1].phys_offset];
	  break;
	}
      }
      t.offs=expdir->namerva+peh->image_base;
      scheduler.addtask(dis_datastring,priority_data,t,NULL);
      numsymbols=expdir->numfunctions;
      chktable=new unsigned char [numsymbols];
      for(j=0;j<numsymbols;j++)
	chktable[j]=0;
      if(expdir->numnames<numsymbols)
	numsymbols=expdir->numnames;
      for(k=0;k<peh->objects;k++)
      { if((expdir->nameaddrrva>=pdata[k].rva)&&(expdir->nameaddrrva<pdata[k].rva+pdata[k].phys_size))
	{ nnaddr=(dword *)&fbuff[expdir->nameaddrrva-pdata[k].rva+pdata[k].phys_offset];
	  break;
	}
      }
      for(k=0;k<peh->objects;k++)
      { if((expdir->funcaddrrva>=pdata[k].rva)&&(expdir->funcaddrrva<pdata[k].rva+pdata[k].phys_size))
	{ fnaddr=(dword *)&fbuff[expdir->funcaddrrva-pdata[k].rva+pdata[k].phys_offset];
	  break;
	}
      }
      for(k=0;k<peh->objects;k++)
      { if((expdir->ordsaddrrva>=pdata[k].rva)&&(expdir->ordsaddrrva<pdata[k].rva+pdata[k].phys_size))
	{ onaddr=(word *)&fbuff[expdir->ordsaddrrva-pdata[k].rva+pdata[k].phys_offset];
	  break;
	}
      }
      lef.assign(options.loadaddr.segm,expdir->funcaddrrva+peh->image_base);
      leo.assign(options.loadaddr.segm,expdir->ordsaddrrva+peh->image_base);
      len.assign(options.loadaddr.segm,expdir->nameaddrrva+peh->image_base);
      while(numsymbols)
      { scheduler.addtask(dis_datadword,priority_data,lef,NULL);
	scheduler.addtask(dis_dataword,priority_data,leo,NULL);
	scheduler.addtask(dis_datadword,priority_data,len,NULL);
	chktable[onaddr[0]]=1;
	t.assign(options.loadaddr.segm,peh->image_base+fnaddr[onaddr[0]]);
	scheduler.addtask(dis_export,priority_export,t,(char *)&fbuff[(*nnaddr)+pdata[k].phys_offset-pdata[k].rva]);
	t.assign(options.loadaddr.segm,(*nnaddr)+peh->image_base);
	scheduler.addtask(dis_datastring,priority_data,t,NULL);
	// actually not definite code since data can be exported too, eg a debug hook address
	// so uses dis_exportcode which will disassemble if its in a code segment only.
	t.assign(options.loadaddr.segm,peh->image_base+fnaddr[onaddr[0]]);
	scheduler.addtask(dis_exportcode,priority_definitecode,t,NULL);
	numsymbols--;
	onaddr++;
	nnaddr++;
	lef+=4;
	leo+=2;
	len+=4;
      }
      if(expdir->numfunctions>expdir->numnames)
      { for(j=0;j<expdir->numfunctions;j++)
	{ if(!chktable[j])
	  { numtmp=j+expdir->base;
	    wsprintf(inum,"%02d",numtmp);
	    lstrcpyn(impbuff,(char *)expname,GNAME_MAXLEN-8);
	    k=0;
	    while((impbuff[k])&&(k<GNAME_MAXLEN-8))
	    { if(impbuff[k]=='.')
		break;
	      k++;
	    }
	    lstrcpy(&impbuff[k],"::ord_");
	    lstrcat(impbuff,inum);
	    newimpname=new char[lstrlen(impbuff)+1];
	    lstrcpy(newimpname,impbuff);
	    if(fnaddr[j])
	    { t.assign(options.loadaddr.segm,fnaddr[j]+peh->image_base);
	      scheduler.addtask(dis_ordexport,priority_export,t,newimpname);
	      scheduler.addtask(dis_code,priority_definitecode,t,NULL);
	    }
	  }
	}
      }
      delete chktable;
    }
    if((pdata[i].rva==peh->importtable_rva) // import info
      ||((peh->importtable_rva>pdata[i].rva)&&(peh->importtable_rva<pdata[i].rva+pdata[i].phys_size)))
    { impdir=(peimportdirentry *)&fbuff[pdata[i].phys_offset+peh->importtable_rva-pdata[i].rva];
      j=0;
      while(impdir[j].firstthunkrva)
      { t.assign(options.loadaddr.segm,
	  peh->image_base+peh->importtable_rva+j*sizeof(struct peimportdirentry));
	scheduler.addtask(dis_datadword,priority_data,t,NULL);
	scheduler.addtask(dis_datadword,priority_data,t+4,NULL);
	scheduler.addtask(dis_datadword,priority_data,t+8,NULL);
	scheduler.addtask(dis_datadword,priority_data,t+12,NULL);
	scheduler.addtask(dis_datadword,priority_data,t+16,NULL);
	for(k1=0;k1<peh->objects;k1++)
	{ if((impdir[j].namerva>=pdata[k1].rva)&&(impdir[j].namerva<pdata[k1].rva+pdata[k1].phys_size))
	  { impname=&fbuff[impdir[j].namerva-pdata[k1].rva+pdata[k1].phys_offset];
	    break;
	  }
	}
	t.assign(options.loadaddr.segm,impdir[j].namerva+peh->image_base);
	scheduler.addtask(dis_datastring,priority_data,t,NULL);
	if(!impdir[j].originalthunkrva)
	  thunkrva=impdir[j].firstthunkrva;
	else
	  thunkrva=impdir[j].originalthunkrva;
	for(k=0;k<peh->objects;k++)
	{ if((thunkrva>=pdata[k].rva)&&(thunkrva<pdata[k].rva+pdata[k].phys_size))
	  { imphint=(dword *)&fbuff[thunkrva-pdata[k].rva+pdata[k].phys_offset];
	    break;
	  }
	}
	impaddr=impdir[j].firstthunkrva+peh->image_base;
	impaddr2=impdir[j].originalthunkrva+peh->image_base;
	while(*imphint)
	{ if((*imphint)&0x80000000)
	  { numtmp=(*imphint)&0x7fffffff;
	    wsprintf(inum,"%02d",numtmp);
	    lstrcpy(impbuff,(char *)impname);
	    k=0;
	    while(impbuff[k])
	    { if(impbuff[k]=='.')
		break;
	      k++;
	    }
	    lstrcpy(&impbuff[k],"::ord_");
	    lstrcat(impbuff,inum);
	    newimpname=new char[lstrlen(impbuff)+1];
	    lstrcpy(newimpname,impbuff);
	    t.assign(options.loadaddr.segm,impaddr);
	    scheduler.addtask(dis_ordimport,priority_import,t,newimpname);
	  }
	  else
	  { t.assign(options.loadaddr.segm,impaddr);
	    scheduler.addtask(dis_import,priority_import,t,(char *)&fbuff[(*imphint)+2+pdata[k1].phys_offset-pdata[k1].rva]);
	  }
	  t.assign(options.loadaddr.segm,peh->image_base+(*imphint));
	  scheduler.addtask(dis_dataword,priority_data,t,NULL);
	  scheduler.addtask(dis_datastring,priority_data,t+2,NULL);
	  t.assign(options.loadaddr.segm,impaddr);
	  scheduler.addtask(dis_datadword,priority_data,t,NULL);
	  t.assign(options.loadaddr.segm,impaddr2);
	  scheduler.addtask(dis_datadword,priority_data,t,NULL);
	  imphint++;
	  impaddr+=4;
	  impaddr2+=4;
	}
	t.assign(options.loadaddr.segm,impaddr);
	scheduler.addtask(dis_datadword,priority_data,t,NULL);
	t.assign(options.loadaddr.segm,impaddr2);
	scheduler.addtask(dis_datadword,priority_data,t,NULL);
	j++;
      }
      t.assign(options.loadaddr.segm,
	peh->image_base+peh->importtable_rva+j*sizeof(struct peimportdirentry));
      scheduler.addtask(dis_datadword,priority_data,t,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+4,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+8,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+12,NULL);
      scheduler.addtask(dis_datadword,priority_data,t+16,NULL);
    }
    if(pdata[i].rva==peh->tls_rva)
      peobjdone=true; // tls info
    if((pdata[i].rva==peh->resourcetable_rva) // resource info
      ||((peh->resourcetable_rva>pdata[i].rva)&&(peh->resourcetable_rva<pdata[i].rva+pdata[i].phys_size)))
    { // RESOURCE_DATA;
      if((pdata[i].phys_size)&&(options.loadresources))
      { resdir=(perestable *)&fbuff[pdata[i].phys_offset+peh->resourcetable_rva-pdata[i].rva];
	pdatarva=peh->resourcetable_rva;  // bugfix  build 14
	rawdata=(byte *)resdir;
	numitems=resdir->numnames+resdir->numids;
	rentry=(struct perestableentry *)(resdir+1);
	while(numitems)
	{ if((rentry->id)&0x80000000)
	  { impname=rawdata+((rentry->id)&0x7fffffff);
	    clen=((word *)impname)[0];
	    WideCharToMultiByte(CP_ACP,0,(const wchar_t *)(impname+2),clen,impbuff,100,NULL,NULL);
	    impbuff[clen]=0;
	  }
	  else
	  { switch(rentry->id)
	    { case 1:
		lstrcpy(impbuff,"Cursor");
		break;
	      case 2:
		lstrcpy(impbuff,"Bitmap");
		break;
	      case 3:
		lstrcpy(impbuff,"Icon");
		break;
	      case 4:
		lstrcpy(impbuff,"Menu");
		break;
	      case 5:
		lstrcpy(impbuff,"Dialog");
		break;
	      case 6:
		lstrcpy(impbuff,"String Table");
		break;
	      case 7:
		lstrcpy(impbuff,"Font Directory");
		break;
	      case 8:
		lstrcpy(impbuff,"Font");
		break;
	      case 9:
		lstrcpy(impbuff,"Accelerators");
		break;
	      case 10:
		lstrcpy(impbuff,"Unformatted Resource Data");
		break;
	      case 11:
		lstrcpy(impbuff,"Message Table");
		break;
	      case 12:
		lstrcpy(impbuff,"Group Cursor");
		break;
	      case 14:
		lstrcpy(impbuff,"Group Icon");
		break;
	      case 16:
		lstrcpy(impbuff,"Version Information");
		break;
	      case 0x2002:
		lstrcpy(impbuff,"New Bitmap");
		break;
	      case 0x2004:
		lstrcpy(impbuff,"New Menu");
		break;
	      case 0x2005:
		lstrcpy(impbuff,"New Dialog");
		break;
	      default:
		lstrcpy(impbuff,"User Defined Id:");
		numtmp=rentry->id&0x7fffffff;
		wsprintf(inum,"%02lx",numtmp);
		lstrcat(impbuff,inum);
		break;
	    }
	  }
	  if(rentry->offset&0x80000000)
	  { subdirsummary(rawdata+((rentry->offset)&0x7fffffff),impbuff,peh->image_base,rentry->id);
	  }
	  else
	  { leafnodesummary(rawdata+((rentry->offset)&0x7fffffff),impbuff,peh->image_base,0);
	  }
	  rentry++;
	  numitems--;
	}
      }
      if(pdata[i].rva==peh->resourcetable_rva)
	peobjdone=true;
    }
    if(pdata[i].rva==peh->fixuptable_rva) // fixup info
    { per=(perelocheader *)&fbuff[pdata[i].phys_offset];
      while(per->rva)
      { rdata=(word *)per+sizeof(perelocheader)/2;
	numrelocs=(per->len-sizeof(perelocheader))/2;
	while((numrelocs)&&(rdata[0]))
	{ t.assign(options.loadaddr.segm,((dword)(rdata[0])&0x0fff)+per->rva+peh->image_base);
	  reloc->addreloc(t,RELOC_NONE);
	  rdata++;
	  numrelocs--;
	}
	per=(perelocheader *)((byte *)(per)+per->len);
      }
      peobjdone=true;
    }
    if(pdata[i].rva==peh->debugtable_rva) // debug info
    { // DEBUG_DATA;
      if((pdata[i].phys_size)&&(options.loaddebug))
      { sseg.offs=pdata[i].rva+peh->image_base;
	dta->addseg(sseg,pdata[i].phys_size,&fbuff[pdata[i].phys_offset],debugdata,NULL);
      }
      peobjdone=true;
    }
    if((pdata[i].obj_flags&0x40)&&(!(pdata[i].obj_flags&0x20))&&(!peobjdone))
    { // INIT_DATA;
      if((pdata[i].phys_size)&&(options.loaddata))
      { sseg.offs=pdata[i].rva+peh->image_base;
	dta->addseg(sseg,pdata[i].phys_size,&fbuff[pdata[i].phys_offset],data32,NULL);
      }
      if((pdata[i].virt_size>pdata[i].phys_size)&&(options.loaddata))
      { sseg.offs=pdata[i].rva+peh->image_base+pdata[i].phys_size;
	uinit=new byte[pdata[i].virt_size-pdata[i].phys_size];
	for(j=0;j<pdata[i].virt_size-pdata[i].phys_size;j++)
	  uinit[j]=0;
	dta->addseg(sseg,pdata[i].virt_size-pdata[i].phys_size,uinit,uninitdata,NULL);
      }
    }
    else if((pdata[i].obj_flags&0x80)&&(!peobjdone))
    { // UNINIT_DATA;
      if(options.loaddata)
      { sseg.offs=pdata[i].rva+peh->image_base;
	uinit=new byte[pdata[i].virt_size];
	for(j=0;j<pdata[i].virt_size;j++)
	  uinit[j]=0;
	dta->addseg(sseg,pdata[i].virt_size,uinit,uninitdata,NULL);
      }
    }
    else if(!peobjdone)
    { // CODE_DATA;
      if(pdata[i].phys_size)
      { sseg.offs=pdata[i].rva+peh->image_base;
	dta->addseg(sseg,pdata[i].phys_size,&fbuff[pdata[i].phys_offset],code32,NULL);
	dta->possibleentrycode(sseg);
      }
    }
    // default start addr=first seg, in the case of no entry point
    // (eg some dll files). added version 2.20
    if(!start_addr.segm)
    { start_addr.assign(options.loadaddr.segm,pdata[i].rva+peh->image_base);
      cvd->setcuraddr(start_addr);
    }
  }
  start_addr.assign(options.loadaddr.segm,peh->entrypoint_rva+peh->image_base);
  cvd->setcuraddr(start_addr);
  scheduler.addtask(dis_code,priority_definitecode,start_addr,NULL);
  scheduler.addtask(nameloc,priority_nameloc,start_addr,"start");
  scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
* mzcmp									*
* - short comparison routine used in a qsort of relocations in dos mz	*
*   executable files							*
************************************************************************/
int mzcmp(const void *a1,const void *a2)
{ if(((word *)a1)[0]<((word *)a2)[0])
    return -1;
  if(((word *)a1)[0]>((word *)a2)[0])
    return 1;
  return 0;
}

/************************************************************************
* readmzfile								*
* - standard dos mz-executable file reader.				*
* - fairly basic at the moment, as it is simply a load, and a better	*
*   analysis of d_seg is required (in fact Borg needs more work on	*
*   segmentation all round.						*
************************************************************************/
void fileloader::readmzfile(dword fsize)
{ mzheader *mzh;
  dword fs;
  byte *roffs;
  byte *poffs;
  word nrelocs,nr;
  word *ritem;
  word *rchange;
  word *rtable;
  lptr sseg,tseg;  // current segment limits
  lptr ip;
  dword saddr,taddr,ipaddr;
  options.loadaddr.offs=0;
  mzh=(mzheader *)fbuff;
  fs=(mzh->numpages-1)*512L+mzh->numbytes;
  if(fs>fsize)
    fs=fsize;
  fs-=mzh->headersize*16L;
  roffs=fbuff+mzh->relocoffs;
  poffs=fbuff+mzh->headersize*16L;
  nrelocs=mzh->numrelocs;
  if(nrelocs)
    rtable=new word[nrelocs];
  if(!nrelocs)
  { MessageBox(MainWnd,"Relocation table is empty\nThis file is probably packed"
    "\nBorg will not be able to create the segments properly","Borg Warning",MB_OK|MB_ICONEXCLAMATION);
  }
  while(nrelocs)
  { ritem=(word *)(&roffs[(mzh->numrelocs-nrelocs)*4L]);
    if((ritem[0])||(ritem[1]))
    { rchange=(word *)(&poffs[ritem[0]+ritem[1]*16L]);
      rchange[0]+=(word)options.loadaddr.segm;
      rtable[mzh->numrelocs-nrelocs]=rchange[0];
    }
    else
      rtable[mzh->numrelocs-nrelocs]=options.loadaddr.segm;
    nrelocs--;
  }
  qsort(rtable,mzh->numrelocs,2,mzcmp);
  sseg=options.loadaddr;
  options.dseg=options.loadaddr.segm;	// need to look for better value for dseg later
  ip=options.loadaddr;
  ipaddr=(((word)mzh->csip)+((word)(mzh->csip/0x10000L)+options.loadaddr.segm)*16L+options.loadaddr.offs)&0xfffff;
  for(nrelocs=0;nrelocs<mzh->numrelocs;nrelocs++)
  { if(rtable[nrelocs]!=sseg.segm)
    { tseg.assign(rtable[nrelocs],0);
      saddr=sseg.segm*16L+sseg.offs;
      taddr=tseg.segm*16L+tseg.offs;
      if((ipaddr>=saddr)&&(ipaddr<taddr))
      { ip.assign(sseg.segm,ipaddr-ip.segm*16L);
      }
      if((saddr<taddr)&&(sseg.segm>=options.loadaddr.segm))
      { dta->addseg(sseg,taddr-saddr,fbuff+mzh->headersize*16
	  +(sseg.segm-options.loadaddr.segm)*16L,code16,NULL);
	dta->possibleentrycode(sseg);
	// go through the reloc items, check if any lie in the seg
	// if they do - add to reloc entries.
	for(nr=0;nr<mzh->numrelocs;nr++)
	{ ritem=(word *)(&roffs[(mzh->numrelocs-nr)*4L]);
	  if((ritem[0])||(ritem[1]))
	  { rchange=(word *)(&poffs[ritem[0]+ritem[1]*16L]);
	    if(((byte *)rchange>=fbuff+mzh->headersize*16+(sseg.segm-options.loadaddr.segm)*16L)
	      &&((byte *)rchange<fbuff+mzh->headersize*16+(sseg.segm-options.loadaddr.segm)*16L+taddr-saddr))
	      reloc->addreloc(sseg+(dword)((byte *)rchange-
		(fbuff+mzh->headersize*16+(sseg.segm-options.loadaddr.segm)*16L)),RELOC_SEG);
	  }
	}
	sseg.segm=tseg.segm;
      }
    }
  }
  if((sseg.segm-options.loadaddr.segm)*16UL<fs)
  { saddr=sseg.segm*16L+sseg.offs;
    if(ipaddr>=saddr)
    { ip.assign(sseg.segm,ipaddr-ip.segm*16L);
    }
    dta->addseg(sseg,fs-(sseg.segm-options.loadaddr.segm)*16L,
      fbuff+mzh->headersize*16+(sseg.segm-options.loadaddr.segm)*16L,code16,NULL);
    for(nr=0;nr<mzh->numrelocs;nr++)
    { ritem=(word *)(&roffs[(mzh->numrelocs-nr)*4L]);
      if((ritem[0])||(ritem[1]))
      { rchange=(word *)(&poffs[ritem[0]+ritem[1]*16L]);
	if(((byte *)rchange>=fbuff+mzh->headersize*16+(sseg.segm-options.loadaddr.segm)*16L)
	  &&((byte *)rchange<fbuff+mzh->headersize*16+fs))
	  reloc->addreloc(sseg+(dword)((byte *)rchange-
	    (fbuff+mzh->headersize*16+(sseg.segm-options.loadaddr.segm)*16L)),RELOC_SEG);
      }
    }
    dta->possibleentrycode(sseg);
  }
  // need to search for dseg better value.
  options.mode16=true;
  options.mode32=false;
  cvd->setcuraddr(ip);
  scheduler.addtask(dis_code,priority_definitecode,ip,NULL);
  scheduler.addtask(nameloc,priority_nameloc,ip,"start");
  scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
  if(mzh->numrelocs)
    delete rtable;
}

/************************************************************************
* readlefile								*
* - to be written yet							*
************************************************************************/
void fileloader::readlefile(void)
{
}

/************************************************************************
* readnefile								*
* - NE = new executable = old windows 16-bit format.			*
* - this is partially written but needs much more work on imports,	*
*   exports, etc							*
************************************************************************/
void fileloader::readnefile(dword neoffs)
{ neheader *neh;
  byte *nestart,*importnames/*,*modoffsets*/;
  word nsegs;
  nesegtable *nesegt;
  int i,j,k;
  lptr sseg,iaddr,inum;
  dword slen,soffs;
  word numrelocs;
  word *stable;
  nesegtablereloc *reloctable;
  char iname[80];
  options.dseg=options.loadaddr.segm;
  sseg.assign(options.loadaddr.segm,0);
  nestart=&fbuff[neoffs];
  neh=(neheader *)nestart;
  if(!neh->csip)
  { MessageBox(MainWnd,"No entry point to executable - assume that Executable"
      "is a resource only\nUse a resource viewer","Borg Warning",MB_OK|MB_ICONEXCLAMATION);
    CloseHandle(efile);
    efile=INVALID_HANDLE_VALUE;
    exetype=0;
    return;
  }
  nsegs=neh->numsegs;
  stable=new word[nsegs];
  nesegt=(nesegtable *)(nestart+neh->offs_segments);
  importnames=(byte *)(nestart+neh->offs_imports);
/*  modoffsets=(byte *)(nestart+neh->offs_module); */
  // add segments
  for(i=0;i<nsegs;i++)
  { slen=nesegt[i].seglength;
    if(!slen)
      slen=0x10000;
    soffs=nesegt[i].sectoroffs;
    // added uninit data borg 2.20
    if(soffs)
    { if(nesegt[i].segflags&1)
      { dta->addseg(sseg,slen,&fbuff[soffs<<(dword)neh->shiftcount],data16,NULL);
	options.dseg=sseg.segm;
      }
      else
      { dta->addseg(sseg,slen,&fbuff[soffs<<(dword)neh->shiftcount],code16,NULL);
	dta->possibleentrycode(sseg);
      }
    }
    else
      dta->addseg(sseg,slen,NULL,uninitdata,NULL); // uninit data
    stable[i]=sseg.segm;
    sseg.segm+=(word)((slen+15)/16L);
  }
  // relocate data
  // approach to imports:
  // - start with a new segment 0xffff, to be created later, size 0.
  // - for each import, if its an ordinal add it at the current addr in the import segment,
  // - and increase the size of the segment, name it = name+ordinal num
  // - otherwise name=importnames table name, check for if it is already an import
  // - and only add if necessary.
  // - finally create the segment at the end.
  iaddr.segm=0xffff;
  inum.segm=0xffff;
  iaddr.offs=0;
  for(i=0;i<nsegs;i++)
  { slen=nesegt[i].seglength;
    if(!slen)
      slen=0x10000;
    soffs=nesegt[i].sectoroffs;
    if((nesegt[i].segflags&100)&&(soffs))
    { // reloc data present
      numrelocs=((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+slen])[0];
      reloctable=(nesegtablereloc *)&fbuff[(soffs<<(dword)neh->shiftcount)+slen+2];
      for(j=0;j<numrelocs;j++)
      { switch(reloctable[j].reloctype)
	{ case 0:      //low byte
	    break;
	  case 2:      //16bit selector
	    if((!reloctable[j].relocsort)&&(reloctable[j].index<0xff))
	    { ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs])[0]=stable[reloctable[j].index-1];
	    }
	    break;
	  case 3:      //32bit pointer
	    if((!reloctable[j].relocsort)&&(reloctable[j].index<0xff))
	    { ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs+2])[0]=stable[reloctable[j].index-1];
	      ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs])[0]=reloctable[j].indexoffs;
	    }
	    else if(reloctable[j].relocsort==2) // import by name
	    { for(k=0;(k<importnames[reloctable[j].indexoffs])&&(k<79);k++)
	      { iname[k]=importnames[reloctable[j].indexoffs+1+k];
		iname[k+1]=0;
	      }
	      inum.offs=import->getoffsfromname(iname);
	      if(!inum.offs)
	      { iaddr++;
		import->addname(iaddr,iname);
		inum.offs=iaddr.offs;
	      }
	      ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs+2])[0]=inum.segm;
	      ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs])[0]=(word)inum.offs;
       }
	    break;
	  case 5:      //16bit offset
	    if((!reloctable[j].relocsort)&&(reloctable[j].index<0xff))
	    { ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs])[0]=reloctable[j].indexoffs;
	    }
	    break;
	  case 11:     //48bit pointer
	    if((!reloctable[j].relocsort)&&(reloctable[j].index<0xff))
	    { ((word *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs+4])[0]=stable[reloctable[j].index-1];
	      ((dword *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs])[0]=reloctable[j].indexoffs;
	    }
	    break;
	  case 13:     //32bit offset
	    if((!reloctable[j].relocsort)&&(reloctable[j].index<0xff))
	    { ((dword *)&fbuff[(soffs<<(dword)neh->shiftcount)+reloctable[j].segm_offs])[0]=reloctable[j].indexoffs;
	    }
	    break;
	  default:
	    break;
	}
      }
    }
  }
  inum.offs=0;
  if(iaddr.offs)
    dta->addseg(inum,iaddr.offs+1,NULL,uninitdata,"Import Segment <Borg>");
  // set up disassembly
  options.loadaddr.assign(stable[(neh->csip>>16)-1],neh->csip&0xffff);
  cvd->setcuraddr(options.loadaddr);
  scheduler.addtask(dis_code,priority_definitecode,options.loadaddr,NULL);
  scheduler.addtask(nameloc,priority_nameloc,options.loadaddr,"start");
  scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
  delete stable;
}

/************************************************************************
* reados2file								*
* - not written yet
************************************************************************/
void fileloader::reados2file(void)
{
}

/************************************************************************
* readbinfile								*
* - reads a file as a flat binary file, so in effect we can load more	*
*   or less anything and do some analysis				*
************************************************************************/
void fileloader::readbinfile(dword fsize)
{ options.mode32=!options.mode16;
  options.dseg=options.loadaddr.segm;
  dta->addseg(options.loadaddr,fsize,fbuff,options.mode32 ? code32:code16,NULL);
  dta->possibleentrycode(options.loadaddr);
  cvd->setcuraddr(options.loadaddr);
  scheduler.addtask(dis_code,priority_definitecode,options.loadaddr,NULL);
  scheduler.addtask(nameloc,priority_nameloc,options.loadaddr,"start");
  scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
* getexetype								*
* - returns the exe type, external class interface function		*
************************************************************************/
int fileloader::getexetype(void)
{ return exetype;
}

/************************************************************************
* setexetype								*
* - sets the exe type, external class interface function		*
************************************************************************/
void fileloader::setexetype(int etype)
{ exetype=etype;
}

/************************************************************************
* subdirsummary								*
* - this is part of the resource analysis for PE files. Resources are	*
*   held in a tree type format consisting of subdirs and leafnodes.	*
************************************************************************/
void fileloader::subdirsummary(byte *data,char *impname,dword image_base,dword rtype)
{ struct perestable *resdir;
  struct perestableentry *rentry;
  unsigned char *name;
  char nbuff[100],nbuff2[100],inum[10];
  int clen;
  dword numtmp;
  unsigned long numitems;
  resdir=(struct perestable *)data;
  numitems=resdir->numnames+resdir->numids;
  rentry=(struct perestableentry *)(resdir+1);
  while(numitems)
  { if(rentry->id&0x80000000)
    { name=rawdata+((rentry->id)&0x7fffffff);
      clen=((short int *)name)[0];
      WideCharToMultiByte(CP_ACP,0,(const wchar_t *)(name+2),clen,nbuff,100,NULL,NULL);
      nbuff[clen]=0;
      if(impname!=NULL)
      { lstrcpy(nbuff2,nbuff);
	lstrcpy(nbuff,impname);
	lstrcat(nbuff," ");
	lstrcat(nbuff,nbuff2);
      }
    }
    else
    { numtmp=rentry->id&0x7fffffff;
      wsprintf(inum,"%02lx",numtmp);
      lstrcpy(nbuff,impname);
      lstrcat(nbuff," Id:");
      lstrcat(nbuff,inum);
    }
    if(rentry->offset&0x80000000)
      leaf2summary(rawdata+((rentry->offset)&0x7fffffff),nbuff,image_base,rtype);
    else
      leafnodesummary(rawdata+((rentry->offset)&0x7fffffff),nbuff,image_base,rtype);
    rentry++;
    numitems--;
  }
}

/************************************************************************
* leaf2summary								*
* - PE resource analysis of leaf nodes					*
************************************************************************/
void fileloader::leaf2summary(byte *data,char *name,dword image_base,dword rtype)
{ struct perestable *resdir;
  struct perestableentry *rentry;
  unsigned long numitems;
  resdir=(struct perestable *)data;
  numitems=resdir->numnames+resdir->numids;
  rentry=(struct perestableentry *)(resdir+1);
  while(numitems)
  { leafnodesummary(rawdata+((rentry->offset)&0x7fffffff),name,image_base,rtype);
    rentry++;
    numitems--;
  }
}

/************************************************************************
* leafnodesummary							*
* - analysis of a leaf node in a PE resource table			*
* - detailed analysis of dialogs and string tables is done at the	*
*   moment								*
************************************************************************/
void fileloader::leafnodesummary(byte *data,char *resname,dword image_base,dword rtype)
{ struct peleafnode *leaf;
  char *rname;
  lptr t;
  leaf=(struct peleafnode *)data;
  t.assign(options.loadaddr.segm,leaf->datarva+image_base);
  // bugfix to third arg - build 14
  dta->addseg(t,leaf->size,&rawdata[leaf->datarva-pdatarva],resourcedata,resname);
  switch(rtype)
  { case 5: // dialog
      rname=new char[lstrlen(resname)+1];
      lstrcpy(rname,resname);
      scheduler.addtask(dis_dialog,priority_data,t,rname);
      break;
    case 6: // stringtable
      rname=new char[lstrlen(resname)+1];
      lstrcpy(rname,resname);
      scheduler.addtask(dis_stringtable,priority_data,t,rname);
      break;
    default:
      break;
  }
}


Detected encoding: ASCII (7 bit)2