首先弄清楚如何加载一个共享库?libdl提供了dlopen(),dlsymb(),dlclose().
objdump --dynamic-syms /lib/libc.so.6 | \
grep _dl_ | egrep "open|close|sym"
000f7d10 g DF .text 000001ad GLIBC_2.2 _dl_vsym
000f6f10 g DF .text 000006b8 GLIBC_2.0 _dl_close
000f6d80 g DF .text 00000190 GLIBC_2.0 _dl_open
000f7c00 g DF .text 0000010d GLIBC_2.2 _dl_sym
可以看到共享库lib.so.6有_dl_open, _dl_sym,和_dl_close。
来看看他们的原型
extern void *dlopen (const char *file, int mode);
extern void *dlsym (void *handle, const char *name)
extern int dlclose (void *handle)
而这些是
void *_dl_open (const char *file, int mode, const void *caller)
void *_dl_sym (void *handle, const char *name, void *who)
void _dl_close (void *_map)
000f6d80 <.text+0xdde00> (_dl_open):
f6d80: 55 push %ebp
f6d81: 89 e5 mov %esp,%ebp
f6d83: 83 ec 2c sub $0x2c,%esp
f6d86: 57 push %edi
f6d87: 56 push %esi
f6d88: 53 push %ebx
f6d89: e8 00 00 00 00 call 0xf6d8e
f6d8e: 5b pop %ebx
f6d8f: 81 c3 ba 10 02 00 add $0x210ba,%ebx
f6d95: 89 c7 mov %eax,%edi
f6d97: 89 d6 mov %edx,%esi
f6d99: 89 4d e4 mov %ecx,0xffffffe4(%ebp)
f6d9c: f7 c6 03 00 00 00 test $0x3,%esi
f6da2: 75 1c jne 0xf6dc0
f6da4: 83 c4 f4 add $0xfffffff4,%esp
void *
internal_function
_dl_open (const char *file, int mode, const void *caller)
{
struct dl_open_args args;
const char *objname;
const char *errstring;
int errcode;
if ((mode & RTLD_BINDING_MASK) == 0)
/* One of the flags must be set. */
_dl_signal_error (EINVAL, file, NULL,
N_("invalid mode for dlopen()"));
....
}
其中eax = library name共享库名 (例如: /lib/libc.so.6)
ecx = caller调用者 (例如: ./example)
edx = mode模式 (例如:RTLD_NOW | 0x80000000)
那么我们可以写下如下代码:
nop
nop
nop
nop
nop
nop
call *%edi # 调用_dl_open
int $0x3 # 断点
nop
其它的期望参数是:
_dl_sym:
eax = library handle被_dl_open打开的库句柄
edx = symbol name符号名(例如:pthread_create)
_dl_close:
eax = library hanlde被_dl_open打开的库句柄