bool VeriFlowAnalysis::MergeRegisterValues(uint32_t dex_pc) { if (dex_pc >= code_item_accessor_.InsnsSizeInCodeUnits()) { returnfalse;
} // TODO: Do the merging. Right now, just return that we should continue // the iteration if the instruction has not been visited. if (!instruction_infos_[dex_pc].has_been_visited) {
dex_registers_[dex_pc]->assign(current_registers_.begin(), current_registers_.end()); returntrue;
} returnfalse;
}
if (code_item_accessor_.TriesSize() != 0) { // TODO: We need to mark the range of dex pcs as flowing in the handlers. /* for(constDexFile::TryItem&try_item:code_item_accessor_.TryItems()){ uint32_tdex_pc_start=try_item.start_addr_; uint32_tdex_pc_end=dex_pc_start+try_item.insn_count_; }
*/
// Iterate over all instructions and find branching instructions. const uint32_t max_pc = code_item_accessor_.InsnsSizeInCodeUnits(); for (const DexInstructionPcPair& pair : code_item_accessor_) { const uint32_t dex_pc = pair.DexPc(); const Instruction& instruction = pair.Inst(); if (dex_pc >= max_pc) { // We need to prevent abnormal access for outside of code break;
}
void VeriFlowAnalysis::UpdateRegister(uint32_t dex_register,
RegisterSource kind,
VeriClass* cls,
uint32_t source_id) { // veridex doesn't do any code verification, so it can be that there are bogus dex // instructions that update a non-existent register. if (dex_register < current_registers_.size()) {
current_registers_[dex_register] = RegisterValue(
kind, DexFileReference(&resolver_->GetDexFile(), source_id), cls);
}
}
void VeriFlowAnalysis::AnalyzeCode() {
std::vector<uint32_t> work_list;
work_list.push_back(0); // Iterate over the code. // When visiting unconditional branches (goto), move to that instruction. // When visiting conditional branches, move to one destination, and put the other // in the worklist. while (!work_list.empty()) {
uint32_t dex_pc = work_list.back();
work_list.pop_back();
CHECK(IsBranchTarget(dex_pc));
current_registers_ = *dex_registers_[dex_pc].get(); const uint32_t max_pc = code_item_accessor_.InsnsSizeInCodeUnits(); while (true) { if (dex_pc >= max_pc) { // We need to prevent abnormal access for outside of code break;
} const uint16_t* insns = code_item_accessor_.Insns() + dex_pc; const Instruction& inst = *Instruction::At(insns);
ProcessDexInstruction(inst);
SetVisited(dex_pc);
if (IsBranchTarget(dex_pc)) { if (MergeRegisterValues(dex_pc)) {
current_registers_ = *dex_registers_[dex_pc].get();
} else { break;
}
}
}
}
}
void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) { switch (instruction.Opcode()) { case Instruction::CONST_4: {
int32_t register_index = instruction.VRegA();
int32_t value = instruction.VRegB_11n();
UpdateRegister(register_index, value, VeriClass::integer_); break;
} case Instruction::CONST_16: {
int32_t register_index = instruction.VRegA();
int32_t value = instruction.VRegB_21s();
UpdateRegister(register_index, value, VeriClass::integer_); break;
}
case Instruction::CONST: {
int32_t register_index = instruction.VRegA();
int32_t value = instruction.VRegB_31i();
UpdateRegister(register_index, value, VeriClass::integer_); break;
}
case Instruction::CONST_HIGH16: {
int32_t register_index = instruction.VRegA();
int32_t value = instruction.VRegB_21h();
UpdateRegister(register_index, value, VeriClass::integer_); break;
}
case Instruction::CONST_WIDE_16: case Instruction::CONST_WIDE_32: case Instruction::CONST_WIDE: case Instruction::CONST_WIDE_HIGH16: {
int32_t register_index = instruction.VRegA();
UpdateRegister(register_index, VeriClass::long_); break;
}
case Instruction::MOVE: case Instruction::MOVE_FROM16: case Instruction::MOVE_16: {
UpdateRegister(instruction.VRegA(), GetRegister(instruction.VRegB())); break;
}
case Instruction::MOVE_WIDE: case Instruction::MOVE_WIDE_FROM16: case Instruction::MOVE_WIDE_16: {
UpdateRegister(instruction.VRegA(), GetRegister(instruction.VRegB())); break;
}
case Instruction::MOVE_OBJECT: case Instruction::MOVE_OBJECT_16: case Instruction::MOVE_OBJECT_FROM16: {
UpdateRegister(instruction.VRegA(), GetRegister(instruction.VRegB())); break;
} case Instruction::CONST_CLASS: {
UpdateRegister(instruction.VRegA_21c(),
RegisterSource::kClass,
VeriClass::class_,
instruction.VRegB_21c()); break;
} case Instruction::CONST_STRING: {
UpdateRegister(instruction.VRegA_21c(),
RegisterSource::kString,
VeriClass::string_,
instruction.VRegB_21c()); break;
}
case Instruction::CONST_STRING_JUMBO: {
UpdateRegister(instruction.VRegA_31c(),
RegisterSource::kString,
VeriClass::string_,
instruction.VRegB_31c()); break;
} case Instruction::INVOKE_DIRECT: case Instruction::INVOKE_INTERFACE: case Instruction::INVOKE_STATIC: case Instruction::INVOKE_SUPER: case Instruction::INVOKE_VIRTUAL: {
last_result_ = AnalyzeInvoke(instruction, /* is_range= */ false); break;
}
case Instruction::INVOKE_DIRECT_RANGE: case Instruction::INVOKE_INTERFACE_RANGE: case Instruction::INVOKE_STATIC_RANGE: case Instruction::INVOKE_SUPER_RANGE: case Instruction::INVOKE_VIRTUAL_RANGE: {
last_result_ = AnalyzeInvoke(instruction, /* is_range= */ true); break;
}
case Instruction::MOVE_RESULT: case Instruction::MOVE_RESULT_WIDE: case Instruction::MOVE_RESULT_OBJECT: {
UpdateRegister(instruction.VRegA(), last_result_); break;
} case Instruction::RETURN_VOID: case Instruction::RETURN_OBJECT: case Instruction::RETURN_WIDE: case Instruction::RETURN: { break;
}
// If operations will be handled when looking at the control flow. #define IF_XX(cond) \ case Instruction::IF_##cond: break; \ case Instruction::IF_##cond##Z: break
case Instruction::GOTO: case Instruction::GOTO_16: case Instruction::GOTO_32: { break;
} case Instruction::INVOKE_POLYMORPHIC: { // TODO break;
}
case Instruction::INVOKE_POLYMORPHIC_RANGE: { // TODO break;
}
case Instruction::NEG_INT: case Instruction::NEG_LONG: case Instruction::NEG_FLOAT: case Instruction::NEG_DOUBLE: case Instruction::NOT_INT: case Instruction::NOT_LONG: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::INT_TO_LONG: case Instruction::INT_TO_FLOAT: case Instruction::INT_TO_DOUBLE: case Instruction::LONG_TO_INT: case Instruction::LONG_TO_FLOAT: case Instruction::LONG_TO_DOUBLE: case Instruction::FLOAT_TO_INT: case Instruction::FLOAT_TO_LONG: case Instruction::FLOAT_TO_DOUBLE: case Instruction::DOUBLE_TO_INT: case Instruction::DOUBLE_TO_LONG: case Instruction::DOUBLE_TO_FLOAT: case Instruction::INT_TO_BYTE: case Instruction::INT_TO_SHORT: case Instruction::INT_TO_CHAR: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::ADD_INT: case Instruction::ADD_LONG: case Instruction::ADD_DOUBLE: case Instruction::ADD_FLOAT: case Instruction::SUB_INT: case Instruction::SUB_LONG: case Instruction::SUB_FLOAT: case Instruction::SUB_DOUBLE: case Instruction::MUL_INT: case Instruction::MUL_LONG: case Instruction::MUL_FLOAT: case Instruction::MUL_DOUBLE: case Instruction::DIV_INT: case Instruction::DIV_LONG: case Instruction::DIV_FLOAT: case Instruction::DIV_DOUBLE: case Instruction::REM_INT: case Instruction::REM_LONG: case Instruction::REM_FLOAT: case Instruction::REM_DOUBLE: case Instruction::AND_INT: case Instruction::AND_LONG: case Instruction::SHL_INT: case Instruction::SHL_LONG: case Instruction::SHR_INT: case Instruction::SHR_LONG: case Instruction::USHR_INT: case Instruction::USHR_LONG: case Instruction::OR_INT: case Instruction::OR_LONG: case Instruction::XOR_INT: case Instruction::XOR_LONG: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::ADD_INT_2ADDR: case Instruction::ADD_LONG_2ADDR: case Instruction::ADD_DOUBLE_2ADDR: case Instruction::ADD_FLOAT_2ADDR: case Instruction::SUB_INT_2ADDR: case Instruction::SUB_LONG_2ADDR: case Instruction::SUB_FLOAT_2ADDR: case Instruction::SUB_DOUBLE_2ADDR: case Instruction::MUL_INT_2ADDR: case Instruction::MUL_LONG_2ADDR: case Instruction::MUL_FLOAT_2ADDR: case Instruction::MUL_DOUBLE_2ADDR: case Instruction::DIV_INT_2ADDR: case Instruction::DIV_LONG_2ADDR: case Instruction::REM_INT_2ADDR: case Instruction::REM_LONG_2ADDR: case Instruction::REM_FLOAT_2ADDR: case Instruction::REM_DOUBLE_2ADDR: case Instruction::SHL_INT_2ADDR: case Instruction::SHL_LONG_2ADDR: case Instruction::SHR_INT_2ADDR: case Instruction::SHR_LONG_2ADDR: case Instruction::USHR_INT_2ADDR: case Instruction::USHR_LONG_2ADDR: case Instruction::DIV_FLOAT_2ADDR: case Instruction::DIV_DOUBLE_2ADDR: case Instruction::AND_INT_2ADDR: case Instruction::AND_LONG_2ADDR: case Instruction::OR_INT_2ADDR: case Instruction::OR_LONG_2ADDR: case Instruction::XOR_INT_2ADDR: case Instruction::XOR_LONG_2ADDR: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::ADD_INT_LIT16: case Instruction::AND_INT_LIT16: case Instruction::OR_INT_LIT16: case Instruction::XOR_INT_LIT16: case Instruction::RSUB_INT: case Instruction::MUL_INT_LIT16: case Instruction::DIV_INT_LIT16: case Instruction::REM_INT_LIT16: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::ADD_INT_LIT8: case Instruction::AND_INT_LIT8: case Instruction::OR_INT_LIT8: case Instruction::XOR_INT_LIT8: case Instruction::RSUB_INT_LIT8: case Instruction::MUL_INT_LIT8: case Instruction::DIV_INT_LIT8: case Instruction::REM_INT_LIT8: case Instruction::SHL_INT_LIT8: case Instruction::SHR_INT_LIT8: case Instruction::USHR_INT_LIT8: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::CMP_LONG: case Instruction::CMPG_FLOAT: case Instruction::CMPG_DOUBLE: case Instruction::CMPL_FLOAT: case Instruction::CMPL_DOUBLE: {
UpdateRegister(instruction.VRegA(), VeriClass::integer_); break;
}
case Instruction::NOP: break;
case Instruction::IGET: case Instruction::IGET_WIDE: case Instruction::IGET_OBJECT: case Instruction::IGET_BOOLEAN: case Instruction::IGET_BYTE: case Instruction::IGET_CHAR: case Instruction::IGET_SHORT: {
UpdateRegister(instruction.VRegA_22c(), GetFieldType(instruction.VRegC_22c())); break;
}
case Instruction::IPUT: case Instruction::IPUT_WIDE: case Instruction::IPUT_OBJECT: case Instruction::IPUT_BOOLEAN: case Instruction::IPUT_BYTE: case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: {
AnalyzeFieldSet(instruction); break;
}
case Instruction::SGET: case Instruction::SGET_WIDE: case Instruction::SGET_OBJECT: case Instruction::SGET_BOOLEAN: case Instruction::SGET_BYTE: case Instruction::SGET_CHAR: case Instruction::SGET_SHORT: {
uint32_t dest_reg = instruction.VRegA_21c();
uint16_t field_index = instruction.VRegB_21c(); if (VeriClass::sdkInt_ != nullptr && resolver_->GetField(field_index) == VeriClass::sdkInt_) {
UpdateRegister(dest_reg, gTargetSdkVersion, VeriClass::integer_);
} else {
UpdateRegister(dest_reg, GetFieldType(field_index));
} break;
}
case Instruction::SPUT: case Instruction::SPUT_WIDE: case Instruction::SPUT_OBJECT: case Instruction::SPUT_BOOLEAN: case Instruction::SPUT_BYTE: case Instruction::SPUT_CHAR: case Instruction::SPUT_SHORT: {
AnalyzeFieldSet(instruction); break;
}
if (method == VeriClass::forName_) { // Class.forName. Fetch the first parameter.
RegisterValue value = GetRegister(GetParameterAt(instruction, is_range, args, 0)); return RegisterValue(
value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
} elseif (IsGetField(method)) { // Class.getField or Class.getDeclaredField. Fetch the first parameter for the class, and the // second parameter for the field name.
RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
uses_.push_back(ReflectAccessInfo(cls, name, /* is_method= */ false)); return GetReturnType(id);
} elseif (IsGetMethod(method)) { // Class.getMethod or Class.getDeclaredMethod. Fetch the first parameter for the class, and the // second parameter for the field name.
RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
uses_.push_back(ReflectAccessInfo(cls, name, /* is_method= */ true)); return GetReturnType(id);
} elseif (method == VeriClass::getClass_) { // Get the type of the first parameter.
RegisterValue obj = GetRegister(GetParameterAt(instruction, is_range, args, 0)); const VeriClass* cls = obj.GetType(); if (cls != nullptr && cls->GetClassDef() != nullptr) { const dex::ClassDef* def = cls->GetClassDef(); return RegisterValue(
RegisterSource::kClass,
DexFileReference(&resolver_->GetDexFileOf(*cls), def->class_idx_.index_),
VeriClass::class_);
} else { return RegisterValue(
obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
}
} elseif (method == VeriClass::loadClass_) { // ClassLoader.loadClass. Fetch the first parameter.
RegisterValue value = GetRegister(GetParameterAt(instruction, is_range, args, 1)); return RegisterValue(
value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
} else { // Return a RegisterValue referencing the method whose type is the return type // of the method. return GetReturnType(id);
}
}
void FlowAnalysisCollector::AnalyzeFieldSet([[maybe_unused]] const Instruction& instruction) { // There are no fields that escape reflection uses.
}
RegisterValue FlowAnalysisSubstitutor::AnalyzeInvoke(const Instruction& instruction, bool is_range) {
uint32_t id = is_range ? instruction.VRegB_3rc() : instruction.VRegB_35c();
MethodReference method(&resolver_->GetDexFile(), id); // TODO: doesn't work for multidex // TODO: doesn't work for overriding (but maybe should be done at a higher level); auto method_accesses_it = accesses_.find(method); if (method_accesses_it == accesses_.end()) { return GetReturnType(id);
}
uint32_t args[5]; if (!is_range) {
instruction.GetVarArgs(args);
} for (const ReflectAccessInfo& info : method_accesses_it->second) { if (info.cls.IsParameter() || info.name.IsParameter()) {
RegisterValue cls = info.cls.IsParameter()
? GetRegister(GetParameterAt(instruction, is_range, args, info.cls.GetParameterIndex()))
: info.cls;
RegisterValue name = info.name.IsParameter()
? GetRegister(GetParameterAt(instruction, is_range, args, info.name.GetParameterIndex()))
: info.name;
uses_.push_back(ReflectAccessInfo(cls, name, info.is_method));
}
} return GetReturnType(id);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.