summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2023-06-13 11:29:42 -0600
committerRusty Wagner <rusty.wagner@gmail.com>2023-06-13 16:46:47 -0400
commit52eb0de5dcddaee2b8bd3122512ae4c20e0e9545 (patch)
tree8543df055ebc32d32283c0231cbeb6c7fd424533 /platform
parentadb7ef55fc4e24f03e6faf353cc9122ee07c714f (diff)
Move platform submodules into API
Diffstat (limited to 'platform')
-rw-r--r--platform/decree/CMakeLists.txt33
-rw-r--r--platform/decree/LICENSE13
-rw-r--r--platform/decree/README.md23
-rw-r--r--platform/decree/platform_decree.cpp66
-rw-r--r--platform/efi/CMakeLists.txt2
-rw-r--r--platform/freebsd/CMakeLists.txt33
-rw-r--r--platform/freebsd/LICENSE13
-rw-r--r--platform/freebsd/README.md23
-rw-r--r--platform/freebsd/platform_freebsd.cpp156
-rw-r--r--platform/linux/CMakeLists.txt33
-rw-r--r--platform/linux/LICENSE13
-rw-r--r--platform/linux/README.md23
-rw-r--r--platform/linux/platform_linux.cpp305
-rw-r--r--platform/mac/CMakeLists.txt33
-rw-r--r--platform/mac/LICENSE13
-rw-r--r--platform/mac/README.md23
-rw-r--r--platform/mac/platform_mac.cpp157
-rw-r--r--platform/windows/CMakeLists.txt33
-rw-r--r--platform/windows/LICENSE13
-rw-r--r--platform/windows/README.md23
-rw-r--r--platform/windows/platform_windows.cpp535
21 files changed, 1565 insertions, 1 deletions
diff --git a/platform/decree/CMakeLists.txt b/platform/decree/CMakeLists.txt
new file mode 100644
index 00000000..646580ee
--- /dev/null
+++ b/platform/decree/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(platform_decree)
+
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
+endif()
+
+file(GLOB SOURCES
+ ${PROJECT_SOURCE_DIR}/*.cpp
+ ${PROJECT_SOURCE_DIR}/*.h)
+
+if(DEMO)
+ add_library(platform_decree STATIC ${SOURCES})
+else()
+ add_library(platform_decree SHARED ${SOURCES})
+endif()
+
+target_link_libraries(platform_decree binaryninjaapi)
+
+set_target_properties(platform_decree PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_INTERNAL_BUILD)
+ plugin_rpath(platform_decree)
+ set_target_properties(platform_decree PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
+endif()
diff --git a/platform/decree/LICENSE b/platform/decree/LICENSE
new file mode 100644
index 00000000..265883c5
--- /dev/null
+++ b/platform/decree/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2021 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.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/platform/decree/README.md b/platform/decree/README.md
new file mode 100644
index 00000000..928f89f6
--- /dev/null
+++ b/platform/decree/README.md
@@ -0,0 +1,23 @@
+# platform-decree
+This is the DECREE platform plugin that ships with Binary Ninja.
+
+## Building
+
+Building the architecture plugin requires `cmake` 3.9 or above. You will also need the
+[Binary Ninja API source](https://github.com/Vector35/binaryninja-api).
+
+Run `cmake`. This can be done either from a separate build directory or from the source
+directory. Once that is complete, run `make` in the build directory to compile the plugin.
+
+The plugin can be found in the root of the build directory as `libplatform_decree.so`,
+`libplatform_decree.dylib` or `platform_decree.dll` depending on your platform.
+
+To install the plugin, first launch Binary Ninja and uncheck the "DECREE platform plugin"
+option in the "Core Plugins" section. This will cause Binary Ninja to stop loading the
+bundled plugin so that its replacement can be loaded. Once this is complete, you can copy
+the plugin into the user plugins directory (you can locate this by using the "Open Plugin Folder"
+option in the Binary Ninja UI).
+
+**Do not replace the architecture plugin in the Binary Ninja install directory. This will
+be overwritten every time there is a Binary Ninja update. Use the above process to ensure that
+updates do not automatically uninstall your custom build.**
diff --git a/platform/decree/platform_decree.cpp b/platform/decree/platform_decree.cpp
new file mode 100644
index 00000000..a0eb2b32
--- /dev/null
+++ b/platform/decree/platform_decree.cpp
@@ -0,0 +1,66 @@
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+class DecreeX86Platform: public Platform
+{
+public:
+ DecreeX86Platform(Architecture* arch): Platform(arch, "decree-x86")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("regparm");
+ if (cc)
+ RegisterFastcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("stdcall");
+ if (cc)
+ RegisterStdcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+
+#ifndef DEMO_VERSION
+ BINARYNINJAPLUGIN void CorePluginDependencies()
+ {
+ AddOptionalPluginDependency("arch_x86");
+ AddOptionalPluginDependency("view_elf");
+ }
+#endif
+
+#ifdef DEMO_VERSION
+ bool DecreePluginInit()
+#else
+ BINARYNINJAPLUGIN bool CorePluginInit()
+#endif
+ {
+ Ref<Architecture> x86 = Architecture::GetByName("x86");
+ if (x86)
+ {
+ Ref<Platform> platform;
+
+ platform = new DecreeX86Platform(x86);
+ Platform::Register("decree", platform);
+ BinaryViewType::RegisterPlatform("ELF", 'C', x86, platform);
+ }
+
+ return true;
+ }
+}
diff --git a/platform/efi/CMakeLists.txt b/platform/efi/CMakeLists.txt
index 62078907..1da0a2d7 100644
--- a/platform/efi/CMakeLists.txt
+++ b/platform/efi/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(platform_efi)
if(NOT BN_INTERNAL_BUILD)
- add_subdirectory(${PROJECT_SOURCE_DIR}/.. ${PROJECT_BINARY_DIR}/api)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
endif()
file(GLOB SOURCES
diff --git a/platform/freebsd/CMakeLists.txt b/platform/freebsd/CMakeLists.txt
new file mode 100644
index 00000000..fd7889b6
--- /dev/null
+++ b/platform/freebsd/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(platform_freebsd)
+
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
+endif()
+
+file(GLOB SOURCES
+ ${PROJECT_SOURCE_DIR}/*.cpp
+ ${PROJECT_SOURCE_DIR}/*.h)
+
+if(DEMO)
+ add_library(platform_freebsd STATIC ${SOURCES})
+else()
+ add_library(platform_freebsd SHARED ${SOURCES})
+endif()
+
+target_link_libraries(platform_freebsd binaryninjaapi)
+
+set_target_properties(platform_freebsd PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_INTERNAL_BUILD)
+ plugin_rpath(platform_freebsd)
+ set_target_properties(platform_freebsd PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
+endif()
diff --git a/platform/freebsd/LICENSE b/platform/freebsd/LICENSE
new file mode 100644
index 00000000..265883c5
--- /dev/null
+++ b/platform/freebsd/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2021 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.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/platform/freebsd/README.md b/platform/freebsd/README.md
new file mode 100644
index 00000000..ecef4b19
--- /dev/null
+++ b/platform/freebsd/README.md
@@ -0,0 +1,23 @@
+# platform-freebsd
+This is the FreeBSD platform plugin that ships with Binary Ninja.
+
+## Building
+
+Building the architecture plugin requires `cmake` 3.9 or above. You will also need the
+[Binary Ninja API source](https://github.com/Vector35/binaryninja-api).
+
+Run `cmake`. This can be done either from a separate build directory or from the source
+directory. Once that is complete, run `make` in the build directory to compile the plugin.
+
+The plugin can be found in the root of the build directory as `libplatform_freebsd.so`,
+`libplatform_freebsd.dylib` or `platform_freebsd.dll` depending on your platform.
+
+To install the plugin, first launch Binary Ninja and uncheck the "FreeBSD platform plugin"
+option in the "Core Plugins" section. This will cause Binary Ninja to stop loading the
+bundled plugin so that its replacement can be loaded. Once this is complete, you can copy
+the plugin into the user plugins directory (you can locate this by using the "Open Plugin Folder"
+option in the Binary Ninja UI).
+
+**Do not replace the architecture plugin in the Binary Ninja install directory. This will
+be overwritten every time there is a Binary Ninja update. Use the above process to ensure that
+updates do not automatically uninstall your custom build.**
diff --git a/platform/freebsd/platform_freebsd.cpp b/platform/freebsd/platform_freebsd.cpp
new file mode 100644
index 00000000..fd936a55
--- /dev/null
+++ b/platform/freebsd/platform_freebsd.cpp
@@ -0,0 +1,156 @@
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+class FreeBSDX86Platform: public Platform
+{
+public:
+ FreeBSDX86Platform(Architecture* arch): Platform(arch, "freebsd-x86")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("regparm");
+ if (cc)
+ RegisterFastcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("stdcall");
+ if (cc)
+ RegisterStdcallCallingConvention(cc);
+ }
+};
+
+
+class FreeBSDX64Platform: public Platform
+{
+public:
+ FreeBSDX64Platform(Architecture* arch): Platform(arch, "freebsd-x86_64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("sysv");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+class FreeBSDArmv7Platform: public Platform
+{
+public:
+ FreeBSDArmv7Platform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+class FreeBSDArm64Platform: public Platform
+{
+public:
+ FreeBSDArm64Platform(Architecture* arch): Platform(arch, "freebsd-aarch64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+
+#ifndef DEMO_VERSION
+ BINARYNINJAPLUGIN void CorePluginDependencies()
+ {
+ AddOptionalPluginDependency("arch_x86");
+ AddOptionalPluginDependency("arch_armv7");
+ AddOptionalPluginDependency("arch_arm64");
+ AddOptionalPluginDependency("view_elf");
+ }
+#endif
+
+#ifdef DEMO_VERSION
+ bool FreeBSDPluginInit()
+#else
+ BINARYNINJAPLUGIN bool CorePluginInit()
+#endif
+ {
+ Ref<Architecture> x86 = Architecture::GetByName("x86");
+ if (x86)
+ {
+ Ref<Platform> platform;
+
+ platform = new FreeBSDX86Platform(x86);
+ Platform::Register("freebsd", platform);
+ BinaryViewType::RegisterPlatform("ELF", 9, x86, platform);
+ }
+
+ Ref<Architecture> x64 = Architecture::GetByName("x86_64");
+ if (x64)
+ {
+ Ref<Platform> platform;
+
+ platform = new FreeBSDX64Platform(x64);
+ Platform::Register("freebsd", platform);
+ BinaryViewType::RegisterPlatform("ELF", 9, x64, platform);
+ }
+
+ Ref<Architecture> armv7 = Architecture::GetByName("armv7");
+ Ref<Architecture> thumb2 = Architecture::GetByName("thumb2");
+ if (armv7 && thumb2)
+ {
+ Ref<Platform> armPlatform, thumbPlatform;
+
+ armPlatform = new FreeBSDArmv7Platform(armv7, "freebsd-armv7");
+ thumbPlatform = new FreeBSDArmv7Platform(thumb2, "freebsd-thumb2");
+ armPlatform->AddRelatedPlatform(thumb2, thumbPlatform);
+ thumbPlatform->AddRelatedPlatform(armv7, armPlatform);
+ Platform::Register("freebsd", armPlatform);
+ Platform::Register("freebsd", thumbPlatform);
+ BinaryViewType::RegisterPlatform("ELF", 9, armv7, armPlatform);
+ }
+
+ Ref<Architecture> arm64 = Architecture::GetByName("aarch64");
+ if (arm64)
+ {
+ Ref<Platform> platform;
+
+ platform = new FreeBSDArm64Platform(arm64);
+ Platform::Register("freebsd", platform);
+ BinaryViewType::RegisterPlatform("ELF", 9, arm64, platform);
+ }
+
+ return true;
+ }
+}
diff --git a/platform/linux/CMakeLists.txt b/platform/linux/CMakeLists.txt
new file mode 100644
index 00000000..03c1ce5d
--- /dev/null
+++ b/platform/linux/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(platform_linux)
+
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
+endif()
+
+file(GLOB SOURCES
+ ${PROJECT_SOURCE_DIR}/*.cpp
+ ${PROJECT_SOURCE_DIR}/*.h)
+
+if(DEMO)
+ add_library(platform_linux STATIC ${SOURCES})
+else()
+ add_library(platform_linux SHARED ${SOURCES})
+endif()
+
+target_link_libraries(platform_linux binaryninjaapi)
+
+set_target_properties(platform_linux PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_INTERNAL_BUILD)
+ plugin_rpath(platform_linux)
+ set_target_properties(platform_linux PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
+endif()
diff --git a/platform/linux/LICENSE b/platform/linux/LICENSE
new file mode 100644
index 00000000..265883c5
--- /dev/null
+++ b/platform/linux/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2021 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.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/platform/linux/README.md b/platform/linux/README.md
new file mode 100644
index 00000000..3061208d
--- /dev/null
+++ b/platform/linux/README.md
@@ -0,0 +1,23 @@
+# platform-linux
+This is the Linux platform plugin that ships with Binary Ninja.
+
+## Building
+
+Building the architecture plugin requires `cmake` 3.9 or above. You will also need the
+[Binary Ninja API source](https://github.com/Vector35/binaryninja-api).
+
+Run `cmake`. This can be done either from a separate build directory or from the source
+directory. Once that is complete, run `make` in the build directory to compile the plugin.
+
+The plugin can be found in the root of the build directory as `libplatform_linux.so`,
+`libplatform_linux.dylib` or `platform_linux.dll` depending on your platform.
+
+To install the plugin, first launch Binary Ninja and uncheck the "Linux platform plugin"
+option in the "Core Plugins" section. This will cause Binary Ninja to stop loading the
+bundled plugin so that its replacement can be loaded. Once this is complete, you can copy
+the plugin into the user plugins directory (you can locate this by using the "Open Plugin Folder"
+option in the Binary Ninja UI).
+
+**Do not replace the architecture plugin in the Binary Ninja install directory. This will
+be overwritten every time there is a Binary Ninja update. Use the above process to ensure that
+updates do not automatically uninstall your custom build.**
diff --git a/platform/linux/platform_linux.cpp b/platform/linux/platform_linux.cpp
new file mode 100644
index 00000000..1a4c9d93
--- /dev/null
+++ b/platform/linux/platform_linux.cpp
@@ -0,0 +1,305 @@
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+class LinuxX86Platform: public Platform
+{
+public:
+ LinuxX86Platform(Architecture* arch): Platform(arch, "linux-x86")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("regparm");
+ if (cc)
+ RegisterCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("stdcall");
+ if (cc)
+ RegisterStdcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+class LinuxPpc32Platform: public Platform
+{
+public:
+ LinuxPpc32Platform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("svr4");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+class LinuxPpc64Platform: public Platform
+{
+public:
+ LinuxPpc64Platform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("svr4");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+class LinuxX64Platform: public Platform
+{
+public:
+ LinuxX64Platform(Architecture* arch): Platform(arch, "linux-x86_64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("sysv");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+
+class LinuxArmv7Platform: public Platform
+{
+public:
+ LinuxArmv7Platform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+
+class LinuxArm64Platform: public Platform
+{
+public:
+ LinuxArm64Platform(Architecture* arch): Platform(arch, "linux-aarch64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+
+class LinuxMipsPlatform: public Platform
+{
+public:
+ LinuxMipsPlatform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("o32");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("linux-syscall");
+ if (cc)
+ SetSystemCallConvention(cc);
+ }
+};
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+
+#ifndef DEMO_VERSION
+ BINARYNINJAPLUGIN void CorePluginDependencies()
+ {
+ AddOptionalPluginDependency("arch_x86");
+ AddOptionalPluginDependency("arch_armv7");
+ AddOptionalPluginDependency("arch_arm64");
+ AddOptionalPluginDependency("arch_mips");
+ AddOptionalPluginDependency("arch_ppc");
+ AddOptionalPluginDependency("view_elf");
+ }
+#endif
+
+#ifdef DEMO_VERSION
+ bool LinuxPluginInit()
+#else
+ BINARYNINJAPLUGIN bool CorePluginInit()
+#endif
+ {
+ Ref<Architecture> x86 = Architecture::GetByName("x86");
+ if (x86)
+ {
+ Ref<Platform> platform;
+
+ platform = new LinuxX86Platform(x86);
+ Platform::Register("linux", platform);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, x86, platform);
+ BinaryViewType::RegisterPlatform("ELF", 3, x86, platform);
+ }
+
+ Ref<Architecture> x64 = Architecture::GetByName("x86_64");
+ if (x64)
+ {
+ Ref<Platform> platform;
+
+ platform = new LinuxX64Platform(x64);
+ Platform::Register("linux", platform);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, x64, platform);
+ BinaryViewType::RegisterPlatform("ELF", 3, x64, platform);
+ }
+
+ Ref<Architecture> armv7 = Architecture::GetByName("armv7");
+ Ref<Architecture> armv7eb = Architecture::GetByName("armv7eb");
+ Ref<Architecture> thumb2 = Architecture::GetByName("thumb2");
+ Ref<Architecture> thumb2eb = Architecture::GetByName("thumb2eb");
+ if (armv7 && armv7eb && thumb2 && thumb2eb)
+ {
+ Ref<Platform> armPlatform, armebPlatform, thumbPlatform, thumbebPlatform;
+
+ armPlatform = new LinuxArmv7Platform(armv7, "linux-armv7");
+ armebPlatform = new LinuxArmv7Platform(armv7eb, "linux-armv7eb");
+ thumbPlatform = new LinuxArmv7Platform(thumb2, "linux-thumb2");
+ thumbebPlatform = new LinuxArmv7Platform(thumb2eb, "linux-thumb2eb");
+ armPlatform->AddRelatedPlatform(thumb2, thumbPlatform);
+ armebPlatform->AddRelatedPlatform(thumb2eb, thumbebPlatform);
+ thumbPlatform->AddRelatedPlatform(armv7, armPlatform);
+ thumbebPlatform->AddRelatedPlatform(armv7eb, armebPlatform);
+ Platform::Register("linux", armPlatform);
+ Platform::Register("linux", thumbPlatform);
+ Platform::Register("linux", armebPlatform);
+ Platform::Register("linux", thumbebPlatform);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, armv7, armPlatform);
+ BinaryViewType::RegisterPlatform("ELF", 3, armv7, armPlatform);
+ BinaryViewType::RegisterPlatform("ELF", 0, armv7eb, armebPlatform);
+ BinaryViewType::RegisterPlatform("ELF", 3, armv7eb, armebPlatform);
+ }
+
+ Ref<Architecture> arm64 = Architecture::GetByName("aarch64");
+ if (arm64)
+ {
+ Ref<Platform> platform;
+
+ platform = new LinuxArm64Platform(arm64);
+ Platform::Register("linux", platform);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, arm64, platform);
+ BinaryViewType::RegisterPlatform("ELF", 3, arm64, platform);
+ }
+
+ Ref<Architecture> ppc = Architecture::GetByName("ppc");
+ Ref<Architecture> ppcle = Architecture::GetByName("ppc_le");
+ if (ppc && ppcle)
+ {
+ Ref<Platform> platform;
+ Ref<Platform> platformle;
+
+ platform = new LinuxPpc32Platform(ppc, "linux-ppc32");
+ platformle = new LinuxPpc32Platform(ppcle, "linux-ppc32_le");
+ Platform::Register("linux", platform);
+ Platform::Register("linux", platformle);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, ppc, platform);
+ BinaryViewType::RegisterPlatform("ELF", 3, ppc, platform);
+ BinaryViewType::RegisterPlatform("ELF", 0, ppcle, platformle);
+ BinaryViewType::RegisterPlatform("ELF", 3, ppcle, platformle);
+ }
+
+ Ref<Architecture> ppc64 = Architecture::GetByName("ppc64");
+ Ref<Architecture> ppc64le = Architecture::GetByName("ppc64_le");
+ if (ppc64 && ppc64le)
+ {
+ Ref<Platform> platform;
+ Ref<Platform> platformle;
+
+ platform = new LinuxPpc64Platform(ppc64, "linux-ppc64");
+ platformle = new LinuxPpc64Platform(ppc64le, "linux-ppc64_le");
+ Platform::Register("linux", platform);
+ Platform::Register("linux", platformle);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, ppc64, platform);
+ BinaryViewType::RegisterPlatform("ELF", 3, ppc64, platform);
+ BinaryViewType::RegisterPlatform("ELF", 0, ppc64le, platformle);
+ BinaryViewType::RegisterPlatform("ELF", 3, ppc64le, platformle);
+ }
+
+ Ref<Architecture> mipsel = Architecture::GetByName("mipsel32");
+ Ref<Architecture> mipseb = Architecture::GetByName("mips32");
+ if (mipsel && mipseb)
+ {
+ Ref<Platform> platformLE, platformBE;
+
+ platformLE = new LinuxMipsPlatform(mipsel, "linux-mipsel");
+ platformBE = new LinuxMipsPlatform(mipseb, "linux-mips");
+ Platform::Register("linux", platformLE);
+ Platform::Register("linux", platformBE);
+ // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
+ BinaryViewType::RegisterPlatform("ELF", 0, mipsel, platformLE);
+ BinaryViewType::RegisterPlatform("ELF", 0, mipseb, platformBE);
+ BinaryViewType::RegisterPlatform("ELF", 3, mipsel, platformLE);
+ BinaryViewType::RegisterPlatform("ELF", 3, mipseb, platformBE);
+ }
+
+ return true;
+ }
+}
diff --git a/platform/mac/CMakeLists.txt b/platform/mac/CMakeLists.txt
new file mode 100644
index 00000000..9ead5abd
--- /dev/null
+++ b/platform/mac/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(platform_mac)
+
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
+endif()
+
+file(GLOB SOURCES
+ ${PROJECT_SOURCE_DIR}/*.cpp
+ ${PROJECT_SOURCE_DIR}/*.h)
+
+if(DEMO)
+ add_library(platform_mac STATIC ${SOURCES})
+else()
+ add_library(platform_mac SHARED ${SOURCES})
+endif()
+
+target_link_libraries(platform_mac binaryninjaapi)
+
+set_target_properties(platform_mac PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_INTERNAL_BUILD)
+ plugin_rpath(platform_mac)
+ set_target_properties(platform_mac PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
+endif()
diff --git a/platform/mac/LICENSE b/platform/mac/LICENSE
new file mode 100644
index 00000000..265883c5
--- /dev/null
+++ b/platform/mac/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2021 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.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/platform/mac/README.md b/platform/mac/README.md
new file mode 100644
index 00000000..043fe035
--- /dev/null
+++ b/platform/mac/README.md
@@ -0,0 +1,23 @@
+# platform-mac
+This is the macOS platform plugin that ships with Binary Ninja.
+
+## Building
+
+Building the architecture plugin requires `cmake` 3.9 or above. You will also need the
+[Binary Ninja API source](https://github.com/Vector35/binaryninja-api).
+
+Run `cmake`. This can be done either from a separate build directory or from the source
+directory. Once that is complete, run `make` in the build directory to compile the plugin.
+
+The plugin can be found in the root of the build directory as `libplatform_mac.so`,
+`libplatform_mac.dylib` or `platform_mac.dll` depending on your platform.
+
+To install the plugin, first launch Binary Ninja and uncheck the "macOS platform plugin"
+option in the "Core Plugins" section. This will cause Binary Ninja to stop loading the
+bundled plugin so that its replacement can be loaded. Once this is complete, you can copy
+the plugin into the user plugins directory (you can locate this by using the "Open Plugin Folder"
+option in the Binary Ninja UI).
+
+**Do not replace the architecture plugin in the Binary Ninja install directory. This will
+be overwritten every time there is a Binary Ninja update. Use the above process to ensure that
+updates do not automatically uninstall your custom build.**
diff --git a/platform/mac/platform_mac.cpp b/platform/mac/platform_mac.cpp
new file mode 100644
index 00000000..34833b67
--- /dev/null
+++ b/platform/mac/platform_mac.cpp
@@ -0,0 +1,157 @@
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+class MacX86Platform: public Platform
+{
+public:
+ MacX86Platform(Architecture* arch): Platform(arch, "mac-x86")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("regparm");
+ if (cc)
+ RegisterFastcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("stdcall");
+ if (cc)
+ RegisterStdcallCallingConvention(cc);
+ }
+};
+
+
+class MacX64Platform: public Platform
+{
+public:
+ MacX64Platform(Architecture* arch): Platform(arch, "mac-x86_64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("sysv");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+class MacArmv7Platform: public Platform
+{
+public:
+ MacArmv7Platform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+class MacArm64Platform: public Platform
+{
+public:
+ MacArm64Platform(Architecture* arch): Platform(arch, "mac-aarch64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("apple-arm64");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+
+#ifndef DEMO_VERSION
+ BINARYNINJAPLUGIN void CorePluginDependencies()
+ {
+ AddOptionalPluginDependency("arch_x86");
+ AddOptionalPluginDependency("arch_armv7");
+ AddOptionalPluginDependency("arch_arm64");
+ AddOptionalPluginDependency("view_macho");
+ }
+#endif
+
+#ifdef DEMO_VERSION
+ bool MacPluginInit()
+#else
+ BINARYNINJAPLUGIN bool CorePluginInit()
+#endif
+ {
+ Ref<Architecture> x86 = Architecture::GetByName("x86");
+ if (x86)
+ {
+ Ref<Platform> platform;
+
+ platform = new MacX86Platform(x86);
+ Platform::Register("mac", platform);
+ BinaryViewType::RegisterPlatform("Mach-O", 0, x86, platform);
+ }
+
+ Ref<Architecture> x64 = Architecture::GetByName("x86_64");
+ if (x64)
+ {
+ Ref<Platform> platform;
+
+ platform = new MacX64Platform(x64);
+ Platform::Register("mac", platform);
+ BinaryViewType::RegisterPlatform("Mach-O", 0, x64, platform);
+ }
+
+ Ref<Architecture> armv7 = Architecture::GetByName("armv7");
+ Ref<Architecture> thumb2 = Architecture::GetByName("thumb2");
+ if (armv7 && thumb2)
+ {
+ Ref<Platform> armPlatform, thumbPlatform;
+
+ armPlatform = new MacArmv7Platform(armv7, "mac-armv7");
+ thumbPlatform = new MacArmv7Platform(thumb2, "mac-thumb2");
+ armPlatform->AddRelatedPlatform(thumb2, thumbPlatform);
+ thumbPlatform->AddRelatedPlatform(armv7, armPlatform);
+ Platform::Register("mac", armPlatform);
+ Platform::Register("mac", thumbPlatform);
+ BinaryViewType::RegisterPlatform("Mach-O", 0, armv7, armPlatform);
+ }
+
+ Ref<Architecture> arm64 = Architecture::GetByName("aarch64");
+ if (arm64)
+ {
+ Ref<Platform> platform;
+
+ platform = new MacArm64Platform(arm64);
+ Platform::Register("mac", platform);
+ BinaryViewType::RegisterPlatform("Mach-O", 9, arm64, platform);
+ BinaryViewType::RegisterPlatform("Mach-O", 0, arm64, platform);
+ }
+
+ return true;
+ }
+}
diff --git a/platform/windows/CMakeLists.txt b/platform/windows/CMakeLists.txt
new file mode 100644
index 00000000..e244fd49
--- /dev/null
+++ b/platform/windows/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(platform_windows)
+
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
+endif()
+
+file(GLOB SOURCES
+ *.cpp
+ *.h)
+
+if(DEMO)
+ add_library(platform_windows STATIC ${SOURCES})
+else()
+ add_library(platform_windows SHARED ${SOURCES})
+endif()
+
+target_link_libraries(platform_windows binaryninjaapi)
+
+set_target_properties(platform_windows PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_INTERNAL_BUILD)
+ plugin_rpath(platform_windows)
+ set_target_properties(platform_windows PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
+endif()
diff --git a/platform/windows/LICENSE b/platform/windows/LICENSE
new file mode 100644
index 00000000..265883c5
--- /dev/null
+++ b/platform/windows/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2021 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.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/platform/windows/README.md b/platform/windows/README.md
new file mode 100644
index 00000000..7c88902c
--- /dev/null
+++ b/platform/windows/README.md
@@ -0,0 +1,23 @@
+# platform-windows
+This is the Windows platform plugin that ships with Binary Ninja.
+
+## Building
+
+Building the architecture plugin requires `cmake` 3.9 or above. You will also need the
+[Binary Ninja API source](https://github.com/Vector35/binaryninja-api).
+
+Run `cmake`. This can be done either from a separate build directory or from the source
+directory. Once that is complete, run `make` in the build directory to compile the plugin.
+
+The plugin can be found in the root of the build directory as `libplatform_windows.so`,
+`libplatform_windows.dylib` or `platform_windows.dll` depending on your platform.
+
+To install the plugin, first launch Binary Ninja and uncheck the "Windows platform plugin"
+option in the "Core Plugins" section. This will cause Binary Ninja to stop loading the
+bundled plugin so that its replacement can be loaded. Once this is complete, you can copy
+the plugin into the user plugins directory (you can locate this by using the "Open Plugin Folder"
+option in the Binary Ninja UI).
+
+**Do not replace the architecture plugin in the Binary Ninja install directory. This will
+be overwritten every time there is a Binary Ninja update. Use the above process to ensure that
+updates do not automatically uninstall your custom build.**
diff --git a/platform/windows/platform_windows.cpp b/platform/windows/platform_windows.cpp
new file mode 100644
index 00000000..2b0a427f
--- /dev/null
+++ b/platform/windows/platform_windows.cpp
@@ -0,0 +1,535 @@
+#include "binaryninjaapi.h"
+#include "lowlevelilinstruction.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+class WindowsX86Platform: public Platform
+{
+public:
+ WindowsX86Platform(Architecture* arch): Platform(arch, "windows-x86")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ }
+
+ cc = arch->GetCallingConventionByName("fastcall");
+ if (cc)
+ RegisterFastcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("stdcall");
+ if (cc)
+ RegisterStdcallCallingConvention(cc);
+
+ cc = arch->GetCallingConventionByName("thiscall");
+ if (cc)
+ RegisterCallingConvention(cc);
+
+ // Linux-style register convention is commonly used by Borland compilers
+ cc = arch->GetCallingConventionByName("regparm");
+ if (cc)
+ RegisterCallingConvention(cc);
+ }
+};
+
+
+class WindowsX64Platform: public Platform
+{
+public:
+ WindowsX64Platform(Architecture* arch): Platform(arch, "windows-x86_64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("win64");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+class WindowsArmv7Platform: public Platform
+{
+public:
+ WindowsArmv7Platform(Architecture* arch, const std::string& name): Platform(arch, name)
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+ }
+};
+
+
+class WindowsArm64Platform: public Platform
+{
+public:
+ WindowsArm64Platform(Architecture* arch): Platform(arch, "windows-aarch64")
+ {
+ Ref<CallingConvention> cc;
+
+ cc = arch->GetCallingConventionByName("cdecl");
+ if (cc)
+ {
+ RegisterDefaultCallingConvention(cc);
+ RegisterCdeclCallingConvention(cc);
+ RegisterFastcallCallingConvention(cc);
+ RegisterStdcallCallingConvention(cc);
+ }
+
+ /* "windows-syscall" is defined and registered in arch-arm64 */
+ cc = arch->GetCallingConventionByName("windows-syscall");
+ if (cc)
+ {
+ SetSystemCallConvention(cc);
+ }
+ }
+};
+
+
+class ExceptionHandlerPrologFunctionRecognizer : public FunctionRecognizer
+{
+ Ref<Platform> m_platform;
+ uint32_t m_esp, m_ebp, m_fsbase;
+
+public:
+ ExceptionHandlerPrologFunctionRecognizer(Ref<Platform> platform) : m_platform(platform)
+ {
+ m_esp = platform->GetArchitecture()->GetRegisterByName("esp");
+ m_ebp = platform->GetArchitecture()->GetRegisterByName("ebp");
+ m_fsbase = platform->GetArchitecture()->GetRegisterByName("fsbase");
+ }
+
+ virtual bool RecognizeLowLevelIL(BinaryView* view, Function* func, LowLevelILFunction* il) override
+ {
+ // Make sure the function belongs to the desired platform. Platform specific function recognizers
+ // are not a feature so this was registered for the architecture as a whole.
+ if (func->GetPlatform() != m_platform)
+ return false;
+
+ // If inlining is already too high confidence, don't check as we won't override it.
+ if (func->IsInlinedDuringAnalysis().GetConfidence() >= BN_HEURISTIC_CONFIDENCE)
+ return false;
+
+ // Iterate through the IL instructions and maintain a set of flags on whether this looks
+ // like a shared function prolog.
+ bool writesToExceptionFramePointer = false;
+ bool writesToFramePointer = false;
+ bool writesToStackPointer = false;
+ bool pushesToStack = false;
+ bool lastPushIsReturnAddr = false;
+ bool writesToOldReturnAddr = false;
+ uint32_t returnAddrReg = BN_INVALID_REGISTER;
+ for (size_t i = 0; i < il->GetInstructionCount(); i++)
+ {
+ LowLevelILInstruction instr = il->GetInstruction(i);
+ if (instr.operation == LLIL_RET)
+ break;
+ switch (instr.operation)
+ {
+ case LLIL_PUSH:
+ pushesToStack = true;
+
+ // If pushing again after pushing the return address, this is not a match.
+ if (lastPushIsReturnAddr)
+ return false;
+
+ // Check for push of the return address, this should be the last push. It may come from a
+ // previously stored register or loaded directly.
+ if (returnAddrReg != BN_INVALID_REGISTER && instr.GetSourceExpr<LLIL_PUSH>().operation == LLIL_REG
+ && instr.GetSourceExpr<LLIL_PUSH>().GetSourceRegister<LLIL_REG>() == returnAddrReg)
+ {
+ lastPushIsReturnAddr = true;
+ }
+ else if (instr.GetSourceExpr<LLIL_PUSH>().operation == LLIL_LOAD)
+ {
+ RegisterValue addr = instr.GetSourceExpr<LLIL_PUSH>().GetSourceExpr<LLIL_LOAD>().GetValue();
+ if (addr.state == StackFrameOffset && addr.value == 0)
+ {
+ // If the return address has already been overwritten, this is not a match.
+ if (writesToOldReturnAddr)
+ return false;
+ lastPushIsReturnAddr = true;
+ }
+ }
+ break;
+ case LLIL_POP:
+ // Should never see a pop, only pushes.
+ return false;
+ case LLIL_SET_REG:
+ if (instr.GetSourceExpr<LLIL_SET_REG>().operation == LLIL_POP)
+ {
+ // Should never see a pop, only pushes.
+ return false;
+ }
+ else if (instr.GetDestRegister() == m_ebp)
+ {
+ // Should always see a frame pointer being set up, should be pointing at a known
+ // stack offset and there should be only one write.
+ if (writesToFramePointer)
+ return false;
+ if (instr.GetSourceExpr<LLIL_SET_REG>().GetValue().state != StackFrameOffset)
+ return false;
+ writesToFramePointer = true;
+ }
+ else if (instr.GetDestRegister() == m_esp)
+ {
+ // There should only be one write to the stack pointer if it is a subtraction with
+ // an unknown value (the incoming amount of stack space to allocate).
+ if (writesToStackPointer)
+ return false;
+ if (instr.GetSourceExpr<LLIL_SET_REG>().operation != LLIL_SUB)
+ return false;
+ if (instr.GetSourceExpr<LLIL_SET_REG>().GetLeftExpr<LLIL_SUB>().operation != LLIL_REG)
+ return false;
+ if (instr.GetSourceExpr<LLIL_SET_REG>().GetLeftExpr<LLIL_SUB>().GetSourceRegister<LLIL_REG>()
+ != m_esp)
+ return false;
+ if (instr.GetSourceExpr<LLIL_SET_REG>().GetRightExpr<LLIL_SUB>().GetValue().state
+ != UndeterminedValue)
+ return false;
+ writesToStackPointer = true;
+ }
+ else if (instr.GetSourceExpr<LLIL_SET_REG>().operation == LLIL_LOAD)
+ {
+ // Read from memory, check for a read of the return address
+ RegisterValue addr = instr.GetSourceExpr<LLIL_SET_REG>().GetSourceExpr<LLIL_LOAD>().GetValue();
+ if (addr.state != StackFrameOffset || addr.value != 0)
+ break;
+
+ // There should only be one read. Keep track of which register holds it.
+ if (returnAddrReg != BN_INVALID_REGISTER)
+ return false;
+ returnAddrReg = instr.GetDestRegister<LLIL_SET_REG>();
+ }
+ else if (instr.GetDestRegister<LLIL_SET_REG>() == returnAddrReg)
+ {
+ // If register that held return address is clobbered, remember that.
+ returnAddrReg = BN_INVALID_REGISTER;
+ }
+ break;
+ case LLIL_STORE:
+ if (instr.GetDestExpr<LLIL_STORE>().operation == LLIL_REG
+ && instr.GetDestExpr<LLIL_STORE>().GetSourceRegister<LLIL_REG>() == m_fsbase)
+ {
+ // Writing to exception handler pointer, there should only be one of these.
+ if (writesToExceptionFramePointer)
+ return false;
+ writesToExceptionFramePointer = true;
+ }
+ else if (instr.GetSourceExpr<LLIL_STORE>().operation == LLIL_POP)
+ {
+ // Should never see a pop, only pushes.
+ return false;
+ }
+ else
+ {
+ // Check for writes to old return address. There should be only one of these.
+ RegisterValue addr = instr.GetDestExpr<LLIL_STORE>().GetValue();
+ if (addr.state != StackFrameOffset || addr.value != 0)
+ break;
+ if (writesToOldReturnAddr)
+ return false;
+ writesToOldReturnAddr = true;
+ }
+ break;
+ case LLIL_JUMP:
+ case LLIL_GOTO:
+ case LLIL_IF:
+ case LLIL_JUMP_TO:
+ case LLIL_NORET:
+ // Prolog functions are a single basic block, so this isn't one.
+ return false;
+ case LLIL_CALL:
+ case LLIL_CALL_STACK_ADJUST:
+ case LLIL_TAILCALL:
+ case LLIL_SYSCALL:
+ // Prolog functions are leaf functions.
+ return false;
+ case LLIL_UNDEF:
+ case LLIL_UNIMPL:
+ case LLIL_UNIMPL_MEM:
+ case LLIL_BP:
+ case LLIL_TRAP:
+ // Prolog functions should not have unimplemented instructions or exceptions.
+ return false;
+ case LLIL_SET_REG_SPLIT:
+ case LLIL_SET_FLAG:
+ case LLIL_SET_REG_STACK_REL:
+ case LLIL_REG_STACK_PUSH:
+ // Prolog functions shouldn't have any split or float register stack manipluation.
+ return false;
+ default:
+ break;
+ }
+ }
+
+ if (!writesToExceptionFramePointer || !writesToFramePointer || !pushesToStack || !lastPushIsReturnAddr
+ || !writesToOldReturnAddr)
+ return false;
+
+ // Function satisfies constraints and looks like a shared prolog function. Mark it for inlining.
+ func->SetAutoInlinedDuringAnalysis(Confidence<bool>(true, BN_HEURISTIC_CONFIDENCE));
+ return true;
+ }
+};
+
+
+class ExceptionHandlerEpilogFunctionRecognizer : public FunctionRecognizer
+{
+ Ref<Platform> m_platform;
+ uint32_t m_esp, m_ebp, m_fsbase;
+
+public:
+ ExceptionHandlerEpilogFunctionRecognizer(Ref<Platform> platform) : m_platform(platform)
+ {
+ m_esp = platform->GetArchitecture()->GetRegisterByName("esp");
+ m_ebp = platform->GetArchitecture()->GetRegisterByName("ebp");
+ m_fsbase = platform->GetArchitecture()->GetRegisterByName("fsbase");
+ }
+
+ virtual bool RecognizeLowLevelIL(BinaryView* view, Function* func, LowLevelILFunction* il) override
+ {
+ // Make sure the function belongs to the desired platform. Platform specific function recognizers
+ // are not a feature so this was registered for the architecture as a whole.
+ if (func->GetPlatform() != m_platform)
+ return false;
+
+ // If inlining is already too high confidence, don't check as we won't override it.
+ if (func->IsInlinedDuringAnalysis().GetConfidence() >= BN_HEURISTIC_CONFIDENCE)
+ return false;
+
+ // Iterate through the IL instructions and maintain a set of flags on whether this looks
+ // like a shared function epilog.
+ bool writesToExceptionFramePointer = false;
+ bool restoresStackPointer = false;
+ bool popsFromStack = false;
+ bool lastPushBeforeReturn = false;
+ bool stackCookieXor = false;
+ bool stackCookieVerifyCall = false;
+ for (size_t i = 0; i < il->GetInstructionCount(); i++)
+ {
+ LowLevelILInstruction instr = il->GetInstruction(i);
+ if (instr.operation == LLIL_RET)
+ break;
+ switch (instr.operation)
+ {
+ case LLIL_PUSH:
+ // There should be exactly one push instruction right before the return (this
+ // is the return address, though we can't verify that since the frame pointer
+ // is unknown for the analysis engine).
+ if (lastPushBeforeReturn)
+ return false;
+ lastPushBeforeReturn = true;
+ break;
+ case LLIL_POP:
+ // Should never see a standalone pop.
+ return false;
+ case LLIL_SET_REG:
+ if (instr.GetSourceExpr<LLIL_SET_REG>().operation == LLIL_POP)
+ {
+ // Should see only pops before the last push
+ if (lastPushBeforeReturn)
+ return false;
+ popsFromStack = true;
+ break;
+ }
+ else if (instr.GetDestRegister() == m_ebp)
+ {
+ // Should not write to frame pointer until stack pointer is restored
+ if (!restoresStackPointer)
+ return false;
+ }
+ else if (instr.GetDestRegister() == m_esp)
+ {
+ // Ensure that this is a frame pointer restore. There should only be one of these.
+ if (instr.GetSourceExpr<LLIL_SET_REG>().operation != LLIL_REG
+ || instr.GetSourceExpr<LLIL_SET_REG>().GetSourceRegister<LLIL_REG>() != m_ebp)
+ return false;
+ if (restoresStackPointer)
+ return false;
+ restoresStackPointer = true;
+ }
+ else if (instr.GetSourceExpr<LLIL_SET_REG>().operation == LLIL_XOR)
+ {
+ // Look for stack cookie transformations. There should only be one of these, and it
+ // should be before any of the other actions.
+ if (stackCookieXor || writesToExceptionFramePointer || restoresStackPointer || popsFromStack
+ || lastPushBeforeReturn)
+ return false;
+ stackCookieXor = true;
+ }
+ break;
+ case LLIL_STORE:
+ if (instr.GetDestExpr<LLIL_STORE>().operation == LLIL_REG
+ && instr.GetDestExpr<LLIL_STORE>().GetSourceRegister<LLIL_REG>() == m_fsbase)
+ {
+ // Writing to exception handler pointer, there should only be one of these.
+ if (writesToExceptionFramePointer)
+ return false;
+ writesToExceptionFramePointer = true;
+ }
+ else if (instr.GetSourceExpr<LLIL_STORE>().operation == LLIL_POP)
+ {
+ // Should never see a pop to memory, only to registers.
+ return false;
+ }
+ break;
+ case LLIL_JUMP:
+ case LLIL_IF:
+ case LLIL_JUMP_TO:
+ case LLIL_NORET:
+ // Epilog functions are a single basic block, so this isn't one.
+ return false;
+ case LLIL_GOTO:
+ // If there is a goto instruction, it must be to the next instruction (this will happen
+ // when inlining other parts of the epilog).
+ if (instr.GetTarget() != (instr.instructionIndex + 1))
+ return false;
+ break;
+ case LLIL_CALL:
+ // Epilog functions are either leaf functions or contain a single call to a stack cookie
+ // verification function. Check for the stack cookie verification, which will be a call
+ // to a static location just after the cookie transformation, and before any other actions.
+ // There should be only one of these.
+ if (instr.GetDestExpr<LLIL_CALL>().operation != LLIL_CONST
+ && instr.GetDestExpr<LLIL_CALL>().operation != LLIL_CONST_PTR)
+ return false;
+ if (!stackCookieXor || stackCookieVerifyCall || writesToExceptionFramePointer || restoresStackPointer
+ || popsFromStack || lastPushBeforeReturn)
+ return false;
+ stackCookieVerifyCall = true;
+ break;
+ case LLIL_CALL_STACK_ADJUST:
+ case LLIL_TAILCALL:
+ case LLIL_SYSCALL:
+ // Epilog functions should not contain tailcalls, syscalls, or calls that adjust the stack.
+ return false;
+ case LLIL_UNDEF:
+ case LLIL_UNIMPL:
+ case LLIL_UNIMPL_MEM:
+ case LLIL_BP:
+ case LLIL_TRAP:
+ // Epilog functions should not have unimplemented instructions or exceptions.
+ return false;
+ case LLIL_SET_REG_SPLIT:
+ case LLIL_SET_FLAG:
+ case LLIL_SET_REG_STACK_REL:
+ case LLIL_REG_STACK_PUSH:
+ // Epilog functions shouldn't have any split or float register stack manipluation.
+ return false;
+ default:
+ break;
+ }
+ }
+
+ if (!writesToExceptionFramePointer || !restoresStackPointer || !popsFromStack || !lastPushBeforeReturn)
+ return false;
+
+ // Function satisfies constraints and looks like a shared epilog function. Mark it for inlining.
+ func->SetAutoInlinedDuringAnalysis(Confidence<bool>(true, BN_HEURISTIC_CONFIDENCE));
+ return true;
+ }
+};
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+
+#ifndef DEMO_VERSION
+ BINARYNINJAPLUGIN void CorePluginDependencies()
+ {
+ AddOptionalPluginDependency("arch_x86");
+ AddOptionalPluginDependency("arch_armv7");
+ AddOptionalPluginDependency("arch_arm64");
+ AddOptionalPluginDependency("view_pe");
+ }
+#endif
+
+#ifdef DEMO_VERSION
+ bool WindowsPluginInit()
+#else
+ BINARYNINJAPLUGIN bool CorePluginInit()
+#endif
+ {
+ Ref<Architecture> x86 = Architecture::GetByName("x86");
+ Ref<Platform> windowsX86;
+ if (x86)
+ {
+ windowsX86 = new WindowsX86Platform(x86);
+ Platform::Register("windows", windowsX86);
+ BinaryViewType::RegisterDefaultPlatform("PE", x86, windowsX86);
+ BinaryViewType::RegisterDefaultPlatform("COFF", x86, windowsX86);
+ }
+
+ Ref<Architecture> x64 = Architecture::GetByName("x86_64");
+ if (x64)
+ {
+ Ref<Platform> platform;
+
+ platform = new WindowsX64Platform(x64);
+ Platform::Register("windows", platform);
+ BinaryViewType::RegisterDefaultPlatform("PE", x64, platform);
+ BinaryViewType::RegisterDefaultPlatform("COFF", x64, platform);
+ }
+
+ Ref<Architecture> armv7 = Architecture::GetByName("armv7");
+ Ref<Architecture> thumb2 = Architecture::GetByName("thumb2");
+ if (armv7 && thumb2)
+ {
+ Ref<Platform> armPlatform, thumbPlatform;
+
+ armPlatform = new WindowsArmv7Platform(armv7, "windows-armv7");
+ thumbPlatform = new WindowsArmv7Platform(thumb2, "windows-thumb2");
+ armPlatform->AddRelatedPlatform(thumb2, thumbPlatform);
+ thumbPlatform->AddRelatedPlatform(armv7, armPlatform);
+ Platform::Register("windows", armPlatform);
+ Platform::Register("windows", thumbPlatform);
+ BinaryViewType::RegisterDefaultPlatform("PE", armv7, armPlatform);
+ BinaryViewType::RegisterDefaultPlatform("COFF", armv7, armPlatform);
+ BinaryViewType::RegisterDefaultPlatform("COFF", thumb2, thumbPlatform);
+ }
+
+ Ref<Architecture> arm64 = Architecture::GetByName("aarch64");
+ if (arm64)
+ {
+ Ref<Platform> platform;
+
+ platform = new WindowsArm64Platform(arm64);
+ Platform::Register("windows", platform);
+ BinaryViewType::RegisterDefaultPlatform("PE", arm64, platform);
+ BinaryViewType::RegisterDefaultPlatform("COFF", arm64, platform);
+ }
+
+ if (x86 && windowsX86)
+ {
+ // Set up exception handler prolog/epilog function inlining. These are registered for
+ // the entire architecture but internally they check to make sure it is the Windows
+ // platform. Internal implementation details prevent platform-specific function
+ // recognizers from being registered.
+ FunctionRecognizer::RegisterArchitectureFunctionRecognizer(
+ x86, new ExceptionHandlerPrologFunctionRecognizer(windowsX86));
+ FunctionRecognizer::RegisterArchitectureFunctionRecognizer(
+ x86, new ExceptionHandlerEpilogFunctionRecognizer(windowsX86));
+ }
+
+ return true;
+ }
+}