This commit is contained in:
Rairosu
2024-04-02 18:52:06 +02:00
parent e7c2b2bd2a
commit 2feb739d75
42 changed files with 4785 additions and 2675 deletions

View File

@@ -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

333
Cargo.lock generated
View File

@@ -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",
]

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -6,5 +6,5 @@ edition = "2021"
[dependencies]
binaryninja = {path="../../"}
clap = { version = "4.3", features = ["derive"] }
clap = { version = "4.4", features = ["derive"] }

View File

@@ -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"] }

View File

@@ -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"

View File

@@ -10,4 +10,4 @@ crate-type = ["cdylib"]
[dependencies]
dwarfreader = { path = "../shared/" }
binaryninja = {path="../../../"}
gimli = "0.27"
gimli = "0.28"

View File

@@ -6,4 +6,4 @@ edition = "2021"
[dependencies]
binaryninja = {path="../../../"}
gimli = "0.27"
gimli = "0.28"

View File

@@ -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"}

View File

@@ -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());
}
}

View File

@@ -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();
}

View File

@@ -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"}

View File

@@ -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());
}
}

View File

@@ -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!("{:<indent$}", "")
}
fn print_operation(operation: &HighLevelILLiftedInstruction) {
use HighLevelILLiftedInstructionKind::*;
match &operation.kind {
Adc(_) => 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();
}

View File

@@ -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"

View File

@@ -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?}");

View File

@@ -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!("{:<indent$}", "")
}
fn print_operation(operation: &MediumLevelILOperation) {
use MediumLevelILOperation::*;
match operation {
Nop(_) => 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!();

View File

@@ -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<RegType = Self>;
fn name(&self) -> Cow<str>;
@@ -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<str>;
@@ -487,6 +487,9 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
fn intrinsics(&self) -> Vec<Self::Intrinsic> {
Vec::new()
}
fn intrinsic_class(&self, _id: u32) -> binaryninjacore_sys::BNIntrinsicClass {
binaryninjacore_sys::BNIntrinsicClass::GeneralIntrinsicClass
}
fn intrinsic_from_id(&self, _id: u32) -> Option<Self::Intrinsic> {
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<Self>,
data: &[u8],
addr: u64,
il: &mut Lifter<Self>,
) -> 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<CoreIntrinsic> {
// TODO validate in debug builds
Some(CoreIntrinsic(self.0, id))
@@ -2366,6 +2382,14 @@ where
}
}
extern "C" fn cb_intrinsic_class<A>(ctxt: *mut c_void, intrinsic: u32) -> BNIntrinsicClass
where
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
{
let custom_arch = unsafe { &*(ctxt as *mut A) };
custom_arch.intrinsic_class(intrinsic)
}
extern "C" fn cb_intrinsic_name<A>(ctxt: *mut c_void, intrinsic: u32) -> *mut c_char
where
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + 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::<A>),
getRegisterStackInfo: Some(cb_reg_stack_info::<A>),
getIntrinsicClass: Some(cb_intrinsic_class::<A>),
getIntrinsicName: Some(cb_intrinsic_name::<A>),
getAllIntrinsics: Some(cb_intrinsics::<A>),
getIntrinsicInputs: Some(cb_intrinsic_inputs::<A>),

View File

@@ -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<BinaryView> {
}
}
#[derive(Debug, Clone)]
pub struct ActiveAnalysisInfo {
pub func: Ref<Function>,
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<ActiveAnalysisInfo>,
}
#[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<Box<dyn Fn(usize, usize) -> 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<AnalysisInfo> {
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<Handler>(event_type: BinaryViewEventType, handler: Handler)
where
Handler: BinaryViewEventHandler,
{
unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>(
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::<Handler>),
raw as *mut ::std::os::raw::c_void,
);
}
}

View File

@@ -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
})
}
}

View File

@@ -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<T: Into<Conf<bool>>>(&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<T: Into<Conf<bool>>>(&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<Ref<hlil::HighLevelILFunction>, ()> {
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<Ref<mlil::MediumLevelILFunction>, ()> {
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<H: std::hash::Hasher>(&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

View File

@@ -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)
}

63
src/hlil/block.rs Normal file
View File

@@ -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<HighLevelILFunction>,
range: Range<u64>,
}
impl Iterator for HighLevelILBlockIter {
type Item = HighLevelILInstruction;
fn next(&mut self) -> Option<Self::Item> {
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<HighLevelILFunction>,
}
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<Self>) -> 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<Self>) -> 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(),
}
}
}

111
src/hlil/function.rs Normal file
View File

@@ -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<H: Hasher>(&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<Self> {
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<Function> {
unsafe {
let func = BNGetHighLevelILOwnerFunction(self.handle);
Function::from_raw(func)
}
}
pub fn basic_blocks(&self) -> Array<BasicBlock<HighLevelILBlock>> {
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<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
unsafe impl RefCountable for HighLevelILFunction {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
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, "<hlil func handle {:p}>", self.handle)
}
}

991
src/hlil/instruction.rs Normal file
View File

@@ -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<HighLevelILFunction>,
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<HighLevelILFunction>, 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<HighLevelILLiftedInstruction> {
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<HighLevelILLiftedInstruction> {
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>(),
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<usize> {
(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)
}

325
src/hlil/lift.rs Normal file
View File

@@ -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<HighLevelILLiftedInstruction>),
Float(f64),
Int(u64),
IntList(Vec<u64>),
Intrinsic(ILIntrinsic),
Label(GotoLabel),
MemberIndex(Option<usize>),
Var(Variable),
VarSsa(SSAVariable),
VarSsaList(Vec<SSAVariable>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct HighLevelILLiftedInstruction {
pub function: Ref<HighLevelILFunction>,
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())),
],
}
}
}

10
src/hlil/mod.rs Normal file
View File

@@ -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::*;

524
src/hlil/operation.rs Normal file
View File

@@ -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<Function>,
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<HighLevelILLiftedInstruction>,
pub right: Box<HighLevelILLiftedInstruction>,
pub carry: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub right: Box<HighLevelILLiftedInstruction>,
}
// ARRAY_INDEX
#[derive(Copy, Clone)]
pub struct ArrayIndex {
pub src: usize,
pub index: usize,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiftedArrayIndex {
pub src: Box<HighLevelILLiftedInstruction>,
pub index: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub src_memory: u64,
pub index: Box<HighLevelILLiftedInstruction>,
}
// ASSIGN
#[derive(Copy, Clone)]
pub struct Assign {
pub dest: usize,
pub src: usize,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiftedAssign {
pub dest: Box<HighLevelILLiftedInstruction>,
pub src: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub dest_memory: u64,
pub src: Box<HighLevelILLiftedInstruction>,
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<HighLevelILLiftedInstruction>,
pub src: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub dest_memory: u64,
pub src: Box<HighLevelILLiftedInstruction>,
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<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub params: Vec<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub params: Vec<HighLevelILLiftedInstruction>,
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<HighLevelILLiftedInstruction>,
pub body: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
}
// DEREF_FIELD_SSA
#[derive(Copy, Clone)]
pub struct DerefFieldSsa {
pub src: usize,
pub src_memory: u64,
pub offset: u64,
pub member_index: Option<usize>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiftedDerefFieldSsa {
pub src: Box<HighLevelILLiftedInstruction>,
pub src_memory: u64,
pub offset: u64,
pub member_index: Option<usize>,
}
// 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<HighLevelILLiftedInstruction>,
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<HighLevelILLiftedInstruction>,
pub condition: Box<HighLevelILLiftedInstruction>,
pub update: Box<HighLevelILLiftedInstruction>,
pub body: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub condition_phi: Box<HighLevelILLiftedInstruction>,
pub condition: Box<HighLevelILLiftedInstruction>,
pub update: Box<HighLevelILLiftedInstruction>,
pub body: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub cond_true: Box<HighLevelILLiftedInstruction>,
pub cond_false: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
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<HighLevelILLiftedInstruction>,
}
// 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<u64>,
}
// 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<HighLevelILLiftedInstruction>,
}
// SPLIT
#[derive(Copy, Clone)]
pub struct Split {
pub high: usize,
pub low: usize,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiftedSplit {
pub high: Box<HighLevelILLiftedInstruction>,
pub low: Box<HighLevelILLiftedInstruction>,
}
// STRUCT_FIELD, DEREF_FIELD
#[derive(Copy, Clone)]
pub struct StructField {
pub src: usize,
pub offset: u64,
pub member_index: Option<usize>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiftedStructField {
pub src: Box<HighLevelILLiftedInstruction>,
pub offset: u64,
pub member_index: Option<usize>,
}
// 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<HighLevelILLiftedInstruction>,
pub default: Box<HighLevelILLiftedInstruction>,
pub cases: Vec<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
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<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
}
// 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<SSAVariable>,
}
// 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<HighLevelILLiftedInstruction>,
pub body: Box<HighLevelILLiftedInstruction>,
}
// 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<HighLevelILLiftedInstruction>,
pub condition: Box<HighLevelILLiftedInstruction>,
pub body: Box<HighLevelILLiftedInstruction>,
}

View File

@@ -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<S: BnStrCompatible>(
) -> Option<rc::Ref<binaryview::BinaryView>> {
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,
)
};

View File

@@ -330,11 +330,7 @@ impl PartialEq for LinearViewCursor {
impl PartialOrd for LinearViewCursor {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
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))
}
}

View File

@@ -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<A: Architecture, M: FunctionMutability, F: FunctionForm> Sync for Fu
impl<A: Architecture, M: FunctionMutability, F: FunctionForm> Eq for Function<A, M, F> {}
impl<A: Architecture, M: FunctionMutability, F: FunctionForm> PartialEq for Function<A, M, F> {
fn eq(&self, rhs: &Self) -> bool {
self.handle == rhs.handle
self.get_function().eq(&rhs.get_function())
}
}
use std::hash::{Hash, Hasher};
impl<A: Architecture, M: FunctionMutability, F: FunctionForm> Hash for Function<A, M, F> {
fn hash<H: Hasher>(&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<Self> {
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<crate::function::Function> {
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<CoreArchitecture, Mutable, NonSSA<LiftedNonSSA>> {
pub fn new(
arch: CoreArchitecture,
source_func: Option<crate::function::Function>,
) -> Result<Ref<Self>, ()> {
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<A, M, F>
where
A: 'func + Architecture,

View File

@@ -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<V>> {
use binaryninjacore_sys::BNLowLevelILOperation::*;

View File

@@ -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<Self>) -> MediumLevelILBlockIter {

View File

@@ -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<H: Hasher>(&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<Self> {
debug_assert!(!handle.is_null());
Self { handle }
Self { handle }.to_owned()
}
pub fn instruction_at<L: Into<Location>>(&self, loc: L) -> Option<MediumLevelILInstruction> {
@@ -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 {

File diff suppressed because it is too large Load Diff

View File

@@ -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<MediumLevelILLiftedInstruction>),
Float(f64),
Int(u64),
IntList(Vec<u64>),
TargetMap(BTreeMap<u64, u64>),
Var(Variable),
VarList(Vec<Variable>),
VarSsa(SSAVariable),
VarSsaList(Vec<SSAVariable>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum MediumLevelILLiftedOperation {
Nop(NoArgs),
Noret(NoArgs),
Bp(NoArgs),
Undef(NoArgs),
Unimpl(NoArgs),
pub struct MediumLevelILLiftedInstruction {
pub function: Ref<MediumLevelILFunction>,
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))],
}
}
}

File diff suppressed because it is too large Load Diff

223
src/operand_iter.rs Normal file
View File

@@ -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<F: ILFunction + RefCountable> {
function: Ref<F>,
remaining: usize,
next_iter_idx: Option<usize>,
current_iter: OperandIterInner,
}
impl<F: ILFunction + RefCountable> OperandIter<F> {
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<F> {
assert_eq!(self.len() % 2, 0);
OperandPairIter(self)
}
pub fn exprs(self) -> OperandExprIter<F> {
OperandExprIter(self)
}
pub fn vars(self) -> OperandVarIter<F> {
OperandVarIter(self)
}
pub fn ssa_vars(self) -> OperandSSAVarIter<F> {
OperandSSAVarIter(self.pairs())
}
}
impl<F: ILFunction + RefCountable> Iterator for OperandIter<F> {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
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<F: ILFunction + RefCountable> ExactSizeIterator for OperandIter<F> {
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<Self::Item> {
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<F: ILFunction + RefCountable>(OperandIter<F>);
impl<F: ILFunction + RefCountable> Iterator for OperandPairIter<F> {
type Item = (u64, u64);
fn next(&mut self) -> Option<Self::Item> {
let first = self.0.next()?;
let second = self.0.next()?;
Some((first, second))
}
}
impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandPairIter<F> {
fn len(&self) -> usize {
self.0.len() / 2
}
}
pub struct OperandExprIter<F: ILFunction + RefCountable>(OperandIter<F>);
impl<F: ILFunction + RefCountable> Iterator for OperandExprIter<F> {
type Item = F::Instruction;
fn next(&mut self) -> Option<Self::Item> {
self.0
.next()
.map(|idx| self.0.function.il_instruction_from_idx(idx as usize))
}
}
impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandExprIter<F> {
fn len(&self) -> usize {
self.0.len()
}
}
pub struct OperandVarIter<F: ILFunction + RefCountable>(OperandIter<F>);
impl<F: ILFunction + RefCountable> Iterator for OperandVarIter<F> {
type Item = Variable;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(get_var)
}
}
impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandVarIter<F> {
fn len(&self) -> usize {
self.0.len()
}
}
pub struct OperandSSAVarIter<F: ILFunction + RefCountable>(OperandPairIter<F>);
impl<F: ILFunction + RefCountable> Iterator for OperandSSAVarIter<F> {
type Item = SSAVariable;
fn next(&mut self) -> Option<Self::Item> {
self.0
.next()
.map(|(id, version)| get_var_ssa(id, version as usize))
}
}
impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandSSAVarIter<F> {
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)
}

View File

@@ -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::<Vec<_>>();
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<Handle = Self> + Send + Sync,
{
fn clone(&self) -> Self {
Self {
handle: self.handle,
}
*self
}
}

View File

@@ -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<S: BnStrCompatible> DataVariableAndName<S> {
}
}
/////////////////////////
// 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<Self> {
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<BNRegisterValue> 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<RegisterValue> 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<Function>,
value: RegisterValue,
}
impl ConstantData {
pub(crate) fn new(function: Ref<Function>, value: RegisterValue) -> Self {
Self { function, value }
}
}
// unsafe impl<S: BnStrCompatible> CoreArrayProvider for DataVariableAndName<S> {
// type Raw = BNDataVariableAndName;
// type Context = ();