Skip to content

Commit

Permalink
Merge branch 'dev' into simpl-arch
Browse files Browse the repository at this point in the history
  • Loading branch information
rbran authored May 2, 2024
2 parents 3296f79 + 87b1470 commit 385c888
Show file tree
Hide file tree
Showing 57 changed files with 1,926 additions and 445 deletions.
118 changes: 118 additions & 0 deletions arch/mips/arch_mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,121 @@ class MipsImportedFunctionRecognizer: public FunctionRecognizer
return false;
}


bool RecognizeELFPLTEntries2(BinaryView* data, Function* func, LowLevelILFunction* il)
{
// Look for the following code pattern:
// $t7 = addr_past_got_end
// $t9 = [$t7 - backward_offset_into_got].d
// $t8 = $t7 + (-backward_offset_into_got)
// OPTIONAL: $t7 = addr_past_got_end
// tailcall($t9)
if (il->GetInstructionCount() < 4)
return false;
if (il->GetInstructionCount() > 5)
return false;

LowLevelILInstruction lui = il->GetInstruction(0);
if (lui.operation != LLIL_SET_REG)
return false;
LowLevelILInstruction luiOperand = lui.GetSourceExpr<LLIL_SET_REG>();
if (!LowLevelILFunction::IsConstantType(luiOperand.operation))
return false;
if (luiOperand.size != func->GetArchitecture()->GetAddressSize())
return false;
uint64_t addrPastGot = luiOperand.GetConstant();
uint32_t pltReg = lui.GetDestRegister<LLIL_SET_REG>();

LowLevelILInstruction ld = il->GetInstruction(1);
if (ld.operation != LLIL_SET_REG)
return false;
uint32_t targetReg = ld.GetDestRegister<LLIL_SET_REG>();
LowLevelILInstruction ldOperand = ld.GetSourceExpr<LLIL_SET_REG>();
if (ldOperand.operation != LLIL_LOAD)
return false;
if (ldOperand.size != func->GetArchitecture()->GetAddressSize())
return false;
LowLevelILInstruction ldAddrOperand = ldOperand.GetSourceExpr<LLIL_LOAD>();
uint64_t entry = addrPastGot;
int64_t ldAddrRightOperandValue = 0;

if ((ldAddrOperand.operation == LLIL_ADD) || (ldAddrOperand.operation == LLIL_SUB))
{
LowLevelILInstruction ldAddrLeftOperand = ldAddrOperand.GetRawOperandAsExpr(0);
LowLevelILInstruction ldAddrRightOperand = ldAddrOperand.GetRawOperandAsExpr(1);
if (ldAddrLeftOperand.operation != LLIL_REG)
return false;
if (ldAddrLeftOperand.GetSourceRegister<LLIL_REG>() != pltReg)
return false;
if (!LowLevelILFunction::IsConstantType(ldAddrRightOperand.operation))
return false;
ldAddrRightOperandValue = ldAddrRightOperand.GetConstant();
if (ldAddrOperand.operation == LLIL_SUB)
ldAddrRightOperandValue = -ldAddrRightOperandValue;
entry = addrPastGot + ldAddrRightOperandValue;
}
else if (ldAddrOperand.operation != LLIL_REG) //If theres no constant
return false;

Ref<Symbol> sym = data->GetSymbolByAddress(entry);
if (!sym)
return false;
if (sym->GetType() != ImportAddressSymbol)
return false;

LowLevelILInstruction add = il->GetInstruction(2);
if (add.operation != LLIL_SET_REG)
return false;
LowLevelILInstruction addOperand = add.GetSourceExpr<LLIL_SET_REG>();

if (addOperand.operation == LLIL_ADD)
{
LowLevelILInstruction addLeftOperand = addOperand.GetLeftExpr<LLIL_ADD>();
LowLevelILInstruction addRightOperand = addOperand.GetRightExpr<LLIL_ADD>();
if (addLeftOperand.operation != LLIL_REG)
return false;
if (addLeftOperand.GetSourceRegister<LLIL_REG>() != pltReg)
return false;
if (!LowLevelILFunction::IsConstantType(addRightOperand.operation))
return false;
if (addRightOperand.GetConstant() != ldAddrRightOperandValue)
return false;
}
else if ((addOperand.operation != LLIL_REG) || (addOperand.GetSourceRegister<LLIL_REG>() != pltReg)) //Simple assignment
return false;

LowLevelILInstruction jump = il->GetInstruction(3);
if (jump.operation == LLIL_SET_REG)
{
if (il->GetInstructionCount() != 5)
return false;
if (jump.GetDestRegister<LLIL_SET_REG>() != pltReg)
return false;
LowLevelILInstruction luiOperand = jump.GetSourceExpr<LLIL_SET_REG>();
if (!LowLevelILFunction::IsConstantType(luiOperand.operation))
return false;
if (luiOperand.size != func->GetArchitecture()->GetAddressSize())
return false;
if (((uint64_t) luiOperand.GetConstant()) != addrPastGot)
return false;
jump = il->GetInstruction(4);
}

if ((jump.operation != LLIL_JUMP) && (jump.operation != LLIL_TAILCALL))
return false;
LowLevelILInstruction jumpOperand = (jump.operation == LLIL_JUMP) ? jump.GetDestExpr<LLIL_JUMP>() : jump.GetDestExpr<LLIL_TAILCALL>();
if (jumpOperand.operation != LLIL_REG)
return false;
if (jumpOperand.GetSourceRegister<LLIL_REG>() != targetReg)
return false;

Ref<Symbol> funcSym = Symbol::ImportedFunctionFromImportAddressSymbol(sym, func->GetStart());
data->DefineAutoSymbol(funcSym);
func->ApplyImportedTypes(funcSym);
return true;
}


public:
virtual bool RecognizeLowLevelIL(BinaryView* data, Function* func, LowLevelILFunction* il) override
{
Expand All @@ -1838,6 +1953,9 @@ class MipsImportedFunctionRecognizer: public FunctionRecognizer
if (RecognizeELFPLTEntries1(data, func, il))
return true;

if (RecognizeELFPLTEntries2(data, func, il))
return true;

return false;
}
};
Expand Down
23 changes: 11 additions & 12 deletions arch/riscv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,23 +508,23 @@ impl<D: RiscVDisassembler> architecture::Intrinsic for RiscVIntrinsic<D> {
}
}

fn inputs(&self) -> Vec<NameAndType<String>> {
fn inputs(&self) -> Vec<Ref<NameAndType>> {
match self.id {
Intrinsic::Uret | Intrinsic::Sret | Intrinsic::Mret | Intrinsic::Wfi => {
vec![]
}
Intrinsic::Csrrd => {
vec![NameAndType::new(
"csr".into(),
"csr",
&Type::int(4, false),
max_confidence(),
)]
}
Intrinsic::Csrrw | Intrinsic::Csrwr | Intrinsic::Csrrs | Intrinsic::Csrrc => {
vec![
NameAndType::new("csr".into(), &Type::int(4, false), max_confidence()),
NameAndType::new("csr", &Type::int(4, false), max_confidence()),
NameAndType::new(
"value".into(),
"value",
&Type::int(<D::RegFile as RegFile>::Int::width(), false),
min_confidence(),
),
Expand All @@ -540,8 +540,8 @@ impl<D: RiscVDisassembler> architecture::Intrinsic for RiscVIntrinsic<D> {
| Intrinsic::Fmin(size)
| Intrinsic::Fmax(size) => {
vec![
NameAndType::new("".into(), &Type::float(size as usize), max_confidence()),
NameAndType::new("".into(), &Type::float(size as usize), max_confidence()),
NameAndType::new("", &Type::float(size as usize), max_confidence()),
NameAndType::new("", &Type::float(size as usize), max_confidence()),
]
}
Intrinsic::Fsqrt(size, _)
Expand All @@ -550,28 +550,28 @@ impl<D: RiscVDisassembler> architecture::Intrinsic for RiscVIntrinsic<D> {
| Intrinsic::FcvtFToI(size, _, _)
| Intrinsic::FcvtFToU(size, _, _) => {
vec![NameAndType::new(
"".into(),
"",
&Type::float(size as usize),
max_confidence(),
)]
}
Intrinsic::FcvtIToF(size, _, _) => {
vec![NameAndType::new(
"".into(),
"",
&Type::int(size as usize, true),
max_confidence(),
)]
}
Intrinsic::FcvtUToF(size, _, _) => {
vec![NameAndType::new(
"".into(),
"",
&Type::int(size as usize, false),
max_confidence(),
)]
}
Intrinsic::Fence => {
vec![NameAndType::new(
"".into(),
"",
&Type::int(4, false),
min_confidence(),
)]
Expand Down Expand Up @@ -2428,10 +2428,9 @@ impl<D: 'static + RiscVDisassembler + Send + Sync> RelocationHandler
.iter()
.find(|r| r.info().native_type == Self::R_RISCV_PCREL_HI20)
{
Some(target) => target,
Some(target) => target.target().wrapping_add(target.info().addend as u64),
None => return false,
};
let target = target.target().wrapping_add(target.info().addend as u64);

let offset = target.wrapping_sub(reloc.target()) as u32;
let low_offset = offset & 0xfff;
Expand Down
92 changes: 92 additions & 0 deletions basedetection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) 2015-2024 Vector 35 Inc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include "binaryninjaapi.h"

using namespace BinaryNinja;


BaseAddressDetection::BaseAddressDetection(Ref<BinaryView> bv)
{
m_object = BNCreateBaseAddressDetection(bv->GetObject());
}


BaseAddressDetection::~BaseAddressDetection()
{
BNFreeBaseAddressDetection(m_object);
}


bool BaseAddressDetection::DetectBaseAddress(BaseAddressDetectionSettings& settings)
{
BNBaseAddressDetectionSettings bnSettings = {
settings.Architecture.c_str(),
settings.Analysis.c_str(),
settings.MinStrlen,
settings.Alignment,
settings.LowerBoundary,
settings.UpperBoundary,
settings.POIAnalysis,
settings.MaxPointersPerCluster,
};

return BNDetectBaseAddress(m_object, bnSettings);
}


void BaseAddressDetection::Abort()
{
return BNAbortBaseAddressDetection(m_object);
}


bool BaseAddressDetection::IsAborted()
{
return BNIsBaseAddressDetectionAborted(m_object);
}


std::set<std::pair<size_t, uint64_t>> BaseAddressDetection::GetScores(BNBaseAddressDetectionConfidence* confidence,
uint64_t *lastTestedBaseAddress)
{
std::set<std::pair<size_t, uint64_t>> result;
BNBaseAddressDetectionScore scores[10];
size_t numCandidates = BNGetBaseAddressDetectionScores(m_object, scores, 10, confidence, lastTestedBaseAddress);
for (size_t i = 0; i < numCandidates; i++)
result.insert(std::make_pair(scores[i].Score, scores[i].BaseAddress));
return result;
}


std::vector<BNBaseAddressDetectionReason> BaseAddressDetection::GetReasonsForBaseAddress(uint64_t baseAddress)
{
std::vector<BNBaseAddressDetectionReason> result;
size_t count;
BNBaseAddressDetectionReason *reasons = BNGetBaseAddressDetectionReasons(m_object, baseAddress, &count);
if (!reasons)
return result;

for (size_t i = 0; i < count; i++)
result.push_back(reasons[i]);

BNFreeBaseAddressDetectionReasons(reasons);
return result;
}
56 changes: 56 additions & 0 deletions binaryninjaapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -17378,6 +17378,62 @@ namespace BinaryNinja {
const std::function<void(Symbol*, Type*)>& add);
void Process();
};

struct BaseAddressDetectionSettings
{
std::string Architecture;
std::string Analysis;
uint32_t MinStrlen;
uint32_t Alignment;
uint64_t LowerBoundary;
uint64_t UpperBoundary;
BNBaseAddressDetectionPOISetting POIAnalysis;
uint32_t MaxPointersPerCluster;
};

/*!
\ingroup baseaddressdetection
*/
class BaseAddressDetection
{
BNBaseAddressDetection* m_object;

public:
BaseAddressDetection(Ref<BinaryView> view);
~BaseAddressDetection();

/*! Analyze program, identify pointers and points-of-interest, and detect candidate base addresses

\param settings Base address detection settings
\return true on success, false otherwise
*/
bool DetectBaseAddress(BaseAddressDetectionSettings& settings);

/*! Get the top 10 candidate base addresses and thier scores

\param confidence Confidence level that indicates the likelihood the top base address candidate is correct
\param lastTestedBaseAddress Last base address tested before analysis was aborted or completed
\return Set of pairs containing candidate base addresses and their scores
*/
std::set<std::pair<size_t, uint64_t>> GetScores(BNBaseAddressDetectionConfidence* confidence, uint64_t *lastTestedBaseAddress);

/*! Get a vector of BNBaseAddressDetectionReasons containing information that indicates why a base address was reported as a candidate

\param baseAddress Base address to query reasons for
\return Vector of reason structures containing information about why a base address was reported as a candidate
*/
std::vector<BNBaseAddressDetectionReason> GetReasonsForBaseAddress(uint64_t baseAddress);

/*! Abort base address detection
*/
void Abort();

/*! Determine if base address detection is aborted

\return true if aborted by user, false otherwise
*/
bool IsAborted();
};
} // namespace BinaryNinja


Expand Down
Loading

0 comments on commit 385c888

Please sign in to comment.