2015-07-15 11 views
3

Мой код хорошо работает с malloc, но не с mmap. Код ниже:LD_PRELOAD не может перехватывать syscalls, но только libcalls?

main.c

#include <stdio.h> 
#include <stdlib.h> 

int main(){ 
    int * p = (int*) malloc(sizeof(int)); 
    printf("in main(): value p = %d\n", *p); 
    free(p); 
} 

preload.c

#define _GNU_SOURCE 
#include <time.h> 
#include <dlfcn.h> 
#include <stdio.h> 
#include <sys/types.h> 

void *(*orig_malloc)(size_t size); 
void *malloc(size_t size){ 
    printf(" Hooked(preload)! malloc:size:%lu\n", size); 
    return orig_malloc(size); 
} 

void * (*orig_mmap)(void *start, size_t length, int prot, int flags, int fd, off_t offset); 
void * mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset){ 
    printf(" Hooked(preload)! mmap:start:%p, length:%lu, prot:%d, flags:%p, fd:%p, offset:%d\n", start, length, prot, flags, fd, offset); 
    return orig_mmap(start, length, prot, flags, fd, offset); 
} 

void 
_init(void) 
{ 
    printf("Loading hack.\n"); 
    orig_malloc = (void* (*)(size_t)) dlsym(RTLD_NEXT, "malloc"); 
    orig_mmap = (void* (*)(void*, size_t, int, int, int, off_t)) dlsym(RTLD_NEXT, "mmap"); 
} 

скомпилировать его

gcc -Wall -fPIC -DPIC -c preload.c 
ld -shared -o preload.so preload.o -ldl 
gcc main.c 

, чтобы запустить его с LD_PRELOAD

LD_PRELOAD=./preload.so ./a.out 

запустить его трассированием

strace ./a.out 2>&1 | view - 

распечатку из LD_PRELOAD не перехватывает вызовы mmap, но только звонки malloc. Между тем, при работе с strace, распечатка действительно показывает, что mmap вызывается несколько раз.

Этот результат меня озадачивает; предполагая, что mmap действительно вызван main.c (я догадываюсь через malloc), почему preload.c не может перехватить mmap?

PS: Моя платформа Ubuntu 14.04 с ядром Linux 3,13

PS2: К системному вызову, я имею в виду системный вызова обертку в LIBC (не уверен, если это имеет значение для вопроса, хотя) ..

ответ

4

mmap - это syscall, malloc - нет.

Поскольку системные вызовы необходимы для функционирования программы, они должны работать до того, как ld.so фактически начнет действовать, они находятся в секции, которая загружается перед всем остальным; он может быть связан динамически, но это сопоставление (этого конкретного «виртуального» динамического объекта) выполняется самим ядром. Looong до ld.so фактически начинает работать.

+0

Я означает, что syscall действительно syscall-оболочка в libc .. в этом смысле, может быть 'LD_PRELOAD' захват syscall wr apper? (Я полагаю, что оболочка syscall вызывается после ld.so) – Richard

+1

@ Richard: Нет, оболочка syscall в libc очень рано связана с PLT-заглушкой. Так рано, что LD_PRELOAD не в состоянии вступить в силу. – datenwolf

+1

@ Richard: см. Эту статью о том, как работает вся PLT/GOT: https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic- libraries.html – datenwolf

3

Название на ваш вопрос на самом деле является ответом.

предполагая, что ММАП действительно называют main.c (я предполагаю, что через таНос)

Так что ваш main.c не вызывает функцию библиотекаmmap()? Конечно, вы не можете перехватить syscalls таким образом, как бы вы это сделали? Некоторые архитектуры имеют инструкцию CPU syscall, некоторые используют специальное прерывание ... Есть много способов, но это в любом случае совершенно отличается от конвенций C-вызова. Ядро не является каким-то образом связанным с вашим двоичным кодом, но получает контроль (с некоторой аппаратной ассистенткой), когда ваш процесс пользовательского процесса что-то делает ... «специальный».

Если вы хотите знать, как перехватывать системные вызовы, это, конечно, очень специфично для платформы, но я бы посоветовал вам просто взглянуть на источник утилиты strace. Вы никогда не увидите malloc() в strace, потому что это не syscall, malloc() использует системный вызов mmap.

С другой стороны, если вы предварительно загрузите свою библиотеку в бинарный файл, который фактически вызывает функцию libc mmap(), она будет работать должным образом.

В двух словах: Libc mmap() является удобной оберткой mmap и системного вызова следующие основные:

#include <sys/mman.h> 

int main() 
{ 
    void *test = mmap(0, 20, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 
     -1, 0); 
    return 0; 
} 

Результат:

Загрузка хак.
Зацепленный (предварительная загрузка)! ММАП: старт: (ноль), длина: 20, Prot: 3, флаги: 0x22,
ФД: 0xffffffff, смещение: 0

+0

Я ориентируюсь только на 'x86_64'; кажется, используется схема команд 'syscall'. интересно, если перехват syscall можно сделать, просто подключив все инструкции syscall в двоичном коде ... – Richard

+0

Я так не думаю ... 'syscall' - это, с одной стороны, инструкция CPU (вы не можете подключить эти), а с другой стороны - минимальная оболочка в 'glibc', позволяющая программам вызывать любой syscall с использованием соглашений вызова C. Последний можно подключить с помощью LD_PRELOAD. –

+0

Я считаю, что это выполнимо методом двоичной перезаписи, хотя – Richard

4

В mmap вызовов, напечатанные strace являются Glibc-внутренним. Это невозможно перехватить GLibC-внутренние вызовы mmap с LD_PRELOAD:

mmap не в .plt -сечением /lib64/libc.so.6 но вызывается непосредственно из Glibc и поэтому LD_PRELOAD не может перехватывать вызовы GLibC к mmap.

$ objdump -j .plt -d /lib64/libc.so.6 

/lib64/libc.so.6:  file format elf64-x86-64 


Disassembly of section .plt: 

000000000001f400 <*ABS*[email protected]>: 
    1f400: ff 35 02 ac 39 00  pushq 0x39ac02(%rip)  # 3ba008 <_GLOBAL_OFFSET_TABLE_+0x8> 
    1f406: ff 25 04 ac 39 00  jmpq *0x39ac04(%rip)  # 3ba010 <_GLOBAL_OFFSET_TABLE_+0x10> 
    1f40c: 0f 1f 40 00    nopl 0x0(%rax) 

000000000001f410 <*ABS*[email protected]>: 
    1f410: ff 25 02 ac 39 00  jmpq *0x39ac02(%rip)  # 3ba018 <_GLOBAL_OFFSET_TABLE_+0x18> 
    1f416: 68 0b 00 00 00   pushq $0xb 
    1f41b: e9 e0 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f420 <*ABS*[email protected]>: 
    1f420: ff 25 fa ab 39 00  jmpq *0x39abfa(%rip)  # 3ba020 <_GLOBAL_OFFSET_TABLE_+0x20> 
    1f426: 68 0a 00 00 00   pushq $0xa 
    1f42b: e9 d0 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f430 <[email protected]>: 
    1f430: ff 25 f2 ab 39 00  jmpq *0x39abf2(%rip)  # 3ba028 <_GLOBAL_OFFSET_TABLE_+0x28> 
    1f436: 68 00 00 00 00   pushq $0x0 
    1f43b: e9 c0 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f440 <[email protected]>: 
    1f440: ff 25 ea ab 39 00  jmpq *0x39abea(%rip)  # 3ba030 <_GLOBAL_OFFSET_TABLE_+0x30> 
    1f446: 68 01 00 00 00   pushq $0x1 
    1f44b: e9 b0 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f450 <[email protected]>: 
    1f450: ff 25 e2 ab 39 00  jmpq *0x39abe2(%rip)  # 3ba038 <_GLOBAL_OFFSET_TABLE_+0x38> 
    1f456: 68 02 00 00 00   pushq $0x2 
    1f45b: e9 a0 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f460 <[email protected]>: 
    1f460: ff 25 da ab 39 00  jmpq *0x39abda(%rip)  # 3ba040 <_GLOBAL_OFFSET_TABLE_+0x40> 
    1f466: 68 03 00 00 00   pushq $0x3 
    1f46b: e9 90 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f470 <*ABS*[email protected]>: 
    1f470: ff 25 d2 ab 39 00  jmpq *0x39abd2(%rip)  # 3ba048 <_GLOBAL_OFFSET_TABLE_+0x48> 
    1f476: 68 09 00 00 00   pushq $0x9 
    1f47b: e9 80 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f480 <[email protected]>: 
    1f480: ff 25 ca ab 39 00  jmpq *0x39abca(%rip)  # 3ba050 <_GLOBAL_OFFSET_TABLE_+0x50> 
    1f486: 68 04 00 00 00   pushq $0x4 
    1f48b: e9 70 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f490 <[email protected]>: 
    1f490: ff 25 c2 ab 39 00  jmpq *0x39abc2(%rip)  # 3ba058 <_GLOBAL_OFFSET_TABLE_+0x58> 
    1f496: 68 05 00 00 00   pushq $0x5 
    1f49b: e9 60 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f4a0 <[email protected]>: 
    1f4a0: ff 25 ba ab 39 00  jmpq *0x39abba(%rip)  # 3ba060 <_GLOBAL_OFFSET_TABLE_+0x60> 
    1f4a6: 68 06 00 00 00   pushq $0x6 
    1f4ab: e9 50 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f4b0 <*ABS*[email protected]>: 
    1f4b0: ff 25 b2 ab 39 00  jmpq *0x39abb2(%rip)  # 3ba068 <_GLOBAL_OFFSET_TABLE_+0x68> 
    1f4b6: 68 08 00 00 00   pushq $0x8 
    1f4bb: e9 40 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 

000000000001f4c0 <*ABS*[email protected]>: 
    1f4c0: ff 25 aa ab 39 00  jmpq *0x39abaa(%rip)  # 3ba070 <_GLOBAL_OFFSET_TABLE_+0x70> 
    1f4c6: 68 07 00 00 00   pushq $0x7 
    1f4cb: e9 30 ff ff ff   jmpq 1f400 <data.8467+0x1f390> 
[[email protected] ~]$ 

призывает к mmap в Glibc не называют это через .plt запись, но напрямую, это невозможно перехватить эти вызовы:

$ objdump -d /lib64/libc.so.6 | grep mmap 
[...] 
    81628: e8 83 ad 07 00   callq fc3b0 <mmap> 
    8177c: e8 2f ac 07 00   callq fc3b0 <mmap> 
00000000000fc3b0 <mmap>: 
    fc3c0: 73 01     jae fc3c3 <mmap+0x13> 
    13a267: e8 44 21 fc ff   callq fc3b0 <mmap> 
$ 

00000000000fc3b0 <mmap>: 
    fc3b0: 49 89 ca    mov %rcx,%r10 
    fc3b3: b8 09 00 00 00   mov $0x9,%eax 
    fc3b8: 0f 05     syscall 
    fc3ba: 48 3d 01 f0 ff ff  cmp $0xfffffffffffff001,%rax 
    fc3c0: 73 01     jae fc3c3 <mmap+0x13> 
    fc3c2: c3      retq 
    fc3c3: 48 8b 0d 96 da 2b 00 mov 0x2bda96(%rip),%rcx  # 3b9e60 <_DYNAMIC+0x2e0> 
    fc3ca: f7 d8     neg %eax 
    fc3cc: 64 89 01    mov %eax,%fs:(%rcx) 
    fc3cf: 48 83 c8 ff    or  $0xffffffffffffffff,%rax 
    fc3d3: c3      retq 
    fc3d4: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 
    fc3db: 00 00 00 
    fc3de: 66 90     xchg %ax,%ax 
+0

Извините, но уверен, что libc 'mmap()' можно подключить таким образом! Просто используйте код OP и крошечную тестовую программу, вызывающую 'mmap()' ... результат здесь: «Hooked (preload)! Mmap: start: (nil), length: 20, prot: 3, flags: 0x22, fd : 0xffffffff, offset: 0 " –

+0

Да, но не вызовы glibc к его' mmap' @FelixPalmen – 4566976

+0

так что это определяет lib? Это определенно перехвачено, и трюк «LD_PRELOAD» может перехватывать вызовы в библиотеки, связанные с помощью 'ld.so' [** edit ** Я думаю, вы ссылаетесь на внутренние вызовы библиотеки ... правильно?] –