Ser etter LD_PRELOAD

Dette notatet ble skrevet i 2014, men jeg kom akkurat under undertrykkelse av Habré og det så ikke dagens lys. Under forbudet glemte jeg det, men nå fant jeg det i utkastene. Jeg tenkte å slette det, men kanskje det vil være nyttig for noen.

Ser etter LD_PRELOAD

Generelt, litt fredagsadministratorlesing om emnet å søke etter "inkludert" LD_PRELOAD.

1. En kort digresjon for de som ikke er kjent med funksjonssubstitusjon

Resten kan gå rett til s.2.

La oss 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 uten noen flagg:

$ gcc ./ld_rand.c -o ld_rand

Og som forventet får vi 5 tilfeldige tall mindre enn 100:

$ ./ld_rand
53
93
48
57
20

Men la oss forestille oss at vi ikke har kildekoden til programmet, men vi må endre atferden.

La oss lage vårt eget bibliotek med vår egen funksjonsprototype, for eksempel:

int rand(){
  return 42;
}

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

Og nå er vårt tilfeldige valg ganske forutsigbart:

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

Dette trikset ser enda mer imponerende ut hvis vi først eksporterer biblioteket vårt via

$ export LD_PRELOAD=$PWD/ld_rand.so

eller så gjør vi det først

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

og kjør deretter programmet som vanlig. Vi har ikke endret en eneste kodelinje i selve programmet, men oppførselen avhenger nå av en liten funksjon i biblioteket vårt. Dessuten, på tidspunktet for skriving av programmet, alle fantes ikke engang.

Hva gjorde at programmet vårt brukte en falsk alle? La oss ta det steg for steg.
Når en applikasjon starter, lastes visse biblioteker som inneholder funksjonene som programmet trenger. Vi kan se dem ved hjelp av 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 listen kan variere avhengig av OS-versjonen, men det må være en fil der libc.so. Det er dette biblioteket som gir systemanrop og grunnleggende funksjoner som f.eks åpen, malloc, printf etc. Våre alle er også blant dem. La oss sørge for dette:

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

La oss se om settet med biblioteker endres når det brukes 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 seg at variabelen er satt LD_PRELOAD tvinger oss til å laste ld_rand.so selv til tross for at selve programmet ikke krever det. Og siden vår funksjon "rand" laster tidligere enn alle fra libc.so, da regjerer hun.

Ok, vi klarte å erstatte den opprinnelige funksjonen, men hvordan kan vi sørge for at funksjonaliteten bevares og noen handlinger legges til. La oss endre vår tilfeldige:

#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, som vårt "tillegg", skriver vi bare ut én tekstlinje, hvoretter vi lager en peker til den opprinnelige funksjonen alle. For å få adressen til denne funksjonen trenger vi dlsym er en funksjon fra biblioteket libdlsom vil finne vår alle i en stabel med dynamiske biblioteker. Deretter vil vi kalle denne funksjonen og returnere verdien. Følgelig må vi legge til "-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 programmet vårt bruker "native" alle, etter å ha utført noen uanstendige handlinger tidligere.

2. Smerten ved å søke

Når vi vet om en potensiell trussel, ønsker vi å oppdage det forspenning Den ble utført. Det er klart at den beste måten å oppdage er å skyve den inn i kjernen, men jeg var interessert i deteksjonsalternativene i brukerområdet.

Deretter vil løsninger for deteksjon og deres tilbakevisning komme i par.

2.1. La oss starte enkelt

Som nevnt tidligere kan du spesifisere biblioteket som skal lastes ved å bruke variabelen LD_PRELOAD eller ved å skrive det i en fil /etc/ld.so.preload. La oss lage to enkle detektorer.

Den første er å sjekke den angitte miljøvariabelen:

#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 andre er å sjekke om filen er åpnet:

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

La oss laste inn bibliotekene:

$ 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 deteksjon.
Følgelig betyr [-] forbigående deteksjon.

Hvor effektiv er en slik detektor? La oss ta en titt på miljøvariabelen først:

#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åte blir vi kvitt sjekken åpen:

#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åter å få tilgang til filen på kan brukes her, for eksempel, open64, stat osv., men faktisk trengs de samme 5-10 kodelinjene for å lure dem.

2.2. La oss gå videre

Ovenfor brukte vi getenv() for å få verdien LD_PRELOAD, men det er også en mer "lavnivå" måte å komme til ENV-variabler. Vi vil ikke bruke mellomfunksjoner, men vil referere til matrisen **miljø, som lagrer en kopi av 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;
}

Siden vi her leser data direkte fra minnet, kan en slik samtale ikke avlyttes, og vår undetect_getenv det forstyrrer ikke lenger å identifisere inntrengingen.

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

Det ser ut til at dette problemet er løst? Det har fortsatt bare begynt.

Etter at programmet er startet, verdien av variabelen LD_PRELOAD hackere trenger det ikke lenger i minnet, det vil si at de kan lese det og slette det før de utfører noen instruksjoner. Selvfølgelig er det å redigere en array i minnet i det minste en dårlig programmeringsstil, men kan dette stoppe noen som egentlig ikke ønsker oss godt likevel?

For å gjøre dette må vi lage vår egen falske funksjon i det(), der vi avskjærer den installerte LD_PRELOAD og send den til linkeren vår:

#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ø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/self/

Minnet er imidlertid ikke det siste stedet du kan finne en erstatning LD_PRELOAD, Det er også / proc /. La oss starte med det åpenbare /proc/{PID}/environ.

Faktisk finnes det en universalløsning for uoppdaget **miljø и /proc/self/environ. Problemet er "feil" oppførsel unsetenv(env).

riktig 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 la oss forestille oss at vi ikke fant det og /proc/self/environ inneholder "problematiske" data.

La oss først prøve med vår forrige "forkledning":

$ (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 bruker det samme for å åpne filen åpen(), så løsningen ligner på det som allerede ble gjort i avsnitt 2.1, men nå lager vi en midlertidig fil der vi kopierer verdiene til det sanne minnet uten linjer som inneholder 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 dette stadiet er passert:

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

Det neste åpenbare stedet er /proc/self/maps. Det er ingen vits i å dvele ved det. Løsningen er helt identisk med den forrige: kopier dataene fra filen minus linjene mellom libc.so и ld.så.

2.4. Alternativ fra Chokepoint

Jeg likte spesielt denne løsningen for sin enkelhet. Vi sammenligner adressene til funksjoner lastet direkte fra libc, og "NESTE"-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;
}

Laster biblioteket med avlytting "åpen()" og sjekk:

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

Tilbakevisningen viste seg å være enda 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 ut til at dette er alt, men vi vil fortsatt flyndre. Hvis vi dirigerer systemanropet direkte til kjernen, vil dette omgå hele avlyttingsprosessen. Løsningen nedenfor er selvfølgelig arkitekturavhengig (x86_64). La oss prøve å implementere det for å oppdage en åpning 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 problemet har en løsning. Utdrag fra mann'EN:

ptrace er et verktøy som lar en overordnet prosess observere og kontrollere fremdriften til en annen prosess, se og endre dens data og registre. Vanligvis brukes denne funksjonen til å lage bruddpunkter i et feilsøkingsprogram og overvåke systemanrop.

Den overordnede prosessen kan begynne å spore ved først å kalle fork(2), og deretter kan den resulterende underordnede prosessen kjøre PTRACE_TRACEME, fulgt (vanligvis) av exec(3). På den annen side kan en overordnet prosess begynne å feilsøke en eksisterende prosess ved å bruke PTRACE_ATTACH.

Ved sporing stopper barneprosessen hver gang den mottar et signal, selv om signalet ignoreres. (Unntaket er SIGKILL, som fungerer normalt.) Foreldreprosessen vil bli varslet om dette ved å ringe wait(2), hvoretter den kan se og endre innholdet i den underordnede prosessen før den starter. Foreldreprosessen lar deretter barnet fortsette å løpe, i noen tilfeller ignorerer signalet som sendes til det eller sender et annet signal i stedet).

Dermed er løsningen å overvåke prosessen, stoppe den før hvert systemanrop og om nødvendig omdirigere tråden til en krokfunksjon.

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

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

+0-0=5

Tusen takk

Charles Hubain
kvelningspunkt
ValdikSS
Philippe Teuwen
derhass

, hvis artikler, kilder og kommentarer gjorde mye mer enn jeg gjorde for å få dette notatet til å vises her.

Kilde: www.habr.com

Legg til en kommentar