//					IMPORTS.CPP

#include <windows.h>

#include "imports.h"
#include "pefiles.h"
#include "disasm.h"
#include "dasm.h"
#include "textout.h"
#include "opcodes.h"

imp::imp(void)
{ HANDLE efile;
  char fname[]="borgexp.dat";
  SECURITY_ATTRIBUTES securityatt;
  DWORD num;
  BOOL found=TRUE;
  unsigned long i,j;
  securityatt.nLength=sizeof(SECURITY_ATTRIBUTES);
  securityatt.lpSecurityDescriptor=NULL;
  securityatt.bInheritHandle=FALSE;
  efile=CreateFile(fname,GENERIC_READ,1,&securityatt,OPEN_EXISTING,0,NULL);
  if(efile==INVALID_HANDLE_VALUE)found=FALSE;
  if(GetFileType(efile)!=FILE_TYPE_DISK)found=FALSE;
  if(found)
  { fsize=GetFileSize(efile,NULL);
	 exportnames=new char[fsize+1];
	 ReadFile(efile,exportnames,fsize,&num,NULL);
	 for(i=0;i<fsize;i++)
	 { if((exportnames[i]==0x0a)||(exportnames[i]==0x0d))exportnames[i]=0;
	 }
	 j=0;
	 for(i=0;i<fsize-1;i++)
	 { exportnames[j]=exportnames[i];
		if((exportnames[i]==0)&&(exportnames[i+1]==0))j--;
		j++;
	 }
	 exportnames[j]=0;
	 fsize=j;
  }
  else exportnames=NULL;
  CloseHandle(efile);
  implist=NULL;
}

imp::~imp(void)
{ struct importlist *nxt;
  while(implist)
  { nxt=implist->next;
	 delete implist->name;
	 delete implist;
	 implist=nxt;
  }
  if(exportnames!=NULL)delete exportnames;
}

void imp::summary(void)
{ struct codedata *importtable,*idata,*itable;
  struct importdirentry *impdir;
  unsigned long *imphint;
  unsigned long importrva,impaddr,datarva,thunkrva,impadd2,adr;
  unsigned char *impname,*knownname;
  unsigned long image_base;
  importtable=pe_exe.getimports();
  if(importtable==NULL)return;
  image_base=pe_exe.getimagebase();
  importrva=importtable->addr-image_base;
  adr=importtable->addr;
  impdir=(struct importdirentry *)importtable->dataptr;
  PrintBuff("");
  PrintBuff("Import Summary");
  PrintBuff("==============");
  while(impdir->firstthunkrva)
  { disassemble.hintdata(adr,OP_DD);
	 disassemble.hintdata(adr+4,OP_DD);
	 disassemble.hintdata(adr+8,OP_DD);
	 disassemble.hintdata(adr+12,OP_DD);
	 disassemble.hintdata(adr+16,OP_DD);
	 adr+=16;
	 if((impdir->namerva<importrva)||(impdir->namerva>importrva+importtable->size))
	 { idata=pe_exe.getinitdata();
		while(idata!=NULL)
		{ datarva=idata->addr-image_base;
		  if((impdir->namerva>=datarva)&&(impdir->namerva<datarva+idata->size))break;
		  idata=idata->next;
		}
		if(idata==NULL)
		{ idata=pe_exe.getcode();
		  while(idata!=NULL)
		  { datarva=idata->addr-image_base;
			 if((impdir->namerva>=datarva)&&(impdir->namerva<datarva+idata->size))break;
			 idata=idata->next;
		  }
		}
		if(idata!=NULL)
		{ impname=impdir->namerva-datarva+idata->dataptr;
		  itable=idata;
		}
	 }
	 else
	 { impname=impdir->namerva-importrva+importtable->dataptr;
		itable=importtable;
	 }
	 disassemble.hintdata(impdir->namerva+image_base,OP_DS);
	 PrintBuff("Import : %s",impname);
	 if(!impdir->originalthunkrva)thunkrva=impdir->firstthunkrva;
	 else thunkrva=impdir->originalthunkrva;
	 imphint=(unsigned long *)pe_exe.findrva(thunkrva);
	 impaddr=impdir->firstthunkrva+image_base;
	 impadd2=impdir->originalthunkrva+image_base;
	 while(*imphint)
	 { if((*imphint)&0x80000000)
		  { PrintBuff("  %lx ",impaddr);
			 LastPrintBuffEpos(15);
			 knownname=lookupimpname(impname,(unsigned long)(*imphint)&0x7fffffff);
			 if(knownname!=NULL) addtoimplist(knownname,impaddr);
			 else ordaddtoimplist(impname,(unsigned long)(*imphint)&0x7fffffff,impaddr);
		  }
		  else
		  { PrintBuff("  %lx ",impaddr);
			 LastPrintBuffEpos(15);
			 addtoimplist(itable->dataptr+(*imphint)+2-itable->addr+image_base,impaddr);
			 disassemble.hintdata((*imphint)+2+image_base,OP_DS);
		  }
		disassemble.hintdata((*imphint)+image_base,OP_DW);
		disassemble.hintdata(impaddr,OP_DD);
		disassemble.hintdata(impadd2,OP_DD);
		imphint++;
		impaddr+=4;
		impadd2+=4;
	 }
	 disassemble.hintdata(impaddr,OP_DD);
	 disassemble.hintdata(impadd2,OP_DD);
	 PrintBuff("");
	 impdir++;
  }
  disassemble.hintdata(adr,OP_DD);
  disassemble.hintdata(adr+4,OP_DD);
  disassemble.hintdata(adr+8,OP_DD);
  disassemble.hintdata(adr+12,OP_DD);
  disassemble.hintdata(adr+16,OP_DD);
}

void imp::ordaddtoimplist(unsigned char *dllname,unsigned long ordnum,unsigned long addr)
{ char buff[256];
  int i;
  i=0;
  while((dllname[i]!=0)&&(dllname[i]!='.'))
  { buff[i]=dllname[i];
	 i++;
  }
  buff[i++]=':';
  buff[i++]=':';
  wsprintf(&buff[i],"Ord%04lx",ordnum);
  addtoimplist((unsigned char *)buff,addr);
}

void imp::addtoimplist(unsigned char *name,unsigned long addr)
{ struct importlist *addit,*prev,*newone;
  unsigned char *newname,buff[256],buff2[256];
  unsigned int namelen,i,j,k,atcount,bpoint;
  BOOL brac,pointer,rpointer;
  prev=NULL;
  if(implist==NULL)
  { implist=new struct importlist;
	 addit=implist;
	 addit->next=NULL;
  }
  else
  { addit=implist;
	 while((addr>addit->addr)&&(addit->next!=NULL))
	 { prev=addit;
		addit=addit->next;
	 }
	 if(addr>addit->addr)
	 { addit->next=new struct importlist;
		addit=addit->next;
		addit->next=NULL;
	 }
	 else
	 { newone=new struct importlist;
		newone->next=addit;
		addit=newone;
		if(prev!=NULL)prev->next=newone;
		else implist=newone;
	 }
  }
  addit->addr=addr;
  atcount=0;
  i=0;
  j=0;
  brac=FALSE;
  while(name[i])
  { if(name[i]=='@')
	 { atcount++;
		if(atcount>1)
		{ buff[j++]=':';
		  buff[j++]=':';
		}
	 }
	 else if((name[i]=='$')&&(name[i+1]=='q')&&(!brac))
	 { brac=TRUE;
		bpoint=j;
		buff[j++]='(';
		i+=1;
	 }
	 else if((name[i]=='$')&&(name[i+1]=='x')&&(name[i+2]=='q')&&(!brac))
	 { brac=TRUE;
		bpoint=j;
		buff[j++]='(';
		i+=2;
	 }
	 else if(!strnicmp((char *)&name[i],"$bctr",5))
	 { k=0;
		while((buff[k]!=':')&&(k<20))
		{ buff[j++]=buff[k++];
		}
		i+=4;
	 }
	 else if(!strnicmp((char *)&name[i],"$bdtr",5))
	 { k=0;
		buff[j++]='~';
		while((buff[k]!=':')&&(k<20))
		{ buff[j++]=buff[k++];
		}
		i+=4;
	 }
	 else if(!strnicmp((char *)&name[i],"$bdla",5))
	 { strcpy((char *)&buff[j],"delete");
		j+=6;
		i+=4;
	 }
	 else if(!strnicmp((char *)&name[i],"$bnwa",5))
	 { strcpy((char *)&buff[j],"new");
		j+=3;
		i+=4;
	 }
	 else if(!strnicmp((char *)&name[i],"$bdele",6))
	 { strcpy((char *)&buff[j],"delete");
		j+=6;
		i+=5;
	 }
	 else if(!strnicmp((char *)&name[i],"$bnew",5))
	 { strcpy((char *)&buff[j],"new");
		j+=5;
		i+=4;
	 }
	 else buff[j++]=name[i];
	 i++;
  }
  if(brac)buff[j++]=')';
  buff[j]=0;
  strcpy((char *)buff2,(char *)buff);
  if(brac)
  { j=bpoint;
	 k=bpoint;
	 i=0;
	 pointer=FALSE;
	 rpointer=FALSE;
	 while(buff[j])
	 { if((buff[j]=='p')&&(!i))
		{ pointer=TRUE;
		  j++;
		}
		if((buff[j]=='r')&&(!i))
		{ rpointer=TRUE;
		  j++;
		}
		else if((buff[j]=='i')&&(!i))
		{ i=1;
		  strcpy((char *)&buff2[k],"int");
		  k+=3;
		  j+=1;
		}
		else if((buff[j]=='c')&&(!i))
		{ i=1;
		  strcpy((char *)&buff2[k],"char");
		  k+=4;
		  j+=1;
		}
		else if((buff[j]=='v')&&(!i))
		{ i=1;
		  strcpy((char *)&buff2[k],"void");
		  k+=4;
		  j+=1;
		}
		else if((buff[j]=='l')&&(!i))
		{ i=1;
		  strcpy((char *)&buff2[k],"long");
		  k+=4;
		  j+=1;
		}
		else if((buff[j]=='u')&&(buff[j+1]=='i')&&(!i))
		{ i=1;
		  strcpy((char *)&buff2[k],"uint");
		  k+=4;
		  j+=2;
		}
		else if((buff[j]==':')&&(buff[j+1]==':')&&(i))
		{ strcpy((char *)&buff2[k],"::");
		  k+=2;
		  j+=2;
		}
		else if((buff[j]=='t')&&((buff[j+1]>='0')&&(buff[j+1]<='9'))&&(!i))
		{ buff2[k++]=buff[j++];
		  buff2[k++]=buff[j++];
		  i=1;
		}
		else if(((buff[j]>='0')&&(buff[j]<='9'))&&(!i))
		{ i=buff[j]-'0';
		  j++;
		  if((buff[j]>='0')&&(buff[j]<='9'))
		  { i=i*10+buff[j]-'0';
			 j++;
		  }
		  i++;
		}
		else buff2[k++]=buff[j++];
		if(i)
		{ i--;
		  if(!i)
		  { if((pointer)&&(buff2[k-1]!=')'))buff2[k++]='*';
			 if((rpointer)&&(buff2[k-1]!=')'))buff2[k++]='&';
			 if((buff[j]!=')')&&(buff2[k-1]!=')'))
				buff2[k++]=',';
			 pointer=FALSE;
          rpointer=FALSE;
		  }
		}
	 }
	 buff2[k]=0;
  }
  namelen=strlen((char *)buff2);
  newname=new unsigned char[namelen+1];
  strcpy((char *)newname,(char *)buff2);
  addit->name=newname;
  LastPrintBuff("%s",newname);
}

BOOL imp::isimport(unsigned long address)
{ struct importlist *ilist;
  ilist=implist;
  while(ilist!=NULL)
  { if(address==ilist->addr)return TRUE;
	 ilist=ilist->next;
  }
  return FALSE;
}

void imp::printname(unsigned long address)
{ struct importlist *ilist;
  ilist=implist;
  while(ilist!=NULL)
  { if(address==ilist->addr)
	 { LastPrintBuff("%s",ilist->name);
		return;
	 }
	 ilist=ilist->next;
  }
}

unsigned char *imp::lookupimpname(unsigned char *dllname,unsigned long ordnum)
{ int i;
  char *ptr;
  BOOL found=FALSE;
  unsigned long curord;
  i=0;
  ptr=exportnames;
  if(exportnames!=NULL)
  { while(i<fsize)
	 { if(ptr[0]=='!')
		{ if(!lstrcmpi(&ptr[1],dllname))
		  { found=TRUE;
			 curord=0;
		  }
		  else found=FALSE;
		}
		i+=strlen(ptr)+1;
		ptr+=strlen(ptr)+1;
		if(found)
		{ curord=(ptr[0]<='9')?(ptr[0]-'0'):(ptr[0]-'a'+10);
		  if(ptr[1]!=' ')
		  { curord=curord*16+(ptr[1]<='9' ?ptr[1]-'0':ptr[1]-'a'+10);
			 if(ptr[2]!=' ')
			 { curord=curord*16+(ptr[2]<='9' ?ptr[2]-'0':ptr[2]-'a'+10);
				if(ptr[3]!=' ') curord=curord*16+(ptr[3]<='9' ?ptr[3]-'0':ptr[3]-'a'+10);
			 }
		  }
		}
		if((found)&&(curord==ordnum))break;
	 }
  }
  if((found)&&(curord==ordnum))
  { while(ptr[0]!=' ')ptr++;
	 return ptr+1;
  }
  else LastPrintBuff("(name not on list) ");
  return NULL;
}


