librex 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. data/README +4 -0
  2. data/lib/rex.rb +101 -0
  3. data/lib/rex.rb.ts.rb +70 -0
  4. data/lib/rex/LICENSE +29 -0
  5. data/lib/rex/arch.rb +103 -0
  6. data/lib/rex/arch/sparc.rb +75 -0
  7. data/lib/rex/arch/sparc.rb.ut.rb +18 -0
  8. data/lib/rex/arch/x86.rb +513 -0
  9. data/lib/rex/arch/x86.rb.ut.rb +93 -0
  10. data/lib/rex/assembly/nasm.rb +100 -0
  11. data/lib/rex/assembly/nasm.rb.ut.rb +22 -0
  12. data/lib/rex/codepage.map +104 -0
  13. data/lib/rex/compat.rb +281 -0
  14. data/lib/rex/constants.rb +113 -0
  15. data/lib/rex/elfparsey.rb +11 -0
  16. data/lib/rex/elfparsey/elf.rb +123 -0
  17. data/lib/rex/elfparsey/elfbase.rb +260 -0
  18. data/lib/rex/elfparsey/exceptions.rb +27 -0
  19. data/lib/rex/elfscan.rb +12 -0
  20. data/lib/rex/elfscan/scanner.rb +207 -0
  21. data/lib/rex/elfscan/search.rb +46 -0
  22. data/lib/rex/encoder/alpha2.rb +31 -0
  23. data/lib/rex/encoder/alpha2/alpha_mixed.rb +68 -0
  24. data/lib/rex/encoder/alpha2/alpha_upper.rb +79 -0
  25. data/lib/rex/encoder/alpha2/generic.rb +113 -0
  26. data/lib/rex/encoder/alpha2/unicode_mixed.rb +117 -0
  27. data/lib/rex/encoder/alpha2/unicode_upper.rb +129 -0
  28. data/lib/rex/encoder/ndr.rb +89 -0
  29. data/lib/rex/encoder/ndr.rb.ut.rb +44 -0
  30. data/lib/rex/encoder/nonalpha.rb +61 -0
  31. data/lib/rex/encoder/nonupper.rb +64 -0
  32. data/lib/rex/encoder/xdr.rb +106 -0
  33. data/lib/rex/encoder/xdr.rb.ut.rb +29 -0
  34. data/lib/rex/encoder/xor.rb +69 -0
  35. data/lib/rex/encoder/xor/dword.rb +13 -0
  36. data/lib/rex/encoder/xor/dword_additive.rb +13 -0
  37. data/lib/rex/encoders/xor_dword.rb +35 -0
  38. data/lib/rex/encoders/xor_dword_additive.rb +53 -0
  39. data/lib/rex/encoders/xor_dword_additive.rb.ut.rb +12 -0
  40. data/lib/rex/encoding/xor.rb +20 -0
  41. data/lib/rex/encoding/xor.rb.ts.rb +14 -0
  42. data/lib/rex/encoding/xor/byte.rb +15 -0
  43. data/lib/rex/encoding/xor/byte.rb.ut.rb +21 -0
  44. data/lib/rex/encoding/xor/dword.rb +21 -0
  45. data/lib/rex/encoding/xor/dword.rb.ut.rb +15 -0
  46. data/lib/rex/encoding/xor/dword_additive.rb +92 -0
  47. data/lib/rex/encoding/xor/dword_additive.rb.ut.rb +15 -0
  48. data/lib/rex/encoding/xor/exceptions.rb +17 -0
  49. data/lib/rex/encoding/xor/generic.rb +146 -0
  50. data/lib/rex/encoding/xor/generic.rb.ut.rb +120 -0
  51. data/lib/rex/encoding/xor/qword.rb +15 -0
  52. data/lib/rex/encoding/xor/word.rb +21 -0
  53. data/lib/rex/encoding/xor/word.rb.ut.rb +13 -0
  54. data/lib/rex/exceptions.rb +275 -0
  55. data/lib/rex/exceptions.rb.ut.rb +44 -0
  56. data/lib/rex/exploitation/cmdstager.rb +133 -0
  57. data/lib/rex/exploitation/egghunter.rb +143 -0
  58. data/lib/rex/exploitation/egghunter.rb.ut.rb +25 -0
  59. data/lib/rex/exploitation/encryptjs.rb +77 -0
  60. data/lib/rex/exploitation/heaplib.js.b64 +331 -0
  61. data/lib/rex/exploitation/heaplib.rb +94 -0
  62. data/lib/rex/exploitation/javascriptosdetect.rb +735 -0
  63. data/lib/rex/exploitation/obfuscatejs.rb +335 -0
  64. data/lib/rex/exploitation/opcodedb.rb +818 -0
  65. data/lib/rex/exploitation/opcodedb.rb.ut.rb +279 -0
  66. data/lib/rex/exploitation/seh.rb +92 -0
  67. data/lib/rex/exploitation/seh.rb.ut.rb +19 -0
  68. data/lib/rex/file.rb +84 -0
  69. data/lib/rex/file.rb.ut.rb +16 -0
  70. data/lib/rex/image_source.rb +12 -0
  71. data/lib/rex/image_source/disk.rb +60 -0
  72. data/lib/rex/image_source/image_source.rb +46 -0
  73. data/lib/rex/image_source/memory.rb +37 -0
  74. data/lib/rex/io/bidirectional_pipe.rb +157 -0
  75. data/lib/rex/io/datagram_abstraction.rb +35 -0
  76. data/lib/rex/io/stream.rb +313 -0
  77. data/lib/rex/io/stream_abstraction.rb +186 -0
  78. data/lib/rex/io/stream_server.rb +211 -0
  79. data/lib/rex/job_container.rb +202 -0
  80. data/lib/rex/logging.rb +4 -0
  81. data/lib/rex/logging/log_dispatcher.rb +179 -0
  82. data/lib/rex/logging/log_sink.rb +42 -0
  83. data/lib/rex/logging/sinks/flatfile.rb +55 -0
  84. data/lib/rex/logging/sinks/stderr.rb +43 -0
  85. data/lib/rex/machparsey.rb +9 -0
  86. data/lib/rex/machparsey/exceptions.rb +34 -0
  87. data/lib/rex/machparsey/mach.rb +209 -0
  88. data/lib/rex/machparsey/machbase.rb +408 -0
  89. data/lib/rex/machscan.rb +9 -0
  90. data/lib/rex/machscan/scanner.rb +217 -0
  91. data/lib/rex/mime.rb +9 -0
  92. data/lib/rex/mime/header.rb +75 -0
  93. data/lib/rex/mime/message.rb +112 -0
  94. data/lib/rex/mime/part.rb +20 -0
  95. data/lib/rex/nop/opty2.rb +108 -0
  96. data/lib/rex/nop/opty2.rb.ut.rb +23 -0
  97. data/lib/rex/nop/opty2_tables.rb +300 -0
  98. data/lib/rex/ole.rb +128 -0
  99. data/lib/rex/ole/clsid.rb +47 -0
  100. data/lib/rex/ole/difat.rb +141 -0
  101. data/lib/rex/ole/directory.rb +230 -0
  102. data/lib/rex/ole/direntry.rb +240 -0
  103. data/lib/rex/ole/fat.rb +99 -0
  104. data/lib/rex/ole/header.rb +204 -0
  105. data/lib/rex/ole/minifat.rb +77 -0
  106. data/lib/rex/ole/samples/create_ole.rb +27 -0
  107. data/lib/rex/ole/samples/dir.rb +35 -0
  108. data/lib/rex/ole/samples/dump_stream.rb +34 -0
  109. data/lib/rex/ole/samples/ole_info.rb +23 -0
  110. data/lib/rex/ole/storage.rb +395 -0
  111. data/lib/rex/ole/stream.rb +53 -0
  112. data/lib/rex/ole/substorage.rb +49 -0
  113. data/lib/rex/ole/util.rb +157 -0
  114. data/lib/rex/parser/arguments.rb +97 -0
  115. data/lib/rex/parser/arguments.rb.ut.rb +67 -0
  116. data/lib/rex/parser/ini.rb +185 -0
  117. data/lib/rex/parser/ini.rb.ut.rb +29 -0
  118. data/lib/rex/parser/nmap_xml.rb +111 -0
  119. data/lib/rex/payloads.rb +1 -0
  120. data/lib/rex/payloads/win32.rb +2 -0
  121. data/lib/rex/payloads/win32/common.rb +26 -0
  122. data/lib/rex/payloads/win32/kernel.rb +53 -0
  123. data/lib/rex/payloads/win32/kernel/common.rb +54 -0
  124. data/lib/rex/payloads/win32/kernel/migration.rb +12 -0
  125. data/lib/rex/payloads/win32/kernel/recovery.rb +50 -0
  126. data/lib/rex/payloads/win32/kernel/stager.rb +171 -0
  127. data/lib/rex/peparsey.rb +12 -0
  128. data/lib/rex/peparsey/exceptions.rb +32 -0
  129. data/lib/rex/peparsey/pe.rb +188 -0
  130. data/lib/rex/peparsey/pe_memdump.rb +63 -0
  131. data/lib/rex/peparsey/pebase.rb +1655 -0
  132. data/lib/rex/peparsey/section.rb +136 -0
  133. data/lib/rex/pescan.rb +13 -0
  134. data/lib/rex/pescan/analyze.rb +309 -0
  135. data/lib/rex/pescan/scanner.rb +206 -0
  136. data/lib/rex/pescan/search.rb +56 -0
  137. data/lib/rex/platforms.rb +1 -0
  138. data/lib/rex/platforms/windows.rb +51 -0
  139. data/lib/rex/poly.rb +132 -0
  140. data/lib/rex/poly/block.rb +468 -0
  141. data/lib/rex/poly/register.rb +100 -0
  142. data/lib/rex/poly/register/x86.rb +40 -0
  143. data/lib/rex/post.rb +8 -0
  144. data/lib/rex/post/dir.rb +51 -0
  145. data/lib/rex/post/file.rb +172 -0
  146. data/lib/rex/post/file_stat.rb +220 -0
  147. data/lib/rex/post/gen.pl +13 -0
  148. data/lib/rex/post/io.rb +182 -0
  149. data/lib/rex/post/meterpreter.rb +4 -0
  150. data/lib/rex/post/meterpreter/channel.rb +438 -0
  151. data/lib/rex/post/meterpreter/channel_container.rb +54 -0
  152. data/lib/rex/post/meterpreter/channels/pool.rb +160 -0
  153. data/lib/rex/post/meterpreter/channels/pools/file.rb +62 -0
  154. data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +103 -0
  155. data/lib/rex/post/meterpreter/channels/stream.rb +87 -0
  156. data/lib/rex/post/meterpreter/client.rb +335 -0
  157. data/lib/rex/post/meterpreter/client_core.rb +274 -0
  158. data/lib/rex/post/meterpreter/dependencies.rb +3 -0
  159. data/lib/rex/post/meterpreter/extension.rb +32 -0
  160. data/lib/rex/post/meterpreter/extensions/espia/espia.rb +58 -0
  161. data/lib/rex/post/meterpreter/extensions/espia/tlv.rb +16 -0
  162. data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +94 -0
  163. data/lib/rex/post/meterpreter/extensions/incognito/tlv.rb +21 -0
  164. data/lib/rex/post/meterpreter/extensions/priv/fs.rb +118 -0
  165. data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +61 -0
  166. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +104 -0
  167. data/lib/rex/post/meterpreter/extensions/priv/tlv.rb +28 -0
  168. data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +100 -0
  169. data/lib/rex/post/meterpreter/extensions/sniffer/tlv.rb +24 -0
  170. data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +333 -0
  171. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +273 -0
  172. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +235 -0
  173. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +103 -0
  174. data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +48 -0
  175. data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +144 -0
  176. data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +73 -0
  177. data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +56 -0
  178. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +137 -0
  179. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +167 -0
  180. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +167 -0
  181. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +192 -0
  182. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +139 -0
  183. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +97 -0
  184. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +184 -0
  185. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +41 -0
  186. data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +61 -0
  187. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +361 -0
  188. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +129 -0
  189. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +55 -0
  190. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +336 -0
  191. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +141 -0
  192. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +279 -0
  193. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +182 -0
  194. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +102 -0
  195. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +174 -0
  196. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +185 -0
  197. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +227 -0
  198. data/lib/rex/post/meterpreter/inbound_packet_handler.rb +30 -0
  199. data/lib/rex/post/meterpreter/object_aliases.rb +83 -0
  200. data/lib/rex/post/meterpreter/packet.rb +596 -0
  201. data/lib/rex/post/meterpreter/packet_dispatcher.rb +409 -0
  202. data/lib/rex/post/meterpreter/packet_parser.rb +94 -0
  203. data/lib/rex/post/meterpreter/packet_response_waiter.rb +83 -0
  204. data/lib/rex/post/meterpreter/ui/console.rb +135 -0
  205. data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +62 -0
  206. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +595 -0
  207. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +108 -0
  208. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +241 -0
  209. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +61 -0
  210. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +98 -0
  211. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +51 -0
  212. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +132 -0
  213. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +187 -0
  214. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +63 -0
  215. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +376 -0
  216. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +270 -0
  217. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +484 -0
  218. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +315 -0
  219. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +95 -0
  220. data/lib/rex/post/permission.rb +26 -0
  221. data/lib/rex/post/process.rb +57 -0
  222. data/lib/rex/post/thread.rb +57 -0
  223. data/lib/rex/post/ui.rb +52 -0
  224. data/lib/rex/proto.rb +12 -0
  225. data/lib/rex/proto.rb.ts.rb +8 -0
  226. data/lib/rex/proto/dcerpc.rb +6 -0
  227. data/lib/rex/proto/dcerpc.rb.ts.rb +9 -0
  228. data/lib/rex/proto/dcerpc/client.rb +358 -0
  229. data/lib/rex/proto/dcerpc/client.rb.ut.rb +491 -0
  230. data/lib/rex/proto/dcerpc/exceptions.rb +150 -0
  231. data/lib/rex/proto/dcerpc/handle.rb +47 -0
  232. data/lib/rex/proto/dcerpc/handle.rb.ut.rb +85 -0
  233. data/lib/rex/proto/dcerpc/ndr.rb +72 -0
  234. data/lib/rex/proto/dcerpc/ndr.rb.ut.rb +41 -0
  235. data/lib/rex/proto/dcerpc/packet.rb +253 -0
  236. data/lib/rex/proto/dcerpc/packet.rb.ut.rb +56 -0
  237. data/lib/rex/proto/dcerpc/response.rb +186 -0
  238. data/lib/rex/proto/dcerpc/response.rb.ut.rb +15 -0
  239. data/lib/rex/proto/dcerpc/uuid.rb +84 -0
  240. data/lib/rex/proto/dcerpc/uuid.rb.ut.rb +46 -0
  241. data/lib/rex/proto/drda.rb +5 -0
  242. data/lib/rex/proto/drda.rb.ts.rb +17 -0
  243. data/lib/rex/proto/drda/constants.rb +49 -0
  244. data/lib/rex/proto/drda/constants.rb.ut.rb +23 -0
  245. data/lib/rex/proto/drda/packet.rb +252 -0
  246. data/lib/rex/proto/drda/packet.rb.ut.rb +109 -0
  247. data/lib/rex/proto/drda/utils.rb +123 -0
  248. data/lib/rex/proto/drda/utils.rb.ut.rb +84 -0
  249. data/lib/rex/proto/http.rb +5 -0
  250. data/lib/rex/proto/http.rb.ts.rb +12 -0
  251. data/lib/rex/proto/http/client.rb +817 -0
  252. data/lib/rex/proto/http/client.rb.ut.rb +93 -0
  253. data/lib/rex/proto/http/handler.rb +46 -0
  254. data/lib/rex/proto/http/handler/erb.rb +128 -0
  255. data/lib/rex/proto/http/handler/erb.rb.ut.rb +21 -0
  256. data/lib/rex/proto/http/handler/erb.rb.ut.rb.rhtml +1 -0
  257. data/lib/rex/proto/http/handler/proc.rb +54 -0
  258. data/lib/rex/proto/http/handler/proc.rb.ut.rb +24 -0
  259. data/lib/rex/proto/http/header.rb +161 -0
  260. data/lib/rex/proto/http/header.rb.ut.rb +46 -0
  261. data/lib/rex/proto/http/packet.rb +394 -0
  262. data/lib/rex/proto/http/packet.rb.ut.rb +165 -0
  263. data/lib/rex/proto/http/request.rb +356 -0
  264. data/lib/rex/proto/http/request.rb.ut.rb +214 -0
  265. data/lib/rex/proto/http/response.rb +85 -0
  266. data/lib/rex/proto/http/response.rb.ut.rb +149 -0
  267. data/lib/rex/proto/http/server.rb +367 -0
  268. data/lib/rex/proto/http/server.rb.ut.rb +79 -0
  269. data/lib/rex/proto/smb.rb +7 -0
  270. data/lib/rex/proto/smb.rb.ts.rb +8 -0
  271. data/lib/rex/proto/smb/client.rb +1733 -0
  272. data/lib/rex/proto/smb/client.rb.ut.rb +223 -0
  273. data/lib/rex/proto/smb/constants.rb +1062 -0
  274. data/lib/rex/proto/smb/constants.rb.ut.rb +18 -0
  275. data/lib/rex/proto/smb/crypt.rb +95 -0
  276. data/lib/rex/proto/smb/crypt.rb.ut.rb +20 -0
  277. data/lib/rex/proto/smb/evasions.rb +65 -0
  278. data/lib/rex/proto/smb/exceptions.rb +846 -0
  279. data/lib/rex/proto/smb/simpleclient.rb +292 -0
  280. data/lib/rex/proto/smb/simpleclient.rb.ut.rb +128 -0
  281. data/lib/rex/proto/smb/utils.rb +514 -0
  282. data/lib/rex/proto/smb/utils.rb.ut.rb +20 -0
  283. data/lib/rex/proto/sunrpc.rb +1 -0
  284. data/lib/rex/proto/sunrpc/client.rb +195 -0
  285. data/lib/rex/script.rb +42 -0
  286. data/lib/rex/script/base.rb +59 -0
  287. data/lib/rex/script/meterpreter.rb +9 -0
  288. data/lib/rex/script/shell.rb +9 -0
  289. data/lib/rex/service.rb +48 -0
  290. data/lib/rex/service_manager.rb +141 -0
  291. data/lib/rex/service_manager.rb.ut.rb +32 -0
  292. data/lib/rex/services/local_relay.rb +423 -0
  293. data/lib/rex/socket.rb +586 -0
  294. data/lib/rex/socket.rb.ut.rb +86 -0
  295. data/lib/rex/socket/comm.rb +119 -0
  296. data/lib/rex/socket/comm/local.rb +409 -0
  297. data/lib/rex/socket/comm/local.rb.ut.rb +75 -0
  298. data/lib/rex/socket/ip.rb +129 -0
  299. data/lib/rex/socket/parameters.rb +345 -0
  300. data/lib/rex/socket/parameters.rb.ut.rb +51 -0
  301. data/lib/rex/socket/range_walker.rb +295 -0
  302. data/lib/rex/socket/range_walker.rb.ut.rb +55 -0
  303. data/lib/rex/socket/ssl_tcp.rb +184 -0
  304. data/lib/rex/socket/ssl_tcp.rb.ut.rb +39 -0
  305. data/lib/rex/socket/ssl_tcp_server.rb +122 -0
  306. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +51 -0
  307. data/lib/rex/socket/subnet_walker.rb +75 -0
  308. data/lib/rex/socket/subnet_walker.rb.ut.rb +28 -0
  309. data/lib/rex/socket/switch_board.rb +272 -0
  310. data/lib/rex/socket/switch_board.rb.ut.rb +52 -0
  311. data/lib/rex/socket/tcp.rb +76 -0
  312. data/lib/rex/socket/tcp.rb.ut.rb +64 -0
  313. data/lib/rex/socket/tcp_server.rb +67 -0
  314. data/lib/rex/socket/tcp_server.rb.ut.rb +44 -0
  315. data/lib/rex/socket/udp.rb +157 -0
  316. data/lib/rex/socket/udp.rb.ut.rb +44 -0
  317. data/lib/rex/struct2.rb +5 -0
  318. data/lib/rex/struct2/c_struct.rb +181 -0
  319. data/lib/rex/struct2/c_struct_template.rb +39 -0
  320. data/lib/rex/struct2/constant.rb +26 -0
  321. data/lib/rex/struct2/element.rb +44 -0
  322. data/lib/rex/struct2/generic.rb +73 -0
  323. data/lib/rex/struct2/restraint.rb +54 -0
  324. data/lib/rex/struct2/s_string.rb +72 -0
  325. data/lib/rex/struct2/s_struct.rb +111 -0
  326. data/lib/rex/sync.rb +6 -0
  327. data/lib/rex/sync/event.rb +94 -0
  328. data/lib/rex/sync/read_write_lock.rb +176 -0
  329. data/lib/rex/sync/ref.rb +57 -0
  330. data/lib/rex/sync/thread_safe.rb +82 -0
  331. data/lib/rex/test.rb +35 -0
  332. data/lib/rex/text.rb +1029 -0
  333. data/lib/rex/text.rb.ut.rb +168 -0
  334. data/lib/rex/time.rb +65 -0
  335. data/lib/rex/transformer.rb +115 -0
  336. data/lib/rex/transformer.rb.ut.rb +38 -0
  337. data/lib/rex/ui.rb +21 -0
  338. data/lib/rex/ui/interactive.rb +252 -0
  339. data/lib/rex/ui/output.rb +80 -0
  340. data/lib/rex/ui/output/none.rb +18 -0
  341. data/lib/rex/ui/progress_tracker.rb +96 -0
  342. data/lib/rex/ui/subscriber.rb +149 -0
  343. data/lib/rex/ui/text/color.rb +97 -0
  344. data/lib/rex/ui/text/color.rb.ut.rb +18 -0
  345. data/lib/rex/ui/text/dispatcher_shell.rb +382 -0
  346. data/lib/rex/ui/text/input.rb +117 -0
  347. data/lib/rex/ui/text/input/buffer.rb +75 -0
  348. data/lib/rex/ui/text/input/readline.rb +129 -0
  349. data/lib/rex/ui/text/input/socket.rb +95 -0
  350. data/lib/rex/ui/text/input/stdio.rb +45 -0
  351. data/lib/rex/ui/text/irb_shell.rb +55 -0
  352. data/lib/rex/ui/text/output.rb +80 -0
  353. data/lib/rex/ui/text/output/buffer.rb +65 -0
  354. data/lib/rex/ui/text/output/file.rb +37 -0
  355. data/lib/rex/ui/text/output/socket.rb +43 -0
  356. data/lib/rex/ui/text/output/stdio.rb +40 -0
  357. data/lib/rex/ui/text/progress_tracker.rb +56 -0
  358. data/lib/rex/ui/text/progress_tracker.rb.ut.rb +34 -0
  359. data/lib/rex/ui/text/shell.rb +321 -0
  360. data/lib/rex/ui/text/table.rb +254 -0
  361. data/lib/rex/ui/text/table.rb.ut.rb +55 -0
  362. data/lib/rex/zip.rb +93 -0
  363. data/lib/rex/zip/archive.rb +91 -0
  364. data/lib/rex/zip/blocks.rb +182 -0
  365. data/lib/rex/zip/entry.rb +95 -0
  366. data/lib/rex/zip/samples/comment.rb +32 -0
  367. data/lib/rex/zip/samples/mkwar.rb +138 -0
  368. data/lib/rex/zip/samples/mkzip.rb +19 -0
  369. data/lib/rex/zip/samples/recursive.rb +58 -0
  370. metadata +435 -0
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: peparsey.rb 5413 2008-02-13 02:43:56Z ramon $
4
+
5
+ module Rex
6
+ module PeParsey
7
+
8
+ end
9
+ end
10
+
11
+ require 'rex/peparsey/pe'
12
+ require 'rex/peparsey/pe_memdump'
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: exceptions.rb 5871 2008-11-10 21:18:12Z hdm $
4
+
5
+ module Rex
6
+ module PeParsey
7
+
8
+ class PeError < ::RuntimeError
9
+ end
10
+
11
+ class ParseError < PeError
12
+ end
13
+
14
+ class DosHeaderError < ParseError
15
+ end
16
+
17
+ class FileHeaderError < ParseError
18
+ end
19
+
20
+ class OptionalHeaderError < ParseError
21
+ end
22
+
23
+ class BoundsError < PeError
24
+ end
25
+
26
+ class WtfError < PeError
27
+ end
28
+
29
+ class SkipError < PeError
30
+ end
31
+
32
+ end end
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: pe.rb 7730 2009-12-07 12:56:54Z sf $
4
+
5
+ require 'rex/image_source'
6
+ require 'rex/peparsey/exceptions'
7
+ require 'rex/peparsey/pebase'
8
+ require 'rex/peparsey/section'
9
+ require 'rex/struct2'
10
+
11
+ module Rex
12
+ module PeParsey
13
+ class Pe < PeBase
14
+
15
+ def initialize(isource)
16
+
17
+ #
18
+ # DOS Header
19
+ #
20
+ # Parse the initial dos header, starting at the file beginning
21
+ #
22
+ offset = 0
23
+ dos_header = self.class._parse_dos_header(isource.read(offset, IMAGE_DOS_HEADER_SIZE))
24
+
25
+ #
26
+ # File Header
27
+ #
28
+ # If there is going to be a PE, the dos header tells us where to find it
29
+ # So now we try to parse the file (pe) header
30
+ #
31
+ offset += dos_header.e_lfanew
32
+
33
+ # most likely an invalid e_lfanew...
34
+ if offset > isource.size
35
+ raise FileHeaderError, "e_lfanew looks invalid", caller
36
+ end
37
+
38
+ file_header = self.class._parse_file_header(isource.read(offset, IMAGE_FILE_HEADER_SIZE))
39
+
40
+ #
41
+ # Optional Header
42
+ #
43
+ # After the file header, we find the optional header. Right now
44
+ # we require a optional header. Despite it's name, all binaries
45
+ # that we are interested in should have one. We need this
46
+ # header for a lot of stuff, so we die without it...
47
+ #
48
+ offset += IMAGE_FILE_HEADER_SIZE
49
+ optional_header = self.class._parse_optional_header(
50
+ isource.read(offset, file_header.SizeOfOptionalHeader)
51
+ )
52
+
53
+ if !optional_header
54
+ raise OptionalHeaderError, "No optional header!", caller
55
+ end
56
+
57
+ base = optional_header.ImageBase
58
+
59
+ #
60
+ # Section Headers
61
+ #
62
+ # After the optional header should be the section headers.
63
+ # We know how many there should be from the file header...
64
+ #
65
+ offset += file_header.SizeOfOptionalHeader
66
+
67
+ num_sections = file_header.NumberOfSections
68
+ section_headers = self.class._parse_section_headers(
69
+ isource.read(offset, IMAGE_SIZEOF_SECTION_HEADER * num_sections)
70
+ )
71
+
72
+ #
73
+ # End of Headers
74
+ #
75
+ # After the section headers (which are padded to FileAlignment)
76
+ # we should find the section data, described by the section
77
+ # headers...
78
+ #
79
+ # So this is the end of our header data, lets store this
80
+ # in an image source for possible access later...
81
+ #
82
+ offset += IMAGE_SIZEOF_SECTION_HEADER * num_sections
83
+ offset = self.class._align_offset(offset, optional_header.FileAlignment)
84
+
85
+ header_section = Section.new(isource.subsource(0, offset), 0, nil)
86
+
87
+ #
88
+ # Sections
89
+ #
90
+ # So from here on out should be section data, and then any
91
+ # trailing data (like authenticode and stuff I think)
92
+ #
93
+
94
+ sections = [ ]
95
+
96
+ section_headers.each do |section_header|
97
+
98
+ rva = section_header.VirtualAddress
99
+ size = section_header.SizeOfRawData
100
+ file_offset = section_header.PointerToRawData
101
+
102
+ sections << Section.new(
103
+ isource.subsource(file_offset, size),
104
+ rva,
105
+ section_header
106
+ )
107
+ end
108
+
109
+
110
+
111
+ #
112
+ # Save the stuffs!
113
+ #
114
+ # We have parsed enough to load the file up here, now we just
115
+ # save off all of the structures and data... We will
116
+ # save our fake header section, the real sections, etc.
117
+ #
118
+
119
+ #
120
+ # These should not be accessed directly
121
+ #
122
+
123
+ self._isource = isource
124
+
125
+ self._dos_header = dos_header
126
+ self._file_header = file_header
127
+ self._optional_header = optional_header
128
+ self._section_headers = section_headers
129
+
130
+ self.image_base = base
131
+ self.sections = sections
132
+ self.header_section = header_section
133
+
134
+ self._config_header = _parse_config_header()
135
+ self._tls_header = _parse_tls_header()
136
+
137
+ # These can be accessed directly
138
+ self.hdr = HeaderAccessor.new
139
+ self.hdr.dos = self._dos_header
140
+ self.hdr.file = self._file_header
141
+ self.hdr.opt = self._optional_header
142
+ self.hdr.sections = self._section_headers
143
+ self.hdr.config = self._config_header
144
+ self.hdr.tls = self._tls_header
145
+ self.hdr.exceptions = self._exception_header
146
+
147
+ # We load the exception directory last as it relies on hdr.file to be created above.
148
+ self._exception_header = _load_exception_directory()
149
+ end
150
+
151
+ #
152
+ # Return everything that's going to be mapped in the process
153
+ # and accessable. This should include all of the sections
154
+ # and our "fake" section for the header data...
155
+ #
156
+ def all_sections
157
+ [ header_section ] + sections
158
+ end
159
+
160
+ #
161
+ # Returns true if this binary is for a 64-bit architecture.
162
+ #
163
+ def ptr_64?
164
+ [
165
+ IMAGE_FILE_MACHINE_IA64,
166
+ IMAGE_FILE_MACHINE_ALPHA64,
167
+ IMAGE_FILE_MACHINE_AMD64
168
+ ].include?(self._file_header.Machine)
169
+ end
170
+
171
+ #
172
+ # Returns true if this binary is for a 32-bit architecture.
173
+ # This check does not take into account 16-bit binaries at the moment.
174
+ #
175
+ def ptr_32?
176
+ ptr_64? == false
177
+ end
178
+
179
+ #
180
+ # Converts a virtual address to a string representation based on the
181
+ # underlying architecture.
182
+ #
183
+ def ptr_s(va)
184
+ (ptr_32?) ? ("0x%.8x" % va) : ("0x%.16x" % va)
185
+ end
186
+
187
+ end end end
188
+
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: pe_memdump.rb 5871 2008-11-10 21:18:12Z hdm $
4
+
5
+ require 'rex/image_source'
6
+ require 'rex/peparsey/exceptions'
7
+ require 'rex/peparsey/pebase'
8
+ require 'rex/peparsey/section'
9
+ require 'rex/struct2'
10
+
11
+ #
12
+ # This class is for use with memdump.exe generated dump images. It basically
13
+ # just lies, gets the ImageBase from the file name, and generates 1 big
14
+ # header_section with all of the data in it...
15
+ #
16
+
17
+ module Rex
18
+ module PeParsey
19
+ class PeMemDump < Pe
20
+
21
+ def self.new_from_string(data)
22
+ raise NotImplementError
23
+ end
24
+
25
+ def self.new_from_file(filename, disk_backed = false)
26
+
27
+ if filename[-4, 4] != '.rng'
28
+ raise "Not a .rng file: #{filename}"
29
+ end
30
+
31
+ if filename[-9, 9] == "index.rng"
32
+ raise SkipError
33
+ end
34
+
35
+ file = File.open(filename, 'rb')
36
+
37
+ if disk_backed
38
+ obj = ImageSource::Disk.new(file)
39
+ else
40
+ obj = ImageSource::Memory.new(file.read)
41
+ obj.close
42
+ end
43
+
44
+ return self.new(obj, filename.gsub(/.*[\/\\]/, '')[0,8].hex)
45
+ end
46
+
47
+ def initialize(isource, base)
48
+ self._isource = isource
49
+ self.header_section = Section.new(isource, base, nil)
50
+ self.sections = [ self.header_section ]
51
+ self.image_base = 0
52
+ end
53
+
54
+ def all_sections
55
+ self.sections
56
+ end
57
+
58
+ # No 64-bit support
59
+ def ptr_64?
60
+ false
61
+ end
62
+
63
+ end end end
@@ -0,0 +1,1655 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: pebase.rb 7730 2009-12-07 12:56:54Z sf $
4
+
5
+ require 'rex/peparsey/exceptions'
6
+ require 'rex/struct2'
7
+
8
+ module Rex
9
+ module PeParsey
10
+ class PeBase
11
+
12
+
13
+ # #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
14
+
15
+ IMAGE_DOS_SIGNATURE = 0x5a4d
16
+
17
+ #
18
+ # typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
19
+ # WORD e_magic; // Magic number
20
+ # WORD e_cblp; // Bytes on last page of file
21
+ # WORD e_cp; // Pages in file
22
+ # WORD e_crlc; // Relocations
23
+ # WORD e_cparhdr; // Size of header in paragraphs
24
+ # WORD e_minalloc; // Minimum extra paragraphs needed
25
+ # WORD e_maxalloc; // Maximum extra paragraphs needed
26
+ # WORD e_ss; // Initial (relative) SS value
27
+ # WORD e_sp; // Initial SP value
28
+ # WORD e_csum; // Checksum
29
+ # WORD e_ip; // Initial IP value
30
+ # WORD e_cs; // Initial (relative) CS value
31
+ # WORD e_lfarlc; // File address of relocation table
32
+ # WORD e_ovno; // Overlay number
33
+ # WORD e_res[4]; // Reserved words
34
+ # WORD e_oemid; // OEM identifier (for e_oeminfo)
35
+ # WORD e_oeminfo; // OEM information; e_oemid specific
36
+ # WORD e_res2[10]; // Reserved words
37
+ # LONG e_lfanew; // File address of new exe header
38
+ # } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
39
+ #
40
+
41
+ IMAGE_DOS_HEADER_SIZE = 64
42
+ IMAGE_DOS_HEADER = Rex::Struct2::CStructTemplate.new(
43
+ [ 'uint16v', 'e_magic', IMAGE_DOS_SIGNATURE ],
44
+ [ 'uint16v', 'e_cblp', 0 ],
45
+ [ 'uint16v', 'e_cp', 0 ],
46
+ [ 'uint16v', 'e_crlc', 0 ],
47
+ [ 'uint16v', 'e_cparhdr', 0 ],
48
+ [ 'uint16v', 'e_minalloc', 0 ],
49
+ [ 'uint16v', 'e_maxalloc', 0 ],
50
+ [ 'uint16v', 'e_ss', 0 ],
51
+ [ 'uint16v', 'e_sp', 0 ],
52
+ [ 'uint16v', 'e_csum', 0 ],
53
+ [ 'uint16v', 'e_ip', 0 ],
54
+ [ 'uint16v', 'e_cs', 0 ],
55
+ [ 'uint16v', 'e_lfarlc', 0 ],
56
+ [ 'uint16v', 'e_ovno', 0 ],
57
+ [ 'template', 'e_res', Rex::Struct2::CStructTemplate.new(
58
+ [ 'uint16v', 'e_res_0', 0 ],
59
+ [ 'uint16v', 'e_res_1', 0 ],
60
+ [ 'uint16v', 'e_res_2', 0 ],
61
+ [ 'uint16v', 'e_res_3', 0 ]
62
+ )],
63
+ [ 'uint16v', 'e_oemid', 0 ],
64
+ [ 'uint16v', 'e_oeminfo', 0 ],
65
+ [ 'template', 'e_res2', Rex::Struct2::CStructTemplate.new(
66
+ [ 'uint16v', 'e_res2_0', 0 ],
67
+ [ 'uint16v', 'e_res2_1', 0 ],
68
+ [ 'uint16v', 'e_res2_2', 0 ],
69
+ [ 'uint16v', 'e_res2_3', 0 ],
70
+ [ 'uint16v', 'e_res2_4', 0 ],
71
+ [ 'uint16v', 'e_res2_5', 0 ],
72
+ [ 'uint16v', 'e_res2_6', 0 ],
73
+ [ 'uint16v', 'e_res2_7', 0 ],
74
+ [ 'uint16v', 'e_res2_8', 0 ],
75
+ [ 'uint16v', 'e_res2_9', 0 ]
76
+ )],
77
+ [ 'uint32v', 'e_lfanew', 0 ]
78
+ )
79
+
80
+
81
+ class HeaderAccessor
82
+ attr_accessor :dos, :file, :opt, :sections, :config, :exceptions, :tls
83
+ def initialize
84
+ end
85
+ end
86
+
87
+ class GenericStruct
88
+ attr_accessor :struct
89
+ def initialize(_struct)
90
+ self.struct = _struct
91
+ end
92
+
93
+ # The following methods are just pass-throughs for struct
94
+
95
+ # Access a value
96
+ def v
97
+ struct.v
98
+ end
99
+
100
+ # Access a value by array
101
+ def [](*args)
102
+ struct[*args]
103
+ end
104
+
105
+ # Obtain an array of all fields
106
+ def keys
107
+ struct.keys
108
+ end
109
+
110
+ def method_missing(meth, *args)
111
+ v[meth.to_s] || (raise NoMethodError.new, meth)
112
+ end
113
+ end
114
+
115
+ class GenericHeader < GenericStruct
116
+ end
117
+
118
+ class DosHeader < GenericHeader
119
+
120
+ def initialize(rawdata)
121
+ dos_header = IMAGE_DOS_HEADER.make_struct
122
+
123
+ if !dos_header.from_s(rawdata)
124
+ raise DosHeaderError, "Couldn't parse IMAGE_DOS_HEADER", caller
125
+ end
126
+
127
+ if dos_header.v['e_magic'] != IMAGE_DOS_SIGNATURE
128
+ raise DosHeaderError, "Couldn't find DOS e_magic", caller
129
+ end
130
+
131
+ self.struct = dos_header
132
+ end
133
+
134
+ def e_lfanew
135
+ v['e_lfanew']
136
+ end
137
+ end
138
+
139
+
140
+ def self._parse_dos_header(rawdata)
141
+ return DosHeader.new(rawdata)
142
+ end
143
+
144
+ #
145
+ # typedef struct _IMAGE_FILE_HEADER {
146
+ # WORD Machine;
147
+ # WORD NumberOfSections;
148
+ # DWORD TimeDateStamp;
149
+ # DWORD PointerToSymbolTable;
150
+ # DWORD NumberOfSymbols;
151
+ # WORD SizeOfOptionalHeader;
152
+ # WORD Characteristics;
153
+ # } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
154
+ #
155
+ # #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
156
+ # #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
157
+ # #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
158
+ # #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
159
+ # #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
160
+ # #define IMAGE_SIZEOF_FILE_HEADER 20
161
+ #
162
+
163
+ IMAGE_NT_SIGNATURE = 0x00004550
164
+ IMAGE_FILE_MACHINE_I386 = 0x014c
165
+ IMAGE_FILE_MACHINE_IA64 = 0x0200
166
+ IMAGE_FILE_MACHINE_ALPHA64 = 0x0284
167
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664
168
+ IMAGE_FILE_HEADER_SIZE = 20+4 # because we include the signature
169
+ IMAGE_FILE_HEADER = Rex::Struct2::CStructTemplate.new(
170
+ # not really in the header, but easier for us this way
171
+ [ 'uint32v', 'NtSignature', 0 ],
172
+ [ 'uint16v', 'Machine', 0 ],
173
+ [ 'uint16v', 'NumberOfSections', 0 ],
174
+ [ 'uint32v', 'TimeDateStamp', 0 ],
175
+ [ 'uint32v', 'PointerToSymbolTable', 0 ],
176
+ [ 'uint32v', 'NumberOfSymbols', 0 ],
177
+ [ 'uint16v', 'SizeOfOptionalHeader', 0 ],
178
+ [ 'uint16v', 'Characteristics', 0 ]
179
+ )
180
+
181
+ SUPPORTED_MACHINES = [
182
+ IMAGE_FILE_MACHINE_I386,
183
+ IMAGE_FILE_MACHINE_IA64,
184
+ IMAGE_FILE_MACHINE_ALPHA64,
185
+ IMAGE_FILE_MACHINE_AMD64
186
+ ]
187
+
188
+ class FileHeader < GenericHeader
189
+ def initialize(rawdata)
190
+ file_header = IMAGE_FILE_HEADER.make_struct
191
+
192
+ if !file_header.from_s(rawdata)
193
+ raise FileHeaderError, "Couldn't parse IMAGE_FILE_HEADER", caller
194
+ end
195
+
196
+ if file_header.v['NtSignature'] != IMAGE_NT_SIGNATURE
197
+ raise FileHeaderError, "Couldn't find the PE magic!"
198
+ end
199
+
200
+ if SUPPORTED_MACHINES.include?(file_header.v['Machine']) == false
201
+ raise FileHeaderError, "Unsupported machine type: #{file_header.v['Machine']}", caller
202
+ end
203
+
204
+ self.struct = file_header
205
+ end
206
+
207
+ def Machine
208
+ v['Machine']
209
+ end
210
+
211
+ def SizeOfOptionalHeader
212
+ v['SizeOfOptionalHeader']
213
+ end
214
+
215
+ def NumberOfSections
216
+ v['NumberOfSections']
217
+ end
218
+ end
219
+
220
+ def self._parse_file_header(rawdata)
221
+ return FileHeader.new(rawdata)
222
+ end
223
+
224
+ #
225
+ # typedef struct _IMAGE_IMPORT_DESCRIPTOR {
226
+ # union {
227
+ # DWORD Characteristics; // 0 for terminating null import descriptor
228
+ # DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
229
+ # };
230
+ # DWORD TimeDateStamp; // 0 if not bound,
231
+ # // -1 if bound, and real date\time stamp
232
+ # // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
233
+ # // O.W. date/time stamp of DLL bound to (Old BIND)
234
+ #
235
+ # DWORD ForwarderChain; // -1 if no forwarders
236
+ # DWORD Name;
237
+ # DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
238
+ # } IMAGE_IMPORT_DESCRIPTOR;
239
+ #
240
+ IMAGE_ORDINAL_FLAG32 = 0x80000000
241
+ IMAGE_IMPORT_DESCRIPTOR_SIZE = 20
242
+ IMAGE_IMPORT_DESCRIPTOR = Rex::Struct2::CStructTemplate.new(
243
+ [ 'uint32v', 'OriginalFirstThunk', 0 ],
244
+ [ 'uint32v', 'TimeDateStamp', 0 ],
245
+ [ 'uint32v', 'ForwarderChain', 0 ],
246
+ [ 'uint32v', 'Name', 0 ],
247
+ [ 'uint32v', 'FirstThunk', 0 ]
248
+ )
249
+
250
+ #
251
+ # typedef struct _IMAGE_IMPORT_BY_NAME {
252
+ # WORD Hint;
253
+ # BYTE Name[1];
254
+ # } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
255
+ #
256
+
257
+ class ImportDescriptor
258
+ attr_accessor :name, :entries
259
+ def initialize(_name, _entries)
260
+ self.name = _name
261
+ self.entries = _entries
262
+ end
263
+ end
264
+
265
+ class ImportEntry
266
+ attr_accessor :name, :ordinal
267
+ def initialize(_name, _ordinal)
268
+ self.name = _name
269
+ self.ordinal = _ordinal
270
+ end
271
+ end
272
+
273
+ #
274
+ # typedef struct _IMAGE_EXPORT_DIRECTORY {
275
+ # DWORD Characteristics;
276
+ # DWORD TimeDateStamp;
277
+ # WORD MajorVersion;
278
+ # WORD MinorVersion;
279
+ # DWORD Name;
280
+ # DWORD Base;
281
+ # DWORD NumberOfFunctions;
282
+ # DWORD NumberOfNames;
283
+ # DWORD AddressOfFunctions; // RVA from base of image
284
+ # DWORD AddressOfNames; // RVA from base of image
285
+ # DWORD AddressOfNameOrdinals; // RVA from base of image
286
+ # } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
287
+ #
288
+ IMAGE_EXPORT_DESCRIPTOR_SIZE = 40
289
+ IMAGE_EXPORT_DESCRIPTOR = Rex::Struct2::CStructTemplate.new(
290
+ [ 'uint32v', 'Characteristics', 0 ],
291
+ [ 'uint32v', 'TimeDateStamp', 0 ],
292
+ [ 'uint16v', 'MajorVersion', 0 ],
293
+ [ 'uint16v', 'MinorVersion', 0 ],
294
+ [ 'uint32v', 'Name', 0 ],
295
+ [ 'uint32v', 'Base', 0 ],
296
+ [ 'uint32v', 'NumberOfFunctions', 0 ],
297
+ [ 'uint32v', 'NumberOfNames', 0 ],
298
+ [ 'uint32v', 'AddressOfFunctions', 0 ],
299
+ [ 'uint32v', 'AddressOfNames', 0 ],
300
+ [ 'uint32v', 'AddressOfNameOrdinals', 0 ]
301
+ )
302
+
303
+ class ExportDirectory
304
+ attr_accessor :name, :entries, :base
305
+
306
+ def initialize(_name, _entries, _base)
307
+ self.name = _name
308
+ self.entries = _entries
309
+ self.base = _base
310
+ end
311
+ end
312
+
313
+ class ExportEntry
314
+ attr_accessor :name, :ordinal, :rva
315
+ def initialize(_name, _ordinal, _rva)
316
+ self.name = _name
317
+ self.ordinal = _ordinal
318
+ self.rva = _rva
319
+ end
320
+ end
321
+
322
+ #
323
+ # typedef struct _IMAGE_DATA_DIRECTORY {
324
+ # DWORD VirtualAddress;
325
+ # DWORD Size;
326
+ # } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
327
+ #
328
+ IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
329
+ IMAGE_DATA_DIRECTORY_SIZE = 8
330
+ IMAGE_DIRECTORY_ENTRY_EXPORT = 0
331
+ IMAGE_DIRECTORY_ENTRY_IMPORT = 1
332
+ IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
333
+ IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
334
+ IMAGE_DIRECTORY_ENTRY_SECURITY = 4
335
+ IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
336
+ IMAGE_DIRECTORY_ENTRY_DEBUG = 6
337
+ IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7
338
+ IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7
339
+ IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
340
+ IMAGE_DIRECTORY_ENTRY_TLS = 9
341
+ IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10
342
+ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11
343
+ IMAGE_DIRECTORY_ENTRY_IAT = 12
344
+ IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
345
+ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
346
+ IMAGE_DATA_DIRECTORY = Rex::Struct2::CStructTemplate.new(
347
+ [ 'uint32v', 'VirtualAddress', 0 ],
348
+ [ 'uint32v', 'Size', 0 ]
349
+ )
350
+
351
+ #
352
+ # typedef struct _IMAGE_OPTIONAL_HEADER {
353
+ # //
354
+ # // Standard fields.
355
+ # //
356
+ #
357
+ # WORD Magic;
358
+ # BYTE MajorLinkerVersion;
359
+ # BYTE MinorLinkerVersion;
360
+ # DWORD SizeOfCode;
361
+ # DWORD SizeOfInitializedData;
362
+ # DWORD SizeOfUninitializedData;
363
+ # DWORD AddressOfEntryPoint;
364
+ # DWORD BaseOfCode;
365
+ # DWORD BaseOfData;
366
+ #
367
+ # //
368
+ # // NT additional fields.
369
+ # //
370
+ #
371
+ # DWORD ImageBase;
372
+ # DWORD SectionAlignment;
373
+ # DWORD FileAlignment;
374
+ # WORD MajorOperatingSystemVersion;
375
+ # WORD MinorOperatingSystemVersion;
376
+ # WORD MajorImageVersion;
377
+ # WORD MinorImageVersion;
378
+ # WORD MajorSubsystemVersion;
379
+ # WORD MinorSubsystemVersion;
380
+ # DWORD Win32VersionValue;
381
+ # DWORD SizeOfImage;
382
+ # DWORD SizeOfHeaders;
383
+ # DWORD CheckSum;
384
+ # WORD Subsystem;
385
+ # WORD DllCharacteristics;
386
+ # DWORD SizeOfStackReserve;
387
+ # DWORD SizeOfStackCommit;
388
+ # DWORD SizeOfHeapReserve;
389
+ # DWORD SizeOfHeapCommit;
390
+ # DWORD LoaderFlags;
391
+ # DWORD NumberOfRvaAndSizes;
392
+ # IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
393
+ # } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
394
+ #
395
+ # #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
396
+ # #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
397
+ #
398
+
399
+ IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
400
+ IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224
401
+ IMAGE_OPTIONAL_HEADER32 = Rex::Struct2::CStructTemplate.new(
402
+ [ 'uint16v', 'Magic', 0 ],
403
+ [ 'uint8', 'MajorLinkerVersion', 0 ],
404
+ [ 'uint8', 'MinorLinkerVersion', 0 ],
405
+ [ 'uint32v', 'SizeOfCode', 0 ],
406
+ [ 'uint32v', 'SizeOfInitializeData', 0 ],
407
+ [ 'uint32v', 'SizeOfUninitializeData', 0 ],
408
+ [ 'uint32v', 'AddressOfEntryPoint', 0 ],
409
+ [ 'uint32v', 'BaseOfCode', 0 ],
410
+ [ 'uint32v', 'BaseOfData', 0 ],
411
+ [ 'uint32v', 'ImageBase', 0 ],
412
+ [ 'uint32v', 'SectionAlignment', 0 ],
413
+ [ 'uint32v', 'FileAlignment', 0 ],
414
+ [ 'uint16v', 'MajorOperatingSystemVersion', 0 ],
415
+ [ 'uint16v', 'MinorOperatingSystemVersion', 0 ],
416
+ [ 'uint16v', 'MajorImageVersion', 0 ],
417
+ [ 'uint16v', 'MinorImageVersion', 0 ],
418
+ [ 'uint16v', 'MajorSubsystemVersion', 0 ],
419
+ [ 'uint16v', 'MinorSubsystemVersion', 0 ],
420
+ [ 'uint32v', 'Win32VersionValue', 0 ],
421
+ [ 'uint32v', 'SizeOfImage', 0 ],
422
+ [ 'uint32v', 'SizeOfHeaders', 0 ],
423
+ [ 'uint32v', 'CheckSum', 0 ],
424
+ [ 'uint16v', 'Subsystem', 0 ],
425
+ [ 'uint16v', 'DllCharacteristics', 0 ],
426
+ [ 'uint32v', 'SizeOfStackReserve', 0 ],
427
+ [ 'uint32v', 'SizeOfStackCommit', 0 ],
428
+ [ 'uint32v', 'SizeOfHeapReserve', 0 ],
429
+ [ 'uint32v', 'SizeOfHeapCommit', 0 ],
430
+ [ 'uint32v', 'LoaderFlags', 0 ],
431
+ [ 'uint32v', 'NumberOfRvaAndSizes', 0 ],
432
+ [ 'template', 'DataDirectory', Rex::Struct2::CStructTemplate.new(
433
+ [ 'template', 'DataDirectoryEntry_0', IMAGE_DATA_DIRECTORY ],
434
+ [ 'template', 'DataDirectoryEntry_1', IMAGE_DATA_DIRECTORY ],
435
+ [ 'template', 'DataDirectoryEntry_2', IMAGE_DATA_DIRECTORY ],
436
+ [ 'template', 'DataDirectoryEntry_3', IMAGE_DATA_DIRECTORY ],
437
+ [ 'template', 'DataDirectoryEntry_4', IMAGE_DATA_DIRECTORY ],
438
+ [ 'template', 'DataDirectoryEntry_5', IMAGE_DATA_DIRECTORY ],
439
+ [ 'template', 'DataDirectoryEntry_6', IMAGE_DATA_DIRECTORY ],
440
+ [ 'template', 'DataDirectoryEntry_7', IMAGE_DATA_DIRECTORY ],
441
+ [ 'template', 'DataDirectoryEntry_8', IMAGE_DATA_DIRECTORY ],
442
+ [ 'template', 'DataDirectoryEntry_9', IMAGE_DATA_DIRECTORY ],
443
+ [ 'template', 'DataDirectoryEntry_10', IMAGE_DATA_DIRECTORY ],
444
+ [ 'template', 'DataDirectoryEntry_11', IMAGE_DATA_DIRECTORY ],
445
+ [ 'template', 'DataDirectoryEntry_12', IMAGE_DATA_DIRECTORY ],
446
+ [ 'template', 'DataDirectoryEntry_13', IMAGE_DATA_DIRECTORY ],
447
+ [ 'template', 'DataDirectoryEntry_14', IMAGE_DATA_DIRECTORY ],
448
+ [ 'template', 'DataDirectoryEntry_15', IMAGE_DATA_DIRECTORY ]
449
+ )]
450
+ )
451
+
452
+ #
453
+ # typedef struct _IMAGE_OPTIONAL_HEADER64 {
454
+ # USHORT Magic;
455
+ # UCHAR MajorLinkerVersion;
456
+ # UCHAR MinorLinkerVersion;
457
+ # ULONG SizeOfCode;
458
+ # ULONG SizeOfInitializedData;
459
+ # ULONG SizeOfUninitializedData;
460
+ # ULONG AddressOfEntryPoint;
461
+ # ULONG BaseOfCode;
462
+ # ULONGLONG ImageBase;
463
+ # ULONG SectionAlignment;
464
+ # ULONG FileAlignment;
465
+ # USHORT MajorOperatingSystemVersion;
466
+ # USHORT MinorOperatingSystemVersion;
467
+ # USHORT MajorImageVersion;
468
+ # USHORT MinorImageVersion;
469
+ # USHORT MajorSubsystemVersion;
470
+ # USHORT MinorSubsystemVersion;
471
+ # ULONG Win32VersionValue;
472
+ # ULONG SizeOfImage;
473
+ # ULONG SizeOfHeaders;
474
+ # ULONG CheckSum;
475
+ # USHORT Subsystem;
476
+ # USHORT DllCharacteristics;
477
+ # ULONGLONG SizeOfStackReserve;
478
+ # ULONGLONG SizeOfStackCommit;
479
+ # ULONGLONG SizeOfHeapReserve;
480
+ # ULONGLONG SizeOfHeapCommit;
481
+ # ULONG LoaderFlags;
482
+ # ULONG NumberOfRvaAndSizes;
483
+ # IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
484
+ # } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
485
+ #
486
+ # #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
487
+ # #define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
488
+ #
489
+
490
+ IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
491
+ IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240
492
+ IMAGE_OPTIONAL_HEADER64 = Rex::Struct2::CStructTemplate.new(
493
+ [ 'uint16v', 'Magic', 0 ],
494
+ [ 'uint8', 'MajorLinkerVersion', 0 ],
495
+ [ 'uint8', 'MinorLinkerVersion', 0 ],
496
+ [ 'uint32v', 'SizeOfCode', 0 ],
497
+ [ 'uint32v', 'SizeOfInitializeData', 0 ],
498
+ [ 'uint32v', 'SizeOfUninitializeData', 0 ],
499
+ [ 'uint32v', 'AddressOfEntryPoint', 0 ],
500
+ [ 'uint32v', 'BaseOfCode', 0 ],
501
+ [ 'uint64v', 'ImageBase', 0 ],
502
+ [ 'uint32v', 'SectionAlignment', 0 ],
503
+ [ 'uint32v', 'FileAlignment', 0 ],
504
+ [ 'uint16v', 'MajorOperatingsystemVersion', 0 ],
505
+ [ 'uint16v', 'MinorOperatingsystemVersion', 0 ],
506
+ [ 'uint16v', 'MajorImageVersion', 0 ],
507
+ [ 'uint16v', 'MinorImageVersion', 0 ],
508
+ [ 'uint16v', 'MajorSubsystemVersion', 0 ],
509
+ [ 'uint16v', 'MinorSubsystemVersion', 0 ],
510
+ [ 'uint32v', 'Win32VersionValue', 0 ],
511
+ [ 'uint32v', 'SizeOfImage', 0 ],
512
+ [ 'uint32v', 'SizeOfHeaders', 0 ],
513
+ [ 'uint32v', 'CheckSum', 0 ],
514
+ [ 'uint16v', 'Subsystem', 0 ],
515
+ [ 'uint16v', 'DllCharacteristics', 0 ],
516
+ [ 'uint64v', 'SizeOfStackReserve', 0 ],
517
+ [ 'uint64v', 'SizeOfStackCommit', 0 ],
518
+ [ 'uint64v', 'SizeOfHeapReserve', 0 ],
519
+ [ 'uint64v', 'SizeOfHeapCommit', 0 ],
520
+ [ 'uint32v', 'LoaderFlags', 0 ],
521
+ [ 'uint32v', 'NumberOfRvaAndSizes', 0 ],
522
+ [ 'template', 'DataDirectory', Rex::Struct2::CStructTemplate.new(
523
+ [ 'template', 'DataDirectoryEntry_0', IMAGE_DATA_DIRECTORY ],
524
+ [ 'template', 'DataDirectoryEntry_1', IMAGE_DATA_DIRECTORY ],
525
+ [ 'template', 'DataDirectoryEntry_2', IMAGE_DATA_DIRECTORY ],
526
+ [ 'template', 'DataDirectoryEntry_3', IMAGE_DATA_DIRECTORY ],
527
+ [ 'template', 'DataDirectoryEntry_4', IMAGE_DATA_DIRECTORY ],
528
+ [ 'template', 'DataDirectoryEntry_5', IMAGE_DATA_DIRECTORY ],
529
+ [ 'template', 'DataDirectoryEntry_6', IMAGE_DATA_DIRECTORY ],
530
+ [ 'template', 'DataDirectoryEntry_7', IMAGE_DATA_DIRECTORY ],
531
+ [ 'template', 'DataDirectoryEntry_8', IMAGE_DATA_DIRECTORY ],
532
+ [ 'template', 'DataDirectoryEntry_9', IMAGE_DATA_DIRECTORY ],
533
+ [ 'template', 'DataDirectoryEntry_10', IMAGE_DATA_DIRECTORY ],
534
+ [ 'template', 'DataDirectoryEntry_11', IMAGE_DATA_DIRECTORY ],
535
+ [ 'template', 'DataDirectoryEntry_12', IMAGE_DATA_DIRECTORY ],
536
+ [ 'template', 'DataDirectoryEntry_13', IMAGE_DATA_DIRECTORY ],
537
+ [ 'template', 'DataDirectoryEntry_14', IMAGE_DATA_DIRECTORY ],
538
+ [ 'template', 'DataDirectoryEntry_15', IMAGE_DATA_DIRECTORY ]
539
+ )]
540
+ )
541
+
542
+ class OptionalHeader < GenericHeader
543
+ def ImageBase
544
+ v['ImageBase']
545
+ end
546
+ def FileAlignment
547
+ v['FileAlignment']
548
+ end
549
+ end
550
+
551
+ class OptionalHeader32 < OptionalHeader
552
+ def initialize(rawdata)
553
+ optional_header = IMAGE_OPTIONAL_HEADER32.make_struct
554
+
555
+ if !optional_header.from_s(rawdata)
556
+ raise OptionalHeaderError, "Couldn't parse IMAGE_OPTIONAL_HEADER32", caller
557
+ end
558
+
559
+ if optional_header.v['Magic'] != IMAGE_NT_OPTIONAL_HDR32_MAGIC
560
+ raise OptionalHeaderError, "Magic did not match!", caller()
561
+ end
562
+
563
+ self.struct = optional_header
564
+ end
565
+ end
566
+
567
+ class OptionalHeader64 < OptionalHeader
568
+ def initialize(rawdata)
569
+ optional_header = IMAGE_OPTIONAL_HEADER64.make_struct
570
+
571
+ if !optional_header.from_s(rawdata)
572
+ raise OptionalHeaderError, "Couldn't parse IMAGE_OPTIONAL_HEADER64", caller
573
+ end
574
+
575
+ if optional_header.v['Magic'] != IMAGE_NT_OPTIONAL_HDR64_MAGIC
576
+ raise OptionalHeaderError, "Magic did not match!", caller()
577
+ end
578
+
579
+ self.struct = optional_header
580
+ end
581
+ end
582
+
583
+ def self._parse_optional_header(rawdata)
584
+ case rawdata.length
585
+ # no optional header
586
+ when 0
587
+ return nil
588
+
589
+ # good, good
590
+ when IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
591
+ return OptionalHeader32.new(rawdata)
592
+
593
+ when IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
594
+ return OptionalHeader64.new(rawdata)
595
+
596
+ # bad, bad
597
+ else
598
+ raise OptionalHeaderError, "I don't know this header size, #{rawdata.length}", caller
599
+ end
600
+
601
+ end
602
+
603
+ #
604
+ # typedef struct _IMAGE_SECTION_HEADER {
605
+ # BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
606
+ # union {
607
+ # DWORD PhysicalAddress;
608
+ # DWORD VirtualSize;
609
+ # } Misc;
610
+ # DWORD VirtualAddress;
611
+ # DWORD SizeOfRawData;
612
+ # DWORD PointerToRawData;
613
+ # DWORD PointerToRelocations;
614
+ # DWORD PointerToLinenumbers;
615
+ # WORD NumberOfRelocations;
616
+ # WORD NumberOfLinenumbers;
617
+ # DWORD Characteristics;
618
+ # } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
619
+ #
620
+ # #define IMAGE_SIZEOF_SECTION_HEADER 40
621
+ #
622
+
623
+ IMAGE_SIZEOF_SECTION_HEADER = 40
624
+ IMAGE_SECTION_HEADER = Rex::Struct2::CStructTemplate.new(
625
+ [ 'string', 'Name', 8, '' ],
626
+ [ 'uint32v', 'Misc', 0 ],
627
+ [ 'uint32v', 'VirtualAddress', 0 ],
628
+ [ 'uint32v', 'SizeOfRawData', 0 ],
629
+ [ 'uint32v', 'PointerToRawData', 0 ],
630
+ [ 'uint32v', 'PointerToRelocations', 0 ],
631
+ [ 'uint32v', 'NumberOfRelocations', 0 ],
632
+ [ 'uint32v', 'NumberOfLineNumbers', 0 ],
633
+ [ 'uint32v', 'Characteristics', 0 ]
634
+ )
635
+
636
+ class SectionHeader < GenericHeader
637
+ def initialize(rawdata)
638
+ section_header = IMAGE_SECTION_HEADER.make_struct
639
+
640
+ if !section_header.from_s(rawdata)
641
+ raise SectionHeaderError, "Could not parse header", caller
642
+ end
643
+
644
+ self.struct = section_header
645
+ end
646
+
647
+ def VirtualAddress
648
+ v['VirtualAddress']
649
+ end
650
+ def SizeOfRawData
651
+ v['SizeOfRawData']
652
+ end
653
+ def PointerToRawData
654
+ v['PointerToRawData']
655
+ end
656
+ end
657
+
658
+ def self._parse_section_headers(rawdata)
659
+ section_headers = [ ]
660
+ size = IMAGE_SIZEOF_SECTION_HEADER
661
+ numsections = rawdata.length / size
662
+
663
+ numsections.times do |i|
664
+ data = rawdata[i * size, size]
665
+ section_headers << SectionHeader.new(data)
666
+ end
667
+
668
+ return section_headers
669
+ end
670
+
671
+ #
672
+ # typedef struct _IMAGE_BASE_RELOCATION {
673
+ # DWORD VirtualAddress;
674
+ # DWORD SizeOfBlock;
675
+ # // WORD TypeOffset[1];
676
+ # } IMAGE_BASE_RELOCATION;
677
+ # typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
678
+ #
679
+ # #define IMAGE_SIZEOF_BASE_RELOCATION 8
680
+ #
681
+ IMAGE_SIZEOF_BASE_RELOCATION = 8
682
+ IMAGE_BASE_RELOCATION = Rex::Struct2::CStructTemplate.new(
683
+ [ 'uint32v', 'VirtualAddress', 0 ],
684
+ [ 'uint32v', 'SizeOfBlock', 0 ]
685
+ )
686
+ IMAGE_BASE_RELOCATION_TYPE_OFFSET = Rex::Struct2::CStructTemplate.new(
687
+ [ 'uint16v', 'TypeOffset', 0 ]
688
+ )
689
+
690
+ class RelocationDirectory
691
+ attr_accessor :entries, :rva
692
+
693
+ def initialize(rva, entries)
694
+ self.rva = rva
695
+ self.entries = entries
696
+ self.name = name
697
+ self.characteristics = chars
698
+ self.timedate = timedate
699
+ self.version = version
700
+ self.entries = []
701
+ end
702
+ end
703
+
704
+ class RelocationEntry
705
+ attr_accessor :rva, :reltype
706
+
707
+ def initialize(_rva, _type)
708
+ self.rva = _rva
709
+ self.reltype = _type
710
+ end
711
+ end
712
+
713
+
714
+ class ResourceDirectory
715
+ attr_accessor :entries, :name
716
+
717
+ def initialize(name, entries)
718
+ self.name = name
719
+ self.entries = entries
720
+ end
721
+ end
722
+
723
+ class ResourceEntry
724
+ attr_accessor :path, :lang, :code, :rva, :size, :pe, :file
725
+
726
+ def initialize(pe, path, lang, code, rva, size, file)
727
+ self.pe = pe
728
+ self.path = path
729
+ self.lang = lang
730
+ self.code = code
731
+ self.rva = rva
732
+ self.size = size
733
+ self.file = file.to_s
734
+ end
735
+
736
+ def data
737
+ pe._isource.read(pe.rva_to_file_offset(rva), size)
738
+ end
739
+ end
740
+
741
+ #
742
+ # typedef struct {
743
+ # DWORD Size;
744
+ # DWORD TimeDateStamp;
745
+ # WORD MajorVersion;
746
+ # WORD MinorVersion;
747
+ # DWORD GlobalFlagsClear;
748
+ # DWORD GlobalFlagsSet;
749
+ # DWORD CriticalSectionDefaultTimeout;
750
+ # DWORD DeCommitFreeBlockThreshold;
751
+ # DWORD DeCommitTotalFreeThreshold;
752
+ # DWORD LockPrefixTable; // VA
753
+ # DWORD MaximumAllocationSize;
754
+ # DWORD VirtualMemoryThreshold;
755
+ # DWORD ProcessHeapFlags;
756
+ # DWORD ProcessAffinityMask;
757
+ # WORD CSDVersion;
758
+ # WORD Reserved1;
759
+ # DWORD EditList; // VA
760
+ # DWORD SecurityCookie; // VA
761
+ # DWORD SEHandlerTable; // VA
762
+ # DWORD SEHandlerCount;
763
+ # } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
764
+ #
765
+ IMAGE_LOAD_CONFIG_DIRECTORY32 = Rex::Struct2::CStructTemplate.new(
766
+ [ 'uint32v', 'Size', 0 ],
767
+ [ 'uint32v', 'TimeDateStamp', 0 ],
768
+ [ 'uint16v', 'MajorVersion', 0 ],
769
+ [ 'uint16v', 'MinorVersion', 0 ],
770
+ [ 'uint32v', 'GlobalFlagsClear', 0 ],
771
+ [ 'uint32v', 'GlobalFlagsSet', 0 ],
772
+ [ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
773
+ [ 'uint32v', 'DeCommitFreeBlockThreshold', 0 ],
774
+ [ 'uint32v', 'DeCommitTotalFreeThreshold', 0 ],
775
+ [ 'uint32v', 'LockPrefixTable', 0 ],
776
+ [ 'uint32v', 'MaximumAllocationSize', 0 ],
777
+ [ 'uint32v', 'VirtualMemoryThreshold', 0 ],
778
+ [ 'uint32v', 'ProcessHeapFlags', 0 ],
779
+ [ 'uint32v', 'ProcessAffinityMask', 0 ],
780
+ [ 'uint16v', 'CSDVersion', 0 ],
781
+ [ 'uint16v', 'Reserved1', 0 ],
782
+ [ 'uint32v', 'EditList', 0 ],
783
+ [ 'uint32v', 'SecurityCookie', 0 ],
784
+ [ 'uint32v', 'SEHandlerTable', 0 ],
785
+ [ 'uint32v', 'SEHandlerCount', 0 ]
786
+ )
787
+
788
+ #
789
+ # typedef struct {
790
+ # ULONG Size;
791
+ # ULONG TimeDateStamp;
792
+ # USHORT MajorVersion;
793
+ # USHORT MinorVersion;
794
+ # ULONG GlobalFlagsClear;
795
+ # ULONG GlobalFlagsSet;
796
+ # ULONG CriticalSectionDefaultTimeout;
797
+ # ULONGLONG DeCommitFreeBlockThreshold;
798
+ # ULONGLONG DeCommitTotalFreeThreshold;
799
+ # ULONGLONG LockPrefixTable; // VA
800
+ # ULONGLONG MaximumAllocationSize;
801
+ # ULONGLONG VirtualMemoryThreshold;
802
+ # ULONGLONG ProcessAffinityMask;
803
+ # ULONG ProcessHeapFlags;
804
+ # USHORT CSDVersion;
805
+ # USHORT Reserved1;
806
+ # ULONGLONG EditList; // VA
807
+ # ULONGLONG SecurityCookie; // VA
808
+ # ULONGLONG SEHandlerTable; // VA
809
+ # ULONGLONG SEHandlerCount;
810
+ # } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
811
+ #
812
+ IMAGE_LOAD_CONFIG_DIRECTORY64 = Rex::Struct2::CStructTemplate.new(
813
+ [ 'uint32v', 'Size', 0 ],
814
+ [ 'uint32v', 'TimeDateStamp', 0 ],
815
+ [ 'uint16v', 'MajorVersion', 0 ],
816
+ [ 'uint16v', 'MinorVersion', 0 ],
817
+ [ 'uint32v', 'GlobalFlagsClear', 0 ],
818
+ [ 'uint32v', 'GlobalFlagsSet', 0 ],
819
+ [ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
820
+ [ 'uint64v', 'DeCommitFreeBlockThreshold', 0 ],
821
+ [ 'uint64v', 'DeCommitTotalFreeThreshold', 0 ],
822
+ [ 'uint64v', 'LockPrefixTable', 0 ],
823
+ [ 'uint64v', 'MaximumAllocationSize', 0 ],
824
+ [ 'uint64v', 'VirtualMemoryThreshold', 0 ],
825
+ [ 'uint64v', 'ProcessAffinityMask', 0 ],
826
+ [ 'uint32v', 'ProcessHeapFlags', 0 ],
827
+ [ 'uint16v', 'CSDVersion', 0 ],
828
+ [ 'uint16v', 'Reserved1', 0 ],
829
+ [ 'uint64v', 'EditList', 0 ],
830
+ [ 'uint64v', 'SecurityCookie', 0 ],
831
+ [ 'uint64v', 'SEHandlerTable', 0 ],
832
+ [ 'uint64v', 'SEHandlerCount', 0 ]
833
+ )
834
+
835
+
836
+ class ConfigHeader < GenericHeader
837
+
838
+ end
839
+
840
+ # doesn't seem to be used -- not compatible with 64-bit
841
+ #def self._parse_config_header(rawdata)
842
+ # header = IMAGE_LOAD_CONFIG_DIRECTORY32.make_struct
843
+ # header.from_s(rawdata)
844
+ # ConfigHeader.new(header)
845
+ #end
846
+
847
+ def _parse_config_header
848
+
849
+ #
850
+ # Get the data directory entry, size, etc
851
+ #
852
+ exports_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]
853
+ rva = exports_entry.v['VirtualAddress']
854
+ size = exports_entry.v['Size']
855
+
856
+ return nil if size == 0
857
+
858
+ #
859
+ # Ok, so we have the data directory, now lets parse it
860
+ #
861
+
862
+ dirdata = _isource.read(rva_to_file_offset(rva), size)
863
+ klass = (ptr_64?) ? IMAGE_LOAD_CONFIG_DIRECTORY64 : IMAGE_LOAD_CONFIG_DIRECTORY32
864
+ header = klass.make_struct
865
+
866
+ header.from_s(dirdata)
867
+
868
+ @config = ConfigHeader.new(header)
869
+ end
870
+
871
+
872
+ def config
873
+ _parse_config_header if @config.nil?
874
+ @config
875
+ end
876
+
877
+ #
878
+ # TLS Directory
879
+ #
880
+
881
+ #
882
+ # typedef struct {
883
+ # DWORD Size;
884
+ # DWORD TimeDateStamp;
885
+ # WORD MajorVersion;
886
+ # WORD MinorVersion;
887
+ # DWORD GlobalFlagsClear;
888
+ # DWORD GlobalFlagsSet;
889
+ # DWORD CriticalSectionDefaultTimeout;
890
+ # DWORD DeCommitFreeBlockThreshold;
891
+ # DWORD DeCommitTotalFreeThreshold;
892
+ # DWORD LockPrefixTable; // VA
893
+ # DWORD MaximumAllocationSize;
894
+ # DWORD VirtualMemoryThreshold;
895
+ # DWORD ProcessHeapFlags;
896
+ # DWORD ProcessAffinityMask;
897
+ # WORD CSDVersion;
898
+ # WORD Reserved1;
899
+ # DWORD EditList; // VA
900
+ # DWORD SecurityCookie; // VA
901
+ # DWORD SEHandlerTable; // VA
902
+ # DWORD SEHandlerCount;
903
+ # } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
904
+ #
905
+ IMAGE_LOAD_TLS_DIRECTORY32 = Rex::Struct2::CStructTemplate.new(
906
+ [ 'uint32v', 'Size', 0 ],
907
+ [ 'uint32v', 'TimeDateStamp', 0 ],
908
+ [ 'uint16v', 'MajorVersion', 0 ],
909
+ [ 'uint16v', 'MinorVersion', 0 ],
910
+ [ 'uint32v', 'GlobalFlagsClear', 0 ],
911
+ [ 'uint32v', 'GlobalFlagsSet', 0 ],
912
+ [ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
913
+ [ 'uint32v', 'DeCommitFreeBlockThreshold', 0 ],
914
+ [ 'uint32v', 'DeCommitTotalFreeThreshold', 0 ],
915
+ [ 'uint32v', 'LockPrefixTable', 0 ],
916
+ [ 'uint32v', 'MaximumAllocationSize', 0 ],
917
+ [ 'uint32v', 'VirtualMemoryThreshold', 0 ],
918
+ [ 'uint32v', 'ProcessHeapFlags', 0 ],
919
+ [ 'uint32v', 'ProcessAffinityMask', 0 ],
920
+ [ 'uint16v', 'CSDVersion', 0 ],
921
+ [ 'uint16v', 'Reserved1', 0 ],
922
+ [ 'uint32v', 'EditList', 0 ],
923
+ [ 'uint32v', 'SecurityCookie', 0 ],
924
+ [ 'uint32v', 'SEHandlerTable', 0 ],
925
+ [ 'uint32v', 'SEHandlerCount', 0 ]
926
+ )
927
+
928
+ #
929
+ # typedef struct {
930
+ # ULONG Size;
931
+ # ULONG TimeDateStamp;
932
+ # USHORT MajorVersion;
933
+ # USHORT MinorVersion;
934
+ # ULONG GlobalFlagsClear;
935
+ # ULONG GlobalFlagsSet;
936
+ # ULONG CriticalSectionDefaultTimeout;
937
+ # ULONGLONG DeCommitFreeBlockThreshold;
938
+ # ULONGLONG DeCommitTotalFreeThreshold;
939
+ # ULONGLONG LockPrefixTable; // VA
940
+ # ULONGLONG MaximumAllocationSize;
941
+ # ULONGLONG VirtualMemoryThreshold;
942
+ # ULONGLONG ProcessAffinityMask;
943
+ # ULONG ProcessHeapFlags;
944
+ # USHORT CSDVersion;
945
+ # USHORT Reserved1;
946
+ # ULONGLONG EditList; // VA
947
+ # ULONGLONG SecurityCookie; // VA
948
+ # ULONGLONG SEHandlerTable; // VA
949
+ # ULONGLONG SEHandlerCount;
950
+ # } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
951
+ #
952
+ IMAGE_LOAD_TLS_DIRECTORY64 = Rex::Struct2::CStructTemplate.new(
953
+ [ 'uint32v', 'Size', 0 ],
954
+ [ 'uint32v', 'TimeDateStamp', 0 ],
955
+ [ 'uint16v', 'MajorVersion', 0 ],
956
+ [ 'uint16v', 'MinorVersion', 0 ],
957
+ [ 'uint32v', 'GlobalFlagsClear', 0 ],
958
+ [ 'uint32v', 'GlobalFlagsSet', 0 ],
959
+ [ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
960
+ [ 'uint64v', 'DeCommitFreeBlockThreshold', 0 ],
961
+ [ 'uint64v', 'DeCommitTotalFreeThreshold', 0 ],
962
+ [ 'uint64v', 'LockPrefixTable', 0 ],
963
+ [ 'uint64v', 'MaximumAllocationSize', 0 ],
964
+ [ 'uint64v', 'VirtualMemoryThreshold', 0 ],
965
+ [ 'uint64v', 'ProcessAffinityMask', 0 ],
966
+ [ 'uint32v', 'ProcessHeapFlags', 0 ],
967
+ [ 'uint16v', 'CSDVersion', 0 ],
968
+ [ 'uint16v', 'Reserved1', 0 ],
969
+ [ 'uint64v', 'EditList', 0 ],
970
+ [ 'uint64v', 'SecurityCookie', 0 ],
971
+ [ 'uint64v', 'SEHandlerTable', 0 ],
972
+ [ 'uint64v', 'SEHandlerCount', 0 ]
973
+ )
974
+
975
+
976
+ class TLSHeader < GenericHeader
977
+
978
+ end
979
+
980
+ def _parse_tls_header
981
+
982
+ #
983
+ # Get the data directory entry, size, etc
984
+ #
985
+ exports_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_TLS]
986
+ rva = exports_entry.v['VirtualAddress']
987
+ size = exports_entry.v['Size']
988
+
989
+ return nil if size == 0
990
+
991
+ #
992
+ # Ok, so we have the data directory, now lets parse it
993
+ #
994
+
995
+ dirdata = _isource.read(rva_to_file_offset(rva), size)
996
+ klass = (ptr_64?) ? IMAGE_LOAD_TLS_DIRECTORY64 : IMAGE_LOAD_TLS_DIRECTORY32
997
+ header = klass.make_struct
998
+
999
+ header.from_s(dirdata)
1000
+
1001
+ @tls = TLSHeader.new(header)
1002
+ end
1003
+
1004
+
1005
+ def tls
1006
+ _parse_config_header if @tls.nil?
1007
+ @tls
1008
+ end
1009
+
1010
+ ##
1011
+ #
1012
+ # Exception directory
1013
+ #
1014
+ ##
1015
+
1016
+ #
1017
+ # typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
1018
+ # DWORD BeginAddress;
1019
+ # DWORD EndAddress;
1020
+ # DWORD UnwindInfoAddress;
1021
+ # } _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
1022
+ #
1023
+ IMAGE_RUNTIME_FUNCTION_ENTRY_SZ = 12
1024
+ IMAGE_RUNTIME_FUNCTION_ENTRY = Rex::Struct2::CStructTemplate.new(
1025
+ [ 'uint32v', 'BeginAddress', 0 ],
1026
+ [ 'uint32v', 'EndAddress', 0 ],
1027
+ [ 'uint32v', 'UnwindInfoAddress', 0 ]
1028
+ )
1029
+
1030
+ UNWIND_INFO_HEADER_SZ = 4
1031
+ UNWIND_INFO_HEADER = Rex::Struct2::CStructTemplate.new(
1032
+ [ 'uint8', 'VersionFlags', 0 ],
1033
+ [ 'uint8', 'SizeOfProlog', 0 ],
1034
+ [ 'uint8', 'CountOfCodes', 0 ],
1035
+ [ 'uint8', 'FrameRegisterAndOffset', 0 ]
1036
+ )
1037
+
1038
+ UWOP_PUSH_NONVOL = 0 # 1 node
1039
+ UWOP_ALLOC_LARGE = 1 # 2 or 3 nodes
1040
+ UWOP_ALLOC_SMALL = 2 # 1 node
1041
+ UWOP_SET_FPREG = 3 # 1 node
1042
+ UWOP_SAVE_NONVOL = 4 # 2 nodes
1043
+ UWOP_SAVE_NONVOL_FAR = 5 # 3 nodes
1044
+ UWOP_SAVE_XMM128 = 8 # 2 nodes
1045
+ UWOP_SAVE_XMM128_FAR = 9 # 3 nodes
1046
+ UWOP_PUSH_MACHFRAME = 10 # 1 node
1047
+
1048
+ UNW_FLAG_EHANDLER = 1
1049
+ UNW_FLAG_UHANDLER = 2
1050
+ UNW_FLAG_CHAININFO = 4
1051
+
1052
+ class UnwindCode
1053
+ def initialize(data)
1054
+
1055
+ self.code_offset = data[0].to_i
1056
+ self.unwind_op = data[1].to_i & 0xf
1057
+ self.op_info = data[1].to_i >> 4
1058
+ self.frame_offset = data[2..3].unpack("v")[0]
1059
+
1060
+ data.slice!(0, 4)
1061
+ end
1062
+
1063
+ attr_reader :code_offset, :unwind_op, :op_info, :frame_offset
1064
+ attr_writer :code_offset, :unwind_op, :op_info, :frame_offset
1065
+
1066
+ end
1067
+
1068
+ class UnwindInfo
1069
+ def initialize(pe, unwind_rva)
1070
+ data = pe.read_rva(unwind_rva, UNWIND_INFO_HEADER_SZ)
1071
+
1072
+ unwind = UNWIND_INFO_HEADER.make_struct
1073
+ unwind.from_s(data)
1074
+
1075
+ @version = unwind.v['VersionFlags'] & 0x7
1076
+ @flags = unwind.v['VersionFlags'] >> 3
1077
+ @size_of_prolog = unwind.v['SizeOfProlog']
1078
+ @count_of_codes = unwind.v['CountOfCodes']
1079
+ @frame_register = unwind.v['FrameRegisterAndOffset'] & 0xf
1080
+ @frame_register_offset = unwind.v['FrameRegisterAndOffset'] >> 4
1081
+
1082
+ # Parse unwind codes
1083
+ clist = pe.read_rva(unwind_rva + UNWIND_INFO_HEADER_SZ, count_of_codes * 4)
1084
+
1085
+ @unwind_codes = []
1086
+
1087
+ while clist.length > 0
1088
+ @unwind_codes << UnwindCode.new(clist)
1089
+ end
1090
+ end
1091
+
1092
+ attr_reader :version, :flags, :size_of_prolog, :count_of_codes
1093
+ attr_reader :frame_register, :frame_register_offset
1094
+
1095
+ def unwind_codes
1096
+ @unwind_codes
1097
+ end
1098
+
1099
+ end
1100
+
1101
+ class RuntimeFunctionEntry
1102
+
1103
+ def initialize(pe, data)
1104
+ @pe = pe
1105
+ @begin_address, @end_address, @unwind_info_address = data.unpack("VVV");
1106
+ self.unwind_info = UnwindInfo.new(pe, unwind_info_address)
1107
+ end
1108
+
1109
+ attr_reader :begin_address, :end_address, :unwind_info_address
1110
+ attr_reader :unwind_info
1111
+ attr_writer :unwind_info
1112
+
1113
+ end
1114
+
1115
+ def _load_exception_directory
1116
+ @exception = []
1117
+
1118
+ exception_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_EXCEPTION]
1119
+ rva = exception_entry.v['VirtualAddress']
1120
+ size = exception_entry.v['Size']
1121
+
1122
+ return if (rva == 0)
1123
+
1124
+ data = _isource.read(rva_to_file_offset(rva), size)
1125
+
1126
+ case hdr.file.Machine
1127
+ when IMAGE_FILE_MACHINE_AMD64
1128
+ count = data.length / IMAGE_RUNTIME_FUNCTION_ENTRY_SZ
1129
+
1130
+ count.times { |current|
1131
+ @exception << RuntimeFunctionEntry.new(self,
1132
+ data.slice!(0, IMAGE_RUNTIME_FUNCTION_ENTRY_SZ))
1133
+ }
1134
+ else
1135
+ end
1136
+
1137
+ return @exception
1138
+ end
1139
+
1140
+
1141
+ def exception
1142
+ _load_exception_directory if @exception.nil?
1143
+ @exception
1144
+ end
1145
+
1146
+ #
1147
+ # Just a stupid routine to round an offset up to it's alignment.
1148
+ #
1149
+ # For example, you're going to want this for FileAlignment and
1150
+ # SectionAlignment, etc...
1151
+ #
1152
+ def self._align_offset(offset, alignment)
1153
+ offset += alignment - 1
1154
+ offset -= offset % alignment
1155
+ return offset
1156
+ end
1157
+
1158
+ #
1159
+ # instance stuff
1160
+ #
1161
+
1162
+ attr_accessor :_isource
1163
+ attr_accessor :_dos_header, :_file_header, :_optional_header,
1164
+ :_section_headers, :_config_header, :_tls_header, :_exception_header
1165
+
1166
+ attr_accessor :sections, :header_section, :image_base
1167
+
1168
+ attr_accessor :_imports_cache, :_imports_cached
1169
+ attr_accessor :_exports_cache, :_exports_cached
1170
+ attr_accessor :_relocations_cache, :_relocations_cached
1171
+ attr_accessor :_resources_cache, :_resources_cached
1172
+
1173
+ attr_accessor :hdr
1174
+
1175
+ def self.new_from_file(filename, disk_backed = false)
1176
+
1177
+ file = ::File.new(filename)
1178
+ file.binmode # windows... :\
1179
+
1180
+ if disk_backed
1181
+ return self.new(ImageSource::Disk.new(file))
1182
+ else
1183
+ obj = new_from_string(file.read)
1184
+ file.close
1185
+ return obj
1186
+ end
1187
+ end
1188
+
1189
+ def self.new_from_string(data)
1190
+ return self.new(ImageSource::Memory.new(data))
1191
+ end
1192
+
1193
+ def close
1194
+ _isource.close
1195
+ end
1196
+
1197
+ #
1198
+ #
1199
+ # Random rva, vma, file offset, section offset, etc
1200
+ # conversion routines...
1201
+ #
1202
+ #
1203
+ def rva_to_vma(rva)
1204
+ return rva + image_base
1205
+ end
1206
+
1207
+ def vma_to_rva(vma)
1208
+ return vma - image_base
1209
+ end
1210
+
1211
+ def rva_to_file_offset(rva)
1212
+ all_sections.each do |section|
1213
+ if section.contains_rva?(rva)
1214
+ return section.rva_to_file_offset(rva)
1215
+ end
1216
+ end
1217
+ raise WtfError, "wtf!", caller
1218
+ end
1219
+
1220
+ def vma_to_file_offset(vma)
1221
+ return rva_to_file_offset(vma_to_rva(vma))
1222
+ end
1223
+
1224
+ def file_offset_to_rva(foffset)
1225
+ if foffset < 0
1226
+ raise WtfError, "lame", caller
1227
+ end
1228
+
1229
+ all_sections.each do |section|
1230
+ if section.contains_file_offset?(foffset)
1231
+ return section.file_offset_to_rva(foffset)
1232
+ end
1233
+ end
1234
+
1235
+ raise WtfError, "wtf! #{foffset}", caller
1236
+ end
1237
+
1238
+ def file_offset_to_vma(foffset)
1239
+ return rva_to_vma(file_offset_to_rva(foffset))
1240
+ end
1241
+
1242
+ #
1243
+ #
1244
+ # Some routines to find which section something belongs
1245
+ # to. These will search all_sections (so including
1246
+ # our fake header section, etc...
1247
+ #
1248
+ #
1249
+
1250
+ #
1251
+ # Find a section by an RVA
1252
+ #
1253
+ def _find_section_by_rva(rva)
1254
+ all_sections.each do |section|
1255
+ if section.contains_rva?(rva)
1256
+ return section
1257
+ end
1258
+ end
1259
+
1260
+ return nil
1261
+ end
1262
+ def find_section_by_rva(rva)
1263
+ section = _find_section_by_rva(rva)
1264
+
1265
+ if !section
1266
+ raise WtfError, "Cannot find rva! #{rva}", caller
1267
+ end
1268
+
1269
+ return section
1270
+ end
1271
+
1272
+ #
1273
+ # Find a section by a VMA
1274
+ #
1275
+ def find_section_by_vma(vma)
1276
+ return find_section_by_rva(vma_to_rva(vma))
1277
+ end
1278
+
1279
+ def valid_rva?(rva)
1280
+ _find_section_by_rva(rva) != nil
1281
+ end
1282
+ def valid_vma?(vma)
1283
+ _find_section_by_rva(vma_to_rva(vma)) != nil
1284
+ end
1285
+
1286
+ #
1287
+ #
1288
+ # Some convenient methods to read a vma/rva without having
1289
+ # the section... (inefficent though I suppose...)
1290
+ #
1291
+ #
1292
+
1293
+ def read_rva(rva, length)
1294
+ return find_section_by_rva(rva).read_rva(rva, length)
1295
+ end
1296
+
1297
+ def read_vma(vma, length)
1298
+ return read_rva(vma_to_rva(vma), length)
1299
+ end
1300
+
1301
+ def read_asciiz_rva(rva)
1302
+ return find_section_by_rva(rva).read_asciiz_rva(rva)
1303
+ end
1304
+
1305
+ def read_asciiz_vma(vma)
1306
+ return read_asciiz_rva(vma_to_rva(vma))
1307
+ end
1308
+
1309
+ #
1310
+ #
1311
+ # Imports, exports, and other stuff!
1312
+ #
1313
+ #
1314
+
1315
+ #
1316
+ # We lazily parse the imports, and then cache it
1317
+ #
1318
+ def imports
1319
+ if !_imports_cached
1320
+ self._imports_cache = _load_imports
1321
+ self._imports_cached = true
1322
+ end
1323
+ return _imports_cache
1324
+ end
1325
+
1326
+ def _load_imports
1327
+ #
1328
+ # Get the data directory entry, size, etc
1329
+ #
1330
+ imports_entry = _optional_header['DataDirectory'][1]
1331
+ rva = imports_entry.v['VirtualAddress']
1332
+ size = imports_entry.v['Size']
1333
+
1334
+ return nil if size == 0
1335
+
1336
+ #
1337
+ # Ok, so we have the data directory, now lets parse it
1338
+ #
1339
+
1340
+ imports = [ ]
1341
+
1342
+ descriptors_data = _isource.read(rva_to_file_offset(rva), size)
1343
+
1344
+ while descriptors_data.length >= IMAGE_IMPORT_DESCRIPTOR_SIZE
1345
+ descriptor = IMAGE_IMPORT_DESCRIPTOR.make_struct
1346
+ descriptor.from_s(descriptors_data)
1347
+ descriptors_data = descriptor.leftover
1348
+
1349
+ othunk = descriptor.v['OriginalFirstThunk']
1350
+ fthunk = descriptor.v['FirstThunk']
1351
+
1352
+ break if fthunk == 0
1353
+
1354
+ dllname = _isource.read_asciiz(rva_to_file_offset(descriptor.v['Name']))
1355
+
1356
+ import = ImportDescriptor.new(dllname, [ ])
1357
+
1358
+ # we prefer the Characteristics/OriginalFirstThunk...
1359
+ thunk_off = rva_to_file_offset(othunk == 0 ? fthunk : othunk)
1360
+
1361
+ while (orgrva = _isource.read(thunk_off, 4).unpack('V')[0]) != 0
1362
+ hint = nil
1363
+ name = nil
1364
+
1365
+ if (orgrva & IMAGE_ORDINAL_FLAG32) != 0
1366
+ hint = orgrva & 0xffff
1367
+ else
1368
+ foff = rva_to_file_offset(orgrva)
1369
+ hint = _isource.read(foff, 2).unpack('v')[0]
1370
+ name = _isource.read_asciiz(foff + 2)
1371
+ end
1372
+
1373
+ import.entries << ImportEntry.new(name, hint)
1374
+
1375
+ thunk_off += 4
1376
+ end
1377
+
1378
+ imports << import
1379
+ end
1380
+
1381
+ return imports
1382
+ end
1383
+
1384
+
1385
+
1386
+ #
1387
+ # We lazily parse the exports, and then cache it
1388
+ #
1389
+ def exports
1390
+ if !_exports_cached
1391
+ self._exports_cache = _load_exports
1392
+ self._exports_cached = true
1393
+ end
1394
+ return _exports_cache
1395
+ end
1396
+
1397
+ def _load_exports
1398
+
1399
+ #
1400
+ # Get the data directory entry, size, etc
1401
+ #
1402
+ exports_entry = _optional_header['DataDirectory'][0]
1403
+ rva = exports_entry.v['VirtualAddress']
1404
+ size = exports_entry.v['Size']
1405
+
1406
+ return nil if size == 0
1407
+
1408
+ #
1409
+ # Ok, so we have the data directory, now lets parse it
1410
+ #
1411
+
1412
+ directory = IMAGE_EXPORT_DESCRIPTOR.make_struct
1413
+ directory.from_s(_isource.read(rva_to_file_offset(rva), IMAGE_EXPORT_DESCRIPTOR_SIZE))
1414
+
1415
+ #
1416
+ # We can have nameless exports, so we need to do the whole
1417
+ # NumberOfFunctions NumberOfNames foo
1418
+ #
1419
+ num_functions = directory.v['NumberOfFunctions']
1420
+ num_names = directory.v['NumberOfNames']
1421
+
1422
+ dllname_rva = directory.v['Name']
1423
+ dllname = _isource.read_asciiz(rva_to_file_offset(dllname_rva))
1424
+
1425
+ # FIXME Base, etc
1426
+ fun_off = rva_to_file_offset(directory.v['AddressOfFunctions'])
1427
+ name_off = rva_to_file_offset(directory.v['AddressOfNames'])
1428
+ ord_off = rva_to_file_offset(directory.v['AddressOfNameOrdinals'])
1429
+ base = directory.v['Base']
1430
+
1431
+ # Allocate the list of names
1432
+ names = Array.new(num_functions)
1433
+
1434
+ #
1435
+ # Iterate the names and name/ordinal list, getting the names
1436
+ # and storing them in the name list...
1437
+ #
1438
+ num_names.times do |i|
1439
+ name_rva = _isource.read(name_off + (i * 4), 4).unpack('V')[0]
1440
+ ordinal = _isource.read(ord_off + (i * 2), 2).unpack('v')[0]
1441
+ name = _isource.read_asciiz(rva_to_file_offset(name_rva))
1442
+
1443
+ # store the exported name in the name list
1444
+ names[ordinal] = name
1445
+ end
1446
+
1447
+ exports = ExportDirectory.new(dllname, [ ], base)
1448
+
1449
+ #
1450
+ # Now just iterate the functions (rvas) list..
1451
+ #
1452
+ num_functions.times do |i|
1453
+ rva = _isource.read(fun_off + (i * 4), 4).unpack('V')[0]
1454
+
1455
+ # ExportEntry.new(name, ordinal, rva)
1456
+ exports.entries << ExportEntry.new(names[i], i + base, rva)
1457
+ end
1458
+
1459
+ return exports
1460
+ end
1461
+
1462
+ #
1463
+ # Base relocations in the hizzy
1464
+ #
1465
+ def relocations
1466
+ if !_relocations_cached
1467
+ self._relocations_cache = _load_relocations
1468
+ self._relocations_cached = true
1469
+ end
1470
+ return _relocations_cache
1471
+ end
1472
+
1473
+ def _load_relocations
1474
+
1475
+ #
1476
+ # Get the data directory entry, size, etc
1477
+ #
1478
+ exports_entry = _optional_header['DataDirectory'][5]
1479
+ rva = exports_entry.v['VirtualAddress']
1480
+ size = exports_entry.v['Size']
1481
+
1482
+ return nil if size == 0
1483
+
1484
+ #
1485
+ # Ok, so we have the data directory, now lets parse it
1486
+ #
1487
+
1488
+ dirdata = _isource.read(rva_to_file_offset(rva), size)
1489
+
1490
+ relocdirs = [ ]
1491
+
1492
+ while dirdata.length >= IMAGE_SIZEOF_BASE_RELOCATION
1493
+ header = IMAGE_BASE_RELOCATION.make_struct
1494
+ header.from_s(dirdata)
1495
+ dirdata = header.leftover
1496
+
1497
+ numrelocs = (header.v['SizeOfBlock'] - IMAGE_SIZEOF_BASE_RELOCATION) / 2
1498
+
1499
+ relocbase = header.v['VirtualAddress']
1500
+
1501
+ relocdir = RelocationDirectory.new(relocbase, [ ])
1502
+
1503
+ numrelocs.times do
1504
+ reloc = IMAGE_BASE_RELOCATION_TYPE_OFFSET.make_struct
1505
+ reloc.from_s(dirdata)
1506
+ dirdata = reloc.leftover
1507
+
1508
+ typeoffset = reloc.v['TypeOffset']
1509
+
1510
+ relocrva = relocbase + (typeoffset & 0xfff)
1511
+ reloctype = (typeoffset >> 12) & 0xf
1512
+
1513
+ relocdir.entries << RelocationEntry.new(relocrva, reloctype)
1514
+ end
1515
+
1516
+ relocdirs << relocdir
1517
+ end
1518
+
1519
+ return relocdirs
1520
+ end
1521
+
1522
+
1523
+ #
1524
+ # We lazily parse the resources, and then cache them
1525
+ #
1526
+ def resources
1527
+ if !_resources_cached
1528
+ _load_resources
1529
+ self._resources_cached = true
1530
+ end
1531
+
1532
+ return self._resources_cache
1533
+ end
1534
+
1535
+ def _load_resources
1536
+ #
1537
+ # Get the data directory entry, size, etc
1538
+ #
1539
+ rsrc_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_RESOURCE]
1540
+ rva = rsrc_entry.v['VirtualAddress']
1541
+ size = rsrc_entry.v['Size']
1542
+
1543
+ return nil if size == 0
1544
+
1545
+ #
1546
+ # Ok, so we have the data directory, now lets parse it
1547
+ #
1548
+ data = _isource.read(rva_to_file_offset(rva), size)
1549
+
1550
+ self._resources_cache = {}
1551
+ _parse_resource_directory(data)
1552
+ end
1553
+
1554
+ def _parse_resource_directory(data, rname=0, rvalue=0x80000000, path='0', pname=nil)
1555
+
1556
+ pname = _parse_resource_name(data, rname)
1557
+ if (path.scan('/').length == 1)
1558
+ if (pname !~ /^\d+/)
1559
+ path = "/" + pname
1560
+ else
1561
+ path = "/" + _resource_lookup( (rname & ~0x80000000).to_s)
1562
+ end
1563
+ end
1564
+
1565
+
1566
+ rvalue &= ~0x80000000
1567
+ vals = data[rvalue, 16].unpack('VVvvvv')
1568
+
1569
+ chars = vals[0]
1570
+ tdate = vals[1]
1571
+ vers = "#{vals[2]}#{vals[3]}"
1572
+ count = vals[4] + vals[5]
1573
+
1574
+ 0.upto(count-1) do |i|
1575
+
1576
+ ename, evalue = data[rvalue + 16 + ( i * 8), 8].unpack('VV')
1577
+ epath = path + '/' + i.to_s
1578
+
1579
+ if (ename & 0x80000000 != 0)
1580
+ pname = _parse_resource_name(data, ename)
1581
+ end
1582
+
1583
+ if (evalue & 0x80000000 != 0)
1584
+ # This is a subdirectory
1585
+ _parse_resource_directory(data, ename, evalue, epath, pname)
1586
+ else
1587
+ # This is an entry
1588
+ _parse_resource_entry(data, ename, evalue, epath, pname)
1589
+ end
1590
+ end
1591
+
1592
+ end
1593
+
1594
+ def _resource_lookup(i)
1595
+ tbl = {
1596
+ '1' => 'RT_CURSOR',
1597
+ '2' => 'RT_BITMAP',
1598
+ '3' => 'RT_ICON',
1599
+ '4' => 'RT_MENU',
1600
+ '5' => 'RT_DIALOG',
1601
+ '6' => 'RT_STRING',
1602
+ '7' => 'RT_FONTDIR',
1603
+ '8' => 'RT_FONT',
1604
+ '9' => 'RT_ACCELERATORS',
1605
+ '10' => 'RT_RCDATA',
1606
+ '11' => 'RT_MESSAGETABLE',
1607
+ '12' => 'RT_GROUP_CURSOR',
1608
+ '14' => 'RT_GROUP_ICON',
1609
+ '16' => 'RT_VERSION',
1610
+ '17' => 'RT_DLGINCLUDE',
1611
+ '19' => 'RT_PLUGPLAY',
1612
+ '20' => 'RT_VXD',
1613
+ '21' => 'RT_ANICURSOR',
1614
+ '22' => 'RT_ANIICON',
1615
+ '23' => 'RT_HTML',
1616
+ '24' => 'RT_MANIFEST',
1617
+ '32767' => 'RT_ERROR',
1618
+ '8192' => 'RT_NEWRESOURCE',
1619
+ '8194' => 'RT_NEWBITMAP',
1620
+ '8196' => 'RT_NEWMENU',
1621
+ '8197' => 'RT_NEWDIALOG'
1622
+ }
1623
+ tbl[i] || i
1624
+ end
1625
+
1626
+ def _parse_resource_entry(data, rname, rvalue, path, pname)
1627
+
1628
+ rva, size, code = data[rvalue, 12].unpack('VVV')
1629
+ lang = _parse_resource_name(data, rname)
1630
+
1631
+ ent = ResourceEntry.new(
1632
+ self,
1633
+ path,
1634
+ lang,
1635
+ code,
1636
+ rva,
1637
+ size,
1638
+ pname
1639
+ )
1640
+ self._resources_cache[path] = ent
1641
+ end
1642
+
1643
+ def _parse_resource_name(data, rname)
1644
+ if (rname & 0x80000000 != 0)
1645
+ rname &= ~0x80000000
1646
+ unistr = data[rname+2, 2 * data[rname,2].unpack('v')[0] ]
1647
+ unistr, trash = unistr.split(/\x00\x00/, 2)
1648
+ return unistr ? unistr.gsub(/\x00/, '') : nil
1649
+ end
1650
+
1651
+ rname.to_s
1652
+ end
1653
+
1654
+ end end end
1655
+