diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2023-06-13 11:29:42 -0600 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2023-06-13 16:46:47 -0400 |
| commit | 52eb0de5dcddaee2b8bd3122512ae4c20e0e9545 (patch) | |
| tree | 8543df055ebc32d32283c0231cbeb6c7fd424533 /platform | |
| parent | adb7ef55fc4e24f03e6faf353cc9122ee07c714f (diff) | |
Move platform submodules into API
Diffstat (limited to 'platform')
| -rw-r--r-- | platform/decree/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | platform/decree/LICENSE | 13 | ||||
| -rw-r--r-- | platform/decree/README.md | 23 | ||||
| -rw-r--r-- | platform/decree/platform_decree.cpp | 66 | ||||
| -rw-r--r-- | platform/efi/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | platform/freebsd/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | platform/freebsd/LICENSE | 13 | ||||
| -rw-r--r-- | platform/freebsd/README.md | 23 | ||||
| -rw-r--r-- | platform/freebsd/platform_freebsd.cpp | 156 | ||||
| -rw-r--r-- | platform/linux/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | platform/linux/LICENSE | 13 | ||||
| -rw-r--r-- | platform/linux/README.md | 23 | ||||
| -rw-r--r-- | platform/linux/platform_linux.cpp | 305 | ||||
| -rw-r--r-- | platform/mac/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | platform/mac/LICENSE | 13 | ||||
| -rw-r--r-- | platform/mac/README.md | 23 | ||||
| -rw-r--r-- | platform/mac/platform_mac.cpp | 157 | ||||
| -rw-r--r-- | platform/windows/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | platform/windows/LICENSE | 13 | ||||
| -rw-r--r-- | platform/windows/README.md | 23 | ||||
| -rw-r--r-- | platform/windows/platform_windows.cpp | 535 |
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; + } +} |
