zydis
zydis copied to clipboard
Hidden memory operands for MONITOR, RMPUPDATE, XLAT
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
andMONITORX
: 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 asMONITOR
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:
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).
No, I believe XLAT
is unique in that regard.
Could also consider hard-coding a condition for it in the decoder code, I suppose.
@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.
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.