From 071198a9c11473190152ed4213fd2ad9597c06bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=A7=E9=83=81=E6=B2=99=E8=8C=B6?= Date: Wed, 1 May 2024 03:47:55 +0800 Subject: [PATCH] Fix tailjump to relocs (#347) Ghidra uses some scripts written in Java to fixup some analysis corner cases (see Ghidra/Features/Base/ghidra_scripts), but currently rz-ghidra is not able to use them, which causes some decompiling issues. This change makes an attempt to fixup one of the corner cases. Details about the issue can be found in #202. We try to solve the issue by adding a hook before decompiling action, but after the initialization of the RizinArchitecture. The hook function uses rizin to analyse shared return calls to relocs, and fixup the P-Code using setFlowOverride() API provided by Ghidra. Fix #202 --- CMakeLists.txt | 2 ++ src/PcodeFixupPreprocessor.cpp | 27 +++++++++++++++++++++++++++ src/PcodeFixupPreprocessor.h | 17 +++++++++++++++++ src/core_ghidra.cpp | 7 +++++++ test/bins/Makefile | 5 ++++- test/bins/sharedReturn.c | 13 +++++++++++++ test/bins/sharedReturn.o | Bin 0 -> 1512 bytes test/db/extras/ghidra | 24 ++++++++++++++++++++++++ 8 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/PcodeFixupPreprocessor.cpp create mode 100644 src/PcodeFixupPreprocessor.h create mode 100644 test/bins/sharedReturn.c create mode 100644 test/bins/sharedReturn.o diff --git a/CMakeLists.txt b/CMakeLists.txt index fa6558fa..3d2ed9ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,8 @@ set(CORE_SOURCE src/RzCoreMutex.cpp src/PrettyXmlEncode.h src/PrettyXmlEncode.cpp + src/PcodeFixupPreprocessor.h + src/PcodeFixupPreprocessor.cpp src/rz_ghidra.h src/rz_ghidra_internal.h) diff --git a/src/PcodeFixupPreprocessor.cpp b/src/PcodeFixupPreprocessor.cpp new file mode 100644 index 00000000..e28ff671 --- /dev/null +++ b/src/PcodeFixupPreprocessor.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2024 Crabtux +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "RizinLoadImage.h" +#include "RizinUtils.h" +#include "PcodeFixupPreprocessor.h" + +#include +#include +#include + +using namespace ghidra; + +void PcodeFixupPreprocessor::fixupSharedReturnJumpToRelocs(RzAnalysisFunction *function, Funcdata *func, RzCore *core, RizinArchitecture &arch) +{ + RzList *xrefs = rz_analysis_function_get_xrefs_from(function); + rz_list_foreach_cpp(xrefs, [&](RzAnalysisXRef *xref){ + // To ensure the instruction is a `jmp` instruction + if (xref->type == RZ_ANALYSIS_XREF_TYPE_CODE) + { + // If the target location is a imported function, then do the patch. + RzBinReloc *reloc = rz_core_get_reloc_to(core, xref->to); + if (reloc != nullptr && reloc->import != nullptr) + func->getOverride().insertFlowOverride(Address(arch.getDefaultCodeSpace(), xref->from), Override::CALL_RETURN); + } + }); +} diff --git a/src/PcodeFixupPreprocessor.h b/src/PcodeFixupPreprocessor.h new file mode 100644 index 00000000..be4f1b34 --- /dev/null +++ b/src/PcodeFixupPreprocessor.h @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2024 Crabtux +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef PCODE_PREPROCESSOR_H +#define PCODE_PREPROCESSOR_H + +#include "RizinArchitecture.h" + +#include + +class PcodeFixupPreprocessor +{ + public: + static void fixupSharedReturnJumpToRelocs(RzAnalysisFunction *function, ghidra::Funcdata *func, RzCore *core, RizinArchitecture &arch); +}; + +#endif \ No newline at end of file diff --git a/src/core_ghidra.cpp b/src/core_ghidra.cpp index 00d50860..b7929904 100644 --- a/src/core_ghidra.cpp +++ b/src/core_ghidra.cpp @@ -8,6 +8,7 @@ #include "CodeXMLParse.h" #include "ArchMap.h" #include "PrettyXmlEncode.h" +#include "PcodeFixupPreprocessor.h" #include "rz_ghidra.h" #include "rz_ghidra_internal.h" @@ -140,6 +141,12 @@ static void Decompile(RzCore *core, ut64 addr, DecompileMode mode, std::stringst ApplyPrintCConfig(core->config, dynamic_cast(arch.print)); if(!func) throw LowlevelError("No function in Scope"); + + // Other archs are not tested + if (strcmp(core->analysis->arch_target->arch, "x86") == 0) + // Must be called after arch.init(), but before decompiling the function + PcodeFixupPreprocessor::fixupSharedReturnJumpToRelocs(function, func, core, arch); + arch.getCore()->sleepBegin(); auto action = arch.allacts.getCurrent(); int res; diff --git a/test/bins/Makefile b/test/bins/Makefile index 50eef138..ba130e5a 100644 --- a/test/bins/Makefile +++ b/test/bins/Makefile @@ -3,7 +3,7 @@ all: .PHONY: clean clean: - rm -fv dectest32 dectest64 rec + rm -fv dectest32 dectest64 rec sharedReturn.o dectest32: dectest.c types.h gcc -m32 -fno-pic -no-pie -fno-omit-frame-pointer -o dectest32 -O0 dectest.c @@ -22,3 +22,6 @@ rec: rec.c types_rec.h strings: strings.c gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -o strings -O0 strings.c + +sharedReturn.o: sharedReturn.c + gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -fno-inline -o sharedReturn.o -O2 -c sharedReturn.c diff --git a/test/bins/sharedReturn.c b/test/bins/sharedReturn.c new file mode 100644 index 00000000..b7ec2a11 --- /dev/null +++ b/test/bins/sharedReturn.c @@ -0,0 +1,13 @@ +#include + +int getNum(void); +int calc(int a, int b); + +int main(void){ + int c = getNum(); + + if (c > 2) + return calc(c, 2); + else + return 0; +} \ No newline at end of file diff --git a/test/bins/sharedReturn.o b/test/bins/sharedReturn.o new file mode 100644 index 0000000000000000000000000000000000000000..9abf334e9bb2970c60ac79fb958a8151e3390e8d GIT binary patch literal 1512 zcmbtSO-md>5Um+EYT^g0MhFR27W zOcy%ZzXU&Ti^!p@%lk|j)9D_s9o(esGW8j zlr@K15sG4MU8e;qZYGIIQI161iF#Z-jNkzvnY;!Op0DJj=@pZ%{&P#1R$;H0*6LKTC?#(3TU9R!_ zlKz>776!DZUw_4dh`l(!{s4)h`}@X?%01EjJ;WvTf)|}lXZ7fVcF}h*j-F=3uctlz d*`bmypFdAY&KSN!rZ6h1@3HXsPT3Fq`acrdZ5;pr literal 0 HcmV?d00001 diff --git a/test/db/extras/ghidra b/test/db/extras/ghidra index b5544a46..ae6ba9ae 100644 --- a/test/db/extras/ghidra +++ b/test/db/extras/ghidra @@ -3364,3 +3364,27 @@ undefined8 main(void) } EOF RUN + +NAME=fixup shared return call to relocs +FILE=bins/sharedReturn.o +CMDS=<