A Common Bug With LEA

If we examine the LEA instruction from text output point of view, we can say that it is similar to the MOV instruction, but a one that uses memoy indirection. Hence you got the square brackets to denote a memory address… Only when you interpret LEA you should know to remove the fake memory indirection and to treat the ‘address’ as an immediate value, or as an expression. The expressions can get as complex  as eax*8+ebx+1234. In reality, in order to simplify matters – the second (source) operand’s type of LEA will be probably OP_TYPE_MEM. Just like any other instruction that might have only a memory indirection, for instance, cmpxchg… So why shouldn’t we (disassemblers) have a special operand type for LEA? Well, mainly to say because it’s a headache to maintain two types that parse the memory indirection bytes, and eventually they really output the same stuff, so why not having only one type which LEA will be able to piggy back?

In diStorm, I used OP_TYPE_MEM for LEA’s operand. I didn’t want to have another special OP_TYPE_LEA. And I didn’t have any problem with it. Until today, I thought of a ‘bug’. You can use a segment override to change the default segment an address will be read from or written to. Here MOV EAX, [FS:EAX]. Normally the segment overrides you will see are only GS and FS, since DS and ES are usually set to the same value, so you can copy data from a source to dest bufferw using the MOVS instruction. Or you can compare two buffers using CMPS… And of course you cannot run without CS and SS… For that reason in 64bits they got rid off CS, DS, ES and SS segment overrides.

So what’s the bug you’re asking? LEA EAX, [FS:EAX] – Doesn’t really make any sense ah? And why does it happen? Because I use the MEM type… So I had two options, either add a special type so you filter the segment overrides for LEA. Or just filter the segment overrides when you see the instruction you decode is LEA. For simplicity I implemented the latter.

Anyway, diStorm is already updated by now. The bug was found in other disassemblers as well, to name Olly and VS’s debugger. I didn’t try other disassemblers, I guess more have this issue. Not to my surprise, IDA is immune.

The moral of the story? hmmm, don’t be a lazy jackass? No. Just don’t assume too much and try to think of the small details. :)

UPDATE:

Try to feed the assemblers with that buggy instruction and you will see that they generate it errornously with the segment override prefix :)

Leave a Reply