
Π Unix-ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½ΠΈ ΡΠΈΡΡΠ΅ΠΌΠΈ ΠΊΠΎΠΌΡΠ½ΠΈΠΊΠ°ΡΠΈΡΡΠ° Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°ΡΠ° Ρ Π²ΡΠ½ΡΠ½ΠΈΡ ΡΠ²ΡΡ ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½Π°ΡΠ° ΡΠΈΡΡΠ΅ΠΌΠ° ΡΡΠ°Π²Π° ΡΡΠ΅Π· ΠΌΠ°Π»ΡΠΊ Π½Π°Π±ΠΎΡ ΠΎΡ ΡΡΠ½ΠΊΡΠΈΠΈ β ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΡΠΈ. Π‘Π»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»Π½ΠΎ, Π·Π° ΠΎΡΡΡΡΠ°Π½ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ, Π΅ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π΄Π° ΡΠ΅ Π½Π°Π±Π»ΡΠ΄Π°Π²Π°Ρ ΠΈΠ·ΠΏΡΠ»Π½ΡΠ²Π°Π½ΠΈΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΠΈ ΡΡΠ΅Π· ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΡΠΈ.
Π£ΡΠΈΠ»ΠΈΡΠ°ΡΠ°, ΠΊΠΎΡΡΠΎ ΠΏΠΎΠΌΠ°Π³Π° Π·Π° ΡΠ»Π΅Π΄Π΅Π½Π΅ Π½Π° 'ΠΈΠ½ΡΠΈΠΌΠ½ΠΈΡ ΠΆΠΈΠ²ΠΎΡ' Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ Π² Linux, strace, Π΅ ΠΏΡΠ΅Π΄ΠΌΠ΅Ρ Π½Π° ΡΠ°Π·ΠΈ ΡΡΠ°ΡΠΈΡ. ΠΡΠΈΠΌΠ΅ΡΠΈ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° 'ΡΠΏΠΈΠΎΠ½ΡΠΊΠΈ' ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΈ Π²ΠΊΠ»ΡΡΠ²Π°Ρ ΠΊΡΠ°ΡΠΊΠ° ΠΈΡΡΠΎΡΠΈΡ strace ΠΈ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π½Π° ΡΡΡΡΠΎΠΉΡΡΠ²ΠΎΡΠΎ Π½Π° ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ.
Π‘ΡΠ΄ΡΡΠΆΠ°Π½ΠΈΠ΅
ΠΡΠΎΠΈΠ·Ρ ΠΎΠ΄ Π½Π° Π²ΠΈΠ΄ΠΎΠ²Π΅ΡΠ΅
ΠΡΠ½ΠΎΠ²Π½ΠΈΡΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ ΠΈ ΡΠ΄ΡΠΎΡΠΎ Π½Π° ΠΠ‘ Π² Unix ΡΠ° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΏΠΎΠ²ΠΈΡΠΈ (Π°Π½Π³Π». system calls, syscalls), Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ΡΠΎ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ Ρ Π²ΡΠ½ΡΠ½ΠΈΡ ΡΠ²ΡΡ ΡΡΠ°Π²Π° Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½ΠΎ ΡΡΠ΅Π· ΡΡΡ .
ΠΠΎ Π² ΠΏΡΡΠ²Π°ΡΠ° ΠΏΡΠ±Π»ΠΈΡΠ½Π° Π²Π΅ΡΡΠΈΡ Π½Π° Unix (, 1975 Π³ΠΎΠ΄ΠΈΠ½Π°) Π½ΡΠΌΠ°ΡΠ΅ ΡΠ΄ΠΎΠ±Π½ΠΈ Π½Π°ΡΠΈΠ½ΠΈ Π·Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΡΠΊΠΈΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΠΈ. ΠΠ° ΡΠ΅ΡΠ°Π²Π°Π½Π΅ Π½Π° ΡΠΎΠ·ΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌ, Bell Labs Π² ΡΠ»Π΅Π΄Π²Π°ΡΠ°ΡΠ° Π²Π΅ΡΡΠΈΡ (, 1979 Π³ΠΎΠ΄ΠΈΠ½Π°) ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠΈΡ
Π° Π½ΠΎΠ² ΡΠΈΡΡΠ΅ΠΌΠ΅Π½ ΠΏΠΎΠ²ΠΈΠΊ β ptrace.
Ptrace Π±Π΅ΡΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ΅Π½ ΠΏΡΠ΅Π΄ΠΈΠΌΠ½ΠΎ Π·Π° ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½ΠΈ Π΄Π΅Π±ΡΠ³Π΅ΡΠΈ, Π½ΠΎ Π² ΠΊΡΠ°Ρ Π½Π° 80-ΡΠ΅ (Π² Π΅ΡΠ°ΡΠ° Π½Π° ΠΊΠΎΠΌΠ΅ΡΡΠΈΠ°Π»Π½ΠΈΡ Π²Π΅ΡΠ΅ ) Π½Π° Π±Π°Π·Π°ΡΠ° Π½Π° Π½Π΅Π³ΠΎ ΡΠ΅ ΠΏΠΎΡΠ²ΠΈΡ Π° ΠΈ ΠΏΠΎΠ»ΡΡΠΈΡ Π° ΡΠΈΡΠΎΠΊΠΎ ΡΠ°Π·ΠΏΡΠΎΡΡΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΠΎΡΠ΅Π½ΠΈ Π΄Π΅Π±ΡΠ³Π΅ΡΠΈ β ΡΡΠ°ΡΠΈΡΠΎΠ²ΡΠΈΡΠΈ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΡΠΈ.
Π²Π΅ΡΡΠΈΡ Π½Π° strace Π±Π΅ΡΠ΅ ΠΏΡΠ±Π»ΠΈΠΊΡΠ²Π°Π½Π° ΠΎΡ ΠΠΎΠ» ΠΡΠΎΠ½Π΅Π½Π±ΡΡΠ³ Π² ΡΠ°Π·ΠΏΡΠ°ΡΠΊΠ°ΡΠ° comp.sources.sun ΠΏΡΠ΅Π· 1992 Π³ΠΎΠ΄ΠΈΠ½Π° ΠΊΠ°ΡΠΎ Π°Π»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π° Π½Π° Π·Π°ΡΠ²ΠΎΡΠ΅Π½Π°ΡΠ° ΡΡΠΈΠ»ΠΈΡΠ° trace ΠΎΡ Sun. ΠΠ°ΠΊ ΠΊΠ»ΠΎΠ½Π°, ΡΠ°ΠΊΠ° ΠΈ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π° Π±ΡΡ
Π° ΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½ΠΈ Π·Π° SunOS, Π½ΠΎ Π΄ΠΎ 1994 Π³ΠΎΠ΄ΠΈΠ½Π° strace Π±Π΅ΡΠ΅ ΠΏΠΎΡΡΠΈΡΠΎΠ²Π°Π½Π° Π½Π° System V, Solaris ΠΈ Π½Π°ΡΠ°ΡΡΠ²Π°ΡΠΈΡ ΠΏΠΎ ΠΏΠΎΠΏΡΠ»ΡΡΠ½ΠΎΡΡ Linux.
ΠΠ½Π΅Ρ strace ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ° ΡΠ°ΠΌΠΎ Linux ΠΈ ΡΠ°Π·ΡΠΈΡΠ° Π½Π° Π²ΡΠΈΡΠΊΠΎ ΡΡΡΠΎΡΠΎ ptrace, ΠΊΠΎΠ΅ΡΠΎ Π΅ Π½Π°ΡΡΡΠΏΠ°Π»ΠΎ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ ΡΠ°Π·ΡΠΈΡΠ΅Π½ΠΈΡ.
Π‘ΡΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΈΡΡ (ΠΈ Π΄ΠΎΡΡΠ° Π°ΠΊΡΠΈΠ²Π΅Π½) ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ°Ρ strace β . ΠΠ»Π°Π³ΠΎΠ΄Π°ΡΠ΅Π½ΠΈΠ΅ Π½Π° Π½Π΅Π³ΠΎ ΡΡΠΈΠ»ΠΈΡΠ°ΡΠ° ΠΏΡΠΈΠ΄ΠΎΠ±ΠΈ Π½Π°ΠΏΡΠ΅Π΄Π½Π°Π»ΠΈ Π²ΡΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΠΊΠ°ΡΠΎ ΠΈΠ½ΠΆΠ΅ΠΊΡΠΈΡ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ Π² ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΏΠΎΠ²ΠΈΡΠΈ, ΠΏΠΎΠ΄Π΄ΡΡΠΆΠΊΠ° Π½Π° ΡΠΈΡΠΎΠΊ ΡΠΏΠ΅ΠΊΡΡΡ ΠΎΡ Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠΈ ΠΈ, Π½Π°ΠΉ-Π²Π°ΠΆΠ½ΠΎΡΠΎ, . ΠΠ΅ΠΎΡΠΈΡΠΈΠ°Π»Π½ΠΈ ΠΈΠ·ΡΠΎΡΠ½ΠΈΡΠΈ ΡΠ²ΡΡΠ΄ΡΡ, ΡΠ΅ ΠΈΠ·Π±ΠΎΡΡΡ Π΅ ΠΏΠ°Π΄Π½Π°Π» Π²ΡΡΡ
Ρ ΡΡΠ°ΡΡΠ° Π·Π°ΡΠ°Π΄ΠΈ Π·Π²ΡΡΠ½ΠΎΡΡΡΠ° Π½Π° ΡΡΡΠΊΠ°ΡΠ° Π΄ΡΠΌΠ° "ΡΡΡΠ°ΡΡ" ΠΈ Π°Π½Π³Π»ΠΈΠΉΡΠΊΠΎΡΠΎ "strace".
Π‘ΡΡΠΎ ΡΠ°ΠΊΠ° Π΅ Π²Π°ΠΆΠ½ΠΎ, ΡΠ΅ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΡ ΠΏΠΎΠ²ΠΈΠΊ ptrace ΠΈ ΡΡΠ°ΡΠΈΡΠΎΠ²ΡΠΈΡΠΈΡΠ΅ ΡΠ°ΠΊΠ° ΠΈ Π½Π΅ Π±ΡΡ Π° Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈ Π² POSIX, Π²ΡΠΏΡΠ΅ΠΊΠΈ Π΄ΡΠ»Π³Π°ΡΠ° ΡΠΈ ΠΈΡΡΠΎΡΠΈΡ ΠΈ Π½Π°Π»ΠΈΡΠΈΠ΅ΡΠΎ Π½Π° ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π² Linux, FreeBSD, OpenBSD ΠΈ ΡΡΠ°Π΄ΠΈΡΠΈΠΎΠ½Π½ΠΈ Unix.
Π£ΡΡΡΠΎΠΉΡΡΠ²ΠΎΡΠΎ Π½Π° strace Π² Π΄Π²Π° Π΄ΡΠΌΠΈ: Piglet Trace
"You are not expected to understand this" (ΠΠ΅Π½ΠΈΡ Π ΠΈΡΠΈ, ΠΊΠΎΠΌΠ΅Π½ΡΠ°Ρ Π² ΠΈΠ·Ρ ΠΎΠ΄Π½ΠΈΡ ΠΊΠΎΠ΄ Π½Π° Version 6 Unix)
ΠΡ ΡΠ°Π½Π½ΠΎ Π΄Π΅ΡΡΡΠ²ΠΎ ΠΌΡΠ°Π·Ρ ΡΠ΅ΡΠ½ΠΈΡΠ΅ ΠΊΡΡΠΈΠΈ: Ρ ΠΈΠ³ΡΠ°ΡΠΊΠΈΡΠ΅ Π½Π΅ ΠΈΠ³ΡΠ°Π΅Ρ , Π° ΡΠ΅ ΠΎΠΏΠΈΡΠ²Π°Ρ Π΄Π° ΡΠ°Π·Π±Π΅ΡΠ° ΡΡΡΡΠΎΠΉΡΡΠ²ΠΎΡΠΎ ΠΈΠΌ (Π²ΡΠ·ΡΠ°ΡΡΠ½ΠΈΡΠ΅ ΠΏΠΎΠ»Π·Π²Π°Ρ Π° Π΄ΡΠΌΠ°ΡΠ° "ΡΡΠΏΠ΅Ρ ", Π½ΠΎ Π½Π΅ Π²ΡΡΠ²Π°ΠΉΡΠ΅ Π½Π° Π·Π»ΠΈΡΠ΅ Π΅Π·ΠΈΡΠΈ). ΠΠ΅ΡΠΎΡΡΠ½ΠΎ Π·Π°ΡΠΎΠ²Π° ΠΌΠΈ Π΅ ΡΠΎΠ»ΠΊΠΎΠ²Π° Π±Π»ΠΈΠ·ΠΊΠ° Π½Π΅ΡΠΎΡΠΌΠ°Π»Π½Π°ΡΠ° ΠΊΡΠ»ΡΡΡΠ° Π½Π° ΡΠ°Π½Π½ΠΈΡ Unix ΠΈ ΡΡΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΡΠΎ open-source Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅.
Π ΡΠ°ΠΌΠΊΠΈΡΠ΅ Π½Π° ΡΠ°Π·ΠΈ ΡΡΠ°ΡΠΈΡ ΡΠ°Π·Π³Π»Π΅ΠΆΠ΄Π°Π½Π΅ΡΠΎ Π½Π° ΠΈΠ·Ρ ΠΎΠ΄Π½ΠΈΡ ΠΊΠΎΠ΄ Π½Π° ΡΡΡΠ΅ΡΠΈΡΠ°Π½ΠΈΡ strace Π½Π΅ Π΅ ΡΠ°Π·ΡΠΌΠ½ΠΎ. ΠΠΎ ΠΈ ΡΠ°ΠΉΠ½ΠΈ Π·Π° ΡΠΈΡΠ°ΡΠ΅Π»ΠΈΡΠ΅ Π½Π΅ ΡΡΡΠ±Π²Π° Π΄Π° ΠΎΡΡΠ°Π²Π°Ρ. ΠΠ°ΡΠΎΠ²Π°, Π·Π° Π΄Π° ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΏΡΠΈΠ½ΡΠΈΠΏΠ° Π½Π° ΡΠ°Π±ΠΎΡΠ° Π½Π° ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ strace, ΡΠ΅ ΠΏΡΠΈΠ²Π΅Π΄Ρ ΠΊΠΎΠ΄Π° Π½Π° ΠΌΠΈΠ½ΠΈΠ°ΡΡΡΠ΅Π½ ΡΡΠ°ΡΠΈΡΠΎΠ²ΡΠΈΠΊ β (ptr). ΠΠΈΡΠΎ ΠΎΡΠΎΠ±Π΅Π½ΠΎ Π½Π΅ ΡΠΌΠ΅Π΅ Π΄Π° ΠΏΡΠ°Π²ΠΈ, Π½ΠΎ Π½Π°ΠΉ-Π²Π°ΠΆΠ½ΠΎΡΠΎ β ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΏΠΎΠ²ΠΈΡΠΈ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°ΡΠ° β ΠΈΠ·Π²Π΅ΠΆΠ΄Π°:
$ gcc examples/piglet-trace.c -o ptr
$ ptr echo test > /dev/null
BRK(12) -> 94744690540544
ACCESS(21) -> 18446744073709551614
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694657216512
CLOSE(3) -> 0
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
READ(0) -> 832
FSTAT(5) -> 0
MMAP(9) -> 140694657208320
MMAP(9) -> 140694650953728
MPROTECT(10) -> 0
MMAP(9) -> 140694655045632
MMAP(9) -> 140694655070208
CLOSE(3) -> 0
unknown(158) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MUNMAP(11) -> 0
BRK(12) -> 94744690540544
BRK(12) -> 94744690675712
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694646390784
CLOSE(3) -> 0
FSTAT(5) -> 0
IOCTL(16) -> 18446744073709551591
WRITE(1) -> 5
CLOSE(3) -> 0
CLOSE(3) -> 0
unknown(231)
Tracee terminatedPiglet Trace ΡΠ°Π·ΠΏΠΎΠ·Π½Π°Π²Π° ΠΎΠΊΠΎΠ»ΠΎ ΡΡΠΎΡΠΈΡΠΈ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠΎΠ²Π΅ Π½Π° Linux (Π²ΠΆ. ) ΠΈ ΡΠ°Π±ΠΎΡΠΈ ΡΠ°ΠΌΠΎ Π½Π° Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ°ΡΠ° x86-64. ΠΠ° ΡΡΠ΅Π±Π½ΠΈ ΡΠ΅Π»ΠΈ ΡΠΎΠ²Π° Π΅ Π΄ΠΎΡΡΠ°ΡΡΡΠ½ΠΎ.
ΠΠ΅ΠΊΠ° ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° Π½Π°ΡΠΈΡ ΠΊΠ»ΠΎΠ½. Π ΡΠ»ΡΡΠ°ΠΉ Π½Π° Linux, Π·Π° Π΄Π΅Π±ΡΠ³Π΅ΡΠΈΡΠ΅ ΠΈ ΡΡΠ°ΡΠΈΡΠΎΠ²ΡΠΈΡΠΈΡΠ΅ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°, ΠΊΠ°ΠΊΡΠΎ ΡΠΏΠΎΠΌΠ΅Π½Π°Ρ
ΠΌΠ΅ ΠΏΠΎ-Π³ΠΎΡΠ΅, ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΡ ΠΏΠΎΠ²ΠΈΠΊ ptrace. Π’ΠΎΠΉ ΡΠ°Π±ΠΎΡΠΈ, ΠΊΠ°ΡΠΎ ΠΏΡΠ΅Π΄Π°Π²Π° Π² ΠΏΡΡΠ²ΠΈΡ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΈΡΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄ΠΈΡΠ΅, ΠΎΡ ΠΊΠΎΠΈΡΠΎ Π½ΠΈ ΡΡΡΠ±Π²Π°Ρ ΡΠ°ΠΌΠΎ PTRACE_TRACEME, PTRACE_SYSCALL ΠΈ PTRACE_GETREGS.
Π Π°Π±ΠΎΡΠ°ΡΠ° Π½Π° ΡΡΠ°ΡΠΈΡΠΎΠ²ΡΠΈΠΊΠ° Π·Π°ΠΏΠΎΡΠ²Π° ΠΏΠΎ ΠΎΠ±ΠΈΡΠ°ΠΉΠ½ΠΈΡ Unix ΡΡΠΈΠ»: fork(2) ΡΡΠ°ΡΡΠΈΡΠ° Π΄ΠΎΡΠ΅ΡΠ΅Π½ ΠΏΡΠΎΡΠ΅Ρ, Π° ΡΠΎΠΉ ΠΎΡ ΡΠ²ΠΎΡ ΡΡΡΠ°Π½Π° Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° exec(3) ΡΡΠ°ΡΡΠΈΡΠ° ΠΈΠ·ΡΠ»Π΅Π΄Π²Π°Π½Π°ΡΠ° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°. ΠΠ΄ΠΈΠ½ΡΡΠ²Π΅Π½Π°ΡΠ° ΡΡΠ½ΠΊΠΎΡΡ ΡΡΠΊ Π΅ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ΡΠΎ Π½Π° ptrace(PTRACE_TRACEME) ΠΏΡΠ΅Π΄ΠΈ exec: ΠΏΡΠΎΡΠ΅ΡΡΡ-ΠΏΠΎΡΠΎΠΌΡΠΊ ΠΎΡΠ°ΠΊΠ²Π°, ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΡ-ΡΠΎΠ΄ΠΈΡΠ΅Π» ΡΠ΅ Π³ΠΎ Π½Π°Π±Π»ΡΠ΄Π°Π²Π°:
pid_t child_pid = fork();
switch (child_pid) {
case -1:
err(EXIT_FAILURE, "fork");
case 0:
/* Child here */
/* Π Π΅ΠΆΠΈΠΌ ΡΡΠ°ΡΡΠΈΡΠΎΠ²ΠΊΠΈ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΡΡ Π²ΠΊΠ»ΡΡΠ΅Π½. Π ΠΎΠ΄ΠΈΡΠ΅Π»Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΠ΄Π΅Ρ ΠΏΠΎΠ΄ΠΎΠΆΠ΄Π°ΡΡ(2) Π·Π° ΡΡΠΎ, */
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
/* ΠΠ°ΠΌΠ΅Π½ΠΈΡΡ ΡΠ΅Π±Ρ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠΎΠΉ Π΄Π»Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ. */
execvp(argv[1], argv + 1);
err(EXIT_FAILURE, "exec");
}ΠΡΠΎΡΠ΅ΡΡΡ-ΡΠΎΠ΄ΠΈΡΠ΅Π» ΡΠ΅Π³Π° ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠ·Π²ΠΈΠΊΠ° wait(2) Π² Π΄ΠΎΡΠ΅ΡΠ½ΠΈΡ ΠΏΡΠΎΡΠ΅Ρ, ΡΠΎ Π΅ΡΡΡ Π΄Π° ΡΠ΅ ΡΠ²Π΅ΡΠΈ, ΡΠ΅ ΠΏΡΠ΅Π²ΠΊΠ»ΡΡΠ²Π°Π½Π΅ΡΠΎ Π² ΡΠ΅ΠΆΠΈΠΌ Π½Π° ΡΡΠ°ΡΠΈΡΠΎΠ²ΠΊΠ° Π΅ ΡΡΠ°Π½Π°Π»ΠΎ:
/* Parent */
/* First we wait for the child to set the traced mode (see
* ptrace(PTRACE_TRACEME) above) */
if (waitpid(child_pid, NULL, 0) == -1)
err(EXIT_FAILURE, "traceme -> waitpid");ΠΠ° ΡΠΎΠ·ΠΈ Π΅ΡΠ°ΠΏ ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ°ΡΠ° ΠΏΡΠΈΠΊΠ»ΡΡΠ²Π° ΠΈ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΏΡΠ΅ΠΌΠΈΠ½Π΅ΠΌ ΠΊΡΠΌ Π½Π°Π±Π»ΡΠ΄Π΅Π½ΠΈΠ΅ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΏΠΎΠ²ΠΈΡΠΈ Π² Π±Π΅Π·ΠΊΡΠ°Π΅Π½ ΡΠΈΠΊΡΠ».
ΠΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ ptrace(PTRACE_SYSCALL) Π³Π°ΡΠ°Π½ΡΠΈΡΠ°, ΡΠ΅ ΠΏΠΎΡΠ»Π΅Π΄Π²Π°ΡΠΈΡΡ wait Π½Π° ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ ΠΏΡΠΈΠΊΠ»ΡΡΠΈ ΠΈΠ»ΠΈ ΠΏΡΠ΅Π΄ΠΈ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡ ΠΏΠΎΠ²ΠΈΠΊ, ΠΈΠ»ΠΈ Π²Π΅Π΄Π½Π°Π³Π° ΡΠ»Π΅Π΄ Π½Π΅Π³ΠΎΠ²ΠΎΡΠΎ Π·Π°Π²ΡΡΡΠ²Π°Π½Π΅. ΠΠ΅ΠΆΠ΄Ρ Π΄Π²Π΅ΡΠ΅ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½ΠΈΡ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΎΡΡΡΠ΅ΡΡΠ²ΠΈΠΌ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ: Π΄Π° Π·Π°ΠΌΠ΅Π½ΠΈΠΌ ΠΏΠΎΠ²ΠΈΠΊΠ° Ρ Π°Π»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π΅Π½, Π΄Π° ΠΏΡΠΎΠΌΠ΅Π½ΠΈΠΌ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΈΡΠ΅ ΠΈΠ»ΠΈ Π²ΡΡΡΠ°Π½Π°ΡΠ° ΡΡΠΎΠΉΠ½ΠΎΡΡ.
ΠΠΎΡΡΠ°ΡΡΡΠ½ΠΎ Π΅ Π΄Π° ΠΈΠ·Π²ΠΈΠΊΠ°ΠΌΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° Π΄Π²Π° ΠΏΡΡΠΈ ptrace(PTRACE_GETREGS), Π·Π° Π΄Π° ΠΏΠΎΠ»ΡΡΠΈΠΌ ΡΡΡΡΠΎΡΠ½ΠΈΠ΅ΡΠΎ Π½Π° ΡΠ΅Π³ΠΈΡΡΡΠ° rax ΠΏΡΠ΅Π΄ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ° (Π½ΠΎΠΌΠ΅Ρ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡ ΠΏΠΎΠ²ΠΈΠΊ) ΠΈ Π²Π΅Π΄Π½Π°Π³Π° ΡΠ»Π΅Π΄ (Π²ΡΡΠ½Π°ΡΠ° ΡΡΠΎΠΉΠ½ΠΎΡΡ).
ΠΡΡΡΠ½ΠΎΡΡ, ΡΠΈΠΊΡΠ»ΡΡ:
/* A system call tracing loop, one interation per call. */
for (;;) {
/* A non-portable structure defined for ptrace/GDB/strace usage mostly.
* It allows to conveniently dump and access register state using
* ptrace. */
struct user_regs_struct registers;
/* Enter syscall: continue execution until the next system call
* beginning. Stop right before syscall.
*
* It's possible to change the system call number, system call
* arguments, return value or even avoid executing the system call
* completely. */
if (ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL) == -1)
err(EXIT_FAILURE, "enter_syscall");
if (waitpid(child_pid, NULL, 0) == -1)
err(EXIT_FAILURE, "enter_syscall -> waitpid");
/* According to the x86-64 system call convention on Linux (see man 2
* syscall) the number identifying a syscall should be put into the rax
* general purpose register, with the rest of the arguments residing in
* other general purpose registers (rdi,rsi, rdx, r10, r8, r9). */
if (ptrace(PTRACE_GETREGS, child_pid, NULL, ®isters) == -1)
err(EXIT_FAILURE, "enter_syscall -> getregs");
/* Note how orig_rax is used here. That's because on x86-64 rax is used
* both for executing a syscall, and returning a value from it. To
* differentiate between the cases both rax and orig_rax are updated on
* syscall entry/exit, and only rax is updated on exit. */
print_syscall_enter(registers.orig_rax);
/* Exit syscall: execute of the syscall, and stop on system
* call exit.
*
* More system call tinkering possible: change the return value, record
* time it took to finish the system call, etc. */
if (ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL) == -1)
err(EXIT_FAILURE, "exit_syscall");
if (waitpid(child_pid, NULL, 0) == -1)
err(EXIT_FAILURE, "exit_syscall -> waitpid");
/* Retrieve register state again as we want to inspect system call
* return value. */
if (ptrace(PTRACE_GETREGS, child_pid, NULL, ®isters) == -1) {
/* ESRCH is returned when a child terminates using a syscall and no
* return value is possible, e.g. as a result of exit(2). */
if (errno == ESRCH) {
fprintf(stderr, "nTracee terminatedn");
break;
}
err(EXIT_FAILURE, "exit_syscall -> getregs");
}
/* Done with this system call, let the next iteration handle the next
* one */
print_syscall_exit(registers.rax);
}Π’ΠΎΠ²Π° Π΅ ΡΠ΅Π»ΠΈΡΡ ΡΡΠ°ΡΠΎΠ²ΠΈΠΊ. Π‘Π΅Π³Π° Π·Π½Π°Π΅ΡΠ΅ ΠΎΡΠΊΡΠ΄Π΅ Π΄Π° Π·Π°ΠΏΠΎΡΠ½Π΅ΡΠ΅ Π½ΠΎΠ²ΠΎΡΠΎ ΠΏΠΎΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Linux.
ΠΡΠ½ΠΎΠ²ΠΈ: ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ° ΠΏΠΎΠ΄ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° strace
ΠΠ°ΡΠΎ ΠΏΡΡΠ²ΠΈ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ strace, Π²Π΅ΡΠΎΡΡΠ½ΠΎ, ΡΠΈ ΡΡΡΡΠ²Π° Π΄Π° ΠΏΡΠΈΠ²Π΅Π΄Π΅ΠΌ Π½Π°ΠΉ-ΠΏΡΠΎΡΡΠΈΡ Π½Π°ΡΠΈΠ½ β ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° strace.
ΠΠ° Π΄Π° Π½Π΅ ΡΠ΅ ΡΠΎΠ²ΠΈΠΌ Π² Π±Π΅Π·ΠΊΡΠ°Π΅Π½ ΡΠΏΠΈΡΡΠΊ ΠΎΡ ΠΏΠΎΠ²ΠΈΡΠΈ Π½Π° ΡΠΈΠΏΠΈΡΠ½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°, ΡΠ΅ Π½Π°ΠΏΠΈΡΠ΅ΠΌ ΠΎΠΊΠΎΠ»ΠΎ write:
int main(int argc, char *argv[])
{
char str[] = "write me to stdoutn";
/* write(2) Π΅ ΠΏΡΠΎΡΡ ΠΎΠ±Π²ΠΈΠ²Π΅Π½ ΠΎΠΊΠΎΠ»ΠΎ ΡΠΈΡΡΠ΅ΠΌΠ΅Π½ ΠΏΠΎΠ²ΠΈΠΊ, ΡΠ°ΠΊΠ° ΡΠ΅ ΡΡΡΠ±Π²Π° Π΄Π° Π΅ Π»Π΅ΡΠ½ΠΎ Π΄Π°
* Π±ΡΠ΄Π΅ ΠΎΡΠΊΡΠΈΡ Π² ΡΡΠ°ΡΠ΅ΡΠΎ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡ ΠΏΠΎΠ²ΠΈΠΊ. */
if (sizeof(str) != write(STDOUT_FILENO, str, sizeof(str))){
perror("write");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
ΠΠ΅ΠΊΠ° ΡΡΠ±Π΅ΡΠ΅ΠΌ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°ΡΠ° ΠΈ Π΄Π° ΡΠ΅ ΡΠ²Π΅ΡΠΈΠΌ, ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ:
$ gcc examples/write-simple.c -o write-simple
$ ./write-simple
write me to stdoutΠ Π½Π°ΠΊΡΠ°Ρ, Π½Π΅ΠΊΠ° Ρ ΡΡΠ°ΡΡΠΈΡΠ°ΠΌΠ΅ ΠΏΠΎΠ΄ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° strace:
$ strace ./write-simple
pexecve("./write", ["./write"], 0x7ffebd6145b0 /* 71 vars */) = 0
brk(NULL) = 0x55ff5489e000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=197410, ...}) = 0
mmap(NULL, 197410, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7a2a633000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113 3 >