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

/************************************************************************
* database.cpp								*
* - functions for loading and saving database files			*
************************************************************************/
#include <windows.h>

#include "dasm.h"
#include "debug.h"
#include "disasm.h"
#include "gname.h"
#include "relocs.h"
#include "xref.h"
#include "data.h"
#include "exeload.h"
#include "schedule.h"
//#include "menuids.rh"
#include "resource.h"
#include "decrypt.h"

//#define _CRTDBG_MAP_ALLOC 
//#include <crtdbg.h>
/************************************************************************
* savedecryptitems							*
* - this saves the list of decryptors to the database			*
************************************************************************/
bool savedecryptitems(savefile *sf) {
 dword ndecs;
 ndecs=decrypter.numlistitems();
 decrypter.resetiterator();
 sf->Write(&ndecs,sizeof(dword));
 for (;ndecs;ndecs--) {
  if (!decrypter.write_item(sf)) return false;
 }
 return true;
}

/************************************************************************
* loaddecryptitems							*
* - here we reload the list of decryptors				*
************************************************************************/
bool loaddecryptitems(savefile *sf) {
 dword ndecs;
 if (!sf->Read(&ndecs,sizeof(dword))) return false;
 for (;ndecs;ndecs--) {
  if (!decrypter.read_item(sf)) return false;
 }
 return true;
}

/************************************************************************
* retstacksavedb							*
* - Borg keeps track of the stack even through saves. It simply saves	*
*   the full stack							*
************************************************************************/
bool retstacksavedb(savefile *sf) {
 sf->Write(&cvd->retstack.stacktop,sizeof(int));
 sf->Write(cvd->retstack.callstack,sizeof(lptr)*CALLSTACKSIZE);
 return sf->okay;
}

/************************************************************************
* retstackloaddb							*
* - reloads the stack from the saved database file			*
************************************************************************/
bool retstackloaddb(savefile *sf) {
 sf->Read(&cvd->retstack.stacktop,sizeof(int));
 sf->Read(cvd->retstack.callstack,sizeof(lptr)*CALLSTACKSIZE);
 return sf->okay;
}

/************************************************************************
* dissavedb								*
* - this routine saves the entire disassembly database to the database	*
*   save file. It converts instruction pointers into instruction uids	*
*   and converts data pointers into offsets for saving			*
************************************************************************/
bool dissavedb(savefile *sf,byte *filebuff) {
 dword ndsms;
 dsmitemsave structsave;
 dsmitem *currdsm;
 ndsms=dsm->numlistitems();
 dsm->resetiterator();
 sf->Write(&ndsms,sizeof(dword));
 for (;ndsms;ndsms--) {
  currdsm=dsm->nextiterator();
    structsave.addr=currdsm->addr;
    structsave.type=currdsm->type;
    structsave.length=currdsm->length;
    structsave.modrm=currdsm->modrm;
    structsave.mode32=currdsm->mode32;
    structsave.override=currdsm->override;
    structsave.flags=currdsm->flags;
    structsave.displayflags=currdsm->displayflags;
    if(structsave.type==dsmxref)
    { structsave.fileoffset=0;	// NULL ptrs
      structsave.tptroffset=0;
    }
    else if(structsave.type==dsmcode)
    { structsave.fileoffset=currdsm->data-filebuff;
      structsave.tptroffset=((asminstdata *)currdsm->tptr)->uniqueid;
    }
    else
    { structsave.fileoffset=lstrlen((char *)currdsm->data)+1; // strlen
      structsave.tptroffset=0; // points to str as well
    }
    sf->Write(&structsave,sizeof(dsmitemsave));
    if ((structsave.type!=dsmxref)&&(structsave.type!=dsmcode))
      sf->Write(currdsm->tptr,structsave.fileoffset);
  }
  // need to save callstack and some other stuff too.
  sf->Write(&cvd->curraddr,sizeof(lptr));
  sf->Write(&cvd->subitem,sizeof(dsmitemtype));
  sf->Write(&dsm->itables,sizeof(int));
  sf->Write(&dsm->jtables,sizeof(int));
  sf->Write(&dsm->irefs,sizeof(int));
  return retstacksavedb(sf);
}

/************************************************************************
* disloaddb								*
* - this routine loads the entire disassembly database from the save	*
*   file It converts instruction uids into the instruction pointers and *
*   converts offsets back into pointers. We have to search the assembly *
*   instructions for the uids in order to find the correct instruction. *
************************************************************************/
bool disloaddb(savefile *sf,byte *filebuff) {
 dword ndsms;
 dsmitemsave structsave;
 dsmitem *currdsm;
 int asminstctr;
 asminstdata *findasm;

 if (!sf->Read(&ndsms,sizeof(dword))) return false;
 for (;ndsms;ndsms--) {
  currdsm=new dsmitem;
  if (!sf->Read(&structsave,sizeof(dsmitemsave)))
     return false;
    currdsm->addr=structsave.addr;
    currdsm->type=structsave.type;
    currdsm->length=structsave.length;
    currdsm->modrm=structsave.modrm;
    currdsm->mode32=structsave.mode32;
    currdsm->override=structsave.override;
    currdsm->flags=structsave.flags;
    currdsm->displayflags=structsave.displayflags;
    switch (structsave.type) {
     case dsmxref: {
      currdsm->data=NULL;
      currdsm->tptr=NULL;
     }break;

     case dsmcode: {
      currdsm->data=structsave.fileoffset+filebuff;
      // now reset the tptr = asminstdata ptr (need to find it from the uniqueid)
      asminstctr=0;
      findasm=reconstruct[asminstctr];
      while((dword)(findasm[0].uniqueid/1000)!=(dword)(structsave.tptroffset/1000)) {
       asminstctr++;
       findasm=reconstruct[asminstctr];
       if (findasm==NULL){
#ifdef DEBUG
	DebugMessage("File Loader:Failed to find instruction table for %lu",structsave.tptroffset);
#endif
	return false;
       }
      }
      asminstctr=0;
      while(findasm[asminstctr].uniqueid!=structsave.tptroffset) {
       asminstctr++;
       if ((!findasm[asminstctr].instbyte)&&(!findasm[asminstctr].processor)) {
#ifdef DEBUG
	DebugMessage("File Loader:Failed to find instruction %lu",structsave.tptroffset);
#endif
	return false;
       }
      }
      currdsm->tptr=(void *)&findasm[asminstctr];
     }break;

     default: {
      currdsm->data=new byte[structsave.fileoffset];
      currdsm->tptr=currdsm->data;
     }
    }
    if (structsave.type!=dsmxref && structsave.type!=dsmcode) {
     if (!sf->Read(currdsm->tptr,structsave.fileoffset))
       return false;
    }
    dsm->addto(currdsm);
  }
  // need to save callstack and some other stuff too.
  sf->Read(&cvd->curraddr,sizeof(lptr));
  sf->Read(&cvd->subitem,sizeof(dsmitemtype));
  sf->Read(&dsm->itables,sizeof(int));
  sf->Read(&dsm->jtables,sizeof(int));
  sf->Read(&dsm->irefs,sizeof(int));
  dsm->dissettable();
  cvd->setcuraddr(cvd->curraddr);
  return retstackloaddb(sf);
}

/************************************************************************
* saverelocitems							*
* - this saves the relocs list to the database file.			*
* - we can simply save the number of items followed by each item	*
************************************************************************/
bool saverelocitems(savefile *sf) {
 dword nrels;
 nrels=reloc->numlistitems();
 reloc->resetiterator();
  // save number of reloc items
 sf->Write(&nrels,sizeof(dword));
 for(;nrels;nrels--) {
  if (!reloc->write_item(sf)) return false;
 }
 return true;
}

/************************************************************************
* loadrelocitems							*
* - this reloads the list of relocs from the database file and		*
*   constructs the list again						*
************************************************************************/
bool loadrelocitems(savefile *sf) {
 dword nrels;
  // get number of items
 if (!sf->Read(&nrels,sizeof(dword))) return false;
 for (;nrels;nrels--) {
  if (!reloc->read_item(sf)) return false;
 }
 return true;
}

/************************************************************************
* gnamesavedb								*
* - saves all the names in the list to the database file being saved.	*
*   this is in a one-pass compatible loading format. ie number of items *
*   followed by each item, and for strings the length of the string	*
*   followed by the string.						*
************************************************************************/
bool gnamesavedb(gname *gn,savefile *sf) {
 dword nexps,nlen;
 gnameitem *currexp;
 nexps=gn->numlistitems();
 gn->resetiterator();
 sf->Write(&nexps,sizeof(dword));
 for(;nexps;nexps--) {
  currexp=gn->nextiterator();
  sf->Write(&(currexp->addr),sizeof(lptr));
  nlen=lstrlen(currexp->name)+1;
  sf->Write(&nlen,sizeof(dword));
  sf->Write(currexp->name,nlen);
 }
 return true;
}

/************************************************************************
* gnameloaddb								*
* - loads the names from the database file and reconstructs the names	*
*   list								*
************************************************************************/
bool gnameloaddb(gname *gn,savefile *sf) {
 dword nexps,nlen;
 gnameitem *currexp;
 sf->Read(&nexps,sizeof(dword));
 for (;nexps;nexps--) {
  currexp=new gnameitem;
  sf->Read(&(currexp->addr),sizeof(lptr));
  sf->Read(&nlen,sizeof(dword));
  currexp->name=new char[nlen];
  sf->Read(currexp->name,nlen);
  gn->addto(currexp);
 }
 return true;
}

/************************************************************************
* savedatasegitems							*
* - we save the data segment data structures to the database file.	*
************************************************************************/
bool savedatasegitems(savefile *sf,byte *filebuff) {
 dword nsegs;
 nsegs=dta->numlistitems();
 dta->resetiterator();
 sf->Write(&nsegs,sizeof(dword));
 for (;nsegs;nsegs--) {
  if (!dta->write_item(sf,filebuff)) return false;
 }
 return true;
}

/************************************************************************
* loaddatasegitems							*
* - loads the data segment data structures in				*
************************************************************************/
bool loaddatasegitems(savefile *sf,byte *filebuff) {
 dword nsegs;
 if (!sf->Read(&nsegs,sizeof(dword))) return false;
#ifdef DEBUG
 DebugMessage("Loading %lu datasegs",nsegs);
#endif
 for (;nsegs;nsegs--) {
  if (!dta->read_item(sf,filebuff)) return false;
 }
 return true;
}

/************************************************************************
* xrefsavedb								*
* save xref list to database file, simply writes the list item out	*
* consisting of loc and ref_by, ie two addresses			*
************************************************************************/
bool xrefsavedb(savefile *sf) {
 dword nxrefs;
 xrefitem *currxref;
 nxrefs=xrefs->numlistitems();
 xrefs->resetiterator();
 sf->Write(&nxrefs,sizeof(dword));
 for(;nxrefs;nxrefs--) {
  currxref=xrefs->nextiterator();
  sf->Write(currxref,sizeof(xrefitem));
 }
 return true;
}

/************************************************************************
* xrefloaddb								*
* load xref list to database file, simply reads the list item in	*
* consisting of loc and ref_by, ie two addresses			*
* and adds it to the new list						*
************************************************************************/
bool xrefloaddb(savefile *sf) {
 dword nxrefs;
 xrefitem *currxref;
 if (!sf->Read(&nxrefs,sizeof(dword))) return false;
 for (;nxrefs;nxrefs--) {
  currxref=new xrefitem;
  if (!sf->Read(currxref,sizeof(xrefitem))) return false;
  xrefs->addto(currxref);
 }
 return true;
}

/************************************************************************
* savemessbox								*
* - A small dialog box which contains the message 'saving' to be shown	*
*   as a database file is saved						*
************************************************************************/
BOOL CALLBACK savemessbox(HWND,UINT,WPARAM,LPARAM) {
 return FALSE;
}

/************************************************************************
* savedbcoord								*
* - coordinates saving of the databases when save as database file is	*
*   chosen in Borg							*
************************************************************************/
bool savedbcoord(char *fname,char *exename, UINT FilterIndex) {
 savefile sf;
 dword flen;
 dword bver;
//  HWND sbox;
  // open file
 StatusMessage("Saving...");
//  sbox=CreateDialog(hInst,MAKEINTRESOURCE(save_box),MainWnd,savemessbox);
//--- better put that into status line! ---
 if (!sf.sopen(fname,GENERIC_WRITE,1,CREATE_ALWAYS,0,FilterIndex==FILTER_RLECOMPRESSED))
    return false;
  // save header to identify as a database file
 sf.Write("BORG",4);
  // save BORG_VERSION
 bver=BORG_VER;
 sf.Write(&bver,sizeof(bver));
 // save filename of exe file.
 flen=lstrlen(exename)+1;
 sf.Write(&flen,sizeof(dword));
 sf.Write(exename,flen);
  // save options.
 sf.Write(&options,sizeof(globaloptions));
 sf.Write(&floader.exetype,sizeof(int));
  // save segment info
 savedatasegitems(&sf,floader.fbuff);
  // save import info
 gnamesavedb(import,&sf);
  // save export info
 gnamesavedb(expt,&sf);
  // save names
 gnamesavedb(name,&sf);
  // save relocs
 saverelocitems(&sf);
  // save xrefs
 xrefsavedb(&sf);
  // save asm database
 dissavedb(&sf,floader.fbuff);
  // save decrypter list
 savedecryptitems(&sf);
 sf.flushfilewrite();
  // close file
 if (sf.okay) StatusMessage("Saved.");
 return sf.okay;
}

/************************************************************************
* loadmessbox								*
* - A small dialog box which contains the message 'loading' to be shown *
*   as a database file is loaded					*
************************************************************************/
BOOL CALLBACK loadmessbox(HWND,UINT,WPARAM,LPARAM) {
 return FALSE;
}

/************************************************************************
* loaddbcoord								*
* - coordinates loading of the databases when load database file is	*
*   chosen in Borg							*
************************************************************************/
bool loaddbcoord(LPCTSTR fname,char *exename, UINT FilterIndex) {
 savefile sf;
 dword num;
 dword flen,fsize;
 dword bver;

  // open file
 StatusMessage("Loading...");
 if (!FilterIndex) {	// unknown type? (from dropping or command line)
  DWORD id;
  HFILE f=_lopen(fname,OF_READ|OF_SHARE_DENY_NONE);
  if (f!=HFILE_ERROR) {
   _lread(f,&id,sizeof(id));
   _lclose(f);
   switch (id) {
    case MAKEFOURCC('B','O','R','G'): FilterIndex=1; break;
    case MAKEFOURCC('B','O',0x05,0x24): FilterIndex=2; break;
   }
  }
 }
//  lbox=CreateDialog(hInst,MAKEINTRESOURCE(load_box),MainWnd,loadmessbox);
  if (!sf.sopen(fname,GENERIC_READ,1,OPEN_EXISTING,0,FilterIndex==FILTER_RLECOMPRESSED)) {
   return false;
  }
  // load header check its a database file
  sf.Read(&bver,4);
  if (bver!=MAKEFOURCC('B','O','R','G')) {
   MessageBox(MainWnd,"Not A Borg Database File",fname,MB_OK|MB_ICONEXCLAMATION);
   return false;
  }
  // read BORG_VERSION
  if (!sf.Read(&bver,sizeof(bver))) return false;
  if (bver>BORG_VER) {
   MessageBox(MainWnd,"Savefile from a later version [or very early version]!",fname,MB_OK|MB_ICONEXCLAMATION);
   return false;
  }
  if (bver<BORG_VER) {
   MessageBox(MainWnd,"Warning:earlier version savefile [will attempt load]",fname,MB_OK|MB_ICONEXCLAMATION);
#ifdef DEBUG
   DebugMessage("Detected version: %d.%d Savefile",bver/100,bver%100);
#endif
  }
  // load filename of exe file.
  flen=0;
  sf.Read(&flen,sizeof(dword));
  sf.Read(exename,flen);
#ifdef DEBUG
  DebugMessage("Filename:%s",exename);
#endif
  // added 226 to allow load of older databases
  if (bver<222) {
   MessageBox(MainWnd,"Older databases are incompatible, please reuse the older version of Borg","Prior to 2.22",MB_OK|MB_ICONEXCLAMATION);
   return false;
  }
  // load options.
  sf.Read(&options,sizeof(globaloptions));
#ifdef DEBUG
  DebugMessage("Global Options Size: %d",sizeof(globaloptions));
#endif
  sf.Read(&floader.exetype,sizeof(int));
  // load exe file.
  // - any errors from here on will now be fatal, and Borg will need to exit
  floader.efile=CreateFile(exename,GENERIC_READ|GENERIC_WRITE,1,NULL,OPEN_EXISTING,0,NULL);
  if (floader.efile==INVALID_HANDLE_VALUE) {
   char *nameptr=strrchr(exename,'\\');
   if (nameptr) {
    nameptr++;		// address the file name portion
    floader.efile=CreateFile(nameptr,GENERIC_READ|GENERIC_WRITE,1,NULL,OPEN_EXISTING,0,NULL);
    if (floader.efile!=INVALID_HANDLE_VALUE) {
     lstrcpy(exename,nameptr);		// shuffle name to lower addresses
    }
   }
  }
  if(floader.efile==INVALID_HANDLE_VALUE)
  { floader.efile=CreateFile(fname,GENERIC_READ,1,NULL,OPEN_EXISTING,0,NULL);
    if(floader.efile==INVALID_HANDLE_VALUE)
    {
      MessageBox(MainWnd,"File open failed?",exename,MB_OK|MB_ICONEXCLAMATION);
      return false;
    }
    options.readonly=true;
    MessageBox(MainWnd,"Couldn't open file to disassemble.\n"
      "A copy of that file inside the database will be presented - "
      "BORG will not be able to apply any patches.\n"
      "BUG: BORG may crash soon or display garbage.",
      "Borg Message",MB_OK);
  }
  if(GetFileType(floader.efile)!=FILE_TYPE_DISK) {
    MessageBox(MainWnd,"File open failed?",exename,MB_OK|MB_ICONEXCLAMATION);
    CloseHandle(floader.efile);
    return false;
  }
  fsize=GetFileSize(floader.efile,NULL);
  floader.fbuff=new byte[fsize];
  SetFilePointer(floader.efile,0x00,NULL,FILE_BEGIN);
  if(!ReadFile(floader.efile,floader.fbuff,fsize,&num,NULL))
  {
    MessageBox(MainWnd,"File read failed?",exename,MB_OK|MB_ICONEXCLAMATION);
    CloseHandle(floader.efile);
    delete floader.fbuff;
    return false;
  }
  // load segment info
  if(!loaddatasegitems(&sf,floader.fbuff))
  {
    MessageBox(MainWnd,"Fatal Error\nSegments: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Imports");
#endif
  // load import info
  if(!gnameloaddb(import,&sf))
  {
    MessageBox(MainWnd,"Fatal Error\nImports: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Exports");
#endif
  // load export info
  if(!gnameloaddb(expt,&sf))
  {
    MessageBox(MainWnd,"Fatal Error\nExports: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Names");
#endif
  // load names
  if(!gnameloaddb(name,&sf))
  {
    MessageBox(MainWnd,"Fatal Error\nNames: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Relocs");
#endif
  // load relocs
  if(!loadrelocitems(&sf))
  {
    MessageBox(MainWnd,"Fatal Error\nRelocs: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd); 
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Xrefs");
#endif
  // load xrefs
  if(!xrefloaddb(&sf))
  {
    MessageBox(MainWnd,"Fatal Error\nXrefs: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Asm database");
#endif
  // load asm database
  if(!disloaddb(&sf,floader.fbuff))
  {
    MessageBox(MainWnd,"Fatal Error\nDatabase: File read failed?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Relocating File");
#endif
  if (!reloc->relocfile()) {
    MessageBox(MainWnd,"Fatal Error\nRelocating File",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
#ifdef DEBUG
  DebugMessage("Loading Decryptors");
#endif
  if(!loaddecryptitems(&sf))
  {
    MessageBox(MainWnd,"Fatal Error\nDecryptors:File read failed ?",fname,MB_OK|MB_ICONEXCLAMATION);
    DestroyWindow(MainWnd);
    return false;
  }
  StatusMessage("Loaded.");
  return true;
}

/************************************************************************
* savedb								*
* - the first place of call when save as database is selected.		*
* - asks the user to select a file before calling the fileloader savedb *
*   which is where the save to database is controlled from		*
************************************************************************/
bool savedb(void) {
 TCHAR szFile[MAX_PATH];
 UINT FilterIndex;
 if (scheduler.sizelist()) {
  MessageBox(MainWnd,"There are still items to process yet","Borg Warning",MB_OK|MB_ICONEXCLAMATION);
  return false;
 }
 if (getfiletosave(szFile,elemof(szFile),IDS_FILTERSAVE,FilterIndex)
 && savedbcoord(szFile,current_exe_name,FilterIndex)) {
  dsm->dirty=false;
  return true;
 }
 return false;
}

/************************************************************************
* loaddb								*
* - the first place of call when load from database is selected.	*
************************************************************************/
bool loaddb(LPCTSTR szFile, UINT FilterIndex) {
 changemenus(true);
 if (loaddbcoord(szFile,current_exe_name,FilterIndex)) {
  TCHAR buf[64];
  StatusMessage("Project Opened");
  wsprintf(buf,T("%s: %s"),winname,current_exe_name);
  SetWindowText(MainWnd,buf);
//   InThread=true;
//   ThreadHandle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,0,0,&ThreadId);
  scheduler.addtask(scrolling,priority_userrequest,nlptr,NULL);
  return true;
 }
 changemenus(false);
 MessageBox(MainWnd,"File open failed?",program_name,MB_OK|MB_ICONEXCLAMATION);
 return false;
}

Detected encoding: ASCII (7 bit)2