From 2feb739d75403ebb6c94834723f8d79cb64f1a87 Mon Sep 17 00:00:00 2001 From: Rairosu Date: Tue, 2 Apr 2024 18:52:06 +0200 Subject: [PATCH] update --- CMakeLists.txt | 2 +- Cargo.lock | 333 +++-- Cargo.toml | 7 +- LICENSE | 2 +- README.md | 13 +- examples/decompile/Cargo.toml | 2 +- examples/dwarf/dwarf_export/Cargo.toml | 4 +- examples/dwarf/dwarf_import/Cargo.toml | 4 +- examples/dwarf/dwarfdump/Cargo.toml | 2 +- examples/dwarf/shared/Cargo.toml | 2 +- examples/hlil_lifter/Cargo.toml | 16 + examples/hlil_lifter/build.rs | 68 + examples/hlil_lifter/src/main.rs | 52 + examples/hlil_visitor/Cargo.toml | 16 + examples/hlil_visitor/build.rs | 68 + examples/hlil_visitor/src/main.rs | 250 ++++ examples/minidump/Cargo.toml | 5 +- examples/mlil_lifter/src/main.rs | 2 +- examples/mlil_visitor/src/main.rs | 40 +- src/architecture.rs | 45 +- src/binaryview.rs | 151 +- src/disassembly.rs | 9 + src/function.rs | 91 +- src/functionrecognizer.rs | 2 +- src/hlil/block.rs | 63 + src/hlil/function.rs | 111 ++ src/hlil/instruction.rs | 991 ++++++++++++ src/hlil/lift.rs | 325 ++++ src/hlil/mod.rs | 10 + src/hlil/operation.rs | 524 +++++++ src/lib.rs | 16 +- src/linearview.rs | 6 +- src/llil/function.rs | 50 +- src/llil/instruction.rs | 7 + src/mlil/block.rs | 4 +- src/mlil/function.rs | 18 +- src/mlil/instruction.rs | 1597 ++++++++++++-------- src/mlil/lift.rs | 258 +++- src/mlil/operation.rs | 1903 ++---------------------- src/operand_iter.rs | 223 +++ src/relocation.rs | 12 +- src/types.rs | 156 ++ 42 files changed, 4785 insertions(+), 2675 deletions(-) create mode 100644 examples/hlil_lifter/Cargo.toml create mode 100644 examples/hlil_lifter/build.rs create mode 100644 examples/hlil_lifter/src/main.rs create mode 100644 examples/hlil_visitor/Cargo.toml create mode 100644 examples/hlil_visitor/build.rs create mode 100644 examples/hlil_visitor/src/main.rs create mode 100644 src/hlil/block.rs create mode 100644 src/hlil/function.rs create mode 100644 src/hlil/instruction.rs create mode 100644 src/hlil/lift.rs create mode 100644 src/hlil/mod.rs create mode 100644 src/hlil/operation.rs create mode 100644 src/operand_iter.rs diff --git a/CMakeLists.txt b/CMakeLists.txt index c46d990..92c6926 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(rust_api) -set(CARGO_API_VERSION stable-2022-12-15) +set(CARGO_API_VERSION 1.77.0) file(GLOB RUST_API_SOURCES CONFIGURE_DEPENDS ../binaryninjacore.h diff --git a/Cargo.lock b/Cargo.lock index b2d3e4a..b57255e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -79,9 +79,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "basic_script" @@ -110,11 +110,11 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.66.1" +version = "0.68.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cexpr", "clang-sys", "lazy_static", @@ -127,21 +127,21 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.57", + "syn 2.0.52", "which", ] [[package]] name = "bitflags" -version = "1.3.2" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] -name = "bitflags" -version = "2.5.0" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cexpr" @@ -171,9 +171,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" dependencies = [ "clap_builder", "clap_derive", @@ -193,14 +193,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.52", ] [[package]] @@ -266,6 +266,26 @@ dependencies = [ "clap", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "dwarf_export" version = "0.1.0" @@ -310,79 +330,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] -name = "encoding" -version = "0.2.33" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", + "cfg-if", ] [[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-korean" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding_index_tests" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" - -[[package]] -name = "enum-primitive-derive" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c375b9c5eadb68d0a6efee2999fef292f45854c3444c86f09d8ab086ba942b0e" -dependencies = [ - "num-traits", - "quote", - "syn 1.0.109", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -396,9 +356,9 @@ dependencies = [ [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "flate2" @@ -419,9 +379,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", "indexmap", @@ -436,24 +396,32 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", ] [[package]] name = "heck" -version = "0.5.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hlil_lifter" +version = "0.1.0" +dependencies = [ + "binaryninja", +] + +[[package]] +name = "hlil_visitor" +version = "0.1.0" +dependencies = [ + "binaryninja", +] [[package]] name = "home" @@ -466,19 +434,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "equivalent", + "hashbrown", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lazy_static" @@ -522,9 +490,9 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memmap2" @@ -537,12 +505,12 @@ dependencies = [ [[package]] name = "minidump" -version = "0.15.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e5cd2ca4f6b85c6c7fb41ae0aebe0b443a6c0558876f1d779c7236d42417cf" +checksum = "e20da5c0aab8b6d683d8a15ca70db468d3f6ddfe38269837c22c7bab7ba2627c" dependencies = [ "debugid", - "encoding", + "encoding_rs", "memmap2", "minidump-common", "num-traits", @@ -556,13 +524,13 @@ dependencies = [ [[package]] name = "minidump-common" -version = "0.15.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694717103b2c15f8c16ddfaec1333fe15673bc22b10ffa6164427415701974ba" +checksum = "6b23ab3a13de24f89fa3060579288f142ac4d138d37eec8a398ba59b0ca4d577" dependencies = [ - "bitflags 1.3.2", + "bitflags", "debugid", - "enum-primitive-derive", + "num-derive", "num-traits", "range-map", "scroll", @@ -576,7 +544,6 @@ dependencies = [ "binaryninja", "log", "minidump", - "time", ] [[package]] @@ -618,6 +585,23 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -627,26 +611,18 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - [[package]] name = "object" -version = "0.30.4" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.13.2", + "hashbrown", "indexmap", "memchr", + "ruzstd", ] [[package]] @@ -663,18 +639,24 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.57", + "syn 2.0.52", ] [[package]] @@ -706,9 +688,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -726,9 +708,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -749,9 +731,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-hash" @@ -761,17 +743,28 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys", ] +[[package]] +name = "ruzstd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +dependencies = [ + "byteorder", + "derive_more", + "twox-hash", +] + [[package]] name = "scroll" version = "0.11.0" @@ -789,7 +782,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.52", ] [[package]] @@ -809,7 +802,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.52", ] [[package]] @@ -820,13 +813,13 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smart-default" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" +checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.52", ] [[package]] @@ -835,6 +828,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.0" @@ -854,9 +853,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.57" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -887,18 +886,19 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.52", ] [[package]] name = "time" -version = "0.3.16" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", "itoa", - "libc", - "num_threads", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -906,16 +906,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.5" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -939,7 +940,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.52", ] [[package]] @@ -951,6 +952,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -965,9 +976,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.8.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" [[package]] name = "version_check" @@ -1070,5 +1081,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.52", ] diff --git a/Cargo.toml b/Cargo.toml index 9ab2413..8e174e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ noexports = [] lazy_static = "1.4.0" log = "0.4" libc = "0.2" -rayon = { version = "1.0", optional = true } +rayon = { version = "1.8", optional = true } binaryninjacore-sys = { path = "binaryninjacore-sys" } [workspace] @@ -26,5 +26,10 @@ members = [ "examples/minidump", "examples/mlil_visitor", "examples/mlil_lifter", + "examples/hlil_visitor", + "examples/hlil_lifter", "examples/template" ] + +[profile.release] +debug = 1 diff --git a/LICENSE b/LICENSE index 265883c..265bf79 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2021 Vector 35 Inc. +Copyright 2021-2024 Vector 35 Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index d2f7f1c..8a037f6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ > :warning: **These bindings are in a very early beta, only have partial support for the core APIs and are still actively under development. Compatibility _will_ break and conventions _will_ change! They are being used for core Binary Ninja features however, so we expect much of what is already there to be reliable enough to build on, just don't be surprised if your plugins/scripts need to hit a moving target.** -> :warning: This project runs on Rust version `stable-2022-12-15` +> :warning: This project runs on Rust version `1.77.0` ## Contributing @@ -15,9 +15,9 @@ Add a "Contributing" section to the Rust API readme ## Dependencies -Having BinaryNinja installed (and your license registered) -Clang -Rust +Having BinaryNinja installed (and your license registered) +Clang +Rust ## How to use @@ -46,8 +46,9 @@ See the `./examples/`. Plugin registration commands are in `binaryninja::comman binaryninja = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"} ``` -All standalone binaries need to provide a `build.rs`. -See [`examples/template`](examples/template) for details. +All standalone binaries should call both `binaryninja::headless::init()` and `binaryninja::headless::shutdown()`. +All standalone binaries need to provide a `build.rs`. +See [`examples/template`](examples/template) for details. ## Docs diff --git a/examples/decompile/Cargo.toml b/examples/decompile/Cargo.toml index 3c3cbb3..09c510f 100644 --- a/examples/decompile/Cargo.toml +++ b/examples/decompile/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" [dependencies] binaryninja = {path="../../"} -clap = { version = "4.3", features = ["derive"] } +clap = { version = "4.4", features = ["derive"] } diff --git a/examples/dwarf/dwarf_export/Cargo.toml b/examples/dwarf/dwarf_export/Cargo.toml index 022d3e0..5f537c6 100644 --- a/examples/dwarf/dwarf_export/Cargo.toml +++ b/examples/dwarf/dwarf_export/Cargo.toml @@ -8,6 +8,6 @@ crate-type = ["cdylib"] [dependencies] binaryninja = {path="../../../"} -gimli = "^0.27" +gimli = "^0.28" log = "^0.4" -object = { version = "0.30.3", features = ["write"] } +object = { version = "0.32.1", features = ["write"] } diff --git a/examples/dwarf/dwarf_import/Cargo.toml b/examples/dwarf/dwarf_import/Cargo.toml index 0760599..c8cea44 100644 --- a/examples/dwarf/dwarf_import/Cargo.toml +++ b/examples/dwarf/dwarf_import/Cargo.toml @@ -10,5 +10,5 @@ crate-type = ["cdylib"] [dependencies] dwarfreader = { path = "../shared/" } binaryninja = { path = "../../../" } -gimli = "0.27" -log = "0.4.17" +gimli = "0.28" +log = "0.4.20" diff --git a/examples/dwarf/dwarfdump/Cargo.toml b/examples/dwarf/dwarfdump/Cargo.toml index 1d3411a..0ede6af 100644 --- a/examples/dwarf/dwarfdump/Cargo.toml +++ b/examples/dwarf/dwarfdump/Cargo.toml @@ -10,4 +10,4 @@ crate-type = ["cdylib"] [dependencies] dwarfreader = { path = "../shared/" } binaryninja = {path="../../../"} -gimli = "0.27" +gimli = "0.28" diff --git a/examples/dwarf/shared/Cargo.toml b/examples/dwarf/shared/Cargo.toml index 9cbd5a2..521a705 100644 --- a/examples/dwarf/shared/Cargo.toml +++ b/examples/dwarf/shared/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" [dependencies] binaryninja = {path="../../../"} -gimli = "0.27" +gimli = "0.28" diff --git a/examples/hlil_lifter/Cargo.toml b/examples/hlil_lifter/Cargo.toml new file mode 100644 index 0000000..c6c8794 --- /dev/null +++ b/examples/hlil_lifter/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "hlil_lifter" +version = "0.1.0" +edition = "2021" + +# Uncomment this if you're writing a plugin (plugins are shared objects loaded by the core): +# [lib] +# crate-type = ["cdylib"] + +# You can point at the BinaryNinja dependency in one of two ways, via path: +[dependencies] +binaryninja = {path="../../"} + +# Or directly at the git repo: +# [dependencies] +# binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"} diff --git a/examples/hlil_lifter/build.rs b/examples/hlil_lifter/build.rs new file mode 100644 index 0000000..5ba9bcd --- /dev/null +++ b/examples/hlil_lifter/build.rs @@ -0,0 +1,68 @@ +use std::env; +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +#[cfg(target_os = "macos")] +static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun"); + +#[cfg(target_os = "linux")] +static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun"); + +#[cfg(windows)] +static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun"); + +// Check last run location for path to BinaryNinja; Otherwise check the default install locations +fn link_path() -> PathBuf { + use std::io::prelude::*; + + let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap()); + let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1); + + File::open(lastrun) + .and_then(|f| { + let mut binja_path = String::new(); + let mut reader = BufReader::new(f); + + reader.read_line(&mut binja_path)?; + Ok(PathBuf::from(binja_path.trim())) + }) + .unwrap_or_else(|_| { + #[cfg(target_os = "macos")] + return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS"); + + #[cfg(target_os = "linux")] + return home.join("binaryninja"); + + #[cfg(windows)] + return PathBuf::from(env::var("PROGRAMFILES").unwrap()) + .join("Vector35\\BinaryNinja\\"); + }) +} + +fn main() { + // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults + let install_path = env::var("BINARYNINJADIR") + .map(PathBuf::from) + .unwrap_or_else(|_| link_path()); + + #[cfg(target_os = "linux")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "macos")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "windows")] + { + println!("cargo:rustc-link-lib=binaryninjacore"); + println!("cargo:rustc-link-search={}", install_path.to_str().unwrap()); + } +} diff --git a/examples/hlil_lifter/src/main.rs b/examples/hlil_lifter/src/main.rs new file mode 100644 index 0000000..36984ef --- /dev/null +++ b/examples/hlil_lifter/src/main.rs @@ -0,0 +1,52 @@ +use std::env; + +use binaryninja::binaryview::BinaryViewExt; + +// Standalone executables need to provide a main function for rustc +// Plugins should refer to `binaryninja::command::*` for the various registration callbacks. +fn main() { + let mut args = env::args(); + let _ = args.next().unwrap(); + let Some(filename) = args.next() else { + panic!("Expected input filename\n"); + }; + + // This loads all the core architecture, platform, etc plugins + // Standalone executables probably need to call this, but plugins do not + println!("Loading plugins..."); + binaryninja::headless::init(); + + // Your code here... + println!("Loading binary..."); + let bv = binaryninja::load(filename).expect("Couldn't open binary file"); + + // Go through all functions in the binary + for func in bv.functions().iter() { + let sym = func.symbol(); + println!("Function {}:", sym.full_name()); + + let Ok(il) = func.high_level_il(true) else { + println!(" Does not have HLIL\n"); + continue; + }; + // Get the SSA form for this function + let il = il.ssa_form(); + + // Loop through all blocks in the function + for block in il.basic_blocks().iter() { + // Loop though each instruction in the block + for instr in block.iter() { + // Uplift the instruction into a native rust format + let lifted = instr.lift(); + let address = instr.address; + + // print the lifted instruction + println!("{address:08x}: {lifted:x?}"); + } + } + println!(); + } + + // Important! Standalone executables need to call shutdown or they will hang forever + binaryninja::headless::shutdown(); +} diff --git a/examples/hlil_visitor/Cargo.toml b/examples/hlil_visitor/Cargo.toml new file mode 100644 index 0000000..036414a --- /dev/null +++ b/examples/hlil_visitor/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "hlil_visitor" +version = "0.1.0" +edition = "2021" + +# Uncomment this if you're writing a plugin (plugins are shared objects loaded by the core): +# [lib] +# crate-type = ["cdylib"] + +# You can point at the BinaryNinja dependency in one of two ways, via path: +[dependencies] +binaryninja = {path="../../"} + +# Or directly at the git repo: +# [dependencies] +# binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"} diff --git a/examples/hlil_visitor/build.rs b/examples/hlil_visitor/build.rs new file mode 100644 index 0000000..5ba9bcd --- /dev/null +++ b/examples/hlil_visitor/build.rs @@ -0,0 +1,68 @@ +use std::env; +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +#[cfg(target_os = "macos")] +static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun"); + +#[cfg(target_os = "linux")] +static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun"); + +#[cfg(windows)] +static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun"); + +// Check last run location for path to BinaryNinja; Otherwise check the default install locations +fn link_path() -> PathBuf { + use std::io::prelude::*; + + let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap()); + let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1); + + File::open(lastrun) + .and_then(|f| { + let mut binja_path = String::new(); + let mut reader = BufReader::new(f); + + reader.read_line(&mut binja_path)?; + Ok(PathBuf::from(binja_path.trim())) + }) + .unwrap_or_else(|_| { + #[cfg(target_os = "macos")] + return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS"); + + #[cfg(target_os = "linux")] + return home.join("binaryninja"); + + #[cfg(windows)] + return PathBuf::from(env::var("PROGRAMFILES").unwrap()) + .join("Vector35\\BinaryNinja\\"); + }) +} + +fn main() { + // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults + let install_path = env::var("BINARYNINJADIR") + .map(PathBuf::from) + .unwrap_or_else(|_| link_path()); + + #[cfg(target_os = "linux")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "macos")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "windows")] + { + println!("cargo:rustc-link-lib=binaryninjacore"); + println!("cargo:rustc-link-search={}", install_path.to_str().unwrap()); + } +} diff --git a/examples/hlil_visitor/src/main.rs b/examples/hlil_visitor/src/main.rs new file mode 100644 index 0000000..6d155ea --- /dev/null +++ b/examples/hlil_visitor/src/main.rs @@ -0,0 +1,250 @@ +use std::env; + +use binaryninja::binaryview::BinaryViewExt; +use binaryninja::hlil::HighLevelILLiftedOperand; +use binaryninja::hlil::{ + HighLevelILFunction, HighLevelILLiftedInstruction, HighLevelILLiftedInstructionKind, +}; +use binaryninja::types::Variable; + +fn print_indent(indent: usize) { + print!("{: print!("Adc"), + Sbb(_) => print!("Sbb"), + Rlc(_) => print!("Rlc"), + Rrc(_) => print!("Rrc"), + Add(_) => print!("Add"), + Sub(_) => print!("Sub"), + And(_) => print!("And"), + Or(_) => print!("Or"), + Xor(_) => print!("Xor"), + Lsl(_) => print!("Lsl"), + Lsr(_) => print!("Lsr"), + Asr(_) => print!("Asr"), + Rol(_) => print!("Rol"), + Ror(_) => print!("Ror"), + Mul(_) => print!("Mul"), + MuluDp(_) => print!("MuluDp"), + MulsDp(_) => print!("MulsDp"), + Divu(_) => print!("Divu"), + DivuDp(_) => print!("DivuDp"), + Divs(_) => print!("Divs"), + DivsDp(_) => print!("DivsDp"), + Modu(_) => print!("Modu"), + ModuDp(_) => print!("ModuDp"), + Mods(_) => print!("Mods"), + ModsDp(_) => print!("ModsDp"), + CmpE(_) => print!("CmpE"), + CmpNe(_) => print!("CmpNe"), + CmpSlt(_) => print!("CmpSlt"), + CmpUlt(_) => print!("CmpUlt"), + CmpSle(_) => print!("CmpSle"), + CmpUle(_) => print!("CmpUle"), + CmpSge(_) => print!("CmpSge"), + CmpUge(_) => print!("CmpUge"), + CmpSgt(_) => print!("CmpSgt"), + CmpUgt(_) => print!("CmpUgt"), + TestBit(_) => print!("TestBit"), + AddOverflow(_) => print!("AddOverflow"), + Fadd(_) => print!("Fadd"), + Fsub(_) => print!("Fsub"), + Fmul(_) => print!("Fmul"), + Fdiv(_) => print!("Fdiv"), + FcmpE(_) => print!("FcmpE"), + FcmpNe(_) => print!("FcmpNe"), + FcmpLt(_) => print!("FcmpLt"), + FcmpLe(_) => print!("FcmpLe"), + FcmpGe(_) => print!("FcmpGe"), + FcmpGt(_) => print!("FcmpGt"), + FcmpO(_) => print!("FcmpO"), + FcmpUo(_) => print!("FcmpUo"), + ArrayIndex(_) => print!("ArrayIndex"), + ArrayIndexSsa(_) => print!("ArrayIndexSsa"), + Assign(_) => print!("Assign"), + AssignMemSsa(_) => print!("AssignMemSsa"), + AssignUnpack(_) => print!("AssignUnpack"), + AssignUnpackMemSsa(_) => print!("AssignUnpackMemSsa"), + Block(_) => print!("Block"), + Call(_) => print!("Call"), + Tailcall(_) => print!("Tailcall"), + CallSsa(_) => print!("CallSsa"), + Case(_) => print!("Case"), + Const(_) => print!("Const"), + ConstPtr(_) => print!("ConstPtr"), + Import(_) => print!("Import"), + ConstData(_) => print!("ConstData"), + Deref(_) => print!("Deref"), + AddressOf(_) => print!("AddressOf"), + Neg(_) => print!("Neg"), + Not(_) => print!("Not"), + Sx(_) => print!("Sx"), + Zx(_) => print!("Zx"), + LowPart(_) => print!("LowPart"), + BoolToInt(_) => print!("BoolToInt"), + UnimplMem(_) => print!("UnimplMem"), + Fsqrt(_) => print!("Fsqrt"), + Fneg(_) => print!("Fneg"), + Fabs(_) => print!("Fabs"), + FloatToInt(_) => print!("FloatToInt"), + IntToFloat(_) => print!("IntToFloat"), + FloatConv(_) => print!("FloatConv"), + RoundToInt(_) => print!("RoundToInt"), + Floor(_) => print!("Floor"), + Ceil(_) => print!("Ceil"), + Ftrunc(_) => print!("Ftrunc"), + DerefFieldSsa(_) => print!("DerefFieldSsa"), + DerefSsa(_) => print!("DerefSsa"), + ExternPtr(_) => print!("ExternPtr"), + FloatConst(_) => print!("FloatConst"), + For(_) => print!("For"), + ForSsa(_) => print!("ForSsa"), + Goto(_) => print!("Goto"), + Label(_) => print!("Label"), + If(_) => print!("If"), + Intrinsic(_) => print!("Intrinsic"), + IntrinsicSsa(_) => print!("IntrinsicSsa"), + Jump(_) => print!("Jump"), + MemPhi(_) => print!("MemPhi"), + Nop => print!("Nop"), + Break => print!("Break"), + Continue => print!("Continue"), + Noret => print!("Noret"), + Unreachable => print!("Unreachable"), + Bp => print!("Bp"), + Undef => print!("Undef"), + Unimpl => print!("Unimpl"), + Ret(_) => print!("Ret"), + Split(_) => print!("Split"), + StructField(_) => print!("StructField"), + DerefField(_) => print!("DerefField"), + Switch(_) => print!("Switch"), + Syscall(_) => print!("Syscall"), + SyscallSsa(_) => print!("SyscallSsa"), + Trap(_) => print!("Trap"), + VarDeclare(_) => print!("VarDeclare"), + Var(_) => print!("Var"), + VarInit(_) => print!("VarInit"), + VarInitSsa(_) => print!("VarInitSsa"), + VarPhi(_) => print!("VarPhi"), + VarSsa(_) => print!("VarSsa"), + While(_) => print!("While"), + DoWhile(_) => print!("DoWhile"), + WhileSsa(_) => print!("WhileSsa"), + DoWhileSsa(_) => print!("DoWhileSsa"), + } +} + +fn print_variable(func: &HighLevelILFunction, var: &Variable) { + print!("{}", func.get_function().get_variable_name(var)); +} + +fn print_il_expr(instr: &HighLevelILLiftedInstruction, mut indent: usize) { + print_indent(indent); + print_operation(instr); + println!(""); + + indent += 1; + + use HighLevelILLiftedOperand::*; + for (_name, operand) in instr.operands() { + match operand { + Int(int) => { + print_indent(indent); + println!("int 0x{:x}", int); + } + Float(float) => { + print_indent(indent); + println!("int {:e}", float); + } + Expr(expr) => print_il_expr(&expr, indent), + Var(var) => { + print_indent(indent); + print!("var "); + print_variable(&instr.function, &var); + println!(); + } + VarSsa(var) => { + print_indent(indent); + print!("ssa var "); + print_variable(&instr.function, &var.variable); + println!("#{}", var.version); + } + IntList(list) => { + print_indent(indent); + print!("index list "); + for i in list { + print!("{i} "); + } + println!(); + } + VarSsaList(list) => { + print_indent(indent); + print!("ssa var list "); + for i in list { + print_variable(&instr.function, &i.variable); + print!("#{} ", i.version); + } + println!(); + } + ExprList(list) => { + print_indent(indent); + println!("expr list"); + for i in list { + print_il_expr(&i, indent + 1); + } + } + Label(label) => println!("label {}", label.name()), + MemberIndex(mem_idx) => println!("member_index {:?}", mem_idx), + ConstantData(_) => println!("constant_data TODO"), + Intrinsic(_) => println!("intrinsic TODO"), + } + } +} + +// Standalone executables need to provide a main function for rustc +// Plugins should refer to `binaryninja::command::*` for the various registration callbacks. +fn main() { + let mut args = env::args(); + let _ = args.next().unwrap(); + let Some(filename) = args.next() else { + panic!("Expected input filename\n"); + }; + + // This loads all the core architecture, platform, etc plugins + // Standalone executables probably need to call this, but plugins do not + println!("Loading plugins..."); + binaryninja::headless::init(); + + // Your code here... + println!("Loading binary..."); + let bv = binaryninja::load(filename).expect("Couldn't open binary file"); + + // Go through all functions in the binary + for func in bv.functions().iter() { + let sym = func.symbol(); + println!("Function {}:", sym.full_name()); + + let Ok(il) = func.high_level_il(true) else { + println!(" Does not have HLIL\n"); + continue; + }; + + // Loop through all blocks in the function + for block in il.basic_blocks().iter() { + // Loop though each instruction in the block + for instr in block.iter() { + // Generically parse the IL tree and display the parts + print_il_expr(&instr.lift(), 2); + } + } + println!(); + } + + // Important! Standalone executables need to call shutdown or they will hang forever + binaryninja::headless::shutdown(); +} diff --git a/examples/minidump/Cargo.toml b/examples/minidump/Cargo.toml index b002271..3e54fd6 100644 --- a/examples/minidump/Cargo.toml +++ b/examples/minidump/Cargo.toml @@ -8,6 +8,5 @@ crate-type = ["cdylib"] [dependencies] binaryninja = {path="../../"} -log = "0.4.17" -minidump = "0.15.2" -time = "=0.3.16" # Remove this when we update from stable-2022-12-15 - it's pinning a dependency that requires a more recent version of rustc +log = "0.4.20" +minidump = "0.18.0" diff --git a/examples/mlil_lifter/src/main.rs b/examples/mlil_lifter/src/main.rs index b827e0c..f6e04f2 100644 --- a/examples/mlil_lifter/src/main.rs +++ b/examples/mlil_lifter/src/main.rs @@ -38,7 +38,7 @@ fn main() { for instr in block.iter() { // Uplift the instruction into a native rust format let lifted = instr.lift(); - let address = instr.address(); + let address = instr.address; // print the lifted instruction println!("{address:08x}: {lifted:x?}"); diff --git a/examples/mlil_visitor/src/main.rs b/examples/mlil_visitor/src/main.rs index 3df005a..63d2f50 100644 --- a/examples/mlil_visitor/src/main.rs +++ b/examples/mlil_visitor/src/main.rs @@ -1,22 +1,24 @@ use std::env; use binaryninja::binaryview::BinaryViewExt; -use binaryninja::mlil::operation::MediumLevelILOperand; -use binaryninja::mlil::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelILOperation}; +use binaryninja::mlil::MediumLevelILLiftedOperand; +use binaryninja::mlil::{ + MediumLevelILFunction, MediumLevelILLiftedInstruction, MediumLevelILLiftedInstructionKind, +}; use binaryninja::types::Variable; fn print_indent(indent: usize) { print!("{: print!("Nop"), - Noret(_) => print!("Noret"), - Bp(_) => print!("Bp"), - Undef(_) => print!("Undef"), - Unimpl(_) => print!("Unimpl"), +fn print_operation(operation: &MediumLevelILLiftedInstruction) { + use MediumLevelILLiftedInstructionKind::*; + match operation.kind { + Nop => print!("Nop"), + Noret => print!("Noret"), + Bp => print!("Bp"), + Undef => print!("Undef"), + Unimpl => print!("Unimpl"), If(_) => print!("If"), FloatConst(_) => print!("FloatConst"), Const(_) => print!("Const"), @@ -149,14 +151,14 @@ fn print_variable(func: &MediumLevelILFunction, var: &Variable) { print!("{}", func.get_function().get_variable_name(var)); } -fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) { +fn print_il_expr(instr: &MediumLevelILLiftedInstruction, mut indent: usize) { print_indent(indent); - print_operation(instr.operation()); + print_operation(instr); println!(""); indent += 1; - use MediumLevelILOperand::*; + use MediumLevelILLiftedOperand::*; for (_name, operand) in instr.operands() { match operand { Int(int) => { @@ -171,13 +173,13 @@ fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) { Var(var) => { print_indent(indent); print!("var "); - print_variable(instr.function(), &var); + print_variable(&instr.function, &var); println!(); } VarSsa(var) => { print_indent(indent); print!("ssa var "); - print_variable(instr.function(), &var.variable); + print_variable(&instr.function, &var.variable); println!("#{}", var.version); } IntList(list) => { @@ -192,7 +194,7 @@ fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) { print_indent(indent); print!("var list "); for i in list { - print_variable(instr.function(), &i); + print_variable(&instr.function, &i); print!(" "); } println!(); @@ -201,7 +203,7 @@ fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) { print_indent(indent); print!("ssa var list "); for i in list { - print_variable(instr.function(), &i.variable); + print_variable(&instr.function, &i.variable); print!("#{} ", i.version); } println!(); @@ -221,6 +223,8 @@ fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) { } println!(); } + ConstantData(_) => println!("contantdata"), + Intrinsic(intrinsic) => println!("intrinsic {}", intrinsic.name()), } } } @@ -258,7 +262,7 @@ fn main() { // Loop though each instruction in the block for instr in block.iter() { // Generically parse the IL tree and display the parts - print_il_expr(&instr, 2); + print_il_expr(&instr.lift(), 2); } } println!(); diff --git a/src/architecture.rs b/src/architecture.rs index f5aed09..9a7b3e7 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -190,7 +190,7 @@ pub trait RegisterInfo: Sized { fn implicit_extend(&self) -> ImplicitRegisterExtend; } -pub trait Register: Sized + Clone + Copy { +pub trait Register: Sized + Clone + Copy + Hash + Eq { type InfoType: RegisterInfo; fn name(&self) -> Cow; @@ -230,7 +230,7 @@ pub trait RegisterStack: Sized + Clone + Copy { fn id(&self) -> u32; } -pub trait Flag: Sized + Clone + Copy { +pub trait Flag: Sized + Clone + Copy + Hash + Eq { type FlagClass: FlagClass; fn name(&self) -> Cow; @@ -487,6 +487,9 @@ pub trait Architecture: 'static + Sized + AsRef { fn intrinsics(&self) -> Vec { Vec::new() } + fn intrinsic_class(&self, _id: u32) -> binaryninjacore_sys::BNIntrinsicClass { + binaryninjacore_sys::BNIntrinsicClass::GeneralIntrinsicClass + } fn intrinsic_from_id(&self, _id: u32) -> Option { None } @@ -997,7 +1000,7 @@ impl Intrinsic for crate::architecture::CoreIntrinsic { let ret = slice::from_raw_parts_mut(inputs, count) .iter() - .map(|input| NameAndType::from_raw(input)) + .map(NameAndType::from_raw) .collect(); BNFreeNameAndTypeList(inputs, count); @@ -1169,14 +1172,23 @@ impl Architecture for CoreArchitecture { } } } - + fn instruction_llil( &self, - _data: &[u8], - _addr: u64, - _il: &mut Lifter, + data: &[u8], + addr: u64, + il: &mut Lifter, ) -> Option<(usize, bool)> { - None + let mut size = data.len(); + let success = unsafe { + BNGetInstructionLowLevelIL(self.0, data.as_ptr(), addr, &mut size as *mut _, il.handle) + }; + + if !success { + None + } else { + Some((size, true)) + } } fn flag_write_llil<'a>( @@ -1437,6 +1449,10 @@ impl Architecture for CoreArchitecture { } } + fn intrinsic_class(&self, id: u32) -> binaryninjacore_sys::BNIntrinsicClass { + unsafe { BNGetArchitectureIntrinsicClass(self.0, id) } + } + fn intrinsic_from_id(&self, id: u32) -> Option { // TODO validate in debug builds Some(CoreIntrinsic(self.0, id)) @@ -2366,6 +2382,14 @@ where } } + extern "C" fn cb_intrinsic_class(ctxt: *mut c_void, intrinsic: u32) -> BNIntrinsicClass + where + A: 'static + Architecture> + Send + Sync, + { + let custom_arch = unsafe { &*(ctxt as *mut A) }; + custom_arch.intrinsic_class(intrinsic) + } + extern "C" fn cb_intrinsic_name(ctxt: *mut c_void, intrinsic: u32) -> *mut c_char where A: 'static + Architecture> + Send + Sync, @@ -2405,7 +2429,7 @@ where unsafe { *count = res.len(); - if res.len() == 0 { + if res.is_empty() { ptr::null_mut() } else { let raw = res.as_mut_ptr(); @@ -2456,7 +2480,7 @@ where unsafe { *count = res.len(); - if res.len() == 0 { + if res.is_empty() { ptr::null_mut() } else { let raw = res.as_mut_ptr(); @@ -2723,6 +2747,7 @@ where getAllRegisterStacks: Some(cb_reg_stacks::), getRegisterStackInfo: Some(cb_reg_stack_info::), + getIntrinsicClass: Some(cb_intrinsic_class::), getIntrinsicName: Some(cb_intrinsic_name::), getAllIntrinsics: Some(cb_intrinsics::), getIntrinsicInputs: Some(cb_intrinsic_inputs::), diff --git a/src/binaryview.rs b/src/binaryview.rs index a6b2b54..e188b65 100644 --- a/src/binaryview.rs +++ b/src/binaryview.rs @@ -19,15 +19,16 @@ use binaryninjacore_sys::*; +pub use binaryninjacore_sys::BNAnalysisState as AnalysisState; pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; use std::collections::HashMap; use std::ffi::c_void; -use std::ops; use std::ops::Range; use std::os::raw::c_char; use std::ptr; use std::result; +use std::{ops, slice}; use crate::architecture::Architecture; use crate::architecture::CoreArchitecture; @@ -145,6 +146,28 @@ pub trait BinaryViewBase: AsRef { } } +#[derive(Debug, Clone)] +pub struct ActiveAnalysisInfo { + pub func: Ref, + pub analysis_time: u64, + pub update_count: usize, + pub submit_count: usize, +} + +#[derive(Debug, Clone)] +pub struct AnalysisInfo { + pub state: AnalysisState, + pub analysis_time: u64, + pub active_info: Vec, +} + +#[derive(Debug, Clone)] +pub struct AnalysisProgress { + pub state: AnalysisState, + pub count: usize, + pub total: usize, +} + // TODO: Copied from debuginfo.rs, this should be consolidated struct ProgressContext(Option Result<()>>>); @@ -273,15 +296,74 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNGetEndOffset(self.as_ref().handle) } } + fn add_analysis_option(&self, name: impl BnStrCompatible) { + unsafe { + BNAddAnalysisOption( + self.as_ref().handle, + name.into_bytes_with_nul().as_ref().as_ptr() as *mut _, + ) + } + } + + fn has_initial_analysis(&self) -> bool { + unsafe { BNHasInitialAnalysis(self.as_ref().handle) } + } + + fn set_analysis_hold(&self, enable: bool) { + unsafe { BNSetAnalysisHold(self.as_ref().handle, enable) } + } + + fn update_analysis(&self) { + unsafe { + BNUpdateAnalysis(self.as_ref().handle); + } + } + fn update_analysis_and_wait(&self) { unsafe { BNUpdateAnalysisAndWait(self.as_ref().handle); } } - fn update_analysis(&self) { - unsafe { - BNUpdateAnalysis(self.as_ref().handle); + fn abort_analysis(&self) { + unsafe { BNAbortAnalysis(self.as_ref().handle) } + } + + fn analysis_info(&self) -> Result { + let info_ref = unsafe { BNGetAnalysisInfo(self.as_ref().handle) }; + if info_ref.is_null() { + return Err(()); + } + let info = unsafe { *info_ref }; + let active_infos = unsafe { slice::from_raw_parts(info.activeInfo, info.count) }; + + let mut active_info_list = vec![]; + for active_info in active_infos { + let func = unsafe { Function::from_raw(BNNewFunctionReference(active_info.func)) }; + active_info_list.push(ActiveAnalysisInfo { + func, + analysis_time: active_info.analysisTime, + update_count: active_info.updateCount, + submit_count: active_info.submitCount, + }); + } + + let result = AnalysisInfo { + state: info.state, + analysis_time: info.analysisTime, + active_info: vec![], + }; + + unsafe { BNFreeAnalysisInfo(info_ref) }; + Ok(result) + } + + fn analysis_progress(&self) -> AnalysisProgress { + let progress = unsafe { BNGetAnalysisProgress(self.as_ref().handle) }; + AnalysisProgress { + state: progress.state, + count: progress.count, + total: progress.total, } } @@ -1452,3 +1534,64 @@ impl std::fmt::Debug for BinaryView { ) } } + +pub trait BinaryViewEventHandler: 'static + Sync { + fn on_event(&self, binary_view: &BinaryView); +} + +pub type BinaryViewEventType = BNBinaryViewEventType; + +/// Registers an event listener for binary view events. +/// +/// # Example +/// +/// ```rust +/// use binaryninja::binaryview::{BinaryView, BinaryViewEventHandler, BinaryViewEventType, register_binary_view_event}; +/// +/// struct EventHandlerContext { +/// // Context holding state available to event handler +/// } +/// +/// impl BinaryViewEventHandler for EventHandlerContext { +/// fn on_event(&mut self, binary_view: &BinaryView) { +/// // handle event +/// } +/// } +/// +/// #[no_mangle] +/// pub extern "C" fn CorePluginInit() { +/// let context = EventHandlerContext { }; +/// +/// register_binary_view_event( +/// BinaryViewEventType::BinaryViewInitialAnalysisCompletionEvent, +/// context, +/// ); +/// } +/// ``` +pub fn register_binary_view_event(event_type: BinaryViewEventType, handler: Handler) +where + Handler: BinaryViewEventHandler, +{ + unsafe extern "C" fn on_event( + ctx: *mut ::std::os::raw::c_void, + view: *mut BNBinaryView, + ) { + ffi_wrap!("EventHandler::on_event", unsafe { + let mut context = &mut *(ctx as *mut Handler); + + let handle = BinaryView::from_raw(BNNewViewReference(view)); + Handler::on_event(&mut context, handle.as_ref()); + }) + } + + let boxed = Box::new(handler); + let raw = Box::into_raw(boxed); + + unsafe { + BNRegisterBinaryViewEvent( + event_type, + Some(on_event::), + raw as *mut ::std::os::raw::c_void, + ); + } +} diff --git a/src/disassembly.rs b/src/disassembly.rs index 161eebc..1d0dfb8 100644 --- a/src/disassembly.rs +++ b/src/disassembly.rs @@ -94,6 +94,7 @@ pub enum InstructionTextTokenContents { NameSpace, GotoLabel(u64), Indentation, + Brace, } impl InstructionTextToken { @@ -141,6 +142,7 @@ impl InstructionTextToken { InstructionTextTokenContents::NameSpace => InstructionTextTokenType::NameSpaceToken, InstructionTextTokenContents::GotoLabel(_) => InstructionTextTokenType::GotoLabelToken, InstructionTextTokenContents::Indentation => InstructionTextTokenType::IndentationToken, + InstructionTextTokenContents::Brace => InstructionTextTokenType::BraceToken, }; let width = text.len() as u64; @@ -157,6 +159,7 @@ impl InstructionTextToken { address, typeNames: ptr::null_mut(), namesCount: 0, + exprIndex: BN_INVALID_EXPR }) } @@ -206,6 +209,10 @@ impl InstructionTextToken { pub fn address(&self) -> u64 { self.0.address } + + pub fn expr_index(&self) -> usize { + self.0.exprIndex + } } impl Default for InstructionTextToken { @@ -222,6 +229,7 @@ impl Default for InstructionTextToken { address: 0, typeNames: ptr::null_mut(), namesCount: 0, + exprIndex: BN_INVALID_EXPR }) } } @@ -240,6 +248,7 @@ impl Clone for InstructionTextToken { confidence: 0xff, typeNames: ptr::null_mut(), namesCount: 0, + exprIndex: self.0.exprIndex }) } } diff --git a/src/function.rs b/src/function.rs index 93af0dd..273a086 100644 --- a/src/function.rs +++ b/src/function.rs @@ -21,12 +21,17 @@ use crate::{ architecture::CoreArchitecture, basicblock::{BasicBlock, BlockContext}, binaryview::{BinaryView, BinaryViewExt}, - llil, mlil, + hlil, llil, mlil, platform::Platform, symbol::Symbol, types::{Conf, NamedTypedVariable, Type}, }; +pub use binaryninjacore_sys::BNAnalysisSkipReason as AnalysisSkipReason; +pub use binaryninjacore_sys::BNFunctionAnalysisSkipOverride as FunctionAnalysisSkipOverride; +pub use binaryninjacore_sys::BNFunctionUpdateType as FunctionUpdateType; + +use std::hash::Hash; use std::{fmt, mem}; pub struct Location { @@ -108,7 +113,7 @@ impl BlockContext for NativeBlock { } } -#[derive(PartialEq, Eq, Hash)] +#[derive(Eq)] pub struct Function { pub(crate) handle: *mut BNFunction, } @@ -178,6 +183,16 @@ impl Function { } } + pub fn set_can_return_auto>>(&self, can_return: T) { + let mut bool_with_confidence = can_return.into().into(); + unsafe { BNSetAutoFunctionCanReturn(self.handle, &mut bool_with_confidence) } + } + + pub fn set_can_return_user>>(&self, can_return: T) { + let mut bool_with_confidence = can_return.into().into(); + unsafe { BNSetAutoFunctionCanReturn(self.handle, &mut bool_with_confidence) } + } + pub fn comment_at(&self, addr: u64) -> BnString { unsafe { BnString::from_raw(BNGetCommentForAddress(self.handle, addr)) } } @@ -225,6 +240,18 @@ impl Function { } } + pub fn high_level_il(&self, full_ast: bool) -> Result, ()> { + unsafe { + let hlil = BNGetFunctionHighLevelIL(self.handle); + + if hlil.is_null() { + return Err(()); + } + + Ok(hlil::HighLevelILFunction::ref_from_raw(hlil, full_ast)) + } + } + pub fn medium_level_il(&self) -> Result, ()> { unsafe { let mlil = BNGetFunctionMediumLevelIL(self.handle); @@ -233,7 +260,7 @@ impl Function { return Err(()); } - Ok(Ref::new(mlil::MediumLevelILFunction::from_raw(mlil))) + Ok(mlil::MediumLevelILFunction::ref_from_raw(mlil)) } } @@ -245,7 +272,7 @@ impl Function { return Err(()); } - Ok(Ref::new(llil::RegularFunction::from_raw(self.arch(), llil))) + Ok(llil::RegularFunction::from_raw(self.arch(), llil)) } } @@ -257,7 +284,7 @@ impl Function { return Err(()); } - Ok(Ref::new(llil::LiftedFunction::from_raw(self.arch(), llil))) + Ok(llil::LiftedFunction::from_raw(self.arch(), llil)) } } @@ -301,6 +328,40 @@ impl Function { ); } } + + pub fn analysis_skipped(&self) -> bool { + unsafe { BNIsFunctionAnalysisSkipped(self.handle) } + } + + pub fn set_analysis_skipped(&self, skip: bool) { + if skip { + unsafe { + BNSetFunctionAnalysisSkipOverride( + self.handle, + BNFunctionAnalysisSkipOverride::AlwaysSkipFunctionAnalysis, + ); + } + } else { + unsafe { + BNSetFunctionAnalysisSkipOverride( + self.handle, + BNFunctionAnalysisSkipOverride::NeverSkipFunctionAnalysis, + ); + } + } + } + + pub fn analysis_skip_reason(&self) -> AnalysisSkipReason { + unsafe { BNGetAnalysisSkipReason(self.handle) } + } + + pub fn analysis_skip_override(&self) -> FunctionAnalysisSkipOverride { + unsafe { BNGetFunctionAnalysisSkipOverride(self.handle) } + } + + pub fn set_analysis_skip_override(&self, override_: FunctionAnalysisSkipOverride) { + unsafe { BNSetFunctionAnalysisSkipOverride(self.handle, override_) } + } } impl fmt::Debug for Function { @@ -354,6 +415,26 @@ unsafe impl<'a> CoreArrayWrapper<'a> for Function { } } +impl Hash for Function { + fn hash(&self, state: &mut H) { + let start_address = self.start(); + let architecture = self.arch(); + let platform = self.platform(); + (start_address, architecture, platform).hash(state) + } +} + +impl PartialEq for Function { + fn eq(&self, other: &Self) -> bool { + if self.handle == other.handle { + return true; + } + self.start() == other.start() + && self.arch() == other.arch() + && self.platform() == other.platform() + } +} + ///////////////// // AddressRange diff --git a/src/functionrecognizer.rs b/src/functionrecognizer.rs index ec56730..c63edca 100644 --- a/src/functionrecognizer.rs +++ b/src/functionrecognizer.rs @@ -70,7 +70,7 @@ where let custom_handler = unsafe { &*(ctxt as *mut R) }; let bv = unsafe { BinaryView::from_raw(BNNewViewReference(bv)) }; let func = unsafe { Function::from_raw(BNNewFunctionReference(func)) }; - let mlil = unsafe { mlil::MediumLevelILFunction::from_raw(mlil) }; + let mlil = unsafe { mlil::MediumLevelILFunction::ref_from_raw(mlil) }; custom_handler.recognize_medium_level_il(bv.as_ref(), func.as_ref(), &mlil) } diff --git a/src/hlil/block.rs b/src/hlil/block.rs new file mode 100644 index 0000000..0bbedd1 --- /dev/null +++ b/src/hlil/block.rs @@ -0,0 +1,63 @@ +use std::ops::Range; + +use binaryninjacore_sys::BNGetHighLevelILIndexForInstruction; + +use crate::basicblock::{BasicBlock, BlockContext}; +use crate::rc::Ref; + +use super::{HighLevelILFunction, HighLevelILInstruction}; + +pub struct HighLevelILBlockIter { + function: Ref, + range: Range, +} + +impl Iterator for HighLevelILBlockIter { + type Item = HighLevelILInstruction; + + fn next(&mut self) -> Option { + self.range + .next() + .map(|i| unsafe { + BNGetHighLevelILIndexForInstruction(self.function.handle, i as usize) + }) + .map(|i| HighLevelILInstruction::new(self.function.to_owned(), i)) + } +} + +pub struct HighLevelILBlock { + pub(crate) function: Ref, +} + +impl core::fmt::Debug for HighLevelILBlock { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "mlil_bb {:?}", self.function) + } +} + +impl BlockContext for HighLevelILBlock { + type Iter = HighLevelILBlockIter; + type Instruction = HighLevelILInstruction; + + fn start(&self, block: &BasicBlock) -> HighLevelILInstruction { + let expr_idx = unsafe { + BNGetHighLevelILIndexForInstruction(self.function.handle, block.raw_start() as usize) + }; + HighLevelILInstruction::new(self.function.to_owned(), expr_idx) + } + + fn iter(&self, block: &BasicBlock) -> HighLevelILBlockIter { + HighLevelILBlockIter { + function: self.function.to_owned(), + range: block.raw_start()..block.raw_end(), + } + } +} + +impl Clone for HighLevelILBlock { + fn clone(&self) -> Self { + HighLevelILBlock { + function: self.function.to_owned(), + } + } +} diff --git a/src/hlil/function.rs b/src/hlil/function.rs new file mode 100644 index 0000000..4bad7f0 --- /dev/null +++ b/src/hlil/function.rs @@ -0,0 +1,111 @@ +use std::hash::{Hash, Hasher}; + +use binaryninjacore_sys::BNFreeHighLevelILFunction; +use binaryninjacore_sys::BNGetHighLevelILBasicBlockList; +use binaryninjacore_sys::BNGetHighLevelILInstructionCount; +use binaryninjacore_sys::BNGetHighLevelILOwnerFunction; +use binaryninjacore_sys::BNGetHighLevelILSSAForm; +use binaryninjacore_sys::BNHighLevelILFunction; +use binaryninjacore_sys::BNNewHighLevelILFunctionReference; + +use crate::basicblock::BasicBlock; +use crate::function::Function; +use crate::rc::{Array, Ref, RefCountable}; + +use super::{HighLevelILBlock, HighLevelILInstruction, HighLevelILLiftedInstruction}; + +pub struct HighLevelILFunction { + pub(crate) full_ast: bool, + pub(crate) handle: *mut BNHighLevelILFunction, +} + +unsafe impl Send for HighLevelILFunction {} +unsafe impl Sync for HighLevelILFunction {} + +impl Eq for HighLevelILFunction {} +impl PartialEq for HighLevelILFunction { + fn eq(&self, rhs: &Self) -> bool { + self.get_function().eq(&rhs.get_function()) + } +} + +impl Hash for HighLevelILFunction { + fn hash(&self, state: &mut H) { + self.get_function().hash(state) + } +} + +impl HighLevelILFunction { + pub(crate) unsafe fn ref_from_raw( + handle: *mut BNHighLevelILFunction, + full_ast: bool, + ) -> Ref { + debug_assert!(!handle.is_null()); + Self { handle, full_ast }.to_owned() + } + + pub fn instruction_from_idx(&self, expr_idx: usize) -> HighLevelILInstruction { + HighLevelILInstruction::new(self.to_owned(), expr_idx) + } + + pub fn lifted_instruction_from_idx(&self, expr_idx: usize) -> HighLevelILLiftedInstruction { + self.instruction_from_idx(expr_idx).lift() + } + + pub fn instruction_count(&self) -> usize { + unsafe { BNGetHighLevelILInstructionCount(self.handle) } + } + + pub fn ssa_form(&self) -> HighLevelILFunction { + let ssa = unsafe { BNGetHighLevelILSSAForm(self.handle) }; + assert!(!ssa.is_null()); + HighLevelILFunction { + handle: ssa, + full_ast: self.full_ast, + } + } + + pub fn get_function(&self) -> Ref { + unsafe { + let func = BNGetHighLevelILOwnerFunction(self.handle); + Function::from_raw(func) + } + } + + pub fn basic_blocks(&self) -> Array> { + let mut count = 0; + let blocks = unsafe { BNGetHighLevelILBasicBlockList(self.handle, &mut count) }; + let context = HighLevelILBlock { + function: self.to_owned(), + }; + + unsafe { Array::new(blocks, count, context) } + } +} + +impl ToOwned for HighLevelILFunction { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for HighLevelILFunction { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: BNNewHighLevelILFunctionReference(handle.handle), + full_ast: handle.full_ast, + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeHighLevelILFunction(handle.handle); + } +} + +impl core::fmt::Debug for HighLevelILFunction { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "", self.handle) + } +} diff --git a/src/hlil/instruction.rs b/src/hlil/instruction.rs new file mode 100644 index 0000000..159652f --- /dev/null +++ b/src/hlil/instruction.rs @@ -0,0 +1,991 @@ +use binaryninjacore_sys::BNFromVariableIdentifier; +use binaryninjacore_sys::BNGetHighLevelILByIndex; +use binaryninjacore_sys::BNHighLevelILOperation; + +use crate::operand_iter::OperandIter; +use crate::rc::Ref; +use crate::types::{ + ConstantData, ILIntrinsic, RegisterValue, RegisterValueType, SSAVariable, Variable, +}; + +use super::operation::*; +use super::{HighLevelILFunction, HighLevelILLiftedInstruction, HighLevelILLiftedInstructionKind}; + +#[derive(Clone)] +pub struct HighLevelILInstruction { + pub function: Ref, + pub address: u64, + pub kind: HighLevelILInstructionKind, +} + +#[derive(Copy, Clone)] +pub enum HighLevelILInstructionKind { + Nop, + Break, + Continue, + Noret, + Unreachable, + Bp, + Undef, + Unimpl, + Adc(BinaryOpCarry), + Sbb(BinaryOpCarry), + Rlc(BinaryOpCarry), + Rrc(BinaryOpCarry), + Add(BinaryOp), + Sub(BinaryOp), + And(BinaryOp), + Or(BinaryOp), + Xor(BinaryOp), + Lsl(BinaryOp), + Lsr(BinaryOp), + Asr(BinaryOp), + Rol(BinaryOp), + Ror(BinaryOp), + Mul(BinaryOp), + MuluDp(BinaryOp), + MulsDp(BinaryOp), + Divu(BinaryOp), + DivuDp(BinaryOp), + Divs(BinaryOp), + DivsDp(BinaryOp), + Modu(BinaryOp), + ModuDp(BinaryOp), + Mods(BinaryOp), + ModsDp(BinaryOp), + CmpE(BinaryOp), + CmpNe(BinaryOp), + CmpSlt(BinaryOp), + CmpUlt(BinaryOp), + CmpSle(BinaryOp), + CmpUle(BinaryOp), + CmpSge(BinaryOp), + CmpUge(BinaryOp), + CmpSgt(BinaryOp), + CmpUgt(BinaryOp), + TestBit(BinaryOp), + AddOverflow(BinaryOp), + Fadd(BinaryOp), + Fsub(BinaryOp), + Fmul(BinaryOp), + Fdiv(BinaryOp), + FcmpE(BinaryOp), + FcmpNe(BinaryOp), + FcmpLt(BinaryOp), + FcmpLe(BinaryOp), + FcmpGe(BinaryOp), + FcmpGt(BinaryOp), + FcmpO(BinaryOp), + FcmpUo(BinaryOp), + ArrayIndex(ArrayIndex), + ArrayIndexSsa(ArrayIndexSsa), + Assign(Assign), + AssignMemSsa(AssignMemSsa), + AssignUnpack(AssignUnpack), + AssignUnpackMemSsa(AssignUnpackMemSsa), + Block(Block), + Call(Call), + Tailcall(Call), + CallSsa(CallSsa), + Case(Case), + Const(Const), + ConstPtr(Const), + Import(Const), + ConstData(ConstData), + Deref(UnaryOp), + AddressOf(UnaryOp), + Neg(UnaryOp), + Not(UnaryOp), + Sx(UnaryOp), + Zx(UnaryOp), + LowPart(UnaryOp), + BoolToInt(UnaryOp), + UnimplMem(UnaryOp), + Fsqrt(UnaryOp), + Fneg(UnaryOp), + Fabs(UnaryOp), + FloatToInt(UnaryOp), + IntToFloat(UnaryOp), + FloatConv(UnaryOp), + RoundToInt(UnaryOp), + Floor(UnaryOp), + Ceil(UnaryOp), + Ftrunc(UnaryOp), + DerefFieldSsa(DerefFieldSsa), + DerefSsa(DerefSsa), + ExternPtr(ExternPtr), + FloatConst(FloatConst), + For(ForLoop), + ForSsa(ForLoopSsa), + Goto(Label), + Label(Label), + If(If), + Intrinsic(Intrinsic), + IntrinsicSsa(IntrinsicSsa), + Jump(Jump), + MemPhi(MemPhi), + Ret(Ret), + Split(Split), + StructField(StructField), + DerefField(StructField), + Switch(Switch), + Syscall(Syscall), + SyscallSsa(SyscallSsa), + Trap(Trap), + VarDeclare(Var), + Var(Var), + VarInit(VarInit), + VarInitSsa(VarInitSsa), + VarPhi(VarPhi), + VarSsa(VarSsa), + While(While), + DoWhile(While), + WhileSsa(WhileSsa), + DoWhileSsa(WhileSsa), +} +impl HighLevelILInstruction { + pub(crate) fn new(function: Ref, idx: usize) -> Self { + let op = unsafe { BNGetHighLevelILByIndex(function.handle, idx, function.full_ast) }; + use BNHighLevelILOperation::*; + use HighLevelILInstructionKind as Op; + let kind = match op.operation { + HLIL_NOP => Op::Nop, + HLIL_BREAK => Op::Break, + HLIL_CONTINUE => Op::Continue, + HLIL_NORET => Op::Noret, + HLIL_UNREACHABLE => Op::Unreachable, + HLIL_BP => Op::Bp, + HLIL_UNDEF => Op::Undef, + HLIL_UNIMPL => Op::Unimpl, + HLIL_ADC => Op::Adc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + HLIL_SBB => Op::Sbb(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + HLIL_RLC => Op::Rlc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + HLIL_RRC => Op::Rrc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + HLIL_ADD => Op::Add(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_SUB => Op::Sub(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_AND => Op::And(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_OR => Op::Or(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_XOR => Op::Xor(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_LSL => Op::Lsl(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_LSR => Op::Lsr(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_ASR => Op::Asr(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_ROL => Op::Rol(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_ROR => Op::Ror(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MUL => Op::Mul(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MULU_DP => Op::MuluDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MULS_DP => Op::MulsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_DIVU => Op::Divu(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_DIVU_DP => Op::DivuDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_DIVS => Op::Divs(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_DIVS_DP => Op::DivsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MODU => Op::Modu(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MODU_DP => Op::ModuDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MODS => Op::Mods(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_MODS_DP => Op::ModsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_E => Op::CmpE(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_NE => Op::CmpNe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_SLT => Op::CmpSlt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_ULT => Op::CmpUlt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_SLE => Op::CmpSle(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_ULE => Op::CmpUle(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_SGE => Op::CmpSge(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_UGE => Op::CmpUge(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_SGT => Op::CmpSgt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_CMP_UGT => Op::CmpUgt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_TEST_BIT => Op::TestBit(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FADD => Op::Fadd(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FSUB => Op::Fsub(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FMUL => Op::Fmul(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FDIV => Op::Fdiv(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_E => Op::FcmpE(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_NE => Op::FcmpNe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_LT => Op::FcmpLt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_LE => Op::FcmpLe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_GE => Op::FcmpGe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_GT => Op::FcmpGt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_O => Op::FcmpO(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_FCMP_UO => Op::FcmpUo(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + HLIL_ARRAY_INDEX => Op::ArrayIndex(ArrayIndex { + src: op.operands[0] as usize, + index: op.operands[1] as usize, + }), + HLIL_ARRAY_INDEX_SSA => Op::ArrayIndexSsa(ArrayIndexSsa { + src: op.operands[0] as usize, + src_memory: op.operands[1], + index: op.operands[2] as usize, + }), + HLIL_ASSIGN => Op::Assign(Assign { + dest: op.operands[0] as usize, + src: op.operands[1] as usize, + }), + HLIL_ASSIGN_MEM_SSA => Op::AssignMemSsa(AssignMemSsa { + dest: op.operands[0] as usize, + dest_memory: op.operands[1], + src: op.operands[2] as usize, + src_memory: op.operands[3], + }), + HLIL_ASSIGN_UNPACK => Op::AssignUnpack(AssignUnpack { + num_dests: op.operands[0] as usize, + first_dest: op.operands[1] as usize, + src: op.operands[2] as usize, + }), + HLIL_ASSIGN_UNPACK_MEM_SSA => Op::AssignUnpackMemSsa(AssignUnpackMemSsa { + num_dests: op.operands[0] as usize, + first_dest: op.operands[1] as usize, + dest_memory: op.operands[2], + src: op.operands[3] as usize, + src_memory: op.operands[4], + }), + HLIL_BLOCK => Op::Block(Block { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + }), + HLIL_CALL => Op::Call(Call { + dest: op.operands[0] as usize, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + }), + HLIL_TAILCALL => Op::Tailcall(Call { + dest: op.operands[0] as usize, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + }), + HLIL_CALL_SSA => Op::CallSsa(CallSsa { + dest: op.operands[0] as usize, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + dest_memory: op.operands[3], + src_memory: op.operands[4], + }), + HLIL_CASE => Op::Case(Case { + num_values: op.operands[0] as usize, + first_value: op.operands[1] as usize, + body: op.operands[2] as usize, + }), + HLIL_CONST => Op::Const(Const { + constant: op.operands[0], + }), + HLIL_CONST_PTR => Op::ConstPtr(Const { + constant: op.operands[0], + }), + HLIL_IMPORT => Op::Import(Const { + constant: op.operands[0], + }), + HLIL_CONST_DATA => Op::ConstData(ConstData { + constant_data_kind: op.operands[0] as u32, + constant_data_value: op.operands[1] as i64, + size: op.size, + }), + HLIL_DEREF => Op::Deref(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_ADDRESS_OF => Op::AddressOf(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_NEG => Op::Neg(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_NOT => Op::Not(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_SX => Op::Sx(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_ZX => Op::Zx(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_LOW_PART => Op::LowPart(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FSQRT => Op::Fsqrt(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FNEG => Op::Fneg(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FABS => Op::Fabs(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FLOAT_CONV => Op::FloatConv(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FLOOR => Op::Floor(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_CEIL => Op::Ceil(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_FTRUNC => Op::Ftrunc(UnaryOp { + src: op.operands[0] as usize, + }), + HLIL_DEREF_FIELD_SSA => Op::DerefFieldSsa(DerefFieldSsa { + src: op.operands[0] as usize, + src_memory: op.operands[1], + offset: op.operands[2], + member_index: get_member_index(op.operands[3]), + }), + HLIL_DEREF_SSA => Op::DerefSsa(DerefSsa { + src: op.operands[0] as usize, + src_memory: op.operands[1], + }), + HLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr { + constant: op.operands[0], + offset: op.operands[1], + }), + HLIL_FLOAT_CONST => Op::FloatConst(FloatConst { + constant: get_float(op.operands[0], op.size), + }), + HLIL_FOR => Op::For(ForLoop { + init: op.operands[0] as usize, + condition: op.operands[1] as usize, + update: op.operands[2] as usize, + body: op.operands[3] as usize, + }), + HLIL_FOR_SSA => Op::ForSsa(ForLoopSsa { + init: op.operands[0] as usize, + condition_phi: op.operands[1] as usize, + condition: op.operands[2] as usize, + update: op.operands[3] as usize, + body: op.operands[4] as usize, + }), + HLIL_GOTO => Op::Goto(Label { + target: op.operands[0], + }), + HLIL_LABEL => Op::Label(Label { + target: op.operands[0], + }), + HLIL_IF => Op::If(If { + condition: op.operands[0] as usize, + cond_true: op.operands[1] as usize, + cond_false: op.operands[2] as usize, + }), + HLIL_INTRINSIC => Op::Intrinsic(Intrinsic { + intrinsic: op.operands[0] as u32, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + }), + HLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa { + intrinsic: op.operands[0] as u32, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + dest_memory: op.operands[3], + src_memory: op.operands[4], + }), + HLIL_JUMP => Op::Jump(Jump { + dest: op.operands[0] as usize, + }), + HLIL_MEM_PHI => Op::MemPhi(MemPhi { + dest: op.operands[0], + num_srcs: op.operands[1] as usize, + first_src: op.operands[2] as usize, + }), + HLIL_RET => Op::Ret(Ret { + num_srcs: op.operands[0] as usize, + first_src: op.operands[1] as usize, + }), + HLIL_SPLIT => Op::Split(Split { + high: op.operands[0] as usize, + low: op.operands[1] as usize, + }), + HLIL_STRUCT_FIELD => Op::StructField(StructField { + src: op.operands[0] as usize, + offset: op.operands[1], + member_index: get_member_index(op.operands[2]), + }), + HLIL_DEREF_FIELD => Op::DerefField(StructField { + src: op.operands[0] as usize, + offset: op.operands[1], + member_index: get_member_index(op.operands[2]), + }), + HLIL_SWITCH => Op::Switch(Switch { + condition: op.operands[0] as usize, + default: op.operands[1] as usize, + num_cases: op.operands[2] as usize, + first_case: op.operands[3] as usize, + }), + HLIL_SYSCALL => Op::Syscall(Syscall { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + }), + HLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + dest_memory: op.operands[2], + src_memory: op.operands[3], + }), + HLIL_TRAP => Op::Trap(Trap { + vector: op.operands[0], + }), + HLIL_VAR_DECLARE => Op::VarDeclare(Var { + var: get_var(op.operands[0]), + }), + HLIL_VAR => Op::Var(Var { + var: get_var(op.operands[0]), + }), + HLIL_VAR_INIT => Op::VarInit(VarInit { + dest: get_var(op.operands[0]), + src: op.operands[1] as usize, + }), + HLIL_VAR_INIT_SSA => Op::VarInitSsa(VarInitSsa { + dest: get_var_ssa((op.operands[0], op.operands[1] as usize)), + src: op.operands[2] as usize, + }), + HLIL_VAR_PHI => Op::VarPhi(VarPhi { + dest: get_var_ssa((op.operands[0], op.operands[1] as usize)), + num_srcs: op.operands[2] as usize, + first_src: op.operands[3] as usize, + }), + HLIL_VAR_SSA => Op::VarSsa(VarSsa { + var: get_var_ssa((op.operands[0], op.operands[1] as usize)), + }), + HLIL_WHILE => Op::While(While { + condition: op.operands[0] as usize, + body: op.operands[1] as usize, + }), + HLIL_DO_WHILE => Op::DoWhile(While { + condition: op.operands[0] as usize, + body: op.operands[1] as usize, + }), + HLIL_WHILE_SSA => Op::WhileSsa(WhileSsa { + condition_phi: op.operands[0] as usize, + condition: op.operands[1] as usize, + body: op.operands[2] as usize, + }), + HLIL_DO_WHILE_SSA => Op::DoWhileSsa(WhileSsa { + condition_phi: op.operands[0] as usize, + condition: op.operands[1] as usize, + body: op.operands[2] as usize, + }), + }; + Self { + function, + address: op.address, + kind, + } + } + + pub fn lift(&self) -> HighLevelILLiftedInstruction { + use HighLevelILInstructionKind::*; + use HighLevelILLiftedInstructionKind as Lifted; + let kind = match self.kind { + Nop => Lifted::Nop, + Break => Lifted::Break, + Continue => Lifted::Continue, + Noret => Lifted::Noret, + Unreachable => Lifted::Unreachable, + Bp => Lifted::Bp, + Undef => Lifted::Undef, + Unimpl => Lifted::Unimpl, + + Adc(op) => Lifted::Adc(self.lift_binary_op_carry(op)), + Sbb(op) => Lifted::Sbb(self.lift_binary_op_carry(op)), + Rlc(op) => Lifted::Rlc(self.lift_binary_op_carry(op)), + Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)), + + Add(op) => Lifted::Add(self.lift_binary_op(op)), + Sub(op) => Lifted::Sub(self.lift_binary_op(op)), + And(op) => Lifted::And(self.lift_binary_op(op)), + Or(op) => Lifted::Or(self.lift_binary_op(op)), + Xor(op) => Lifted::Xor(self.lift_binary_op(op)), + Lsl(op) => Lifted::Lsl(self.lift_binary_op(op)), + Lsr(op) => Lifted::Lsr(self.lift_binary_op(op)), + Asr(op) => Lifted::Asr(self.lift_binary_op(op)), + Rol(op) => Lifted::Rol(self.lift_binary_op(op)), + Ror(op) => Lifted::Ror(self.lift_binary_op(op)), + Mul(op) => Lifted::Mul(self.lift_binary_op(op)), + MuluDp(op) => Lifted::MuluDp(self.lift_binary_op(op)), + MulsDp(op) => Lifted::MulsDp(self.lift_binary_op(op)), + Divu(op) => Lifted::Divu(self.lift_binary_op(op)), + DivuDp(op) => Lifted::DivuDp(self.lift_binary_op(op)), + Divs(op) => Lifted::Divs(self.lift_binary_op(op)), + DivsDp(op) => Lifted::DivsDp(self.lift_binary_op(op)), + Modu(op) => Lifted::Modu(self.lift_binary_op(op)), + ModuDp(op) => Lifted::ModuDp(self.lift_binary_op(op)), + Mods(op) => Lifted::Mods(self.lift_binary_op(op)), + ModsDp(op) => Lifted::ModsDp(self.lift_binary_op(op)), + CmpE(op) => Lifted::CmpE(self.lift_binary_op(op)), + CmpNe(op) => Lifted::CmpNe(self.lift_binary_op(op)), + CmpSlt(op) => Lifted::CmpSlt(self.lift_binary_op(op)), + CmpUlt(op) => Lifted::CmpUlt(self.lift_binary_op(op)), + CmpSle(op) => Lifted::CmpSle(self.lift_binary_op(op)), + CmpUle(op) => Lifted::CmpUle(self.lift_binary_op(op)), + CmpSge(op) => Lifted::CmpSge(self.lift_binary_op(op)), + CmpUge(op) => Lifted::CmpUge(self.lift_binary_op(op)), + CmpSgt(op) => Lifted::CmpSgt(self.lift_binary_op(op)), + CmpUgt(op) => Lifted::CmpUgt(self.lift_binary_op(op)), + TestBit(op) => Lifted::TestBit(self.lift_binary_op(op)), + AddOverflow(op) => Lifted::AddOverflow(self.lift_binary_op(op)), + Fadd(op) => Lifted::Fadd(self.lift_binary_op(op)), + Fsub(op) => Lifted::Fsub(self.lift_binary_op(op)), + Fmul(op) => Lifted::Fmul(self.lift_binary_op(op)), + Fdiv(op) => Lifted::Fdiv(self.lift_binary_op(op)), + FcmpE(op) => Lifted::FcmpE(self.lift_binary_op(op)), + FcmpNe(op) => Lifted::FcmpNe(self.lift_binary_op(op)), + FcmpLt(op) => Lifted::FcmpLt(self.lift_binary_op(op)), + FcmpLe(op) => Lifted::FcmpLe(self.lift_binary_op(op)), + FcmpGe(op) => Lifted::FcmpGe(self.lift_binary_op(op)), + FcmpGt(op) => Lifted::FcmpGt(self.lift_binary_op(op)), + FcmpO(op) => Lifted::FcmpO(self.lift_binary_op(op)), + FcmpUo(op) => Lifted::FcmpUo(self.lift_binary_op(op)), + + ArrayIndex(op) => Lifted::ArrayIndex(LiftedArrayIndex { + src: self.lift_operand(op.src), + index: self.lift_operand(op.index), + }), + ArrayIndexSsa(op) => Lifted::ArrayIndexSsa(LiftedArrayIndexSsa { + src: self.lift_operand(op.src), + src_memory: op.src_memory, + index: self.lift_operand(op.index), + }), + Assign(op) => Lifted::Assign(LiftedAssign { + dest: self.lift_operand(op.dest), + src: self.lift_operand(op.src), + }), + AssignUnpack(op) => Lifted::AssignUnpack(LiftedAssignUnpack { + dest: self.lift_instruction_list(op.first_dest, op.num_dests), + src: self.lift_operand(op.src), + }), + AssignMemSsa(op) => Lifted::AssignMemSsa(LiftedAssignMemSsa { + dest: self.lift_operand(op.dest), + dest_memory: op.dest_memory, + src: self.lift_operand(op.src), + src_memory: op.src_memory, + }), + AssignUnpackMemSsa(op) => Lifted::AssignUnpackMemSsa(LiftedAssignUnpackMemSsa { + dest: self.lift_instruction_list(op.first_dest, op.num_dests), + dest_memory: op.dest_memory, + src: self.lift_operand(op.src), + src_memory: op.src_memory, + }), + Block(op) => Lifted::Block(LiftedBlock { + body: self.lift_instruction_list(op.first_param, op.num_params), + }), + + Call(op) => Lifted::Call(self.lift_call(op)), + Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), + CallSsa(op) => Lifted::CallSsa(LiftedCallSsa { + dest: self.lift_operand(op.dest), + params: self.lift_instruction_list(op.first_param, op.num_params), + dest_memory: op.dest_memory, + src_memory: op.src_memory, + }), + + Case(op) => Lifted::Case(LiftedCase { + values: self.lift_instruction_list(op.first_value, op.num_values), + body: self.lift_operand(op.body), + }), + Const(op) => Lifted::Const(op), + ConstPtr(op) => Lifted::ConstPtr(op), + Import(op) => Lifted::Import(op), + ConstData(op) => Lifted::ConstData(LiftedConstData { + constant_data: ConstantData::new( + self.function.get_function(), + RegisterValue { + state: RegisterValueType::from_raw_value(op.constant_data_kind).unwrap(), + value: op.constant_data_value, + offset: 0, + size: op.size, + }, + ), + }), + + Deref(op) => Lifted::Deref(self.lift_unary_op(op)), + AddressOf(op) => Lifted::AddressOf(self.lift_unary_op(op)), + Neg(op) => Lifted::Neg(self.lift_unary_op(op)), + Not(op) => Lifted::Not(self.lift_unary_op(op)), + Sx(op) => Lifted::Sx(self.lift_unary_op(op)), + Zx(op) => Lifted::Zx(self.lift_unary_op(op)), + LowPart(op) => Lifted::LowPart(self.lift_unary_op(op)), + BoolToInt(op) => Lifted::BoolToInt(self.lift_unary_op(op)), + UnimplMem(op) => Lifted::UnimplMem(self.lift_unary_op(op)), + Fsqrt(op) => Lifted::Fsqrt(self.lift_unary_op(op)), + Fneg(op) => Lifted::Fneg(self.lift_unary_op(op)), + Fabs(op) => Lifted::Fabs(self.lift_unary_op(op)), + FloatToInt(op) => Lifted::FloatToInt(self.lift_unary_op(op)), + IntToFloat(op) => Lifted::IntToFloat(self.lift_unary_op(op)), + FloatConv(op) => Lifted::FloatConv(self.lift_unary_op(op)), + RoundToInt(op) => Lifted::RoundToInt(self.lift_unary_op(op)), + Floor(op) => Lifted::Floor(self.lift_unary_op(op)), + Ceil(op) => Lifted::Ceil(self.lift_unary_op(op)), + Ftrunc(op) => Lifted::Ftrunc(self.lift_unary_op(op)), + + DerefFieldSsa(op) => Lifted::DerefFieldSsa(LiftedDerefFieldSsa { + src: self.lift_operand(op.src), + src_memory: op.src_memory, + offset: op.offset, + member_index: op.member_index, + }), + DerefSsa(op) => Lifted::DerefSsa(LiftedDerefSsa { + src: self.lift_operand(op.src), + src_memory: op.src_memory, + }), + ExternPtr(op) => Lifted::ExternPtr(op), + FloatConst(op) => Lifted::FloatConst(op), + For(op) => Lifted::For(LiftedForLoop { + init: self.lift_operand(op.init), + condition: self.lift_operand(op.condition), + update: self.lift_operand(op.update), + body: self.lift_operand(op.body), + }), + Goto(op) => Lifted::Goto(self.lift_label(op)), + Label(op) => Lifted::Label(self.lift_label(op)), + ForSsa(op) => Lifted::ForSsa(LiftedForLoopSsa { + init: self.lift_operand(op.init), + condition_phi: self.lift_operand(op.condition_phi), + condition: self.lift_operand(op.condition), + update: self.lift_operand(op.update), + body: self.lift_operand(op.body), + }), + If(op) => Lifted::If(LiftedIf { + condition: self.lift_operand(op.condition), + cond_true: self.lift_operand(op.cond_true), + cond_false: self.lift_operand(op.cond_false), + }), + Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { + intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), + params: self.lift_instruction_list(op.first_param, op.num_params), + }), + IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { + intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), + params: self.lift_instruction_list(op.first_param, op.num_params), + dest_memory: op.dest_memory, + src_memory: op.src_memory, + }), + Jump(op) => Lifted::Jump(LiftedJump { + dest: self.lift_operand(op.dest), + }), + MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { + dest: op.dest, + src: OperandIter::new(&*self.function, op.first_src, op.num_srcs).collect(), + }), + Ret(op) => Lifted::Ret(LiftedRet { + src: self.lift_instruction_list(op.first_src, op.num_srcs), + }), + Split(op) => Lifted::Split(LiftedSplit { + high: self.lift_operand(op.high), + low: self.lift_operand(op.low), + }), + StructField(op) => Lifted::StructField(self.lift_struct_field(op)), + DerefField(op) => Lifted::DerefField(self.lift_struct_field(op)), + Switch(op) => Lifted::Switch(LiftedSwitch { + condition: self.lift_operand(op.condition), + default: self.lift_operand(op.default), + cases: self.lift_instruction_list(op.first_case, op.num_cases), + }), + Syscall(op) => Lifted::Syscall(LiftedSyscall { + params: self.lift_instruction_list(op.first_param, op.num_params), + }), + SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { + params: self.lift_instruction_list(op.first_param, op.num_params), + dest_memory: op.dest_memory, + src_memory: op.src_memory, + }), + Trap(op) => Lifted::Trap(op), + VarDeclare(op) => Lifted::VarDeclare(op), + Var(op) => Lifted::Var(op), + VarInit(op) => Lifted::VarInit(LiftedVarInit { + dest: op.dest, + src: self.lift_operand(op.src), + }), + VarInitSsa(op) => Lifted::VarInitSsa(LiftedVarInitSsa { + dest: op.dest, + src: self.lift_operand(op.src), + }), + VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { + dest: op.dest, + src: OperandIter::new(&*self.function, op.first_src, op.num_srcs) + .ssa_vars() + .collect(), + }), + VarSsa(op) => Lifted::VarSsa(op), + + While(op) => Lifted::While(self.lift_while(op)), + DoWhile(op) => Lifted::DoWhile(self.lift_while(op)), + + WhileSsa(op) => Lifted::WhileSsa(self.lift_while_ssa(op)), + DoWhileSsa(op) => Lifted::DoWhileSsa(self.lift_while_ssa(op)), + }; + HighLevelILLiftedInstruction { + function: self.function.clone(), + address: self.address, + kind, + } + } + + fn lift_operand(&self, expr_idx: usize) -> Box { + Box::new(self.function.lifted_instruction_from_idx(expr_idx)) + } + + fn lift_binary_op(&self, op: BinaryOp) -> LiftedBinaryOp { + LiftedBinaryOp { + left: self.lift_operand(op.left), + right: self.lift_operand(op.right), + } + } + + fn lift_binary_op_carry(&self, op: BinaryOpCarry) -> LiftedBinaryOpCarry { + LiftedBinaryOpCarry { + left: self.lift_operand(op.left), + right: self.lift_operand(op.right), + carry: self.lift_operand(op.carry), + } + } + + fn lift_unary_op(&self, op: UnaryOp) -> LiftedUnaryOp { + LiftedUnaryOp { + src: self.lift_operand(op.src), + } + } + + fn lift_label(&self, op: Label) -> LiftedLabel { + LiftedLabel { + target: GotoLabel { + function: self.function.get_function(), + target: op.target, + }, + } + } + + fn lift_call(&self, op: Call) -> LiftedCall { + LiftedCall { + dest: self.lift_operand(op.dest), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } + + fn lift_while(&self, op: While) -> LiftedWhile { + LiftedWhile { + condition: self.lift_operand(op.condition), + body: self.lift_operand(op.body), + } + } + + fn lift_while_ssa(&self, op: WhileSsa) -> LiftedWhileSsa { + LiftedWhileSsa { + condition_phi: self.lift_operand(op.condition_phi), + condition: self.lift_operand(op.condition), + body: self.lift_operand(op.body), + } + } + + fn lift_struct_field(&self, op: StructField) -> LiftedStructField { + LiftedStructField { + src: self.lift_operand(op.src), + offset: op.offset, + member_index: op.member_index, + } + } + + fn lift_instruction_list( + &self, + first_instruction: usize, + num_instructions: usize, + ) -> Vec { + OperandIter::new(&*self.function, first_instruction, num_instructions) + .exprs() + .map(|expr| expr.lift()) + .collect() + } +} + +impl core::fmt::Debug for HighLevelILInstruction { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + f, + "<{} at 0x{:08}>", + core::any::type_name::(), + self.address, + ) + } +} + +fn get_float(value: u64, size: usize) -> f64 { + match size { + 4 => f32::from_bits(value as u32) as f64, + 8 => f64::from_bits(value), + // TODO how to handle this value? + size => todo!("float size {}", size), + } +} + +fn get_var(id: u64) -> Variable { + unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } +} + +fn get_member_index(idx: u64) -> Option { + (idx as i64 > 0).then_some(idx as usize) +} + +fn get_var_ssa(input: (u64, usize)) -> SSAVariable { + SSAVariable::new(get_var(input.0), input.1) +} diff --git a/src/hlil/lift.rs b/src/hlil/lift.rs new file mode 100644 index 0000000..f8db34c --- /dev/null +++ b/src/hlil/lift.rs @@ -0,0 +1,325 @@ +use super::{operation::*, HighLevelILFunction}; + +use crate::rc::Ref; +use crate::types::{ConstantData, ILIntrinsic, SSAVariable, Variable}; + +#[derive(Clone)] +pub enum HighLevelILLiftedOperand { + ConstantData(ConstantData), + Expr(HighLevelILLiftedInstruction), + ExprList(Vec), + Float(f64), + Int(u64), + IntList(Vec), + Intrinsic(ILIntrinsic), + Label(GotoLabel), + MemberIndex(Option), + Var(Variable), + VarSsa(SSAVariable), + VarSsaList(Vec), +} + +#[derive(Clone, Debug, PartialEq)] +pub struct HighLevelILLiftedInstruction { + pub function: Ref, + pub address: u64, + pub kind: HighLevelILLiftedInstructionKind, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum HighLevelILLiftedInstructionKind { + Nop, + Break, + Continue, + Noret, + Unreachable, + Bp, + Undef, + Unimpl, + Adc(LiftedBinaryOpCarry), + Sbb(LiftedBinaryOpCarry), + Rlc(LiftedBinaryOpCarry), + Rrc(LiftedBinaryOpCarry), + Add(LiftedBinaryOp), + Sub(LiftedBinaryOp), + And(LiftedBinaryOp), + Or(LiftedBinaryOp), + Xor(LiftedBinaryOp), + Lsl(LiftedBinaryOp), + Lsr(LiftedBinaryOp), + Asr(LiftedBinaryOp), + Rol(LiftedBinaryOp), + Ror(LiftedBinaryOp), + Mul(LiftedBinaryOp), + MuluDp(LiftedBinaryOp), + MulsDp(LiftedBinaryOp), + Divu(LiftedBinaryOp), + DivuDp(LiftedBinaryOp), + Divs(LiftedBinaryOp), + DivsDp(LiftedBinaryOp), + Modu(LiftedBinaryOp), + ModuDp(LiftedBinaryOp), + Mods(LiftedBinaryOp), + ModsDp(LiftedBinaryOp), + CmpE(LiftedBinaryOp), + CmpNe(LiftedBinaryOp), + CmpSlt(LiftedBinaryOp), + CmpUlt(LiftedBinaryOp), + CmpSle(LiftedBinaryOp), + CmpUle(LiftedBinaryOp), + CmpSge(LiftedBinaryOp), + CmpUge(LiftedBinaryOp), + CmpSgt(LiftedBinaryOp), + CmpUgt(LiftedBinaryOp), + TestBit(LiftedBinaryOp), + AddOverflow(LiftedBinaryOp), + Fadd(LiftedBinaryOp), + Fsub(LiftedBinaryOp), + Fmul(LiftedBinaryOp), + Fdiv(LiftedBinaryOp), + FcmpE(LiftedBinaryOp), + FcmpNe(LiftedBinaryOp), + FcmpLt(LiftedBinaryOp), + FcmpLe(LiftedBinaryOp), + FcmpGe(LiftedBinaryOp), + FcmpGt(LiftedBinaryOp), + FcmpO(LiftedBinaryOp), + FcmpUo(LiftedBinaryOp), + ArrayIndex(LiftedArrayIndex), + ArrayIndexSsa(LiftedArrayIndexSsa), + Assign(LiftedAssign), + AssignMemSsa(LiftedAssignMemSsa), + AssignUnpack(LiftedAssignUnpack), + AssignUnpackMemSsa(LiftedAssignUnpackMemSsa), + Block(LiftedBlock), + Call(LiftedCall), + Tailcall(LiftedCall), + CallSsa(LiftedCallSsa), + Case(LiftedCase), + Const(Const), + ConstPtr(Const), + Import(Const), + ConstData(LiftedConstData), + Deref(LiftedUnaryOp), + AddressOf(LiftedUnaryOp), + Neg(LiftedUnaryOp), + Not(LiftedUnaryOp), + Sx(LiftedUnaryOp), + Zx(LiftedUnaryOp), + LowPart(LiftedUnaryOp), + BoolToInt(LiftedUnaryOp), + UnimplMem(LiftedUnaryOp), + Fsqrt(LiftedUnaryOp), + Fneg(LiftedUnaryOp), + Fabs(LiftedUnaryOp), + FloatToInt(LiftedUnaryOp), + IntToFloat(LiftedUnaryOp), + FloatConv(LiftedUnaryOp), + RoundToInt(LiftedUnaryOp), + Floor(LiftedUnaryOp), + Ceil(LiftedUnaryOp), + Ftrunc(LiftedUnaryOp), + DerefFieldSsa(LiftedDerefFieldSsa), + DerefSsa(LiftedDerefSsa), + ExternPtr(ExternPtr), + FloatConst(FloatConst), + For(LiftedForLoop), + ForSsa(LiftedForLoopSsa), + Goto(LiftedLabel), + Label(LiftedLabel), + If(LiftedIf), + Intrinsic(LiftedIntrinsic), + IntrinsicSsa(LiftedIntrinsicSsa), + Jump(LiftedJump), + MemPhi(LiftedMemPhi), + Ret(LiftedRet), + Split(LiftedSplit), + StructField(LiftedStructField), + DerefField(LiftedStructField), + Switch(LiftedSwitch), + Syscall(LiftedSyscall), + SyscallSsa(LiftedSyscallSsa), + Trap(Trap), + VarDeclare(Var), + Var(Var), + VarInit(LiftedVarInit), + VarInitSsa(LiftedVarInitSsa), + VarPhi(LiftedVarPhi), + VarSsa(VarSsa), + While(LiftedWhile), + DoWhile(LiftedWhile), + WhileSsa(LiftedWhileSsa), + DoWhileSsa(LiftedWhileSsa), +} + +impl HighLevelILLiftedInstruction { + pub fn operands(&self) -> Vec<(&'static str, HighLevelILLiftedOperand)> { + use HighLevelILLiftedInstructionKind::*; + use HighLevelILLiftedOperand as Operand; + match &self.kind { + Nop | Break | Continue | Noret | Unreachable | Bp | Undef | Unimpl => vec![], + Adc(op) | Sbb(op) | Rlc(op) | Rrc(op) => vec![ + ("left", Operand::Expr(*op.left.clone())), + ("right", Operand::Expr(*op.right.clone())), + ("carry", Operand::Expr(*op.carry.clone())), + ], + Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op) + | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op) + | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) | CmpE(op) + | CmpNe(op) | CmpSlt(op) | CmpUlt(op) | CmpSle(op) | CmpUle(op) | CmpSge(op) + | CmpUge(op) | CmpSgt(op) | CmpUgt(op) | TestBit(op) | AddOverflow(op) | Fadd(op) + | Fsub(op) | Fmul(op) | Fdiv(op) | FcmpE(op) | FcmpNe(op) | FcmpLt(op) | FcmpLe(op) + | FcmpGe(op) | FcmpGt(op) | FcmpO(op) | FcmpUo(op) => vec![ + ("left", Operand::Expr(*op.left.clone())), + ("right", Operand::Expr(*op.right.clone())), + ], + ArrayIndex(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("index", Operand::Expr(*op.index.clone())), + ], + ArrayIndexSsa(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ("index", Operand::Expr(*op.index.clone())), + ], + Assign(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("src", Operand::Expr(*op.src.clone())), + ], + AssignMemSsa(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src", Operand::Expr(*op.src.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + AssignUnpack(op) => vec![ + ("dest", Operand::ExprList(op.dest.clone())), + ("src", Operand::Expr(*op.src.clone())), + ], + AssignUnpackMemSsa(op) => vec![ + ("dest", Operand::ExprList(op.dest.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src", Operand::Expr(*op.src.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + Block(op) => vec![("body", Operand::ExprList(op.body.clone()))], + Call(op) | Tailcall(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ], + CallSsa(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ], + Case(op) => vec![ + ("values", Operand::ExprList(op.values.clone())), + ("body", Operand::Expr(*op.body.clone())), + ], + Const(op) | ConstPtr(op) | Import(op) => vec![("constant", Operand::Int(op.constant))], + ConstData(op) => vec![( + "constant_data", + Operand::ConstantData(op.constant_data.clone()), + )], + Deref(op) | AddressOf(op) | Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op) + | BoolToInt(op) | UnimplMem(op) | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op) + | IntToFloat(op) | FloatConv(op) | RoundToInt(op) | Floor(op) | Ceil(op) + | Ftrunc(op) => vec![("src", Operand::Expr(*op.src.clone()))], + DerefFieldSsa(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ("offset", Operand::Int(op.offset)), + ("member_index", Operand::MemberIndex(op.member_index)), + ], + DerefSsa(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + ExternPtr(op) => vec![ + ("constant", Operand::Int(op.constant)), + ("offset", Operand::Int(op.offset)), + ], + FloatConst(op) => vec![("constant", Operand::Float(op.constant))], + For(op) => vec![ + ("init", Operand::Expr(*op.init.clone())), + ("condition", Operand::Expr(*op.condition.clone())), + ("update", Operand::Expr(*op.update.clone())), + ("body", Operand::Expr(*op.body.clone())), + ], + ForSsa(op) => vec![ + ("init", Operand::Expr(*op.init.clone())), + ("condition_phi", Operand::Expr(*op.condition_phi.clone())), + ("condition", Operand::Expr(*op.condition.clone())), + ("update", Operand::Expr(*op.update.clone())), + ("body", Operand::Expr(*op.body.clone())), + ], + Goto(op) | Label(op) => vec![("target", Operand::Label(op.target.clone()))], + If(op) => vec![ + ("condition", Operand::Expr(*op.condition.clone())), + ("cond_true", Operand::Expr(*op.cond_true.clone())), + ("cond_false", Operand::Expr(*op.cond_false.clone())), + ], + Intrinsic(op) => vec![ + ("intrinsic", Operand::Intrinsic(op.intrinsic)), + ("params", Operand::ExprList(op.params.clone())), + ], + IntrinsicSsa(op) => vec![ + ("intrinsic", Operand::Intrinsic(op.intrinsic)), + ("params", Operand::ExprList(op.params.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ], + Jump(op) => vec![("dest", Operand::Expr(*op.dest.clone()))], + MemPhi(op) => vec![ + ("dest", Operand::Int(op.dest)), + ("src", Operand::IntList(op.src.clone())), + ], + Ret(op) => vec![("src", Operand::ExprList(op.src.clone()))], + Split(op) => vec![ + ("high", Operand::Expr(*op.high.clone())), + ("low", Operand::Expr(*op.low.clone())), + ], + StructField(op) | DerefField(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("offset", Operand::Int(op.offset)), + ("member_index", Operand::MemberIndex(op.member_index)), + ], + Switch(op) => vec![ + ("condition", Operand::Expr(*op.condition.clone())), + ("default", Operand::Expr(*op.default.clone())), + ("cases", Operand::ExprList(op.cases.clone())), + ], + Syscall(op) => vec![("params", Operand::ExprList(op.params.clone()))], + SyscallSsa(op) => vec![ + ("params", Operand::ExprList(op.params.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ], + Trap(op) => vec![("vector", Operand::Int(op.vector))], + VarDeclare(op) | Var(op) => vec![("var", Operand::Var(op.var))], + VarInit(op) => vec![ + ("dest", Operand::Var(op.dest)), + ("src", Operand::Expr(*op.src.clone())), + ], + VarInitSsa(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("src", Operand::Expr(*op.src.clone())), + ], + VarPhi(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("src", Operand::VarSsaList(op.src.clone())), + ], + VarSsa(op) => vec![("var", Operand::VarSsa(op.var))], + While(op) | DoWhile(op) => vec![ + ("condition", Operand::Expr(*op.condition.clone())), + ("body", Operand::Expr(*op.body.clone())), + ], + WhileSsa(op) | DoWhileSsa(op) => vec![ + ("condition_phi", Operand::Expr(*op.condition_phi.clone())), + ("condition", Operand::Expr(*op.condition.clone())), + ("body", Operand::Expr(*op.body.clone())), + ], + } + } +} diff --git a/src/hlil/mod.rs b/src/hlil/mod.rs new file mode 100644 index 0000000..8a9103a --- /dev/null +++ b/src/hlil/mod.rs @@ -0,0 +1,10 @@ +mod block; +mod function; +mod instruction; +mod lift; +pub mod operation; + +pub use self::block::*; +pub use self::function::*; +pub use self::instruction::*; +pub use self::lift::*; diff --git a/src/hlil/operation.rs b/src/hlil/operation.rs new file mode 100644 index 0000000..965d951 --- /dev/null +++ b/src/hlil/operation.rs @@ -0,0 +1,524 @@ +use binaryninjacore_sys::BNGetGotoLabelName; + +use crate::function::Function; +use crate::rc::Ref; +use crate::types::{ConstantData, ILIntrinsic, SSAVariable, Variable}; + +use super::HighLevelILLiftedInstruction; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct GotoLabel { + pub(crate) function: Ref, + pub(crate) target: u64, +} + +impl GotoLabel { + pub fn name(&self) -> &str { + let raw_str = unsafe { BNGetGotoLabelName(self.function.handle, self.target) }; + let c_str = unsafe { core::ffi::CStr::from_ptr(raw_str) }; + c_str.to_str().unwrap() + } +} + +// ADC, SBB, RLC, RRC +#[derive(Copy, Clone)] +pub struct BinaryOpCarry { + pub left: usize, + pub right: usize, + pub carry: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedBinaryOpCarry { + pub left: Box, + pub right: Box, + pub carry: Box, +} + +// ADD, SUB, AND, OR, XOR, LSL, LSR, ASR, ROL, ROR, MUL, MULU_DP, MULS_DP, DIVU, DIVU_DP, DIVS, DIVS_DP, MODU, MODU_DP, MODS, MODS_DP, CMP_E, CMP_NE, CMP_SLT, CMP_ULT, CMP_SLE, CMP_ULE, CMP_SGE, CMP_UGE, CMP_SGT, CMP_UGT, TEST_BIT, ADD_OVERFLOW, FADD, FSUB, FMUL, FDIV, FCMP_E, FCMP_NE, FCMP_LT, FCMP_LE, FCMP_GE, FCMP_GT, FCMP_O, FCMP_UO +#[derive(Copy, Clone)] +pub struct BinaryOp { + pub left: usize, + pub right: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedBinaryOp { + pub left: Box, + pub right: Box, +} + +// ARRAY_INDEX +#[derive(Copy, Clone)] +pub struct ArrayIndex { + pub src: usize, + pub index: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedArrayIndex { + pub src: Box, + pub index: Box, +} + +// ARRAY_INDEX_SSA +#[derive(Copy, Clone)] +pub struct ArrayIndexSsa { + pub src: usize, + pub src_memory: u64, + pub index: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedArrayIndexSsa { + pub src: Box, + pub src_memory: u64, + pub index: Box, +} + +// ASSIGN +#[derive(Copy, Clone)] +pub struct Assign { + pub dest: usize, + pub src: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedAssign { + pub dest: Box, + pub src: Box, +} + +// ASSIGN_MEM_SSA +#[derive(Copy, Clone)] +pub struct AssignMemSsa { + pub dest: usize, + pub dest_memory: u64, + pub src: usize, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedAssignMemSsa { + pub dest: Box, + pub dest_memory: u64, + pub src: Box, + pub src_memory: u64, +} + +// ASSIGN_UNPACK +#[derive(Copy, Clone)] +pub struct AssignUnpack { + pub first_dest: usize, + pub num_dests: usize, + pub src: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedAssignUnpack { + pub dest: Vec, + pub src: Box, +} + +// ASSIGN_UNPACK_MEM_SSA +#[derive(Copy, Clone)] +pub struct AssignUnpackMemSsa { + pub first_dest: usize, + pub num_dests: usize, + pub dest_memory: u64, + pub src: usize, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedAssignUnpackMemSsa { + pub dest: Vec, + pub dest_memory: u64, + pub src: Box, + pub src_memory: u64, +} + +// BLOCK +#[derive(Copy, Clone)] +pub struct Block { + pub first_param: usize, + pub num_params: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedBlock { + pub body: Vec, +} + +// CALL, TAILCALL +#[derive(Copy, Clone)] +pub struct Call { + pub dest: usize, + pub first_param: usize, + pub num_params: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCall { + pub dest: Box, + pub params: Vec, +} + +// CALL_SSA +#[derive(Copy, Clone)] +pub struct CallSsa { + pub dest: usize, + pub first_param: usize, + pub num_params: usize, + pub dest_memory: u64, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCallSsa { + pub dest: Box, + pub params: Vec, + pub dest_memory: u64, + pub src_memory: u64, +} + +// CASE +#[derive(Copy, Clone)] +pub struct Case { + pub first_value: usize, + pub num_values: usize, + pub body: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCase { + pub values: Vec, + pub body: Box, +} + +// CONST, CONST_PTR, IMPORT +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Const { + pub constant: u64, +} + +// CONST_DATA +#[derive(Copy, Clone)] +pub struct ConstData { + pub constant_data_kind: u32, + pub constant_data_value: i64, + pub size: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedConstData { + pub constant_data: ConstantData, +} + +// DEREF, ADDRESS_OF, NEG, NOT, SX, ZX, LOW_PART, BOOL_TO_INT, UNIMPL_MEM, FSQRT, FNEG, FABS, FLOAT_TO_INT, INT_TO_FLOAT, FLOAT_CONV, ROUND_TO_INT, FLOOR, CEIL, FTRUNC +#[derive(Copy, Clone)] +pub struct UnaryOp { + pub src: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedUnaryOp { + pub src: Box, +} + +// DEREF_FIELD_SSA +#[derive(Copy, Clone)] +pub struct DerefFieldSsa { + pub src: usize, + pub src_memory: u64, + pub offset: u64, + pub member_index: Option, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedDerefFieldSsa { + pub src: Box, + pub src_memory: u64, + pub offset: u64, + pub member_index: Option, +} + +// DEREF_SSA +#[derive(Copy, Clone)] +pub struct DerefSsa { + pub src: usize, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedDerefSsa { + pub src: Box, + pub src_memory: u64, +} + +// EXTERN_PTR +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ExternPtr { + pub constant: u64, + pub offset: u64, +} + +// FLOAT_CONST +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct FloatConst { + pub constant: f64, +} + +// FOR +#[derive(Copy, Clone)] +pub struct ForLoop { + pub init: usize, + pub condition: usize, + pub update: usize, + pub body: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedForLoop { + pub init: Box, + pub condition: Box, + pub update: Box, + pub body: Box, +} + +// FOR_SSA +#[derive(Copy, Clone)] +pub struct ForLoopSsa { + pub init: usize, + pub condition_phi: usize, + pub condition: usize, + pub update: usize, + pub body: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedForLoopSsa { + pub init: Box, + pub condition_phi: Box, + pub condition: Box, + pub update: Box, + pub body: Box, +} + +// GOTO, LABEL +#[derive(Copy, Clone)] +pub struct Label { + pub target: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedLabel { + pub target: GotoLabel, +} + +// IF +#[derive(Copy, Clone)] +pub struct If { + pub condition: usize, + pub cond_true: usize, + pub cond_false: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedIf { + pub condition: Box, + pub cond_true: Box, + pub cond_false: Box, +} + +// INTRINSIC +#[derive(Copy, Clone)] +pub struct Intrinsic { + pub intrinsic: u32, + pub first_param: usize, + pub num_params: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedIntrinsic { + pub intrinsic: ILIntrinsic, + pub params: Vec, +} + +// INTRINSIC_SSA +#[derive(Copy, Clone)] +pub struct IntrinsicSsa { + pub intrinsic: u32, + pub first_param: usize, + pub num_params: usize, + pub dest_memory: u64, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedIntrinsicSsa { + pub intrinsic: ILIntrinsic, + pub params: Vec, + pub dest_memory: u64, + pub src_memory: u64, +} + +// JUMP +#[derive(Copy, Clone)] +pub struct Jump { + pub dest: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedJump { + pub dest: Box, +} + +// MEM_PHI +#[derive(Copy, Clone)] +pub struct MemPhi { + pub dest: u64, + pub first_src: usize, + pub num_srcs: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedMemPhi { + pub dest: u64, + pub src: Vec, +} + +// RET +#[derive(Copy, Clone)] +pub struct Ret { + pub first_src: usize, + pub num_srcs: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedRet { + pub src: Vec, +} + +// SPLIT +#[derive(Copy, Clone)] +pub struct Split { + pub high: usize, + pub low: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedSplit { + pub high: Box, + pub low: Box, +} + +// STRUCT_FIELD, DEREF_FIELD +#[derive(Copy, Clone)] +pub struct StructField { + pub src: usize, + pub offset: u64, + pub member_index: Option, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedStructField { + pub src: Box, + pub offset: u64, + pub member_index: Option, +} + +// SWITCH +#[derive(Copy, Clone)] +pub struct Switch { + pub condition: usize, + pub default: usize, + pub first_case: usize, + pub num_cases: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedSwitch { + pub condition: Box, + pub default: Box, + pub cases: Vec, +} + +// SYSCALL +#[derive(Copy, Clone)] +pub struct Syscall { + pub first_param: usize, + pub num_params: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedSyscall { + pub params: Vec, +} + +// SYSCALL_SSA +#[derive(Copy, Clone)] +pub struct SyscallSsa { + pub first_param: usize, + pub num_params: usize, + pub dest_memory: u64, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedSyscallSsa { + pub params: Vec, + pub dest_memory: u64, + pub src_memory: u64, +} + +// TRAP +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Trap { + pub vector: u64, +} + +// VAR_DECLARE, VAR +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Var { + pub var: Variable, +} + +// VAR_INIT +#[derive(Copy, Clone)] +pub struct VarInit { + pub dest: Variable, + pub src: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedVarInit { + pub dest: Variable, + pub src: Box, +} + +// VAR_INIT_SSA +#[derive(Copy, Clone)] +pub struct VarInitSsa { + pub dest: SSAVariable, + pub src: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedVarInitSsa { + pub dest: SSAVariable, + pub src: Box, +} + +// VAR_PHI +#[derive(Copy, Clone)] +pub struct VarPhi { + pub dest: SSAVariable, + pub first_src: usize, + pub num_srcs: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedVarPhi { + pub dest: SSAVariable, + pub src: Vec, +} + +// VAR_SSA +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct VarSsa { + pub var: SSAVariable, +} + +// WHILE, DO_WHILE +#[derive(Copy, Clone)] +pub struct While { + pub condition: usize, + pub body: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedWhile { + pub condition: Box, + pub body: Box, +} + +// WHILE_SSA, DO_WHILE_SSA +#[derive(Copy, Clone)] +pub struct WhileSsa { + pub condition_phi: usize, + pub condition: usize, + pub body: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedWhileSsa { + pub condition_phi: Box, + pub condition: Box, + pub body: Box, +} diff --git a/src/lib.rs b/src/lib.rs index fa33439..0d38574 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ //! //! > ⚠️ **These bindings are in a very early beta, only have partial support for the core APIs and are still actively under development. Compatibility _will_ break and conventions _will_ change! They are being used for core Binary Ninja features however, so we expect much of what is already there to be reliable enough to build on, just don't be surprised if your plugins/scripts need to hit a moving target.** //! -//! > ⚠️ This project runs on Rust version `stable-2022-12-15` +//! > ⚠️ This project runs on Rust version `1.77.0` //! //! --- //! @@ -124,6 +124,7 @@ extern crate rayon; #[macro_use] mod ffi; +mod operand_iter; pub mod architecture; pub mod backgroundtask; @@ -145,6 +146,7 @@ pub mod flowgraph; pub mod function; pub mod functionrecognizer; pub mod headless; +pub mod hlil; pub mod interaction; pub mod linearview; pub mod llil; @@ -230,16 +232,18 @@ pub fn load_with_options( ) -> Option> { let filename = filename.into_bytes_with_nul(); + let options_or_default = if let Some(opt) = options { + opt + } else { + Metadata::new_of_type(MetadataType::KeyValueDataType) + }; + let handle = unsafe { binaryninjacore_sys::BNLoadFilename( filename.as_ref().as_ptr() as *mut _, update_analysis_and_wait, None, - if let Some(options) = options { - options.as_ref().handle - } else { - Metadata::new_of_type(MetadataType::KeyValueDataType).handle - }, + options_or_default.as_ref().handle, ) }; diff --git a/src/linearview.rs b/src/linearview.rs index 82094f6..09968fc 100644 --- a/src/linearview.rs +++ b/src/linearview.rs @@ -330,11 +330,7 @@ impl PartialEq for LinearViewCursor { impl PartialOrd for LinearViewCursor { fn partial_cmp(&self, other: &Self) -> Option { - match unsafe { BNCompareLinearViewCursors(self.handle, other.handle) } { - i if i < 0 => Some(std::cmp::Ordering::Less), - i if i > 0 => Some(std::cmp::Ordering::Greater), - _ => Some(std::cmp::Ordering::Equal), - } + Some(self.cmp(other)) } } diff --git a/src/llil/function.rs b/src/llil/function.rs index 46d3e6d..8f1eac6 100644 --- a/src/llil/function.rs +++ b/src/llil/function.rs @@ -13,12 +13,14 @@ // limitations under the License. use binaryninjacore_sys::BNFreeLowLevelILFunction; +use binaryninjacore_sys::BNGetLowLevelILOwnerFunction; use binaryninjacore_sys::BNLowLevelILFunction; use binaryninjacore_sys::BNNewLowLevelILFunctionReference; use std::borrow::Borrow; use std::marker::PhantomData; +use crate::architecture::CoreArchitecture; use crate::basicblock::BasicBlock; use crate::rc::*; @@ -65,14 +67,14 @@ unsafe impl Sync for Fu impl Eq for Function {} impl PartialEq for Function { fn eq(&self, rhs: &Self) -> bool { - self.handle == rhs.handle + self.get_function().eq(&rhs.get_function()) } } use std::hash::{Hash, Hasher}; impl Hash for Function { fn hash(&self, state: &mut H) { - self.handle.hash(state); + self.get_function().hash(state) } } @@ -82,7 +84,10 @@ where M: FunctionMutability, F: FunctionForm, { - pub(crate) unsafe fn from_raw(borrower: A::Handle, handle: *mut BNLowLevelILFunction) -> Self { + pub(crate) unsafe fn from_raw( + borrower: A::Handle, + handle: *mut BNLowLevelILFunction, + ) -> Ref { debug_assert!(!handle.is_null()); Self { @@ -92,6 +97,7 @@ where _mutability: PhantomData, _form: PhantomData, } + .to_owned() } pub(crate) fn arch(&self) -> &A { @@ -139,6 +145,13 @@ where BNGetLowLevelILInstructionCount(self.handle) } } + + pub fn get_function(&self) -> Ref { + unsafe { + let func = BNGetLowLevelILOwnerFunction(self.handle); + crate::function::Function::from_raw(func) + } + } } // LLIL basic blocks are not available until the function object @@ -162,6 +175,37 @@ where } } +// Allow instantiating Lifted IL functions for querying Lifted IL from Architectures +impl Function> { + pub fn new( + arch: CoreArchitecture, + source_func: Option, + ) -> Result, ()> { + use binaryninjacore_sys::BNCreateLowLevelILFunction; + use std::ptr::null_mut; + + let handle = unsafe { + match source_func { + Some(func) => BNCreateLowLevelILFunction(arch.0, func.handle), + None => BNCreateLowLevelILFunction(arch.0, null_mut()), + } + }; + if handle.is_null() { + return Err(()); + } + + Ok(unsafe { + Ref::new(Self { + borrower: arch, + handle, + _arch: PhantomData, + _mutability: PhantomData, + _form: PhantomData, + }) + }) + } +} + impl<'func, A, M, F> ToOwned for Function where A: 'func + Architecture, diff --git a/src/llil/instruction.rs b/src/llil/instruction.rs index 9f2ad9b..469c10f 100644 --- a/src/llil/instruction.rs +++ b/src/llil/instruction.rs @@ -95,6 +95,13 @@ where M: FunctionMutability, V: NonSSAVariant, { + pub fn address(&self) -> u64 { + let expr_idx = + unsafe { BNGetLowLevelILIndexForInstruction(self.function.handle, self.instr_idx) }; + let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, expr_idx) }; + return op.address; + } + pub fn info(&self) -> InstrInfo<'func, A, M, NonSSA> { use binaryninjacore_sys::BNLowLevelILOperation::*; diff --git a/src/mlil/block.rs b/src/mlil/block.rs index 734d651..015c7ba 100644 --- a/src/mlil/block.rs +++ b/src/mlil/block.rs @@ -21,7 +21,7 @@ impl Iterator for MediumLevelILBlockIter { .map(|i| unsafe { BNGetMediumLevelILIndexForInstruction(self.function.handle, i as usize) }) - .map(|i| MediumLevelILInstruction::new(&self.function, i)) + .map(|i| MediumLevelILInstruction::new(self.function.to_owned(), i)) } } @@ -43,7 +43,7 @@ impl BlockContext for MediumLevelILBlock { let expr_idx = unsafe { BNGetMediumLevelILIndexForInstruction(self.function.handle, block.raw_start() as usize) }; - MediumLevelILInstruction::new(&self.function, expr_idx) + MediumLevelILInstruction::new(self.function.to_owned(), expr_idx) } fn iter(&self, block: &BasicBlock) -> MediumLevelILBlockIter { diff --git a/src/mlil/function.rs b/src/mlil/function.rs index 63c63a3..16cc510 100644 --- a/src/mlil/function.rs +++ b/src/mlil/function.rs @@ -14,7 +14,7 @@ use crate::function::Function; use crate::function::Location; use crate::rc::{Array, Ref, RefCountable}; -use super::{MediumLevelILBlock, MediumLevelILInstruction}; +use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction}; pub struct MediumLevelILFunction { pub(crate) handle: *mut BNMediumLevelILFunction, @@ -26,21 +26,21 @@ unsafe impl Sync for MediumLevelILFunction {} impl Eq for MediumLevelILFunction {} impl PartialEq for MediumLevelILFunction { fn eq(&self, rhs: &Self) -> bool { - self.handle == rhs.handle + self.get_function().eq(&rhs.get_function()) } } impl Hash for MediumLevelILFunction { fn hash(&self, state: &mut H) { - self.handle.hash(state); + self.get_function().hash(state) } } impl MediumLevelILFunction { - pub(crate) unsafe fn from_raw(handle: *mut BNMediumLevelILFunction) -> Self { + pub(crate) unsafe fn ref_from_raw(handle: *mut BNMediumLevelILFunction) -> Ref { debug_assert!(!handle.is_null()); - Self { handle } + Self { handle }.to_owned() } pub fn instruction_at>(&self, loc: L) -> Option { @@ -53,12 +53,16 @@ impl MediumLevelILFunction { if expr_idx >= self.instruction_count() { None } else { - Some(MediumLevelILInstruction::new(self, expr_idx)) + Some(MediumLevelILInstruction::new(self.to_owned(), expr_idx)) } } pub fn instruction_from_idx(&self, expr_idx: usize) -> MediumLevelILInstruction { - MediumLevelILInstruction::new(self, expr_idx) + MediumLevelILInstruction::new(self.to_owned(), expr_idx) + } + + pub fn lifted_instruction_from_idx(&self, expr_idx: usize) -> MediumLevelILLiftedInstruction { + self.instruction_from_idx(expr_idx).lift() } pub fn instruction_count(&self) -> usize { diff --git a/src/mlil/instruction.rs b/src/mlil/instruction.rs index 139abe2..e457c93 100644 --- a/src/mlil/instruction.rs +++ b/src/mlil/instruction.rs @@ -1,26 +1,32 @@ +use binaryninjacore_sys::BNFromVariableIdentifier; use binaryninjacore_sys::BNGetMediumLevelILByIndex; +use binaryninjacore_sys::BNMediumLevelILInstruction; use binaryninjacore_sys::BNMediumLevelILOperation; -use crate::mlil::MediumLevelILLiftedOperation; +use crate::operand_iter::OperandIter; use crate::rc::Ref; +use crate::types::{ + ConstantData, ILIntrinsic, RegisterValue, RegisterValueType, SSAVariable, Variable, +}; +use super::lift::*; use super::operation::*; -use super::{MediumLevelILFunction, MediumLevelILLiftedInstruction}; +use super::MediumLevelILFunction; #[derive(Clone)] pub struct MediumLevelILInstruction { - pub(crate) function: Ref, - pub(crate) address: u64, - pub(crate) operation: MediumLevelILOperation, + pub function: Ref, + pub address: u64, + pub kind: MediumLevelILInstructionKind, } #[derive(Copy, Clone)] -pub enum MediumLevelILOperation { - Nop(NoArgs), - Noret(NoArgs), - Bp(NoArgs), - Undef(NoArgs), - Unimpl(NoArgs), +pub enum MediumLevelILInstructionKind { + Nop, + Noret, + Bp, + Undef, + Unimpl, If(MediumLevelILOperationIf), FloatConst(FloatConst), Const(Constant), @@ -160,584 +166,845 @@ impl core::fmt::Debug for MediumLevelILInstruction { } impl MediumLevelILInstruction { - pub(crate) fn new(function: &MediumLevelILFunction, idx: usize) -> Self { + pub(crate) fn new(function: Ref, idx: usize) -> Self { let op = unsafe { BNGetMediumLevelILByIndex(function.handle, idx) }; use BNMediumLevelILOperation::*; - use MediumLevelILOperation as Op; - let info = match op.operation { - MLIL_NOP => Op::Nop(NoArgs::default()), - MLIL_NORET => Op::Noret(NoArgs::default()), - MLIL_BP => Op::Bp(NoArgs::default()), - MLIL_UNDEF => Op::Undef(NoArgs::default()), - MLIL_UNIMPL => Op::Unimpl(NoArgs::default()), - MLIL_IF => Op::If(MediumLevelILOperationIf::new( - op.operands[0] as usize, - op.operands[1], - op.operands[2], - )), - MLIL_FLOAT_CONST => Op::FloatConst(FloatConst::new(op.operands[0], op.size)), - MLIL_CONST => Op::Const(Constant::new(op.operands[0])), - MLIL_CONST_PTR => Op::ConstPtr(Constant::new(op.operands[0])), - MLIL_IMPORT => Op::Import(Constant::new(op.operands[0])), - MLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr::new(op.operands[0], op.operands[1])), - MLIL_CONST_DATA => Op::ConstData(ConstData::new((op.operands[0], op.operands[1]))), - MLIL_JUMP => Op::Jump(Jump::new(op.operands[0] as usize)), - MLIL_RET_HINT => Op::RetHint(Jump::new(op.operands[0] as usize)), - MLIL_STORE_SSA => Op::StoreSsa(StoreSsa::new( - op.operands[0] as usize, - op.operands[1], - op.operands[2], - op.operands[3] as usize, - )), - MLIL_STORE_STRUCT_SSA => Op::StoreStructSsa(StoreStructSsa::new( - op.operands[0] as usize, - op.operands[1], - op.operands[2], - op.operands[3], - op.operands[4] as usize, - )), - MLIL_STORE_STRUCT => Op::StoreStruct(StoreStruct::new( - op.operands[0] as usize, - op.operands[1], - op.operands[2] as usize, - )), - MLIL_STORE => Op::Store(Store::new(op.operands[0] as usize, op.operands[1] as usize)), - MLIL_JUMP_TO => Op::JumpTo(JumpTo::new( - op.operands[0] as usize, - (op.operands[1] as usize, op.operands[2] as usize), - )), - MLIL_GOTO => Op::Goto(Goto::new(op.operands[0])), - MLIL_FREE_VAR_SLOT => Op::FreeVarSlot(FreeVarSlot::new(op.operands[0])), - MLIL_SET_VAR_FIELD => Op::SetVarField(SetVarField::new( - op.operands[0], - op.operands[1], - op.operands[2] as usize, - )), - MLIL_SET_VAR => Op::SetVar(SetVar::new(op.operands[0], op.operands[1] as usize)), - MLIL_FREE_VAR_SLOT_SSA => Op::FreeVarSlotSsa(FreeVarSlotSsa::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[0], op.operands[2] as usize), - )), - MLIL_SET_VAR_SSA_FIELD => Op::SetVarSsaField(SetVarSsaField::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[0], op.operands[2] as usize), - op.operands[3], - op.operands[4] as usize, - )), - MLIL_SET_VAR_ALIASED_FIELD => Op::SetVarAliasedField(SetVarSsaField::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[0], op.operands[2] as usize), - op.operands[3], - op.operands[4] as usize, - )), - MLIL_SET_VAR_ALIASED => Op::SetVarAliased(SetVarAliased::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[0], op.operands[2] as usize), - op.operands[3] as usize, - )), - MLIL_SET_VAR_SSA => Op::SetVarSsa(SetVarSsa::new( - (op.operands[0], op.operands[1] as usize), - op.operands[2] as usize, - )), - MLIL_VAR_PHI => Op::VarPhi(VarPhi::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[2] as usize, op.operands[3] as usize), - )), - MLIL_MEM_PHI => Op::MemPhi(MemPhi::new( - op.operands[0], - (op.operands[1] as usize, op.operands[2] as usize), - )), - MLIL_VAR_SPLIT => Op::VarSplit(VarSplit::new(op.operands[0], op.operands[1])), - MLIL_SET_VAR_SPLIT => Op::SetVarSplit(SetVarSplit::new( - op.operands[0], - op.operands[1], - op.operands[2] as usize, - )), - MLIL_VAR_SPLIT_SSA => Op::VarSplitSsa(VarSplitSsa::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[2], op.operands[3] as usize), - )), - MLIL_SET_VAR_SPLIT_SSA => Op::SetVarSplitSsa(SetVarSplitSsa::new( - (op.operands[0], op.operands[1] as usize), - (op.operands[2], op.operands[3] as usize), - op.operands[4] as usize, - )), - MLIL_ADD => Op::Add(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_SUB => Op::Sub(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_AND => Op::And(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_OR => Op::Or(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_XOR => Op::Xor(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_LSL => Op::Lsl(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_LSR => Op::Lsr(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_ASR => Op::Asr(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_ROL => Op::Rol(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_ROR => Op::Ror(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MUL => Op::Mul(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MULU_DP => Op::MuluDp(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MULS_DP => Op::MulsDp(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_DIVU => Op::Divu(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_DIVU_DP => Op::DivuDp(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_DIVS => Op::Divs(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_DIVS_DP => Op::DivsDp(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MODU => Op::Modu(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MODU_DP => Op::ModuDp(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MODS => Op::Mods(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_MODS_DP => Op::ModsDp(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_E => Op::CmpE(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_NE => Op::CmpNe(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_SLT => Op::CmpSlt(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_ULT => Op::CmpUlt(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_SLE => Op::CmpSle(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_ULE => Op::CmpUle(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_SGE => Op::CmpSge(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_UGE => Op::CmpUge(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_SGT => Op::CmpSgt(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_CMP_UGT => Op::CmpUgt(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_TEST_BIT => Op::TestBit(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_E => Op::FcmpE(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_NE => Op::FcmpNe(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_LT => Op::FcmpLt(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_LE => Op::FcmpLe(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_GE => Op::FcmpGe(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_GT => Op::FcmpGt(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_O => Op::FcmpO(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FCMP_UO => Op::FcmpUo(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FADD => Op::Fadd(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FSUB => Op::Fsub(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FMUL => Op::Fmul(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_FDIV => Op::Fdiv(BinaryOp::new( - op.operands[0] as usize, - op.operands[1] as usize, - )), - MLIL_ADC => Op::Adc(BinaryOpCarry::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - )), - MLIL_SBB => Op::Sbb(BinaryOpCarry::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - )), - MLIL_RLC => Op::Rlc(BinaryOpCarry::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - )), - MLIL_RRC => Op::Rrc(BinaryOpCarry::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - )), - MLIL_CALL => Op::Call(Call::new( - (op.operands[0] as usize, op.operands[1] as usize), - op.operands[2] as usize, - (op.operands[3] as usize, op.operands[4] as usize), - )), - MLIL_TAILCALL => Op::Tailcall(Call::new( - (op.operands[0] as usize, op.operands[1] as usize), - op.operands[2] as usize, - (op.operands[3] as usize, op.operands[4] as usize), - )), - MLIL_SYSCALL => Op::Syscall(Syscall::new( - (op.operands[0] as usize, op.operands[1] as usize), - (op.operands[2] as usize, op.operands[3] as usize), - )), - MLIL_INTRINSIC => Op::Intrinsic(Intrinsic::new( - (op.operands[0] as usize, op.operands[1] as usize), - op.operands[2] as usize, - (op.operands[3] as usize, op.operands[4] as usize), - )), - MLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa::new( - (op.operands[0] as usize, op.operands[1] as usize), - op.operands[2] as usize, - (op.operands[3] as usize, op.operands[4] as usize), - )), - MLIL_CALL_SSA => Op::CallSsa(CallSsa::new( - op.operands[0] as usize, - op.operands[1] as usize, - (op.operands[2] as usize, op.operands[3] as usize), - op.operands[4], - )), - MLIL_TAILCALL_SSA => Op::TailcallSsa(CallSsa::new( - op.operands[0] as usize, - op.operands[1] as usize, - (op.operands[2] as usize, op.operands[3] as usize), - op.operands[4], - )), - MLIL_CALL_UNTYPED_SSA => Op::CallUntypedSsa(CallUntypedSsa::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - op.operands[3] as usize, - )), - MLIL_TAILCALL_UNTYPED_SSA => Op::TailcallUntypedSsa(CallUntypedSsa::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - op.operands[3] as usize, - )), - MLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa::new( - op.operands[0] as usize, - (op.operands[1] as usize, op.operands[2] as usize), - op.operands[3], - )), - MLIL_SYSCALL_UNTYPED_SSA => Op::SyscallUntypedSsa(SyscallUntypedSsa::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - )), - MLIL_CALL_UNTYPED => Op::CallUntyped(CallUntyped::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - op.operands[3] as usize, - )), - MLIL_TAILCALL_UNTYPED => Op::TailcallUntyped(CallUntyped::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - op.operands[3] as usize, - )), - MLIL_SYSCALL_UNTYPED => Op::SyscallUntyped(SyscallUntyped::new( - op.operands[0] as usize, - op.operands[1] as usize, - op.operands[2] as usize, - )), - MLIL_SEPARATE_PARAM_LIST => Op::SeparateParamList(SeparateParamList::new( - (op.operands[0] as usize, op.operands[1] as usize) - )), - MLIL_SHARED_PARAM_SLOT => Op::SharedParamSlot(SharedParamSlot::new( - (op.operands[0] as usize, op.operands[1] as usize) - )), - MLIL_NEG => Op::Neg(UnaryOp::new(op.operands[0] as usize)), - MLIL_NOT => Op::Not(UnaryOp::new(op.operands[0] as usize)), - MLIL_SX => Op::Sx(UnaryOp::new(op.operands[0] as usize)), - MLIL_ZX => Op::Zx(UnaryOp::new(op.operands[0] as usize)), - MLIL_LOW_PART => Op::LowPart(UnaryOp::new(op.operands[0] as usize)), - MLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp::new(op.operands[0] as usize)), - MLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp::new(op.operands[0] as usize)), - MLIL_FSQRT => Op::Fsqrt(UnaryOp::new(op.operands[0] as usize)), - MLIL_FNEG => Op::Fneg(UnaryOp::new(op.operands[0] as usize)), - MLIL_FABS => Op::Fabs(UnaryOp::new(op.operands[0] as usize)), - MLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp::new(op.operands[0] as usize)), - MLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp::new(op.operands[0] as usize)), - MLIL_FLOAT_CONV => Op::FloatConv(UnaryOp::new(op.operands[0] as usize)), - MLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp::new(op.operands[0] as usize)), - MLIL_FLOOR => Op::Floor(UnaryOp::new(op.operands[0] as usize)), - MLIL_CEIL => Op::Ceil(UnaryOp::new(op.operands[0] as usize)), - MLIL_FTRUNC => Op::Ftrunc(UnaryOp::new(op.operands[0] as usize)), - MLIL_LOAD => Op::Load(UnaryOp::new(op.operands[0] as usize)), - MLIL_LOAD_STRUCT => { - Op::LoadStruct(LoadStruct::new(op.operands[0] as usize, op.operands[1])) - } - MLIL_LOAD_STRUCT_SSA => Op::LoadStructSsa(LoadStructSsa::new( - op.operands[0] as usize, - op.operands[1], - op.operands[2], - )), - MLIL_LOAD_SSA => Op::LoadSsa(LoadSsa::new(op.operands[0] as usize, op.operands[1])), - MLIL_RET => Op::Ret(Ret::new((op.operands[0] as usize, op.operands[1] as usize))), - MLIL_VAR => Op::Var(Var::new(op.operands[0])), - MLIL_ADDRESS_OF => Op::AddressOf(Var::new(op.operands[0])), - MLIL_VAR_FIELD => Op::VarField(Field::new(op.operands[0], op.operands[1])), - MLIL_ADDRESS_OF_FIELD => Op::AddressOfField(Field::new(op.operands[0], op.operands[1])), - MLIL_VAR_SSA => Op::VarSsa(VarSsa::new((op.operands[0], op.operands[1] as usize))), - MLIL_VAR_ALIASED => { - Op::VarAliased(VarSsa::new((op.operands[0], op.operands[1] as usize))) - } - MLIL_VAR_SSA_FIELD => Op::VarSsaField(VarSsaField::new( - (op.operands[0], op.operands[1] as usize), - op.operands[2], - )), - MLIL_VAR_ALIASED_FIELD => Op::VarAliasedField(VarSsaField::new( - (op.operands[0], op.operands[1] as usize), - op.operands[2], - )), - MLIL_TRAP => Op::Trap(Trap::new(op.operands[0])), + use MediumLevelILInstructionKind as Op; + let kind = match op.operation { + MLIL_NOP => Op::Nop, + MLIL_NORET => Op::Noret, + MLIL_BP => Op::Bp, + MLIL_UNDEF => Op::Undef, + MLIL_UNIMPL => Op::Unimpl, + MLIL_IF => Op::If(MediumLevelILOperationIf { + condition: op.operands[0] as usize, + dest_true: op.operands[1], + dest_false: op.operands[2], + }), + MLIL_FLOAT_CONST => Op::FloatConst(FloatConst { + constant: get_float(op.operands[0], op.size), + }), + MLIL_CONST => Op::Const(Constant { + constant: op.operands[0], + }), + MLIL_CONST_PTR => Op::ConstPtr(Constant { + constant: op.operands[0], + }), + MLIL_IMPORT => Op::Import(Constant { + constant: op.operands[0], + }), + MLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr { + constant: op.operands[0], + offset: op.operands[1], + }), + MLIL_CONST_DATA => Op::ConstData(ConstData { + constant_data_kind: op.operands[0] as u32, + constant_data_value: op.operands[1] as i64, + size: op.size, + }), + MLIL_JUMP => Op::Jump(Jump { + dest: op.operands[0] as usize, + }), + MLIL_RET_HINT => Op::RetHint(Jump { + dest: op.operands[0] as usize, + }), + MLIL_STORE_SSA => Op::StoreSsa(StoreSsa { + dest: op.operands[0] as usize, + dest_memory: op.operands[1], + src_memory: op.operands[2], + src: op.operands[3] as usize, + }), + MLIL_STORE_STRUCT_SSA => Op::StoreStructSsa(StoreStructSsa { + dest: op.operands[0] as usize, + offset: op.operands[1], + dest_memory: op.operands[2], + src_memory: op.operands[3], + src: op.operands[4] as usize, + }), + MLIL_STORE_STRUCT => Op::StoreStruct(StoreStruct { + dest: op.operands[0] as usize, + offset: op.operands[1], + src: op.operands[2] as usize, + }), + MLIL_STORE => Op::Store(Store { + dest: op.operands[0] as usize, + src: op.operands[1] as usize, + }), + MLIL_JUMP_TO => Op::JumpTo(JumpTo { + dest: op.operands[0] as usize, + num_operands: op.operands[1] as usize, + first_operand: op.operands[2] as usize, + }), + MLIL_GOTO => Op::Goto(Goto { + dest: op.operands[0], + }), + MLIL_FREE_VAR_SLOT => Op::FreeVarSlot(FreeVarSlot { + dest: get_var(op.operands[0]), + }), + MLIL_SET_VAR_FIELD => Op::SetVarField(SetVarField { + dest: get_var(op.operands[0]), + offset: op.operands[1], + src: op.operands[2] as usize, + }), + MLIL_SET_VAR => Op::SetVar(SetVar { + dest: get_var(op.operands[0]), + src: op.operands[1] as usize, + }), + MLIL_FREE_VAR_SLOT_SSA => Op::FreeVarSlotSsa(FreeVarSlotSsa { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + }), + MLIL_SET_VAR_SSA_FIELD => Op::SetVarSsaField(SetVarSsaField { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + offset: op.operands[3], + src: op.operands[4] as usize, + }), + MLIL_SET_VAR_ALIASED_FIELD => Op::SetVarAliasedField(SetVarSsaField { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + offset: op.operands[3], + src: op.operands[4] as usize, + }), + MLIL_SET_VAR_ALIASED => Op::SetVarAliased(SetVarAliased { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + src: op.operands[3] as usize, + }), + MLIL_SET_VAR_SSA => Op::SetVarSsa(SetVarSsa { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + src: op.operands[2] as usize, + }), + MLIL_VAR_PHI => Op::VarPhi(VarPhi { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + num_operands: op.operands[2] as usize, + first_operand: op.operands[3] as usize, + }), + MLIL_MEM_PHI => Op::MemPhi(MemPhi { + dest_memory: op.operands[0], + num_operands: op.operands[1] as usize, + first_operand: op.operands[2] as usize, + }), + MLIL_VAR_SPLIT => Op::VarSplit(VarSplit { + high: get_var(op.operands[0]), + low: get_var(op.operands[1]), + }), + MLIL_SET_VAR_SPLIT => Op::SetVarSplit(SetVarSplit { + high: get_var(op.operands[0]), + low: get_var(op.operands[1]), + src: op.operands[2] as usize, + }), + MLIL_VAR_SPLIT_SSA => Op::VarSplitSsa(VarSplitSsa { + high: get_var_ssa(op.operands[0], op.operands[1] as usize), + low: get_var_ssa(op.operands[2], op.operands[3] as usize), + }), + MLIL_SET_VAR_SPLIT_SSA => Op::SetVarSplitSsa(SetVarSplitSsa { + high: get_var_ssa(op.operands[0], op.operands[1] as usize), + low: get_var_ssa(op.operands[2], op.operands[3] as usize), + src: op.operands[4] as usize, + }), + MLIL_ADD => Op::Add(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_SUB => Op::Sub(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_AND => Op::And(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_OR => Op::Or(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_XOR => Op::Xor(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_LSL => Op::Lsl(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_LSR => Op::Lsr(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ASR => Op::Asr(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ROL => Op::Rol(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ROR => Op::Ror(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MUL => Op::Mul(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MULU_DP => Op::MuluDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MULS_DP => Op::MulsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVU => Op::Divu(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVU_DP => Op::DivuDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVS => Op::Divs(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVS_DP => Op::DivsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODU => Op::Modu(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODU_DP => Op::ModuDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODS => Op::Mods(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODS_DP => Op::ModsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_E => Op::CmpE(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_NE => Op::CmpNe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SLT => Op::CmpSlt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_ULT => Op::CmpUlt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SLE => Op::CmpSle(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_ULE => Op::CmpUle(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SGE => Op::CmpSge(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_UGE => Op::CmpUge(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SGT => Op::CmpSgt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_UGT => Op::CmpUgt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_TEST_BIT => Op::TestBit(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_E => Op::FcmpE(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_NE => Op::FcmpNe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_LT => Op::FcmpLt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_LE => Op::FcmpLe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_GE => Op::FcmpGe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_GT => Op::FcmpGt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_O => Op::FcmpO(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_UO => Op::FcmpUo(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FADD => Op::Fadd(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FSUB => Op::Fsub(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FMUL => Op::Fmul(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FDIV => Op::Fdiv(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ADC => Op::Adc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_SBB => Op::Sbb(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_RLC => Op::Rlc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_RRC => Op::Rrc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_CALL => Op::Call(Call { + num_outputs: op.operands[0] as usize, + first_output: op.operands[1] as usize, + dest: op.operands[2] as usize, + num_params: op.operands[3] as usize, + first_param: op.operands[4] as usize, + }), + MLIL_TAILCALL => Op::Tailcall(Call { + num_outputs: op.operands[0] as usize, + first_output: op.operands[1] as usize, + dest: op.operands[2] as usize, + num_params: op.operands[3] as usize, + first_param: op.operands[4] as usize, + }), + MLIL_SYSCALL => Op::Syscall(Syscall { + num_outputs: op.operands[0] as usize, + first_output: op.operands[1] as usize, + num_params: op.operands[2] as usize, + first_param: op.operands[3] as usize, + }), + MLIL_INTRINSIC => Op::Intrinsic(Intrinsic { + num_outputs: op.operands[0] as usize, + first_output: op.operands[1] as usize, + intrinsic: op.operands[2] as u32, + num_params: op.operands[3] as usize, + first_param: op.operands[4] as usize, + }), + MLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa { + num_outputs: op.operands[0] as usize, + first_output: op.operands[1] as usize, + intrinsic: op.operands[2] as u32, + num_params: op.operands[3] as usize, + first_param: op.operands[4] as usize, + }), + MLIL_CALL_SSA => Op::CallSsa(CallSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + num_params: op.operands[2] as usize, + first_param: op.operands[3] as usize, + src_memory: op.operands[4], + }), + MLIL_TAILCALL_SSA => Op::TailcallSsa(CallSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + num_params: op.operands[2] as usize, + first_param: op.operands[3] as usize, + src_memory: op.operands[4], + }), + MLIL_CALL_UNTYPED_SSA => Op::CallUntypedSsa(CallUntypedSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + params: op.operands[2] as usize, + stack: op.operands[3] as usize, + }), + MLIL_TAILCALL_UNTYPED_SSA => Op::TailcallUntypedSsa(CallUntypedSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + params: op.operands[2] as usize, + stack: op.operands[3] as usize, + }), + MLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa { + output: op.operands[0] as usize, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + src_memory: op.operands[3], + }), + MLIL_SYSCALL_UNTYPED_SSA => Op::SyscallUntypedSsa(SyscallUntypedSsa { + output: op.operands[0] as usize, + params: op.operands[1] as usize, + stack: op.operands[2] as usize, + }), + MLIL_CALL_UNTYPED => Op::CallUntyped(CallUntyped { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + params: op.operands[2] as usize, + stack: op.operands[3] as usize, + }), + MLIL_TAILCALL_UNTYPED => Op::TailcallUntyped(CallUntyped { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + params: op.operands[2] as usize, + stack: op.operands[3] as usize, + }), + MLIL_SYSCALL_UNTYPED => Op::SyscallUntyped(SyscallUntyped { + output: op.operands[0] as usize, + params: op.operands[1] as usize, + stack: op.operands[2] as usize, + }), + MLIL_NEG => Op::Neg(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_NOT => Op::Not(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_SX => Op::Sx(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_ZX => Op::Zx(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_LOW_PART => Op::LowPart(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FSQRT => Op::Fsqrt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FNEG => Op::Fneg(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FABS => Op::Fabs(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FLOAT_CONV => Op::FloatConv(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FLOOR => Op::Floor(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_CEIL => Op::Ceil(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FTRUNC => Op::Ftrunc(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_LOAD => Op::Load(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_LOAD_STRUCT => Op::LoadStruct(LoadStruct { + src: op.operands[0] as usize, + offset: op.operands[1], + }), + MLIL_LOAD_STRUCT_SSA => Op::LoadStructSsa(LoadStructSsa { + src: op.operands[0] as usize, + offset: op.operands[1], + src_memory: op.operands[2], + }), + MLIL_LOAD_SSA => Op::LoadSsa(LoadSsa { + src: op.operands[0] as usize, + src_memory: op.operands[1], + }), + MLIL_RET => Op::Ret(Ret { + num_operands: op.operands[0] as usize, + first_operand: op.operands[1] as usize, + }), + MLIL_SEPARATE_PARAM_LIST => Op::SeparateParamList(SeparateParamList { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + }), + MLIL_SHARED_PARAM_SLOT => Op::SharedParamSlot(SharedParamSlot { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + }), + MLIL_VAR => Op::Var(Var { + src: get_var(op.operands[0]), + }), + MLIL_ADDRESS_OF => Op::AddressOf(Var { + src: get_var(op.operands[0]), + }), + MLIL_VAR_FIELD => Op::VarField(Field { + src: get_var(op.operands[0]), + offset: op.operands[1], + }), + MLIL_ADDRESS_OF_FIELD => Op::AddressOfField(Field { + src: get_var(op.operands[0]), + offset: op.operands[1], + }), + MLIL_VAR_SSA => Op::VarSsa(VarSsa { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + }), + MLIL_VAR_ALIASED => Op::VarAliased(VarSsa { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + }), + MLIL_VAR_SSA_FIELD => Op::VarSsaField(VarSsaField { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + offset: op.operands[2], + }), + MLIL_VAR_ALIASED_FIELD => Op::VarAliasedField(VarSsaField { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + offset: op.operands[2], + }), + MLIL_TRAP => Op::Trap(Trap { + vector: op.operands[0], + }), // translated directly into a list for Expression or Variables - MLIL_CALL_OUTPUT | MLIL_CALL_PARAM | MLIL_CALL_PARAM_SSA | MLIL_CALL_OUTPUT_SSA => { + // TODO MLIL_MEMORY_INTRINSIC_SSA needs to be handled properly + MLIL_CALL_OUTPUT | MLIL_CALL_PARAM | MLIL_CALL_PARAM_SSA | MLIL_CALL_OUTPUT_SSA | MLIL_MEMORY_INTRINSIC_OUTPUT_SSA | MLIL_MEMORY_INTRINSIC_SSA => { unreachable!() } }; + Self { - function: function.to_owned(), + function, address: op.address, - operation: info, + kind, } } - pub fn function(&self) -> &MediumLevelILFunction { - &self.function - } - - pub fn address(&self) -> u64 { - self.address - } - - pub fn operation(&self) -> &MediumLevelILOperation { - &self.operation - } - pub fn lift(&self) -> MediumLevelILLiftedInstruction { - use MediumLevelILLiftedOperation as Lifted; - use MediumLevelILOperation::*; + use MediumLevelILInstructionKind::*; + use MediumLevelILLiftedInstructionKind as Lifted; + + let kind = match self.kind { + Nop => Lifted::Nop, + Noret => Lifted::Noret, + Bp => Lifted::Bp, + Undef => Lifted::Undef, + Unimpl => Lifted::Unimpl, + If(op) => Lifted::If(LiftedIf { + condition: self.lift_operand(op.condition), + dest_true: op.dest_true, + dest_false: op.dest_false, + }), - let operation = match self.operation { - Nop(op) => Lifted::Nop(op), - Noret(op) => Lifted::Noret(op), - Bp(op) => Lifted::Bp(op), - Undef(op) => Lifted::Undef(op), - Unimpl(op) => Lifted::Unimpl(op), - If(op) => Lifted::If(op.lift(&self.function)), FloatConst(op) => Lifted::FloatConst(op), Const(op) => Lifted::Const(op), ConstPtr(op) => Lifted::ConstPtr(op), Import(op) => Lifted::Import(op), ExternPtr(op) => Lifted::ExternPtr(op), - ConstData(op) => Lifted::ConstData(op.lift(&self.function)), - Jump(op) => Lifted::Jump(op.lift(&self.function)), - RetHint(op) => Lifted::RetHint(op.lift(&self.function)), - StoreSsa(op) => Lifted::StoreSsa(op.lift(&self.function)), - StoreStructSsa(op) => Lifted::StoreStructSsa(op.lift(&self.function)), - StoreStruct(op) => Lifted::StoreStruct(op.lift(&self.function)), - Store(op) => Lifted::Store(op.lift(&self.function)), - JumpTo(op) => Lifted::JumpTo(op.lift(&self.function)), + + ConstData(op) => Lifted::ConstData(LiftedConstData { + constant_data: ConstantData::new( + self.function.get_function(), + RegisterValue { + state: RegisterValueType::from_raw_value(op.constant_data_kind).unwrap(), + value: op.constant_data_value, + offset: 0, + size: op.size, + }, + ), + }), + Jump(op) => Lifted::Jump(LiftedJump { + dest: self.lift_operand(op.dest), + }), + RetHint(op) => Lifted::RetHint(LiftedJump { + dest: self.lift_operand(op.dest), + }), + StoreSsa(op) => Lifted::StoreSsa(LiftedStoreSsa { + dest: self.lift_operand(op.dest), + dest_memory: op.dest_memory, + src_memory: op.src_memory, + src: self.lift_operand(op.src), + }), + StoreStructSsa(op) => Lifted::StoreStructSsa(LiftedStoreStructSsa { + dest: self.lift_operand(op.dest), + offset: op.offset, + dest_memory: op.dest_memory, + src_memory: op.src_memory, + src: self.lift_operand(op.src), + }), + StoreStruct(op) => Lifted::StoreStruct(LiftedStoreStruct { + dest: self.lift_operand(op.dest), + offset: op.offset, + src: self.lift_operand(op.src), + }), + Store(op) => Lifted::Store(LiftedStore { + dest: self.lift_operand(op.dest), + src: self.lift_operand(op.src), + }), + JumpTo(op) => Lifted::JumpTo(LiftedJumpTo { + dest: self.lift_operand(op.dest), + targets: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .pairs() + .collect(), + }), Goto(op) => Lifted::Goto(op), FreeVarSlot(op) => Lifted::FreeVarSlot(op), - SetVarField(op) => Lifted::SetVarField(op.lift(&self.function)), - SetVar(op) => Lifted::SetVar(op.lift(&self.function)), - FreeVarSlotSsa(op) => Lifted::FreeVarSlotSsa(op.lift()), - SetVarSsaField(op) => Lifted::SetVarSsaField(op.lift(&self.function)), - SetVarAliasedField(op) => Lifted::SetVarAliasedField(op.lift(&self.function)), - SetVarAliased(op) => Lifted::SetVarAliased(op.lift(&self.function)), - SetVarSsa(op) => Lifted::SetVarSsa(op.lift(&self.function)), - VarPhi(op) => Lifted::VarPhi(op.lift(&self.function)), - MemPhi(op) => Lifted::MemPhi(op.lift(&self.function)), - VarSplit(op) => Lifted::VarSplit(op.lift()), - SetVarSplit(op) => Lifted::SetVarSplit(op.lift(&self.function)), - VarSplitSsa(op) => Lifted::VarSplitSsa(op.lift()), - SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(op.lift(&self.function)), - Add(op) => Lifted::Add(op.lift(&self.function)), - Sub(op) => Lifted::Sub(op.lift(&self.function)), - And(op) => Lifted::And(op.lift(&self.function)), - Or(op) => Lifted::Or(op.lift(&self.function)), - Xor(op) => Lifted::Xor(op.lift(&self.function)), - Lsl(op) => Lifted::Lsl(op.lift(&self.function)), - Lsr(op) => Lifted::Lsr(op.lift(&self.function)), - Asr(op) => Lifted::Asr(op.lift(&self.function)), - Rol(op) => Lifted::Rol(op.lift(&self.function)), - Ror(op) => Lifted::Ror(op.lift(&self.function)), - Mul(op) => Lifted::Mul(op.lift(&self.function)), - MuluDp(op) => Lifted::MuluDp(op.lift(&self.function)), - MulsDp(op) => Lifted::MulsDp(op.lift(&self.function)), - Divu(op) => Lifted::Divu(op.lift(&self.function)), - DivuDp(op) => Lifted::DivuDp(op.lift(&self.function)), - Divs(op) => Lifted::Divs(op.lift(&self.function)), - DivsDp(op) => Lifted::DivsDp(op.lift(&self.function)), - Modu(op) => Lifted::Modu(op.lift(&self.function)), - ModuDp(op) => Lifted::ModuDp(op.lift(&self.function)), - Mods(op) => Lifted::Mods(op.lift(&self.function)), - ModsDp(op) => Lifted::ModsDp(op.lift(&self.function)), - CmpE(op) => Lifted::CmpE(op.lift(&self.function)), - CmpNe(op) => Lifted::CmpNe(op.lift(&self.function)), - CmpSlt(op) => Lifted::CmpSlt(op.lift(&self.function)), - CmpUlt(op) => Lifted::CmpUlt(op.lift(&self.function)), - CmpSle(op) => Lifted::CmpSle(op.lift(&self.function)), - CmpUle(op) => Lifted::CmpUle(op.lift(&self.function)), - CmpSge(op) => Lifted::CmpSge(op.lift(&self.function)), - CmpUge(op) => Lifted::CmpUge(op.lift(&self.function)), - CmpSgt(op) => Lifted::CmpSgt(op.lift(&self.function)), - CmpUgt(op) => Lifted::CmpUgt(op.lift(&self.function)), - TestBit(op) => Lifted::TestBit(op.lift(&self.function)), - AddOverflow(op) => Lifted::AddOverflow(op.lift(&self.function)), - FcmpE(op) => Lifted::FcmpE(op.lift(&self.function)), - FcmpNe(op) => Lifted::FcmpNe(op.lift(&self.function)), - FcmpLt(op) => Lifted::FcmpLt(op.lift(&self.function)), - FcmpLe(op) => Lifted::FcmpLe(op.lift(&self.function)), - FcmpGe(op) => Lifted::FcmpGe(op.lift(&self.function)), - FcmpGt(op) => Lifted::FcmpGt(op.lift(&self.function)), - FcmpO(op) => Lifted::FcmpO(op.lift(&self.function)), - FcmpUo(op) => Lifted::FcmpUo(op.lift(&self.function)), - Fadd(op) => Lifted::Fadd(op.lift(&self.function)), - Fsub(op) => Lifted::Fsub(op.lift(&self.function)), - Fmul(op) => Lifted::Fmul(op.lift(&self.function)), - Fdiv(op) => Lifted::Fdiv(op.lift(&self.function)), - Adc(op) => Lifted::Adc(op.lift(&self.function)), - Sbb(op) => Lifted::Sbb(op.lift(&self.function)), - Rlc(op) => Lifted::Rlc(op.lift(&self.function)), - Rrc(op) => Lifted::Rrc(op.lift(&self.function)), - Call(op) => Lifted::Call(op.lift(&self.function)), - Tailcall(op) => Lifted::Tailcall(op.lift(&self.function)), - Intrinsic(op) => Lifted::Intrinsic(op.lift(&self.function)), - Syscall(op) => Lifted::Syscall(op.lift(&self.function)), - IntrinsicSsa(op) => Lifted::IntrinsicSsa(op.lift(&self.function)), - CallSsa(op) => Lifted::CallSsa(op.lift(&self.function)), - TailcallSsa(op) => Lifted::TailcallSsa(op.lift(&self.function)), - CallUntypedSsa(op) => Lifted::CallUntypedSsa(op.lift(&self.function)), - TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(op.lift(&self.function)), - SyscallSsa(op) => Lifted::SyscallSsa(op.lift(&self.function)), - SyscallUntypedSsa(op) => Lifted::SyscallUntypedSsa(op.lift(&self.function)), - CallUntyped(op) => Lifted::CallUntyped(op.lift(&self.function)), - TailcallUntyped(op) => Lifted::TailcallUntyped(op.lift(&self.function)), - SyscallUntyped(op) => Lifted::SyscallUntyped(op.lift(&self.function)), - SeparateParamList(op) => Lifted::SeparateParamList(op.lift(&self.function)), - SharedParamSlot(op) => Lifted::SharedParamSlot(op.lift(&self.function)), - Neg(op) => Lifted::Neg(op.lift(&self.function)), - Not(op) => Lifted::Not(op.lift(&self.function)), - Sx(op) => Lifted::Sx(op.lift(&self.function)), - Zx(op) => Lifted::Zx(op.lift(&self.function)), - LowPart(op) => Lifted::LowPart(op.lift(&self.function)), - BoolToInt(op) => Lifted::BoolToInt(op.lift(&self.function)), - UnimplMem(op) => Lifted::UnimplMem(op.lift(&self.function)), - Fsqrt(op) => Lifted::Fsqrt(op.lift(&self.function)), - Fneg(op) => Lifted::Fneg(op.lift(&self.function)), - Fabs(op) => Lifted::Fabs(op.lift(&self.function)), - FloatToInt(op) => Lifted::FloatToInt(op.lift(&self.function)), - IntToFloat(op) => Lifted::IntToFloat(op.lift(&self.function)), - FloatConv(op) => Lifted::FloatConv(op.lift(&self.function)), - RoundToInt(op) => Lifted::RoundToInt(op.lift(&self.function)), - Floor(op) => Lifted::Floor(op.lift(&self.function)), - Ceil(op) => Lifted::Ceil(op.lift(&self.function)), - Ftrunc(op) => Lifted::Ftrunc(op.lift(&self.function)), - Load(op) => Lifted::Load(op.lift(&self.function)), - LoadStruct(op) => Lifted::LoadStruct(op.lift(&self.function)), - LoadStructSsa(op) => Lifted::LoadStructSsa(op.lift(&self.function)), - LoadSsa(op) => Lifted::LoadSsa(op.lift(&self.function)), - Ret(op) => Lifted::Ret(op.lift(&self.function)), + SetVarField(op) => Lifted::SetVarField(LiftedSetVarField { + dest: op.dest, + offset: op.offset, + src: self.lift_operand(op.src), + }), + SetVar(op) => Lifted::SetVar(LiftedSetVar { + dest: op.dest, + src: self.lift_operand(op.src), + }), + FreeVarSlotSsa(op) => Lifted::FreeVarSlotSsa(op), + SetVarSsaField(op) => Lifted::SetVarSsaField(LiftedSetVarSsaField { + dest: op.dest, + prev: op.prev, + offset: op.offset, + src: self.lift_operand(op.src), + }), + SetVarAliasedField(op) => Lifted::SetVarAliasedField(LiftedSetVarSsaField { + dest: op.dest, + prev: op.prev, + offset: op.offset, + src: self.lift_operand(op.src), + }), + SetVarAliased(op) => Lifted::SetVarAliased(LiftedSetVarAliased { + dest: op.dest, + prev: op.prev, + src: self.lift_operand(op.src), + }), + SetVarSsa(op) => Lifted::SetVarSsa(LiftedSetVarSsa { + dest: op.dest, + src: self.lift_operand(op.src), + }), + VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { + dest: op.dest, + src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .ssa_vars() + .collect(), + }), + MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { + dest_memory: op.dest_memory, + src_memory: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .collect(), + }), + VarSplit(op) => Lifted::VarSplit(op), + SetVarSplit(op) => Lifted::SetVarSplit(LiftedSetVarSplit { + high: op.high, + low: op.low, + src: self.lift_operand(op.src), + }), + VarSplitSsa(op) => Lifted::VarSplitSsa(op), + SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(LiftedSetVarSplitSsa { + high: op.high, + low: op.low, + src: self.lift_operand(op.src), + }), + + Add(op) => Lifted::Add(self.lift_binary_op(op)), + Sub(op) => Lifted::Sub(self.lift_binary_op(op)), + And(op) => Lifted::And(self.lift_binary_op(op)), + Or(op) => Lifted::Or(self.lift_binary_op(op)), + Xor(op) => Lifted::Xor(self.lift_binary_op(op)), + Lsl(op) => Lifted::Lsl(self.lift_binary_op(op)), + Lsr(op) => Lifted::Lsr(self.lift_binary_op(op)), + Asr(op) => Lifted::Asr(self.lift_binary_op(op)), + Rol(op) => Lifted::Rol(self.lift_binary_op(op)), + Ror(op) => Lifted::Ror(self.lift_binary_op(op)), + Mul(op) => Lifted::Mul(self.lift_binary_op(op)), + MuluDp(op) => Lifted::MuluDp(self.lift_binary_op(op)), + MulsDp(op) => Lifted::MulsDp(self.lift_binary_op(op)), + Divu(op) => Lifted::Divu(self.lift_binary_op(op)), + DivuDp(op) => Lifted::DivuDp(self.lift_binary_op(op)), + Divs(op) => Lifted::Divs(self.lift_binary_op(op)), + DivsDp(op) => Lifted::DivsDp(self.lift_binary_op(op)), + Modu(op) => Lifted::Modu(self.lift_binary_op(op)), + ModuDp(op) => Lifted::ModuDp(self.lift_binary_op(op)), + Mods(op) => Lifted::Mods(self.lift_binary_op(op)), + ModsDp(op) => Lifted::ModsDp(self.lift_binary_op(op)), + CmpE(op) => Lifted::CmpE(self.lift_binary_op(op)), + CmpNe(op) => Lifted::CmpNe(self.lift_binary_op(op)), + CmpSlt(op) => Lifted::CmpSlt(self.lift_binary_op(op)), + CmpUlt(op) => Lifted::CmpUlt(self.lift_binary_op(op)), + CmpSle(op) => Lifted::CmpSle(self.lift_binary_op(op)), + CmpUle(op) => Lifted::CmpUle(self.lift_binary_op(op)), + CmpSge(op) => Lifted::CmpSge(self.lift_binary_op(op)), + CmpUge(op) => Lifted::CmpUge(self.lift_binary_op(op)), + CmpSgt(op) => Lifted::CmpSgt(self.lift_binary_op(op)), + CmpUgt(op) => Lifted::CmpUgt(self.lift_binary_op(op)), + TestBit(op) => Lifted::TestBit(self.lift_binary_op(op)), + AddOverflow(op) => Lifted::AddOverflow(self.lift_binary_op(op)), + FcmpE(op) => Lifted::FcmpE(self.lift_binary_op(op)), + FcmpNe(op) => Lifted::FcmpNe(self.lift_binary_op(op)), + FcmpLt(op) => Lifted::FcmpLt(self.lift_binary_op(op)), + FcmpLe(op) => Lifted::FcmpLe(self.lift_binary_op(op)), + FcmpGe(op) => Lifted::FcmpGe(self.lift_binary_op(op)), + FcmpGt(op) => Lifted::FcmpGt(self.lift_binary_op(op)), + FcmpO(op) => Lifted::FcmpO(self.lift_binary_op(op)), + FcmpUo(op) => Lifted::FcmpUo(self.lift_binary_op(op)), + Fadd(op) => Lifted::Fadd(self.lift_binary_op(op)), + Fsub(op) => Lifted::Fsub(self.lift_binary_op(op)), + Fmul(op) => Lifted::Fmul(self.lift_binary_op(op)), + Fdiv(op) => Lifted::Fdiv(self.lift_binary_op(op)), + + Adc(op) => Lifted::Adc(self.lift_binary_op_carry(op)), + Sbb(op) => Lifted::Sbb(self.lift_binary_op_carry(op)), + Rlc(op) => Lifted::Rlc(self.lift_binary_op_carry(op)), + Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)), + + Call(op) => Lifted::Call(self.lift_call(op)), + Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), + + Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .vars() + .collect(), + intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + }), + Syscall(op) => Lifted::Syscall(LiftedSyscallCall { + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .vars() + .collect(), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + }), + IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .ssa_vars() + .collect(), + intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + }), + + CallSsa(op) => Lifted::CallSsa(self.lift_call_ssa(op)), + TailcallSsa(op) => Lifted::TailcallSsa(self.lift_call_ssa(op)), + + CallUntypedSsa(op) => Lifted::CallUntypedSsa(self.lift_call_untyped_ssa(op)), + TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(self.lift_call_untyped_ssa(op)), + + SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { + output: get_call_output_ssa(&self.function, op.output).collect(), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + src_memory: op.src_memory, + }), + SyscallUntypedSsa(op) => Lifted::SyscallUntypedSsa(LiftedSyscallUntypedSsa { + output: get_call_output_ssa(&self.function, op.output).collect(), + params: get_call_params_ssa(&self.function, op.params) + .map(|param| param.lift()) + .collect(), + stack: self.lift_operand(op.stack), + }), + + CallUntyped(op) => Lifted::CallUntyped(self.lift_call_untyped(op)), + TailcallUntyped(op) => Lifted::TailcallUntyped(self.lift_call_untyped(op)), + SyscallUntyped(op) => Lifted::SyscallUntyped(LiftedSyscallUntyped { + output: get_call_output(&self.function, op.output).collect(), + params: get_call_params(&self.function, op.params) + .map(|param| param.lift()) + .collect(), + stack: self.lift_operand(op.stack), + }), + + Neg(op) => Lifted::Neg(self.lift_unary_op(op)), + Not(op) => Lifted::Not(self.lift_unary_op(op)), + Sx(op) => Lifted::Sx(self.lift_unary_op(op)), + Zx(op) => Lifted::Zx(self.lift_unary_op(op)), + LowPart(op) => Lifted::LowPart(self.lift_unary_op(op)), + BoolToInt(op) => Lifted::BoolToInt(self.lift_unary_op(op)), + UnimplMem(op) => Lifted::UnimplMem(self.lift_unary_op(op)), + Fsqrt(op) => Lifted::Fsqrt(self.lift_unary_op(op)), + Fneg(op) => Lifted::Fneg(self.lift_unary_op(op)), + Fabs(op) => Lifted::Fabs(self.lift_unary_op(op)), + FloatToInt(op) => Lifted::FloatToInt(self.lift_unary_op(op)), + IntToFloat(op) => Lifted::IntToFloat(self.lift_unary_op(op)), + FloatConv(op) => Lifted::FloatConv(self.lift_unary_op(op)), + RoundToInt(op) => Lifted::RoundToInt(self.lift_unary_op(op)), + Floor(op) => Lifted::Floor(self.lift_unary_op(op)), + Ceil(op) => Lifted::Ceil(self.lift_unary_op(op)), + Ftrunc(op) => Lifted::Ftrunc(self.lift_unary_op(op)), + Load(op) => Lifted::Load(self.lift_unary_op(op)), + + LoadStruct(op) => Lifted::LoadStruct(LiftedLoadStruct { + src: self.lift_operand(op.src), + offset: op.offset, + }), + LoadStructSsa(op) => Lifted::LoadStructSsa(LiftedLoadStructSsa { + src: self.lift_operand(op.src), + offset: op.offset, + src_memory: op.src_memory, + }), + LoadSsa(op) => Lifted::LoadSsa(LiftedLoadSsa { + src: self.lift_operand(op.src), + src_memory: op.src_memory, + }), + Ret(op) => Lifted::Ret(LiftedRet { + src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .exprs() + .map(|expr| expr.lift()) + .collect(), + }), + SeparateParamList(op) => Lifted::SeparateParamList(LiftedSeparateParamList { + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + }), + SharedParamSlot(op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + }), Var(op) => Lifted::Var(op), AddressOf(op) => Lifted::AddressOf(op), VarField(op) => Lifted::VarField(op), @@ -748,77 +1015,137 @@ impl MediumLevelILInstruction { VarAliasedField(op) => Lifted::VarAliasedField(op), Trap(op) => Lifted::Trap(op), }; + MediumLevelILLiftedInstruction { + function: self.function.clone(), address: self.address, - operation, + kind, } } - pub fn operands(&self) -> Box> { - use MediumLevelILOperation::*; - match &self.operation { - Nop(_op) | Noret(_op) | Bp(_op) | Undef(_op) | Unimpl(_op) => Box::new([].into_iter()), - If(op) => Box::new(op.operands(&self.function)), - FloatConst(op) => Box::new(op.operands()), - Const(op) | ConstPtr(op) | Import(op) => Box::new(op.operands()), - ExternPtr(op) => Box::new(op.operands(&self.function)), - ConstData(op) => Box::new(op.operands(&self.function)), - Jump(op) | RetHint(op) => Box::new(op.operands(&self.function)), - StoreSsa(op) => Box::new(op.operands(&self.function)), - StoreStructSsa(op) => Box::new(op.operands(&self.function)), - StoreStruct(op) => Box::new(op.operands(&self.function)), - Store(op) => Box::new(op.operands(&self.function)), - JumpTo(op) => Box::new(op.operands(&self.function)), - Goto(op) => Box::new(op.operands()), - FreeVarSlot(op) => Box::new(op.operands()), - SetVarField(op) => Box::new(op.operands(&self.function)), - SetVar(op) => Box::new(op.operands(&self.function)), - FreeVarSlotSsa(op) => Box::new(op.operands()), - SetVarSsaField(op) | SetVarAliasedField(op) => Box::new(op.operands(&self.function)), - SetVarAliased(op) => Box::new(op.operands(&self.function)), - SetVarSsa(op) => Box::new(op.operands(&self.function)), - VarPhi(op) => Box::new(op.operands(&self.function)), - MemPhi(op) => Box::new(op.operands(&self.function)), - VarSplit(op) => Box::new(op.operands()), - SetVarSplit(op) => Box::new(op.operands(&self.function)), - VarSplitSsa(op) => Box::new(op.operands()), - SetVarSplitSsa(op) => Box::new(op.operands(&self.function)), - Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op) - | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op) - | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) | CmpE(op) - | CmpNe(op) | CmpSlt(op) | CmpUlt(op) | CmpSle(op) | CmpUle(op) | CmpSge(op) - | CmpUge(op) | CmpSgt(op) | CmpUgt(op) | TestBit(op) | AddOverflow(op) | FcmpE(op) - | FcmpNe(op) | FcmpLt(op) | FcmpLe(op) | FcmpGe(op) | FcmpGt(op) | FcmpO(op) - | FcmpUo(op) | Fadd(op) | Fsub(op) | Fmul(op) | Fdiv(op) => { - Box::new(op.operands(&self.function)) - } - Adc(op) | Sbb(op) | Rlc(op) | Rrc(op) => Box::new(op.operands(&self.function)), - Call(op) | Tailcall(op) => Box::new(op.operands(&self.function)), - Syscall(op) => Box::new(op.operands(&self.function)), - Intrinsic(op) => Box::new(op.operands(&self.function)), - IntrinsicSsa(op) => Box::new(op.operands(&self.function)), - CallSsa(op) | TailcallSsa(op) => Box::new(op.operands(&self.function)), - CallUntypedSsa(op) | TailcallUntypedSsa(op) => Box::new(op.operands(&self.function)), - SyscallSsa(op) => Box::new(op.operands(&self.function)), - SyscallUntypedSsa(op) => Box::new(op.operands(&self.function)), - CallUntyped(op) | TailcallUntyped(op) => Box::new(op.operands(&self.function)), - SyscallUntyped(op) => Box::new(op.operands(&self.function)), - SeparateParamList(op) => Box::new(op.operands(&self.function)), - SharedParamSlot(op) => Box::new(op.operands(&self.function)), - Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op) | BoolToInt(op) | UnimplMem(op) - | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op) | IntToFloat(op) | FloatConv(op) - | RoundToInt(op) | Floor(op) | Ceil(op) | Ftrunc(op) | Load(op) => { - Box::new(op.operands(&self.function)) - } - LoadStruct(op) => Box::new(op.operands(&self.function)), - LoadStructSsa(op) => Box::new(op.operands(&self.function)), - LoadSsa(op) => Box::new(op.operands(&self.function)), - Ret(op) => Box::new(op.operands(&self.function)), - Var(op) | AddressOf(op) => Box::new(op.operands()), - VarField(op) | AddressOfField(op) => Box::new(op.operands()), - VarSsa(op) | VarAliased(op) => Box::new(op.operands()), - VarSsaField(op) | VarAliasedField(op) => Box::new(op.operands()), - Trap(op) => Box::new(op.operands()), + fn lift_operand(&self, expr_idx: usize) -> Box { + Box::new(self.function.lifted_instruction_from_idx(expr_idx)) + } + + fn lift_binary_op(&self, op: BinaryOp) -> LiftedBinaryOp { + LiftedBinaryOp { + left: self.lift_operand(op.left), + right: self.lift_operand(op.right), + } + } + + fn lift_binary_op_carry(&self, op: BinaryOpCarry) -> LiftedBinaryOpCarry { + LiftedBinaryOpCarry { + left: self.lift_operand(op.left), + right: self.lift_operand(op.right), + carry: self.lift_operand(op.carry), + } + } + + fn lift_unary_op(&self, op: UnaryOp) -> LiftedUnaryOp { + LiftedUnaryOp { + src: self.lift_operand(op.src), + } + } + + fn lift_call(&self, op: Call) -> LiftedCall { + LiftedCall { + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .vars() + .collect(), + dest: self.lift_operand(op.dest), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } + + fn lift_call_untyped(&self, op: CallUntyped) -> LiftedCallUntyped { + LiftedCallUntyped { + output: get_call_output(&self.function, op.output).collect(), + dest: self.lift_operand(op.dest), + params: get_call_params(&self.function, op.params) + .map(|expr| expr.lift()) + .collect(), + stack: self.lift_operand(op.stack), + } + } + + fn lift_call_ssa(&self, op: CallSsa) -> LiftedCallSsa { + LiftedCallSsa { + output: get_call_output_ssa(&self.function, op.output).collect(), + dest: self.lift_operand(op.dest), + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + src_memory: op.src_memory, + } + } + + fn lift_call_untyped_ssa(&self, op: CallUntypedSsa) -> LiftedCallUntypedSsa { + LiftedCallUntypedSsa { + output: get_call_output_ssa(&self.function, op.output).collect(), + dest: self.lift_operand(op.dest), + params: get_call_params_ssa(&self.function, op.params) + .map(|param| param.lift()) + .collect(), + stack: self.lift_operand(op.stack), } } } + +fn get_float(value: u64, size: usize) -> f64 { + match size { + 4 => f32::from_bits(value as u32) as f64, + 8 => f64::from_bits(value), + // TODO how to handle this value? + size => todo!("float size {}", size), + } +} + +fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction { + unsafe { BNGetMediumLevelILByIndex(function.handle, idx) } +} + +fn get_var(id: u64) -> Variable { + unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } +} + +fn get_var_ssa(id: u64, version: usize) -> SSAVariable { + SSAVariable::new(get_var(id), version) +} + +fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> impl Iterator { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT); + OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).vars() +} + +fn get_call_params( + function: &MediumLevelILFunction, + idx: usize, +) -> impl Iterator { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM); + OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).exprs() +} + +fn get_call_output_ssa( + function: &MediumLevelILFunction, + idx: usize, +) -> impl Iterator { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA); + OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).ssa_vars() +} + +fn get_call_params_ssa( + function: &MediumLevelILFunction, + idx: usize, +) -> impl Iterator { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA); + OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).exprs() +} diff --git a/src/mlil/lift.rs b/src/mlil/lift.rs index fc996cb..ba434d1 100644 --- a/src/mlil/lift.rs +++ b/src/mlil/lift.rs @@ -1,25 +1,48 @@ -use super::operation::*; +use std::collections::BTreeMap; -#[derive(Clone, Debug, PartialEq)] -pub struct MediumLevelILLiftedInstruction { - pub address: u64, - pub operation: MediumLevelILLiftedOperation, +use crate::rc::Ref; +use crate::types::{ConstantData, ILIntrinsic, SSAVariable, Variable}; + +use super::operation::*; +use super::MediumLevelILFunction; + +#[derive(Clone)] +pub enum MediumLevelILLiftedOperand { + ConstantData(ConstantData), + Intrinsic(ILIntrinsic), + Expr(MediumLevelILLiftedInstruction), + ExprList(Vec), + Float(f64), + Int(u64), + IntList(Vec), + TargetMap(BTreeMap), + Var(Variable), + VarList(Vec), + VarSsa(SSAVariable), + VarSsaList(Vec), } #[derive(Clone, Debug, PartialEq)] -pub enum MediumLevelILLiftedOperation { - Nop(NoArgs), - Noret(NoArgs), - Bp(NoArgs), - Undef(NoArgs), - Unimpl(NoArgs), +pub struct MediumLevelILLiftedInstruction { + pub function: Ref, + pub address: u64, + pub kind: MediumLevelILLiftedInstructionKind, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum MediumLevelILLiftedInstructionKind { + Nop, + Noret, + Bp, + Undef, + Unimpl, If(LiftedIf), FloatConst(FloatConst), Const(Constant), ConstPtr(Constant), Import(Constant), ExternPtr(ExternPtr), - ConstData(ConstantData), + ConstData(LiftedConstData), Jump(LiftedJump), RetHint(LiftedJump), StoreSsa(LiftedStoreSsa), @@ -93,8 +116,8 @@ pub enum MediumLevelILLiftedOperation { Rrc(LiftedBinaryOpCarry), Call(LiftedCall), Tailcall(LiftedCall), - Intrinsic(LiftedInnerCall), - Syscall(LiftedInnerCall), + Intrinsic(LiftedIntrinsic), + Syscall(LiftedSyscallCall), IntrinsicSsa(LiftedIntrinsicSsa), CallSsa(LiftedCallSsa), TailcallSsa(LiftedCallSsa), @@ -139,3 +162,210 @@ pub enum MediumLevelILLiftedOperation { VarAliasedField(VarSsaField), Trap(Trap), } + +impl MediumLevelILLiftedInstruction { + pub fn operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { + use MediumLevelILLiftedInstructionKind::*; + use MediumLevelILLiftedOperand as Operand; + match &self.kind { + Nop | Noret | Bp | Undef | Unimpl => vec![], + If(op) => vec![ + ("condition", Operand::Expr(*op.condition.clone())), + ("dest_true", Operand::Int(op.dest_true)), + ("dest_false", Operand::Int(op.dest_false)), + ], + FloatConst(op) => vec![("constant", Operand::Float(op.constant))], + Const(op) | ConstPtr(op) | Import(op) => vec![("constant", Operand::Int(op.constant))], + ExternPtr(op) => vec![ + ("constant", Operand::Int(op.constant)), + ("offset", Operand::Int(op.offset)), + ], + ConstData(op) => vec![( + "constant_data", + Operand::ConstantData(op.constant_data.clone()), + )], + Jump(op) | RetHint(op) => vec![("dest", Operand::Expr(*op.dest.clone()))], + StoreSsa(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ("src", Operand::Expr(*op.src.clone())), + ], + StoreStructSsa(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("offset", Operand::Int(op.offset)), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ("src", Operand::Expr(*op.src.clone())), + ], + StoreStruct(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("offset", Operand::Int(op.offset)), + ("src", Operand::Expr(*op.src.clone())), + ], + Store(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("src", Operand::Expr(*op.src.clone())), + ], + JumpTo(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("targets", Operand::TargetMap(op.targets.clone())), + ], + Goto(op) => vec![("dest", Operand::Int(op.dest))], + FreeVarSlot(op) => vec![("dest", Operand::Var(op.dest))], + SetVarField(op) => vec![ + ("dest", Operand::Var(op.dest)), + ("offset", Operand::Int(op.offset)), + ("src", Operand::Expr(*op.src.clone())), + ], + SetVar(op) => vec![ + ("dest", Operand::Var(op.dest)), + ("src", Operand::Expr(*op.src.clone())), + ], + FreeVarSlotSsa(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("prev", Operand::VarSsa(op.prev)), + ], + SetVarSsaField(op) | SetVarAliasedField(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("prev", Operand::VarSsa(op.prev)), + ("offset", Operand::Int(op.offset)), + ("src", Operand::Expr(*op.src.clone())), + ], + SetVarAliased(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("prev", Operand::VarSsa(op.prev)), + ("src", Operand::Expr(*op.src.clone())), + ], + SetVarSsa(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("src", Operand::Expr(*op.src.clone())), + ], + VarPhi(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("src", Operand::VarSsaList(op.src.clone())), + ], + MemPhi(op) => vec![ + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::IntList(op.src_memory.clone())), + ], + VarSplit(op) => vec![ + ("high", Operand::Var(op.high)), + ("low", Operand::Var(op.low)), + ], + SetVarSplit(op) => vec![ + ("high", Operand::Var(op.high)), + ("low", Operand::Var(op.low)), + ("src", Operand::Expr(*op.src.clone())), + ], + VarSplitSsa(op) => vec![ + ("high", Operand::VarSsa(op.high)), + ("low", Operand::VarSsa(op.low)), + ], + SetVarSplitSsa(op) => vec![ + ("high", Operand::VarSsa(op.high)), + ("low", Operand::VarSsa(op.low)), + ("src", Operand::Expr(*op.src.clone())), + ], + Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op) + | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op) + | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) | CmpE(op) + | CmpNe(op) | CmpSlt(op) | CmpUlt(op) | CmpSle(op) | CmpUle(op) | CmpSge(op) + | CmpUge(op) | CmpSgt(op) | CmpUgt(op) | TestBit(op) | AddOverflow(op) | FcmpE(op) + | FcmpNe(op) | FcmpLt(op) | FcmpLe(op) | FcmpGe(op) | FcmpGt(op) | FcmpO(op) + | FcmpUo(op) | Fadd(op) | Fsub(op) | Fmul(op) | Fdiv(op) => vec![ + ("left", Operand::Expr(*op.left.clone())), + ("right", Operand::Expr(*op.right.clone())), + ], + Adc(op) | Sbb(op) | Rlc(op) | Rrc(op) => vec![ + ("left", Operand::Expr(*op.left.clone())), + ("right", Operand::Expr(*op.right.clone())), + ("carry", Operand::Expr(*op.carry.clone())), + ], + Call(op) | Tailcall(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ], + Syscall(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("params", Operand::ExprList(op.params.clone())), + ], + Intrinsic(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("intrinsic", Operand::Intrinsic(op.intrinsic)), + ("params", Operand::ExprList(op.params.clone())), + ], + IntrinsicSsa(op) => vec![ + ("output", Operand::VarSsaList(op.output.clone())), + ("intrinsic", Operand::Intrinsic(op.intrinsic)), + ("params", Operand::ExprList(op.params.clone())), + ], + CallSsa(op) | TailcallSsa(op) => vec![ + ("output", Operand::VarSsaList(op.output.clone())), + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + CallUntypedSsa(op) | TailcallUntypedSsa(op) => vec![ + ("output", Operand::VarSsaList(op.output.clone())), + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("stack", Operand::Expr(*op.stack.clone())), + ], + SyscallSsa(op) => vec![ + ("output", Operand::VarSsaList(op.output.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + SyscallUntypedSsa(op) => vec![ + ("output", Operand::VarSsaList(op.output.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("stack", Operand::Expr(*op.stack.clone())), + ], + CallUntyped(op) | TailcallUntyped(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("stack", Operand::Expr(*op.stack.clone())), + ], + SyscallUntyped(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("stack", Operand::Expr(*op.stack.clone())), + ], + Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op) | BoolToInt(op) | UnimplMem(op) + | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op) | IntToFloat(op) | FloatConv(op) + | RoundToInt(op) | Floor(op) | Ceil(op) | Ftrunc(op) | Load(op) => { + vec![("src", Operand::Expr(*op.src.clone()))] + } + LoadStruct(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("offset", Operand::Int(op.offset)), + ], + LoadStructSsa(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("offset", Operand::Int(op.offset)), + ("src_memory", Operand::Int(op.src_memory)), + ], + LoadSsa(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + Ret(op) => vec![("src", Operand::ExprList(op.src.clone()))], + SeparateParamList(op) => vec![("params", Operand::ExprList(op.params.clone()))], + SharedParamSlot(op) => vec![("params", Operand::ExprList(op.params.clone()))], + Var(op) | AddressOf(op) => vec![("src", Operand::Var(op.src))], + VarField(op) | AddressOfField(op) => vec![ + ("src", Operand::Var(op.src)), + ("offset", Operand::Int(op.offset)), + ], + VarSsa(op) | VarAliased(op) => vec![("src", Operand::VarSsa(op.src))], + VarSsaField(op) | VarAliasedField(op) => vec![ + ("src", Operand::VarSsa(op.src)), + ("offset", Operand::Int(op.offset)), + ], + Trap(op) => vec![("vector", Operand::Int(op.vector))], + } + } +} diff --git a/src/mlil/operation.rs b/src/mlil/operation.rs index 880155e..822688a 100644 --- a/src/mlil/operation.rs +++ b/src/mlil/operation.rs @@ -1,317 +1,15 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; -use binaryninjacore_sys::BNFromVariableIdentifier; -use binaryninjacore_sys::BNGetMediumLevelILByIndex; -use binaryninjacore_sys::BNMediumLevelILInstruction; -use binaryninjacore_sys::BNMediumLevelILOperation; +use crate::types::{ConstantData, ILIntrinsic, SSAVariable, Variable}; -use crate::rc::Ref; -use crate::types::{SSAVariable, Variable}; - -use super::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelILLiftedInstruction}; - -pub enum MediumLevelILOperand { - //TODO - //ConstantData(!), - //TODO - //Intrinsic(!), - Expr(MediumLevelILInstruction), - ExprList(OperandExprList), - Float(f64), - Int(u64), - IntList(OperandList), - TargetMap(OperandDubleList), - Var(Variable), - VarList(OperandVariableList), - VarSsa(SSAVariable), - VarSsaList(OperandSSAVariableList), -} - -// Iterator for the get_list, this is better then a inline iterator because -// this also implement ExactSizeIterator, what a inline iterator does not. -pub struct OperandList { - function: Ref, - remaining: usize, - next_node_idx: Option, - - current_node: core::array::IntoIter, -} -impl OperandList { - fn new(function: &MediumLevelILFunction, idx: usize, number: usize) -> Self { - // alternative to core::array::IntoIter::empty(); - let mut iter = [0; 4].into_iter(); - for _ in 0..4 { - let _ = iter.next(); - } - Self { - function: function.to_owned(), - remaining: number, - next_node_idx: Some(idx), - current_node: iter, - } - } - fn duble(self) -> OperandDubleList { - assert_eq!(self.len() % 2, 0); - OperandDubleList(self) - } - fn map_expr(self) -> OperandExprList { - OperandExprList(self) - } - fn map_var(self) -> OperandVariableList { - OperandVariableList(self) - } - fn map_ssa_var(self) -> OperandSSAVariableList { - OperandSSAVariableList(self.duble()) - } -} -impl Iterator for OperandList { - type Item = u64; - - fn next(&mut self) -> Option { - // if there is an item in this node, return it - if let Some(current_node) = self.current_node.next() { - return Some(current_node); - } - - // no more items to fetch - if self.remaining == 0 { - return None; - } - - // otherwise get the next node - let next_idx = self.next_node_idx?; - let node = unsafe { BNGetMediumLevelILByIndex(self.function.handle, next_idx) }; - assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); - - // each node contains at most 4, the last is reserved to next node idx - let consume = if self.remaining > 4 { - // there are more nodes after this one - self.next_node_idx = Some(node.operands[4] as usize); - self.remaining -= 4; - &node.operands[0..4] - } else { - // last part of the list, there is no next node - self.next_node_idx = None; - let nodes = &node.operands[0..self.remaining]; - self.remaining = 0; - nodes - }; - // the iter need to have a space of 4, but we may have less then that, - // solution is create a dummy elements at the start and discard it - let mut nodes = [0; 4]; - let dummy_values = 4 - consume.len(); - nodes[dummy_values..4].copy_from_slice(consume); - self.current_node = nodes.into_iter(); - for _ in 0..dummy_values { - let _ = self.current_node.next(); - } - - self.current_node.next() - } - - fn size_hint(&self) -> (usize, Option) { - (self.len(), Some(self.len())) - } -} -impl ExactSizeIterator for OperandList { - fn len(&self) -> usize { - self.remaining + self.current_node.len() - } -} - -// Iterator similar to OperationList, but returns two elements -pub struct OperandDubleList(OperandList); -impl Iterator for OperandDubleList { - type Item = (u64, u64); - - fn next(&mut self) -> Option { - let first = self.0.next()?; - let second = self.0.next().unwrap(); - Some((first, second)) - } - - fn size_hint(&self) -> (usize, Option) { - (self.len(), Some(self.len())) - } -} -impl ExactSizeIterator for OperandDubleList { - fn len(&self) -> usize { - self.0.len() / 2 - } -} - -pub struct OperandExprList(OperandList); -impl Iterator for OperandExprList { - type Item = MediumLevelILInstruction; - - fn next(&mut self) -> Option { - self.0 - .next() - .map(|idx| get_operation(&self.0.function, idx as usize)) - } - - fn size_hint(&self) -> (usize, Option) { - (self.0.len(), Some(self.0.len())) - } -} -impl ExactSizeIterator for OperandExprList { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandVariableList(OperandList); -impl Iterator for OperandVariableList { - type Item = Variable; - - fn next(&mut self) -> Option { - self.0.next().map(get_var) - } - - fn size_hint(&self) -> (usize, Option) { - (self.0.len(), Some(self.0.len())) - } -} -impl ExactSizeIterator for OperandVariableList { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandSSAVariableList(OperandDubleList); -impl Iterator for OperandSSAVariableList { - type Item = SSAVariable; - - fn next(&mut self) -> Option { - self.0.next().map(|(id, version)| { - let raw = unsafe { BNFromVariableIdentifier(id) }; - let var = unsafe { Variable::from_raw(raw) }; - SSAVariable::new(var, version as usize) - }) - } - - fn size_hint(&self) -> (usize, Option) { - (self.len(), Some(self.len())) - } -} -impl ExactSizeIterator for OperandSSAVariableList { - fn len(&self) -> usize { - self.0.len() - } -} - -fn get_float(value: u64, size: usize) -> f64 { - match size { - 4 => f32::from_bits(value as u32) as f64, - 8 => f64::from_bits(value), - // TODO how to handle this value? - size => todo!("float size {}", size), - } -} - -// TODO implement ConstantData -fn get_constant_data( - _function: &MediumLevelILFunction, - _value: u64, - _state: u64, - _size: usize, -) -> ! { - todo!() -} - -// TODO implement Intrinsic -fn get_intrinsic(_function: &MediumLevelILFunction, _idx: usize) -> ! { - todo!() -} - -fn get_operation(function: &MediumLevelILFunction, idx: usize) -> MediumLevelILInstruction { - function.instruction_from_idx(idx) -} - -fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction { - unsafe { BNGetMediumLevelILByIndex(function.handle, idx) } -} - -fn get_var(id: u64) -> Variable { - unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } -} - -fn get_var_ssa(id: u64, version: usize) -> SSAVariable { - let raw = unsafe { BNFromVariableIdentifier(id) }; - let var = unsafe { Variable::from_raw(raw) }; - SSAVariable::new(var, version) -} - -fn get_call_list( - function: &MediumLevelILFunction, - op_type: BNMediumLevelILOperation, - idx: usize, -) -> OperandVariableList { - let op = unsafe { BNGetMediumLevelILByIndex(function.handle, idx) }; - assert_eq!(op.operation, op_type); - OperandList::new(function, op.operands[1] as usize, op.operands[0] as usize).map_var() -} - -fn get_call_exprs( - function: &MediumLevelILFunction, - op_type: BNMediumLevelILOperation, - idx: usize, -) -> OperandExprList { - let op = unsafe { BNGetMediumLevelILByIndex(function.handle, idx) }; - assert_eq!(op.operation, op_type); - OperandList::new(function, op.operands[1] as usize, op.operands[0] as usize).map_expr() -} - -fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> OperandVariableList { - get_call_list(function, BNMediumLevelILOperation::MLIL_CALL_OUTPUT, idx) -} - -fn get_call_params(function: &MediumLevelILFunction, idx: usize) -> OperandExprList { - get_call_exprs(function, BNMediumLevelILOperation::MLIL_CALL_PARAM, idx) -} - -fn get_call_list_ssa( - function: &MediumLevelILFunction, - op_type: BNMediumLevelILOperation, - idx: usize, -) -> OperandSSAVariableList { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, op_type); - OperandList::new(function, op.operands[2] as usize, op.operands[1] as usize).map_ssa_var() -} - -fn get_call_exprs_ssa( - function: &MediumLevelILFunction, - op_type: BNMediumLevelILOperation, - idx: usize, -) -> OperandExprList { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, op_type); - OperandList::new(function, op.operands[2] as usize, op.operands[1] as usize).map_expr() -} - -fn get_call_output_ssa(function: &MediumLevelILFunction, idx: usize) -> OperandSSAVariableList { - get_call_list_ssa( - function, - BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA, - idx, - ) -} - -fn get_call_params_ssa(function: &MediumLevelILFunction, idx: usize) -> OperandExprList { - get_call_exprs_ssa(function, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA, idx) -} - -// NOP, NORET, BP, UNDEF, UNIMPL -#[derive(Default, Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct NoArgs {} +use super::MediumLevelILLiftedInstruction; // IF #[derive(Copy, Clone)] pub struct MediumLevelILOperationIf { - condition: usize, - dest_true: u64, - dest_false: u64, + pub condition: usize, + pub dest_true: u64, + pub dest_false: u64, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedIf { @@ -319,79 +17,18 @@ pub struct LiftedIf { pub dest_true: u64, pub dest_false: u64, } -impl MediumLevelILOperationIf { - pub fn new(condition: usize, dest_true: u64, dest_false: u64) -> Self { - Self { - condition, - dest_true, - dest_false, - } - } - pub fn condition(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.condition) - } - pub fn dest_true(&self) -> u64 { - self.dest_true - } - pub fn dest_false(&self) -> u64 { - self.dest_false - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedIf { - LiftedIf { - condition: Box::new(self.condition(function).lift()), - dest_true: self.dest_true(), - dest_false: self.dest_false(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("condition", Expr(self.condition(function))), - ("dest_true", Int(self.dest_true())), - ("dest_false", Int(self.dest_false())), - ] - .into_iter() - } -} // FLOAT_CONST #[derive(Copy, Clone, Debug, PartialEq)] pub struct FloatConst { pub constant: f64, } -impl FloatConst { - pub fn new(constant: u64, size: usize) -> Self { - Self { - constant: get_float(constant, size), - } - } - pub fn constant(&self) -> f64 { - self.constant - } - pub fn operands(&self) -> impl Iterator { - [("constant", MediumLevelILOperand::Float(self.constant()))].into_iter() - } -} // CONST, CONST_PTR, IMPORT #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Constant { pub constant: u64, } -impl Constant { - pub fn new(constant: u64) -> Self { - Self { constant } - } - pub fn constant(&self) -> u64 { - self.constant - } - pub fn operands(&self) -> impl Iterator { - [("constant", MediumLevelILOperand::Int(self.constant()))].into_iter() - } -} // EXTERN_PTR #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -399,97 +36,36 @@ pub struct ExternPtr { pub constant: u64, pub offset: u64, } -impl ExternPtr { - pub fn new(constant: u64, offset: u64) -> Self { - Self { constant, offset } - } - pub fn constant(&self) -> u64 { - self.constant - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn operands( - &self, - _function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("constant", MediumLevelILOperand::Int(self.constant())), - ("offset", MediumLevelILOperand::Int(self.offset())), - ] - .into_iter() - } -} // CONST_DATA #[derive(Copy, Clone)] pub struct ConstData { - constant_data: (u64, u64), + pub constant_data_kind: u32, + pub constant_data_value: i64, + pub size: usize, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct ConstantData { - //pub constant_data: !, -} -impl ConstData { - pub fn new(constant_data: (u64, u64)) -> Self { - Self { constant_data } - } - pub fn constant_data(&self, function: &MediumLevelILFunction, size: usize) -> ! { - get_constant_data(function, self.constant_data.0, self.constant_data.1, size) - } - pub fn lift(&self, _function: &MediumLevelILFunction) -> ConstantData { - ConstantData { - // TODO - } - } - pub fn operands( - &self, - _function: &MediumLevelILFunction, - ) -> impl Iterator { - // TODO - [ - //("contant_data", MediumLevelILOperand::ConstData(_self.constant_data(function, self.size))) - ] - .into_iter() - } +#[derive(Clone, Debug, Hash, PartialEq)] +pub struct LiftedConstData { + pub constant_data: ConstantData, } // JUMP, RET_HINT #[derive(Copy, Clone)] pub struct Jump { - dest: usize, + pub dest: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedJump { pub dest: Box, } -impl Jump { - pub fn new(dest: usize) -> Self { - Self { dest } - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedJump { - LiftedJump { - dest: Box::new(self.dest(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [("dest", MediumLevelILOperand::Expr(self.dest(function)))].into_iter() - } -} // STORE_SSA #[derive(Copy, Clone)] pub struct StoreSsa { - dest: usize, - dest_memory: u64, - src_memory: u64, - src: usize, + pub dest: usize, + pub dest_memory: u64, + pub src_memory: u64, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedStoreSsa { @@ -498,57 +74,15 @@ pub struct LiftedStoreSsa { pub src_memory: u64, pub src: Box, } -impl StoreSsa { - pub fn new(dest: usize, dest_memory: u64, src_memory: u64, src: usize) -> Self { - Self { - dest, - dest_memory, - src_memory, - src, - } - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn dest_memory(&self) -> u64 { - self.dest_memory - } - pub fn src_memory(&self) -> u64 { - self.src_memory - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStoreSsa { - LiftedStoreSsa { - dest: Box::new(self.dest(function).lift()), - dest_memory: self.dest_memory(), - src_memory: self.src_memory(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::Expr(self.dest(function))), - ("dest_memory", MediumLevelILOperand::Int(self.dest_memory())), - ("src_memory", MediumLevelILOperand::Int(self.src_memory())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // STORE_STRUCT_SSA #[derive(Copy, Clone)] pub struct StoreStructSsa { - dest: usize, - offset: u64, - dest_memory: u64, - src_memory: u64, - src: usize, + pub dest: usize, + pub offset: u64, + pub dest_memory: u64, + pub src_memory: u64, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedStoreStructSsa { @@ -558,61 +92,13 @@ pub struct LiftedStoreStructSsa { pub src_memory: u64, pub src: Box, } -impl StoreStructSsa { - pub fn new(dest: usize, offset: u64, dest_memory: u64, src_memory: u64, src: usize) -> Self { - Self { - dest, - offset, - dest_memory, - src_memory, - src, - } - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn dest_memory(&self) -> u64 { - self.dest_memory - } - pub fn src_memory(&self) -> u64 { - self.src_memory - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStoreStructSsa { - LiftedStoreStructSsa { - dest: Box::new(self.dest(function).lift()), - offset: self.offset(), - dest_memory: self.dest_memory(), - src_memory: self.src_memory(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::Expr(self.dest(function))), - ("offset", MediumLevelILOperand::Int(self.offset())), - ("dest_memory", MediumLevelILOperand::Int(self.dest_memory())), - ("src_memory", MediumLevelILOperand::Int(self.src_memory())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // STORE_STRUCT #[derive(Copy, Clone)] pub struct StoreStruct { - dest: usize, - offset: u64, - src: usize, + pub dest: usize, + pub offset: u64, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedStoreStruct { @@ -620,160 +106,50 @@ pub struct LiftedStoreStruct { pub offset: u64, pub src: Box, } -impl StoreStruct { - pub fn new(dest: usize, offset: u64, src: usize) -> Self { - Self { dest, offset, src } - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStoreStruct { - LiftedStoreStruct { - dest: Box::new(self.dest(function).lift()), - offset: self.offset(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::Expr(self.dest(function))), - ("offset", MediumLevelILOperand::Int(self.offset())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // STORE #[derive(Copy, Clone)] pub struct Store { - dest: usize, - src: usize, + pub dest: usize, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedStore { pub dest: Box, pub src: Box, } -impl Store { - pub fn new(dest: usize, src: usize) -> Self { - Self { dest, src } - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStore { - LiftedStore { - dest: Box::new(self.dest(function).lift()), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::Expr(self.dest(function))), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // JUMP_TO #[derive(Copy, Clone)] pub struct JumpTo { - dest: usize, - targets: (usize, usize), + pub dest: usize, + pub first_operand: usize, + pub num_operands: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedJumpTo { pub dest: Box, - pub targets: HashMap, -} -impl JumpTo { - pub fn new(dest: usize, targets: (usize, usize)) -> Self { - Self { dest, targets } - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn targets(&self, function: &MediumLevelILFunction) -> OperandDubleList { - OperandList::new(function, self.targets.1, self.targets.0).duble() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedJumpTo { - LiftedJumpTo { - dest: Box::new(self.dest(function).lift()), - targets: self.targets(function).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("dest", Expr(self.dest(function))), - ("targets", TargetMap(self.targets(function))), - ] - .into_iter() - } + pub targets: BTreeMap, } // GOTO -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Goto { pub dest: u64, } -impl Goto { - pub fn new(dest: u64) -> Self { - Self { dest } - } - pub fn dest(&self) -> u64 { - self.dest - } - pub fn operands(&self) -> impl Iterator { - [("dest", MediumLevelILOperand::Int(self.dest()))].into_iter() - } -} // FREE_VAR_SLOT #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct FreeVarSlot { pub dest: Variable, } -impl FreeVarSlot { - pub fn new(dest: u64) -> Self { - Self { - dest: get_var(dest), - } - } - pub fn dest(&self) -> Variable { - self.dest - } - pub fn operands(&self) -> impl Iterator { - [("dest", MediumLevelILOperand::Var(self.dest()))].into_iter() - } -} // SET_VAR_FIELD #[derive(Copy, Clone)] pub struct SetVarField { - dest: u64, - offset: u64, - src: usize, + pub dest: Variable, + pub offset: u64, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVarField { @@ -781,77 +157,18 @@ pub struct LiftedSetVarField { pub offset: u64, pub src: Box, } -impl SetVarField { - pub fn new(dest: u64, offset: u64, src: usize) -> Self { - Self { dest, offset, src } - } - pub fn dest(&self) -> Variable { - get_var(self.dest) - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarField { - LiftedSetVarField { - dest: self.dest(), - offset: self.offset(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::Var(self.dest())), - ("offset", MediumLevelILOperand::Int(self.offset())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // SET_VAR #[derive(Copy, Clone)] pub struct SetVar { - dest: u64, - src: usize, + pub dest: Variable, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVar { pub dest: Variable, pub src: Box, } -impl SetVar { - pub fn new(dest: u64, src: usize) -> Self { - Self { dest, src } - } - pub fn dest(&self) -> Variable { - get_var(self.dest) - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVar { - LiftedSetVar { - dest: self.dest(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::Var(self.dest())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // FREE_VAR_SLOT_SSA #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -859,41 +176,14 @@ pub struct FreeVarSlotSsa { pub dest: SSAVariable, pub prev: SSAVariable, } -impl FreeVarSlotSsa { - pub fn new(dest: (u64, usize), prev: (u64, usize)) -> Self { - Self { - dest: get_var_ssa(dest.0, dest.1), - prev: get_var_ssa(prev.0, prev.1), - } - } - pub fn dest(&self) -> SSAVariable { - self.dest - } - pub fn prev(&self) -> SSAVariable { - self.prev - } - pub fn lift(self) -> FreeVarSlotSsa { - FreeVarSlotSsa { - dest: self.dest(), - prev: self.prev(), - } - } - pub fn operands(&self) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::VarSsa(self.dest())), - ("prev", MediumLevelILOperand::VarSsa(self.prev())), - ] - .into_iter() - } -} // SET_VAR_SSA_FIELD, SET_VAR_ALIASED_FIELD #[derive(Copy, Clone)] pub struct SetVarSsaField { - dest: (u64, usize), - prev: (u64, usize), - offset: u64, - src: usize, + pub dest: SSAVariable, + pub prev: SSAVariable, + pub offset: u64, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVarSsaField { @@ -902,55 +192,13 @@ pub struct LiftedSetVarSsaField { pub offset: u64, pub src: Box, } -impl SetVarSsaField { - pub fn new(dest: (u64, usize), prev: (u64, usize), offset: u64, src: usize) -> Self { - Self { - dest, - prev, - offset, - src, - } - } - pub fn dest(&self) -> SSAVariable { - get_var_ssa(self.dest.0, self.dest.1) - } - pub fn prev(&self) -> SSAVariable { - get_var_ssa(self.prev.0, self.prev.1) - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSsaField { - LiftedSetVarSsaField { - dest: self.dest(), - prev: self.prev(), - offset: self.offset(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::VarSsa(self.dest())), - ("prev", MediumLevelILOperand::VarSsa(self.prev())), - ("offset", MediumLevelILOperand::Int(self.offset())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // SET_VAR_ALIASED #[derive(Copy, Clone)] pub struct SetVarAliased { - dest: (u64, usize), - prev: (u64, usize), - src: usize, + pub dest: SSAVariable, + pub prev: SSAVariable, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVarAliased { @@ -958,159 +206,44 @@ pub struct LiftedSetVarAliased { pub prev: SSAVariable, pub src: Box, } -impl SetVarAliased { - pub fn new(dest: (u64, usize), prev: (u64, usize), src: usize) -> Self { - Self { dest, prev, src } - } - pub fn dest(&self) -> SSAVariable { - get_var_ssa(self.dest.0, self.dest.1) - } - pub fn prev(&self) -> SSAVariable { - get_var_ssa(self.prev.0, self.prev.1) - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarAliased { - LiftedSetVarAliased { - dest: self.dest(), - prev: self.prev(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::VarSsa(self.dest())), - ("prev", MediumLevelILOperand::VarSsa(self.prev())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // SET_VAR_SSA #[derive(Copy, Clone)] pub struct SetVarSsa { - dest: (u64, usize), - src: usize, + pub dest: SSAVariable, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVarSsa { pub dest: SSAVariable, pub src: Box, } -impl SetVarSsa { - pub fn new(dest: (u64, usize), src: usize) -> Self { - Self { dest, src } - } - pub fn dest(&self) -> SSAVariable { - get_var_ssa(self.dest.0, self.dest.1) - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSsa { - LiftedSetVarSsa { - dest: self.dest(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::VarSsa(self.dest())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // VAR_PHI #[derive(Copy, Clone)] pub struct VarPhi { - dest: (u64, usize), - src: (usize, usize), + pub dest: SSAVariable, + pub first_operand: usize, + pub num_operands: usize, } #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct LiftedVarPhi { pub dest: SSAVariable, pub src: Vec, } -impl VarPhi { - pub fn new(dest: (u64, usize), src: (usize, usize)) -> Self { - Self { dest, src } - } - pub fn dest(&self) -> SSAVariable { - get_var_ssa(self.dest.0, self.dest.1) - } - pub fn src(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList { - OperandList::new(function, self.src.1, self.src.0).map_ssa_var() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedVarPhi { - LiftedVarPhi { - dest: self.dest(), - src: self.src(function).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("dest", MediumLevelILOperand::VarSsa(self.dest())), - ("src", MediumLevelILOperand::VarSsaList(self.src(function))), - ] - .into_iter() - } -} // MEM_PHI #[derive(Copy, Clone)] pub struct MemPhi { - dest_memory: u64, - src_memory: (usize, usize), + pub dest_memory: u64, + pub first_operand: usize, + pub num_operands: usize, } #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct LiftedMemPhi { pub dest_memory: u64, pub src_memory: Vec, } -impl MemPhi { - pub fn new(dest_memory: u64, src_memory: (usize, usize)) -> Self { - Self { - dest_memory, - src_memory, - } - } - pub fn dest_memory(&self) -> u64 { - self.dest_memory - } - pub fn src_memory(&self, function: &MediumLevelILFunction) -> OperandList { - OperandList::new(function, self.src_memory.1, self.src_memory.0) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedMemPhi { - LiftedMemPhi { - dest_memory: self.dest_memory(), - src_memory: self.src_memory(function).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("dest_memory", Int(self.dest_memory())), - ("src_memory", IntList(self.src_memory(function))), - ] - .into_iter() - } -} // VAR_SPLIT #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -1118,40 +251,13 @@ pub struct VarSplit { pub high: Variable, pub low: Variable, } -impl VarSplit { - pub fn new(high: u64, low: u64) -> Self { - Self { - high: get_var(high), - low: get_var(low), - } - } - pub fn high(&self) -> Variable { - self.high - } - pub fn low(&self) -> Variable { - self.low - } - pub fn lift(self) -> VarSplit { - VarSplit { - high: self.high(), - low: self.low(), - } - } - pub fn operands(&self) -> impl Iterator { - [ - ("high", MediumLevelILOperand::Var(self.high())), - ("low", MediumLevelILOperand::Var(self.low())), - ] - .into_iter() - } -} // SET_VAR_SPLIT #[derive(Copy, Clone)] pub struct SetVarSplit { - high: u64, - low: u64, - src: usize, + pub high: Variable, + pub low: Variable, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVarSplit { @@ -1159,38 +265,6 @@ pub struct LiftedSetVarSplit { pub low: Variable, pub src: Box, } -impl SetVarSplit { - pub fn new(high: u64, low: u64, src: usize) -> Self { - Self { high, low, src } - } - pub fn high(&self) -> Variable { - get_var(self.high) - } - pub fn low(&self) -> Variable { - get_var(self.low) - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSplit { - LiftedSetVarSplit { - high: self.high(), - low: self.low(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("high", MediumLevelILOperand::Var(self.high())), - ("low", MediumLevelILOperand::Var(self.low())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // VAR_SPLIT_SSA #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -1198,40 +272,13 @@ pub struct VarSplitSsa { pub high: SSAVariable, pub low: SSAVariable, } -impl VarSplitSsa { - pub fn new(high: (u64, usize), low: (u64, usize)) -> Self { - Self { - high: get_var_ssa(high.0, high.1), - low: get_var_ssa(low.0, low.1), - } - } - pub fn high(&self) -> SSAVariable { - self.high - } - pub fn low(&self) -> SSAVariable { - self.low - } - pub fn lift(self) -> VarSplitSsa { - VarSplitSsa { - high: self.high(), - low: self.low(), - } - } - pub fn operands(&self) -> impl Iterator { - [ - ("high", MediumLevelILOperand::VarSsa(self.high())), - ("low", MediumLevelILOperand::VarSsa(self.low())), - ] - .into_iter() - } -} // SET_VAR_SPLIT_SSA #[derive(Copy, Clone)] pub struct SetVarSplitSsa { - high: (u64, usize), - low: (u64, usize), - src: usize, + pub high: SSAVariable, + pub low: SSAVariable, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSetVarSplitSsa { @@ -1239,84 +286,25 @@ pub struct LiftedSetVarSplitSsa { pub low: SSAVariable, pub src: Box, } -impl SetVarSplitSsa { - pub fn new(high: (u64, usize), low: (u64, usize), src: usize) -> Self { - Self { high, low, src } - } - pub fn high(&self) -> SSAVariable { - get_var_ssa(self.high.0, self.high.1) - } - pub fn low(&self) -> SSAVariable { - get_var_ssa(self.low.0, self.low.1) - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSplitSsa { - LiftedSetVarSplitSsa { - high: self.high(), - low: self.low(), - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("high", MediumLevelILOperand::VarSsa(self.high())), - ("low", MediumLevelILOperand::VarSsa(self.low())), - ("src", MediumLevelILOperand::Expr(self.src(function))), - ] - .into_iter() - } -} // ADD, SUB, AND, OR, XOR, LSL, LSR, ASR, ROL, ROR, MUL, MULU_DP, MULS_DP, DIVU, DIVU_DP, DIVS, DIVS_DP, MODU, MODU_DP, MODS, MODS_DP, CMP_E, CMP_NE, CMP_SLT, CMP_ULT, CMP_SLE, CMP_ULE, CMP_SGE, CMP_UGE, CMP_SGT, CMP_UGT, TEST_BIT, ADD_OVERFLOW, FCMP_E, FCMP_NE, FCMP_LT, FCMP_LE, FCMP_GE, FCMP_GT, FCMP_O, FCMP_UO, FADD, FSUB, FMUL, FDIV #[derive(Copy, Clone)] pub struct BinaryOp { - left: usize, - right: usize, + pub left: usize, + pub right: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedBinaryOp { pub left: Box, pub right: Box, } -impl BinaryOp { - pub fn new(left: usize, right: usize) -> Self { - Self { left, right } - } - pub fn left(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.left) - } - pub fn right(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.right) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedBinaryOp { - LiftedBinaryOp { - left: Box::new(self.left(function).lift()), - right: Box::new(self.right(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("left", MediumLevelILOperand::Expr(self.left(function))), - ("right", MediumLevelILOperand::Expr(self.right(function))), - ] - .into_iter() - } -} // ADC, SBB, RLC, RRC #[derive(Copy, Clone)] pub struct BinaryOpCarry { - left: usize, - right: usize, - carry: usize, + pub left: usize, + pub right: usize, + pub carry: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedBinaryOpCarry { @@ -1324,45 +312,15 @@ pub struct LiftedBinaryOpCarry { pub right: Box, pub carry: Box, } -impl BinaryOpCarry { - pub fn new(left: usize, right: usize, carry: usize) -> Self { - Self { left, right, carry } - } - pub fn left(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.left) - } - pub fn right(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.right) - } - pub fn carry(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.carry) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedBinaryOpCarry { - LiftedBinaryOpCarry { - left: Box::new(self.left(function).lift()), - right: Box::new(self.right(function).lift()), - carry: Box::new(self.carry(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("left", MediumLevelILOperand::Expr(self.left(function))), - ("right", MediumLevelILOperand::Expr(self.right(function))), - ("carry", MediumLevelILOperand::Expr(self.carry(function))), - ] - .into_iter() - } -} // CALL, TAILCALL #[derive(Copy, Clone)] pub struct Call { - output: (usize, usize), - dest: usize, - params: (usize, usize), + pub first_output: usize, + pub num_outputs: usize, + pub dest: usize, + pub first_param: usize, + pub num_params: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedCall { @@ -1370,197 +328,61 @@ pub struct LiftedCall { pub dest: Box, pub params: Vec, } -impl Call { - pub fn new(output: (usize, usize), dest: usize, params: (usize, usize)) -> Self { - Self { - output, - dest, - params, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList { - OperandList::new(function, self.output.1, self.output.0).map_var() - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCall { - LiftedCall { - output: self.output(function).collect(), - dest: Box::new(self.dest(function).lift()), - params: self.params(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ( - "output", - MediumLevelILOperand::VarList(self.output(function)), - ), - ("dest", MediumLevelILOperand::Expr(self.dest(function))), - ( - "params", - MediumLevelILOperand::ExprList(self.params(function)), - ), - ] - .into_iter() - } -} // SYSCALL #[derive(Copy, Clone)] pub struct Syscall { - output: (usize, usize), - params: (usize, usize), + pub first_output: usize, + pub num_outputs: usize, + pub first_param: usize, + pub num_params: usize, } #[derive(Clone, Debug, PartialEq)] -pub struct LiftedInnerCall { +pub struct LiftedSyscallCall { pub output: Vec, pub params: Vec, } -impl Syscall { - pub fn new(output: (usize, usize), params: (usize, usize)) -> Self { - Self { output, params } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList { - OperandList::new(function, self.output.1, self.output.0).map_var() - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedInnerCall { - LiftedInnerCall { - output: self.output(function).collect(), - params: self.params(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarList(self.output(function))), - ("params", ExprList(self.params(function))), - ] - .into_iter() - } -} // INTRINSIC #[derive(Copy, Clone)] pub struct Intrinsic { - output: (usize, usize), - intrinsic: usize, - params: (usize, usize), + pub first_output: usize, + pub num_outputs: usize, + pub intrinsic: u32, + pub first_param: usize, + pub num_params: usize, } #[derive(Clone, Debug, PartialEq)] -pub struct MediumLevelILLiftedIntrinsic { +pub struct LiftedIntrinsic { pub output: Vec, - //pub intrinsic: !, + pub intrinsic: ILIntrinsic, pub params: Vec, } -impl Intrinsic { - pub fn new(output: (usize, usize), intrinsic: usize, params: (usize, usize)) -> Self { - Self { - output, - intrinsic, - params, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList { - OperandList::new(function, self.output.1, self.output.0).map_var() - } - pub fn intrinsic(&self, function: &MediumLevelILFunction) -> ! { - get_intrinsic(function, self.intrinsic) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedInnerCall { - LiftedInnerCall { - output: self.output(function).collect(), - //intrinsic: get_intrinsic(function, self.intrinsic), - params: self.params(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarList(self.output(function))), - //("intrinsic", VarList(self.output(function))), - ("params", ExprList(self.params(function))), - ] - .into_iter() - } -} // INTRINSIC_SSA #[derive(Copy, Clone)] pub struct IntrinsicSsa { - output: (usize, usize), - intrinsic: usize, - params: (usize, usize), + pub first_output: usize, + pub num_outputs: usize, + pub intrinsic: u32, + pub first_param: usize, + pub num_params: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedIntrinsicSsa { pub output: Vec, - //pub intrinsic: !, + pub intrinsic: ILIntrinsic, pub params: Vec, } -impl IntrinsicSsa { - pub fn new(output: (usize, usize), intrinsic: usize, params: (usize, usize)) -> Self { - Self { - output, - intrinsic, - params, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList { - OperandList::new(function, self.output.1, self.output.0).map_ssa_var() - } - pub fn intrinsic(&self, function: &MediumLevelILFunction) -> ! { - get_intrinsic(function, self.intrinsic) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedIntrinsicSsa { - LiftedIntrinsicSsa { - output: self.output(function).collect(), - //intrinsic: get_intrinsic(function, self.intrinsic), - params: self.params(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarSsaList(self.output(function))), - ("params", ExprList(self.params(function))), - ] - .into_iter() - } -} // CALL_SSA, TAILCALL_SSA #[derive(Copy, Clone)] pub struct CallSsa { - output: usize, - dest: usize, - params: (usize, usize), - src_memory: u64, + pub output: usize, + pub dest: usize, + pub first_param: usize, + pub num_params: usize, + pub src_memory: u64, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedCallSsa { @@ -1569,57 +391,14 @@ pub struct LiftedCallSsa { pub params: Vec, pub src_memory: u64, } -impl CallSsa { - pub fn new(output: usize, dest: usize, params: (usize, usize), src_memory: u64) -> Self { - Self { - output, - dest, - params, - src_memory, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList { - get_call_output_ssa(function, self.output) - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn src_memory(&self) -> u64 { - self.src_memory - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCallSsa { - LiftedCallSsa { - output: self.output(function).collect(), - dest: Box::new(self.dest(function).lift()), - params: self.params(function).map(|instr| instr.lift()).collect(), - src_memory: self.src_memory(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarSsaList(self.output(function))), - ("dest", Expr(self.dest(function))), - ("params", ExprList(self.params(function))), - ("src_memory", Int(self.src_memory())), - ] - .into_iter() - } -} // CALL_UNTYPED_SSA, TAILCALL_UNTYPED_SSA #[derive(Copy, Clone)] pub struct CallUntypedSsa { - output: usize, - dest: usize, - params: usize, - stack: usize, + pub output: usize, + pub dest: usize, + pub params: usize, + pub stack: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedCallUntypedSsa { @@ -1628,56 +407,14 @@ pub struct LiftedCallUntypedSsa { pub params: Vec, pub stack: Box, } -impl CallUntypedSsa { - pub fn new(output: usize, dest: usize, params: usize, stack: usize) -> Self { - Self { - output, - dest, - params, - stack, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList { - get_call_output_ssa(function, self.output) - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - get_call_params_ssa(function, self.params) - } - pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.stack) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCallUntypedSsa { - LiftedCallUntypedSsa { - output: self.output(function).collect(), - dest: Box::new(self.dest(function).lift()), - params: self.params(function).map(|instr| instr.lift()).collect(), - stack: Box::new(self.stack(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarSsaList(self.output(function))), - ("dest", Expr(self.dest(function))), - ("params", ExprList(self.params(function))), - ("stack", Expr(self.stack(function))), - ] - .into_iter() - } -} // SYSCALL_SSA #[derive(Copy, Clone)] pub struct SyscallSsa { - output: usize, - params: (usize, usize), - src_memory: u64, + pub output: usize, + pub first_param: usize, + pub num_params: usize, + pub src_memory: u64, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSyscallSsa { @@ -1685,50 +422,13 @@ pub struct LiftedSyscallSsa { pub params: Vec, pub src_memory: u64, } -impl SyscallSsa { - pub fn new(output: usize, params: (usize, usize), src_memory: u64) -> Self { - Self { - output, - params, - src_memory, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList { - get_call_output_ssa(function, self.output) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn src_memory(&self) -> u64 { - self.src_memory - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSyscallSsa { - LiftedSyscallSsa { - output: self.output(function).collect(), - params: self.params(function).map(|instr| instr.lift()).collect(), - src_memory: self.src_memory(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarSsaList(self.output(function))), - ("params", ExprList(self.params(function))), - ("src_memory", MediumLevelILOperand::Int(self.src_memory())), - ] - .into_iter() - } -} // SYSCALL_UNTYPED_SSA #[derive(Copy, Clone)] pub struct SyscallUntypedSsa { - output: usize, - params: usize, - stack: usize, + pub output: usize, + pub params: usize, + pub stack: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSyscallUntypedSsa { @@ -1736,51 +436,14 @@ pub struct LiftedSyscallUntypedSsa { pub params: Vec, pub stack: Box, } -impl SyscallUntypedSsa { - pub fn new(output: usize, params: usize, stack: usize) -> Self { - Self { - output, - params, - stack, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList { - get_call_output_ssa(function, self.output) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - get_call_params_ssa(function, self.params) - } - pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.stack) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSyscallUntypedSsa { - LiftedSyscallUntypedSsa { - output: self.output(function).collect(), - params: self.params(function).map(|instr| instr.lift()).collect(), - stack: Box::new(self.stack(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarSsaList(self.output(function))), - ("params", ExprList(self.params(function))), - ("stack", Expr(self.stack(function))), - ] - .into_iter() - } -} // CALL_UNTYPED, TAILCALL_UNTYPED #[derive(Copy, Clone)] pub struct CallUntyped { - output: usize, - dest: usize, - params: usize, - stack: usize, + pub output: usize, + pub dest: usize, + pub params: usize, + pub stack: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedCallUntyped { @@ -1789,56 +452,13 @@ pub struct LiftedCallUntyped { pub params: Vec, pub stack: Box, } -impl CallUntyped { - pub fn new(output: usize, dest: usize, params: usize, stack: usize) -> Self { - Self { - output, - dest, - params, - stack, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList { - get_call_output(function, self.output) - } - pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.dest) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - get_call_params(function, self.params) - } - pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.stack) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCallUntyped { - LiftedCallUntyped { - output: self.output(function).collect(), - dest: Box::new(self.dest(function).lift()), - params: self.params(function).map(|instr| instr.lift()).collect(), - stack: Box::new(self.stack(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarList(self.output(function))), - ("dest", Expr(self.dest(function))), - ("params", ExprList(self.params(function))), - ("stack", Expr(self.stack(function))), - ] - .into_iter() - } -} // SYSCALL_UNTYPED #[derive(Copy, Clone)] pub struct SyscallUntyped { - output: usize, - params: usize, - stack: usize, + pub output: usize, + pub params: usize, + pub stack: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSyscallUntyped { @@ -1846,118 +466,35 @@ pub struct LiftedSyscallUntyped { pub params: Vec, pub stack: Box, } -impl SyscallUntyped { - pub fn new(output: usize, params: usize, stack: usize) -> Self { - Self { - output, - params, - stack, - } - } - pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList { - get_call_output(function, self.output) - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - get_call_params(function, self.params) - } - pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.stack) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSyscallUntyped { - LiftedSyscallUntyped { - output: self.output(function).collect(), - params: self.params(function).map(|instr| instr.lift()).collect(), - stack: Box::new(self.stack(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - use MediumLevelILOperand::*; - [ - ("output", VarList(self.output(function))), - ("params", ExprList(self.params(function))), - ("stack", Expr(self.stack(function))), - ] - .into_iter() - } -} // NEG, NOT, SX, ZX, LOW_PART, BOOL_TO_INT, UNIMPL_MEM, FSQRT, FNEG, FABS, FLOAT_TO_INT, INT_TO_FLOAT, FLOAT_CONV, ROUND_TO_INT, FLOOR, CEIL, FTRUNC, LOAD #[derive(Copy, Clone)] pub struct UnaryOp { - src: usize, + pub src: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedUnaryOp { pub src: Box, } -impl UnaryOp { - pub fn new(src: usize) -> Self { - Self { src } - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedUnaryOp { - LiftedUnaryOp { - src: Box::new(self.src(function).lift()), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [("src", MediumLevelILOperand::Expr(self.src(function)))].into_iter() - } -} // LOAD_STRUCT #[derive(Copy, Clone)] pub struct LoadStruct { - src: usize, - offset: u64, + pub src: usize, + pub offset: u64, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedLoadStruct { pub src: Box, pub offset: u64, } -impl LoadStruct { - pub fn new(src: usize, offset: u64) -> Self { - Self { src, offset } - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedLoadStruct { - LiftedLoadStruct { - src: Box::new(self.src(function).lift()), - offset: self.offset(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("src", MediumLevelILOperand::Expr(self.src(function))), - ("offset", MediumLevelILOperand::Int(self.offset())), - ] - .into_iter() - } -} // LOAD_STRUCT_SSA #[derive(Copy, Clone)] pub struct LoadStructSsa { - src: usize, - offset: u64, - src_memory: u64, + pub src: usize, + pub offset: u64, + pub src_memory: u64, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedLoadStructSsa { @@ -1965,185 +502,57 @@ pub struct LiftedLoadStructSsa { pub offset: u64, pub src_memory: u64, } -impl LoadStructSsa { - pub fn new(src: usize, offset: u64, src_memory: u64) -> Self { - Self { - src, - offset, - src_memory, - } - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn src_memory(&self) -> u64 { - self.src_memory - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedLoadStructSsa { - LiftedLoadStructSsa { - src: Box::new(self.src(function).lift()), - offset: self.offset(), - src_memory: self.src_memory(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("src", MediumLevelILOperand::Expr(self.src(function))), - ("offset", MediumLevelILOperand::Int(self.offset())), - ("src_memory", MediumLevelILOperand::Int(self.src_memory())), - ] - .into_iter() - } -} // LOAD_SSA #[derive(Copy, Clone)] pub struct LoadSsa { - src: usize, - src_memory: u64, + pub src: usize, + pub src_memory: u64, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedLoadSsa { pub src: Box, pub src_memory: u64, } -impl LoadSsa { - pub fn new(src: usize, src_memory: u64) -> Self { - Self { src, src_memory } - } - pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction { - get_operation(function, self.src) - } - pub fn src_memory(&self) -> u64 { - self.src_memory - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedLoadSsa { - LiftedLoadSsa { - src: Box::new(self.src(function).lift()), - src_memory: self.src_memory(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [ - ("src", MediumLevelILOperand::Expr(self.src(function))), - ("src_memory", MediumLevelILOperand::Int(self.src_memory())), - ] - .into_iter() - } -} // RET #[derive(Copy, Clone)] pub struct Ret { - src: (usize, usize), + pub first_operand: usize, + pub num_operands: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedRet { pub src: Vec, } -impl Ret { - pub fn new(src: (usize, usize)) -> Self { - Self { src } - } - pub fn src(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.src.1, self.src.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedRet { - LiftedRet { - src: self.src(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [("src", MediumLevelILOperand::ExprList(self.src(function)))].into_iter() - } -} // SEPARATE_PARAM_LIST #[derive(Copy, Clone)] pub struct SeparateParamList { - params: (usize, usize), + pub first_param: usize, + pub num_params: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSeparateParamList { pub params: Vec, } -impl SeparateParamList { - pub fn new(params: (usize, usize)) -> Self { - Self { params } - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSeparateParamList { - LiftedSeparateParamList { - params: self.params(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [("params", MediumLevelILOperand::ExprList(self.params(function)))].into_iter() - } -} // SHARED_PARAM_SLOT #[derive(Copy, Clone)] pub struct SharedParamSlot { - params: (usize, usize), + pub first_param: usize, + pub num_params: usize, } #[derive(Clone, Debug, PartialEq)] pub struct LiftedSharedParamSlot { pub params: Vec, } -impl SharedParamSlot { - pub fn new(params: (usize, usize)) -> Self { - Self { params } - } - pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList { - OperandList::new(function, self.params.1, self.params.0).map_expr() - } - pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSharedParamSlot { - LiftedSharedParamSlot { - params: self.params(function).map(|instr| instr.lift()).collect(), - } - } - pub fn operands( - &self, - function: &MediumLevelILFunction, - ) -> impl Iterator { - [("params", MediumLevelILOperand::ExprList(self.params(function)))].into_iter() - } -} // VAR, ADDRESS_OF #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Var { pub src: Variable, } -impl Var { - pub fn new(src: u64) -> Self { - Self { src: get_var(src) } - } - pub fn src(&self) -> Variable { - self.src - } - pub fn operands(&self) -> impl Iterator { - [("src", MediumLevelILOperand::Var(self.src()))].into_iter() - } -} // VAR_FIELD, ADDRESS_OF_FIELD #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -2151,46 +560,12 @@ pub struct Field { pub src: Variable, pub offset: u64, } -impl Field { - pub fn new(src: u64, offset: u64) -> Self { - Self { - src: get_var(src), - offset, - } - } - pub fn src(&self) -> Variable { - self.src - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn operands(&self) -> impl Iterator { - [ - ("src", MediumLevelILOperand::Var(self.src())), - ("offset", MediumLevelILOperand::Int(self.offset())), - ] - .into_iter() - } -} // VAR_SSA, VAR_ALIASED #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct VarSsa { pub src: SSAVariable, } -impl VarSsa { - pub fn new(src: (u64, usize)) -> Self { - Self { - src: get_var_ssa(src.0, src.1), - } - } - pub fn src(&self) -> SSAVariable { - self.src - } - pub fn operands(&self) -> impl Iterator { - [("src", MediumLevelILOperand::VarSsa(self.src()))].into_iter() - } -} // VAR_SSA_FIELD, VAR_ALIASED_FIELD #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -2198,41 +573,9 @@ pub struct VarSsaField { pub src: SSAVariable, pub offset: u64, } -impl VarSsaField { - pub fn new(src: (u64, usize), offset: u64) -> Self { - Self { - src: get_var_ssa(src.0, src.1), - offset, - } - } - pub fn src(&self) -> SSAVariable { - self.src - } - pub fn offset(&self) -> u64 { - self.offset - } - pub fn operands(&self) -> impl Iterator { - [ - ("src", MediumLevelILOperand::VarSsa(self.src())), - ("offset", MediumLevelILOperand::Int(self.offset())), - ] - .into_iter() - } -} // TRAP #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Trap { pub vector: u64, } -impl Trap { - pub fn new(vector: u64) -> Self { - Self { vector } - } - pub fn vector(&self) -> u64 { - self.vector - } - pub fn operands(&self) -> impl Iterator { - [("vector", MediumLevelILOperand::Int(self.vector()))].into_iter() - } -} diff --git a/src/operand_iter.rs b/src/operand_iter.rs new file mode 100644 index 0000000..5f0fbd8 --- /dev/null +++ b/src/operand_iter.rs @@ -0,0 +1,223 @@ +use binaryninjacore_sys::BNFromVariableIdentifier; +use binaryninjacore_sys::BNGetHighLevelILByIndex; +use binaryninjacore_sys::BNGetMediumLevelILByIndex; +use binaryninjacore_sys::BNHighLevelILOperation; +use binaryninjacore_sys::BNMediumLevelILOperation; + +use crate::hlil::{HighLevelILFunction, HighLevelILInstruction}; +use crate::mlil::{MediumLevelILFunction, MediumLevelILInstruction}; +use crate::rc::{Ref, RefCountable}; +use crate::types::{SSAVariable, Variable}; + +pub trait ILFunction { + type Instruction; + + fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction; + fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5]; +} + +impl ILFunction for MediumLevelILFunction { + type Instruction = MediumLevelILInstruction; + + fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction { + self.instruction_from_idx(expr_idx) + } + + fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5] { + let node = unsafe { BNGetMediumLevelILByIndex(self.handle, expr_idx) }; + assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); + node.operands + } +} + +impl ILFunction for HighLevelILFunction { + type Instruction = HighLevelILInstruction; + + fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction { + self.instruction_from_idx(expr_idx) + } + + fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5] { + let node = unsafe { BNGetHighLevelILByIndex(self.handle, expr_idx, self.full_ast) }; + assert_eq!(node.operation, BNHighLevelILOperation::HLIL_UNDEF); + node.operands + } +} + +pub struct OperandIter { + function: Ref, + remaining: usize, + next_iter_idx: Option, + current_iter: OperandIterInner, +} + +impl OperandIter { + pub(crate) fn new(function: &F, idx: usize, number: usize) -> Self { + // Zero-length lists immediately finish iteration + let next_iter_idx = if number > 0 { Some(idx) } else { None }; + Self { + function: function.to_owned(), + remaining: number, + next_iter_idx, + current_iter: OperandIterInner::empty(), + } + } + + pub fn pairs(self) -> OperandPairIter { + assert_eq!(self.len() % 2, 0); + OperandPairIter(self) + } + + pub fn exprs(self) -> OperandExprIter { + OperandExprIter(self) + } + + pub fn vars(self) -> OperandVarIter { + OperandVarIter(self) + } + + pub fn ssa_vars(self) -> OperandSSAVarIter { + OperandSSAVarIter(self.pairs()) + } +} + +impl Iterator for OperandIter { + type Item = u64; + fn next(&mut self) -> Option { + if let Some(item) = self.current_iter.next() { + self.remaining -= 1; + Some(item) + } else { + // Will short-circuit and return `None` once iter is exhausted + let iter_idx = self.next_iter_idx?; + let operands = self.function.operands_from_idx(iter_idx); + + let next = if self.remaining > 4 { + self.next_iter_idx = Some(operands[4] as usize); + &operands[..4] + } else { + self.next_iter_idx = None; + &operands[..self.remaining] + }; + + self.current_iter = OperandIterInner::from_slice(next); + self.next() + } + } +} +impl ExactSizeIterator for OperandIter { + fn len(&self) -> usize { + self.remaining + self.current_iter.len() + } +} + +struct OperandIterInner { + arr: [u64; 4], + idx: usize, +} + +impl OperandIterInner { + fn from_slice(slice: &[u64]) -> Self { + assert!(slice.len() <= 4); + let idx = 4 - slice.len(); + let mut arr = [0; 4]; + arr[idx..].copy_from_slice(slice); + Self { arr, idx } + } + + fn empty() -> Self { + Self { + arr: [0; 4], + idx: 4, + } + } +} + +impl Iterator for OperandIterInner { + type Item = u64; + + fn next(&mut self) -> Option { + if self.idx < 4 { + let val = self.arr[self.idx]; + self.idx += 1; + Some(val) + } else { + None + } + } +} +impl ExactSizeIterator for OperandIterInner { + fn len(&self) -> usize { + 4 - self.idx + } +} + +pub struct OperandPairIter(OperandIter); +impl Iterator for OperandPairIter { + type Item = (u64, u64); + + fn next(&mut self) -> Option { + let first = self.0.next()?; + let second = self.0.next()?; + Some((first, second)) + } +} +impl ExactSizeIterator for OperandPairIter { + fn len(&self) -> usize { + self.0.len() / 2 + } +} + +pub struct OperandExprIter(OperandIter); +impl Iterator for OperandExprIter { + type Item = F::Instruction; + + fn next(&mut self) -> Option { + self.0 + .next() + .map(|idx| self.0.function.il_instruction_from_idx(idx as usize)) + } +} +impl ExactSizeIterator for OperandExprIter { + fn len(&self) -> usize { + self.0.len() + } +} + +pub struct OperandVarIter(OperandIter); +impl Iterator for OperandVarIter { + type Item = Variable; + + fn next(&mut self) -> Option { + self.0.next().map(get_var) + } +} +impl ExactSizeIterator for OperandVarIter { + fn len(&self) -> usize { + self.0.len() + } +} + +pub struct OperandSSAVarIter(OperandPairIter); +impl Iterator for OperandSSAVarIter { + type Item = SSAVariable; + + fn next(&mut self) -> Option { + self.0 + .next() + .map(|(id, version)| get_var_ssa(id, version as usize)) + } +} +impl ExactSizeIterator for OperandSSAVarIter { + fn len(&self) -> usize { + self.0.len() + } +} + +pub fn get_var(id: u64) -> Variable { + unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } +} + +pub fn get_var_ssa(id: u64, version: usize) -> SSAVariable { + SSAVariable::new(get_var(id), version) +} diff --git a/src/relocation.rs b/src/relocation.rs index 7be7861..f9cbb3c 100644 --- a/src/relocation.rs +++ b/src/relocation.rs @@ -172,6 +172,12 @@ impl RelocationInfo { } } +impl Default for RelocationInfo { + fn default() -> Self { + Self::new() + } +} + pub struct Relocation(*mut BNRelocation); impl Relocation { @@ -430,7 +436,7 @@ where let result = unsafe { core::slice::from_raw_parts_mut(result, count) }; let mut info = result .iter() - .map(|i| RelocationInfo::from_raw(i)) + .map(RelocationInfo::from_raw) .collect::>(); let ok = custom_handler.get_relocation_info(bv.as_ref(), arch.as_ref(), info.as_mut_slice()); @@ -549,9 +555,7 @@ where R: 'static + RelocationHandler + Send + Sync, { fn clone(&self) -> Self { - Self { - handle: self.handle, - } + *self } } diff --git a/src/types.rs b/src/types.rs index 2d67522..5463ce3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -23,6 +23,7 @@ use crate::{ binaryview::{BinaryView, BinaryViewExt}, callingconvention::CallingConvention, filemetadata::FileMetadata, + function::Function, rc::*, string::{raw_to_string, BnStr, BnStrCompatible, BnString}, symbol::Symbol, @@ -2585,6 +2586,161 @@ impl DataVariableAndName { } } +///////////////////////// +// ILIntrinsic + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ILIntrinsic { + arch: CoreArchitecture, + index: u32, +} + +impl ILIntrinsic { + pub(crate) fn new(arch: CoreArchitecture, index: u32) -> Self { + Self { arch, index } + } + + pub fn name(&self) -> &str { + let name_ptr = unsafe { BNGetArchitectureIntrinsicName(self.arch.0, self.index) }; + let name_raw = unsafe { core::ffi::CStr::from_ptr(name_ptr) }; + name_raw.to_str().unwrap() + } + + // TODO impl inputs and outputs function +} + +///////////////////////// +// RegisterValueType + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum RegisterValueType { + UndeterminedValue, + EntryValue, + ConstantValue, + ConstantPointerValue, + ExternalPointerValue, + StackFrameOffset, + ReturnAddressValue, + ImportedAddressValue, + SignedRangeValue, + UnsignedRangeValue, + LookupTableValue, + InSetOfValues, + NotInSetOfValues, + ConstantDataValue, + ConstantDataZeroExtendValue, + ConstantDataSignExtendValue, + ConstantDataAggregateValue, +} + +impl RegisterValueType { + pub(crate) fn from_raw_value(value: u32) -> Option { + use BNRegisterValueType::*; + Some(match value { + x if x == UndeterminedValue as u32 => Self::UndeterminedValue, + x if x == EntryValue as u32 => Self::EntryValue, + x if x == ConstantValue as u32 => Self::ConstantValue, + x if x == ConstantPointerValue as u32 => Self::ConstantPointerValue, + x if x == ExternalPointerValue as u32 => Self::ExternalPointerValue, + x if x == StackFrameOffset as u32 => Self::StackFrameOffset, + x if x == ReturnAddressValue as u32 => Self::ReturnAddressValue, + x if x == ImportedAddressValue as u32 => Self::ImportedAddressValue, + x if x == SignedRangeValue as u32 => Self::SignedRangeValue, + x if x == UnsignedRangeValue as u32 => Self::UnsignedRangeValue, + x if x == LookupTableValue as u32 => Self::LookupTableValue, + x if x == InSetOfValues as u32 => Self::InSetOfValues, + x if x == NotInSetOfValues as u32 => Self::NotInSetOfValues, + x if x == ConstantDataValue as u32 => Self::ConstantDataValue, + x if x == ConstantDataZeroExtendValue as u32 => Self::ConstantDataZeroExtendValue, + x if x == ConstantDataSignExtendValue as u32 => Self::ConstantDataSignExtendValue, + x if x == ConstantDataAggregateValue as u32 => Self::ConstantDataAggregateValue, + _ => return None, + }) + } + + pub(crate) fn into_raw_value(self) -> BNRegisterValueType { + use BNRegisterValueType::*; + match self { + Self::UndeterminedValue => UndeterminedValue, + Self::EntryValue => EntryValue, + Self::ConstantValue => ConstantValue, + Self::ConstantPointerValue => ConstantPointerValue, + Self::ExternalPointerValue => ExternalPointerValue, + Self::StackFrameOffset => StackFrameOffset, + Self::ReturnAddressValue => ReturnAddressValue, + Self::ImportedAddressValue => ImportedAddressValue, + Self::SignedRangeValue => SignedRangeValue, + Self::UnsignedRangeValue => UnsignedRangeValue, + Self::LookupTableValue => LookupTableValue, + Self::InSetOfValues => InSetOfValues, + Self::NotInSetOfValues => NotInSetOfValues, + Self::ConstantDataValue => ConstantDataValue, + Self::ConstantDataZeroExtendValue => ConstantDataZeroExtendValue, + Self::ConstantDataSignExtendValue => ConstantDataSignExtendValue, + Self::ConstantDataAggregateValue => ConstantDataAggregateValue, + } + } +} + +///////////////////////// +// RegisterValue + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct RegisterValue { + pub(crate) state: RegisterValueType, + pub(crate) value: i64, + pub(crate) offset: i64, + pub(crate) size: usize, +} + +impl RegisterValue { + pub fn new(state: RegisterValueType, value: i64, offset: i64, size: usize) -> Self { + Self { + state, + value, + offset, + size, + } + } +} + +impl From for RegisterValue { + fn from(value: BNRegisterValue) -> Self { + Self { + state: RegisterValueType::from_raw_value(value.state as u32).unwrap(), + value: value.value, + offset: value.offset, + size: value.size, + } + } +} + +impl From for BNRegisterValue { + fn from(value: RegisterValue) -> Self { + Self { + state: value.state.into_raw_value(), + value: value.value, + offset: value.offset, + size: value.size, + } + } +} + +///////////////////////// +// ConstantData + +#[derive(Clone, Debug, PartialEq, Hash)] +pub struct ConstantData { + function: Ref, + value: RegisterValue, +} + +impl ConstantData { + pub(crate) fn new(function: Ref, value: RegisterValue) -> Self { + Self { function, value } + } +} + // unsafe impl CoreArrayProvider for DataVariableAndName { // type Raw = BNDataVariableAndName; // type Context = ();