radare2/libr/anal/p/anal_x86_simple.c

536 lines
13 KiB
C

/* radare - LGPL - Copyright 2009-2010 */
/* pancake<nopcode.org> */
/* nibble<.ds@gmail.com> */
#include <string.h>
#include <r_types.h>
#include <r_lib.h>
#include <r_asm.h>
#include <r_anal.h>
#include "x86/dislen/dislen.h"
/* code analysis functions */
/* arch_op for x86 */
// CMP ARG1
// 837d0801 cmp dword [ebp+0x8], 0x1
// 803db501060800 cmp byte [0x80601b5], 0x0
// SET VAR_41c
// 8985e4fbffff mov [ebp-41C],eax
// GET VAR_41c
// 8b85e4fbffff mov eax,[ebp-41C]
// 8b450c mov eax,[ebp+C]
// 8d85e8fbffff lea eax,[ebp-418]
// c68405e7fbffff. mov byte ptr [ebp+eax-419],0x0
//3d00400000 cmp eax, 0x4000
//81fa00c00000 cmp edx, 0xc000
//83fa01 cmp edx, 0x1
static const char *testregs[] = {
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
// NOTE: buf should be at least 16 bytes!
// XXX addr should be off_t for 64 love
static int myop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
if (buf == NULL)
return 0;
memset (op, 0, sizeof (RAnalOp));
op->type = R_ANAL_OP_TYPE_UNK;
op->addr = addr;
op->jump = op->fail = -1;
op->ref = op->value = -1;
switch (buf[0]) {
case 0x8a:
case 0x8b:
case 0x03: // 034518 add eax, [ebp+0x18]
switch (buf[1]) {
case 0x45:
case 0x46:
case 0x55:
case 0x5d:
case 0x7d:
/* mov -0xc(%ebp, %eax */
op->ref = (st64)((char)buf[2]);
op->stackop = R_ANAL_STACK_GET;
break;
case 0x95:
if (buf[2]==0xe0) { // ebp
op->ref = (st64)((int)(buf[3]+(buf[4]<<8)+(buf[5]<<16)+(buf[6]<<24)));
op->stackop = R_ANAL_STACK_GET;
}
//op->ref = -(buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24));
break;
case 0xbd:
op->ref = (st64)((int)(buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24)));
//op->ref = -(buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24));
op->stackop = R_ANAL_STACK_GET;
break;
}
break;
case 0x88:
case 0x89: // move
switch (buf[1]) {
case 0x45:
case 0x4d: // 894de0 mov [ebp-0x20], ecx
case 0x55:
op->stackop = R_ANAL_STACK_SET;
op->ref = (st64)((char)buf[2]);
break;
case 0x85:
op->stackop = R_ANAL_STACK_SET;
op->ref = (st64)((int)(buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24)));
break;
case 0x75:
op->stackop = R_ANAL_STACK_GET;
op->ref = (st64)((char)buf[2]); //+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24));
break;
}
// XXX: maybe store or mov depending on opcode
// 89c3 mov ebx, eax
// 897c2408 mov [esp+0x8], edi
op->type = R_ANAL_OP_TYPE_STORE;
break;
case 0xf4: // hlt
op->type = R_ANAL_OP_TYPE_RET;
op->length = 1;
break;
case 0xc3: // ret
case 0xc2: // ret + 2 bytes
case 0xcb: // lret
case 0xcf: // iret
op->type = R_ANAL_OP_TYPE_RET;
op->eob = 1;
break;
//case 0xea: // far jmp
// TODO moar
case 0x3b: //cmp
op->ref = (st64)((char)buf[2]);
op->stackop = R_ANAL_STACK_GET;
case 0x39:
case 0x3c:
case 0x3d:
// 3d 00 40 00 00 cmp eax, 0x4000
op->src[0] = r_anal_value_new ();
op->src[0]->reg = r_reg_get (anal->reg, testregs[(buf[0]&7)%8], R_REG_TYPE_GPR);
op->src[1] = r_anal_value_new ();
op->src[1]->base = buf[1]+(buf[2]<<8)+(buf[3]<<16)+(buf[4]<<24);
op->type = R_ANAL_OP_TYPE_CMP;
break;
case 0x80:
op->type = R_ANAL_OP_TYPE_CMP;
switch (buf[1]) {
case 0x3d: // 80 3d b5010608 00 cmp byte [0x80601b5], 0x0
op->src[0] = r_anal_value_new ();
op->src[0]->memref = 1;
op->src[0]->base = buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24);
op->src[1] = r_anal_value_new ();
op->src[1]->base = buf[6];
break;
}
break;
case 0x85:
op->type = R_ANAL_OP_TYPE_CMP;
if (buf[1]>=0xc0) {
int src = buf[1]&7;
int dst = (buf[1]&0x38)>>3;
op->src[0] = r_anal_value_new ();
op->src[0]->reg = r_reg_get (anal->reg, testregs[src%8], R_REG_TYPE_GPR);
op->src[1] = r_anal_value_new ();
op->src[1]->reg = r_reg_get (anal->reg, testregs[dst%8], R_REG_TYPE_GPR);
op->src[2] = NULL;
//eprintf ("REGZ (%s)\n", anal->reg);
//eprintf ("REG IZ: (%s)\n", testregs[src%8]);
//eprintf ("REG IZ: %p (%s)\n", op->src[0], op->src[0]->reg->name);
if (op->src[0]->reg == op->src[1]->reg) {
//eprintf ("fruity\n");
r_anal_value_free (op->src[1]);
op->src[1] = NULL;
}
//eprintf ("0x%"PFMT64x": (%02x) %d %d\n", addr, buf[1], src, dst);
} else if (buf[1]<0xc0) { // test [eax+delta], eax
/* not yet supported */
}
// c0-c7 : eax, ecx, edx, ebx, esp, ebp, esi, edi
// 83f821 cmp eax, 0x21
// 85c0 test eax, eax
// 85c9 test ecx, ecx
break;
case 0x90:
op->type = R_ANAL_OP_TYPE_NOP;
op->length = 1;
break;
case 0x0f: // 3 byte nop
//0fbe55ff movsx edx, byte [ebp-0x1]
if (buf[1]==0xbe) {
op->ref = (st64)((char)buf[3]);
op->stackop = R_ANAL_STACK_GET;
} else
if (buf[1]==0x31) {
// RDTSC // colorize or sthg?
op->eob = 0;
} else
if (buf[1]>=0x18 && buf[1]<=0x1f) {
op->type = R_ANAL_OP_TYPE_NOP;
op->length = 3;
} else
if (buf[1]>=0x80 && buf[1]<=0x8f) {
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = addr+6+buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24);//((unsigned long)((buf+2))+6);
op->fail = addr+6;
op->length = 6;
//op->eob = 1;
} else
if (buf[1]>=0x40 && buf[1]<=0x4f) { /* Conditional MOV */
op->type = R_ANAL_OP_TYPE_MOV;
op->eob = 0;
op->length = 4;
return 4;
}
break;
case 0xcc: // int3
// op->eob = 1;
op->value = 3;
op->type = R_ANAL_OP_TYPE_SWI;
break;
case 0xf1: // int1
op->length = 1;
op->value = 1;
op->type = R_ANAL_OP_TYPE_SWI;
break;
case 0xb8: // mov eax, <inmedate>
case 0xb9: // mov ecx, <inmedate>
case 0xba: // mov edx, <inmedate>
case 0xbb: // mov ebx, <inmedate>
case 0xbc: // mov esp, <inmedate>
case 0xbd: // mov esp, <inmedate>
case 0xbf:
op->type = R_ANAL_OP_TYPE_MOV; // bfdc054000 mov edi, 0x4005dc
op->ref = (st64)((int)buf[1]+(buf[2]<<8)+(buf[3]<<16)+(buf[4]<<24));//((unsigned long)((buf+2))+6);
break;
case 0xcd:
op->length = 2;
op->type = R_ANAL_OP_TYPE_SWI;
op->value = buf[1];
break;
case 0xe8: // call
op->type = R_ANAL_OP_TYPE_CALL;
op->length = 5;
//op->jump = addr+*ptr+5; //(unsigned long)((buf+1)+5);
op->jump = addr+5+buf[1]+(buf[2]<<8)+(buf[3]<<16)+(buf[4]<<24);//((unsigned long)((buf+2))+6);
op->fail = addr+5;
//printf("addr: %08"PFMT64x"\n call %08"PFMT64x" \n ret %08"PFMT64x"\n", addr, op->jump, op->fail);
// op->eob = 1;
break;
case 0xe9: // jmp
op->type = R_ANAL_OP_TYPE_JMP;
op->length = 5;
//op->jump = (unsigned long)((buf+1)+5);
op->jump = addr+5+buf[1]+(buf[2]<<8)+(buf[3]<<16)+(buf[4]<<24);//((unsigned long)((buf+2))+6);
op->fail = 0L;
op->eob = 1;
break;
case 0xeb: // short jmp
op->type = R_ANAL_OP_TYPE_JMP;
op->length = 2;
op->jump = addr+((unsigned long)((char)buf[1])+2);
op->fail = 0L;
op->eob = 1;
break;
case 0xf2: // repnz
case 0xf3: // repz
op->type = R_ANAL_OP_TYPE_REP;
//op->length = dislen((unsigned char *)&buf); //instLength(buf, 16, 0);
op->jump = 0L;
op->fail = 0L;
break;
case 0xff:
if (buf[1]== 0x75) {
op->type = R_ANAL_OP_TYPE_PUSH;
op->stackop = R_ANAL_STACK_GET;
op->ref = 0LL;
op->ref = (st64)((char)(buf[2]));
op->stackptr = 4;
} else
if (buf[1]== 0x45) {
op->type = R_ANAL_OP_TYPE_ADD;
op->stackop = R_ANAL_STACK_SET;
op->ref = (st64)((char)buf[2]);
} else
if (buf[1]>=0x50 && buf[1]<=0x6f) {
op->type = R_ANAL_OP_TYPE_UJMP;
op->eob = 1;
} else
if (buf[1]>=0xd0 && buf[1]<=0xd7) {
op->type = R_ANAL_OP_TYPE_CALL;
op->length = 2;
op->eob = 1;
//op->jump = vm_arch_x86_regs[VM_X86_EAX+buf[1]-0xd0];
op->fail = addr+2;
} else
if (buf[1]>=0xe0 && buf[1]<=0xe7) {
op->type = R_ANAL_OP_TYPE_UJMP;
op->length = 2;
//op->jump = vm_arch_x86_regs[VM_X86_EAX+buf[1]-0xd0];
op->eob = 1;
}
break;
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x58:
case 0x59:
op->type = R_ANAL_OP_TYPE_UPUSH;
op->ref = 0; // TODO value of register here! get_offset
op->stackptr = 4;
break;
case 0x6a: // push $7
op->type = R_ANAL_OP_TYPE_PUSH;
op->ref = buf[1];
op->stackptr = 4;
break;
break;
case 0x5a:
case 0x5b:
case 0x5c:
case 0x5d:
case 0x5e:
case 0x5f:
op->type = R_ANAL_OP_TYPE_POP;
op->length = 1;
op->stackptr = -4;
break;
case 0x2e: // 2e64796e jns 0xb770a4ab !!
if (buf[1]>=0x64 && buf[1]<=0x67) {
int ret = myop (anal, op, addr, buf+1, len-1);
op->jump++;
op->length++;
return ret;
}
break;
case 0x64:
case 0x65:
case 0x66:
case 0x67:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = addr+3+buf[2]; //+(buf[2]<<8)+(buf[3]<<16); // XXX
op->length = 3;
op->fail = addr+op->length;
//op->eob = 1;
break;
case 0x68:
op->type = R_ANAL_OP_TYPE_PUSH;
op->ref = (st64)((int)buf[1]+(buf[2]<<8)+(buf[3]<<16)+(buf[4]<<24));
op->stackptr = 4;
break;
case 0x81:
op->type = R_ANAL_OP_TYPE_ADD;
if (buf[1] == 0xec) {
/* sub $0x????????, $esp*/
// 81ece00d0000 sub esp, 0xde0 ;
op->value = buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24);
op->stackop = R_ANAL_STACK_INC;
op->stackptr = op->value;
break;
} else
if (buf[1] == 0xfa) {
op->type = R_ANAL_OP_TYPE_CMP;
// 81fa00c00000 cmp edx, 0xc000
// XXX TODO
}
break;
case 0x83:
switch (buf[1]) {
case 0xe4: // and
op->value = (ut64)(unsigned char)buf[2];
op->type = R_ANAL_OP_TYPE_AND;
break;
case 0xc4:
/* inc $0x????????, $esp*/
op->value = -(ut64)(unsigned char)buf[2];
op->stackop = R_ANAL_STACK_INC;
op->stackptr = op->value;
break;
case 0xf8:
case 0xf9:
case 0xfa:
{
int src = buf[1]&7;
op->src[0] = r_anal_value_new ();
op->src[0]->reg = r_reg_get (anal->reg, testregs[src%8], R_REG_TYPE_GPR);
op->src[1] = r_anal_value_new ();
op->src[1]->base = buf[2];
// 83f821 cmp eax, 0x21
op->type = R_ANAL_OP_TYPE_CMP;
op->length = 3;
}
break;
case 0xec:
/* sub $0x????????, $esp*/
op->value = (ut64)(unsigned char)buf[2];
op->stackop = R_ANAL_STACK_INC;
op->stackptr = op->value;
break;
case 0xbd: /* 837dfc02 cmp dword [ebp-0x4], 0x2 */
switch (buf[2]) {
case 0xe0: // ebp
if ((char)buf[2]>0) {
op->stackop = R_ANAL_STACK_GET;
op->value = buf[3]+(buf[4]<<8)+(buf[5]<<16)+(buf[6]<<24);
} else {
op->stackop = R_ANAL_STACK_GET;
op->value = buf[3]+(buf[4]<<8)+(buf[5]<<16)+(buf[6]<<24);
}
op->type = R_ANAL_OP_TYPE_CMP;
break;
}
break;
case 0x7d: /* 837dfc02 cmp dword [ebp-0x4], 0x2 */
if ((char)buf[2]>0) {
op->stackop = R_ANAL_STACK_GET;
op->value = (ut64)(char)buf[2];
} else {
op->stackop = R_ANAL_STACK_GET;
op->value = (ut64)-(char)buf[2];
}
op->type = R_ANAL_OP_TYPE_CMP;
break;
}
break;
case 0x8d:
/* LEA */
if (buf[1] == 0x85) {
op->ref = (st64)((int)(buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24)));
op->stackop = R_ANAL_STACK_GET;
}
op->type =R_ANAL_OP_TYPE_MOV;
break;
case 0xc6:
case 0xc7:
/* mov dword [ebp-0xc], 0x0 || c7 45 f4 00000000 */
switch (buf[1]) {
case 0x85:
op->ref = (st64)(((int)(buf[2]+(buf[3]<<8)+(buf[4]<<16)+(buf[5]<<24))));
break;
//c785 e4fbffff 00. mov dword [ebp+0xfffffbe4], 0x0
case 0x45:
op->stackop = R_ANAL_STACK_SET;
op->ref = (st64)((char)buf[2]);
break;
case 0x05:
// c7050c0106080000. mov dword [0x806010c], 0x0
// c605b401060800 mov byte [0x80601b4], 0x0
// TODO:
break;
case 0x04:
// c7042496850408 dword [esp] = 0x8048596 ; LOL
op->refptr = 4;
op->ref = (st64)(((int)(buf[3]+(buf[4]<<8)+(buf[5]<<16)+(buf[6]<<24))));
break;
}
op->type = R_ANAL_OP_TYPE_STORE;
break;
case 0x82:
op->type = R_ANAL_OP_TYPE_ADD;
break;
case 0x29:
op->type = R_ANAL_OP_TYPE_SUB;
break;
case 0x31:
op->type = R_ANAL_OP_TYPE_XOR;
break;
case 0x32:
op->type = R_ANAL_OP_TYPE_AND;
break;
case 0xa1: // mov eax, [addr]
op->type = R_ANAL_OP_TYPE_MOV;
//vm_arch_x86_regs[VM_X86_EAX] = addr+buf[1]+(buf[2]<<8)+(buf[3]<<16)+(buf[4]<<24);
//radare_read_at((ut64)vm_arch_x86_regs[VM_X86_EAX], (unsigned char *)&(vm_arch_x86_regs[VM_X86_EAX]), 4);
break;
#if 0
case0xF
/* conditional jump */
if (buf[1]>=0x80&&buf[1]<=0x8F) {
op->type = R_ANAL_OP_TYPE_CJMP;
op->length = 6;
op->jump = (unsigned long)((buf+2)+6);
op->fail = addr+6;
op->eob = 1;
return 5;
}
break;
#endif
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x78:
case 0x79:
case 0x7a:
case 0x7b:
case 0x7c:
case 0x7d:
case 0x7e:
case 0x7f: {
int bo = (int)((char) buf[1]);
/* conditional jump */
//if (buf[1]>=0x80&&buf[1]<=0x8F) {
op->type = R_ANAL_OP_TYPE_CJMP;
op->length = 2;
// op->jump = (unsigned long)((buf+2)+6);
op->jump = addr+bo+2; //(unsigned long)((buf+1)+5);
op->fail = addr+2;
op->eob = 1;
//return 2;
}
break;
//default:
//op->type = R_ANAL_OP_TYPE_UNK;
}
//if (op->length == 0)
op->length = dislen ((unsigned char *)buf, 64); //instLength(buf, 16, 0);
//op->length = instLength(buf, 16, 0);
if (!(op->jump>>33))
op->jump &= 0xFFFFFFFF; // XXX may break on 64 bits here
return op->length;
}
struct r_anal_plugin_t r_anal_plugin_x86_simple = {
.name = "x86.simple",
.desc = "X86 analysis plugin",
.arch = R_SYS_ARCH_X86,
.bits = 32,
.init = NULL,
.fini = NULL,
.op = &myop,
.set_reg_profile = NULL,
.fingerprint_bb = NULL,
.fingerprint_fcn = NULL,
.diff_bb = NULL,
.diff_fcn = NULL,
.diff_eval = NULL
};
#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
.type = R_LIB_TYPE_ANAL,
.data = &r_anal_plugin_x86_simple
};
#endif