Leder efter LD_PRELOAD

Denne note blev skrevet i 2014, men jeg er lige blevet undertrykt af Habré, og den så ikke dagens lys. Under forbuddet glemte jeg det, men nu fandt jeg det i udkastene. Jeg overvejede at slette det, men måske vil det være nyttigt for nogen.

Leder efter LD_PRELOAD

Generelt lidt fredagsadministratorlæsning om emnet at søge efter "inkluderet" LD_PRELOAD.

1. En kort digression for dem, der ikke er fortrolige med funktionssubstitution

Resten kan gå direkte til punkt 2.

Lad os starte med et klassisk eksempel:

#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 kompilerer uden nogen flag:

$ gcc ./ld_rand.c -o ld_rand

Og som forventet får vi 5 tilfældige tal mindre end 100:

$ ./ld_rand
53
93
48
57
20

Men lad os forestille os, at vi ikke har kildekoden til programmet, men vi skal ændre adfærden.

Lad os skabe vores eget bibliotek med vores egen funktionsprototype, for eksempel:

int rand(){
  return 42;
}

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

Og nu er vores tilfældige valg ret forudsigeligt:

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

Dette trick ser endnu mere imponerende ud, hvis vi først eksporterer vores bibliotek via

$ export LD_PRELOAD=$PWD/ld_rand.so

eller vi gør det først

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

og kør derefter programmet som normalt. Vi har ikke ændret en eneste kodelinje i selve programmet, men dets adfærd afhænger nu af en lillebitte funktion i vores bibliotek. Desuden, på tidspunktet for skrivning af programmet rand fandtes ikke engang.

Hvad fik vores program til at bruge en falsk rand? Lad os tage det skridt for skridt.
Når en applikation starter, indlæses visse biblioteker, der indeholder de funktioner, som programmet har brug for. Vi kan se dem vha 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)

Denne liste kan variere afhængigt af OS-versionen, men der skal være en fil der libc.so. Det er dette bibliotek, der leverer systemkald og basale funktioner som f.eks åbent, malloc, printf osv. Vores rand er også blandt dem. Lad os sikre os dette:

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

Lad os se, om sættet af biblioteker ændres, når det bruges 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 viser sig, at variablen er indstillet LD_PRELOAD tvinger os til at lade ld_rand.so også på trods af, at selve programmet ikke kræver det. Og siden vores funktion "rand" læsser tidligere end rand fra libc.so, så bestemmer hun.

Ok, det lykkedes os at erstatte den oprindelige funktion, men hvordan kan vi sikre, at dens funktionalitet bevares og nogle handlinger tilføjes. Lad os ændre vores tilfældige:

#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();
}

Her udskriver vi som vores “tilføjelse” kun én tekstlinje, hvorefter vi laver en pointer til den oprindelige funktion rand. For at få adressen på denne funktion har vi brug for dlsym er en funktion fra biblioteket libdlsom vil finde vores rand i en stak dynamiske biblioteker. Hvorefter vi kalder denne funktion og returnerer dens værdi. Derfor bliver vi nødt til at tilføje "-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

Og vores program bruger "native" rand, efter at have udført nogle obskøne handlinger.

2. Smerten ved at søge

Når vi kender til en potentiel trussel, ønsker vi at opdage det preload Det blev udført. Det er klart, at den bedste måde at detektere på er at skubbe det ind i kernen, men jeg var interesseret i detekteringsmulighederne i brugerområdet.

Dernæst vil løsninger til detektion og deres gendrivelse komme i par.

2.1. Lad os starte enkelt

Som tidligere nævnt kan du angive det bibliotek, der skal indlæses ved hjælp af variablen LD_PRELOAD eller ved at skrive det i en fil /etc/ld.so.preload. Lad os skabe to simple detektorer.

Den første er at kontrollere den indstillede miljøvariabel:

#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 anden er at kontrollere, om filen er åbnet:

#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");
}

Lad os indlæse bibliotekerne:

$ 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) [+]

Her og nedenfor indikerer [+] vellykket detektion.
Følgelig betyder [-] omgåelse af detektion.

Hvor effektiv er sådan en detektor? Lad os først tage et kig på miljøvariablen:

#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) [-]

På samme måde slipper vi for checken åbent:

#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) [-]

Ja, andre måder at få adgang til filen kan bruges her, som f.eks. open64, stat osv., men faktisk er de samme 5-10 linjer kode nødvendige for at bedrage dem.

2.2. Lad os gå videre

Ovenfor brugte vi getenv() for at få værdien LD_PRELOAD, men der er også en mere "low-level" måde at komme til ENV-variabler. Vi vil ikke bruge mellemfunktioner, men vil referere til arrayet **miljø, som gemmer en kopi af miljøet:

#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;
}

Da vi her læser data direkte fra hukommelsen, kan et sådant opkald ikke opsnappes, og vores undetect_getenv det forstyrrer ikke længere at identificere indtrængen.

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

Det ser ud til, at dette problem er løst? Det er stadig lige begyndt.

Efter programmet er startet, værdien af ​​variablen LD_PRELOAD hackere har ikke længere brug for det i hukommelsen, det vil sige, de kan læse det og slette det, før de udfører nogen instruktioner. Selvfølgelig er redigering af et array i hukommelsen som minimum en dårlig programmeringsstil, men hvordan kan dette stoppe nogen, der ikke rigtig ønsker os det bedste alligevel?

For at gøre dette skal vi oprette vores egen falske funktion i det(), hvor vi opsnapper de installerede LD_PRELOAD og send det til vores linker:

#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 udfører og kontrollerer:

$ 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/selv/

Hukommelsen er dog ikke det sidste sted, hvor du kan finde en erstatning LD_PRELOAD, der er også / proc /. Lad os starte med det åbenlyse /proc/{PID}/environ.

Faktisk er der en universel løsning til uopdaget **miljø и /proc/self/environ. Problemet er den "forkerte" adfærd unsetenv(env).

korrekte mulighed

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 lad os forestille os, at vi ikke fandt det og /proc/self/environ indeholder "problematiske" data.

Lad os først prøve med vores tidligere "udklædning":

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

hvordan bruger det samme til at åbne filen åben(), så løsningen ligner det, der allerede blev gjort i afsnit 2.1, men nu opretter vi en midlertidig fil, hvor vi kopierer værdierne af den sande hukommelse uden linjer, der indeholder 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);
}

Og denne fase er bestået:

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

Det næste oplagte sted er /proc/self/maps. Det nytter ikke at dvæle ved det. Løsningen er helt identisk med den forrige: Kopier dataene fra filen minus linjerne imellem libc.so и ld.så.

2.4. Mulighed fra Chokepoint

Jeg kunne især godt lide denne løsning for dens enkelhed. Vi sammenligner adresserne på funktioner indlæst direkte fra libc, og "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;
}

Indlæser biblioteket med aflytning "åben()" og tjek:

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

Afvisningen viste sig at være endnu enklere:

#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 ser ud til, at dette er alt, men vi vil stadig skrubbe. Hvis vi dirigerer systemkaldet direkte til kernen, vil dette omgå hele aflytningsprocessen. Nedenstående løsning er naturligvis arkitekturafhængig (x86_64). Lad os prøve at implementere det for at opdage en åbning 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) [+]

Og dette problem har en løsning. Uddrag fra mand'EN:

ptrace er et værktøj, der gør det muligt for en overordnet proces at observere og kontrollere forløbet af en anden proces, se og ændre dens data og registre. Typisk bruges denne funktion til at oprette brudpunkter i et fejlretningsprogram og overvåge systemkald.

Den overordnede proces kan begynde at spore ved først at kalde fork(2), og derefter kan den resulterende underordnede proces udføre PTRACE_TRACEME, efterfulgt (normalt) af at udføre exec(3). På den anden side kan en overordnet proces begynde at fejlfinde en eksisterende proces ved hjælp af PTRACE_ATTACH.

Ved sporing stopper den underordnede proces, hver gang den modtager et signal, selvom signalet ignoreres. (Undtagelsen er SIGKILL, som fungerer normalt.) Forældreprocessen vil få besked om dette ved at kalde wait(2), hvorefter den kan se og ændre indholdet af den underordnede proces, før den starter. Forældreprocessen giver så barnet mulighed for at fortsætte med at løbe, i nogle tilfælde ignorerer det signalet, der sendes til det, eller sender et andet signal i stedet).

Løsningen er således at overvåge processen, stoppe den før hvert systemkald og om nødvendigt omdirigere tråden til en krogfunktion.

#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 tjekker:

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

+0-0=5

Mange tak

Charles Hubain
kvælningspunkt
ValdikSS
Philippe Teuwen
derhass

, hvis artikler, kilder og kommentarer gjorde meget mere end jeg gjorde for at få denne note til at blive vist her.

Kilde: www.habr.com

Tilføj en kommentar