Build executable so (shared object) on Android

0x00 背景

0x01 方法

用以下Android.mkmain.c编译即可。编译出的libmain.so既可以当作动态库来链接,也可当作可执行文件执行。需要注意的是,如果是使用cpp后缀,__attribute__((section(".interp")))将不起作用。包含__attribute__((section(".interp")))的源码只能使用.c后缀

//Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := main

LOCAL_CFLAGS += -fPIC -pie
LOCAL_LDFLAGS += -Wl,-e,entry -llog

LOCAL_MODULE    := main
LOCAL_SRC_FILES := main.c

include $(BUILD_SHARED_LIBRARY)

//main.c
#include <stdlib.h>
#include <stdio.h>
#include <android/log.h>


#define  LOG_TAG    "MY_LOG"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

const char interp_section[] __attribute__((section(".interp"))) = "/system/bin/linker";

void entry()
{
    printf("hello\n");
    LOGD("hell0, main\n");
    exit(0);
}

编译出libmain.so后我们来看一下:

$ file ../libs/armeabi-v7a/libmain.so 
../libs/armeabi-v7a/libmain.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, BuildID[sha1]=3d99b878a4db700cde253a277d23ac9c1d92aa23, stripped

interpreter有了。

$ arm-linux-androideabi-readelf -l ../libs/armeabi-v7a/libmain.so 

Elf file type is DYN (Shared object file)
Entry point 0xfb5
There are 9 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x00120 0x00120 R   0x4
  INTERP         0x00263c 0x0000263c 0x0000263c 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /system/bin/linker]
  LOAD           0x000000 0x00000000 0x00000000 0x0264f 0x0264f R E 0x1000
  LOAD           0x002e34 0x00003e34 0x00003e34 0x001d0 0x001d0 RW  0x1000
  DYNAMIC        0x002e40 0x00003e40 0x00003e40 0x00120 0x00120 RW  0x4
  NOTE           0x000154 0x00000154 0x00000154 0x000bc 0x000bc R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  EXIDX          0x00253c 0x0000253c 0x0000253c 0x00100 0x00100 R   0x4
  GNU_RELRO      0x002e34 0x00003e34 0x00003e34 0x001cc 0x001cc RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .note.android.ident .note.gnu.build-id .dynsym .dynstr .hash .gnu.version .gnu.version_d .gnu.version_r .rel.dyn .rel.plt .plt .text .ARM.extab .ARM.exidx .interp 
   03     .fini_array .init_array .dynamic .got .data 
   04     .dynamic 
   05     .note.android.ident .note.gnu.build-id 
   06     
   07     .ARM.exidx 
   08     .fini_array .init_array .dynamic .got 

Entry point有了: 0xfb5 (0xfb4)。

$ arm-linux-androideabi-objdump -d ../libs/armeabi-v7a/libmain.so | grep fb4 -A20
00000fb4 <entry@@Base>:
     fb4:   b580        push    {r7, lr}
     fb6:   466f        mov r7, sp
     fb8:   a005        add r0, pc, #20 ; (adr r0, fd0 <entry@@Base+0x1c>)
     fba:   f7ff ef36   blx e28 <puts@plt>
     fbe:   a106        add r1, pc, #24 ; (adr r1, fd8 <entry@@Base+0x24>)
     fc0:   a207        add r2, pc, #28 ; (adr r2, fe0 <entry@@Base+0x2c>)
     fc2:   2003        movs    r0, #3
     fc4:   f7ff ef36   blx e34 <__android_log_print@plt>
     fc8:   2000        movs    r0, #0
     fca:   f7ff ef3a   blx e40 <exit@plt>
     fce:   bf00        nop
     ...

看一下Entry point,确实是我们写的entry函数。