I was going through the paper Smashing The Stack For Fun And Profit. Now there is a section of assembly code where we need to calculate the offsets manually forjmp
and call
instruction, which are relative to the program counter.
jmp offset-to-call # 2 bytes -----
popl %esi # 1 byte | <----------
movl %esi,array-offset(%esi) # 3 bytes | |
movb $0x0,nullbyteoffset(%esi) # 4 bytes | |
movl $0x0,null-offset(%esi) # 7 bytes | |
movl $0xb,%eax # 5 bytes | |
movl %esi,%ebx # 2 bytes | |
leal array-offset,(%esi),%ecx # 3 bytes | |
leal null-offset(%esi),%edx # 3 bytes | |
int $0x80 # 2 bytes | |
movl $0x1, %eax # 5 bytes | |
movl $0x0, %ebx # 5 bytes | |
int $0x80 # 2 bytes | |
call offset-to-popl # 5 bytes <------- ----------
/bin/sh string goes here.
The above is the rough sketch of the assembly the author wants to achieve.
Then the author plugs in the actual offsets as follows:
jmp 0x26 # 2 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
movb $0x0,0x7(%esi) # 4 bytes
movl $0x0,0xc(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2b # 5 bytes
.string \"/bin/sh\" # 8 bytes
I have the basic knowledge of how instruction fetch works. Especially I have experience of MIPS 32 assembly. There all the instructions are of fixed length (4 bytes) and the instructions are fetched in chunks of 4 bytes. Now for a jump instruction there, we calculate the offset for the target branch as follows:
Suppose, the target of a branch (relative) is at an address x
which is word aligned (assuming word length of 4 bytes). And if our jump instruction is at address y
. The offset is such a value, which shall give the target, when added with the current PC (program counter). So when the instruction at address y
is fetched, PC is y+4
. So we get the offset to the target address as x-y-4
.
Now if we consider the same here, considering the instructions are fetched in instruction granularity (i.e. not in chunks of 4 bytes but based on the size of the instruction), then when the jmp
instruction is fetched, the PC (eip) points to the popl
instruction. So based on that offset to the call
instruction should have been : 1+3+4+7+5+2+3+3+2+5+5+2=42= 0x2a
(and not 38=0x26
). So definitely, it is not the way how it is done.
Based on this approach, if I calculate the offset in call
instruction, I get the offset as: -(5+2+5+5+2+3+3+2+5+7+4+3+1)=-47=-0x2f
Now, just tweaking into the instructions, I found that for the jmp
the offset is calculated on the basis that the PC (eip) points to the start of movb
, after jmp
is fetched.
Also the offset for call
is calculated on the basis that PC (eip) points to the start of the call
instruction.
Please can anyone help me out, how are these manual calculations done?