int main(int argc, const char* argv[]) { if (argc != 3) { std::cerr << "Wrong number of parameters. Should be 2." << std::endl; return 0; } Disassembler disassembler; if (disassembler.LoadAssembly(argv[2])) disassembler.Disassemble(std::cout); return 0; }
virtual bool PostInit() override { auto func_base = (uintptr_t)this->GetFuncAddr(); auto l_is_call_to_addr = [](const auto& insn, void *addr){ if (insn.ID() != X86_INS_CALL) return false; auto operands = insn.Operands(); if (operands.size() != 1) return false; auto op0 = operands[0]; if (op0.Type() != X86_OP_IMM || op0.Imm_U32() != (uintptr_t)addr) return false; return true; }; auto l_is_push_imm32_arg = [](const auto& insn, uint32_t esp_off, uint32_t imm_val){ if (insn.ID() != X86_INS_MOV) return false; auto operands = insn.Operands(); if (operands.size() != 2) return false; auto op0 = operands[0]; if (op0.Type() != X86_OP_MEM || op0.Size() != 4 || op0.Mem_Seg() != X86_REG_INVALID || op0.Mem_Base() != X86_REG_ESP || op0.Mem_Index() != X86_REG_INVALID || op0.Mem_Disp() != esp_off) return false; auto op1 = operands[1]; if (op1.Type() != X86_OP_IMM || op1.Size() != 4 || op1.Imm_U32() != imm_val) return false; return true; }; auto l_is_test_al = [](const auto& insn){ if (insn.ID() != X86_INS_TEST) return false; auto operands = insn.Operands(); if (operands.size() != 2) return false; auto op0 = operands[0]; if (op0.Type() != X86_OP_REG || op0.Reg() != X86_REG_AL) return false; auto op1 = operands[1]; if (op1.Type() != X86_OP_REG || op1.Reg() != X86_REG_AL) return false; return true; }; auto l_is_jcc_imm = [](const auto& insn){ switch (insn.ID()) { case X86_INS_JAE: case X86_INS_JA: case X86_INS_JBE: case X86_INS_JB: case X86_INS_JE: case X86_INS_JGE: case X86_INS_JG: case X86_INS_JLE: case X86_INS_JL: case X86_INS_JNE: case X86_INS_JNO: case X86_INS_JNP: case X86_INS_JNS: case X86_INS_JO: case X86_INS_JP: case X86_INS_JS: break; default: return false; } auto operands = insn.Operands(); if (operands.size() != 1) return false; auto op0 = operands[0]; if (op0.Type() != X86_OP_IMM) return false; return true; }; void *call_target = AddrManager::GetAddr("CTFPlayer::IsPlayerClass"); if (call_target == nullptr) return false; Disassembler<true> disasm; auto result = disasm.Disassemble(func_base, s_DisasmLimit); auto it_arg4 = result.end(); auto it_call = result.end(); auto it_test = result.end(); auto it_jcc = result.end(); for (auto i = result.begin(); i != result.end(); ++i) { // auto insn = *i; // uintptr_t off = insn.Addr() - func_base; // if (off >= 0x5e2 && off < 0x600) { // DevMsg("\n+0x%03x: %s %s\n", off, insn.MnemonicStr(), insn.OperandStr()); // // DevMsg("Bytes:"); // for (auto byte : insn.Bytes()) { // DevMsg(" %02X", byte); // } // DevMsg("\n"); // } /* find the call to CTFPlayer::IsPlayerClass */ if (l_is_call_to_addr(*i, call_target)) { it_call = i; DevMsg("Found call @ +0x%03x\n", (*it_call).Addr() - func_base); for (auto j = i - 1; j >= i - 4 && j != result.begin(); --j) { if (it_arg4 == result.end() && l_is_push_imm32_arg(*j, 0x4, TF_CLASS_ENGINEER)) { it_arg4 = j; DevMsg("Found arg4 @ +0x%03x\n", (*it_arg4).Addr() - func_base); } } for (auto j = i + 1; j <= i + 1 && j != result.end(); ++j) { if (it_test == result.end() && l_is_test_al(*j)) { it_test = j; DevMsg("Found test @ +0x%03x\n", (*it_test).Addr() - func_base); } } for (auto j = i + 2; j <= i + 2 && j != result.end(); ++j) { if (it_jcc == result.end() && l_is_jcc_imm(*j)) { it_jcc = j; DevMsg("Found jcc @ +0x%03x\n", (*it_jcc).Addr() - func_base); } } } } #if 0 bool result = disasm.IterateRange(this->GetFuncAddr(), s_DisasmLimit, [=](const InstructionDetailed& insn){ uint32_t off = insn.Addr() - (uintptr_t)this->GetFuncAddr(); if (off >= 0x5e2 && off < 0x600) { DevMsg("\n+0x%03x: %s %s\n", off, insn.MnemonicStr(), insn.OperandStr()); DevMsg("Bytes:"); for (auto byte : insn.Bytes()) { DevMsg(" %02X", byte); } DevMsg("\n"); } /* DevMsg("Insn @ %s+0x%03x: mnemonic '%s' opcode '%s'\n", this->GetFuncName(), (insn.Addr() - (uintptr_t)this->GetFuncAddr()), insn.MnemonicStr(), insn.OperandStr()); if (insn.ID() != X86_INS_CALL) return true; DevMsg("Call @ %s+0x%03x: mnemonic '%s' opcode '%s'\n", this->GetFuncName(), (insn.Addr() - (uintptr_t)this->GetFuncAddr()), insn.MnemonicStr(), insn.OperandStr()); DevMsg("Bytes:"); for (auto byte : insn.Bytes()) { DevMsg(" %02X", byte); } DevMsg("\n");*/ return true; // TODO: return false if we find what we're looking for // also set m_bFound // also set m_FuncOff // also set up m_Buf and m_Mask }); DevMsg("PostInit: result is %d, error is '%s'\n", result, disasm.ErrorString()); #endif // TODO: return false upon failure return true; }