1

Hey I am having hard time solving my homework.

Then x86 processor executes commands EIP register(counter) value increases by 1 byte or by a few bytes depending on command's type. Which instructions we have to use so EIP value may go over 100 bytes?

Answers are: JMP | ADD | SUB | PUSH | JNZ | MUL | CALL | JZ

As I get the idea, EIP is special case register which we can't use. It's called Extended Instruction Pointer. And to increase it's value over 100 bytes, we need to find how much each command is adding to EIP value?

devKanapka
  • 83
  • 7
  • 1
    Usually, instructions are executed in order, without skipping over any instructions. What instructions might cause the program to execute out-of-order? – Mark Snyder Jan 15 '20 at 22:02

2 Answers2

4

Any of those instructions could #PF (page fault exception) on a memory operand (or other ways depending on the instruction) and change CS:EIP to a totally new value loaded from the IDT. e.g. push dword [0]. That would include changing EIP by more than 100 unless your current EIP is within 100 bytes of the page-fault exception handler's address.

Or if we're talking about where the exception handler returns, if your process had a signal handler installed for SIGSEGV, the kernel could deliver that signal, effectively changing EIP within your process to your segfault signal handler.

But I think the intent of the question is about changing EIP by a specific desired relative amount, e.g. to reach another block of code. (Also not changing CS, the code-segment, so you stay in user-mode if you were there to start with.) I.e. 100 bytes away from the current EIP. The phrasing is awkward and could be read as setting EIP to any absolute value > 100, but x86 branches are relative and the question makes more sense that way.

As @zx485 points out, you need a control transfer instruction, aka a jump or branch. 386 (i.e. any machine with an EIP not just 16-bit IP) supports jcc rel32 conditional near jump as well as the shorter jcc rel8 short jump, so conditional jumps can reach anywhere in the entire 32-bit address space, same as jmp rel32 and call rel32. https://www.felixcloutier.com/x86/jcc.

But even a jcc rel8 (like JZ or JNZ) or jmp rel8 encoding can reach from -128 to +127 bytes relative to the end of the instruction. (Signed 8-bit 2's complement branch displacement.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
3

There are several possible answers to this:

  1. Use a relative JMP rel8: Many asemblers use a syntax like this:

    JMP $+100 
    

    where $ is the current value of EIP (the beginning of the JMP) and 100 is the decimal value to add to this position. The JMP itself occupies two bytes - which are subtracted from the 100 calculation in the instruction encoding. So the code is

    EB 62               (Address after the JMP + 98d=62h)
    
  2. You can use conditional jumps like JNZ and JZ which function in the same way.

  3. You can also use a relative CALL rel32 like this:

    CALL $+100
    

    In this case the instruction length is different ( =5 ). The count starts after the CALL, so the instruction is

    E8 5F 00 00 00      (Address after the CALL + 95d=5Fh)
    

    Note that the address after the CALL is also PUSHed to the stack before the jump is executed.

  4. The instructions ADD, SUB, PUSH, MUL do not have any influence on EIP except for advancing it by their own instruction length.

    So you could also just combine them sequentially to progress 100 bytes, but that answer is trivial.

zx485
  • 28,498
  • 28
  • 50
  • 59