zydis icon indicating copy to clipboard operation
zydis copied to clipboard

Hidden memory operands for MONITOR, RMPUPDATE, XLAT

Open tremalrik opened this issue 2 years ago • 5 comments

There are a few instructions where Zydis/ZydisInfo reports one of the instruction operands as a register operand, but where I believe it would be more accurate to report the operand as a hidden memory operand:

  • MONITOR and MONITORX: These instructions take an implicit memory address operand in AX/EAX/RAX, and perform the equivalent of a 1-byte memory read at the given address (for the purpose of checking for pagefaults and other memory-exceptions).
  • UMONITOR: This instruction takes an explicit register operand, and uses this address for the same kind of 1-byte access check as MONITOR does.
  • RMPUPDATE : This instruction takes an implicit memory address operand in RCX, and performs a 16-byte memory read from that address.

Similar to e.g. lodsb or maskmovdqu, all of these instructions by default use the DS segment for these hidden memory operands, but allow the segment to be overridden with segment override prefixes.

For XLAT, Zydis already reports a hidden memory operand, however given that the instruction computes the memory address to access as [BX/EBX/RBX+AL], it seems to me like the index field of this memory operand should be set to the al register with a scale of 1, rather than none with a scale of 0.

tremalrik avatar Aug 28 '21 23:08 tremalrik

@tremalrik:

The XLAT case currently can't be modelled in the data-tables. Our implicit memory operands only support a segment and a base register for now. This is why we used the workaround with the extra register, which is ... kinda ugly, I have to admit.

Are you aware of more such cases were an implicit index register and scale might be needed? I can easily add support for this, but at the cost of structure size (operand-definition needs to be extended).

flobernd avatar Aug 29 '21 09:08 flobernd

No, I believe XLAT is unique in that regard.

tremalrik avatar Aug 29 '21 10:08 tremalrik

Could also consider hard-coding a condition for it in the decoder code, I suppose.

athre0z avatar Aug 29 '21 16:08 athre0z

@tremalrik

The RMPUPDATE expects a physical address in the register. For the reasons mentionied in https://github.com/zyantific/zydis/issues/181#issuecomment-907837389, I will keep the register here.

In case of MONITOR and UMONITOR I think the semantics are kinda complex as well and I'm not sure if it would be a good idea to use a memory operand here for the same reasons (the intel SDM as well uses REG instead of MEM). As far as I can tell from the documentation it indeed might raise a page fault, but no actual read is documented here. I tend to keep the register here as well.

I will leave this issue open for discussion and as a reminder for the xlat case.

flobernd avatar Aug 31 '21 12:08 flobernd

RMPUPDATE is a bit unusual in that it takes two address operands that are treated very differently - RCX appears to be a conventional effective-address that points to a 16-byte data structure and is affected by segmentation and paging in the usual way, while RAX is a pseudo-memory operand with the sort of very nonstandard semantics that the #181 comment is talking about (AMD APM: "The system physical address of a page whose RMP entry is modified is specified in the RAX register")

For MONITOR and friends, it's presumably a judgement call how to categorize the operand. It is affected by the segment prefix - e.g. if the DS and GS segment have different base addresses, then 0F 01 C8 (plain MONITOR) and 65 0F 01 C8 (MONITOR with GS prefix) will set up memory address monitors at different memory locations, and it seems to me like this ought to be captured somehow.

tremalrik avatar Sep 02 '21 10:09 tremalrik