EXE.pm 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. #------------------------------------------------------------------------------
  2. # File: EXE.pm
  3. #
  4. # Description: Read meta information of various executable file formats
  5. #
  6. # Revisions: 2008/08/28 - P. Harvey Created
  7. # 2011/07/12 - P. Harvey Added CHM (ok, not EXE, but it fits here)
  8. #
  9. # References: 1) http://www.openwatcom.org/ftp/devel/docs/pecoff.pdf
  10. # 2) http://support.microsoft.com/kb/65122
  11. # 3) http://www.opensource.apple.com
  12. # 4) http://www.skyfree.org/linux/references/ELF_Format.pdf
  13. # 5) http://msdn.microsoft.com/en-us/library/ms809762.aspx
  14. # 6) http://code.google.com/p/pefile/
  15. # 7) http://www.codeproject.com/KB/DLL/showver.aspx
  16. #------------------------------------------------------------------------------
  17. package Image::ExifTool::EXE;
  18. use strict;
  19. use vars qw($VERSION);
  20. use Image::ExifTool qw(:DataAccess :Utils);
  21. $VERSION = '1.12';
  22. sub ProcessPEResources($$);
  23. sub ProcessPEVersion($$);
  24. # PE file resource types (ref 6)
  25. my %resourceType = (
  26. 1 => 'Cursor',
  27. 2 => 'Bitmap',
  28. 3 => 'Icon',
  29. 4 => 'Menu',
  30. 5 => 'Dialog',
  31. 6 => 'String',
  32. 7 => 'Font Dir',
  33. 8 => 'Font',
  34. 9 => 'Accelerator',
  35. 10 => 'RC Data',
  36. 11 => 'Message Table',
  37. 12 => 'Group Cursor',
  38. 14 => 'Group Icon',
  39. 16 => 'Version',
  40. 17 => 'Dialog Include',
  41. 19 => 'Plug-n-Play',
  42. 20 => 'VxD',
  43. 21 => 'Animated Cursor',
  44. 22 => 'Animated Icon',
  45. 23 => 'HTML',
  46. 24 => 'Manifest',
  47. );
  48. my %languageCode = (
  49. '0000' => 'Neutral',
  50. '007F' => 'Invariant',
  51. '0400' => 'Process default',
  52. '0401' => 'Arabic',
  53. '0402' => 'Bulgarian',
  54. '0403' => 'Catalan',
  55. '0404' => 'Chinese (Traditional)',
  56. '0405' => 'Czech',
  57. '0406' => 'Danish',
  58. '0407' => 'German',
  59. '0408' => 'Greek',
  60. '0409' => 'English (U.S.)',
  61. '040A' => 'Spanish (Castilian)',
  62. '040B' => 'Finnish',
  63. '040C' => 'French',
  64. '040D' => 'Hebrew',
  65. '040E' => 'Hungarian',
  66. '040F' => 'Icelandic',
  67. '0410' => 'Italian',
  68. '0411' => 'Japanese',
  69. '0412' => 'Korean',
  70. '0413' => 'Dutch',
  71. '0414' => 'Norwegian (Bokml)',
  72. '0415' => 'Polish',
  73. '0416' => 'Portuguese (Brazilian)',
  74. '0417' => 'Rhaeto-Romanic',
  75. '0418' => 'Romanian',
  76. '0419' => 'Russian',
  77. '041A' => 'Croato-Serbian (Latin)',
  78. '041B' => 'Slovak',
  79. '041C' => 'Albanian',
  80. '041D' => 'Swedish',
  81. '041E' => 'Thai',
  82. '041F' => 'Turkish',
  83. '0420' => 'Urdu',
  84. # 0421-0493 ref 6
  85. '0421' => 'Indonesian',
  86. '0422' => 'Ukrainian',
  87. '0423' => 'Belarusian',
  88. '0424' => 'Slovenian',
  89. '0425' => 'Estonian',
  90. '0426' => 'Latvian',
  91. '0427' => 'Lithuanian',
  92. '0428' => 'Maori',
  93. '0429' => 'Farsi',
  94. '042a' => 'Vietnamese',
  95. '042b' => 'Armenian',
  96. '042c' => 'Azeri',
  97. '042d' => 'Basque',
  98. '042e' => 'Sorbian',
  99. '042f' => 'Macedonian',
  100. '0430' => 'Sutu',
  101. '0431' => 'Tsonga',
  102. '0432' => 'Tswana',
  103. '0433' => 'Venda',
  104. '0434' => 'Xhosa',
  105. '0435' => 'Zulu',
  106. '0436' => 'Afrikaans',
  107. '0437' => 'Georgian',
  108. '0438' => 'Faeroese',
  109. '0439' => 'Hindi',
  110. '043a' => 'Maltese',
  111. '043b' => 'Saami',
  112. '043c' => 'Gaelic',
  113. '043e' => 'Malay',
  114. '043f' => 'Kazak',
  115. '0440' => 'Kyrgyz',
  116. '0441' => 'Swahili',
  117. '0443' => 'Uzbek',
  118. '0444' => 'Tatar',
  119. '0445' => 'Bengali',
  120. '0446' => 'Punjabi',
  121. '0447' => 'Gujarati',
  122. '0448' => 'Oriya',
  123. '0449' => 'Tamil',
  124. '044a' => 'Telugu',
  125. '044b' => 'Kannada',
  126. '044c' => 'Malayalam',
  127. '044d' => 'Assamese',
  128. '044e' => 'Marathi',
  129. '044f' => 'Sanskrit',
  130. '0450' => 'Mongolian',
  131. '0456' => 'Galician',
  132. '0457' => 'Konkani',
  133. '0458' => 'Manipuri',
  134. '0459' => 'Sindhi',
  135. '045a' => 'Syriac',
  136. '0460' => 'Kashmiri',
  137. '0461' => 'Nepali',
  138. '0465' => 'Divehi',
  139. '047f' => 'Invariant',
  140. '048f' => 'Esperanto',
  141. '0490' => 'Walon',
  142. '0491' => 'Cornish',
  143. '0492' => 'Welsh',
  144. '0493' => 'Breton',
  145. '0800' => 'Neutral 2',
  146. '0804' => 'Chinese (Simplified)',
  147. '0807' => 'German (Swiss)',
  148. '0809' => 'English (British)',
  149. '080A' => 'Spanish (Mexican)',
  150. '080C' => 'French (Belgian)',
  151. '0810' => 'Italian (Swiss)',
  152. '0813' => 'Dutch (Belgian)',
  153. '0814' => 'Norwegian (Nynorsk)',
  154. '0816' => 'Portuguese',
  155. '081A' => 'Serbo-Croatian (Cyrillic)',
  156. '0C07' => 'German (Austrian)',
  157. '0C09' => 'English (Australian)',
  158. '0C0A' => 'Spanish (Modern)',
  159. '0C0C' => 'French (Canadian)',
  160. '1009' => 'English (Canadian)',
  161. '100C' => 'French (Swiss)',
  162. );
  163. # Information extracted from PE COFF (Windows EXE) file header
  164. %Image::ExifTool::EXE::Main = (
  165. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  166. GROUPS => { 2 => 'Other' },
  167. FORMAT => 'int16u',
  168. NOTES => q{
  169. This module extracts information from various types of Windows, MacOS and
  170. Unix executable and library files. The first table below lists information
  171. extracted from the header of Windows PE (Portable Executable) EXE files and
  172. DLL libraries.
  173. },
  174. 0 => {
  175. Name => 'MachineType',
  176. PrintHex => 1,
  177. PrintConv => {
  178. 0x014c => 'Intel 386 or later, and compatibles',
  179. 0x014d => 'Intel i860', #5
  180. 0x0162 => 'MIPS R3000',
  181. 0x0166 => 'MIPS little endian (R4000)',
  182. 0x0168 => 'MIPS R10000',
  183. 0x0169 => 'MIPS little endian WCI v2',
  184. 0x0183 => 'Alpha AXP (old)', #5
  185. 0x0184 => 'Alpha AXP',
  186. 0x01a2 => 'Hitachi SH3',
  187. 0x01a3 => 'Hitachi SH3 DSP',
  188. 0x01a6 => 'Hitachi SH4',
  189. 0x01a8 => 'Hitachi SH5',
  190. 0x01c0 => 'ARM little endian',
  191. 0x01c2 => 'Thumb',
  192. 0x01d3 => 'Matsushita AM33',
  193. 0x01f0 => 'PowerPC little endian',
  194. 0x01f1 => 'PowerPC with floating point support',
  195. 0x0200 => 'Intel IA64',
  196. 0x0266 => 'MIPS16',
  197. 0x0268 => 'Motorola 68000 series',
  198. 0x0284 => 'Alpha AXP 64-bit',
  199. 0x0366 => 'MIPS with FPU',
  200. 0x0466 => 'MIPS16 with FPU',
  201. 0x0ebc => 'EFI Byte Code',
  202. 0x8664 => 'AMD AMD64',
  203. 0x9041 => 'Mitsubishi M32R little endian',
  204. 0xc0ee => 'clr pure MSIL',
  205. },
  206. },
  207. 2 => {
  208. Name => 'TimeStamp',
  209. Format => 'int32u',
  210. Groups => { 2 => 'Time' },
  211. ValueConv => 'ConvertUnixTime($val,1)',
  212. PrintConv => '$self->ConvertDateTime($val)',
  213. },
  214. 10 => {
  215. Name => 'PEType',
  216. PrintHex => 1,
  217. PrintConv => {
  218. 0x10b => 'PE32',
  219. 0x20b => 'PE32+',
  220. },
  221. },
  222. 11 => {
  223. Name => 'LinkerVersion',
  224. Format => 'int8u[2]',
  225. ValueConv => '$val=~tr/ /./; $val',
  226. },
  227. 12 => {
  228. Name => 'CodeSize',
  229. Format => 'int32u',
  230. },
  231. 14 => {
  232. Name => 'InitializedDataSize',
  233. Format => 'int32u',
  234. },
  235. 16 => {
  236. Name => 'UninitializedDataSize',
  237. Format => 'int32u',
  238. },
  239. 18 => {
  240. Name => 'EntryPoint',
  241. Format => 'int32u',
  242. PrintConv => 'sprintf("0x%.4x", $val)',
  243. },
  244. 30 => {
  245. Name => 'OSVersion',
  246. Format => 'int16u[2]',
  247. ValueConv => '$val=~tr/ /./; $val',
  248. },
  249. 32 => {
  250. Name => 'ImageVersion',
  251. Format => 'int16u[2]',
  252. ValueConv => '$val=~tr/ /./; $val',
  253. },
  254. 34 => {
  255. Name => 'SubsystemVersion',
  256. Format => 'int16u[2]',
  257. ValueConv => '$val=~tr/ /./; $val',
  258. },
  259. 44 => {
  260. Name => 'Subsystem',
  261. PrintConv => {
  262. 0 => 'Unknown',
  263. 1 => 'Native',
  264. 2 => 'Windows GUI',
  265. 3 => 'Windows command line',
  266. 5 => 'OS/2 command line', #5
  267. 7 => 'POSIX command line',
  268. 9 => 'Windows CE GUI',
  269. 10 => 'EFI application',
  270. 11 => 'EFI boot service',
  271. 12 => 'EFI runtime driver',
  272. 13 => 'EFI ROM', #6
  273. 14 => 'XBOX', #6
  274. },
  275. },
  276. );
  277. # PE file version information (ref 6)
  278. %Image::ExifTool::EXE::PEVersion = (
  279. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  280. GROUPS => { 2 => 'Other' },
  281. FORMAT => 'int32u',
  282. NOTES => q{
  283. Information extracted from the VS_VERSION_INFO structure of Windows PE
  284. files.
  285. },
  286. # (boring -- always 0xfeef04bd)
  287. #0 => {
  288. # Name => 'Signature',
  289. # PrintConv => 'sprintf("0x%.4x",$val)',
  290. #},
  291. # (boring -- always 1.0)
  292. #1 => {
  293. # Name => 'StructVersion',
  294. # Format => 'int16u[2]',
  295. # ValueConv => 'my @a=split(" ",$val); "$a[1].$a[0]"',
  296. #},
  297. 2 => {
  298. Name => 'FileVersionNumber',
  299. Format => 'int16u[4]',
  300. ValueConv => 'my @a=split(" ",$val); "$a[1].$a[0].$a[3].$a[2]"',
  301. },
  302. 4 => {
  303. Name => 'ProductVersionNumber',
  304. Format => 'int16u[4]',
  305. ValueConv => 'my @a=split(" ",$val); "$a[1].$a[0].$a[3].$a[2]"',
  306. },
  307. 6 => {
  308. Name => 'FileFlagsMask',
  309. PrintConv => 'sprintf("0x%.4x",$val)',
  310. },
  311. 7 => { # ref Cygwin /usr/include/w32api/winver.h
  312. Name => 'FileFlags',
  313. PrintConv => { BITMASK => {
  314. 0 => 'Debug',
  315. 1 => 'Pre-release',
  316. 2 => 'Patched',
  317. 3 => 'Private build',
  318. 4 => 'Info inferred',
  319. 5 => 'Special build',
  320. }},
  321. },
  322. 8 => {
  323. Name => 'FileOS',
  324. PrintHex => 1,
  325. PrintConv => { # ref Cygwin /usr/include/w32api/winver.h
  326. 0x00001 => 'Win16',
  327. 0x00002 => 'PM-16',
  328. 0x00003 => 'PM-32',
  329. 0x00004 => 'Win32',
  330. 0x10000 => 'DOS',
  331. 0x20000 => 'OS/2 16-bit',
  332. 0x30000 => 'OS/2 32-bit',
  333. 0x40000 => 'Windows NT',
  334. 0x10001 => 'Windows 16-bit',
  335. 0x10004 => 'Windows 32-bit',
  336. 0x20002 => 'OS/2 16-bit PM-16',
  337. 0x30003 => 'OS/2 32-bit PM-32',
  338. 0x40004 => 'Windows NT 32-bit',
  339. },
  340. },
  341. 9 => { # ref Cygwin /usr/include/w32api/winver.h
  342. Name => 'ObjectFileType',
  343. PrintConv => {
  344. 0 => 'Unknown',
  345. 1 => 'Executable application',
  346. 2 => 'Dynamic link library',
  347. 3 => 'Driver',
  348. 4 => 'Font',
  349. 5 => 'VxD',
  350. 7 => 'Static library',
  351. },
  352. },
  353. 10 => 'FileSubtype',
  354. # (these are usually zero, so ignore them)
  355. # 11 => 'FileDateMS',
  356. # 12 => 'FileDateLS',
  357. );
  358. # Windows PE StringFileInfo resource strings
  359. # (see http://msdn.microsoft.com/en-us/library/aa381049.aspx)
  360. %Image::ExifTool::EXE::PEString = (
  361. GROUPS => { 2 => 'Other' },
  362. VARS => { NO_ID => 1 },
  363. NOTES => q{
  364. Resource strings found in Windows PE files. The B<TagID>'s are not shown
  365. because they are the same as the B<Tag Name>. ExifTool will extract any
  366. existing StringFileInfo tags even if not listed in this table.
  367. },
  368. LanguageCode => {
  369. Notes => 'extracted from the StringFileInfo value',
  370. # ref http://techsupt.winbatch.com/TS/T000001050F49.html
  371. # (also see http://support.bigfix.com/fixlet/documents/WinInspectors-2006-08-10.pdf)
  372. # (also see ftp://ftp.dyu.edu.tw/pub/cpatch/faq/tech/tech_nlsnt.txt)
  373. # (not a complete set)
  374. PrintString => 1,
  375. SeparateTable => 1,
  376. PrintConv => \%languageCode,
  377. },
  378. CharacterSet => {
  379. Notes => 'extracted from the StringFileInfo value',
  380. # ref http://techsupt.winbatch.com/TS/T000001050F49.html
  381. # (also see http://blog.chinaunix.net/u1/41189/showart_345768.html)
  382. PrintString => 1,
  383. PrintConv => {
  384. '0000' => 'ASCII',
  385. '03A4' => 'Windows, Japan (Shift - JIS X-0208)', # cp932
  386. '03A8' => 'Windows, Chinese (Simplified)', # cp936
  387. '03B5' => 'Windows, Korea (Shift - KSC 5601)', # cp949
  388. '03B6' => 'Windows, Taiwan (Big5)', # cp950
  389. '04B0' => 'Unicode', # UCS-2
  390. '04E2' => 'Windows, Latin2 (Eastern European)',
  391. '04E3' => 'Windows, Cyrillic',
  392. '04E4' => 'Windows, Latin1',
  393. '04E5' => 'Windows, Greek',
  394. '04E6' => 'Windows, Turkish',
  395. '04E7' => 'Windows, Hebrew',
  396. '04E8' => 'Windows, Arabic',
  397. },
  398. },
  399. BuildDate => { Groups => { 2 => 'Time' } }, # (non-standard)
  400. BuildVersion => { }, # (non-standard)
  401. Comments => { },
  402. CompanyName => { },
  403. Copyright => { }, # (non-standard)
  404. FileDescription => { },
  405. FileVersion => { },
  406. InternalName => { },
  407. LegalCopyright => { },
  408. LegalTrademarks => { },
  409. OriginalFilename=> { Name => 'OriginalFileName' },
  410. PrivateBuild => { },
  411. ProductName => { },
  412. ProductVersion => { },
  413. SpecialBuild => { },
  414. );
  415. # Information extracted from Mach-O (Mac OS X) file header
  416. %Image::ExifTool::EXE::MachO = (
  417. GROUPS => { 2 => 'Other' },
  418. VARS => { ID_LABEL => 'Index' },
  419. NOTES => q{
  420. Information extracted from Mach-O (Mac OS X) executable files and DYLIB
  421. libraries.
  422. },
  423. # ref http://www.opensource.apple.com/darwinsource/DevToolsOct2007/cctools-622.9/include/mach/machine.h
  424. 0 => 'CPUArchitecture',
  425. 1 => 'CPUByteOrder',
  426. 2 => 'CPUCount',
  427. # ref /System/Library/Frameworks/Kernel.framework/Versions/A/Headers/mach/machine.h
  428. 3 => {
  429. Name => 'CPUType',
  430. List => 1,
  431. PrintConv => {
  432. # handle 64-bit flag (0x1000000)
  433. OTHER => sub {
  434. my ($val, $inv, $conv) = @_;
  435. my $v = $val & 0xfeffffff;
  436. return $$conv{$v} ? "$$conv{$v} 64-bit" : "Unknown ($val)";
  437. },
  438. -1 => 'Any',
  439. 1 => 'VAX',
  440. 2 => 'ROMP',
  441. 4 => 'NS32032',
  442. 5 => 'NS32332',
  443. 6 => 'MC680x0',
  444. 7 => 'x86',
  445. 8 => 'MIPS',
  446. 9 => 'NS32532',
  447. 10 => 'MC98000',
  448. 11 => 'HPPA',
  449. 12 => 'ARM',
  450. 13 => 'MC88000',
  451. 14 => 'SPARC',
  452. 15 => 'i860 big endian',
  453. 16 => 'i860 little endian',
  454. 17 => 'RS6000',
  455. 18 => 'PowerPC',
  456. 255 => 'VEO',
  457. },
  458. },
  459. # ref /System/Library/Frameworks/Kernel.framework/Versions/A/Headers/mach/machine.h
  460. 4 => {
  461. Name => 'CPUSubtype',
  462. List => 1,
  463. PrintConv => {
  464. # handle 64-bit flags on CPUType (0x1000000) and CPUSubtype (0x80000000)
  465. OTHER => sub {
  466. my ($val, $inv, $conv) = @_;
  467. my @v = split ' ', $val;
  468. my $v = ($v[0] & 0xfeffffff) . ' ' . ($v[1] & 0x7fffffff);
  469. return $$conv{$v} ? "$$conv{$v} 64-bit" : "Unknown ($val)";
  470. },
  471. # in theory, subtype can be -1 for multiple CPU types,
  472. # but in practice I'm not sure anyone uses this - PH
  473. '1 0' => 'VAX (all)',
  474. '1 1' => 'VAX780',
  475. '1 2' => 'VAX785',
  476. '1 3' => 'VAX750',
  477. '1 4' => 'VAX730',
  478. '1 5' => 'UVAXI',
  479. '1 6' => 'UVAXII',
  480. '1 7' => 'VAX8200',
  481. '1 8' => 'VAX8500',
  482. '1 9' => 'VAX8600',
  483. '1 10' => 'VAX8650',
  484. '1 11' => 'VAX8800',
  485. '1 12' => 'UVAXIII',
  486. '2 0' => 'RT (all)',
  487. '2 1' => 'RT PC',
  488. '2 2' => 'RT APC',
  489. '2 3' => 'RT 135',
  490. # 32032/32332/32532 subtypes.
  491. '4 0' => 'NS32032 (all)',
  492. '4 1' => 'NS32032 DPC (032 CPU)',
  493. '4 2' => 'NS32032 SQT',
  494. '4 3' => 'NS32032 APC FPU (32081)',
  495. '4 4' => 'NS32032 APC FPA (Weitek)',
  496. '4 5' => 'NS32032 XPC (532)',
  497. '5 0' => 'NS32332 (all)',
  498. '5 1' => 'NS32332 DPC (032 CPU)',
  499. '5 2' => 'NS32332 SQT',
  500. '5 3' => 'NS32332 APC FPU (32081)',
  501. '5 4' => 'NS32332 APC FPA (Weitek)',
  502. '5 5' => 'NS32332 XPC (532)',
  503. '6 1' => 'MC680x0 (all)',
  504. '6 2' => 'MC68040',
  505. '6 3' => 'MC68030',
  506. '7 3' => 'i386 (all)',
  507. '7 4' => 'i486',
  508. '7 132' => 'i486SX',
  509. '7 5' => 'i586',
  510. '7 22' => 'Pentium Pro',
  511. '7 54' => 'Pentium II M3',
  512. '7 86' => 'Pentium II M5',
  513. '7 103' => 'Celeron',
  514. '7 119' => 'Celeron Mobile',
  515. '7 8' => 'Pentium III',
  516. '7 24' => 'Pentium III M',
  517. '7 40' => 'Pentium III Xeon',
  518. '7 9' => 'Pentium M',
  519. '7 10' => 'Pentium 4',
  520. '7 26' => 'Pentium 4 M',
  521. '7 11' => 'Itanium',
  522. '7 27' => 'Itanium 2',
  523. '7 12' => 'Xeon',
  524. '7 28' => 'Xeon MP',
  525. '8 0' => 'MIPS (all)',
  526. '8 1' => 'MIPS R2300',
  527. '8 2' => 'MIPS R2600',
  528. '8 3' => 'MIPS R2800',
  529. '8 4' => 'MIPS R2000a',
  530. '8 5' => 'MIPS R2000',
  531. '8 6' => 'MIPS R3000a',
  532. '8 7' => 'MIPS R3000',
  533. '10 0' => 'MC98000 (all)',
  534. '10 1' => 'MC98601',
  535. '11 0' => 'HPPA (all)',
  536. '11 1' => 'HPPA 7100LC',
  537. '12 0' => 'ARM (all)',
  538. '12 1' => 'ARM A500 ARCH',
  539. '12 2' => 'ARM A500',
  540. '12 3' => 'ARM A440',
  541. '12 4' => 'ARM M4',
  542. '12 5' => 'ARM A680/V4T',
  543. '12 6' => 'ARM V6',
  544. '12 7' => 'ARM V5TEJ',
  545. '12 8' => 'ARM XSCALE',
  546. '12 9' => 'ARM V7',
  547. '13 0' => 'MC88000 (all)',
  548. '13 1' => 'MC88100',
  549. '13 2' => 'MC88110',
  550. '14 0' => 'SPARC (all)',
  551. '14 1' => 'SUN 4/260',
  552. '14 2' => 'SUN 4/110',
  553. '15 0' => 'i860 (all)',
  554. '15 1' => 'i860 860',
  555. '16 0' => 'i860 little (all)',
  556. '16 1' => 'i860 little',
  557. '17 0' => 'RS6000 (all)',
  558. '17 1' => 'RS6000',
  559. '18 0' => 'PowerPC (all)',
  560. '18 1' => 'PowerPC 601',
  561. '18 2' => 'PowerPC 602',
  562. '18 3' => 'PowerPC 603',
  563. '18 4' => 'PowerPC 603e',
  564. '18 5' => 'PowerPC 603ev',
  565. '18 6' => 'PowerPC 604',
  566. '18 7' => 'PowerPC 604e',
  567. '18 8' => 'PowerPC 620',
  568. '18 9' => 'PowerPC 750',
  569. '18 10' => 'PowerPC 7400',
  570. '18 11' => 'PowerPC 7450',
  571. '18 100' => 'PowerPC 970',
  572. '255 1' => 'VEO 1',
  573. '255 2' => 'VEO 2',
  574. },
  575. },
  576. 5 => {
  577. Name => 'ObjectFileType',
  578. PrintHex => 1,
  579. # ref https://svn.red-bean.com/pyobjc/branches/pyobjc-20x-branch/macholib/macholib/mach_o.py
  580. PrintConv => {
  581. -1 => 'Static library', #PH (internal use only)
  582. 1 => 'Relocatable object',
  583. 2 => 'Demand paged executable',
  584. 3 => 'Fixed VM shared library',
  585. 4 => 'Core',
  586. 5 => 'Preloaded executable',
  587. 6 => 'Dynamically bound shared library',
  588. 7 => 'Dynamic link editor',
  589. 8 => 'Dynamically bound bundle',
  590. 9 => 'Shared library stub for static linking',
  591. },
  592. },
  593. );
  594. # Information extracted from PEF (Classic MacOS executable) file header
  595. %Image::ExifTool::EXE::PEF = (
  596. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  597. GROUPS => { 2 => 'Other' },
  598. NOTES => q{
  599. Information extracted from PEF (Classic MacOS) executable files and
  600. libraries.
  601. },
  602. FORMAT => 'int32u',
  603. 2 => {
  604. Name => 'CPUArchitecture',
  605. Format => 'undef[4]',
  606. PrintConv => {
  607. pwpc => 'PowerPC',
  608. m68k => '68000',
  609. },
  610. },
  611. 3 => 'PEFVersion',
  612. 4 => {
  613. Name => 'TimeStamp',
  614. Groups => { 2 => 'Time' },
  615. # timestamp is relative to Jan 1, 1904
  616. ValueConv => 'ConvertUnixTime($val - ((66 * 365 + 17) * 24 * 3600))',
  617. PrintConv => '$self->ConvertDateTime($val)',
  618. },
  619. #5 => 'OldDefVersion',
  620. #6 => 'OldImpVersion',
  621. #7 => 'CurrentVersion',
  622. );
  623. # Information extracted from ELF (Unix executable) file header
  624. %Image::ExifTool::EXE::ELF = (
  625. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  626. GROUPS => { 2 => 'Other' },
  627. NOTES => q{
  628. Information extracted from ELF (Unix) executable files and SO libraries.
  629. },
  630. 4 => {
  631. Name => 'CPUArchitecture',
  632. PrintConv => {
  633. 1 => '32 bit',
  634. 2 => '64 bit',
  635. },
  636. },
  637. 5 => {
  638. Name => 'CPUByteOrder',
  639. PrintConv => {
  640. 1 => 'Little endian',
  641. 2 => 'Big endian',
  642. },
  643. },
  644. 16 => {
  645. Name => 'ObjectFileType',
  646. Format => 'int16u',
  647. PrintConv => {
  648. 0 => 'None',
  649. 1 => 'Relocatable file',
  650. 2 => 'Executable file',
  651. 3 => 'Shared object file',
  652. 4 => 'Core file',
  653. },
  654. },
  655. 18 => {
  656. Name => 'CPUType',
  657. Format => 'int16u',
  658. # ref /usr/include/linux/elf-em.h
  659. PrintConv => {
  660. 0 => 'None',
  661. 1 => 'AT&T WE 32100',
  662. 2 => 'SPARC',
  663. 3 => 'i386',
  664. 4 => 'Motorola 68000',
  665. 5 => 'Motorola 88000',
  666. 6 => 'i486',
  667. 7 => 'i860',
  668. 8 => 'MIPS R3000',
  669. 10 => 'MIPS R4000',
  670. 15 => 'HPPA',
  671. 18 => 'Sun v8plus',
  672. 20 => 'PowerPC',
  673. 21 => 'PowerPC 64-bit',
  674. 22 => 'IBM S/390',
  675. 23 => 'Cell BE SPU',
  676. 42 => 'SuperH',
  677. 43 => 'SPARC v9 64-bit',
  678. 46 => 'Renesas H8/300,300H,H8S',
  679. 50 => 'HP/Intel IA-64',
  680. 62 => 'AMD x86-64',
  681. 76 => 'Axis Communications 32-bit embedded processor',
  682. 87 => 'NEC v850',
  683. 88 => 'Renesas M32R',
  684. 0x5441 => 'Fujitsu FR-V',
  685. 0x9026 => 'Alpha', # (interim value)
  686. 0x9041 => 'm32r (old)',
  687. 0x9080 => 'v850 (old)',
  688. 0xa390 => 'S/390 (old)',
  689. },
  690. },
  691. );
  692. # Microsoft compiled help format (ref http://www.russotto.net/chm/chmformat.html)
  693. %Image::ExifTool::EXE::CHM = (
  694. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  695. GROUPS => { 2 => 'Other' },
  696. NOTES => 'Tags extracted from Microsoft Compiled HTML files.',
  697. FORMAT => 'int32u',
  698. 1 => { Name => 'CHMVersion' },
  699. # 2 - total header length
  700. # 3 - 1
  701. # 4 - low bits of date/time value plus 42 (ref http://www.nongnu.org/chmspec/latest/ITSF.html)
  702. 5 => {
  703. Name => 'LanguageCode',
  704. SeparateTable => 1,
  705. ValueConv => 'sprintf("%.4X", $val)',
  706. PrintConv => \%languageCode,
  707. },
  708. );
  709. #------------------------------------------------------------------------------
  710. # Extract information from a CHM file
  711. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  712. # Returns: 1 on success, 0 if this wasn't a valid CHM file
  713. sub ProcessCHM($$)
  714. {
  715. my ($et, $dirInfo) = @_;
  716. my $raf = $$dirInfo{RAF};
  717. my $buff;
  718. return 0 unless $raf->Read($buff, 56) == 56 and
  719. $buff =~ /^ITSF.{20}\x10\xfd\x01\x7c\xaa\x7b\xd0\x11\x9e\x0c\0\xa0\xc9\x22\xe6\xec/s;
  720. my $tagTablePtr = GetTagTable('Image::ExifTool::EXE::CHM');
  721. $et->SetFileType();
  722. SetByteOrder('II');
  723. $et->ProcessDirectory({ DataPt => \$buff }, $tagTablePtr);
  724. return 1;
  725. }
  726. #------------------------------------------------------------------------------
  727. # Read Unicode string (null terminated) from resource
  728. # Inputs: 0) data ref, 1) start offset, 2) data end, 3) optional ExifTool object ref
  729. # Returns: 0) Unicode string translated to UTF8, or current CharSet with ExifTool ref
  730. # 1) end pos (rounded up to nearest 4 bytes)
  731. sub ReadUnicodeStr($$$;$)
  732. {
  733. my ($dataPt, $pos, $end, $et) = @_;
  734. $end = length $$dataPt if $end > length $$dataPt; # (be safe)
  735. my $str = '';
  736. while ($pos + 2 <= $end) {
  737. my $ch = substr($$dataPt, $pos, 2);
  738. $pos += 2;
  739. last if $ch eq "\0\0";
  740. $str .= $ch;
  741. }
  742. $pos += 2 if $pos & 0x03;
  743. my $to = $et ? $et->Options('Charset') : 'UTF8';
  744. return (Image::ExifTool::Decode(undef,$str,'UCS2','II',$to), $pos);
  745. }
  746. #------------------------------------------------------------------------------
  747. # Process Windows PE Version Resource
  748. # Inputs: 0) ExifTool object ref, 1) dirInfo ref
  749. # Returns: true on success
  750. sub ProcessPEVersion($$)
  751. {
  752. my ($et, $dirInfo) = @_;
  753. my $dataPt = $$dirInfo{DataPt};
  754. my $pos = $$dirInfo{DirStart};
  755. my $end = $pos + $$dirInfo{DirLen};
  756. my ($index, $len, $valLen, $type, $string, $strEnd);
  757. # get VS_VERSION_INFO
  758. for ($index = 0; ; ++$index) {
  759. $pos = ($pos + 3) & 0xfffffffc; # align on a 4-byte boundary
  760. last if $pos + 6 > $end;
  761. $len = Get16u($dataPt, $pos);
  762. $valLen = Get16u($dataPt, $pos + 2);
  763. $type = Get16u($dataPt, $pos + 4);
  764. return 0 unless $len or $valLen; # prevent possible infinite loop
  765. ($string, $strEnd) = ReadUnicodeStr($dataPt, $pos + 6, $pos + $len);
  766. return 0 if $strEnd + $valLen > $end;
  767. unless ($index or $string eq 'VS_VERSION_INFO') {
  768. $et->Warn('Invalid Version Info block');
  769. return 0;
  770. }
  771. if ($string eq 'VS_VERSION_INFO') {
  772. # parse the fixed version info
  773. $$dirInfo{DirStart} = $strEnd;
  774. $$dirInfo{DirLen} = $valLen;
  775. my $subTablePtr = GetTagTable('Image::ExifTool::EXE::PEVersion');
  776. $et->ProcessDirectory($dirInfo, $subTablePtr);
  777. $pos = $strEnd + $valLen;
  778. } elsif ($string eq 'StringFileInfo' and $valLen == 0) {
  779. $pos += $len;
  780. my $pt = $strEnd;
  781. # parse string table
  782. my $tagTablePtr = GetTagTable('Image::ExifTool::EXE::PEString');
  783. for ($index = 0; $pt + 6 < $pos; ++$index) {
  784. $len = Get16u($dataPt, $pt);
  785. $valLen = Get16u($dataPt, $pt + 2);
  786. # $type = Get16u($dataPt, $pt + 4);
  787. my $entryEnd = $pt + $len;
  788. # get tag ID (converted to UTF8)
  789. ($string, $pt) = ReadUnicodeStr($dataPt, $pt + 6, $entryEnd);
  790. unless ($index) {
  791. # separate the language code and character set
  792. # (not sure what the CharacterSet tag is for, but the string
  793. # values stored here are UCS-2 in all my files even if the
  794. # CharacterSet is otherwise)
  795. my $char;
  796. if (length($string) > 4) {
  797. $char = substr($string, 4);
  798. $string = substr($string, 0, 4);
  799. }
  800. $et->HandleTag($tagTablePtr, 'LanguageCode', uc $string);
  801. $et->HandleTag($tagTablePtr, 'CharacterSet', uc $char) if $char;
  802. next;
  803. }
  804. my $tag = $string;
  805. # create entry in tag table if it doesn't already exist
  806. unless ($$tagTablePtr{$tag}) {
  807. my $name = $tag;
  808. $name =~ tr/-_a-zA-Z0-9//dc; # remove illegal characters
  809. next unless length $name;
  810. AddTagToTable($tagTablePtr, $tag, { Name => $name });
  811. }
  812. # get tag value (converted to current Charset)
  813. if ($valLen) {
  814. ($string, $pt) = ReadUnicodeStr($dataPt, $pt, $entryEnd, $et);
  815. } else {
  816. $string = '';
  817. }
  818. $et->HandleTag($tagTablePtr, $tag, $string);
  819. # step to next entry (padded to an even word)
  820. $pt = ($entryEnd + 3) & 0xfffffffc;
  821. }
  822. } else {
  823. $pos += $len + $valLen;
  824. # ignore other information (for now)
  825. }
  826. }
  827. return 1;
  828. }
  829. #------------------------------------------------------------------------------
  830. # Process Windows PE Resources
  831. # Inputs: 0) ExifTool object ref, 1) dirInfo ref
  832. # Returns: true on success
  833. sub ProcessPEResources($$)
  834. {
  835. my ($et, $dirInfo) = @_;
  836. my $raf = $$dirInfo{RAF};
  837. my $base = $$dirInfo{Base};
  838. my $dirStart = $$dirInfo{DirStart} + $base;
  839. my $level = $$dirInfo{Level} || 0;
  840. my $verbose = $et->Options('Verbose');
  841. my ($buff, $buf2, $item);
  842. return 0 if $level > 10; # protect against deep recursion
  843. # read the resource header
  844. $raf->Seek($dirStart, 0) and $raf->Read($buff, 16) == 16 or return 0;
  845. my $nameEntries = Get16u(\$buff, 12);
  846. my $idEntries = Get16u(\$buff, 14);
  847. my $count = $nameEntries + $idEntries;
  848. $raf->Read($buff, $count * 8) == $count * 8 or return 0;
  849. # loop through all resource entries
  850. for ($item=0; $item<$count; ++$item) {
  851. my $pos = $item * 8;
  852. my $name = Get32u(\$buff, $pos);
  853. my $entryPos = Get32u(\$buff, $pos + 4);
  854. unless ($level) {
  855. # set resource type if this is the 0th level directory
  856. my $resType = $resourceType{$name} || sprintf('Unknown (0x%x)', $name);
  857. # ignore everything but the Version resource unless verbose
  858. if ($verbose) {
  859. $et->VPrint(0, "$resType resource:\n");
  860. } else {
  861. next unless $resType eq 'Version';
  862. }
  863. $$dirInfo{ResType} = $resType;
  864. }
  865. if ($entryPos & 0x80000000) { # is this a directory?
  866. # descend into next directory level
  867. $$dirInfo{DirStart} = $entryPos & 0x7fffffff;
  868. $$dirInfo{Level} = $level + 1;
  869. ProcessPEResources($et, $dirInfo) or return 0;
  870. --$$dirInfo{Level};
  871. } elsif ($$dirInfo{ResType} eq 'Version' and $level == 2 and
  872. not $$dirInfo{GotVersion}) # (only process first Version resource)
  873. {
  874. # get position of this resource in the file
  875. my $buf2;
  876. $raf->Seek($entryPos + $base, 0) and $raf->Read($buf2, 16) == 16 or return 0;
  877. my $off = Get32u(\$buf2, 0);
  878. my $len = Get32u(\$buf2, 4);
  879. # determine which section this is in so we can convert the virtual address
  880. my ($section, $filePos);
  881. foreach $section (@{$$dirInfo{Sections}}) {
  882. next unless $off >= $$section{VirtualAddress} and
  883. $off < $$section{VirtualAddress} + $$section{Size};
  884. $filePos = $off + $$section{Base} - $$section{VirtualAddress};
  885. last;
  886. }
  887. return 0 unless $filePos;
  888. $raf->Seek($filePos, 0) and $raf->Read($buf2, $len) == $len or return 0;
  889. ProcessPEVersion($et, {
  890. DataPt => \$buf2,
  891. DataLen => $len,
  892. DirStart => 0,
  893. DirLen => $len,
  894. }) or $et->Warn('Possibly corrupt Version resource');
  895. $$dirInfo{GotVersion} = 1; # set flag so we don't do this again
  896. }
  897. }
  898. return 1;
  899. }
  900. #------------------------------------------------------------------------------
  901. # Process Windows PE file data dictionary
  902. # Inputs: 0) ExifTool object ref, 1) dirInfo ref
  903. # Returns: true on success
  904. sub ProcessPEDict($$)
  905. {
  906. my ($et, $dirInfo) = @_;
  907. my $raf = $$dirInfo{RAF};
  908. my $dataPt = $$dirInfo{DataPt};
  909. my $dirLen = length($$dataPt);
  910. my ($pos, @sections, %dirInfo);
  911. # loop through all sections
  912. for ($pos=0; $pos+40<=$dirLen; $pos+=40) {
  913. my $name = substr($$dataPt, $pos, 8);
  914. my $va = Get32u($dataPt, $pos + 12);
  915. my $size = Get32u($dataPt, $pos + 16);
  916. my $offset = Get32u($dataPt, $pos + 20);
  917. # remember the section offsets for the VirtualAddress lookup later
  918. push @sections, { Base => $offset, Size => $size, VirtualAddress => $va };
  919. # save details of the first resource section
  920. %dirInfo = (
  921. RAF => $raf,
  922. Base => $offset,
  923. DirStart => 0, # (relative to Base)
  924. DirLen => $size,
  925. Sections => \@sections,
  926. ) if $name eq ".rsrc\0\0\0" and not %dirInfo;
  927. }
  928. # process the first resource section
  929. ProcessPEResources($et, \%dirInfo) or return 0 if %dirInfo;
  930. return 1;
  931. }
  932. #------------------------------------------------------------------------------
  933. # Extract information from an EXE file
  934. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  935. # Returns: 1 on success, 0 if this wasn't a valid EXE file
  936. sub ProcessEXE($$)
  937. {
  938. my ($et, $dirInfo) = @_;
  939. my $raf = $$dirInfo{RAF};
  940. my ($buff, $buf2, $type, $mime, $ext, $tagTablePtr, %dirInfo);
  941. my $size = $raf->Read($buff, 0x40) or return 0;
  942. my $fast3 = $$et{OPTIONS}{FastScan} && $$et{OPTIONS}{FastScan} == 3;
  943. #
  944. # DOS and Windows EXE
  945. #
  946. if ($buff =~ /^MZ/ and $size == 0x40) {
  947. # DOS/Windows executable
  948. # validate DOS header
  949. # (ref http://www.delphidabbler.com/articles?article=8&part=2)
  950. # 0 magic : int16u # Magic number ("MZ")
  951. # 2 cblp : int16u # Bytes on last page of file
  952. # 4 cp : int16u # Pages in file
  953. # 6 crlc : int16u # Relocations
  954. # 8 cparhdr : int16u # Size of header in paragraphs
  955. # 10 minalloc: int16u # Minimum extra paragraphs needed
  956. # 12 maxalloc: int16u # Maximum extra paragraphs needed
  957. # 14 ss : int16u # Initial (relative) SS value
  958. # 16 sp : int16u # Initial SP value
  959. # 18 csum : int16u # Checksum
  960. # 20 ip : int16u # Initial IP value
  961. # 22 cs : int16u # Initial (relative) CS value
  962. # 24 lfarlc : int16u # Address of relocation table
  963. # 26 ovno : int16u # Overlay number
  964. # 28 res : int16u[4] # Reserved words
  965. # 36 oemid : int16u # OEM identifier (for oeminfo)
  966. # 38 oeminfo : int16u # OEM info; oemid specific
  967. # 40 res2 : int16u[10]# Reserved words
  968. # 60 lfanew : int32u; # File address of new exe header
  969. SetByteOrder('II');
  970. my ($cblp, $cp, $lfarlc, $lfanew) = unpack('x2v2x18vx34V', $buff);
  971. my $fileSize = ($cp - ($cblp ? 1 : 0)) * 512 + $cblp;
  972. #(patch to accommodate observed 64-bit files)
  973. #return 0 if $fileSize < 0x40 or $fileSize < $lfarlc;
  974. return 0 if $fileSize < 0x40;
  975. # read the Windows NE, PE or LE (virtual device driver) header
  976. #if ($lfarlc == 0x40 and $fileSize > $lfanew + 2 and ...
  977. if ($raf->Seek($lfanew, 0) and $raf->Read($buff, 0x40) and $buff =~ /^(NE|PE|LE)/) {
  978. if ($1 eq 'NE') {
  979. if ($size >= 0x40) { # NE header is 64 bytes (ref 2)
  980. # check for DLL
  981. my $appFlags = Get16u(\$buff, 0x0c);
  982. $ext = $appFlags & 0x80 ? 'DLL' : 'EXE';
  983. $type = "Win16 $ext";
  984. # offset 0x02 is 2 bytes with linker version and revision numbers
  985. # offset 0x36 is executable type (2 = Windows)
  986. }
  987. } elsif ($1 eq 'PE') {
  988. # PE header comes at byte 4 in buff:
  989. # 4 int16u Machine
  990. # 6 int16u NumberOfSections
  991. # 8 int32u TimeDateStamp
  992. # 12 int32u PointerToSymbolTable
  993. # 16 int32u NumberOfSymbols
  994. # 20 int16u SizeOfOptionalHeader
  995. # 22 int16u Characteristics
  996. if ($size >= 24) { # PE header is 24 bytes (plus optional header)
  997. my $machine = $Image::ExifTool::EXE::Main{0}{PrintConv}{Get16u(\$buff, 4)} || '';
  998. my $winType = $machine =~ /64/ ? 'Win64' : 'Win32';
  999. my $flags = Get16u(\$buff, 22);
  1000. $ext = $flags & 0x2000 ? 'DLL' : 'EXE';
  1001. $et->SetFileType("$winType $ext", undef, $ext);
  1002. return 1 if $fast3;
  1003. # read the rest of the optional header if necessary
  1004. my $optSize = Get16u(\$buff, 20);
  1005. my $more = $optSize + 24 - $size;
  1006. if ($more > 0) {
  1007. if ($raf->Read($buf2, $more) == $more) {
  1008. $buff .= $buf2;
  1009. $size += $more;
  1010. my $magic = Get16u(\$buff, 24);
  1011. # verify PE32/PE32+ magic number
  1012. unless ($magic == 0x10b or $magic == 0x20b) {
  1013. $et->Warn('Unknown PE magic number');
  1014. return 1;
  1015. }
  1016. } else {
  1017. $et->Warn('Error reading optional header');
  1018. }
  1019. }
  1020. # process PE COFF file header
  1021. $tagTablePtr = GetTagTable('Image::ExifTool::EXE::Main');
  1022. %dirInfo = (
  1023. DataPt => \$buff,
  1024. DataPos => $raf->Tell() - $size,
  1025. DataLen => $size,
  1026. DirStart => 4,
  1027. DirLen => $size,
  1028. );
  1029. $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
  1030. # process data dictionary
  1031. my $num = Get16u(\$buff, 6); # NumberOfSections
  1032. if ($raf->Read($buff, 40 * $num) == 40 * $num) {
  1033. %dirInfo = (
  1034. RAF => $raf,
  1035. DataPt => \$buff,
  1036. );
  1037. ProcessPEDict($et, \%dirInfo) or $et->Warn('Error processing PE data dictionary');
  1038. }
  1039. return 1;
  1040. }
  1041. } else {
  1042. $type = 'Virtual Device Driver';
  1043. $ext = '386';
  1044. }
  1045. } else {
  1046. $type = 'DOS EXE';
  1047. $ext = 'exe';
  1048. }
  1049. #
  1050. # Mach-O (Mac OS X)
  1051. #
  1052. } elsif ($buff =~ /^(\xca\xfe\xba\xbe|\xfe\xed\xfa(\xce|\xcf)|(\xce|\xcf)\xfa\xed\xfe)/ and $size > 12) {
  1053. # Mach-O executable
  1054. # (ref http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html)
  1055. $tagTablePtr = GetTagTable('Image::ExifTool::EXE::MachO');
  1056. if ($1 eq "\xca\xfe\xba\xbe") {
  1057. SetByteOrder('MM');
  1058. $et->SetFileType('Mach-O fat binary executable', undef, '');
  1059. return 1 if $fast3;
  1060. my $count = Get32u(\$buff, 4); # get architecture count
  1061. my $more = $count * 20 - ($size - 8);
  1062. if ($more > 0) {
  1063. unless ($raf->Read($buf2, $more) == $more) {
  1064. $et->Warn('Error reading fat-arch headers');
  1065. return 1;
  1066. }
  1067. $buff .= $buf2;
  1068. $size += $more;
  1069. }
  1070. $et->HandleTag($tagTablePtr, 2, $count);
  1071. my $i;
  1072. for ($i=0; $i<$count; ++$i) {
  1073. my $cpuType = Get32s(\$buff, 8 + $i * 20);
  1074. my $cpuSubtype = Get32u(\$buff, 12 + $i * 20);
  1075. $et->HandleTag($tagTablePtr, 3, $cpuType);
  1076. $et->HandleTag($tagTablePtr, 4, "$cpuType $cpuSubtype");
  1077. }
  1078. # load first Mach-O header to get the object file type
  1079. my $offset = Get32u(\$buff, 16);
  1080. if ($raf->Seek($offset, 0) and $raf->Read($buf2, 16) == 16) {
  1081. if ($buf2 =~ /^(\xfe\xed\xfa(\xce|\xcf)|(\xce|\xcf)\xfa\xed\xfe)/) {
  1082. SetByteOrder($buf2 =~ /^\xfe\xed/ ? 'MM' : 'II');
  1083. my $objType = Get32s(\$buf2, 12);
  1084. $et->HandleTag($tagTablePtr, 5, $objType);
  1085. } elsif ($buf2 =~ /^!<arch>\x0a/) {
  1086. # .a libraries use this magic number
  1087. $et->HandleTag($tagTablePtr, 5, -1);
  1088. } else {
  1089. $et->Warn('Unrecognized object file type');
  1090. }
  1091. } else {
  1092. $et->Warn('Error reading file');
  1093. }
  1094. } elsif ($size >= 16) {
  1095. $et->SetFileType('Mach-O executable', undef, '');
  1096. return 1 if $fast3;
  1097. my $info = {
  1098. "\xfe\xed\xfa\xce" => ['32 bit', 'Big endian'],
  1099. "\xce\xfa\xed\xfe" => ['32 bit', 'Little endian'],
  1100. "\xfe\xed\xfa\xcf" => ['64 bit', 'Big endian'],
  1101. "\xcf\xfa\xed\xfe" => ['64 bit', 'Little endian'],
  1102. }->{substr($buff, 0, 4)};
  1103. my $byteOrder = ($buff =~ /^\xfe/) ? 'MM' : 'II';
  1104. SetByteOrder($byteOrder);
  1105. my $cpuType = Get32s(\$buff, 4);
  1106. my $cpuSubtype = Get32s(\$buff, 8);
  1107. my $objType = Get32s(\$buff, 12);
  1108. $et->HandleTag($tagTablePtr, 0, $$info[0]);
  1109. $et->HandleTag($tagTablePtr, 1, $$info[1]);
  1110. $et->HandleTag($tagTablePtr, 3, $cpuType);
  1111. $et->HandleTag($tagTablePtr, 4, "$cpuType $cpuSubtype");
  1112. $et->HandleTag($tagTablePtr, 5, $objType);
  1113. }
  1114. return 1;
  1115. #
  1116. # PEF (classic MacOS)
  1117. #
  1118. } elsif ($buff =~ /^Joy!peff/ and $size > 12) {
  1119. # ref http://developer.apple.com/documentation/mac/pdf/MacOS_RT_Architectures.pdf
  1120. $et->SetFileType('Classic MacOS executable', undef, '');
  1121. return 1 if $fast3;
  1122. SetByteOrder('MM');
  1123. $tagTablePtr = GetTagTable('Image::ExifTool::EXE::PEF');
  1124. %dirInfo = (
  1125. DataPt => \$buff,
  1126. DataPos => 0,
  1127. DataLen => $size,
  1128. DirStart => 0,
  1129. DirLen => $size,
  1130. );
  1131. $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
  1132. return 1;
  1133. #
  1134. # ELF (Unix)
  1135. #
  1136. } elsif ($buff =~ /^\x7fELF/ and $size >= 16) {
  1137. $et->SetFileType('ELF executable', undef, '');
  1138. return 1 if $fast3;
  1139. SetByteOrder(Get8u(\$buff,5) == 1 ? 'II' : 'MM');
  1140. $tagTablePtr = GetTagTable('Image::ExifTool::EXE::ELF');
  1141. %dirInfo = (
  1142. DataPt => \$buff,
  1143. DataPos => 0,
  1144. DataLen => $size,
  1145. DirStart => 0,
  1146. DirLen => $size,
  1147. );
  1148. $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
  1149. return 1;
  1150. #
  1151. # various scripts (perl, sh, etc...)
  1152. #
  1153. } elsif ($buff =~ m{^#!\s*/\S*bin/(\w+)}) {
  1154. my $prog = $1;
  1155. $prog = $1 if $prog eq 'env' and $buff =~ /\b(perl|python|ruby|php)\b/;
  1156. $type = "$prog script";
  1157. $mime = "text/x-$prog";
  1158. $ext = {
  1159. perl => 'pl',
  1160. python => 'py',
  1161. ruby => 'rb',
  1162. php => 'php',
  1163. }->{$1};
  1164. # use '.sh' for extension of all shell scripts
  1165. $ext = $prog =~ /sh$/ ? 'sh' : '' unless defined $ext;
  1166. #
  1167. # .a libraries
  1168. #
  1169. } elsif ($buff =~ /^!<arch>\x0a/) {
  1170. $type = 'Static library';
  1171. $ext = 'a';
  1172. }
  1173. return 0 unless $type;
  1174. $et->SetFileType($type, $mime, $ext);
  1175. return 1;
  1176. }
  1177. 1; # end
  1178. __END__
  1179. =head1 NAME
  1180. Image::ExifTool::EXE - Read executable file meta information
  1181. =head1 SYNOPSIS
  1182. This module is used by Image::ExifTool
  1183. =head1 DESCRIPTION
  1184. This module contains definitions required by Image::ExifTool to extract meta
  1185. information from various types of Windows, MacOS and Unix executable and
  1186. library files.
  1187. =head1 AUTHOR
  1188. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  1189. This library is free software; you can redistribute it and/or modify it
  1190. under the same terms as Perl itself.
  1191. =head1 REFERENCES
  1192. =over 4
  1193. =item L<http://www.openwatcom.org/ftp/devel/docs/pecoff.pdf>
  1194. =item L<http://support.microsoft.com/kb/65122>
  1195. =item L<http://www.opensource.apple.com>
  1196. =item L<http://www.skyfree.org/linux/references/ELF_Format.pdf>
  1197. =item L<http://msdn.microsoft.com/en-us/library/ms809762.aspx>
  1198. =item L<http://code.google.com/p/pefile/>
  1199. =item L<http://www.codeproject.com/KB/DLL/showver.aspx>
  1200. =back
  1201. =head1 SEE ALSO
  1202. L<Image::ExifTool::TagNames/EXE Tags>,
  1203. L<Image::ExifTool(3pm)|Image::ExifTool>
  1204. =cut