Leaked source code of windows server 2003
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.

335 lines
15 KiB

  1. This is an overview document describing how to create module patches
  2. in Windows 95.
  3. Legal aspects:
  4. --------------
  5. While we are obviously using this module-patching technology to
  6. make already-shipping apps run or run better, it is possible
  7. for us to make a mistake and wrongly patch a module. For example,
  8. there might be two similar versions of an app which need to be
  9. patched differently, but we only know about one of them. Due to the
  10. obvious liability concerns, we need to obtain authorization from
  11. the app vendor for each module patch we put into the registry.
  12. The letter must specify the name of the module, the number of the
  13. segment taking the patch, the bytes being replaced, and the new
  14. bytes taking their place. The letter can be from any responsible
  15. person at the vendor, eg. an engineer who is familiar with the code.
  16. At the same time, talking to the vendor will help us find out how
  17. many different versions there are of an app, so we can figure out
  18. how to patch each one.
  19. See brianrey if you have a module patch you want to check in.
  20. It would be a good idea to get the ball rolling on getting the
  21. letter as soon as possible after you know what the patch is, since
  22. it can sometimes take a while to get these things taken care of.
  23. We already get similar letters for app-hack bits.
  24. How to check in a patch:
  25. ------------------------
  26. Since the patch values go in the registry, and since the initial registry
  27. contents are owned by setup, you must work with Andy Hill to get your
  28. module patches checked in.
  29. A common mistake when adding app-patches to msbase.inx is to leave out
  30. field 4 (field 3 if you are a computer), which are flags. The reason
  31. for the confusion is the flag that means "This is a binary regkey" is 01,
  32. and the opcode for "Change" is also 01, so everything just shifts down
  33. one step and nobody gets hurt. Except that the patch doesn't work.
  34. eg: If you want to add a key whose value is <01,09,70,00,02,ff,76,eb,15>
  35. WRONG
  36. HKLM,"SYSTEM\...",Change,01,09,70,00,02,ff,76,eb,15
  37. BETTER
  38. HKLM,"SYSTEM\...",Change,1,01,09,70,00,02,ff,76,eb,15
  39. How to make a patch:
  40. --------------------
  41. All definitions of the structures used below are in core\kernel\patch.asm.
  42. The loader knows to look in the registry for patch data if the MCF_MODPATCH
  43. bit is set in the [ModuleCompatibility] section in win.ini.
  44. eg.
  45. [ModuleCompatibility]
  46. GENERIC=0x0002
  47. All registry keys and values for module-patching are stored
  48. under HKEY_LOCAL_MACHINE under REGSTR_PATH_APPPATCH:
  49. (from dev\sdk\inc\regstr.h)
  50. #define REGSTR_PATH_APPPATCH "System\\CurrentControlSet\\Control\\SessionManager\\AppPatches"
  51. The actual patches are values stored in the registry under
  52. REGSTR_PATH_APPPATCH\<mod_name>\<signature>\<segment_number>
  53. where
  54. mod_name = the module name
  55. signature = a signature string identifying the module version
  56. segment_number = the hex number of the segment receiving the patches
  57. Signatures:
  58. -----------
  59. Signatures are strings of ANSI characters representing hex numbers
  60. in nibble-swapped byte format (what you see in wdeb386 if you type
  61. db). Blanks and commas are ignored, and may be included for readability.
  62. The easiest way to create a signature is to run dev\tools\binw\gensig.
  63. eg. If you want to patch segment 3 in foo.dll, run "gensig foo.exe 3"
  64. and a tight signature will be written to stdout.
  65. type-1 and -2 signatures:
  66. A type-1 signature specifies a list of byte sequences with byte offsets
  67. (type-2 has word offsets) which must all match for the signature to match.
  68. A 0 byte-count marks the end of the list.
  69. A match-any-file signature is "0100".
  70. eg. signature = "01 02,00,4e,45 02,3e,0a,03 00" is a type-1 signature which
  71. || || || || || || || || || ||
  72. type --------++ || || || || || || || || ||
  73. || || || || || || || || ||
  74. byte count------++ || || || || || || || ||
  75. offset-------------++ || || || || || || ||
  76. match bytes-----------++-++ || || || || ||
  77. || || || || ||
  78. byte count------------------++ || || || ||
  79. offset-------------------------++ || || ||
  80. match bytes-----------------------++-++ ||
  81. ||
  82. terminating byte count------------------++
  83. matches if the 2 bytes starting at offset 0 in the exe header match
  84. 4e,45 ("NE") and if the 2 bytes starting at offset 3e match 0a,03.
  85. Note- DO NOT include a match on NE in your signature. This is just
  86. for illustrative purposes. The windows version and size(s) of the
  87. segment(s) being patched are good candidates.
  88. type-3, -4 and -5 signatures:
  89. Type-3, -4 and -5 signatures are similar to type-1 and -2 signatures,
  90. except that the offsets are offsets in the module file. Type-3 takes
  91. word offsets, type-4 takes 3-byte offsets, and type-5 takes dword offsets.
  92. eg. signature = "03,03,67,05,c2,0a,00,00"
  93. || || || || || || || ||
  94. type---------++ || || || || || || ||
  95. || || || || || || ||
  96. byte count------++ || || || || || ||
  97. file offset--------++-++ || || || ||
  98. match bytes--------------++-++-++ ||
  99. ||
  100. terminating byte count------------++
  101. matches if the 3 bytes at offset 567h in the file match c2,0a,00.
  102. type-6, -7 and -8 signatures:
  103. Type-6, -7 and -8 signatures specify the file size of the matching
  104. module. The number of bytes used to specify the matching file size
  105. is 2, 3 or 4 respectively.
  106. eg. signature = "06,d0,0c"
  107. || || ||
  108. type---------++ || ||
  109. file size-------++-++
  110. matches if the file size is 0cd0h.
  111. type-ff signatures:
  112. Type-ff signatures are meta-signatures and consist of a list of the
  113. other types of signatures. Each list element consists of a byte count
  114. and a sub-signature. A 0 byte-count ends the list.
  115. eg. signature = "ff 06,01,02,3e,0a,03,00 03,06,d0,0c 00"
  116. || || || || || || || || || || || || ||
  117. type---------++ || || || || || || || || || || || ||
  118. || || || || || || || || || || || ||
  119. byte count------++ || || || || || || || || || || ||
  120. sub-type-----------++ || || || || || || || || || ||
  121. sub-byte-count--------++ || || || || || || || || ||
  122. hExe offset--------------++ || || || || || || || ||
  123. match bytes-----------------++-++ || || || || || ||
  124. sub-type terminator---------------++ || || || || ||
  125. || || || || ||
  126. byte count---------------------------++ || || || ||
  127. sub-type--------------------------------++ || || ||
  128. file size----------------------------------++-++ ||
  129. ||
  130. terminating byte count---------------------------++
  131. matches if the 2 bytes at offset 3eh in the exe header match 0a,03
  132. and the file size is 0cd0h.
  133. Criteria for selecting a signature:
  134. -----------------------------------
  135. In terms of time required to validate a signature, the hExe types are
  136. the fastest, the file size types are next-fastest, and the file data
  137. types are the slowest. A signature specifying the expected Windows
  138. version (hExe offset 3e) and the file size is probably sufficient
  139. for most cases, since almost any code change changes the file size.
  140. A signature which also requires a file match on the bytes being replaced
  141. (if they are not fixed up and they are in a segment, they must be
  142. somewhere in the file!) is very good, but might be overkill.
  143. Since file match signatures hit the disk, they might noticeably increase
  144. the load time of the module.
  145. DO NOT match on the NE signature in the module header. This is
  146. just a waste of bytes, since it always matches.
  147. DO match on the file size unless you have a very good reason not to.
  148. If going through the ifs, this is a very cheap test.
  149. DO match on something, since we don't want to rely on just the
  150. name of the module. We have signatures. Use them. If you have
  151. no better idea (eg. there is only one version), match on the
  152. windows version, the size(s) of the segment(s) being patched, and
  153. the file size.
  154. Patch data:
  155. -----------
  156. The patch values specify sequences of bytes to add or replace.
  157. Add's must be placed after the end of the unpatched segment.
  158. The segment is GlobalReAlloc'd as necessary to contain the new code.
  159. Replace's must be within the limits of the unpatched segment,
  160. and they must match the sequence of old bytes in the patch value.
  161. Obviously, replaced bytes cannot contain fixups.
  162. The contents of the value string are not used, except to be sent
  163. to the debugger as a debugging aid when the value is loaded from
  164. the registry. The contents of the value data must be in REG_BINARY
  165. format.
  166. Example:
  167. --------
  168. Note: The registry key show below will not work as shown, since it
  169. has been broken into multiple lines for legibility. Join the lines
  170. together and it works.
  171. ==================================================================
  172. REGEDIT4
  173. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\SessionManager
  174. \AppPatches\GENERIC
  175. \ff 06,01,02,3e,0a,03,00 03,06,d0,0c 08,03,03,67,05,c2,0a,00,00 00
  176. \1]
  177. "Add"=hex:02,08,f0,03,03,c2,0a,00
  178. "Replace"=hex:01,0b,67,00,03,c2,0a,00,e9,86,03
  179. ==================================================================
  180. The Add value has data with a size of 8 bytes, saying that at offset
  181. 3f0h that the 3 bytes c2,0a,00 should be added.
  182. "Add"=hex:02,08,f0,03,03,c2,0a,00
  183. || || || || || || || ||
  184. type=Add--++ || || || || || || ||
  185. total bytes--++ || || || || || ||
  186. offset----------++-++ || || || ||
  187. byte count------------++ || || ||
  188. bytes to add-------------++-++-++
  189. The Replace value has data with a size of 0bh bytes, saying that at
  190. offset 67h that the 3 bytes c2,0a,00 should be replaced with e9,86,03.
  191. "Replace"=hex:01,0b,67,00,03,c2,0a,00,e9,86,03
  192. || || || || || || || || || || ||
  193. type=Replace--++ || || || || || || || || || ||
  194. total bytes------++ || || || || || || || || ||
  195. offset--------------++-++ || || || || || || ||
  196. byte count----------------++ || || || || || ||
  197. old bytes--------------------++-++-++ || || ||
  198. new bytes-----------------------------++-++-++
  199. The combined effect of these two changes is to replace a "retn a" at 67
  200. with "jmp 3f0" and, at 3f0 to add "retn a". The app runs exactly as
  201. before in this case, except for a small detour. When it reaches ip=67,
  202. instead of doing "retn a", it does a "jmp 3f0" and then the "retn a".
  203. Example for code segment 1 of module "INSTALL":
  204. We want to change the message number they are checking against in a WndProc
  205. from 181 to 402. So here's what ya gatta do....
  206. 1. Open a patch.ini file in your favorite editor
  207. 2. Run private\tools16\gensig.exe : gensig file.exe seg#
  208. where seg# is the 1-based HEX value of the segment you want to patch. You
  209. will see the correct segment number to use if you do a "vdmexts!lm sel"
  210. dump for the selector of interest under ntsd (it will be under the "Seg"
  211. heading).
  212. gensig install.exe 1
  213. ff06010242136500030600d600 <--- resulting hex string signature
  214. 3. Grab the resulting hex string & paste it in your patch.ini file with the
  215. following format: RegistryPath\ModuleName\HexSignature\SegNum
  216. \Registry\MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppPatches\INSTALL\ff06010242136500030600d600\1
  217. 4. Now the fun part. The patch bytes list needs to be done in groups of 4 bytes
  218. because it will be converted to DWORDS later.
  219. The first DWORD is the 1-Byte_ByteCount with a bunch of leading zeros:
  220. 0x0000000B Note: this must match the 1-Byte_ByteCount in the next DWORD
  221. See "^^Note:" at the end of this section on how to
  222. calculate this.
  223. The second DWORD takes the following format:
  224. 2-Byte_CodeOffset 1-Byte_ByteCount 1-Byte_PatchCode
  225. where the 2-Byte_CodeOffset is the same offset you would type to
  226. disassemble the code under ntsd: u seg:off
  227. For this example we want to alter 3 bytes at 1:305 so we need to write:
  228. 0x03050B01
  229. \__/\/\/
  230. \ \ \___ The 1-Byte_PatchCode (01 = "replace")
  231. \ \____ The 1-Byte_ByteCount (# bytes in the entire patch string)
  232. \______ The code offset
  233. Next write a 1-Byte_PatchByteCount followed by the PatchBytes. For the 3
  234. bytes we are replacing in this example:
  235. 03 2d 81 01 2d 02 04 00
  236. \/ \/ \___/ \/ \___/ \/ ______
  237. \ \ \ \ \ \___ Zero pad the DWORD |
  238. \ \ \ \ \_______ The value "402" |
  239. \ \ \ \__________ "Sub" instruction code |-- PatchBytes
  240. \ \ \________________ The value "181" |
  241. \ \___________________ "Sub" instruction ______|
  242. \_____________________ 1-Byte_PatchByteCount
  243. Now DWORD arrange the above 4-byte clusters:
  244. 0x01812d03 0x0004022d
  245. Put this all together as follows:
  246. Change1 = REG_BINARY 0x0000000B 0x03050B01 0x01812d03 0x0004022d
  247. \/ \/
  248. \________\__ These two will be the same
  249. ^^Note: the 1-Byte_ByteCount is the count of the bytes in all of the
  250. DWORDS we built except the first one (0x0000000B in this
  251. case) and doesn't count any of the padding zeros in the
  252. last DWORD. See below:
  253. 0 bytes 4 bytes 4 bytes 3 bytes
  254. Change1 = REG_BINARY 0x0000000B 0x03050B01 0x01812d03 0x0004022d
  255. 1-Byte_ByteCount = 4 + 4 + 3 = 0xB
  256. 5. Next add another registry path entry to the "ModuleCompatibility" section:
  257. \Registry\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ModuleCompatibility
  258. Followed by a REG_SZ entry for the Module:
  259. INSTALL = REG_SZ "0x0002"
  260. \____/
  261. \____ use "0x0002" for WOW in general
  262. and "0x8000" for RISC WOW only
  263. 6. The resulting patch.ini file should look like this:
  264. \Registry\MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppPatches\INSTALL\ff06010242136500030600d600\1
  265. Change1 = REG_BINARY 0x0000000B 0x03050B01 0x01812d03 0x0004022d
  266. \Registry\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ModuleCompatibility
  267. INSTALL = REG_SZ "0x0002"
  268. 7. Run "regini patch.ini" to update the registry
  269. 8. Install a checked krnl386 and run the app under ntsd to see any patching
  270. messages when the module loads. If you have any problems set a bp at
  271. PatchAppSegWorker in krnl386 (source: wow16\kernel31\patch.asm) and step
  272. through what's going on. Chances are you have the byte order mixed up and
  273. you can see how you will need to re-arrange the PatchBytes in patch.ini
  274. to get what you really want.