123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- {
- Copyright (c) 1998-2002 by Pavel
- This unit finds the export defs from PE files
- C source code of DEWIN Windows disassembler (written by A. Milukov) was
- partially used
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit impdef;
- {$ifndef STANDALONE}
- {$i fpcdefs.inc}
- {$endif}
- interface
- uses
- SysUtils;
- var
- as_name,
- ar_name : string;
- function makedef(const binname,
- {$IFDEF STANDALONE}
- textname,
- {$ENDIF}
- libname:string):longbool;
- implementation
- {$IFDEF STANDALONE}
- var
- __textname : string;
- const
- kind : array[longbool] of pchar=('',' DATA');
- {$ENDIF}
- var
- f:file;
- {$IFDEF STANDALONE}
- t:text;
- FileCreated:longbool;
- {$ENDIF}
- lname:string;
- impname:string;
- TheWord:array[0..1]of char;
- PEoffset:cardinal;
- loaded:longint;
- function DOSstubOK(var x:cardinal):longbool;
- begin
- blockread(f,TheWord,2,loaded);
- if loaded<>2 then
- DOSstubOK:=false
- else
- begin
- DOSstubOK:=TheWord='MZ';
- seek(f,$3C);
- blockread(f,x,4,loaded);
- if(loaded<>4)or(x>filesize(f))then
- DOSstubOK:=false;
- end;
- end;
- function isPE(x:longint):longbool;
- begin
- seek(f,x);
- blockread(f,TheWord,2,loaded);
- isPE:=(loaded=2)and(TheWord='PE');
- end;
- var
- cstring : array[0..127]of char;
- function GetEdata(PE:cardinal):longbool;
- type
- TObjInfo=packed record
- ObjName:array[0..7]of char;
- VirtSize,
- VirtAddr,
- RawSize,
- RawOffset,
- Reloc,
- LineNum:cardinal;
- RelCount,
- LineCount:word;
- flags:cardinal;
- end;
- var
- i:cardinal;
- ObjOfs:cardinal;
- Obj:TObjInfo;
- APE_obj,APE_Optsize:word;
- ExportRVA:cardinal;
- delta:cardinal;
- const
- IMAGE_SCN_CNT_CODE=$00000020;
- const
- {$ifdef unix}
- DirSep = '/';
- {$else}
- {$if defined(amiga) or defined(morphos)}
- DirSep = '/';
- {$else}
- DirSep = '\';
- {$endif}
- {$endif}
- var
- path:string;
- _d:dirstr;
- _n:namestr;
- _e:extstr;
- common_created:longbool;
- procedure cleardir(const s,ext:string);
- var
- ff:file;
- dir:searchrec;
- attr:word;
- begin
- findfirst(s+dirsep+ext,anyfile,dir);
- while (doserror=0) do
- begin
- assign(ff,s+dirsep+dir.name);
- GetFattr(ff,attr);
- if not((DOSError<>0)or(Attr and Directory<>0))then
- Erase(ff);
- findnext(dir);
- end;
- findclose(dir);
- end;
- procedure CreateTempDir(const s:string);
- var
- attr:word;
- ff:file;
- begin
- assign(ff,s);
- GetFattr(ff,attr);
- if DosError=0 then
- begin
- cleardir(s,'*.sw');
- cleardir(s,'*.swo');
- end
- else
- begin
- {$push} {$I-}
- mkdir(s);
- {$pop}
- if ioresult<>0 then;
- end;
- end;
- procedure call_as(const name:string);
- begin
- FlushOutput;
- ExecuteProcess(as_name,'-o '+name+'o '+name);
- end;
- procedure call_ar;
- var
- f:file;
- attr:word;
- begin
- {$IFDEF STANDALONE}
- if impname='' then
- exit;
- {$ENDIF}
- assign(f,impname);
- GetFAttr(f,attr);
- If DOSError=0 then
- erase(f);
- FlushOutput;
- ExecuteProcess(ar_name,'rs '+impname+' '+path+dirsep+'*.swo');
- cleardir(path,'*.sw');
- cleardir(path,'*.swo');
- {$push} {$I-}
- RmDir(path);
- {$pop}
- if ioresult<>0 then;
- end;
- procedure makeasm(index:cardinal;name:pchar;isData:longbool);
- type
- tt=array[1..1]of pchar;
- pt=^tt;
- const
- fn_template:array[1..24]of pchar=(
- '.section .idata$2',
- '.rva .L4',
- '.long 0,0',
- '.rva ',
- '.rva .L5',
- '.section .idata$4',
- '.L4:',
- '.rva .L6',
- '.long 0',
- '.section .idata$5',
- '.L5:',
- '.text',
- '.globl ',
- ':',
- 'jmp *.L7',
- '.balign 4,144',
- '.section .idata$5',
- '.L7:',
- '.rva .L6',
- '.long 0',
- '.section .idata$6',
- '.L6:',
- '.short 0',
- '.ascii "\000"'
- );
- var_template:array[1..19]of pchar=(
- '.section .idata$2',
- '.rva .L7',
- '.long 0,0',
- '.rva ',
- '.rva .L8',
- '.section .idata$4',
- '.L7:',
- '.rva .L9',
- '.long 0',
- '.section .idata$5',
- '.L8:',
- '.globl ',
- ':',
- '.rva .L9',
- '.long 0',
- '.section .idata$6',
- '.L9:',
- '.short 0',
- '.ascii "\000"'
- );
- __template:array[longbool]of pointer=(@fn_template,@var_template);
- common_part:array[1..5]of pchar=(
- '.balign 2,0',
- '.section .idata$7',
- '.globl ',
- ':',
- '.ascii "\000"'
- );
- posit:array[longbool,1..4]of longint=((4,13,14,24),(4,12,13,19));
- var
- template:array[longbool]of pt absolute __template;
- f:text;
- s:string;
- i:longint;
- n:string;
- common_name,asmout:string;
- __d:dirstr;
- __n:namestr;
- __x:extstr;
- begin
- if not common_created then
- begin
- common_name:='_$'+_n+'@common';
- asmout:=path+dirsep+'0.sw';
- assign(f,asmout);
- rewrite(f);
- for i:=1 to 5 do
- begin
- s:=StrPas(Common_part[i]);
- case i of
- 3:
- s:=s+common_name;
- 4:
- s:=common_name+s;
- 5:
- begin
- fsplit(lname,__d,__n,__x);
- insert(__n+__x,s,9);
- end;
- end;
- writeln(f,s);
- end;
- close(f);
- call_as(asmout);
- common_created:=true;
- end;
- n:=strpas(name);
- str(succ(index):0,s);
- asmout:=path+dirsep+s+'.sw';
- assign(f,asmout);
- rewrite(f);
- for i:=1 to posit[isData,4]do
- begin
- s:=StrPas(template[isData]^[i]);
- if i=posit[isData,1]then
- s:=s+common_name
- else if i=posit[isData,2]then
- s:=s+n
- else if i=posit[isData,3]then
- s:=n+s
- else if i=posit[isData,4]then
- insert(n,s,9);
- writeln(f,s);
- end;
- close(f);
- call_as(asmout);
- end;
- procedure ProcessEdata;
- type
- a8=array[0..7]of char;
- function GetSectionName(rva:cardinal;var Flags:cardinal):a8;
- var
- i:cardinal;
- LocObjOfs:cardinal;
- LocObj:TObjInfo;
- begin
- GetSectionName:='';
- Flags:=0;
- LocObjOfs:=APE_OptSize+PEoffset+24;
- for i:=1 to APE_obj do
- begin
- seek(f,LocObjOfs);
- blockread(f,LocObj,sizeof(LocObj));
- if(rva>=LocObj.VirtAddr)and(rva<=LocObj.VirtAddr+LocObj.RawSize)then
- begin
- GetSectionName:=a8(LocObj.ObjName);
- Flags:=LocObj.flags;
- end;
- end;
- end;
- var
- j,Fl:cardinal;
- ulongval,procEntry:cardinal;
- Ordinal:word;
- isData:longbool;
- ExpDir:packed record
- flag,
- stamp:cardinal;
- Major,
- Minor:word;
- Name,
- Base,
- NumFuncs,
- NumNames,
- AddrFuncs,
- AddrNames,
- AddrOrds:cardinal;
- end;
- begin
- with Obj do
- begin
- seek(f,RawOffset+delta);
- blockread(f,ExpDir,sizeof(ExpDir));
- fsplit(impname,_d,_n,_e);
- path:=_d+_n+'.ils';
- {$IFDEF STANDALONE}
- if impname<>'' then
- {$ENDIF}
- CreateTempDir(path);
- Common_created:=false;
- for j:=0 to pred(ExpDir.NumNames)do
- begin
- seek(f,RawOffset-VirtAddr+ExpDir.AddrOrds+j*2);
- blockread(f,Ordinal,2);
- seek(f,RawOffset-VirtAddr+ExpDir.AddrFuncs+Cardinal(Ordinal*4));
- blockread(f,ProcEntry,4);
- seek(f,RawOffset-VirtAddr+ExpDir.AddrNames+j*4);
- blockread(f,ulongval,4);
- seek(f,RawOffset-VirtAddr+ulongval);
- blockread(f,cstring,sizeof(cstring));
- {$IFDEF STANDALONE}
- if not FileCreated then
- begin
- FileCreated:=true;
- if(__textname<>'')or(impname='')then
- begin
- rewrite(t);
- writeln(t,'EXPORTS');
- end;
- end;
- {$ENDIF}
- isData:=GetSectionName(procentry,Fl)='';
- if not isData then
- isData:=Fl and IMAGE_SCN_CNT_CODE<>IMAGE_SCN_CNT_CODE;
- {$IFDEF STANDALONE}
- if(__textname<>'')or(impname='')then
- writeln(t,cstring,' @',succ(ordinal):0,' ',kind[isData]);
- if impname<>''then
- {$ENDIF}
- makeasm(j,cstring,isData);
- end;
- call_ar;
- end;
- end;
- begin
- GetEdata:=false;
- {$IFDEF STANDALONE}
- FileCreated:=false;
- {$ENDIF}
- seek(f,PE+120);
- blockread(f,ExportRVA,4);
- seek(f,PE+6);
- blockread(f,APE_Obj,2);
- seek(f,PE+20);
- blockread(f,APE_OptSize,2);
- ObjOfs:=APE_OptSize+PEoffset+24;
- for i:=1 to APE_obj do
- begin
- seek(f,ObjOfs);
- blockread(f,Obj,sizeof(Obj));
- inc(ObjOfs,sizeof(Obj));
- with Obj do
- if(VirtAddr<=ExportRva)and(ExportRva<VirtAddr+VirtSize)then
- begin
- delta:=ExportRva-VirtAddr;
- ProcessEdata;
- GetEdata:=true;
- end;
- end;
- end;
- function makedef(const binname,
- {$IFDEF STANDALONE}
- textname,
- {$ENDIF}
- libname:string):longbool;
- var
- OldFileMode:longint;
- begin
- assign(f,binname);
- {$IFDEF STANDALONE}
- FileCreated:=false;
- assign(t,textname);
- __textname:=textname;
- {$ENDIF}
- impname:=libname;
- lname:=binname;
- OldFileMode:=filemode;
- {$push} {$I-}
- filemode:=0;
- reset(f,1);
- filemode:=OldFileMode;
- {$pop}
- if IOResult<>0 then
- begin
- makedef:=false;
- exit;
- end;
- if not DOSstubOK(PEoffset)then
- makedef:=false
- else if not IsPE(PEoffset)then
- makedef:=false
- else
- makedef:=GetEdata(PEoffset);
- close(f);
- {$IFDEF STANDALONE}
- if FileCreated then
- if(textname<>'')or(impname='')then
- close(t);
- {$ENDIF}
- end;
- end.
|