Question

I've got the 32bit opcode: FF 35 0E 20 40 00. Does anybody know a good OpCode table that gives an answer to this? (I know I could use a disassembler, but I'd like to know, how to determine this with an opcode table). I found this webpage, but there are 7 different solutions for FF. I'm not getting it.

Was it helpful?

Solution

You're looking in the wrong place. You should looking this in Intel's or AMD's official documentation.

Appendix A Opcode Map of Vol 2B of Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 3A and 3B says that FF is INC/DEC Grp51A.

Table A-6 Opcode Extensions for One- and Two-byte Opcodes by Group Number of Vol 2B says FF/Group 5 either of INC, DEC, CALLN, CALLF, JMPN, JMPF, PUSH, depending on bits 5 through 3 of the ModR/M byte, the byte that follows. (0x35>>3)&7=6 or 110 in binary. So, this is PUSH Ev.

Chapter 2 Instruction Format of Vol 2A explains what parts an instruction consists of, including those ModR/M bytes and what not.

Appendix A Using Opcode Tables of Vol 2B tells you for E:

A ModR/M byte follows the opcode and specifies the operand. The operand is either a general-purpose register or a memory address. If it is a memory address, the address is computed from a segment register and any of the following values: a base register, an index register, a scaling factor, a displacement.

It also tells you for v:

Word, doubleword or quadword (in 64-bit mode), depending on operand-size attribute.

So, you know that Ev means a register or a memory operand and since this is for 32-bit code and there are no instruction prefixes, the operand size is 32 bits. So, Ev a 32-bit register or a 32-bit variable in memory.

Now you need to figure out the rest of the bytes from ModR/M until the end.

Look at Figure 2-1. Intel 64 and IA-32 Architectures Instruction Format of Vol 2A. It tells you that in ModR/M=0x35:

Mod = 00 (binary)
Reg = 110 (binary; we've extracted these 3 bits before)
R/M = 101 (binary)

Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte of Vol 2A tells you that Mod = 00 and R/M = 101 means disp32, IOW, there's a memory operand consisting of a 32-bit displacement in the instruction.

The Reg field of the ModR/M byte has already been used to choose one of the seven instructions and therefore this field does not encode a register operand.

So, your instruction is PUSH DWORD [0x0040200E].

And that agrees with my disassembler output.

OTHER TIPS

Let's try going through this byte sequence one byte at a time.

  1. The first byte is FF. Looking it up in the Opcode Map in the Intel Instruction Set Reference tells us that this is an INC or a DEC instruction, along with the cryptical "Grp 5 - 1A". The 1A means that "Bits 5, 4, and 3 of ModR/M byte used as an opcode extension". The ModR/M byte is the byte that encodes the source and the address of the operands that are used for this instruction. In this case, the three bits are used for extending the opcode.
  2. The next byte is 35. This is the ModR/M byte, which normally appears right after the opcode itself, in instructions that use it. 35 (in hex) is 00110101 in binary, so bits 5, 4, and 3 are 110. Looking this up in the opcode extension table (Table A-6) we can see that this means this is a PUSH d64 Ev instruction. The d64 footnote means that "When in 64-bit mode, instruction defaults to 64-bit operand size and cannot encode 32-bit operand size.". This is expected for the PUSH instruction. Ev is a symbol that specifies the operand encoding - most importantly, it states that a ModR/M byte follows the opcode itself. The v, on the other hand, signals that the operand's size is dependent on the operand-size attribute. We already have the ModR/M byte, so let's decode it (Table 2-2, assuming that this code is running in 32-bit mode) : the effective address is specified by a disp32, which means that a 32-bit displacement should follow the ModR/M byte. The part specifying the register says that ESI should be used, but in this case this field is used for the opcode extension, so it isn't used to signify a register source operand.
  3. The next four bytes are the 32-bit displacement. 0E 20 40 00, when decoded as little endian, means 0x40200e. This is the address of the operand that will be used for this instruction.

Summing it all up, we got that FF 35 0E 20 40 00 is PUSH DWORD [0x40200e], i.e. it will push the 32-bit value read from the address 0x40200e on the stack.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top