Skip to content

In long mode 64 bits, jcc instructions have implicit operand of eip and not rip #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tperami opened this issue Oct 29, 2019 · 4 comments
Labels
A-decoder Area: Decoder C-bug Category: This is a bug (or a fix for a bug, when applied to PRs) P-high Priority: High

Comments

@tperami
Copy link

tperami commented Oct 29, 2019

Bug report

The second operand of a conditional jump (for example jnz) with 8 bits relative offset should be rip but is currently eip.

Expected Behavior

In 64 bit mode, the second operand (implicit) of a jcc instruction like jnz with a relative offset of 8 bits is rip.

Actual Behavior

In 64 bit mode, the second operand (implicit) of a jcc instruction like jnz with a relative offset of 8 bits is eip.

Steps to Reproduce the Problem

Minimal failing example:

#include <stdio.h>
#include <inttypes.h>
#include <Zydis/Zydis.h>

int main()
{
    ZyanU8 data[] = {0x75, 0x00}; // equivalent to "jnz here; here:"
    // ZyanU8 data[] = {0x0F, 0x85, 0x00, 0x00, 0x00, 0x00}; // 32 bit displacement jnz


    // Initialize decoder context
    ZydisDecoder decoder;
    ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);

    ZydisFormatter formatter;
    ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);

    ZydisDecodedInstruction instruction;

    ZydisDecoderDecodeBuffer(&decoder, data, sizeof(data), &instruction);

    char buffer[256];

    ZydisFormatterFormatOperand(&formatter, &instruction, 1, buffer, 256, 0);

    puts(buffer);

}

It outputs eip but should output rip.
For information, the first operand is the immediate displacement value and the third operand is rflags.

Remarks

If you take a long jnz encoding with 32 bit displacement, e.g. 0F8500000000, it outputs rip as expected

I tested with some other randomly picked jcc instruction like ja or je and they all have the same bug.

Specifications

  • Version: Zydis 3.0.0
  • Platform: Linux kernel 5.3.7, gcc 9.2.0 and compiled in C++
@athre0z athre0z added A-decoder Area: Decoder C-bug Category: This is a bug (or a fix for a bug, when applied to PRs) P-high Priority: High labels Oct 29, 2019
@flobernd
Copy link
Member

Thanks for the detailed bug report! I will have a look tomorrow.

@athre0z
Copy link
Member

athre0z commented Oct 29, 2019

jq '.[] | select(.meta_info.category == "COND_BR" and .filters?.mode? == "64" and any(.operands[]?; .register == "eip")) ' instructions.json

yields a total of 15 affected instruction. Substituting "eip" with "rip" for these should do the trick. XED correctly displays rip for these btw, so it looks like this slipped though our compare tool.

@athre0z
Copy link
Member

athre0z commented Oct 29, 2019

I updated the matching instructions which I think should resolve the issue, but don't have the table generator at hand, so we'll have to wait for @flobernd to update the generated files in this repo.

https://github.com/zyantific/zydis-db/tree/fix-jcc

I pushed it on a fresh branch because I was unable to verify if it "compiles".

@flobernd
Copy link
Member

Thanks! I just generated the new files from the fixed instruction database.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-decoder Area: Decoder C-bug Category: This is a bug (or a fix for a bug, when applied to PRs) P-high Priority: High
Projects
None yet
Development

No branches or pull requests

3 participants