smallworld-re 1.0.3__py3-none-any.whl → 2.0.0__py3-none-any.whl

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 (306) hide show
  1. smallworld/analyses/__init__.py +8 -0
  2. smallworld/analyses/analysis.py +8 -67
  3. smallworld/analyses/code_coverage.py +1 -2
  4. smallworld/analyses/colorizer.py +301 -534
  5. smallworld/analyses/colorizer_def_use.py +217 -0
  6. smallworld/analyses/colorizer_summary.py +173 -83
  7. smallworld/analyses/field_detection/field_analysis.py +7 -8
  8. smallworld/analyses/field_detection/hints.py +1 -1
  9. smallworld/analyses/field_detection/malloc.py +2 -2
  10. smallworld/analyses/trace_execution.py +160 -0
  11. smallworld/analyses/trace_execution_types.py +42 -0
  12. smallworld/analyses/unstable/angr/divergence.py +1 -2
  13. smallworld/analyses/unstable/angr/model.py +5 -6
  14. smallworld/analyses/unstable/angr_nwbt.py +3 -4
  15. smallworld/analyses/unstable/code_coverage.py +2 -3
  16. smallworld/analyses/unstable/code_reachable.py +2 -3
  17. smallworld/analyses/unstable/control_flow_tracer.py +2 -3
  18. smallworld/analyses/unstable/pointer_finder.py +2 -3
  19. smallworld/analyses/unstable/utils/tui.py +71 -0
  20. smallworld/emulators/__init__.py +3 -1
  21. smallworld/emulators/angr/angr.py +30 -9
  22. smallworld/emulators/angr/machdefs/__init__.py +2 -0
  23. smallworld/emulators/angr/machdefs/aarch64.py +1 -1
  24. smallworld/emulators/angr/machdefs/amd64.py +0 -4
  25. smallworld/emulators/angr/machdefs/arm.py +0 -2
  26. smallworld/emulators/angr/machdefs/i386.py +0 -2
  27. smallworld/emulators/angr/machdefs/loongarch.py +340 -0
  28. smallworld/emulators/angr/machdefs/machdef.py +1 -8
  29. smallworld/emulators/angr/machdefs/mips.py +0 -2
  30. smallworld/emulators/angr/machdefs/mips64.py +0 -2
  31. smallworld/emulators/angr/machdefs/ppc.py +1 -2
  32. smallworld/emulators/angr/machdefs/riscv.py +8 -10
  33. smallworld/emulators/angr/machdefs/xtensa.py +7 -4
  34. smallworld/emulators/emulator.py +22 -0
  35. smallworld/emulators/ghidra/__init__.py +37 -0
  36. smallworld/emulators/ghidra/ghidra.py +513 -0
  37. smallworld/emulators/ghidra/machdefs/__init__.py +31 -0
  38. smallworld/emulators/ghidra/machdefs/aarch64.py +289 -0
  39. smallworld/emulators/ghidra/machdefs/amd64.py +185 -0
  40. smallworld/emulators/ghidra/machdefs/arm.py +370 -0
  41. smallworld/emulators/ghidra/machdefs/i386.py +109 -0
  42. smallworld/emulators/ghidra/machdefs/loongarch.py +162 -0
  43. smallworld/emulators/ghidra/machdefs/machdef.py +81 -0
  44. smallworld/emulators/ghidra/machdefs/mips.py +163 -0
  45. smallworld/emulators/ghidra/machdefs/mips64.py +186 -0
  46. smallworld/emulators/ghidra/machdefs/ppc.py +98 -0
  47. smallworld/emulators/ghidra/machdefs/riscv.py +208 -0
  48. smallworld/emulators/ghidra/machdefs/xtensa.py +21 -0
  49. smallworld/emulators/ghidra/typing.py +28 -0
  50. smallworld/emulators/hookable.py +18 -4
  51. smallworld/emulators/panda/machdefs/__init__.py +2 -2
  52. smallworld/emulators/panda/machdefs/aarch64.py +186 -11
  53. smallworld/emulators/panda/machdefs/amd64.py +103 -11
  54. smallworld/emulators/panda/machdefs/arm.py +216 -20
  55. smallworld/emulators/panda/machdefs/i386.py +30 -7
  56. smallworld/emulators/panda/machdefs/machdef.py +9 -16
  57. smallworld/emulators/panda/machdefs/mips.py +49 -5
  58. smallworld/emulators/panda/machdefs/mips64.py +57 -5
  59. smallworld/emulators/panda/machdefs/ppc.py +38 -13
  60. smallworld/emulators/panda/panda.py +146 -44
  61. smallworld/emulators/unicorn/__init__.py +2 -0
  62. smallworld/emulators/unicorn/machdefs/aarch64.py +253 -264
  63. smallworld/emulators/unicorn/machdefs/amd64.py +254 -259
  64. smallworld/emulators/unicorn/machdefs/arm.py +200 -212
  65. smallworld/emulators/unicorn/machdefs/i386.py +84 -90
  66. smallworld/emulators/unicorn/machdefs/machdef.py +2 -23
  67. smallworld/emulators/unicorn/machdefs/mips.py +127 -135
  68. smallworld/emulators/unicorn/unicorn.py +52 -13
  69. smallworld/helpers.py +4 -19
  70. smallworld/hinting/hinting.py +22 -192
  71. smallworld/hinting/hints.py +50 -18
  72. smallworld/instructions/bsid.py +8 -8
  73. smallworld/logging.py +4 -2
  74. smallworld/platforms/__init__.py +12 -0
  75. smallworld/platforms/defs/__init__.py +36 -0
  76. smallworld/platforms/defs/aarch64.py +450 -0
  77. smallworld/platforms/defs/amd64.py +463 -0
  78. smallworld/platforms/defs/arm.py +519 -0
  79. smallworld/platforms/defs/i386.py +258 -0
  80. smallworld/platforms/defs/loongarch.py +270 -0
  81. smallworld/platforms/defs/mips.py +321 -0
  82. smallworld/platforms/defs/mips64.py +313 -0
  83. smallworld/platforms/defs/platformdef.py +97 -0
  84. smallworld/platforms/defs/powerpc.py +259 -0
  85. smallworld/platforms/defs/riscv.py +257 -0
  86. smallworld/platforms/defs/xtensa.py +96 -0
  87. smallworld/{platforms.py → platforms/platforms.py} +3 -0
  88. smallworld/state/cpus/__init__.py +2 -0
  89. smallworld/state/cpus/aarch64.py +0 -9
  90. smallworld/state/cpus/amd64.py +6 -28
  91. smallworld/state/cpus/arm.py +0 -11
  92. smallworld/state/cpus/cpu.py +0 -11
  93. smallworld/state/cpus/i386.py +0 -7
  94. smallworld/state/cpus/loongarch.py +299 -0
  95. smallworld/state/cpus/mips.py +4 -47
  96. smallworld/state/cpus/mips64.py +18 -58
  97. smallworld/state/cpus/powerpc.py +2 -9
  98. smallworld/state/cpus/riscv.py +1 -11
  99. smallworld/state/cpus/xtensa.py +0 -5
  100. smallworld/state/memory/code.py +38 -2
  101. smallworld/state/memory/elf/__init__.py +5 -1
  102. smallworld/state/memory/elf/coredump/__init__.py +3 -0
  103. smallworld/state/memory/elf/coredump/coredump.py +46 -0
  104. smallworld/state/memory/elf/coredump/prstatus/__init__.py +27 -0
  105. smallworld/state/memory/elf/coredump/prstatus/aarch64.py +46 -0
  106. smallworld/state/memory/elf/coredump/prstatus/amd64.py +40 -0
  107. smallworld/state/memory/elf/coredump/prstatus/arm.py +53 -0
  108. smallworld/state/memory/elf/coredump/prstatus/i386.py +30 -0
  109. smallworld/state/memory/elf/coredump/prstatus/mips.py +55 -0
  110. smallworld/state/memory/elf/coredump/prstatus/mips64.py +57 -0
  111. smallworld/state/memory/elf/coredump/prstatus/ppc.py +82 -0
  112. smallworld/state/memory/elf/coredump/prstatus/prstatus.py +129 -0
  113. smallworld/state/memory/elf/elf.py +211 -57
  114. smallworld/state/memory/elf/register_state.py +36 -0
  115. smallworld/state/memory/elf/rela/__init__.py +2 -0
  116. smallworld/state/memory/elf/rela/aarch64.py +3 -1
  117. smallworld/state/memory/elf/rela/amd64.py +4 -2
  118. smallworld/state/memory/elf/rela/arm.py +4 -2
  119. smallworld/state/memory/elf/rela/i386.py +4 -2
  120. smallworld/state/memory/elf/rela/loongarch.py +32 -0
  121. smallworld/state/memory/elf/rela/mips.py +39 -18
  122. smallworld/state/memory/elf/rela/ppc.py +31 -14
  123. smallworld/state/memory/elf/structs.py +3 -0
  124. smallworld/state/memory/heap.py +2 -2
  125. smallworld/state/memory/memory.py +18 -0
  126. smallworld/state/memory/pe/__init__.py +3 -0
  127. smallworld/state/memory/pe/pe.py +361 -0
  128. smallworld/state/memory/pe/structs.py +60 -0
  129. smallworld/state/memory/stack/__init__.py +2 -0
  130. smallworld/state/memory/stack/loongarch.py +26 -0
  131. smallworld/state/models/__init__.py +29 -2
  132. smallworld/state/models/aarch64/__init__.py +1 -0
  133. smallworld/state/models/aarch64/systemv/__init__.py +6 -0
  134. smallworld/state/models/aarch64/systemv/c99/__init__.py +12 -0
  135. smallworld/state/models/aarch64/systemv/c99/signal.py +16 -0
  136. smallworld/state/models/aarch64/systemv/c99/stdio.py +265 -0
  137. smallworld/state/models/aarch64/systemv/c99/stdlib.py +169 -0
  138. smallworld/state/models/aarch64/systemv/c99/string.py +139 -0
  139. smallworld/state/models/aarch64/systemv/c99/time.py +61 -0
  140. smallworld/state/models/aarch64/systemv/posix/__init__.py +6 -0
  141. smallworld/state/models/aarch64/systemv/posix/libgen.py +16 -0
  142. smallworld/state/models/aarch64/systemv/posix/signal.py +157 -0
  143. smallworld/state/models/aarch64/systemv/systemv.py +80 -0
  144. smallworld/state/models/amd64/__init__.py +1 -0
  145. smallworld/state/models/amd64/systemv/__init__.py +6 -0
  146. smallworld/state/models/amd64/systemv/c99/__init__.py +12 -0
  147. smallworld/state/models/amd64/systemv/c99/signal.py +16 -0
  148. smallworld/state/models/amd64/systemv/c99/stdio.py +265 -0
  149. smallworld/state/models/amd64/systemv/c99/stdlib.py +169 -0
  150. smallworld/state/models/amd64/systemv/c99/string.py +139 -0
  151. smallworld/state/models/amd64/systemv/c99/time.py +61 -0
  152. smallworld/state/models/amd64/systemv/posix/__init__.py +6 -0
  153. smallworld/state/models/amd64/systemv/posix/libgen.py +16 -0
  154. smallworld/state/models/amd64/systemv/posix/signal.py +157 -0
  155. smallworld/state/models/amd64/systemv/systemv.py +78 -0
  156. smallworld/state/models/armel/__init__.py +1 -0
  157. smallworld/state/models/armel/systemv/__init__.py +6 -0
  158. smallworld/state/models/armel/systemv/c99/__init__.py +12 -0
  159. smallworld/state/models/armel/systemv/c99/signal.py +16 -0
  160. smallworld/state/models/armel/systemv/c99/stdio.py +265 -0
  161. smallworld/state/models/armel/systemv/c99/stdlib.py +169 -0
  162. smallworld/state/models/armel/systemv/c99/string.py +139 -0
  163. smallworld/state/models/armel/systemv/c99/time.py +61 -0
  164. smallworld/state/models/armel/systemv/posix/__init__.py +6 -0
  165. smallworld/state/models/armel/systemv/posix/libgen.py +16 -0
  166. smallworld/state/models/armel/systemv/posix/signal.py +157 -0
  167. smallworld/state/models/armel/systemv/systemv.py +82 -0
  168. smallworld/state/models/armhf/__init__.py +1 -0
  169. smallworld/state/models/armhf/systemv/__init__.py +6 -0
  170. smallworld/state/models/armhf/systemv/c99/__init__.py +12 -0
  171. smallworld/state/models/armhf/systemv/c99/signal.py +16 -0
  172. smallworld/state/models/armhf/systemv/c99/stdio.py +265 -0
  173. smallworld/state/models/armhf/systemv/c99/stdlib.py +169 -0
  174. smallworld/state/models/armhf/systemv/c99/string.py +139 -0
  175. smallworld/state/models/armhf/systemv/c99/time.py +61 -0
  176. smallworld/state/models/armhf/systemv/posix/__init__.py +6 -0
  177. smallworld/state/models/armhf/systemv/posix/libgen.py +16 -0
  178. smallworld/state/models/armhf/systemv/posix/signal.py +157 -0
  179. smallworld/state/models/armhf/systemv/systemv.py +77 -0
  180. smallworld/state/models/c99/__init__.py +12 -0
  181. smallworld/state/models/c99/fmt_print.py +915 -0
  182. smallworld/state/models/c99/fmt_scan.py +864 -0
  183. smallworld/state/models/c99/math.py +362 -0
  184. smallworld/state/models/c99/signal.py +71 -0
  185. smallworld/state/models/c99/stdio.py +1305 -0
  186. smallworld/state/models/c99/stdlib.py +595 -0
  187. smallworld/state/models/c99/string.py +674 -0
  188. smallworld/state/models/c99/time.py +340 -0
  189. smallworld/state/models/c99/utils.py +89 -0
  190. smallworld/state/models/cstd.py +759 -0
  191. smallworld/state/models/errno.py +581 -0
  192. smallworld/state/models/filedesc.py +515 -0
  193. smallworld/state/models/i386/__init__.py +1 -0
  194. smallworld/state/models/i386/systemv/__init__.py +6 -0
  195. smallworld/state/models/i386/systemv/c99/__init__.py +12 -0
  196. smallworld/state/models/i386/systemv/c99/signal.py +16 -0
  197. smallworld/state/models/i386/systemv/c99/stdio.py +265 -0
  198. smallworld/state/models/i386/systemv/c99/stdlib.py +169 -0
  199. smallworld/state/models/i386/systemv/c99/string.py +139 -0
  200. smallworld/state/models/i386/systemv/c99/time.py +61 -0
  201. smallworld/state/models/i386/systemv/posix/__init__.py +6 -0
  202. smallworld/state/models/i386/systemv/posix/libgen.py +16 -0
  203. smallworld/state/models/i386/systemv/posix/signal.py +157 -0
  204. smallworld/state/models/i386/systemv/systemv.py +71 -0
  205. smallworld/state/models/loongarch64/__init__.py +1 -0
  206. smallworld/state/models/loongarch64/systemv/__init__.py +6 -0
  207. smallworld/state/models/loongarch64/systemv/c99/__init__.py +12 -0
  208. smallworld/state/models/loongarch64/systemv/c99/signal.py +16 -0
  209. smallworld/state/models/loongarch64/systemv/c99/stdio.py +265 -0
  210. smallworld/state/models/loongarch64/systemv/c99/stdlib.py +169 -0
  211. smallworld/state/models/loongarch64/systemv/c99/string.py +139 -0
  212. smallworld/state/models/loongarch64/systemv/c99/time.py +61 -0
  213. smallworld/state/models/loongarch64/systemv/posix/__init__.py +6 -0
  214. smallworld/state/models/loongarch64/systemv/posix/libgen.py +16 -0
  215. smallworld/state/models/loongarch64/systemv/posix/signal.py +157 -0
  216. smallworld/state/models/loongarch64/systemv/systemv.py +83 -0
  217. smallworld/state/models/mips/__init__.py +1 -0
  218. smallworld/state/models/mips/systemv/__init__.py +6 -0
  219. smallworld/state/models/mips/systemv/c99/__init__.py +12 -0
  220. smallworld/state/models/mips/systemv/c99/signal.py +16 -0
  221. smallworld/state/models/mips/systemv/c99/stdio.py +265 -0
  222. smallworld/state/models/mips/systemv/c99/stdlib.py +169 -0
  223. smallworld/state/models/mips/systemv/c99/string.py +139 -0
  224. smallworld/state/models/mips/systemv/c99/time.py +61 -0
  225. smallworld/state/models/mips/systemv/posix/__init__.py +6 -0
  226. smallworld/state/models/mips/systemv/posix/libgen.py +16 -0
  227. smallworld/state/models/mips/systemv/posix/signal.py +157 -0
  228. smallworld/state/models/mips/systemv/systemv.py +78 -0
  229. smallworld/state/models/mips64/__init__.py +1 -0
  230. smallworld/state/models/mips64/systemv/__init__.py +6 -0
  231. smallworld/state/models/mips64/systemv/c99/__init__.py +12 -0
  232. smallworld/state/models/mips64/systemv/c99/signal.py +16 -0
  233. smallworld/state/models/mips64/systemv/c99/stdio.py +265 -0
  234. smallworld/state/models/mips64/systemv/c99/stdlib.py +169 -0
  235. smallworld/state/models/mips64/systemv/c99/string.py +139 -0
  236. smallworld/state/models/mips64/systemv/c99/time.py +61 -0
  237. smallworld/state/models/mips64/systemv/posix/__init__.py +6 -0
  238. smallworld/state/models/mips64/systemv/posix/libgen.py +16 -0
  239. smallworld/state/models/mips64/systemv/posix/signal.py +157 -0
  240. smallworld/state/models/mips64/systemv/systemv.py +98 -0
  241. smallworld/state/models/mips64el/__init__.py +1 -0
  242. smallworld/state/models/mips64el/systemv/__init__.py +6 -0
  243. smallworld/state/models/mips64el/systemv/c99/__init__.py +12 -0
  244. smallworld/state/models/mips64el/systemv/c99/signal.py +16 -0
  245. smallworld/state/models/mips64el/systemv/c99/stdio.py +265 -0
  246. smallworld/state/models/mips64el/systemv/c99/stdlib.py +169 -0
  247. smallworld/state/models/mips64el/systemv/c99/string.py +139 -0
  248. smallworld/state/models/mips64el/systemv/c99/time.py +61 -0
  249. smallworld/state/models/mips64el/systemv/posix/__init__.py +6 -0
  250. smallworld/state/models/mips64el/systemv/posix/libgen.py +16 -0
  251. smallworld/state/models/mips64el/systemv/posix/signal.py +157 -0
  252. smallworld/state/models/mips64el/systemv/systemv.py +96 -0
  253. smallworld/state/models/mipsel/__init__.py +1 -0
  254. smallworld/state/models/mipsel/systemv/__init__.py +6 -0
  255. smallworld/state/models/mipsel/systemv/c99/__init__.py +12 -0
  256. smallworld/state/models/mipsel/systemv/c99/signal.py +16 -0
  257. smallworld/state/models/mipsel/systemv/c99/stdio.py +265 -0
  258. smallworld/state/models/mipsel/systemv/c99/stdlib.py +169 -0
  259. smallworld/state/models/mipsel/systemv/c99/string.py +139 -0
  260. smallworld/state/models/mipsel/systemv/c99/time.py +61 -0
  261. smallworld/state/models/mipsel/systemv/posix/__init__.py +6 -0
  262. smallworld/state/models/mipsel/systemv/posix/libgen.py +16 -0
  263. smallworld/state/models/mipsel/systemv/posix/signal.py +157 -0
  264. smallworld/state/models/mipsel/systemv/systemv.py +78 -0
  265. smallworld/state/models/model.py +27 -2
  266. smallworld/state/models/posix/__init__.py +6 -0
  267. smallworld/state/models/posix/libgen.py +123 -0
  268. smallworld/state/models/posix/signal.py +690 -0
  269. smallworld/state/models/powerpc/__init__.py +1 -0
  270. smallworld/state/models/powerpc/systemv/__init__.py +6 -0
  271. smallworld/state/models/powerpc/systemv/c99/__init__.py +12 -0
  272. smallworld/state/models/powerpc/systemv/c99/signal.py +16 -0
  273. smallworld/state/models/powerpc/systemv/c99/stdio.py +265 -0
  274. smallworld/state/models/powerpc/systemv/c99/stdlib.py +169 -0
  275. smallworld/state/models/powerpc/systemv/c99/string.py +139 -0
  276. smallworld/state/models/powerpc/systemv/c99/time.py +61 -0
  277. smallworld/state/models/powerpc/systemv/posix/__init__.py +6 -0
  278. smallworld/state/models/powerpc/systemv/posix/libgen.py +16 -0
  279. smallworld/state/models/powerpc/systemv/posix/signal.py +157 -0
  280. smallworld/state/models/powerpc/systemv/systemv.py +93 -0
  281. smallworld/state/models/riscv64/__init__.py +1 -0
  282. smallworld/state/models/riscv64/systemv/__init__.py +6 -0
  283. smallworld/state/models/riscv64/systemv/c99/__init__.py +12 -0
  284. smallworld/state/models/riscv64/systemv/c99/signal.py +16 -0
  285. smallworld/state/models/riscv64/systemv/c99/stdio.py +265 -0
  286. smallworld/state/models/riscv64/systemv/c99/stdlib.py +169 -0
  287. smallworld/state/models/riscv64/systemv/c99/string.py +139 -0
  288. smallworld/state/models/riscv64/systemv/c99/time.py +61 -0
  289. smallworld/state/models/riscv64/systemv/posix/__init__.py +6 -0
  290. smallworld/state/models/riscv64/systemv/posix/libgen.py +16 -0
  291. smallworld/state/models/riscv64/systemv/posix/signal.py +157 -0
  292. smallworld/state/models/riscv64/systemv/systemv.py +85 -0
  293. smallworld/state/state.py +65 -24
  294. smallworld/state/unstable/elf.py +16 -31
  295. smallworld/utils.py +6 -1
  296. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/METADATA +74 -42
  297. smallworld_re-2.0.0.dist-info/RECORD +374 -0
  298. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/WHEEL +1 -1
  299. smallworld/state/models/x86/__init__.py +0 -2
  300. smallworld/state/models/x86/microsoftcdecl.py +0 -35
  301. smallworld/state/models/x86/systemv.py +0 -240
  302. smallworld_re-1.0.3.dist-info/RECORD +0 -166
  303. /smallworld/state/models/{posix.py → _posix.py} +0 -0
  304. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/entry_points.txt +0 -0
  305. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/licenses/LICENSE.txt +0 -0
  306. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,361 @@
1
+ import typing
2
+
3
+ import lief
4
+
5
+ from ....exceptions import ConfigurationError
6
+ from ....platforms import Architecture, Byteorder, Platform, PlatformDef
7
+ from ....utils import RangeCollection
8
+ from ...state import BytesValue
9
+ from ..code import Executable
10
+ from .structs import PEExport, PEImport
11
+
12
+ # PE32+ machine types
13
+ # There are a lot more of these, but I can only test on amd64 and i386
14
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664
15
+ IMAGE_FILE_MACHINE_I386 = 0x14C
16
+
17
+ # Section flags
18
+ # Currently, the only one we care about is "code".
19
+ # Not sure how the others interact with file loading.
20
+ IMAGE_SCN_CNT_CODE = 0x20
21
+
22
+ # Relocation types
23
+ # All of these adjust based on the difference between
24
+ # the requested and actual load addresses
25
+ IMAGE_REL_BASED_ABSOLUTE = 0x0 # No-op
26
+ IMAGE_REL_BASED_HIGHLOW = 0x3 # Add 32-bit difference to a 32-bit value
27
+ IMAGE_REL_BASED_DIR64 = 0xA # Add 64-bit difference to a 64-bit value
28
+
29
+
30
+ class PEExecutable(Executable):
31
+ """Executable loaded from a PE32+
32
+
33
+ This loads a single PE32+ file into a SmallWorld memory object.
34
+ It performs no relocation or initialization,
35
+ just maps the file into memory as the kernel intended.
36
+
37
+ Arguments:
38
+ file: File-like object containing the image
39
+ platform: Optional platform; used for header verification
40
+ ignore_platform: Do not try to ID or verify platform from headers
41
+ user_base: Optional user-specified base address
42
+ page_size: System page size
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ file: typing.BinaryIO,
48
+ platform: typing.Optional[Platform] = None,
49
+ ignore_platform: bool = False,
50
+ user_base: typing.Optional[int] = None,
51
+ page_size: int = 0x1000,
52
+ ):
53
+ # Initialize with null address and size;
54
+ # we will update these later
55
+ super().__init__(0, 0)
56
+
57
+ self.platform = platform
58
+ self.platdef: typing.Optional[PlatformDef] = None
59
+ self.bounds: RangeCollection = RangeCollection()
60
+
61
+ self._page_size = page_size
62
+ self._user_base = user_base
63
+ self._file_base = 0
64
+
65
+ self._exports: typing.List[PEExport] = list()
66
+ self._exports_by_name: typing.Dict[typing.Tuple[str, str], PEExport] = dict()
67
+ self._exports_by_ordinal: typing.Dict[typing.Tuple[str, int], PEExport] = dict()
68
+
69
+ self._imports: typing.List[PEImport] = list()
70
+ self._imports_by_name: typing.Dict[typing.Tuple[str, str], PEImport] = dict()
71
+ self._imports_by_ordinal: typing.Dict[typing.Tuple[str, int], PEImport] = dict()
72
+
73
+ # Read the entire image out of the file
74
+ image = file.read()
75
+
76
+ # Use lief to check if this is a PE
77
+ # NOTE: For some reason, this takes list(int), not bytes
78
+ if not lief.is_pe(list(image)):
79
+ raise ConfigurationError("Image is not a PE")
80
+
81
+ # Use lief to parse the PE
82
+ # NOTE: For some reason, this takes list(int), not bytes
83
+ # NOTE: lief objects aren't deep-copyable.
84
+ # I'd love to keep `pe` around for later use, but I can't.
85
+ pe = lief.PE.parse(list(image))
86
+ if pe is None:
87
+ raise ConfigurationError("Failed parsing PE image")
88
+
89
+ # Check machine compatibility
90
+ if not ignore_platform:
91
+ hdr_platform = self._platform_for_chdr(pe)
92
+ if self.platform is not None:
93
+ if self.platform != hdr_platform:
94
+ raise ConfigurationError(
95
+ "Platform mismatch: "
96
+ f"specified {self.platform}, but got {hdr_platform} from header"
97
+ )
98
+ else:
99
+ self.platform = hdr_platform
100
+ self.platdef = PlatformDef.for_platform(hdr_platform)
101
+
102
+ # Determine the file base address
103
+ self._file_base = pe.imagebase
104
+ self._determine_base()
105
+
106
+ for section in pe.sections:
107
+ # TODO: How do PE32+ files distinguish loadable segments?
108
+ # mingw objdump has some notion of allocated segments,
109
+ # but it doesn't map to anything in any of the flags.
110
+ self._map_section(section, image)
111
+
112
+ # Fix up the memory image to account for changes in the base address
113
+ self._apply_base_relocations(pe)
114
+
115
+ # Compute the final total capacity
116
+ for offset, value in self.items():
117
+ self.size = max(self.size, offset + value.get_size())
118
+
119
+ # Extract exports
120
+ self._extract_exports(pe)
121
+
122
+ # Extract imports
123
+ self._extract_imports(pe)
124
+
125
+ def _platform_for_chdr(self, pe):
126
+ if pe.header.machine.value == IMAGE_FILE_MACHINE_AMD64:
127
+ return Platform(Architecture.X86_64, Byteorder.LITTLE)
128
+ elif pe.header.machine.value == IMAGE_FILE_MACHINE_I386:
129
+ return Platform(Architecture.X86_32, Byteorder.LITTLE)
130
+ else:
131
+ raise ConfigurationError(f"Unsupported machine type {pe.header.machine}")
132
+
133
+ def _determine_base(self):
134
+ if self._user_base is None:
135
+ # No user base requested
136
+ if self._file_base == 0:
137
+ # No file base defined (unusal for PE32+)
138
+ # Need the user to provide one
139
+ raise ConfigurationError(
140
+ "No base address provided, and none defined in PE file"
141
+ )
142
+ else:
143
+ self.address = self._file_base
144
+ else:
145
+ # PE files are always position-independent;
146
+ # we'll just have to fix things up later.
147
+ self.address = self._user_base
148
+
149
+ def _rebase_file(self, val: int):
150
+ # Rebase an offset from file-relative to image-relative
151
+ res = val + self.address
152
+ return res
153
+
154
+ def _page_align(self, val: int, up: bool = True):
155
+ if up:
156
+ val += self._page_size - 1
157
+ return (val // self._page_size) * self._page_size
158
+
159
+ def _map_section(self, sect, image):
160
+ # NOTE: Unlike ELFs, The physical address of PE sections is not page-aligned.
161
+ sect_start = sect.offset
162
+ sect_end = sect.offset + sect.size
163
+ sect_addr = self._page_align(self._rebase_file(sect.virtual_address), up=False)
164
+ sect_size = self._page_align(sect.virtual_size)
165
+
166
+ sect_data = image[sect_start:sect_end]
167
+ if len(sect_data) < sect_size:
168
+ # Section is shorter than what's available in the file;
169
+ # THis will get zero-padded.
170
+ pad_size = sect_size - len(sect_data)
171
+ sect_data += b"\0" * pad_size
172
+ if len(sect_data) != sect_size:
173
+ raise ConfigurationError(
174
+ f"Expected segment of size {sect_size}, but got {len(sect_data)}"
175
+ )
176
+
177
+ if 0 != (sect.characteristics & IMAGE_SCN_CNT_CODE):
178
+ # This is a code segment; add it to program bounds
179
+ self.bounds.add_range((sect_addr, sect_addr + sect_size))
180
+
181
+ sect_value = BytesValue(sect_data, None)
182
+ self[sect_addr - self.address] = sect_value
183
+
184
+ def _apply_base_relocations(self, pe):
185
+ # PE32+ files always allow the loader to override
186
+ # the program's base address.
187
+ #
188
+ # The relocation section marks places where
189
+ # an absolute offset needs fixing
190
+ # if the loader decides to override
191
+ if self.address == self._file_base:
192
+ # This file was not relocated. Nothing to do.
193
+ return
194
+
195
+ if self.platform.byteorder == Byteorder.LITTLE:
196
+ byteorder = "little"
197
+ elif self.platform.byteorder == Byteorder.BIG:
198
+ byteorder = "big"
199
+ else:
200
+ raise ConfigurationError(
201
+ f"Can't encode byteorder {self.platform.byteorder}"
202
+ )
203
+
204
+ for base_reloc in pe.relocations:
205
+ for entry in base_reloc.entries:
206
+ if entry.type.value == IMAGE_REL_BASED_ABSOLUTE:
207
+ # Entry is a no-op; continue
208
+ continue
209
+ for off, val in self.items():
210
+ if entry.address >= off and entry.address <= val.get_size():
211
+ # Find the section containing this address
212
+ contents = bytearray(val.get_content())
213
+ fix_off = entry.address - off
214
+
215
+ if entry.type.value == IMAGE_REL_BASED_HIGHLOW:
216
+ # 4-byte repair
217
+ tofix = int.from_bytes(
218
+ contents[fix_off : fix_off + 4], byteorder
219
+ )
220
+ tofix += self.address - self._file_base
221
+ contents[fix_off : fix_off + 4] = tofix.to_bytes(
222
+ 4, byteorder
223
+ )
224
+
225
+ elif entry.type.value == IMAGE_REL_BASED_DIR64:
226
+ # 8-byte repair
227
+ tofix = int.from_bytes(
228
+ contents[fix_off : fix_off + 8], byteorder
229
+ )
230
+ tofix += self.address - self._file_base
231
+ contents[fix_off : fix_off + 8] = tofix.to_bytes(
232
+ 8, byteorder
233
+ )
234
+
235
+ else:
236
+ raise ConfigurationError(
237
+ "Unhandled relocation type {entry.type}"
238
+ )
239
+ # Reset the data
240
+ val.set_content(bytes(contents))
241
+ break
242
+
243
+ def _extract_exports(self, pe) -> None:
244
+ if not pe.has_exports:
245
+ return
246
+
247
+ d = pe.get_export()
248
+ for e in d.entries:
249
+ if e.is_forwarded:
250
+ raise NotImplementedError(
251
+ "{d.name}.{e.name} is forwarded to {e.forward_information}"
252
+ )
253
+ else:
254
+ exp = PEExport(
255
+ dll=d.name,
256
+ name=e.name,
257
+ ordinal=e.ordinal,
258
+ forwarder=None,
259
+ value=e.value + self.address,
260
+ )
261
+ self._exports.append(exp)
262
+ self._exports_by_name[(d.name, e.name)] = exp
263
+ self._exports_by_ordinal[(d.name, e.ordinal)] = exp
264
+
265
+ def _extract_imports(self, pe) -> None:
266
+ if not pe.has_imports:
267
+ return
268
+
269
+ # Iterate over the import directories
270
+ # These group imports by the DLL that provides them
271
+ for d in pe.imports:
272
+ for e in d.entries:
273
+ imp = PEImport(
274
+ dll=d.name,
275
+ name=e.name if not e.is_ordinal else None,
276
+ ordinal=e.ordinal if e.is_ordinal else None,
277
+ iat_address=e.iat_address + self.address,
278
+ forwarder=None,
279
+ value=None,
280
+ )
281
+ if e.name == "puts":
282
+ print(f"puts IAT at {e.iat_address:x} or {e.iat_value:x}")
283
+ self._imports.append(imp)
284
+ if e.is_ordinal:
285
+ self._imports_by_ordinal[(d.name, e.ordinal)] = imp
286
+ else:
287
+ self._imports_by_name[(d.name, e.name)] = imp
288
+
289
+ def update_import(
290
+ self, dll: str, hint: typing.Union[str, int, PEImport], value: int
291
+ ) -> None:
292
+ """Update an imported symbol in this PE file
293
+
294
+ Arguments:
295
+ dll: Name of the DLL where the import is defined
296
+ hint: Symbol name or ordinal
297
+ value: New value of the symbol
298
+ """
299
+ # No platform specified
300
+ if self.platform is None or self.platdef is None:
301
+ raise ConfigurationError("No platform specified; can't update imports")
302
+
303
+ if isinstance(hint, str):
304
+ # Look up by name
305
+ if (dll, hint) not in self._imports_by_name:
306
+ raise ConfigurationError(
307
+ f"No import for {dll}.{hint}. Try by ordinal?"
308
+ )
309
+ imp = self._imports_by_name[(dll, hint)]
310
+ elif isinstance(hint, int):
311
+ # Look up by ordinal
312
+ if (dll, hint) not in self._imports_by_ordinal:
313
+ raise ConfigurationError(f"No import for {dll}.#{hint}. Try by name?")
314
+ imp = self._imports_by_ordinal[(dll, hint)]
315
+ elif isinstance(hint, PEImport):
316
+ imp = hint
317
+ else:
318
+ raise TypeError(f"Unexpected hint {hint} of type {type(hint)}")
319
+
320
+ # Save the new value to the import
321
+ # This marks it as initialized
322
+ imp.value = value
323
+
324
+ # Convert value to bytes
325
+ if self.platform.byteorder == Byteorder.LITTLE:
326
+ value_bytes = value.to_bytes(self.platdef.address_size, "little")
327
+ elif self.platform.byteorder == Byteorder.BIG:
328
+ value_bytes = value.to_bytes(self.platdef.address_size, "big")
329
+ else:
330
+ raise ConfigurationError(
331
+ f"Can't encode int for byteorder {self.platform.byteorder}"
332
+ )
333
+
334
+ # Rewrite IAT slot
335
+ # NOTE: PE files can have overlapping segments; check all of them.
336
+ for off, seg in self.items():
337
+ start = off + self.address
338
+ stop = start + seg.get_size()
339
+ if imp.iat_address >= start and imp.iat_address < stop:
340
+ start = imp.iat_address - start
341
+ end = start + len(value_bytes)
342
+ contents = seg.get_content()
343
+ contents = contents[0:start] + value_bytes + contents[end:]
344
+ seg.set_content(contents)
345
+
346
+ def link_pe(self, dll: "PEExecutable"):
347
+ for imp in self._imports:
348
+ if imp.value is not None:
349
+ continue
350
+
351
+ if imp.name is not None and (imp.dll, imp.name) in dll._exports_by_name:
352
+ exp = dll._exports_by_name[(imp.dll, imp.name)]
353
+ elif (
354
+ imp.ordinal is not None
355
+ and (imp.dll, imp.ordinal) in dll._exports_by_ordinal
356
+ ):
357
+ exp = dll._exports_by_ordinal[(imp.dll, imp.ordinal)]
358
+ else:
359
+ continue
360
+
361
+ self.update_import(imp.dll, imp, exp.value)
@@ -0,0 +1,60 @@
1
+ import typing
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass(frozen=False)
6
+ class PEExport:
7
+ """PE export struct
8
+
9
+ Lief parses this data, but I can't keep the objects around.
10
+
11
+ An export defines a symbol that can be imported by other images.
12
+ See 'PEImport' for more on that process.
13
+
14
+ This is a mashup of a number of PE32+ structs
15
+ (export definitions are actually somewhat complicated
16
+ compared to import definitions).
17
+
18
+ Exports can be referenced by name or by ordinal - a numeric key
19
+ specific to the DLL.
20
+
21
+ Exports can provide an actual address, or a "forwarder".
22
+ This is the name of another export in another DLL that
23
+ will provide the actual value of the symbol... or possibly forward again.
24
+ """
25
+
26
+ dll: str
27
+ ordinal: int
28
+ name: str
29
+ forwarder: typing.Optional[str]
30
+ value: int
31
+
32
+
33
+ @dataclass(frozen=False)
34
+ class PEImport:
35
+ """PE import struct
36
+
37
+ Lief parses this data, but I can't keep the objects around.
38
+
39
+ An import defines that a specific exported symbol
40
+ is required from a specific DLL file.
41
+
42
+ They are closer to a relocation entry than a symbol;
43
+ each import defines the export required, and where
44
+ to write the exported value. There is exactly one
45
+ relocation mechanism, making this a lot easier to parse than ELF.
46
+
47
+ This class actually mashes up two PE32+ structures:
48
+ an Import Directory Entry, which defines a DLL that the file needs,
49
+ and an Import Lookup Entry, which defines a specific export it needs.
50
+
51
+ Lookup requires two keys, either the DLL name and export name,
52
+ or the DLL and export ordinal - a numeric key specified wihtin the DLL.
53
+ """
54
+
55
+ dll: str # Name of the DLL
56
+ name: typing.Optional[str] # String name of the export
57
+ ordinal: typing.Optional[int] # Ordinal of the export
58
+ iat_address: int # Address of the IAT slot for this import
59
+ forwarder: typing.Optional[str] # Forwarder export, if provided
60
+ value: typing.Optional[int] # Value imported
@@ -2,6 +2,7 @@ from .aarch64 import AArch64Stack
2
2
  from .amd64 import AMD64Stack
3
3
  from .arm import ARMv5tStack, ARMv6mStack, ARMv7aStack, ARMv7mStack, ARMv7rStack
4
4
  from .i386 import X86Stack
5
+ from .loongarch import LoongArch64Stack
5
6
  from .mips import MIPSBEStack, MIPSELStack
6
7
  from .mips64 import MIPS64BEStack, MIPS64ELStack
7
8
  from .ppc import PowerPC32Stack, PowerPC64Stack
@@ -19,6 +20,7 @@ __all__ = __stack__ + [
19
20
  "ARMv7rStack",
20
21
  "ARMv7aStack",
21
22
  "X86Stack",
23
+ "LoongArch64Stack",
22
24
  "MIPSBEStack",
23
25
  "MIPSELStack",
24
26
  "MIPS64BEStack",
@@ -0,0 +1,26 @@
1
+ import typing
2
+
3
+ from .... import platforms
4
+ from . import stack
5
+
6
+
7
+ class LoongArchStack(stack.DescendingStack):
8
+ """A stack for a LoongArch CPU"""
9
+
10
+ def get_pointer(self) -> int:
11
+ return (self.address + self.size) - self.get_used()
12
+
13
+ def get_alignment(self) -> int:
14
+ return 4
15
+
16
+ @classmethod
17
+ def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
18
+ raise NotImplementedError("Stack initialization not implemented for MIPS64")
19
+
20
+
21
+ class LoongArch64Stack(LoongArchStack):
22
+ """A stack for a LoongArch 64-bit CPU"""
23
+
24
+ platform = platforms.Platform(
25
+ platforms.Architecture.LOONGARCH64, platforms.Byteorder.LITTLE
26
+ )
@@ -1,6 +1,33 @@
1
- from . import x86
1
+ from . import (
2
+ aarch64,
3
+ amd64,
4
+ armel,
5
+ armhf,
6
+ i386,
7
+ loongarch64,
8
+ mips,
9
+ mips64,
10
+ mips64el,
11
+ mipsel,
12
+ powerpc,
13
+ riscv64,
14
+ )
2
15
  from .mmio import MemoryMappedModel
3
16
  from .model import * # noqa: F401, F403
4
17
  from .model import __all__ as __model__
5
18
 
6
- __all__ = __model__ + ["MemoryMappedModel", "x86"]
19
+ __all__ = __model__ + [
20
+ "MemoryMappedModel",
21
+ "aarch64",
22
+ "amd64",
23
+ "armel",
24
+ "armhf",
25
+ "i386",
26
+ "loongarch64",
27
+ "mips",
28
+ "mipsel",
29
+ "mips64",
30
+ "mips64el",
31
+ "powerpc",
32
+ "riscv64",
33
+ ]
@@ -0,0 +1 @@
1
+ from .systemv import __all__ as __sysv__ # noqa: F401
@@ -0,0 +1,6 @@
1
+ from .c99 import * # noqa: F401,F403
2
+ from .c99 import __all__ as __c99__
3
+ from .posix import * # noqa: F401,F403
4
+ from .posix import __all__ as __posix__
5
+
6
+ __all__ = __c99__ + __posix__
@@ -0,0 +1,12 @@
1
+ from .signal import * # noqa F401,F403
2
+ from .signal import __all__ as __signal__
3
+ from .stdio import * # noqa F401,F403
4
+ from .stdio import __all__ as __stdio__
5
+ from .stdlib import * # noqa F401,F403
6
+ from .stdlib import __all__ as __stdlib__
7
+ from .string import * # noqa F401,F403
8
+ from .string import __all__ as __string__
9
+ from .time import * # noqa F401,F403
10
+ from .time import __all__ as __time__
11
+
12
+ __all__ = __signal__ + __stdlib__ + __string__ + __stdio__ + __time__
@@ -0,0 +1,16 @@
1
+ from ....c99.signal import Raise, Signal
2
+ from ..systemv import AArch64SysVModel
3
+
4
+
5
+ class AArch64SysVRaise(Raise, AArch64SysVModel):
6
+ pass
7
+
8
+
9
+ class AArch64SysVSignal(Signal, AArch64SysVModel):
10
+ pass
11
+
12
+
13
+ __all__ = [
14
+ "AArch64SysVRaise",
15
+ "AArch64SysVSignal",
16
+ ]