I have implemented packer of x86_64 shared library. Briefly, a loader is injected to a shared library, and the rela.dyn entry is modified such that it points to the address of the loader. Once the loader is triggered, it decrypts the .text section and finally jump to the address of the .text section.
The mechanism works fine for x86_64 shared library. But it failed on aarch64 shared library.
Questions:
- Did I miss any steps that specifically for the aarch64 ?
- Is there any other ways to pack an aarch64 shared library ?
The result of readelf
is provided bellow.
libtest.so
is the library before packing.
While libtest_packed.so
is the library after packing.
here is the result of readelf --relocs libtest.so
Relocation section '.rela.dyn' at offset 0x550 contains 7 entries:
000000010df0 000000000403 R_AARCH64_RELATIV 780
000000010df8 000000000403 R_AARCH64_RELATIV 738
000000011018 000000000403 R_AARCH64_RELATIV 11018
000000010fc8 000300000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTMClone + 0
000000010fd0 000400000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
000000010fd8 000500000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
000000010fe0 000700000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCloneTa + 0
the functions corresponding to the first 3 entries are:
0000000000000780 t frame_dummy
0000000000000738 t __do_global_dtors_aux
000000000011018 d __dso_handle
here is the result of readelf --relocs libtest_packed.so
Relocation section '.rela.dyn' at offset 0x550 contains 7 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000010df0 000000000403 R_AARCH64_RELATIV 11028
000000010df8 000000000403 R_AARCH64_RELATIV 738
000000011018 000000000403 R_AARCH64_RELATIV 11018
000000010fc8 000300000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTMClone + 0
000000010fd0 000400000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
000000010fd8 000500000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
000000010fe0 000700000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCloneTa + 0
As you can see, the first entry is overwritten by the address of the loader.
------------ Update ---------
- if I xor-ed the .text section, the xor-loader is bypassed
- I got Illegal instruction (core dumped), since the .text section has not been decrypted by the xor-loader. (confirmed by inspecting the .text section by gdb)
- I have the loader objdump-ed, the loader is intact.
- if I don't xor the .text section, the xor-loader is called and work normally. (But the decryption is wrong, since the .text section has not been xor-ed beforehand).
Since shared library don't have an entry point. I overwrite the frame_dummy pointer such that the program can jump to the .text section, base on this project
https://github.com/0xN3utr0n/Noteme/blob/master/injection.c
The mechanism of my loader is inspired by https://github.com/sebastiencs/Packer_ELF