Guest User


a guest
Jun 25th, 2014
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.31 KB | None | 0 0
  1. HWPatcher
  2. ---------
  4. 1) Introduction
  5. ---------------
  7. This tool is intended to a be scriptable general purpose file patcher.
  8. The underlying principle is simple: the tool provide lua-callable functions
  9. to load/save/modify binary objects (raw binary, elf, sb, edoc, formats are easily
  10. added). On top of that, a lua library also provides useful functions to
  11. manipulate addresses and to parse/generate ARM/Thumb code. This is very useful
  12. to patch jumpb addresses or generate small stubs when inserting some code into
  13. a firmware for example.
  15. 2) Builtin library
  16. ------------------
  18. The major concept of this tool is that of firmware. Conceptually, a firmware is
  19. made up of "sections" and each section can be read from or written too. The
  20. notion of section is specific to each format:
  21. - binary: there is only one section called ""
  22. - elf: these are usual elf sections
  23. - sb: sections are named "sec" to refer to a complete section block, or "sec.idx"
  24. to refer to a particular section and a particular subsection. A subsection
  25. is defined as a list of instruction ending by a call or a jump. Index start
  26. at 0.
  27. - edoc: there is only one section called ""
  29. A section is usually made up of a contiguous set of addresses but this is not
  30. mandatory. When reading from a section, all addresses must be mapped to the read
  31. to be successful. When writing to a section, it is guaranteed to succeed if
  32. all addresses are mapped, but some formats may support on-the-fly section creation
  33. or extension.
  35. Since a file can contain several section, the notion of address has to be
  36. extended. For this reason, an "address" (given to the read/write code) is a table
  37. containing two fields:
  38. - address: contain the numeric address within the section
  39. - section: optional section name
  40. If no section is specified, the code will determine if the unspecified is unique
  41. or not. If not, an error will be issued, otherwise the unique matching location
  42. will be used.
  44. NOTE: see 3) on how to create address properly
  46. The following functions are exported to the lua code:
  47. - load_file(filename) Load a firmware and guess type, return firmware
  48. - load_elf_file(filename) Load a firmware as ELF, return firmware
  49. - load_sb_file(filename) Load a firmware as SB, return firmware
  50. - load_sb1_file(filename) Load a firmware as SB1, return firmware
  51. - load_bin_file(filename) Load a firmware as binary, return firmware
  52. - save_file(obj, filename) Save a firmware to a file
  53. - read(obj, addr, len) Read data (array of bytes) from a firmware
  54. - write(obj, addr, data) Write data (array of bytes) to a firmware
  55. - section_info(obj, sec) Return information about a section in a table (or nil)
  57. Section information is provided in a table with the following fields:
  58. - addr: first address in the section
  59. - size: number of bytes after the starting address
  61. The builtin library also provides the following miscellaneous functions:
  62. - md5sum(filename) Compute the MD5 sum (array of bytes) of a file
  65. - there is no way to get the list of sections
  66. - currently the code won't extend sections on write
  67. - section information is only implemented for raw binary
  68. - section information needs to be extended to a list of [addr,size] and maybe
  69. make a difference between data and bss
  70. - add support for jump/call instruction in SB ?
  72. 3) The 'lib' library
  73. --------------------
  75. The builtin interface is rather crude to use so some extra functions are provided
  76. in the 'lib' library which can be imported using:
  78. require('lib')
  80. It contains helper functions to create addresses:
  81. - hwp.make_addr(addr, section) Create a new address
  82. - hwp.inc_addr(addr, amount) Create a new address from another with offset
  84. NOTE: you should always use hwp.make_addr() to create an address, it provides
  85. safety checks and also a default stringify method to display the address as
  86. a string nicely.
  88. There also are some convenient functions to read/write integers to firmwares:
  89. - hwp.read32(obj, addr) Read a 32-bit integer
  90. - hwp.write32(obj, addr, v) Write a 32-bit integer
  92. It also provides the following miscellaneous functions:
  93. - hwp.md5str(md5) Convert a MD5 sum into a readable string
  95. 4) The 'arm' library
  96. --------------------
  98. In order to help patching ARM/Thumb code, the 'arm' library introduces useful
  99. functions to parse and generate instructions. It can be imported using:
  101. require('arm')
  103. WARNING: although the arm library has been tested, it may generate wrong code,
  104. so do not trust it blindly.
  106. First, it is important to understand that the library differentiate ARM and Thumb
  107. code by using the least significant bit of the addresses. In order words, an
  108. address is Thumb if it's even and ARM if it's odd. An ARM address which is not
  109. word-aligned is invalid.
  111. The following functions provide warpers around this concept:
  112. - arm.is_thumb(addr) Return true if the address is Thumb
  113. - arm.xlate_addr(addr) Translate an ARM/Thumb address (*)
  114. - arm.to_thumb(addr) Take any address and make it Thumb
  115. - arm.to_arm(addr) Take any address and make it ARM
  117. (*) Translating means: for ARM address, return the address and for Thumb, return
  118. address with least significant bit cleared, in other word this is the actual
  119. address of the instruction, which is always half-word aligned
  121. It also contains a few useful integer manipulation routines to go from unsigned
  122. integers to signed, either 32-bit or n-bit:
  123. - arm.sign32(v) Convert a 32-bit unsigned integer to a signed one
  124. - arm.sign_extend(val, n) Convert a n-bit unsigned integer to a signed one
  126. The vast majority of the code in the arm library is to parse and generate
  127. branch instruction. As such, branches are a first-class citizen and have their
  128. own representation as a table containing:
  129. - type: always equal to "branch"
  130. - addr: jump address
  131. - link: boolean (true is branch & link, false is just branch)
  133. NOTE: you should always use arm.make_branch() to create a branch
  135. The library provides the following functions to work with branches:
  136. - arm.make_branch(addr, link) Create a branch instruction
  137. - arm.parse_branch(fw, addr) Parse a branch instruction
  138. - arm.write_branch(fw, addr, branch, pool) Write an instruction (*)
  140. Parsing a branch is conceptually easy: given an ARM or Thumb address, it will
  141. parse the opcode and create the corresponding branch, properly handling link
  142. and destination (either ARM or Thumb). If the instruction is not a branch,
  143. it will report an error.
  144. Creating a branch is slightly more involved: given an ARM or Thumb address, it
  145. will try to write a branch. However, given all the possible constraints (ARM/
  146. Thumb, link, destination), it is not always possible to do at all, or just within
  147. the 32-bit of the instruction. For this reason, the user can given an optional
  148. (pass nil to forbid) pool where to put some values. This is useful for indirect
  149. jumps like "ldr pc, [pool]". Note that the library does not report if it used the
  150. pool or not, so in doubt you should always advance the pool by 32-bit (4 bytes)
  151. after writing a branch, if you plan to use the pool for other values.
  153. Finally, the library provide some other useful code generation functions:
  154. - arm.write_return(fw, addr) Generate a "bx lr" instruction
  155. - arm.write_xxx_regs(fw, addr, load) Generate a "{stm,ldm}fd sp!,{r0-r12, lr}"
Add Comment
Please, Sign In to add comment