Em computação, o Executable and Linking Format (ELF, também chamado de Extensible Linking Format) é um padrão comum de arquivo para executáveis, código objeto, bibliotecas compartilhadas, e core dumps. Publicado pela primeira vez na especificação para a interface binária de aplicação (Application Binary Interface - ABI) da versão denominada System V Release 4 (SVR4) do sistema operacional Unix, e posteriormente no Padrão de Interface de Ferramenta, foi rapidamente aceito entre diferentes fornecedores de sistemas Unix. [https://pt.wikipedia.org/wiki/Executable_and_Linkable_Format]
Cada arquivo ELF é composto de um cabeçalho ELF, seguido pelos dados do arquivo.
Os dados podem incluir:
Tabela de cabeçalho do programa, descrevendo zero ou mais segmentos de memória;
Tabela de cabeçalho de seção, descrevendo zero ou mais seções;
Dados referidos por entradas na tabela de cabeçalho do programa ou na tabela de cabeçalho de seção.
Entre os dados referidos pelas entradas de cabeçalho do programa (ou de tabela de cabeçalho de seção), encontraremos o payload, que consiste nas instruções em linguagem de máquina (para cada arquitetura) que codifica os fragmentos de código (text) que representam o programa.
O respectivo formato de arquivo para sistemas da Microsoft (Windows) é o PE. [https://en.wikipedia.org/wiki/Portable_Executable]
Seguindo formato ELF, shared objects e executáveis possuem duas tabelas de símbolos: “.symtab” e “.dynsym”.
A tabela .dynsym é uma versão reduzida da tabela .symtab que contém apenas símbolos globais. A informação encontrada em .dynsym é também disponibilizada em .symtab, enquanto o contrário nem sempre é válido.
A ideia da tabela .dynsym é facilitar o processo de carga dinâmica em tempo de execução, provendo lista de símbolos que deverão ser resolvidos pelo carregador. Por ser reduzida, quando comparada com .symtab, permite otimizar o processo de disparo de execução da aplicação.
Neste exercício, você deverá criar uma aplicação capaz de receber um parâmetro em linha de comando, que será o nome do binário a ser analisado: meubinario
.
A partir do parâmetro recebido, sua aplicação deverá analisar o cabeçalho ELF do binário e deverá listar, na sequência de registro, os símbolos constantes na tabela .dynsym.
Um exemplo típico de linha de comando pode ser encontrado abaixo:
$ ./meu_programa ./minhalib.so
A aplicação deverá responder da seguinte forma:
caso a DL informada em linha de comando não exista, a aplicação deverá informar mensagem em linha única de stdout
;
para cada símbolo encontrado na tabela .dynsym, o valor do símbolo deverá ser impresso em linha separada;
caso a entrada da tabela de símbolos não tenha uma string associada, deverá ser impressa linha em branco.
Tomemos como referência uma aplicação (64 bits) do tipo “Alo mundo” provida pelo binário ./alo
.
A execução do comando readelf -s ./alo
retorna:
(...)
Tabela de símbolo ".dynsym" contém 7 entradas:
Número: Tamanho do Valor do Tipo de Vínculo Nome Vis Ndx
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
(...)
A saída esperada pela aplicação solução ao exercício será:
_ITM_deregisterTMCloneTable
puts
__libc_start_main
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
Perceba que as 7 entradas da tabela .dynsym são listadas.
A entrada 0
existe, mas não possui string vinculada. Logo, como saída, imprime-se linha vazia.
Para as demais entradas, imprime-se a string vinculada. Observe que não se imprime os caracteres depois do @
.
A entrada é uma chamada de linha de comando para a execução da aplicação, chamada na qual é informado o caminho do binário cujo cabeçalho ELF será analisado.
A saída é a lista dos símbolos constantes na tabela .dynsym do binário apontado na linha de comando da aplicação.
$ ./meu_programa naoexiste.exe
nao disponivel
$ ./meu_programa ./minhalib.so
_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
calcula
imprime
$ ./meu_programa ./alo
_ITM_deregisterTMCloneTable
puts
__libc_start_main
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
$ ./meu_programa ./libpthread.so
__libc_siglongjmp
__tsearch
__clone
free
__getrlimit
abort
unlink
_ITM_deregisterTMCloneTable
_exit
__sched_getscheduler
__libc_dlclose
errno
__libc_fatal
__statfs
__sched_get_priority_max
__mempcpy
__resp
getpid
__sigtimedwait
__mmap
fclose
strlen
__getpid
__stack_chk_fail
__libc_system
getuid
mmap
strchr
__munmap
__assert_fail
memset
__libc_fork
_IO_enable_locks
__write_nocancel
__register_atfork
sched_yield
_dl_deallocate_tls
__call_tls_dtors
__sched_getparam
_setjmp
calloc
__getdelim
__getmntent_r
__fxstat64
__libc_stack_end
strcmp
__twalk_r
__libc_thread_freeres
__endmntent
memcpy
__mprotect
_rtld_global_ro
__clock_gettime
__libc_fcntl64
prctl
__libc_current_sigrtmax_private
__tdelete
__sched_setscheduler
__libc_dlopen_mode
__getpagesize
malloc
__read_nocancel
_dl_make_stack_executable
__isoc99_sscanf
__libc_pthread_init
__ctype_init
realloc
__libc_dlsym
__tfind
munmap
__open64_nocancel
__libc_current_sigrtmin_private
__madvise
__h_errno
fopen
__mktemp
_dl_allocate_tls
__setmntent
__tunable_get_val
sched_setparam
_dl_get_tls_static_info
sprintf
link
exit
getrlimit
_ITM_registerTMCloneTable
__libc_alloca_cutoff
_dl_allocate_tls_init
__close_nocancel
_rtld_global
__libc_allocate_rtsig_private
__libc_longjmp
__cxa_finalize
__sched_get_priority_min
pthread_getattr_np
pthread_condattr_getpshared
pthread_attr_setaffinity_np
pthread_attr_setaffinity_np
pthread_rwlockattr_init
pthread_timedjoin_np
pthread_attr_setguardsize
pthread_rwlock_clockwrlock
pthread_attr_getstackaddr
pthread_condattr_setclock
thrd_join
write
cnd_init
__open64
__errno_location
pthread_sigqueue
__close
pthread_attr_setscope
pthread_barrierattr_setpshared
send
pause
pthread_condattr_setpshared
pthread_rwlock_destroy
sigwait
pthread_barrierattr_destroy
pthread_setaffinity_np
pthread_rwlock_init
pthread_setaffinity_np
mtx_timedlock
pthread_mutex_setprioceiling
tss_set
cnd_destroy
__libc_current_sigrtmin
GLIBC_2.11
pthread_mutex_trylock
pthread_rwlockattr_getpshared
GLIBC_2.12
__lseek
close
fsync
pthread_mutexattr_setpshared
GLIBC_2.18
flockfile
pthread_attr_getguardsize
__pthread_mutexattr_settype
pthread_clockjoin_np
__pthread_unregister_cancel_restore
pthread_attr_getschedpolicy
pthread_yield
accept
pthread_attr_setschedpolicy
__pthread_rwlock_destroy
_pthread_cleanup_pop_restore
pthread_attr_getstack
system
pthread_rwlock_unlock
sem_close
lseek
pthread_spin_destroy
pthread_mutex_destroy
pthread_kill
GLIBC_2.28
cnd_signal
pthread_sigmask
raise
pthread_getspecific
__fork
tss_delete
mtx_unlock
sem_open
pthread_setattr_default_np
sem_destroy
sem_wait
pthread_join
GLIBC_2.30
GLIBC_2.31
__pthread_unregister_cancel
pthread_cond_wait
pthread_cond_wait
pthread_rwlock_clockrdlock
__fcntl
__pthread_barrier_init
__pthread_rwlock_unlock
thrd_exit
__pthread_mutex_destroy
pthread_spin_lock
pthread_condattr_destroy
pthread_create
pthread_barrierattr_getpshared
__pthread_rwlock_trywrlock
open64
pthread_mutexattr_getrobust_np
__libpthread_freeres
pthread_setname_np
cnd_timedwait
pthread_detach
_pthread_cleanup_push
_pthread_cleanup_push_defer
__sigaction
__libpthread_version_placeholder
fcntl
pthread_rwlock_timedrdlock
pthread_mutex_timedlock
_IO_flockfile
pthread_mutexattr_getrobust
mtx_lock
pthread_spin_unlock
pthread_mutexattr_destroy
pthread_mutexattr_getpshared
tss_create
pthread_cond_broadcast
pthread_cond_broadcast
GLIBC_2.2.5
GLIBC_2.2.6
pthread_cond_signal
pthread_cond_signal
__send
pthread_getconcurrency
pthread_rwlock_trywrlock
pthread_setconcurrency
_IO_ftrylockfile
pthread_getcpuclockid
pthread_tryjoin_np
pthread_rwlock_timedwrlock
pthread_spin_trylock
pthread_mutex_lock
__pthread_key_create
tss_get
_pthread_cleanup_pop
ftrylockfile
longjmp
pthread_rwlock_wrlock
pthread_barrier_wait
msync
sem_clockwait
pthread_mutex_consistent
pthread_kill_other_threads_np
pthread_exit
pthread_barrierattr_init
pthread_mutex_unlock
mtx_destroy
recvfrom
GLIBC_2.3.2
pthread_mutexattr_setrobust_np
GLIBC_2.3.3
GLIBC_2.3.4
pthread_getschedparam
__pthread_unwind_next
__pthread_mutex_trylock
sem_timedwait
pthread_attr_setstack
__pthread_setspecific
__pthread_mutex_lock
__pthread_rwlock_tryrdlock
sem_trywait
__pthread_rwlock_wrlock
__pthread_mutexattr_destroy
pthread_mutex_clocklock
siglongjmp
tcdrain
pthread_getname_np
__pthread_get_minstack
pthread_setschedprio
pthread_condattr_init
pread64
GLIBC_PRIVATE
sem_init
__pread64
__pthread_register_cancel_defer
__libc_current_sigrtmax
sem_post
read
pthread_cond_init
pthread_cond_init
open
pthread_setcancelstate
pthread_rwlock_tryrdlock
pthread_mutexattr_getprioceiling
pthread_mutexattr_setprioceiling
pthread_rwlockattr_getkind_np
__pwrite64
pthread_mutexattr_setkind_np
__pthread_mutex_unlock
cnd_wait
pthread_rwlock_rdlock
pthread_condattr_getclock
__res_state
pthread_cancel
sem_unlink
__pthread_once
recvmsg
pthread_rwlockattr_setkind_np
__pthread_rwlock_init
pthread_testcancel
pthread_once
pthread_attr_getscope
__libc_allocate_rtsig
pthread_attr_getaffinity_np
pthread_attr_getaffinity_np
pwrite
cnd_broadcast
mtx_trylock
pthread_spin_init
pthread_barrier_destroy
pthread_mutexattr_gettype
pwrite64
pthread_cond_destroy
pthread_cond_destroy
__pthread_rwlock_rdlock
pthread_getaffinity_np
pthread_getaffinity_np
pthread_mutexattr_getprotocol
pthread_mutex_getprioceiling
recv
pthread_setcanceltype
sem_getvalue
pthread_rwlockattr_destroy
pthread_mutexattr_setprotocol
pthread_barrier_init
pthread_mutex_consistent_np
__h_errno_location
mtx_init
pthread_getattr_default_np
__pthread_register_cancel
__pthread_getspecific
sendto
__pthread_initialize_minimal
funlockfile
lseek64
pthread_key_delete
sigaction
pthread_rwlockattr_setpshared
pthread_mutex_init
pthread_attr_setstacksize
pthread_mutexattr_init
pthread_cond_clockwait
__pthread_unwind
pthread_mutexattr_getkind_np
fork
pthread_atfork
thrd_create
pthread_setschedparam
__pthread_barrier_wait
__pthread_cleanup_routine
pread
pthread_attr_setstackaddr
pthread_setspecific
_IO_funlockfile
thrd_detach
connect
__connect
__read
__shm_directory
sendmsg
__open
pthread_mutexattr_settype
GLIBC_2.4
pthread_cond_timedwait
pthread_cond_timedwait
__write
__pthread_mutexattr_init
pthread_attr_getstacksize
call_once
pthread_mutexattr_setrobust
__pthread_mutex_init
pthread_key_create