mirror of
https://github.com/upx/upx.git
synced 2025-08-11 22:52:30 +08:00
SIGSEGV: handle and pretty-print on amd64-linux
This commit is contained in:
@ -423,6 +423,8 @@ tc.amd64-linux.elf.gcc = amd64-linux-gcc-3.4.4 -fPIC -m64 -nostdinc -MMD -MT $@
|
||||
tc.amd64-linux.elf.gcc += -fno-exceptions -fno-asynchronous-unwind-tables
|
||||
tc.amd64-linux.elf.gcc += -Wall -W -Wcast-align -Wcast-qual -Wstrict-prototypes -Wwrite-strings -Werror
|
||||
|
||||
#amd64-linux.elf-entry.h amd64-linux.elf-fold.h: tc.amd64-linux.elf.gcc += -DTEST_SIGSEGV
|
||||
|
||||
amd64-linux.elf-entry.h: $(srcdir)/src/$$T.S
|
||||
@echo; echo TARGET=$@ PATH=$(PATH); echo
|
||||
$(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
|
||||
|
@ -95,6 +95,45 @@ _start: .globl _start
|
||||
push %rcx // argc
|
||||
push %rdx // param for atexit()
|
||||
|
||||
#if TEST_SIGSEGV
|
||||
// install SIGSEGV handler for debugging
|
||||
SIGSEGV= 11
|
||||
SA_SIGINFO= 4 // /usr/include/bits/sigaction.h
|
||||
SA_RESTORER= 0x04000000
|
||||
__NR_rt_sigaction= 13 // /usr/include/asm/unistd_64.h
|
||||
push %rdi // save reg
|
||||
sub %edx,%edx // arg3= 0 ==> do not save old sigaction
|
||||
push %rdx // .sa_mask: 64 bits (8 bytes) of flags for signals
|
||||
lea __restore_rt(%rip),%rax; push %rax // .sa_restorer
|
||||
push $SA_RESTORER | SA_SIGINFO // .sa_flags
|
||||
lea sigsegv_sigaction(%rip),%rax; push %rax // .sa_sigaction
|
||||
push %rsp; pop %rsi // arg2= &new struct sigaction
|
||||
push $SIGSEGV; pop %rdi // arg1= signum
|
||||
push $8; pop %r10 // sys4= sizeof(__sigset_t) ==> 64 bits
|
||||
push $__NR_rt_sigaction; pop %rax; syscall
|
||||
add $(3 + 1) * NBPW,%rsp // toss struct sigaction
|
||||
pop %rdi // restore reg
|
||||
|
||||
#if 0 //{ TEST ONLY
|
||||
movl $0x18181818,%r8d
|
||||
movl $0x19191919,%r9d
|
||||
movl $0x1a1a1a1a,%r10d
|
||||
movl $0x1b1b1b1b,%r11d
|
||||
movl $0x1c1c1c1c,%r12d
|
||||
movl $0x1d1d1d1d,%r13d
|
||||
movl $0x1e1e1e1e,%r14d
|
||||
movl $0x1f1f1f1f,%r15d
|
||||
movl $0xaaaaaaaa,%eax
|
||||
movl $0xbbbbbbbb,%ebx
|
||||
movl $0xcccccccc,%ecx
|
||||
movl $0xdddddddd,%edx
|
||||
movl $0x55555555,%ebp
|
||||
movl $0x66666666,%esi
|
||||
movl $0x77777777,%edi
|
||||
movl (%rdx),%edx // force SIGSEGV
|
||||
#endif //}
|
||||
#endif // TEST_SIGSEGV
|
||||
|
||||
#define old_sp %rbp
|
||||
F_FRAME= 7*NBPW
|
||||
F_ENTR= 6*NBPW; F_PMASK= F_ENTR
|
||||
@ -295,6 +334,165 @@ eof_n2b:
|
||||
add $D_FOLD,%rax // beyond .data
|
||||
jmp *%rax // goto unfolded stub
|
||||
|
||||
#if TEST_SIGSEGV
|
||||
__NR_rt_sigreturn= 15
|
||||
.balign 16
|
||||
__restore_rt:
|
||||
endbr64
|
||||
mov $__NR_rt_sigreturn,%eax
|
||||
syscall
|
||||
|
||||
.balign 16
|
||||
sigsegv_sigaction:
|
||||
endbr64
|
||||
push %rdx // save &ucontext_t
|
||||
|
||||
// print /proc/self/maps of child (same as parent: the beauty of fork())
|
||||
mov $end_announce_sigaction - announce_sigaction,%edx // arg3 len
|
||||
lea announce_sigaction(%rip),%rsi // arg2 buf
|
||||
push $2; pop %rdi // arg1 fd_stderr
|
||||
push $__NR_write; pop %eax; syscall // ignore error on write()
|
||||
|
||||
xor %esi,%esi // arg2 O_RDONLY
|
||||
lea proc_self_maps(%rip),%arg1
|
||||
push $__NR_open; pop %rax; syscall
|
||||
mov %rax,%r12 // fd_maps
|
||||
BUFLEN= 4096
|
||||
mov $BUFLEN,%ebx; sub %rbx,%rsp // allocate buffer
|
||||
loop_maps:
|
||||
mov %ebx,%edx // arg3 buflen
|
||||
push %rsp; pop %rsi // arg2 buffer
|
||||
mov %r12,%rdi // arg1 fd_maps
|
||||
xor %eax,%eax; syscall // __NR_read
|
||||
test %eax,%eax; jle done_maps // ignore error on read()
|
||||
mov %eax,%edx // arg3 buflen
|
||||
push %rsp; pop %rsi // arg2 buf
|
||||
push $2; pop %rdi // arg1 fd_stderr
|
||||
push $__NR_write; pop %rax; syscall // ignore error on write()
|
||||
jmp loop_maps
|
||||
done_maps:
|
||||
mov %r12,%rdi //arg1 fd_maps
|
||||
add %rbx,%rsp // discard buffer
|
||||
push $__NR_close; pop %rax; syscall
|
||||
// end printing of /proc/self/maps
|
||||
|
||||
pop %rdx // restore &ucontext_t
|
||||
__NR_fork= 57
|
||||
push $__NR_fork; pop %rax; call sys_check
|
||||
test %eax,%eax; je child
|
||||
parent:
|
||||
jmp parent // spin; paused by gdb
|
||||
|
||||
proc_self_cmdline:
|
||||
.asciz "/proc/self/cmdline"
|
||||
announce_sigaction:
|
||||
.asciz "\n\nSIGSEGV address space:\n"
|
||||
end_announce_sigaction:
|
||||
|
||||
proc_self_maps:
|
||||
.asciz "/proc/self/maps"
|
||||
minus_q:
|
||||
.asciz "-q"
|
||||
path_gdb:
|
||||
.asciz "/usr/bin/gdb"
|
||||
commands_gdb:
|
||||
.ascii "info inferiors\n"
|
||||
|
||||
.ascii "print \"r8, r9\"\n"
|
||||
.ascii "x/2xg $rdx + 5*8\n"
|
||||
.ascii "print \"r10, r11\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
.ascii "print \"r12, r13\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
.ascii "print \"r14, r15\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
|
||||
.ascii "print \"rdi, rsi\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
.ascii "print \"rbp, rbx\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
.ascii "print \"rdx, rax\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
.ascii "print \"rcx, rsp\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
.ascii "print \"rip, efl\"\n"
|
||||
.ascii "x/2xg\n"
|
||||
|
||||
.ascii "set $pc = *(long *)($rdx + 168)\n"
|
||||
.ascii "print \"faulting instr\"\n"
|
||||
.ascii "x/i $pc\n"
|
||||
.ascii "print \"fault context\"\n"
|
||||
.ascii "x/24i $pc - 0x20\n"
|
||||
|
||||
.ascii "kill\n"
|
||||
.ascii "quit 1"
|
||||
.byte 0
|
||||
commands_gdb_end:
|
||||
|
||||
child:
|
||||
PATH_MAX= 4096
|
||||
sub $PATH_MAX,%rsp
|
||||
lea proc_self_cmdline(%rip),%arg1
|
||||
O_RDONLY= 0
|
||||
push $O_RDONLY; pop %arg2
|
||||
push $__NR_open; pop %rax; call sys_check
|
||||
push %rax; pop %arg1 // fd
|
||||
push %rsp; pop %arg2 // buffer
|
||||
push $PATH_MAX; pop %arg3
|
||||
__NR_read= 0
|
||||
push $__NR_read; pop %rax; call sys_check
|
||||
push $__NR_close; pop %eax; call sys_check
|
||||
|
||||
__NR_getppid= 110
|
||||
push $__NR_getppid; pop %eax; syscall
|
||||
push %rax; pop %rsi
|
||||
xor %eax,%eax; push %rax; push %rax // decimal(pid) fits in 16 bytes
|
||||
push %rsp; pop %rdi; call unsimal
|
||||
// argv
|
||||
push %rsp; pop %rsi // fence post: &pid.unsimal
|
||||
push $0 // argv[4]
|
||||
push %rsi // arg3 pid
|
||||
add $16,%rsi; push %rsi // arg2 exename
|
||||
lea minus_q(%rip),%rax; push %rax // arg1 "-q"
|
||||
add $(path_gdb - minus_q),%rax; push %rax // arg[0] "/usr/bin/gdb"
|
||||
|
||||
#if 1 //{ pipe input to gdb
|
||||
xor %edi,%edi; push $__NR_close; pop %rax; syscall
|
||||
push %rax; push %rsp; pop %rdi // &fd_pipe[2]; 4 bytes each
|
||||
__NR_pipe= 22
|
||||
push $__NR_pipe; pop %rax; call sys_check
|
||||
pop %rdi; shr $32,%rdi // arg1 write side of pipe
|
||||
|
||||
push $commands_gdb_end - commands_gdb; pop %arg3
|
||||
lea commands_gdb(%rip),%arg2
|
||||
__NR_write= 1
|
||||
push $__NR_write; pop %rax; call sys_check
|
||||
push $__NR_close; pop %rax; syscall
|
||||
#endif //}
|
||||
|
||||
push $0; pop %arg3 // _environ BUG
|
||||
push %rsp; pop %arg2 // argv
|
||||
movq (%arg2),%arg1 // "/usr/bin/gdb"
|
||||
__NR_execve= 59
|
||||
push $__NR_execve; pop %rax; call sys_check
|
||||
hlt
|
||||
|
||||
unsimal: // (dst, value)
|
||||
push $10; pop %rcx // radix
|
||||
mov %esi,%eax // value
|
||||
call 0f
|
||||
movb $0,(%rdi) // terminator
|
||||
ret
|
||||
0:
|
||||
xor %edx,%edx; div %ecx; push %rdx // eax= quo(%edx:%eax / %ecx); edx= rem
|
||||
// 'div' undefines all flags!
|
||||
test %eax,%eax; je 1f; call 0b
|
||||
1:
|
||||
pop %rax; add $'0',%eax
|
||||
stosb
|
||||
ret
|
||||
#endif // TEST_SIGSEGV
|
||||
|
||||
sys_check:
|
||||
push %rax // save __NR_ for debug
|
||||
syscall
|
||||
|
@ -177,6 +177,17 @@ no_env_pse:
|
||||
mov %ebp,%ebx # fd
|
||||
movq %rax,3*NBPW(%rsp) # entry
|
||||
|
||||
#if TEST_SIGSEGV
|
||||
// Uninstall SIGSEGV handler
|
||||
SIGSEGV= 11
|
||||
__NR_rt_sigaction= 13 // /usr/include/asm/unistd_64.h
|
||||
push $8; pop %sys4 // sys_arg4 minimal byte count
|
||||
xor %edx,%edx // no old
|
||||
xor %esi,%esi // no new
|
||||
push $SIGSEGV; pop %rdi
|
||||
push $__NR_rt_sigaction; pop %eax; syscall
|
||||
#endif // TEST_SIGSEGV
|
||||
|
||||
sz_Ehdr= 8*NBPW
|
||||
e_type= 16
|
||||
ET_EXEC= 2
|
||||
|
Reference in New Issue
Block a user