Instructions’ Prefixes Hell

Since the first day diStorm was out people didn’t know how to deal with the fact that I drop(ignore) some prefixes. It seems that dropping unused prefixes isn’t such a great feature for many people and it only complicates the scanning of streams. Therefore I am thinking about removing the whole mechanism, or maybe change it in a way that still preserves the same interface but behaves differently.

For the following stream: “67 50”, the result by diStorm will be: “db 0x67” – “push eax”. The 0x67 prefix supposes to change the address size, which none is used in our case, thus it’s dropped. However, if we look at the hex code of the “push eax” part we will see “67 50”. And this is where most of the people become dumbfounded. Getting twice the same prefix-byte of the stream in two results is in a way confusing. Taking a look at other disassemblers will tell you that diStorm is not the only one to do such games with prefixes. Sometimes I get emails regarding this “impossible” prefix – since it gets to be output twice, which is wrong, right? Well, don’t know, it depends how you choose to decode it. The way I chose to decode prefixes was really advanced, each prefix could have been ignored, unless it has really affected (one of) the operand itself. I had to really keep tracking on each prefix and know whether it affected any operands in the instructions and only then I examined which prefixes I drop or not. This all sounds right in a way. Hey, at least for me.

However, we didn’t even talk about what you will do if you have multiple prefixes of the same family (segment-overide: DS, ES, SS, etc). Now this one is really up to interpretations of the designer. Probably the way I did it in diStorm is wrong, I admit it, that’s why I want to rewrite the whole prefixes thing from the beginning. There are 4 or 5 types of prefixes and according to the specs (Intel/AMD) I quote: “A single instruction should include a maximum of one prefix from each of the five groups.” …. “The result of using multiple prefixes from a single group is unpredictable.”. This pretty much sums all the problems in the world related to prefixes. I guess you can see for yourself from these 2 lines you can actually treat them in many different ways. We know now that it can lead to “unpredictable” results if you have many prefixes – in reality it won’t shut down your CPU, it won’t even throw an exception. So screw it you say, and you’re right. Now let’s see some CPU (16 bits) logic for decoding the prefixes:

while (prefix byte is read) {
 switch (prefix): {
  case seg_cs: use_seg = cs; break;
  case seg_ds: use_seg = ds; break;
  case seg_ss: use_seg = ss; break;
  ….
  ….
 case op_size: op_size = 32; break;
  case op_addr: op_addr = 32; break;
 case rep_z: rep = z; break;
 …
 }
 – skip byte in stream –
}

The processor will use those flags in order to know which prefix was presented or not. The thing about using a loop (in any form) is that now that you have to show text out of some streams with many prefixes, you don’t know whether the processor really uses the first occurrance of the prefix or its last, or maybe both? And maybe Intel and AMD implement it differently?

You know what? Why the heck do I bother so much with some minor end cases that never really happen in real code sections. I ask myself too, maybe I shouldn’t. Although I happened to see for myself some malware code that tries to screw up the disassembler with many extra prefixes, etc.. and I thought diStorm could help malware analyzers as well with advanced prefixes decoding.

Anyways, according to the above logic code I’m supposed to use the last prefix of each type. Given a stream such as: 66 66 67 67 40. I will get:
0: 66 (dropped)
2: 67 (dropped)
1: 66 67 40
Now you can see that the prefixes used are the second and the fourth and that the instruction starts at the second byte on the stream. Now I officially can commit a suicide, even I can’t follow these addresses, it’s hell. So any better solution?

6 Responses to “Instructions’ Prefixes Hell”

  1. Peter Ferrie says:

    The prefix ordering used to be a worse problem – the first REP had priority until the Pentium II, but for all other groups it was the last one. Now it’s the last REP, so the last type is used for all groups, on all CPUs.
    It was a problem mostly for emulators, though.

  2. Jose Luu says:

    A solution could to flag the prefixes:
    – unused/used -> in one more field in the ouput structure

    Another feature could be a distrom intialization flag
    – attach all prefixes to the next instruction
    – attach only used prefixes to instructions

    Some compilers (microsoft) emit extraneous (=unused) prefixes, this would definitively be a nice improvement.

  3. arkon says:

    Hey Jose,
    the problem is now that it requires another parameter in the function (/interface) and I’m not willing to add one.
    So I need to decide for everybody else what’s good for them. Currently, I’m thinking about attaching all instructions to next instruction, it seems more “the way the CPU works”.

  4. My question to your last response is: What length do you return for the instruction if you attach all prefix bytes to the instruction? 5, 3, or 1. There are instances where you need to know the exact/correct length of the instruction in order to add a breakpoint, or “back-up” in the listing, etc.

    I prefer displaying the nonsense prefix bytes as nonsense, not dropping any of them. This way the user examining the output will be alerted to the fact that something “fishy” is going on.

  5. arkon says:

    Hey Russ,
    it’s a good question actually and I like this way of consideration. I guess that the first prefix should be replaced/have a BP. As we know it, you should set the BP on the first byte. Although I don’t see why you care about the length, as far as the prefixes, either malformed, are part of the instruction itself. So in a way, there is no “exact/correct” length!

    The meaning of dropping them is actually marking them as nonsense, that something is wrong. Because in a real code flow it shouldn’t happen. Unless you see it in jumps or as special padding…

  6. […] this time. By including the last prefix found of that prefix-type. You can read more about this, here. I made the code way more optimized and eliminated double code and it’s still readable, if […]

Leave a Reply