Kap chèche LD_PRELOAD

Nòt sa a te ekri an 2014, men mwen jis te vin anba represyon sou Habré e li pa t wè limyè a. Pandan entèdiksyon an mwen bliye sou li, men kounye a mwen jwenn li nan proje yo. Mwen te panse sou efase li, men petèt li pral itil yon moun.

Kap chèche LD_PRELOAD

An jeneral, yon ti vandredi admin lekti sou sijè a nan rechèch pou "enkli" LD_PRELOAD.

1. Yon digression kout pou moun ki pa abitye ak sibstitisyon fonksyon

Rès la ka ale tou dwat nan p.2.

Ann kòmanse ak yon egzanp klasik:

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

Nou konpile san okenn drapo:

$ gcc ./ld_rand.c -o ld_rand

Epi, jan nou espere, nou jwenn 5 nimewo o aza mwens pase 100:

$ ./ld_rand
53
93
48
57
20

Men, an nou imajine ke nou pa gen kòd sous pwogram nan, men nou bezwen chanje konpòtman an.

Ann kreye pwòp bibliyotèk nou ak pwòp pwototip fonksyon nou an, pou egzanp:

int rand(){
  return 42;
}

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

Epi, koulye a chwa o aza nou an se byen previzib:

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

Trick sa a sanble menm plis enpresyonan si nou premye ekspòte bibliyotèk nou an atravè

$ export LD_PRELOAD=$PWD/ld_rand.so

oswa nou pral fè li an premye

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

ak Lè sa a, kouri pwogram nan kòm dabitid. Nou pa chanje yon sèl liy kòd nan pwogram nan tèt li, men konpòtman li kounye a depann sou yon ti fonksyon nan bibliyotèk nou an. Anplis, nan moman ekri pwogram nan, la rand pa t menm egziste.

Ki sa ki fè pwogram nou an itilize yon fo rand? Ann pran li etap pa etap.
Lè yon aplikasyon kòmanse, yo chaje sèten bibliyotèk ki genyen fonksyon pwogram lan bezwen. Nou ka wè yo lè l sèvi avèk 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)

Lis sa a ka varye selon vèsyon OS la, men dwe genyen yon dosye la libc.so. Li se bibliyotèk sa a ki bay apèl sistèm ak fonksyon debaz tankou ouvri, malok, printf elatriye nou rand se pami yo tou. Ann asire w ke sa a:

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

Ann wè si seri bibliyotèk la chanje lè yo itilize yo 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)

Li sanble varyab la mete LD_PRELOAD fòse nou chaje ld_rand.so menm malgre lefèt ke pwogram nan tèt li pa mande pou li. E depi fonksyon nou "Rand" chaj pi bonè pase rand soti nan libc.so, Lè sa a, li dirije roost la.

Oke, nou jere ranplase fonksyon natif natal la, men ki jan nou ka asire w ke fonksyonalite li yo konsève ak kèk aksyon yo ajoute. Ann modifye o aza nou an:

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

Isit la, kòm "adisyon", nou sèlman enprime yon liy tèks, apre sa nou kreye yon konsèy sou fonksyon orijinal la rand. Pou jwenn adrès fonksyon sa a nou bezwen dlsym se yon fonksyon nan bibliyotèk la libdlki pral jwenn nou rand nan yon pil bibliyotèk dinamik. Apre sa, nou pral rele fonksyon sa a epi retounen valè li. An konsekans, nou pral bezwen ajoute "-ldl" pandan asanble:

$ 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

Ak pwogram nou an itilize "natif natal" rand, li te deja fè kèk aksyon obsèn.

2. Doulè pou chèche

Lè nou konnen yon menas potansyèl, nou vle detekte sa précharge Li te fèt. Li klè ke pi bon fason pou detekte se pouse li nan nwayo a, men mwen te enterese nan opsyon deteksyon yo nan espas itilizatè.

Apre sa, solisyon pou deteksyon ak refitasyon yo ap vini an pè.

2.1. Ann kòmanse senp

Kòm mansyone pi bonè, ou ka presize bibliyotèk la chaje lè l sèvi avèk varyab la LD_PRELOAD oswa lè w ekri li nan yon dosye /etc/ld.so.preload. Ann kreye de detektè senp.

Premye a se tcheke varyab anviwònman an mete:

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

Dezyèm lan se tcheke si dosye a louvri:

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

Ann chaje bibliyotèk yo:

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

Isit la ak anba a, [+] endike deteksyon siksè.
An konsekans, [-] vle di kontoune deteksyon.

Ki jan efikas yon detektè konsa? Ann pran yon gade nan varyab anviwònman an premye:

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

Menm jan an tou, nou debarase m de chèk la ouvri:

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

Wi, lòt fason pou jwenn aksè nan dosye a ka itilize isit la, tankou, louvri64, eta elatriye, men, an reyalite, yo bezwen menm 5-10 liy kòd yo pou twonpe yo.

2.2. Ann avanse

Pi wo a nou itilize getenv() pou jwenn valè a LD_PRELOAD, men gen tou yon fason ki pi "ba-nivo" pou ale nan ENV- varyab. Nou pa pral sèvi ak fonksyon entèmedyè, men nou pral refere a etalaj la **anviwon, ki estoke yon kopi anviwònman an:

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

Depi isit la nou ap li done ki sòti dirèkteman nan memwa, tankou yon apèl pa ka entèsepte, ak nou an undetect_getenv li pa entèfere ankò ak idantifye entrizyon an.

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

Li ta sanble ke pwoblèm sa a rezoud? Li fèk kòmanse toujou.

Apre pwogram nan kòmanse, valè varyab la LD_PRELOAD entru yo pa bezwen li ankò nan memwa, se sa ki, yo ka li li epi efase li anvan yo egzekite nenpòt enstriksyon. Natirèlman, modifye yon etalaj nan memwa se, nan yon minimòm, yon style pwogramasyon move, men ki jan sa a ka sispann yon moun ki pa reyèlman swete nou byen de tout fason?

Pou fè sa nou bezwen kreye pwòp fo fonksyon nou an nan li(), nan ki nou entèsepte enstale a LD_PRELOAD epi pase l bay linker nou an:

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

Nou egzekite ak tcheke:

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

Sepandan, memwa se pa dènye kote ou ka jwenn yon sibstitisyon LD_PRELOAD, gen tou /proc/. Ann kòmanse ak evidan an /proc/{PID}/environ.

An reyalite, gen yon solisyon inivèsèl pou detekte **anviwon и /proc/self/environment. Pwoblèm lan se "move" konpòtman an unsetenv(env).

opsyon kòrèk

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, an n imajine ke nou pa t 'jwenn li ak /proc/self/environment gen done "pwoblèm".

Premyèman, ann eseye ak "degize" anvan nou an:

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

chat sèvi ak menm bagay la pou louvri dosye a louvri (), Se konsa, solisyon an sanble ak sa ki te deja fè nan seksyon 2.1, men kounye a nou kreye yon dosye tanporè kote nou kopye valè yo nan memwa a vre san yo pa liy ki gen ladan. 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);
}

Epi etap sa a te pase:

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

Pwochen kote evidan se /proc/self/maps. Pa gen okenn pwen nan rete sou li. Solisyon an absoliman idantik ak anvan an: kopye done ki soti nan dosye a mwens liy ki genyen ant yo libc.so и ld.so.

2.4. Opsyon soti nan Chokepoint

Mwen espesyalman te renmen solisyon sa a pou senplisite li. Nou konpare adrès fonksyon ki chaje dirèkteman nan libc, ak adrès "PROCHAIN".

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

Chaje bibliyotèk la ak entèsepsyon "louvri()" epi tcheke:

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

Refite a te vin menm pi senp:

#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

Li ta sanble ke sa a se tout, men nou pral toujou flounder. Si nou voye apèl sistèm lan dirèkteman nan nwayo a, sa a pral kontoune tout pwosesis entèsepsyon an. Solisyon ki anba a se, nan kou, achitekti-depandan (x86_64). Ann eseye aplike li pou detekte yon ouvèti 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) [+]

Ak pwoblèm sa a gen yon solisyon. Ekstrè soti nan nonm'A:

ptrace se yon zouti ki pèmèt yon pwosesis paran yo obsève ak kontwole pwogrè yon lòt pwosesis, wè ak chanje done li yo ak anrejistre. Tipikman yo itilize fonksyon sa a pou kreye pwen breakpoints nan yon pwogram debogaj epi kontwole apèl sistèm yo.

Pwosesis paran an ka kòmanse trase pa premye rele fork(2), ak Lè sa a, pwosesis pitit ki kapab lakòz ka egzekite PTRACE_TRACEME, swiv (anjeneral) pa egzekite exec (3). Nan lòt men an, yon pwosesis paran ka kòmanse debogaj yon pwosesis ki egziste deja lè l sèvi avèk PTRACE_ATTACH.

Tracing sispann pwosesis timoun nan chak fwa li resevwa yon siyal, menm si siyal la inyore. (Eksepsyon an se SIGKILL, ki travay nòmalman.) Pwosesis paran an pral resevwa notifikasyon sou sa lè w rele wait(2), apre sa li ka wè ak modifye sa ki nan pwosesis pitit la anvan li kòmanse. Pwosesis paran an Lè sa a, pèmèt timoun nan kontinye kouri, nan kèk ka inyore siyal la voye ba li oswa voye yon lòt siyal pito).

Kidonk, solisyon an se kontwole pwosesis la, sispann li anvan chak apèl sistèm epi, si sa nesesè, redireksyon fil la nan yon fonksyon zen.

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

Nou tcheke:

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

+0-0=5

Mèsi anpil

Charles Hubain
pwen toufe
ValdikSS
Philippe Teuwen
derhass

, ki gen atik, sous ak kòmantè te fè pi plis pase mwen te fè nòt sa a parèt isit la.

Sous: www.habr.com

Add nouvo kòmantè