From a4c030b500d9c67664c8c572909a4b6e60a7daf8 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 23 Apr 2011 20:50:52 +0000 Subject: [PATCH] Beginning to decode Dalvik instructions again --- src/arch.c | 17 ++++-- src/arch/dalvik.c | 132 +++++++++++++++++++++++++++++++++++++++++++- src/arch/dalvik.ins | 4 +- 3 files changed, 146 insertions(+), 7 deletions(-) diff --git a/src/arch.c b/src/arch.c index cfedc8d..abb2368 100644 --- a/src/arch.c +++ b/src/arch.c @@ -393,6 +393,9 @@ ArchRegister * arch_get_register_by_id_size(Arch * arch, uint32_t id, { size_t i; +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%u, %u)\n", __func__, id, size); +#endif for(i = 0; i < arch->registers_cnt; i++) if(arch->plugin->registers[i].id == id && arch->plugin->registers[i].size == size) @@ -459,7 +462,7 @@ static void _decode_print(off_t offset, ArchInstructionCall * call) ArchOperand * ao; char const * name; - printf("%08x: %s", offset, call->name); + printf("%08lx: %s", offset, call->name); for(i = 0; i < call->operands_cnt; i++) { ao = &call->operands[i]; @@ -497,11 +500,13 @@ int arch_decode_at(Arch * arch, off_t offset, size_t size, off_t base) { int ret; + /* FIXME this only works for files */ if(arch->fp == NULL) return -error_set_code(1, "%s", strerror(ENOSYS)); if(fseek(arch->fp, offset, SEEK_SET) != 0) return -error_set_code(1, "%s", strerror(errno)); - /* FIXME implement size, consider offset and base */ + arch->buffer_pos = offset + base; + arch->buffer_cnt = offset + base + size; if((ret = arch_decode(arch)) == 0 && fseek(arch->fp, offset + size, SEEK_SET) != 0) ret = -error_set_code(1, "%s", strerror(errno)); @@ -592,10 +597,12 @@ static char const * _arch_get_filename(Arch * arch) /* arch_read */ static ssize_t _arch_read(Arch * arch, void * buf, size_t size) { - if(fread(buf, size, 1, arch->fp) == 1) + size_t s = min(arch->buffer_cnt - arch->buffer_pos, size); + + if(fread(buf, s, 1, arch->fp) == 1) { - arch->buffer_pos += size; - return size; + arch->buffer_pos += s; + return s; } if(ferror(arch->fp)) return -error_set_code(1, "%s: %s", arch->filename, diff --git a/src/arch/dalvik.c b/src/arch/dalvik.c index 004aee4..b60ca84 100644 --- a/src/arch/dalvik.c +++ b/src/arch/dalvik.c @@ -68,6 +68,7 @@ static ArchInstruction _dalvik_instructions[] = /* plug-in */ static int _dalvik_write(ArchPlugin * plugin, ArchInstruction * instruction, ArchInstructionCall * call); +static int _dalvik_decode(ArchPlugin * plugin, ArchInstructionCall * call); /* public */ @@ -80,7 +81,7 @@ ArchPlugin arch_plugin = _dalvik_registers, _dalvik_instructions, _dalvik_write, - NULL + _dalvik_decode }; @@ -119,3 +120,132 @@ static int _dalvik_write(ArchPlugin * plugin, ArchInstruction * instruction, return -1; return 0; } + + +/* dalvik_decode */ +static int _decode_immediate(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i); +static int _decode_operand(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i); +static int _decode_register(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i); + +static int _dalvik_decode(ArchPlugin * plugin, ArchInstructionCall * call) +{ + ArchPluginHelper * helper = plugin->helper; + uint8_t u8; + ArchInstruction * ai; + size_t i; + + /* FIXME detect end of input */ + if(helper->read(helper->arch, &u8, sizeof(u8)) != sizeof(u8)) + return -1; + call->operands[0].type = AOT_NONE; + call->operands[1].type = AOT_NONE; + call->operands[2].type = AOT_NONE; + if((ai = helper->get_instruction_by_opcode(helper->arch, 8, u8)) + == NULL) + /* FIXME check if it's a nop or return "dw" */ + return -1; + call->name = ai->name; + call->operands[0].type = ai->op1; + call->operands[1].type = ai->op2; + call->operands[2].type = ai->op3; + for(i = 0; AO_GET_TYPE(call->operands[i].type) != 0; i++) + if(_decode_operand(plugin, call, i) != 0) + return -1; + call->operands_cnt = i; + return 0; +} + +static int _decode_immediate(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i) +{ + ArchPluginHelper * helper = plugin->helper; + ArchOperand * ao = &call->operands[i]; + uint8_t u8; + uint16_t u16; + uint32_t u32; + + switch(AO_GET_SIZE(call->operands[i].type)) + { + case 8: + if(helper->read(helper->arch, &u8, sizeof(u8)) + != sizeof(u8)) + return -1; + ao->value.immediate.value = u8; + break; + case 16: + if(helper->read(helper->arch, &u16, sizeof(u16)) + != sizeof(u16)) + return -1; + ao->value.immediate.value = _htol16(u16); + break; + case 32: + if(helper->read(helper->arch, &u32, sizeof(u32)) + != sizeof(u32)) + return -1; + ao->value.immediate.value = _htol32(u32); + break; + default: + return -1; + } + ao->value.immediate.negative = 0; + return 0; +} + +static int _decode_operand(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i) +{ + switch(AO_GET_TYPE(call->operands[i].type)) + { + case AOT_IMMEDIATE: + return _decode_immediate(plugin, call, i); + case AOT_REGISTER: + return _decode_register(plugin, call, i); + default: + return -1; + } + return 0; +} + +static int _decode_register(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i) +{ + ArchPluginHelper * helper = plugin->helper; + uint32_t id; + uint8_t u8; + uint16_t u16; + ArchRegister * ar; + + if(AO_GET_FLAGS(call->operands[i].type) & AOF_IMPLICIT) + id = AO_GET_VALUE(call->operands[i].type); + else if(AO_GET_FLAGS(call->operands[i].type) & AOF_DALVIK_REGSIZE) + { + switch(AO_GET_VALUE(call->operands[i].type)) + { + case 8: + if(helper->read(helper->arch, &u8, sizeof(u8)) + != sizeof(u8)) + return -1; + id = u8; + break; + case 16: + if(helper->read(helper->arch, &u16, sizeof(u16)) + != sizeof(u16)) + return -1; + id = _htol16(u16); + break; + case 4: + /* FIXME implement */ + default: + return -1; + } + } + else + return -1; + if((ar = helper->get_register_by_id_size(helper->arch, id, 32)) == NULL) + return -1; + call->operands[i].value._register.name = ar->name; + return 0; +} diff --git a/src/arch/dalvik.ins b/src/arch/dalvik.ins index d890ffc..cb8e66c 100644 --- a/src/arch/dalvik.ins +++ b/src/arch/dalvik.ins @@ -23,8 +23,10 @@ /* operands */ /* registers */ +#define AOF_DALVIK_REGSIZE 0x2 #define OP_v0 AO_REGISTER(AOF_IMPLICIT, 32, REG_v0_id) #define OP_REGISTER AO_REGISTER(0, 32, 0) +#define OP_REG8 AO_REGISTER(AOF_DALVIK_REGSIZE, 32, 8) /* immediate values */ #define OP_U8 AO_IMMEDIATE(0, 0, 8) @@ -87,7 +89,7 @@ { "const/16", 0x13, OP1F, OP_REGISTER, OP_U16, AOT_NONE }, { "const/high16", 0x15, OP1F, OP_REGISTER, OP_U16, AOT_NONE }, { "const-class", 0x1c, OP1F, OP_REGISTER, OP_U16, AOT_NONE }, -{ "const-string", 0x1a, OP1F, OP_REGISTER, OP_U16, AOT_NONE }, +{ "const-string", 0x1a, OP1F, OP_REG8, OP_U16, AOT_NONE }, { "const-wide", 0x18, OP1F, OP_REGISTER, OP_U64, AOT_NONE }, { "const-wide/16", 0x16, OP1F, OP_REGISTER, OP_U16, AOT_NONE }, { "const-wide/32", 0x17, OP1F, OP_REGISTER, OP_U32, AOT_NONE },