/* Chrysalide - Outil d'analyse de fichiers binaires * operand.c - gestion des operandes de l'architecture x86 * * Copyright (C) 2008-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "operand.h" /****************************************************************************** * * * Paramètres : instr = instruction dont la définition est à compléter. [OUT]* * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * count = quantité d'opérandes à lire. * * ... = éventuelle(s) information(s) complémentaire(s). * * * * Description : Procède à la lecture de trois opérandes donnés. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _x86_read_operands(GArchInstruction *instr, const bin_t *data, off_t *pos, off_t len, unsigned int count, ...) { bool result; /* Bilan à retourner */ va_list ap; /* Liste des compléments */ X86OperandType types[MAX_OPERANDS]; /* Type des opérandes */ unsigned int i; /* Boucle de parcours */ bool op1_first; /* Position de l'opérande #1 */ bool op2_first; /* Position de l'opérande #2 */ MemoryDataSize oprsize; /* Taille des opérandes */ off_t op_pos[MAX_OPERANDS]; /* Position après lecture */ vmpa_t offset; /* Adresse courante */ bin_t base; /* Indice du premier registre */ GArchOperand *op; /* Opérande unique décodé */ if (count > MAX_OPERANDS) return false; result = true; va_start(ap, count); /* Types à charger */ for (i = 0; i < count; i++) types[i] = va_arg(ap, MemoryDataSize); for ( ; i < MAX_OPERANDS; i++) types[i] = X86_OTP_NONE; /* Initialisations */ if (types[0] & X86_OTP_RM_TYPE) { op1_first = true; op2_first = false; } else if (types[1] & X86_OTP_RM_TYPE) { op1_first = false; op2_first = true; } else { op1_first = true; op2_first = false; } oprsize = MDS_UNDEFINED; /* Lecture des opérandes */ for (i = 0; i < count && result; i++) { /* Tête de lecture */ switch (i) { case 0: op_pos[0] = *pos; break; case 1: if ((types[0] & X86_OTP_REG_TYPE || types[0] & X86_OTP_RM_TYPE) && (types[1] & X86_OTP_IMM_TYPE)) op_pos[1] = op_pos[0]; else op_pos[1] = *pos; *pos = op_pos[0]; break; case 2 ... MAX_OPERANDS: *pos = MAX(*pos, op_pos[i - 1]); op_pos[i] = *pos; } /* Lecture */ switch (types[i]) { case X86_OTP_IMM8: assert(0); //op = g_imm_operand_new_from_data_old(MDS_8_BITS, data, &op_pos[i], len, SRE_LITTLE /* FIXME */); break; case X86_OTP_IMM16: assert(0); //op = g_imm_operand_new_from_data_old(MDS_16_BITS, data, &op_pos[i], len, SRE_LITTLE /* FIXME */); break; case X86_OTP_IMM1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); assert(0); //op = g_imm_operand_new_from_data_old(oprsize == MDS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, &op_pos[i], len, SRE_LITTLE /* FIXME */); break; case X86_OTP_MOFFS8: op = g_x86_moffs_operand_new(data, &op_pos[i], len, MDS_8_BITS); break; case X86_OTP_MOFFS1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); op = g_x86_moffs_operand_new(data, &op_pos[i], len, oprsize); break; case X86_OTP_REL8: offset = va_arg(ap, vmpa_t); op = g_x86_relative_operand_new(data, &op_pos[i], len, MDS_8_BITS, offset + 1); break; case X86_OTP_REL1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); offset = va_arg(ap, vmpa_t); op = g_x86_relative_operand_new(data, &op_pos[i], len, oprsize, offset + 1); break; case X86_OTP_R8: op = g_x86_register_operand_new_from_mod_rm(data, &op_pos[i], len, MDS_8_BITS, i == 0 ? op1_first : op2_first); break; case X86_OTP_R1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); op = g_x86_register_operand_new_from_mod_rm(data, &op_pos[i], len, oprsize, i == 0 ? op1_first : op2_first); break; case X86_OTP_OP_R8: base = (bin_t)va_arg(ap, int); op = g_x86_register_operand_new_from_opcode(data, &op_pos[i], len, MDS_8_BITS, base); break; case X86_OTP_OP_R1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); base = (bin_t)va_arg(ap, int); op = g_x86_register_operand_new_from_opcode(data, &op_pos[i], len, oprsize, base); break; case X86_OTP_RM8: op = g_x86_mod_rm_operand_new(data, &op_pos[i], len, MDS_8_BITS); break; case X86_OTP_RM16: op = g_x86_mod_rm_operand_new(data, &op_pos[i], len, MDS_16_BITS); break; case X86_OTP_RM1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); op = g_x86_mod_rm_operand_new(data, &op_pos[i], len, oprsize); break; case X86_OTP_DST_8: op = g_x86_data_operand_new(MDS_8_BITS, true); break; case X86_OTP_DST_1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); op = g_x86_data_operand_new(oprsize == MDS_32_BITS ? MDS_32_BITS : MDS_16_BITS, true); break; case X86_OTP_SRC_8: op = g_x86_data_operand_new(MDS_8_BITS, false); break; case X86_OTP_SRC_1632: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); op = g_x86_data_operand_new(oprsize == MDS_32_BITS ? MDS_32_BITS : MDS_16_BITS, false); break; case X86_OTP_ONE: op = g_imm_operand_new_from_value(MDS_8_BITS, 1); break; case X86_OTP_CL: op = g_x86_register_operand_new_from_index(0x01, MDS_8_BITS); break; case X86_OTP_AL: op = g_x86_register_operand_new_from_index(0x00, MDS_8_BITS); break; case X86_OTP_E_AX: if (oprsize == MDS_UNDEFINED) oprsize = va_arg(ap, MemoryDataSize); op = g_x86_register_operand_new_from_index(0x00, oprsize); break; } if (op == NULL) result = false; else g_arch_instruction_attach_extra_operand(instr, op); } *pos = MAX(*pos, op_pos[i - 1]); return result; }