| 함수호출규약 | 사용 컴파일러 | 인자 전달 방식 | 스택 정리 | 적용 |
|---|---|---|---|---|
| stdcall | MSVC | Stack | Callee | WINAPI |
| cdecl | GCC, MSVC | Stack | Caller | 일반함수 |
| fastcall | MSVC | ECX, EDX | Callee | 최적화된 함수 |
| thiscall | MSVC | ECX(인스턴스), Stack(인자) | Callee | 클래스의 함수 |
| 함수호출규약 | 사용 컴파일러 | 인자 전달 방식 | 스택 정리 | 적용 |
|---|---|---|---|---|
| MS ABI | MSVC | RCX, RDX, R8, R9 | Caller | 일반함수, Windows Syscall |
| System ABI | GCC | RDI, RSI, RDX, RCX, R8, R9, XMM0-7 | Caller | 일반함수 |
$ file /bin/ls
/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV) ...
// Name: sysv.c
// Compile: gcc -fno-asynchronous-unwind-tables -masm=intel \
// -fno-omit-frame-pointer -S sysv.c -fno-pic -O0
#define ull unsigned long long
ull callee(ull a1, int a2, int a3, int a4, int a5, int a6, int a7) {
ull ret = a1 + a2 + a3 + a4 + a5 + a6 + a7;
return ret;
}
void caller() { callee(123456789123456789, 2, 3, 4, 5, 6, 7); }
int main() { caller(); }
$ gcc -fno-asynchronous-unwind-tables -masm=intel -fno-omit-frame-pointer -o sysv sysv.c -fno-pic -O0
$ gdb -q sysv
pwndbg: loaded 139 pwndbg commands and 49 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
Reading symbols from sysv...
...
pwndbg> b *caller
Breakpoint 1 at 0x1185
pwndbg> r
Starting program: /home/dreamhack/sysv
Breakpoint 1, 0x0000555555555185 in caller ()
...
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
► 0x555555555185 <caller> endbr64
0x555555555189 <caller+4> push rbp
0x55555555518a <caller+5> mov rbp, rsp
0x55555555518d <caller+8> push 7
0x55555555518f <caller+10> mov r9d, 6
0x555555555195 <caller+16> mov r8d, 5
0x55555555519b <caller+22> mov ecx, 4
0x5555555551a0 <caller+27> mov edx, 3
0x5555555551a5 <caller+32> mov esi, 2
0x5555555551aa <caller+37> movabs rax, 0x1b69b4bacd05f15
0x5555555551b4 <caller+47> mov rdi, rax
0x5555555551b7 <caller+50> call 0x555555555129 <callee>
0x5555555551bc <caller+55> add rsp,0x8
pwndbg> disass caller
...
0x00005555555551b7 <+50>: call 0x555555555129 <callee>
...
pwndbg> b *caller+50
Breakpoint 2 at 0x5555555551b7
pwndbg> c
Continuing.
Breakpoint 2, 0x00005555555551b7 in caller ()
...
─────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────
*RAX 0x1b69b4bacd05f15
RBX 0x0
*RCX 0x4
*RDX 0x3
*RDI 0x1b69b4bacd05f15
*RSI 0x2
*R8 0x5
*R9 0x6
R10 0x7ffff7fc3908 ◂— 0xd00120000000e
R11 0x7ffff7fde680 (_dl_audit_preinit) ◂— endbr64
...
pwndbg> x/4gx $rsp
0x7fffffffe2f8: 0x0000000000000007 0x00007fffffffe310
0x7fffffffe308: 0x00005555555551d5 0x0000000000000001
pwndbg> si
0x00005555555545fa in callee ()
...
pwndbg> x/4gx $rsp
0x7fffffffdf70: 0x0000555555554682 0x0000000000000007
0x7fffffffdf80: 0x00007fffffffdf90 0x0000555555554697
pwndbg> x/10i 0x0000555555554682 - 5
0x55555555467d <caller+43>: call 0x5555555545fa <callee>
0x555555554682 <caller+48>: add rsp,0x8
pwndbg> x/9i $rip
=> 0x555555555129 <callee>: endbr64
0x55555555512d <callee+4>: push rbp
0x55555555512e <callee+5>: mov rbp,rsp
0x555555555131 <callee+8>: mov QWORD PTR [rbp-0x18],rdi
0x555555555135 <callee+12>: mov DWORD PTR [rbp-0x1c],esi
0x555555555138 <callee+15>: mov DWORD PTR [rbp-0x20],edx
0x55555555513b <callee+18>: mov DWORD PTR [rbp-0x24],ecx
0x55555555513e <callee+21>: mov DWORD PTR [rbp-0x28],r8d
0x555555555142 <callee+25>: mov DWORD PTR [rbp-0x2c],r9d
pwndbg> si
pwndbg> si
0x000055555555512e in callee ()
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
0x555555555129 <callee> endbr64
0x55555555512d <callee+4> push rbp
► 0x55555555512e <callee+5> mov rbp, rsp
0x555555555131 <callee+8> mov qword ptr [rbp - 0x18], rdi
...
pwndbg> x/4gx $rsp
0x7fffffffe2e8: 0x00007fffffffe300 0x00005555555551bc
0x7fffffffe2f8: 0x0000000000000007 0x00007fffffffe310
pwndbg> print $rbp
$1 = (void *) 0x7fffffffe300
pwndbg> x/5i $rip
=> 0x55555555512e <callee+5>: mov rbp,rsp
0x555555555131 <callee+8>: mov QWORD PTR [rbp-0x18],rdi
0x555555555135 <callee+12>: mov DWORD PTR [rbp-0x1c],esi
0x555555555138 <callee+15>: mov DWORD PTR [rbp-0x20],edx
0x55555555513b <callee+18>: mov DWORD PTR [rbp-0x24],ecx
pwndbg> print $rbp
$2 = (void *) 0x7fffffffe300
pwndbg> print $rsp
$3 = (void *) 0x7fffffffe2e8
pwndbg> si
pwndbg> print $rbp
$4 = (void *) 0x7fffffffe2e8
pwndbg> print $rsp
$5 = (void *) 0x7fffffffe2e8
pwndbg> b *callee+79
Breakpoint 3 at 0x555555555178
pwndbg> c
...
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
► 0x555555555178 <callee+79> add rax, rdx
0x55555555517b <callee+82> mov qword ptr [rbp - 8], rax
0x55555555517f <callee+86> mov rax, qword ptr [rbp - 8]
0x555555555183 <callee+90> pop rbp
0x555555555184 <callee+91> ret
pwndbg> b *callee+91
Breakpoint 4 at 0x555555555184
pwndbg> c
...
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
0x555555555178 <callee+79> add rax, rdx
0x55555555517b <callee+82> mov qword ptr [rbp - 8], rax
0x55555555517f <callee+86> mov rax, qword ptr [rbp - 8]
0x555555555183 <callee+90> pop rbp
► 0x555555555184 <callee+91> ret <0x5555555551bc; caller+55>
↓
...
pwndbg> print $rax
$1 = 123456789123456816
pwndbg> d
pwndbg> b *callee+90
Breakpoint 1 at 0x1183
pwndbg> r
...
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
► 0x555555555183 <callee+90> pop rbp
0x555555555184 <callee+91> ret
↓
...
pwndbg> si
pwndbg> si
...
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
0x555555555183 <callee+90> pop rbp
0x555555555184 <callee+91> ret
↓
► 0x5555555551bc <caller+55> add rsp, 8
0x5555555551c0 <caller+59> nop
0x5555555551c1 <caller+60> leave
0x5555555551c2 <caller+61> ret
↓
...
pwndbg> print $rbp
$1 = (void *) 0x7fffffffe300
pwndbg> print $rip
$2 = (void (*)()) 0x5555555551bc <caller+55>
// Name: sbof_auth.c
// Compile: gcc -o sbof_auth sbof_auth.c -fno-stack-protector
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_auth(char *password) {
int auth = 0;
char temp[16];
strncpy(temp, password, strlen(password));
if(!strcmp(temp, "SECRET_PASSWORD"))
auth = 1;
return auth;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ./sbof_auth ADMIN_PASSWORD\n");
exit(-1);
}
if (check_auth(argv[1]))
printf("Hello Admin!\n");
else
printf("Access Denied!\n");
}
// Name: sbof_auth.c
// Compile: gcc -o sbof_auth sbof_auth.c -fno-stack-protector
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_auth(char *password) {
int auth = 0;
char temp[16];
strncpy(temp, password, strlen(password));
if(!strcmp(temp, "SECRET_PASSWORD"))
auth = 1;
return auth;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ./sbof_auth ADMIN_PASSWORD\n");
exit(-1);
}
if (check_auth(argv[1]))
printf("Hello Admin!\n");
else
printf("Access Denied!\n");
}
// Name: rao.c
// Compile: gcc -o rao rao.c -fno-stack-protector -no-pie
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[0x28];
init();
printf("Input: ");
scanf("%s", buf);
return 0;
}
strcpy, strcat, sprintf 대신strncpy, strncat, snprintf, fgets, memcpy 사용// 정상 종료
$ gcc -o rao rao.c -fno-stack-protector -no-pie
$ ./rao
Input: AAAAA
$
// 비정상 종료
$ ./rao
Input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[1] 1828520 segmentation fault (core dumped) ./rao
$ gdb rao -c core.1828876
...
Could not check ASLR: Couldn't get personality
Core was generated by `./rao'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000400729 in main ()
...
pwndbg>
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
► 0x400729 <main+65> ret <0x4141414141414141>
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rsp 0x7fffc86322f8 ◂— 'AAAAAAAA'
01:0008│ 0x7fffc8632300 ◂— 0x0
02:0010│ 0x7fffc8632308 —▸ 0x4006e8 (main) ◂— push rbp
03:0018│ 0x7fffc8632310 ◂— 0x100000000
04:0020│ 0x7fffc8632318 —▸ 0x7fffc8632408 —▸ 0x7fffc86326f0 ◂— 0x434c006f61722f2e /* './rao' */
05:0028│ 0x7fffc8632320 ◂— 0x0
06:0030│ 0x7fffc8632328 ◂— 0x14b87e10e2771087
07:0038│ 0x7fffc8632330 —▸ 0x7fffc8632408 —▸ 0x7fffc86326f0 ◂— 0x434c006f61722f2e /* './rao' */
-> segfalut 발생 시 프로그램 상태
pwndbg> nearpc
0x400706 call printf@plt
0x40070b lea rax, [rbp - 0x30]
0x40070f mov rsi, rax
0x400712 lea rdi, [rip + 0xab]
0x400719 mov eax, 0
► 0x40071e call __isoc99_scanf@plt <__isoc99_scanf @plt>
format: 0x4007c4 ◂— 0x3b031b0100007325 /* '%s' */
vararg: 0x7fffffffe2e0 ◂— 0x0
...
pwndbg> x/s 0x4007c4
0x4007c4: "%s"__isoc99_scanf
-> scanf() 함수를 호출하는 어셈블리 코드