저는 Oracle Linux 9(XFS 파일 시스템)에서 바이너리의 동작을 연구하고 있습니다. 프로세스가 이 바이너리를 호출하면 그 아래에 디렉터리가 생성되고 /tmp
일부 파일이 해당 디렉터리에 복사됩니다. 이 디렉터리는 프로세스가 실행될 때마다 임의의 이름(키워드 + GUID)을 가져옵니다.
그 후에는 해당 디렉터리를 즉시 삭제합니다. 디렉토리를 삭제하기 전에 디렉토리에 포함된 파일에 액세스하고 싶지만 명령을 실행하기에는 전체 프로세스가 너무 빨리 종료됩니다.
디렉터리를 삭제하기 전에 디렉터리를 "가로채서" 복사할 수 있는 방법이 있습니까?
답변1
언제든지 다음 위치에서 애플리케이션을 실행할 수 있습니다.
gdb --args /path/to/your/your-program and its args
unlink()
unlinkat()
그런 다음 , , rmdir()
함수 또는 시스템 호출 에 중단점을 추가합니다 .
catch syscall unlink
catch syscall unlinkat
catch syscall rmdir
run
그런 다음 중단점에 도달할 때마다 해당 디렉터리의 파일을 삭제할지 확인하고 그 안에 있는 파일을 확인하거나 다른 곳에 복사하세요. cont
실행을 재개하려면(다음 중단점까지) gdb에 입력하세요 .
예 rm -rf
:
$ gdb -q --args rm -rf /tmp/tmp.HudBncQ4Ni
Reading symbols from rm...
Reading symbols from /usr/lib/debug/.build-id/f6/7ac1d7304650a51950992d074f98ec88fe2f49.debug...
(gdb) catch syscall unlink
Catchpoint 1 (syscall 'unlink' [87])
(gdb) catch syscall unlinkat
Catchpoint 2 (syscall 'unlinkat' [263])
(gdb) catch syscall rmdir
Catchpoint 3 (syscall 'rmdir' [84])
(gdb) run
Starting program: /bin/rm -rf /tmp/tmp.HudBncQ4Ni
Catchpoint 2 (call to syscall unlinkat), 0x00007ffff7eb6fa7 in __GI_unlinkat () at ../sysdeps/unix/syscall-template.S:120
120 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) info registers
rax 0xffffffffffffffda -38
rbx 0x555555569830 93824992319536
rcx 0x7ffff7eb6fa7 140737352789927
rdx 0x0 0
rsi 0x555555569938 93824992319800
rdi 0x4 4
rbp 0x555555568440 0x555555568440
rsp 0x7fffffffda48 0x7fffffffda48
r8 0x3 3
r9 0x0 0
r10 0xfffffffffffffa9c -1380
r11 0x206 518
r12 0x0 0
r13 0x7fffffffdc30 140737488346160
r14 0x0 0
r15 0x555555569830 93824992319536
rip 0x7ffff7eb6fa7 0x7ffff7eb6fa7 <__GI_unlinkat+7>
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) x/s $rsi
0x555555569938: "test"
(gdb) info proc
process 7524
cmdline = '/bin/rm -rf /tmp/tmp.HudBncQ4Ni'
cwd = '/export/home/stephane'
exe = '/bin/rm'
(gdb) !readlink /proc/7524/fd/4
/tmp/tmp.HudBncQ4Ni
(gdb) !find /tmp/tmp.HudBncQ4Ni -ls
1875981 4 drwx------ 2 stephane stephane 4096 Aug 8 09:30 /tmp/tmp.HudBncQ4Ni
1835128 4 -rw-r--r-- 1 stephane stephane 5 Aug 8 09:30 /tmp/tmp.HudBncQ4Ni/test
여기서 중단점은 unlinkat()
x86_64 Linux 시스템 내부 항목의 시스템 호출에 배치됩니다. 여기서 시스템 호출의 처음 두 매개변수는 및 레지스터에 있습니다.test
/tmp/tmp.HudBncQ4Ni
rdi
rsi
strace
시스템 호출을 호출할 때 프로세스에 신호(예: 일시 중지)를 주입할 수 있지만 strace -e inject=unlink,unlinkat,rmdir:signal=STOP
AFAICT는 항상 그렇습니다.뒤쪽에파일이 삭제되면 시스템 호출이 반환됩니다.
Ctrl그러나 + 를 사용하여 수동으로 일시 중지 할 수 있도록 입력을 지연할 수 있습니다 Z. 예를 들면 다음과 같습니다.
$ strace -e inject=unlink,unlinkat,rmdir:delay_enter=5s -e unlink,unlinkat,rmdir rm -rf /tmp/tmp.HudBncQ4Ni
unlinkat(4, "test", 0^Z
zsh: suspended strace -e inject=unlink,unlinkat,rmdir:delay_enter=10s -e rm -rf
또는 @PhilippWendler가 제안한 대로 다음을 사용할 수 있습니다.
strace -e inject=unlink,unlinkat,rmdir:retval=0 -e unlink,unlinkat,rmdir ...
또는:
strace -e inject=unlink,unlinkat,rmdir:error=EACCES -e unlink,unlinkat,rmdir ...
시스템 호출을 하이재킹하고 성공(사용 retval=0
)하거나 실패( EACCES
여기서는 의미) 한 척합니다.허가가 거부되었습니다) 실제로 전화하지 않고.
gdb
strace
이미 실행 중인 프로세스에 각각 사용/연결할 수 있습니다 . 또한 포크와 실행을 추적하고 하위 항목을 추적하여 상위 항목에 연결하고 하위 항목의 연결 해제를 모니터링하거나 하이재킹할 수 있도록 지시할 수도 있습니다( 및 의 설정 참조).--pid <the-process-id>
-p <the-process-id>
-f
strace
follow-*
gdb
답변2
내가 원하는 것을 정확히 수행하는 inotify-tools를 사용하여 이 쉘 스크립트를 찾았습니다(저자:https://unix.stackexchange.com/a/265995/536771):
#!/bin/sh
TMP_DIR=/tmp
CLONE_DIR=/tmp/clone
mkdir -p $CLONE_DIR
wait_dir() {
inotifywait -mr --format='%w%f' -e create "$1" 2>/dev/null | while read file; do
echo $file
DIR=`dirname "$file"`
mkdir -p "${CLONE_DIR}/${DIR#$TMP_DIR/}"
cp -rl "$file" "${CLONE_DIR}/${file#$TMP_DIR/}"
done
}
trap "trap - TERM && kill -- -$$" INT TERM EXIT
inotifywait -m --format='%w%f' -e create "$TMP_DIR" | while read file; do
if ! [ -d "$file" ]; then
continue
fi
echo "setting up wait for $file"
wait_dir "$file" &
done
저에게는 간단한 솔루션이 스크립트보다 훨씬 좋습니다.
chattr +a /tmp
이는 바이너리가 폴더 대신 /tmp 아래에 단일 파일을 생성하는 경우 스크립트가 실패하기 때문입니다. 바이너리가 /tmp 아래에 여러 폴더를 생성하는 경우에도 실패합니다.
편집: 작동하는 더 간단한 솔루션은 다음을 실행하는 것입니다.
cp -rp /source /clone
chattr이 내가 확인하는 내용을 방해합니다. 첫 번째 스크립트는 /tmp 아래에 생성된 디렉터리에는 작동하지만 /tmp 아래에 생성된 파일에는 작동하지 않습니다.
답변3
나는 과거에도 비슷한 상황에 처해 있었습니다. chattr -R -a /tmp
본질적으로 방금 추가된 비슷한 것을 실행한 것을 막연하게 기억합니다 /tmp
. 프로세스는 파일/디렉토리를 생성할 수 있지만 삭제할 수는 없습니다. 명령을 실행하기 전에 주의 깊게 확인하고 가능한 한 빨리 속성을 취소하십시오.
답변4
내가 다양한 기능(듣기)에 사용한 솔루션은 관심 있는 기능(예: unlink 또는 fopen)을 재정의하는 간단한 동적 라이브러리를 만드는 것입니다.
컴파일하고 링크하여 -fPIC
동적 라이브러리를 만든 다음 바이너리에 삽입합니다.
LD_PRELOAD=/path/to/mylib.so ./binary