zyantific / zydis-rs

Zydis Rust Bindings
MIT License
83 stars 14 forks source link

lea, "(empty)" second operand "action" #25

Closed KosBeg closed 3 years ago

KosBeg commented 3 years ago

hi! there is a bug in rust bindings(and potentially in zydis-c) long short story

lea rax, [rsp+0x20]
DecodedOperand { id: 0, ty: REGISTER, visibility: EXPLICIT, **action: WRITE,** ... }
DecodedOperand { id: 1, ty: MEMORY, visibility: EXPLICIT, **action: (empty)**, ... }

lea eax, [esp+0x20]
DecodedOperand { id: 0, ty: REGISTER, visibility: EXPLICIT, **action: WRITE**, ... }
DecodedOperand { id: 1, ty: MEMORY, visibility: EXPLICIT, **action: (empty)**, ... }

code to reproduce bug

fn main() {
    use zydis::*;
    let data = [0x48, 0x8D, 0x44, 0x24, 0x20];

    let decoder = Decoder::new(MachineMode::LONG_64, AddressWidth::_64).unwrap();
    let instr = decoder.decode(&data).unwrap().unwrap();

    let formatter = Formatter::new(FormatterStyle::INTEL).unwrap();
    let mut buffer = [0u8; 200];
    let mut buffer = OutputBuffer::new(&mut buffer[..]);

    formatter
        .format_instruction(&instr, &mut buffer, None, None)
        .unwrap();
    println!("{}", format!("{}", buffer));

    for i in 0..instr.operand_count as usize {
        println!("{:?}", instr.operands[i]);
    }
    println!();

    let data = [0x8D, 0x44, 0x24, 0x20];

    let decoder = Decoder::new(MachineMode::LONG_COMPAT_32, AddressWidth::_32).unwrap();
    let instr = decoder.decode(&data).unwrap().unwrap();

    let formatter = Formatter::new(FormatterStyle::INTEL).unwrap();
    let mut buffer = [0u8; 200];
    let mut buffer = OutputBuffer::new(&mut buffer[..]);

    formatter
        .format_instruction(&instr, &mut buffer, None, None)
        .unwrap();
    println!("{}", format!("{}", buffer));

    for i in 0..instr.operand_count as usize {
        println!("{:?}", instr.operands[i]);
    }
}
th0rex commented 3 years ago

Hi, this also happens in zydis, so is not specific to zydis-rs:

== [ OPERANDS ] ============================================================================================
##       TYPE  VISIBILITY  ACTION      ENCODING   SIZE  NELEM  ELEMSZ  ELEMTYPE                        VALUE
--  ---------  ----------  ------  ------------   ----  -----  ------  --------  ---------------------------
 0   REGISTER    EXPLICIT       W     MODRM_REG     64      1      64       INT                          rax
 1     MEMORY    EXPLICIT    NONE      MODRM_RM     64      1       0       INT  TYPE  =                AGEN
                                                                                 SEG   =                  ss
                                                                                 BASE  =                 rsp
                                                                                 INDEX =                none
                                                                                 SCALE =                   0
                                                                                 DISP  =  0x0000000000000020

However, I'm not quite sure what the bug should be. NONE (which gets printed as (empty) in rust) for the second operand makes sense to me, since the memory is never read, because it is only used for address generation (which can be figured out by checking for operand.mem.ty == MemoryOperandType::AGEN). As far as I can see, this is intended, but maybe @flobernd or @athre0z can give more details.

flobernd commented 3 years ago

@th0rex is right. The LEA instruction does not actually access the memory referenced by the AGEN operand in any way. That's why the action is NONE and not e.g. READ.

KosBeg commented 3 years ago

thx @th0rex && @flobernd, after your explanation this is also intended for me ;)