📄 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!=NULL)
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(mainwindow,"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);
}
/************************************************************************
* patchoep *
* - writes to the currently open file (does not check it is opened with *
* write access), given the new oep for the file is in options.oep *
* - added in Borg v2.28 *
************************************************************************/
void fileloader::patchoep(void)
{ if(exetype!=PE_EXE)
return;
peh->entrypoint_rva=options.oep.offs-peh->image_base;
patchfile((byte *)&peh->entrypoint_rva-fbuff,4,(byte *)&peh->entrypoint_rva);
}
/************************************************************************
* 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(mainwindow,"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;
dio.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;
dio.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])&&((((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])&&((((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)||((unsigned)(devhdr+devlength)>(fsize-10)))
done=true;
devhdr+=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)
{ 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[GNAME_MAXLEN+1];
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -