Friday, October 20, 2023

UPX Linux .so: "CantPackException: bad e_shoff"

 I was trying to compress a .so file I had built from Go, but UPX threw an error:

upx --ultra-brute --lzma libname.so
upx: libname.so: CantPackException: bad e_shoff

After compression, the file could no longer be read by the following nm command, which lists exposed functions in the given library:

nm -D libname.so | grep my_function_name
nm: libname.so: file format not recognized

There's an issue on the Github issue tracker for UPX from 2021 that appears to not be solved, which clarifies the problem:
https://github.com/upx/upx/issues/506#issuecomment-1168570219

This style of layout of the address space in the shared library, having 4 [PT_]LOAD segments [...] requires that the upx runtime de-compression stub be significantly enhanced from the upx stub that handles shared libraries with only 2 PT_LOAD segments (one R E and one RW). Upgrading the upx stub has been in progress for a while, and the code is getting close, but is not yet complete.

Running the command suggested in that thread confirms that my .so file also contains 4 LOAD segments, alongside the other program headers:

readelf --segments libname.so  

Elf file type is DYN (Shared object file)
Entry point 0x0
There are 10 program headers, starting at offset 64

Program Headers:
 Type           Offset             VirtAddr           PhysAddr
                FileSiz            MemSiz              Flags  Align
 LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                0x0000000000042f98 0x0000000000042f98  R      0x1000
 LOAD           0x0000000000043000 0x0000000000043000 0x0000000000043000
                0x000000000012faa9 0x000000000012faa9  R E    0x1000
 LOAD           0x0000000000173000 0x0000000000173000 0x0000000000173000
                0x00000000002ec30c 0x00000000002ec30c  R      0x1000
 LOAD           0x0000000000460208 0x0000000000461208 0x0000000000461208
                0x000000000014ee74 0x0000000000182988  RW     0x1000
 DYNAMIC        0x0000000000560dc8 0x0000000000561dc8 0x0000000000561dc8
                0x00000000000001f0 0x00000000000001f0  RW     0x8
 NOTE           0x0000000000000270 0x0000000000000270 0x0000000000000270
                0x0000000000000088 0x0000000000000088  R      0x4
 TLS            0x0000000000460208 0x0000000000461208 0x0000000000461208
                0x0000000000000000 0x0000000000000008  R      0x8
 GNU_EH_FRAME   0x000000000045e8d0 0x000000000045e8d0 0x000000000045e8d0
                0x00000000000001ac 0x00000000000001ac  R      0x4
 GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                0x0000000000000000 0x0000000000000000  RW     0x10
 GNU_RELRO      0x0000000000460208 0x0000000000461208 0x0000000000461208
                0x0000000000100df8 0x0000000000100df8  R      0x1


The only solution is to wait for UPX maintainers to address this.

No comments: