완료됨
질문입니다!!
- 지역변수를 스택에 넣고 뺄 때 push, pop 명령어를 쓰지 않고 sub rsp, 8 이런식으로 하는 이유가 있나요??
- push eax하면 스택에 4바이트 저장이고 push rax하면 스택에 8바이트 저장인가요??
- push 0x00이면 스택에 1바이트 저장이고 push 0x0000이면 스택에 2바이트 저장인가요??
- 매개변수를 rdi, rsi, rdx에 넣는 방식을 찾아보니 fastcall이라는 함수 호출 규약이라고 하던데 syscall은 당연히 fastcall 규약을 따르는 건가요??
- 찾아보니 32비트는 호출 규약이 cdecl, stdcall, fastcall이 있고 64비트는 fastcall하나만 있다고 하던데 제 cpu는 64비트 cpu니까 무조건 fastcall 규약을 써야하나요??
- 프로그램내에서 여러가지 함수 호출 규약을 사용할 수 있나요?? 예를 들어 a함수는 cdecl규약을 쓰고 b함수는 stdcall규약을 쓰는 식으로
- 함수 호출 규약을 정하는 것은 프로그램을 작성하는 쪽에서 임의로 지정할 수 있나요?? 아니면 아키텍처에 맞춰서 알아서 지정이 되는 건가요??
감사합니다!!
#시스템_해킹
#공격기법
작성자 정보
답변
1
2dedce
워게임 고인물
sub rsp, 8
는 push랑 비슷하지만 값을 push하기 보다는 스택에 지역변수로 쓸 공간을 확보하는 겁니다. rsp를 감소시켜 공간을 미리 확보해 놓았으므로 이후의 push, pop에 영향을 받지 않고 지역변수로써 사용가능하죠.add rsp, 8
은 결과는 pop하고 비슷하지만 레지스터에 값을 저장하지 않고 값을 버리는 거죠. 보통 함수 처음에sub rsp, 0x30
처럼 지역변수 공간을 확보하고 함수 끝날 때add rsp, 0x30
으로 rsp를 되돌려 스택을 정리하기도 하고, sfp(stack frame pointer)을 활용해push rbp; mov rbp, rsp; sub rsp, 0x30
해놓고 끝날 때leave
로 rsp를 복구시키기도 합니다. (rsp가 어떻게 관리되는지는 간단한 함수를 컴파일하고 gdb 동적분석으로 어셈블리 코드를 따라가며 이해하시는 것이 좋습니다.)- push eax는 64비트에서 불가능합니다. 스택은 8바이트 단위로 관리되므로 8바이트 레지스터인 push rax로 해야합니다.
- 64비트에서 push 0x00 이나 push 0x0000이나 8바이트 저장입니다.
- syscall도 fastcall을 따릅니다. syscall은 커널모드로 전환하는 거라서 커널이 fastcall로 짜여져 있어서 그렇습니다.
- x64는 기본으로 fastcall 규약을 쓰기로 약속했습니다. 근데 바이너리의 코드가 그걸 안 지키며 짜여져 있을 수 있죠. 근데 보통 컴파일러가 호출규약으로 fastcall만 허용하도록 해서 바이너리를 만드므로 그런 바이너리는 어셈블러로 억지로 만들지 않는다면 없다고 보면 됩니다.
- 어셈블러로 직접 코드를 짜면 여러 호출규약이 가능합니다. x86에서는 c언어에서
__fastcall
__stdcall
과 같은 키워드로 여러가지 함수 호출규약을 사용할 수 있습니다. - 컴파일러가 아키텍처에 맞게 알아서 지정해줍니다. c언어에서는 x86 호출규약을 임의로 고를 수 있습니다.