Skip to content

Commit d20c74b

Browse files
committed
Expose shared lifted branch overrides across language bindings
Add the core API and C++, Rust, and Python context methods for applying branch overrides to staged LLIL. Update DefaultLiftFunction to use the shared implementation and add Rust binding coverage.
1 parent 8f788dc commit d20c74b

6 files changed

Lines changed: 461 additions & 402 deletions

File tree

‎architecture.cpp‎

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,108 @@ const std::map<ArchAndAddr, std::map<BNBranchType, BranchOverride>>& FunctionLif
666666
}
667667

668668

669+
PreparedLiftedBranchOverride::PreparedLiftedBranchOverride(BNPreparedLiftedBranchOverride* object) : m_object(object)
670+
{}
671+
672+
673+
PreparedLiftedBranchOverride::~PreparedLiftedBranchOverride()
674+
{
675+
BNFreePreparedLiftedBranchOverride(m_object);
676+
}
677+
678+
679+
bool PreparedLiftedBranchOverride::SuppressesInstruction() const
680+
{
681+
return BNPreparedLiftedBranchOverrideSuppressesInstruction(m_object);
682+
}
683+
684+
685+
Ref<LowLevelILFunction> PreparedLiftedBranchOverride::GetSource()
686+
{
687+
if (!m_source)
688+
m_source = new LowLevelILFunction(BNGetPreparedLiftedBranchOverrideSource(m_object));
689+
return m_source;
690+
}
691+
692+
693+
bool PreparedLiftedBranchOverride::Apply(uint64_t continuationAddress)
694+
{
695+
return BNApplyPreparedLiftedBranchOverride(m_object, continuationAddress);
696+
}
697+
698+
699+
struct FunctionLifterContext::LiftedBranchOverrideInputs
700+
{
701+
vector<BNOverridableBranchInfo> branches;
702+
vector<BNBranchOverride> overrides;
703+
vector<BNArchitectureAndAddress> indirectTargets;
704+
BNLiftedBranchOverrideInfo info{};
705+
};
706+
707+
708+
FunctionLifterContext::LiftedBranchOverrideInputs FunctionLifterContext::GetLiftedBranchOverrideInputs(
709+
const ArchAndAddr& location, const vector<OverridableBranchInfo>& branches) const
710+
{
711+
LiftedBranchOverrideInputs result;
712+
auto& rawBranches = result.branches;
713+
auto& rawOverrides = result.overrides;
714+
auto& indirectTargets = result.indirectTargets;
715+
auto it = m_branchOverrides.find(location);
716+
if (!location.arch || (it == m_branchOverrides.end()))
717+
return result;
718+
719+
rawBranches.reserve(branches.size());
720+
for (const auto& branch : branches)
721+
rawBranches.push_back({branch.type, branch.target, branch.arch ? branch.arch->GetObject() : nullptr});
722+
723+
rawOverrides.reserve(it->second.size());
724+
for (const auto& [originalType, value] : it->second)
725+
{
726+
rawOverrides.push_back({location.arch->GetObject(), location.address, originalType, value.type,
727+
value.target.has_value(), value.targetArch ? value.targetArch->GetObject() : nullptr,
728+
value.target.value_or(0)});
729+
}
730+
731+
const set<ArchAndAddr>* targets = nullptr;
732+
if (auto user = m_userIndirectBranches.find(location); user != m_userIndirectBranches.end())
733+
targets = &user->second;
734+
else if (auto automatic = m_autoIndirectBranches.find(location); automatic != m_autoIndirectBranches.end())
735+
targets = &automatic->second;
736+
if (targets)
737+
{
738+
indirectTargets.reserve(targets->size());
739+
for (const auto& target : *targets)
740+
indirectTargets.push_back({target.arch->GetObject(), target.address});
741+
}
742+
743+
result.info = {location.arch->GetObject(), location.address, 0,
744+
rawBranches.data(), rawBranches.size(), rawOverrides.data(), rawOverrides.size(),
745+
m_noReturnCalls.count(location) != 0, indirectTargets.data(), indirectTargets.size()};
746+
return result;
747+
}
748+
749+
750+
unique_ptr<PreparedLiftedBranchOverride> FunctionLifterContext::PrepareLiftedBranchOverrides(
751+
LowLevelILFunction& dest, BasicBlock* block, const ArchAndAddr& location,
752+
const vector<OverridableBranchInfo>& branches) const
753+
{
754+
auto inputs = GetLiftedBranchOverrideInputs(location, branches);
755+
if (!inputs.info.arch)
756+
return nullptr;
757+
auto result = BNPrepareLiftedBranchOverrides(dest.GetObject(), block ? block->GetObject() : nullptr, &inputs.info);
758+
return result ? make_unique<PreparedLiftedBranchOverride>(result) : nullptr;
759+
}
760+
761+
762+
bool FunctionLifterContext::ApplyLiftedBranchOverrides(LowLevelILFunction& dest, LowLevelILFunction& source,
763+
const ArchAndAddr& location, uint64_t continuationAddress, const vector<OverridableBranchInfo>& branches) const
764+
{
765+
auto inputs = GetLiftedBranchOverrideInputs(location, branches);
766+
inputs.info.continuationAddress = continuationAddress;
767+
return inputs.info.arch && BNApplyLiftedBranchOverrides(dest.GetObject(), source.GetObject(), &inputs.info);
768+
}
769+
770+
669771
Ref<Logger>& FunctionLifterContext::GetLogger()
670772
{
671773
return m_logger;

‎binaryninjaapi.h‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9850,6 +9850,24 @@ namespace BinaryNinja {
98509850
void Finalize();
98519851
};
98529852

9853+
// A prepared override owns its inputs and staging IL. Use only while lifting.
9854+
// The architecture chooses the instruction group and its continuation address.
9855+
class PreparedLiftedBranchOverride
9856+
{
9857+
BNPreparedLiftedBranchOverride* m_object;
9858+
Ref<LowLevelILFunction> m_source;
9859+
9860+
public:
9861+
explicit PreparedLiftedBranchOverride(BNPreparedLiftedBranchOverride* object);
9862+
~PreparedLiftedBranchOverride();
9863+
PreparedLiftedBranchOverride(const PreparedLiftedBranchOverride&) = delete;
9864+
PreparedLiftedBranchOverride& operator=(const PreparedLiftedBranchOverride&) = delete;
9865+
bool SuppressesInstruction() const;
9866+
Ref<LowLevelILFunction> GetSource();
9867+
// A successful application consumes the prepared override; a second call returns false.
9868+
bool Apply(uint64_t continuationAddress);
9869+
};
9870+
98539871
class FunctionLifterContext
98549872
{
98559873
Ref<LowLevelILFunction> m_function;
@@ -9867,6 +9885,9 @@ namespace BinaryNinja {
98679885
bool* m_containsInlinedFunctions;
98689886
void* m_functionArchContext;
98699887
Ref<LifterInstructionData> m_lifterInstructionData;
9888+
struct LiftedBranchOverrideInputs;
9889+
LiftedBranchOverrideInputs GetLiftedBranchOverrideInputs(
9890+
const ArchAndAddr& location, const std::vector<OverridableBranchInfo>& branches) const;
98709891

98719892
public:
98729893
BNFunctionLifterContext* m_context;
@@ -9881,6 +9902,17 @@ namespace BinaryNinja {
98819902
std::map<ArchAndAddr, std::set<ArchAndAddr>>& GetUserIndirectBranches();
98829903
std::map<ArchAndAddr, std::set<ArchAndAddr>>& GetAutoIndirectBranches();
98839904
const std::map<ArchAndAddr, std::map<BNBranchType, BranchOverride>>& GetBranchOverrides() const;
9905+
// Returns null for no matching overrides or invalid inputs, without changing dest.
9906+
// The result owns a snapshot of the inputs; no staging IL is allocated until GetSource.
9907+
// See BNPrepareLiftedBranchOverrides and BNApplyLiftedBranchOverrides for requirements.
9908+
std::unique_ptr<PreparedLiftedBranchOverride> PrepareLiftedBranchOverrides(LowLevelILFunction& dest,
9909+
BasicBlock* block, const ArchAndAddr& location, const std::vector<OverridableBranchInfo>& branches) const;
9910+
// Append an isolated, unfinalized instruction group using this context's overrides.
9911+
// See BNApplyLiftedBranchOverrides for label, temporary-register, and ownership requirements.
9912+
// False leaves dest untouched, including when no original branch has an override.
9913+
bool ApplyLiftedBranchOverrides(LowLevelILFunction& dest, LowLevelILFunction& source,
9914+
const ArchAndAddr& location, uint64_t continuationAddress,
9915+
const std::vector<OverridableBranchInfo>& branches) const;
98849916
std::set<uint64_t>& GetInlinedCalls();
98859917
void SetContainsInlinedFunctions(bool value);
98869918
void* GetFunctionArchContextRaw() const { return m_functionArchContext; }

‎binaryninjacore.h‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ extern "C"
255255
typedef struct BNFunction BNFunction;
256256
typedef struct BNBasicBlock BNBasicBlock;
257257
typedef struct BNLifterInstructionData BNLifterInstructionData;
258+
typedef struct BNPreparedLiftedBranchOverride BNPreparedLiftedBranchOverride;
258259
typedef struct BNDownloadProvider BNDownloadProvider;
259260
typedef struct BNDownloadInstance BNDownloadInstance;
260261
typedef struct BNWebsocketProvider BNWebsocketProvider;
@@ -2187,6 +2188,20 @@ extern "C"
21872188
uint64_t replacementTarget;
21882189
} BNBranchOverride;
21892190

2191+
typedef struct BNLiftedBranchOverrideInfo
2192+
{
2193+
BNArchitecture* arch;
2194+
uint64_t address;
2195+
uint64_t continuationAddress;
2196+
const BNOverridableBranchInfo* branches;
2197+
size_t branchCount;
2198+
const BNBranchOverride* overrides;
2199+
size_t overrideCount;
2200+
bool noReturnCall;
2201+
const BNArchitectureAndAddress* indirectTargets;
2202+
size_t indirectTargetCount;
2203+
} BNLiftedBranchOverrideInfo;
2204+
21902205
typedef struct BNBasicBlockAnalysisContext
21912206
{
21922207
BNFunction* function;
@@ -5894,6 +5909,17 @@ extern "C"
58945909
BNBasicBlockAnalysisContext* context);
58955910
BINARYNINJACOREAPI bool BNArchitectureSetDefaultLiftFunctionCallback(void *callback);
58965911
BINARYNINJACOREAPI bool BNArchitectureDefaultLiftFunction(BNLowLevelILFunction* function, BNFunctionLifterContext* context);
5912+
BINARYNINJACOREAPI bool BNApplyLiftedBranchOverrides(BNLowLevelILFunction* dest,
5913+
BNLowLevelILFunction* source, const BNLiftedBranchOverrideInfo* info);
5914+
BINARYNINJACOREAPI BNPreparedLiftedBranchOverride* BNPrepareLiftedBranchOverrides(
5915+
BNLowLevelILFunction* dest, BNBasicBlock* block, const BNLiftedBranchOverrideInfo* info);
5916+
BINARYNINJACOREAPI void BNFreePreparedLiftedBranchOverride(BNPreparedLiftedBranchOverride* prepared);
5917+
BINARYNINJACOREAPI bool BNPreparedLiftedBranchOverrideSuppressesInstruction(
5918+
BNPreparedLiftedBranchOverride* prepared);
5919+
BINARYNINJACOREAPI BNLowLevelILFunction* BNGetPreparedLiftedBranchOverrideSource(
5920+
BNPreparedLiftedBranchOverride* prepared);
5921+
BINARYNINJACOREAPI bool BNApplyPreparedLiftedBranchOverride(
5922+
BNPreparedLiftedBranchOverride* prepared, uint64_t continuationAddress);
58975923
BINARYNINJACOREAPI bool BNArchitectureLiftFunction(BNArchitecture* arch, BNLowLevelILFunction* function,
58985924
BNFunctionLifterContext* context);
58995925
BINARYNINJACOREAPI void BNArchitectureFreeFunctionArchContext(BNArchitecture* arch, void* context);

0 commit comments

Comments
 (0)