Section设置

版本0.2.0之后,micro采用ELF/PE/Mach-O文件的section/segment来获取信息,不再采用多次构建。

Section模式支持配置limit,UPX压缩(ELF下需要修改二进制),数字签名,允许构建后修改二进制

文件结构

| ELF/PE/Mach-O Executable | INI settings | PHP or PHAR payload | Other data |

limit配置

如果未设置以下的sfxsize section:

  • micro_get_sfxsize_limit返回0,所有size之后的数据均为payload
  • micro_get_sfxsize返回
    • ELF为最后一个Section的结尾,如果没有Section表,返回最后一个Program Header Segment的结尾
    • Mach-O为__LINKEDIT的结尾
    • Windows下为最后一个Section的结尾

sfxsize section

sfxsize section的格式为:

typedef struct _micro_sfxsize_section_t {
    uint64_t size; /* sfx大小,大端序 */
    uint64_t limit; /* limit大小,大端序 */
} __attribute__((pacaked)) micro_sfxsize_section_t;

size表示可执行文件二进制大小,单位bytes,大端序

limit表示sfx二进制+payload大小,单位bytes,大端序

limit为0时,表示不限制大小,所有size之后的数据均为payload

ELF

对于使用ELF作为可执行文件格式的系统,例如Linux,FreeBSD:

micro通过.sh_name.sfxsize的Section获取上面的结构体

Mach-O

对于macOS的Mach-O:

micro通过__DATA Segment的__micro_sfxsize Section获取上面的结构体

PE

对于Windows的PE:

micro通过ID为PHP_MICRO_SFXSIZE_ID12345RC_DATA获取上面的结构体

UPX压缩

Windows下可以直接进行UPX压缩

ELF下由于UPX将section表丢掉了,无法获取UPX后的真实结尾位置,所以需要修改二进制:

sfx压缩后,将最后一个Program Header Segment后的数据删除,这么做后UPX无法解压,会让你的程序看起来很像病毒。

操作参考:先获取Program Header Segment

readelf -l micro.sfx.upxed

输出类似:

...
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000001000 0x0000000001cb6f88  RW     0x1000
  LOAD           0x0000000000000000 0x0000000001cb7000 0x0000000001cb7000
                 0x000000000065aadb 0x000000000065aadb  R E    0x1000
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
...

将文件截断到最大的Offset+FileSiz(0x0000000000000000 + 0x000000000065aadb = 6662875)即可

dd if=micro.sfx.upxed of=micro.sfx.upxed.stripped bs=6662875 count=1
chmod 0755 micro.sfx.upxed.stripped

数字签名

TODO:做一个工具方便签名

Windows

Windows下的数字签名是修改部分PE/COFF头内容(不改变大小),然后在文件结尾添加一段数据,因此参考的步骤是:

  1. 对sfx进行想要的修改,比如换个喜欢的logo啥的,可以使用Resource Hacker
  2. 在sfx里添加ID为PHP_MICRO_SIGNATURE_ID12346RC_DATA,大小为16bytes,记录这个时候sfx的大小
  3. 将2中section的数据改为真实数据(.size = sfx大小, .limit = sfx大小+payload大小,不含之后的padding),参考上面的sfxsize section
  4. 将文件补0对齐到4096(好像512就够,但我用4096)
  5. 将最后一个section的结尾设为文件结尾
  6. 进行签名

Mach-O

Mach-O签名是添加了一个segment/section,因此需要这么操作:

  1. 将sfx和payload拼接
  2. 补0对齐到4096
  3. 将__LINKEDIT的结尾设为文件结尾
  4. 进行签名