You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

148 lines
4.0 KiB

  1. // Copyright (c) 2017, Google Inc.
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. // break-hash parses an ELF binary containing the FIPS module and corrupts the
  15. // first byte of the module. This should cause the integrity check to fail.
  16. package main
  17. import (
  18. "bytes"
  19. "crypto/hmac"
  20. "crypto/sha512"
  21. "debug/elf"
  22. "encoding/hex"
  23. "errors"
  24. "fmt"
  25. "io/ioutil"
  26. "os"
  27. )
  28. func do(outPath, inPath string) error {
  29. objectBytes, err := ioutil.ReadFile(inPath)
  30. if err != nil {
  31. return err
  32. }
  33. object, err := elf.NewFile(bytes.NewReader(objectBytes))
  34. if err != nil {
  35. return errors.New("failed to parse object: " + err.Error())
  36. }
  37. // Find the .text section.
  38. var textSection *elf.Section
  39. var textSectionIndex elf.SectionIndex
  40. for i, section := range object.Sections {
  41. if section.Name == ".text" {
  42. textSectionIndex = elf.SectionIndex(i)
  43. textSection = section
  44. break
  45. }
  46. }
  47. if textSection == nil {
  48. return errors.New("failed to find .text section in object")
  49. }
  50. symbols, err := object.Symbols()
  51. if err != nil {
  52. return errors.New("failed to parse symbols: " + err.Error())
  53. }
  54. // Find the start and end markers of the module.
  55. var startSeen, endSeen bool
  56. var start, end uint64
  57. for _, symbol := range symbols {
  58. if symbol.Section != textSectionIndex {
  59. continue
  60. }
  61. switch symbol.Name {
  62. case "BORINGSSL_bcm_text_start":
  63. if startSeen {
  64. return errors.New("duplicate start symbol found")
  65. }
  66. startSeen = true
  67. start = symbol.Value
  68. case "BORINGSSL_bcm_text_end":
  69. if endSeen {
  70. return errors.New("duplicate end symbol found")
  71. }
  72. endSeen = true
  73. end = symbol.Value
  74. default:
  75. continue
  76. }
  77. }
  78. if !startSeen || !endSeen {
  79. return errors.New("could not find module in object")
  80. }
  81. moduleText := make([]byte, end-start)
  82. if n, err := textSection.ReadAt(moduleText, int64(start-textSection.Addr)); err != nil {
  83. return fmt.Errorf("failed to read from module start (at %d of %d) in .text: %s", start, textSection.Size, err)
  84. } else if n != len(moduleText) {
  85. return fmt.Errorf("short read from .text: wanted %d, got %d", len(moduleText), n)
  86. }
  87. // In order to match up the module start with the raw ELF contents,
  88. // search for the first 256 bytes and assume that will be unique.
  89. offset := bytes.Index(objectBytes, moduleText[:256])
  90. if offset < 0 {
  91. return errors.New("did not find module prefix in object file")
  92. }
  93. if bytes.Index(objectBytes[offset+1:], moduleText[:256]) >= 0 {
  94. return errors.New("found two occurrences of prefix in object file")
  95. }
  96. // Corrupt the module in the ELF.
  97. objectBytes[offset] ^= 1
  98. // Calculate the before and after hash of the module.
  99. var zeroKey [64]byte
  100. mac := hmac.New(sha512.New, zeroKey[:])
  101. mac.Write(moduleText)
  102. hashWas := mac.Sum(nil)
  103. moduleText[0] ^= 1
  104. mac.Reset()
  105. mac.Write(moduleText)
  106. newHash := mac.Sum(nil)
  107. fmt.Printf("Found start of module at offset 0x%x (VMA 0x%x):\n", start-textSection.Addr, start)
  108. fmt.Printf(hex.Dump(moduleText[:128]))
  109. fmt.Printf("\nHash of module was: %x\n", hashWas)
  110. fmt.Printf("Hash of corrupted module is: %x\n", newHash)
  111. return ioutil.WriteFile(outPath, objectBytes, 0755)
  112. }
  113. func main() {
  114. if len(os.Args) != 3 {
  115. usage()
  116. os.Exit(1)
  117. }
  118. if err := do(os.Args[2], os.Args[1]); err != nil {
  119. fmt.Fprintf(os.Stderr, "%s\n", err)
  120. os.Exit(1)
  121. }
  122. }
  123. func usage() {
  124. fmt.Fprintf(os.Stderr, "Usage: %s <input binary> <output path>\n", os.Args[0])
  125. }