impdef.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. {
  2. Copyright (c) 1998-2002 by Pavel
  3. This unit finds the export defs from PE files
  4. C source code of DEWIN Windows disassembler (written by A. Milukov) was
  5. partially used
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit impdef;
  20. {$ifndef STANDALONE}
  21. {$i fpcdefs.inc}
  22. {$endif}
  23. interface
  24. uses
  25. {$IFDEF USE_SYSUTILS}
  26. SysUtils,
  27. {$ELSE USE_SYSUTILS}
  28. Dos;
  29. {$ENDIF USE_SYSUTILS}
  30. var
  31. as_name,
  32. ar_name : string;
  33. function makedef(const binname,
  34. {$IFDEF STANDALONE}
  35. textname,
  36. {$ENDIF}
  37. libname:string):longbool;
  38. implementation
  39. {$IFDEF STANDALONE}
  40. var
  41. __textname : string;
  42. const
  43. kind : array[longbool] of pchar=('',' DATA');
  44. {$ENDIF}
  45. var
  46. f:file;
  47. {$IFDEF STANDALONE}
  48. t:text;
  49. FileCreated:longbool;
  50. {$ENDIF}
  51. lname:string;
  52. impname:string;
  53. TheWord:array[0..1]of char;
  54. PEoffset:cardinal;
  55. loaded:longint;
  56. function DOSstubOK(var x:cardinal):longbool;
  57. begin
  58. blockread(f,TheWord,2,loaded);
  59. if loaded<>2 then
  60. DOSstubOK:=false
  61. else
  62. begin
  63. DOSstubOK:=TheWord='MZ';
  64. seek(f,$3C);
  65. blockread(f,x,4,loaded);
  66. if(loaded<>4)or(x>filesize(f))then
  67. DOSstubOK:=false;
  68. end;
  69. end;
  70. function isPE(x:longint):longbool;
  71. begin
  72. seek(f,x);
  73. blockread(f,TheWord,2,loaded);
  74. isPE:=(loaded=2)and(TheWord='PE');
  75. end;
  76. var
  77. cstring : array[0..127]of char;
  78. function GetEdata(PE:cardinal):longbool;
  79. type
  80. TObjInfo=packed record
  81. ObjName:array[0..7]of char;
  82. VirtSize,
  83. VirtAddr,
  84. RawSize,
  85. RawOffset,
  86. Reloc,
  87. LineNum:cardinal;
  88. RelCount,
  89. LineCount:word;
  90. flags:cardinal;
  91. end;
  92. var
  93. i:cardinal;
  94. ObjOfs:cardinal;
  95. Obj:TObjInfo;
  96. APE_obj,APE_Optsize:word;
  97. ExportRVA:cardinal;
  98. delta:cardinal;
  99. const
  100. IMAGE_SCN_CNT_CODE=$00000020;
  101. const
  102. {$ifdef unix}
  103. DirSep = '/';
  104. {$else}
  105. {$ifdef amiga}
  106. DirSep = '/';
  107. {$else}
  108. DirSep = '\';
  109. {$endif}
  110. {$endif}
  111. var
  112. path:string;
  113. _d:dirstr;
  114. _n:namestr;
  115. _e:extstr;
  116. common_created:longbool;
  117. procedure cleardir(const s,ext:string);
  118. var
  119. ff:file;
  120. dir:searchrec;
  121. attr:word;
  122. begin
  123. findfirst(s+dirsep+ext,anyfile,dir);
  124. while (doserror=0) do
  125. begin
  126. assign(ff,s+dirsep+dir.name);
  127. GetFattr(ff,attr);
  128. if not((DOSError<>0)or(Attr and Directory<>0))then
  129. Erase(ff);
  130. findnext(dir);
  131. end;
  132. findclose(dir);
  133. end;
  134. procedure CreateTempDir(const s:string);
  135. var
  136. attr:word;
  137. ff:file;
  138. begin
  139. assign(ff,s);
  140. GetFattr(ff,attr);
  141. if DosError=0 then
  142. begin
  143. cleardir(s,'*.sw');
  144. cleardir(s,'*.swo');
  145. end
  146. else
  147. begin
  148. {$I-}
  149. mkdir(s);
  150. {$I+}
  151. if ioresult<>0 then;
  152. end;
  153. end;
  154. procedure call_as(const name:string);
  155. begin
  156. FlushOutput;
  157. {$IFDEF USE_SYSUTILS}
  158. ExecuteProcess(as_name,'-o '+name+'o '+name);
  159. {$ELSE USE_SYSUTILS}
  160. exec(as_name,'-o '+name+'o '+name);
  161. {$ENDIF USE_SYSUTILS}
  162. end;
  163. procedure call_ar;
  164. var
  165. f:file;
  166. attr:word;
  167. begin
  168. {$IFDEF STANDALONE}
  169. if impname='' then
  170. exit;
  171. {$ENDIF}
  172. assign(f,impname);
  173. GetFAttr(f,attr);
  174. If DOSError=0 then
  175. erase(f);
  176. FlushOutput;
  177. {$IFDEF USE_SYSUTILS}
  178. ExecuteProcess(ar_name,'rs '+impname+' '+path+dirsep+'*.swo');
  179. {$ELSE USE_SYSUTILS}
  180. exec(ar_name,'rs '+impname+' '+path+dirsep+'*.swo');
  181. {$ENDIF USE_SYSUTILS}
  182. cleardir(path,'*.sw');
  183. cleardir(path,'*.swo');
  184. {$i-}
  185. RmDir(path);
  186. {$i+}
  187. if ioresult<>0 then;
  188. end;
  189. procedure makeasm(index:cardinal;name:pchar;isData:longbool);
  190. type
  191. tt=array[1..1]of pchar;
  192. pt=^tt;
  193. const
  194. fn_template:array[1..24]of pchar=(
  195. '.section .idata$2',
  196. '.rva .L4',
  197. '.long 0,0',
  198. '.rva ',
  199. '.rva .L5',
  200. '.section .idata$4',
  201. '.L4:',
  202. '.rva .L6',
  203. '.long 0',
  204. '.section .idata$5',
  205. '.L5:',
  206. '.text',
  207. '.globl ',
  208. ':',
  209. 'jmp *.L7',
  210. '.balign 4,144',
  211. '.section .idata$5',
  212. '.L7:',
  213. '.rva .L6',
  214. '.long 0',
  215. '.section .idata$6',
  216. '.L6:',
  217. '.short 0',
  218. '.ascii "\000"'
  219. );
  220. var_template:array[1..19]of pchar=(
  221. '.section .idata$2',
  222. '.rva .L7',
  223. '.long 0,0',
  224. '.rva ',
  225. '.rva .L8',
  226. '.section .idata$4',
  227. '.L7:',
  228. '.rva .L9',
  229. '.long 0',
  230. '.section .idata$5',
  231. '.L8:',
  232. '.globl ',
  233. ':',
  234. '.rva .L9',
  235. '.long 0',
  236. '.section .idata$6',
  237. '.L9:',
  238. '.short 0',
  239. '.ascii "\000"'
  240. );
  241. __template:array[longbool]of pointer=(@fn_template,@var_template);
  242. common_part:array[1..5]of pchar=(
  243. '.balign 2,0',
  244. '.section .idata$7',
  245. '.globl ',
  246. ':',
  247. '.ascii "\000"'
  248. );
  249. posit:array[longbool,1..4]of longint=((4,13,14,24),(4,12,13,19));
  250. var
  251. template:array[longbool]of pt absolute __template;
  252. f:text;
  253. s:string;
  254. i:longint;
  255. n:string;
  256. common_name,asmout:string;
  257. __d:dirstr;
  258. __n:namestr;
  259. __x:extstr;
  260. begin
  261. if not common_created then
  262. begin
  263. common_name:='_$'+_n+'@common';
  264. asmout:=path+dirsep+'0.sw';
  265. assign(f,asmout);
  266. rewrite(f);
  267. for i:=1 to 5 do
  268. begin
  269. s:=StrPas(Common_part[i]);
  270. case i of
  271. 3:
  272. s:=s+common_name;
  273. 4:
  274. s:=common_name+s;
  275. 5:
  276. begin
  277. fsplit(lname,__d,__n,__x);
  278. insert(__n+__x,s,9);
  279. end;
  280. end;
  281. writeln(f,s);
  282. end;
  283. close(f);
  284. call_as(asmout);
  285. common_created:=true;
  286. end;
  287. n:=strpas(name);
  288. str(succ(index):0,s);
  289. asmout:=path+dirsep+s+'.sw';
  290. assign(f,asmout);
  291. rewrite(f);
  292. for i:=1 to posit[isData,4]do
  293. begin
  294. s:=StrPas(template[isData]^[i]);
  295. if i=posit[isData,1]then
  296. s:=s+common_name
  297. else if i=posit[isData,2]then
  298. s:=s+n
  299. else if i=posit[isData,3]then
  300. s:=n+s
  301. else if i=posit[isData,4]then
  302. insert(n,s,9);
  303. writeln(f,s);
  304. end;
  305. close(f);
  306. call_as(asmout);
  307. end;
  308. procedure ProcessEdata;
  309. type
  310. a8=array[0..7]of char;
  311. function GetSectionName(rva:cardinal;var Flags:cardinal):a8;
  312. var
  313. i:cardinal;
  314. LocObjOfs:cardinal;
  315. LocObj:TObjInfo;
  316. begin
  317. GetSectionName:='';
  318. Flags:=0;
  319. LocObjOfs:=APE_OptSize+PEoffset+24;
  320. for i:=1 to APE_obj do
  321. begin
  322. seek(f,LocObjOfs);
  323. blockread(f,LocObj,sizeof(LocObj));
  324. if(rva>=LocObj.VirtAddr)and(rva<=LocObj.VirtAddr+LocObj.RawSize)then
  325. begin
  326. GetSectionName:=a8(LocObj.ObjName);
  327. Flags:=LocObj.flags;
  328. end;
  329. end;
  330. end;
  331. var
  332. j,Fl:cardinal;
  333. ulongval,procEntry:cardinal;
  334. Ordinal:word;
  335. isData:longbool;
  336. ExpDir:packed record
  337. flag,
  338. stamp:cardinal;
  339. Major,
  340. Minor:word;
  341. Name,
  342. Base,
  343. NumFuncs,
  344. NumNames,
  345. AddrFuncs,
  346. AddrNames,
  347. AddrOrds:cardinal;
  348. end;
  349. begin
  350. with Obj do
  351. begin
  352. seek(f,RawOffset+delta);
  353. blockread(f,ExpDir,sizeof(ExpDir));
  354. fsplit(impname,_d,_n,_e);
  355. path:=_d+_n+'.ils';
  356. {$IFDEF STANDALONE}
  357. if impname<>'' then
  358. {$ENDIF}
  359. CreateTempDir(path);
  360. Common_created:=false;
  361. for j:=0 to pred(ExpDir.NumNames)do
  362. begin
  363. seek(f,RawOffset-VirtAddr+ExpDir.AddrOrds+j*2);
  364. blockread(f,Ordinal,2);
  365. seek(f,RawOffset-VirtAddr+ExpDir.AddrFuncs+Cardinal(Ordinal*4));
  366. blockread(f,ProcEntry,4);
  367. seek(f,RawOffset-VirtAddr+ExpDir.AddrNames+j*4);
  368. blockread(f,ulongval,4);
  369. seek(f,RawOffset-VirtAddr+ulongval);
  370. blockread(f,cstring,sizeof(cstring));
  371. {$IFDEF STANDALONE}
  372. if not FileCreated then
  373. begin
  374. FileCreated:=true;
  375. if(__textname<>'')or(impname='')then
  376. begin
  377. rewrite(t);
  378. writeln(t,'EXPORTS');
  379. end;
  380. end;
  381. {$ENDIF}
  382. isData:=GetSectionName(procentry,Fl)='';
  383. if not isData then
  384. isData:=Fl and IMAGE_SCN_CNT_CODE<>IMAGE_SCN_CNT_CODE;
  385. {$IFDEF STANDALONE}
  386. if(__textname<>'')or(impname='')then
  387. writeln(t,cstring,' @',succ(ordinal):0,' ',kind[isData]);
  388. if impname<>''then
  389. {$ENDIF}
  390. makeasm(j,cstring,isData);
  391. end;
  392. call_ar;
  393. end;
  394. end;
  395. begin
  396. GetEdata:=false;
  397. {$IFDEF STANDALONE}
  398. FileCreated:=false;
  399. {$ENDIF}
  400. seek(f,PE+120);
  401. blockread(f,ExportRVA,4);
  402. seek(f,PE+6);
  403. blockread(f,APE_Obj,2);
  404. seek(f,PE+20);
  405. blockread(f,APE_OptSize,2);
  406. ObjOfs:=APE_OptSize+PEoffset+24;
  407. for i:=1 to APE_obj do
  408. begin
  409. seek(f,ObjOfs);
  410. blockread(f,Obj,sizeof(Obj));
  411. inc(ObjOfs,sizeof(Obj));
  412. with Obj do
  413. if(VirtAddr<=ExportRva)and(ExportRva<VirtAddr+VirtSize)then
  414. begin
  415. delta:=ExportRva-VirtAddr;
  416. ProcessEdata;
  417. GetEdata:=true;
  418. end;
  419. end;
  420. end;
  421. function makedef(const binname,
  422. {$IFDEF STANDALONE}
  423. textname,
  424. {$ENDIF}
  425. libname:string):longbool;
  426. var
  427. OldFileMode:longint;
  428. begin
  429. assign(f,binname);
  430. {$IFDEF STANDALONE}
  431. FileCreated:=false;
  432. assign(t,textname);
  433. __textname:=textname;
  434. {$ENDIF}
  435. impname:=libname;
  436. lname:=binname;
  437. OldFileMode:=filemode;
  438. {$I-}
  439. filemode:=0;
  440. reset(f,1);
  441. filemode:=OldFileMode;
  442. {$I+}
  443. if IOResult<>0 then
  444. begin
  445. makedef:=false;
  446. exit;
  447. end;
  448. if not DOSstubOK(PEoffset)then
  449. makedef:=false
  450. else if not IsPE(PEoffset)then
  451. makedef:=false
  452. else
  453. makedef:=GetEdata(PEoffset);
  454. close(f);
  455. {$IFDEF STANDALONE}
  456. if FileCreated then
  457. if(textname<>'')or(impname='')then
  458. close(t);
  459. {$ENDIF}
  460. end;
  461. end.