msincore 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/env perl
  2. #
  3. # Copyright (c) 2012 The OpenSSL Project.
  4. #
  5. # The script embeds fingerprint into Microsoft PE-COFF executable object.
  6. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  7. unshift(@INC,$dir);
  8. require "hmac_sha1.pl";
  9. ######################################################################
  10. #
  11. # PE-COFF segment table parser by <appro@openssl.org>.
  12. #
  13. { package PECOFF;
  14. use FileHandle;
  15. sub dup { my %copy=map {$_} @_; return \%copy; }
  16. sub Load {
  17. my $class = shift;
  18. my $self = {};
  19. my $FD = FileHandle->new(); # autoclose
  20. my $file = shift;
  21. bless $self,$class;
  22. sysopen($FD,$file,0) or die "$!";
  23. binmode($FD);
  24. #################################################
  25. # read IMAGE_DOS_HEADER
  26. #
  27. read($FD,my $mz,64) or die "$!";
  28. my @dos_header=unpack("a2C58V",$mz);
  29. $!=42; # signal fipsld to revert to two-step link
  30. die "$file is not PE-COFF image" if (@dos_header[0] ne "MZ");
  31. my $e_lfanew=pop(@dos_header);
  32. seek($FD,$e_lfanew,0) or die "$!";
  33. read($FD,my $magic,4) or die "$!";
  34. $!=42; # signal fipsld to revert to two-step link
  35. die "$file is not PE-COFF image" if (unpack("V",$magic)!=0x4550);
  36. #################################################
  37. # read and parse COFF header...
  38. #
  39. read($FD,my $coff,20) or die "$!";
  40. my %coff_header;
  41. @coff_header{machine,nsects,date,syms_off,nsyms,opt,flags}=
  42. unpack("v2V3v2",$coff);
  43. my $strings;
  44. my $symsize;
  45. #################################################
  46. # load strings table
  47. #
  48. if ($coff_header{syms_off}) {
  49. seek($FD,$coff_header{syms_off}+18*$coff_header{nsyms},0) or die "$!";
  50. read($FD,$strings,4) or die "$!";
  51. $symsize = unpack("V",$strings);
  52. read($FD,$strings,$symsize,4) or die "$!";
  53. }
  54. #################################################
  55. # read sections
  56. #
  57. my $i;
  58. # seek to section headers
  59. seek($FD,$e_lfanew+24+@coff_header{opt},0) or die "$!";
  60. for ($i=0;$i<$coff_header{nsects};$i++) {
  61. my %coff_shdr;
  62. my $name;
  63. read($FD,my $section,40) or die "$!";
  64. @coff_shdr{sh_name,sh_vsize,sh_vaddr,
  65. sh_rawsize,sh_offset,sh_relocs,sh_lines,
  66. sh_nrelocls,sh_nlines,sh_flags} =
  67. unpack("a8V6v2V",$section);
  68. $name = $coff_shdr{sh_name};
  69. # see if sh_name is an offset in $strings
  70. my ($hi,$lo) = unpack("V2",$name);
  71. if ($hi==0 && $lo<$symsize) {
  72. $name = substr($strings,$lo,64);
  73. }
  74. $name = (split(chr(0),$name))[0];
  75. $coff_shdr{sh_name} = $name;
  76. $self->{sections}{$name} = dup(%coff_shdr);
  77. }
  78. return $self;
  79. }
  80. sub Lookup {
  81. my $self = shift;
  82. my $name = shift;
  83. return $self->{sections}{$name};
  84. }
  85. }
  86. ######################################################################
  87. #
  88. # main()
  89. #
  90. my $legacy_mode;
  91. if ($#ARGV<0 || ($#ARGV>0 && !($legacy_mode=(@ARGV[0] =~ /^\-(dso|exe)$/)))) {
  92. print STDERR "usage: $0 [-dso|-exe] pe-coff-binary\n";
  93. exit(1);
  94. }
  95. $exe = PECOFF->Load(@ARGV[$#ARGV]);
  96. sysopen(FD,@ARGV[$#ARGV],$legacy_mode?0:2) or die "$!"; # 2 is read/write
  97. binmode(FD);
  98. sub FIPS_incore_fingerprint {
  99. my $ctx = HMAC->Init("etaonrishdlcupfm");
  100. my ($beg,$end);
  101. my $sect;
  102. $sect = $exe->Lookup("fipstx") or die "no fipstx section";
  103. seek(FD,$sect->{sh_offset},0) or die "$!";
  104. read(FD,$blob,$sect->{sh_vsize}) or die "$!";
  105. ($beg = index($blob,"SPIFxet_ts_tXtra")) >= 0
  106. or die "no FIPS_text_startX";
  107. ($end = rindex($blob,"SPIFxet_ne_t][Xd")) >= 0
  108. or die "no FIPS_text_endX";
  109. $ctx->Update(substr($blob,$beg,$end-$beg));
  110. $sect = $exe->Lookup("fipsro") or die "no fipsro section";
  111. seek(FD,$sect->{sh_offset},0) or die "$!";
  112. read(FD,$blob,$sect->{sh_vsize}) or die "$!";
  113. ($beg = index($blob,"SPIFdor__atarats",40)) >= 0
  114. or die "no FIPS_rodata_start";
  115. ($end = rindex($blob,"SPIFdor__ata[dne")) >= 0
  116. or die "no FIPS_rodata_end";
  117. $ctx->Update(substr($blob,$beg,$end-$beg));
  118. return $ctx->Final();
  119. }
  120. $fingerprint = FIPS_incore_fingerprint();
  121. if ($legacy_mode) {
  122. print unpack("H*",$fingerprint);
  123. } else {
  124. my $sect = $exe->Lookup("fipsro");
  125. seek(FD,$sect->{sh_offset},0) or die "$!";
  126. print FD unpack("H*",$fingerprint) or die "$!";
  127. }
  128. close (FD);