Erroneous patching of call instruction with indirect address
I would like to add instrumentation before an instruction "call QWORD PTR [r15+rbx*8]" (0x41 0xff 0x14 0xdf). However, the Zipr step fails since it tries to patch the instruction in function ZiprPatcherX86_t::ApplyPatch although branching instructions with indirect targets are not meant to be patched as far as I understood. Here's the zipr.log with the error message:
found patch for instruction with prefix. prefix is: A. Recursing at 40076a
insn_first_byte: 0xff
zipr.exe: zipr/src/patcher_x86.cpp:159: virtual void zipr::ZiprPatcherX86_t::ApplyPatch(Zipr_SDK::RangeAddress_t, Zipr_SDK::RangeAddress_t): Assertion '0' failed. /home/franzi/Documents/zipr/irdb-libs/plugins_install/zipr.sh: line 7: 3613117 Aborted
I understood now that the problem is related to the fact that I add assembly before this instruction twice. The MemoryAccessHandler::instrument
function returns the original instruction, which is then in turn instrumented by ControlFlowHandler::checkMem
. If I leave out one of the insertions, the problem disappears. How to correctly add assembly to an instruction twice? The two functions for instrumentation:
IRDB_SDK::Instruction_t *MemoryAccessHandler::instrument(Instruction_t *instruction) {
auto decodedInstruction = DecodedInstruction_t::factory(instruction);
auto operands = decodedInstruction->getOperands();
auto operand = operands[0];
if (!operand->isMemory()) {
operand = operands[1];
}
if (!operand->hasBaseRegister() && !operand->hasIndexRegister()) {
return instruction;
}
std::cout << "MemoryAccessHandler. Operand: " << operand->getString() << std::endl;
string instrumentation = Utils::getStateSavingInstrumentation();
vector<basic_string<char>> instrumentationParams{4};
if (operand->hasBaseRegister()) {
auto baseReg = operand->getBaseRegister();
auto baseRegWidth = disassemblyService->getBaseRegWidth(instruction);
instrumentation = instrumentation +
"mov rdi, %%1\n" + // first argument
"mov rsi, %%2\n" + // second argument
"call 0\n";
instrumentationParams[0] = to_string(baseReg);
instrumentationParams[1] = to_string(baseRegWidth);
}
if (operand->hasIndexRegister()) {
auto indexReg = operand->getIndexRegister();
auto indexRegWidth = disassemblyService->getIndexRegWidth(instruction);
instrumentation = instrumentation +
"mov rdi, %%3\n" + // first argument
"mov rsi, %%4\n" + // second argument
"call 0\n";
instrumentationParams[2] = to_string(indexReg);
instrumentationParams[3] = to_string(indexRegWidth);
}
instrumentation = instrumentation + Utils::getStateRestoringInstrumentation();
const auto new_instr = IRDB_SDK::insertAssemblyInstructionsBefore(fileIr, instruction, instrumentation,
instrumentationParams);
auto calls = DisassemblyService::getCallInstructionPosition(new_instr);
for (auto index: calls) {
new_instr[index]->setTarget(RuntimeLib::checkRegIsInit);
}
return new_instr.back();
}
IRDB_SDK::Instruction_t *ControlFlowHandler::checkMem(IRDB_SDK::Instruction_t *instruction, unique_ptr<DecodedInstruction_t> &decodedInstr) {
auto memOperand = disassemblyService->getMemoryOperandDisassembly(instruction);
auto width = decodedInstr->getOperand(0)->getArgumentSizeInBytes();
string instrumentation = Utils::getStateSavingInstrumentation() +
"lea rdi, %%1\n" + // x
"mov rsi, %%2\n" + // size
"call 0\n" + // __msan_check_mem_is_initialized
Utils::getStateRestoringInstrumentation();
vector<basic_string<char>> instrumentationParams{memOperand, to_string(width)};
const auto new_instr = insertAssemblyInstructionsBefore(fileIr, instruction, instrumentation,
instrumentationParams);
auto calls = DisassemblyService::getCallInstructionPosition(new_instr);
new_instr[calls[0]]->setTarget(RuntimeLib::msan_check_mem_is_initialized);
return new_instr.back();
}
@jdh8d I cannot assign you, so here's a ping.