Date: Mon, 29 Jul 2024 16:06:19 +0100
On Mon, Jul 29, 2024 at 2:13 AM Thiago Macieira wrote:
>
> On Sunday 28 July 2024 18:11:22 GMT-7 Thiago Macieira wrote:
>>
> > It will break on 100% of them with sufficiently many parameters: 4 for ARM
> > 32- bit, 4 for x86-64 on Windows, 6 for x86-64 on Unix systems, 8 on IA-64,
> > etc.
>
> And, of course, zero on i386.
You've chosen i386, I presume, because all the arguments are passed on
the stack instead of in registers. For clarity let's call it x86_32
instead of i386.
Let's take the example program from this webpage:
https://geekyarthurs.medium.com/x86-32bit-function-calls-in-assembly-explained-c1a683e5ddc4
I have copy-pasted the example here:
int sub(int a, int b)
{
return a - b;
}
int main(void)
{
sub(8,2);
return 0;
}
The function "main" will get compiled to 6 instructions:
main:
push $2
push $8
call sub
add $8, %esp
mov $0, %eax
ret
These 6 instructions can become 7 instructions if we break the "call"
into two instructions:
main:
push $2
push $8
push next_instruction
jmp sub
next_instruction:
add $8, %esp
mov $0, %eax
ret
The most important thing to note in the above assembler is that the
arguments are pushed onto the stack _before_ the return address is
pushed onto the stack. Therefore, when the function "sub" is entered,
the thing at the top of the stack will always be the return address.
The code I showed in my previous posts yesterday relied on the return
address being on the top of the stack. But you think my code won't
work. Well here' s a GodBolt showing it working for x86_32:
https://godbolt.org/z/T9P7oxv7h
(I'll admit that this took me hours to get right)
You also mentioned something about "Controlflow Enforcement
Technology" -- let's see if we can trigger this protection mechanism.
My GodBolt above doesn't break it. Can you break it, Thiago?
>
> On Sunday 28 July 2024 18:11:22 GMT-7 Thiago Macieira wrote:
>>
> > It will break on 100% of them with sufficiently many parameters: 4 for ARM
> > 32- bit, 4 for x86-64 on Windows, 6 for x86-64 on Unix systems, 8 on IA-64,
> > etc.
>
> And, of course, zero on i386.
You've chosen i386, I presume, because all the arguments are passed on
the stack instead of in registers. For clarity let's call it x86_32
instead of i386.
Let's take the example program from this webpage:
https://geekyarthurs.medium.com/x86-32bit-function-calls-in-assembly-explained-c1a683e5ddc4
I have copy-pasted the example here:
int sub(int a, int b)
{
return a - b;
}
int main(void)
{
sub(8,2);
return 0;
}
The function "main" will get compiled to 6 instructions:
main:
push $2
push $8
call sub
add $8, %esp
mov $0, %eax
ret
These 6 instructions can become 7 instructions if we break the "call"
into two instructions:
main:
push $2
push $8
push next_instruction
jmp sub
next_instruction:
add $8, %esp
mov $0, %eax
ret
The most important thing to note in the above assembler is that the
arguments are pushed onto the stack _before_ the return address is
pushed onto the stack. Therefore, when the function "sub" is entered,
the thing at the top of the stack will always be the return address.
The code I showed in my previous posts yesterday relied on the return
address being on the top of the stack. But you think my code won't
work. Well here' s a GodBolt showing it working for x86_32:
https://godbolt.org/z/T9P7oxv7h
(I'll admit that this took me hours to get right)
You also mentioned something about "Controlflow Enforcement
Technology" -- let's see if we can trigger this protection mechanism.
My GodBolt above doesn't break it. Can you break it, Thiago?
Received on 2024-07-29 15:06:28