ืื™ืจ ื–ื•ื›ื˜ ืคึฟืึทืจ LD_PRELOAD

ื“ืขืจ ืฆืขื˜ืœ ืื™ื– ื’ืขื•ื•ืขืŸ ื’ืขืฉืจื™ื‘ืŸ ืื™ืŸ 2014, ืึธื‘ืขืจ ืื™ืš ื ืึธืจ ื’ืขืงื•ืžืขืŸ ืื•ื ื˜ืขืจ ืคืึทืจืฉื˜ื™ืงื•ื ื’ ืื•ื™ืฃ Habrรฉ ืื•ืŸ ืขืก ื”ืื˜ ื ื™ืฉื˜ ื–ืขืŸ ื“ื™ ืœื™ื›ื˜ ืคื•ืŸ ื˜ืึธื’. ื‘ืขืฉืึทืก ื“ื™ ืคืึทืจื‘ืึธื˜ ืื™ืš ืคืืจื’ืขืกืŸ ื•ื•ืขื’ืŸ ืื™ื, ืึธื‘ืขืจ ืื™ืฆื˜ ืื™ืš ื’ืขืคื•ื ืขืŸ ืขืก ืื™ืŸ ื“ื™ ื“ืจืึทืคืฅ. ืื™ืš ื’ืขื“ืึทื ืง ื•ื•ืขื’ืŸ ื•ื™ืกืžืขืงืŸ ืขืก, ืึธื‘ืขืจ ืืคึฟืฉืจ ืขืก ื•ื•ืขื˜ ื–ื™ื™ืŸ ื ื•ืฆื™ืง ืคึฟืึทืจ ืขืžืขืฆืขืจ.

ืื™ืจ ื–ื•ื›ื˜ ืคึฟืึทืจ LD_PRELOAD

ืื™ืŸ ืึทืœื’ืขืžื™ื™ืŸ, ืึท ื‘ื™ืกืœ ืคืจื™ื™ื˜ืื’ ืึทื“ืžื™ืŸ ืœื™ื™ืขื ืขืŸ ืื•ื™ืฃ ื“ืขืจ ื˜ืขืžืข ืคื•ืŸ โ€‹โ€‹ื–ื•ื›ืŸ ืคึฟืึทืจ "ืึทืจื™ื™ึทื ื’ืขืจืขื›ื ื˜" LD_PRELOAD.

1. ื ืงื•ืจืฅ ื“ื™ื’ืจืขืฉืึทืŸ ืคึฟืึทืจ ื“ื™ ื•ื•ืืก ื–ืขื ืขืŸ ื ื™ืฉื˜ ื‘ืึทืงืึทื ื˜ ืžื™ื˜ ืคื•ื ืงืฆื™ืึธื ื™ืจืŸ ืกืึทื‘ืกื˜ื™ื˜ื•ืฉืึทืŸ

ื“ื™ ืžื ื•ื—ื” ืงืขื ืขืŸ ื’ื™ื™ืŸ ื’ืœื™ื™ึทืš ืฆื• ื–.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);
  }
}

ืžื™ืจ ืฆื•ื ื•ื™ืคืฉื˜ืขืœื  ื–ื™ืš ืึธืŸ ืงื™ื™ืŸ ืคืœืึทื’ืก:

$ gcc ./ld_rand.c -o ld_rand

ืื•ืŸ, ื•ื•ื™ ื“ืขืจื•ื•ืึทืจื˜, ืžื™ืจ ื‘ืึทืงื•ืžืขืŸ 5 ื˜ืจืึทืค - ื ื•ืžืขืจืŸ ื•ื•ื™ื™ื ื™ืงืขืจ ื•ื•ื™ 100:

$ ./ld_rand
53
93
48
57
20

ืึธื‘ืขืจ ืœืึธื–ืŸ ืื•ื ื“ื– ื™ืžืึทื“ื–ืฉืึทืŸ ืึทื– ืžื™ืจ ื˜ืึธืŸ ื ื™ื˜ ื”ืึธื‘ืŸ ื“ื™ ืžืงื•ืจ ืงืึธื“ ืคื•ืŸ ื“ื™ ืคึผืจืึธื’ืจืึทื, ืึธื‘ืขืจ ืžื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ื˜ื•ื™ืฉืŸ ื“ื™ ื ืึทื˜ื•ืจ.

ืœืึธืžื™ืจ ืžืึทื›ืŸ ืื•ื ื“ื–ืขืจ ืื™ื™ื’ืขื ืข ื‘ื™ื‘ืœื™ืึธื˜ืขืง ืžื™ื˜ ืื•ื ื“ื–ืขืจ ืื™ื™ื’ืขื ืข ืคึผืจืึธื•ื˜ืึทื˜ื™ื™ืคึผ ืคืึทื ื’ืงืฉืึทื ื–, ืœืžืฉืœ:

int rand(){
  return 42;
}

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

ืื•ืŸ ืื™ืฆื˜ ืื•ื ื“ื–ืขืจ ื˜ืจืึทืค - ื‘ืจื™ืจื” ืื™ื– ื’ืึทื ืฅ ืคึผืจื™ื“ื™ืงื˜ืึทื‘ืึทืœ:

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

ื“ืขืจ ืงื•ื ืฅ ืงื•ืงื˜ ืืคื™ืœื• ืžืขืจ ื™ืžืคึผืจืขืกื™ื•ื• ืื•ื™ื‘ ืžื™ืจ ืขืจืฉื˜ืขืจ ืึทืจื•ื™ืกืคื™ืจืŸ ืื•ื ื“ื–ืขืจ ื‘ื™ื‘ืœื™ืึธื˜ืขืง ื“ื•ืจืš

$ export LD_PRELOAD=$PWD/ld_rand.so

ืึธื“ืขืจ ืžื™ืจ ื•ื•ืขืœืŸ ื˜ืึธืŸ ืขืก ืขืจืฉื˜ืขืจ

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

ืื•ืŸ ื“ืขืžืึธืœื˜ ืœื•ื™ืคืŸ ื“ื™ ืคึผืจืึธื’ืจืึทื ื•ื•ื™ ื’ืขื•ื•ื™ื™ื ื˜ืœืขืš. ืžื™ืจ ื”ืึธื‘ืŸ ื ื™ืฉื˜ ืคืืจืขื ื“ืขืจื˜ ืึท ืื™ื™ืŸ ืฉื•ืจื” ืคื•ืŸ ืงืึธื“ ืื™ืŸ ื“ื™ ืคึผืจืึธื’ืจืึทื ื–ื™ืš, ืึธื‘ืขืจ ื–ื™ื™ืŸ ื ืึทื˜ื•ืจ ื“ืขืคึผืขื ื“ืก ืื™ืฆื˜ ืื•ื™ืฃ ืึท ืงืœื™ื™ื ื˜ืฉื™ืง ืคื•ื ืงืฆื™ืข ืื™ืŸ ืื•ื ื“ื–ืขืจ ื‘ื™ื‘ืœื™ืึธื˜ืขืง. ื“ืขืจืฆื•, ืื™ืŸ ื“ืขืจ ืฆื™ื™ื˜ ืคื•ืŸ ืฉืจื™ื™ื‘ืŸ ื“ืขื ืคึผืจืึธื’ืจืึทื, ื“ื™ ืจืึทื ื“ ื”ืื˜ ืืคื™ืœื• ื ื™ืฉื˜ ืขืงื–ื™ืกื˜ื™ืจื˜.

ื•ื•ืึธืก ื’ืขืžืื›ื˜ ืื•ื ื“ื–ืขืจ ืคึผืจืึธื’ืจืึทื ื ื•ืฆืŸ ืึท ืฉื•ื•ื™ื ื“ืœ ืจืึทื ื“? ื–ืืœ ืก ื ืขืžืขืŸ ืขืก ืฉืจื™ื˜ ื“ื•ืจืš ืฉืจื™ื˜.
ื•ื•ืขืŸ ืึท ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ืกื˜ืึทืจืฅ, ืขื˜ืœืขื›ืข ืœื™ื™ื‘ืจืขืจื™ื– ื–ืขื ืขืŸ ืœืึธื•ื“ื™ื“ ื•ื•ืึธืก ืึทื ื˜ื”ืึทืœื˜ืŸ ื“ื™ ืคืึทื ื’ืงืฉืึทื ื– ื•ื•ืึธืก ื“ื™ ืคึผืจืึธื’ืจืึทื ื“ืึทืจืฃ. ืžื™ืจ ืงืขื ืขืŸ ื–ืขืŸ ื–ื™ื™ ื ื™ืฆืŸ ืœื“:

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

ื“ื™ ืจืฉื™ืžื” ืงืขืŸ ื‘ื™ื™ึทื˜ืŸ ื“ื™ืคึผืขื ื“ื™ื ื’ ืื•ื™ืฃ ื“ื™ ืึทืก ื•ื•ืขืจืกื™ืข, ืึธื‘ืขืจ ืขืก ืžื•ื–ืŸ ื–ื™ื™ืŸ ืึท ื˜ืขืงืข ื“ืึธืจื˜ libc.so. ืขืก ืื™ื– ื“ื™ ื‘ื™ื‘ืœื™ืึธื˜ืขืง ื•ื•ืึธืก ื’ื™ื˜ ืกื™ืกื˜ืขื ืงืึทืœืœืก ืื•ืŸ ื™ืงืขืจื“ื™ืง ืคืึทื ื’ืงืฉืึทื ื– ืึทื–ืึท ื•ื•ื™ ืขืคืขื ืขืŸ, malloc, ืคึผืจื™ื ื˜ืฃ ื•ื›ื•' ืื•ื ื“ื–ืขืจืข ืจืึทื ื“ ืื™ื– ืื•ื™ืš ืฆื•ื•ื™ืฉืŸ ื–ื™ื™. ื–ืืœ ืก ืžืึทื›ืŸ ื–ื™ื›ืขืจ ืคื•ืŸ ื“ืขื:

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

ื–ืืœ ืก ื–ืขืŸ ืื•ื™ื‘ ื“ื™ ื’ืึทื ื’ ืคื•ืŸ ืœื™ื™ื‘ืจืขืจื™ื– ืขื ื“ืขืจื•ื ื’ืขืŸ ื•ื•ืขืŸ ื’ืขื•ื•ื™ื™ื ื˜ 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)

ืขืก ืงื•ืงื˜ ื•ื•ื™ ื“ื™ ื•ื•ืขืจื™ืึทื‘ืึทืœื– ืื™ื– ื‘ืึทืฉื˜ื™ืžื˜ LD_PRELOAD ืคืึธืจืกืขืก ืื•ื ื“ื–ืขืจ ืฆื• ืžืึทืกืข ld_rand.so ืืคื™ืœื• ื˜ืจืึธืฅ ื“ืขืจ ืคืึทืงื˜ ืึทื– ื“ื™ ืคึผืจืึธื’ืจืึทื ื–ื™ืš ื˜ื•ื˜ ื ื™ืฉื˜ ื“ืึทืจืคืŸ ืขืก. ืื•ืŸ ื–ื™ื ื˜ ืื•ื ื“ื–ืขืจ ืคึฟื•ื ืงืฆื™ืข "ืจืึทื ื“" ืœืึธื•ื“ื– ืคืจื™ืขืจ ื•ื•ื™ ืจืึทื ื“ ืคื•ืŸ libc.so, ื“ืขืžืืœ ื˜ ื”ืขืจืฉ ื˜ ื– ื™ ื“ืข ืจ ืจื•ื˜ .

ื’ื•ื˜, ืžื™ืจ ื’ืขืจืื˜ืŸ ืฆื• ืคืึทืจื‘ื™ื™ึทื˜ืŸ ื“ื™ ื’ืขื‘ื•ื™ืจืŸ ืคื•ื ืงืฆื™ืข, ืึธื‘ืขืจ ื•ื•ื™ ืงืขื ืขืŸ ืžื™ืจ ืžืึทื›ืŸ ื–ื™ื›ืขืจ ืึทื– ื“ื™ ืคืึทื ื’ืงืฉืึทื ืึทืœื™ื˜ื™ ืื™ื– ืืคื’ืขื”ื™ื˜ ืื•ืŸ ืขื˜ืœืขื›ืข ืึทืงืฉืึทื ื– ื–ืขื ืขืŸ ืฆื•ื’ืขื’ืขื‘ืŸ. ืœืึธืžื™ืจ ืžืึธื“ื™ืคื™ืฆื™ืจืŸ ืื•ื ื“ื–ืขืจ ื˜ืจืึทืค:

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

ื“ืึธ, ื•ื•ื™ ืื•ื ื“ื–ืขืจ "ืฆื•ื’ืขื‘ืŸ", ืžื™ืจ ื“ืจื•ืงืŸ ื‘ืœื•ื™ื– ืื™ื™ืŸ ืฉื•ืจื” ืคื•ืŸ ื˜ืขืงืกื˜, ื ืึธืš ื•ื•ืึธืก ืžื™ืจ ืžืึทื›ืŸ ืึท ื˜ื™ื™ึทื˜ืœ ืฆื• ื“ืขืจ ืึธืจื™ื’ื™ื ืขืœ ืคึฟื•ื ืงืฆื™ืข ืจืึทื ื“. ืฆื• ื‘ืึทืงื•ืžืขืŸ ื“ื™ ืึทื“ืจืขืก ืคื•ืŸ ื“ืขื ืคึฟื•ื ืงืฆื™ืข ืžื™ืจ ื“ืึทืจืคึฟืŸ dlsym ืื™ื– ืึท ืคึฟื•ื ืงืฆื™ืข ืคึฟื•ืŸ ื“ืขืจ ื‘ื™ื‘ืœื™ืึธื˜ืขืง libdlื•ื•ืึธืก ื•ื•ืขื˜ ื’ืขืคึฟื™ื ืขืŸ ืื•ื ื“ื–ืขืจ ืจืึทื ื“ ืื™ืŸ ืึท ืึธื ืœื™ื™ื’ืŸ ืคื•ืŸ ื“ื™ื ืึทืžื™ืฉ ืœื™ื™ื‘ืจืขืจื™ื–. ื ืึธืš ื•ื•ืึธืก ืžื™ืจ ื•ื•ืขืœืŸ ืจื•ืคืŸ ื“ืขื ืคึฟื•ื ืงืฆื™ืข ืื•ืŸ ืฆื•ืจื™ืงืงื•ืžืขืŸ ื–ื™ื™ึทืŸ ื•ื•ืขืจื˜. ืึทืงืงืึธืจื“ื™ื ื’ืœื™, ืžื™ืจ ื•ื•ืขืœืŸ ื“ืึทืจืคึฟืŸ ืฆื• ืœื™ื™ื’ืŸ "-ืœื“ืœ" ื‘ืขืช ืืกื™ืคื”:

$ 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

ืื•ืŸ ืื•ื ื“ื–ืขืจ ืคึผืจืึธื’ืจืึทื ื ื™ืฆื˜ "ื’ืขื‘ื•ื™ืจืŸ" ืจืึทื ื“, ื•ื•ื™ื™ืœ ืคืจื™ืขืจ ื’ืขื˜ืืŸ ืขื˜ืœืขื›ืข ื’ืจืึธื‘ ืึทืงืฉืึทื ื–.

2. ื“ืขืจ ื•ื•ื™ื™ื˜ื™ืง ืคื•ืŸ ื–ื•ื›ืŸ

ื•ื•ื™ืกืŸ ื•ื•ืขื’ืŸ ืึท ืคึผืึธื˜ืขื ืฆื™ืขืœ ืกืึทืงืึธื ืข, ืžื™ืจ ื•ื•ืขืœืŸ ืฆื• ื“ืขื˜ืขืงื˜ ืึทื– ืคึผืจืขืœืึธืึทื“ ืขืก ืื™ื– ื’ืขื•ื•ืขืŸ ื’ืขื˜ืืŸ. ืขืก ืื™ื– ืงืœืึธืจ ืึทื– ื“ืขืจ ื‘ืขืกื˜ืขืจ ื•ื•ืขื’ ืฆื• ื“ืขื˜ืขืงื˜ ืื™ื– ืฆื• ืฉื˜ื•ืคึผืŸ ืขืก ืื™ืŸ ื“ื™ ืงืขืจืŸ, ืึธื‘ืขืจ ืื™ืš ืื™ื– ื’ืขื•ื•ืขืŸ ืื™ื ื˜ืขืจืขืกื™ืจื˜ ืื™ืŸ ื“ื™ ื“ื™ื˜ืขืงืฉืึทืŸ ืึธืคึผืฆื™ืขืก ืื™ืŸ ื‘ืึทื ื™ืฆืขืจ ืคึผืœืึทืฅ.

ื•ื•ื™ื™ึทื˜ืขืจ, ืกืึทืœื•ืฉืึทื ื– ืคึฟืึทืจ ื“ื™ื˜ืขืงืฉืึทืŸ ืื•ืŸ ื–ื™ื™ืขืจ ืจื™ืคื™ื•ื˜ื™ื™ืฉืึทืŸ ื•ื•ืขื˜ ืงื•ืžืขืŸ ืื™ืŸ ืคึผืขืจื–.

2.1. ื–ืืœ ืก ืึธื ื”ื™ื™ื‘ืŸ ืคึผืฉื•ื˜

ื•ื•ื™ ื“ืขืจืžืื ื˜ ืคืจื™ืขืจ, ืื™ืจ ืงืขื ืขืŸ ืกืคึผืขืฆื™ืคื™ืฆื™ืจืŸ ื“ื™ ื‘ื™ื‘ืœื™ืึธื˜ืขืง ืฆื• ืžืึทืกืข ืžื™ื˜ ื“ื™ ื‘ื™ื™ึทื˜ืขื•ื•ื“ื™ืง 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");
}

ื“ื™ ืจื’ืข ืื™ื– ืฆื• ืงืึธื ื˜ืจืึธืœื™ืจืŸ ืฆื™ ื“ื™ ื˜ืขืงืข ืื™ื– ื’ืขืขืคื ื˜:

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

ื“ืึธ ืื•ืŸ ืื•ื ื˜ืŸ, [+] ื™ื ื“ื™ืงื™ื™ืฅ ืึท ืžืฆืœื™ื— ื“ื™ื˜ืขืงืฉืึทืŸ.
ืึทืงืงืึธืจื“ื™ื ื’ืœื™, [-] ืžื™ื˜ืœ ื‘ื™ื™ืคึผืึทืกื™ื ื’ ื“ื™ื˜ืขืงืฉืึทืŸ.

ื•ื•ื™ ืขืคืขืงื˜ื™ื•ื• ืื™ื– ืึทื–ืึท ืึท ื“ืขื˜ืขืงื˜ืึธืจ? ื–ืืœ ืก ื ืขืžืขืŸ ืึท ืงื•ืง ืื™ืŸ ื“ื™ ืกื•ื•ื™ื•ื•ืข ื•ื•ืขืจื™ืึทื‘ืึทืœ ืขืจืฉื˜ืขืจ:

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

ืกื™ืžื™ืœืึทืจืœื™, ืžื™ืจ ื‘ืึทืงื•ืžืขืŸ ื‘ืึทืคืจื™ื™ึทืขืŸ ืคื•ืŸ ื“ื™ ื˜ืฉืขืง ืขืคืขื ืขืŸ:

#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, ืžืขื“ื™ื ืข ืืื–"ื• ื•, ืึธื‘ืขืจ, ืื™ืŸ ืคืึทืงื˜, ื“ื™ ื–ืขืœื‘ืข 5-10 ืฉื•ืจื•ืช ืคื•ืŸ ืงืึธื“ ื–ืขื ืขืŸ ื“ืืจืฃ ืฆื• ืึธืคึผื ืึทืจืŸ ื–ื™ื™.

2.2. ืœืืžื™ืจ ื•ื•ื™ื™ื˜ืขืจ ื’ื™ื™ืŸ

ืื•ื™ื‘ืŸ ืžื™ืจ ื’ืขื•ื•ื™ื™ื ื˜ ื’ืขื˜ืขื ื•ื•() ืฆื• ื‘ืึทืงื•ืžืขืŸ ื“ื™ ื•ื•ืขืจื˜ LD_PRELOAD, ืึธื‘ืขืจ ืขืก ืื™ื– ืื•ื™ืš ืึท ืžืขืจ "ื ื™ื“ืขืจื™ืง ืžื“ืจื’ื”" ื•ื•ืขื’ ืฆื• ื‘ืึทืงื•ืžืขืŸ ืฆื• ENV- ื•ื•ืขืจื™ืึทื‘ืึทืœื–. ืžื™ืจ ื•ื•ืขืœืŸ ื ื™ืฉื˜ ื ื•ืฆืŸ ื™ื ื˜ืขืจืžื™ื“ื™ื™ื˜ ืคืึทื ื’ืงืฉืึทื ื–, ืึธื‘ืขืจ ืึธืคึผืฉื™ืงืŸ ืฆื• ื“ื™ ืžืขื ื’ืข **ืกื‘ื™ื‘, ื•ื•ืึธืก ืกื˜ืึธืจื– ืึท ืงืึธืคึผื™ืข ืคื•ืŸ โ€‹โ€‹โ€‹โ€‹ื“ื™ ืกื•ื•ื™ื•ื•ืข:

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

ืขืก ื•ื•ืึธืœื˜ ื•ื™ืกืงื•ืžืขืŸ ืึทื– ื“ืขื ืคึผืจืึธื‘ืœืขื ืื™ื– ืกืึทืœื•ื•ื“? ืขืก ืก ื ืึธืš ื ืึธืจ ืึธื ื”ื™ื™ื‘.

ื ืึธืš ื“ื™ ืคึผืจืึธื’ืจืึทื ืื™ื– ืกื˜ืึทืจื˜ืขื“, ื“ื™ ื•ื•ืขืจื˜ ืคื•ืŸ ื“ื™ ื‘ื™ื™ึทื˜ืขื•ื•ื“ื™ืง LD_PRELOAD ื›ืึทืงืขืจื– ื ื™ื˜ ืžืขืจ ื“ืึทืจืคึฟืŸ ืขืก ืื™ืŸ ื–ื›ึผืจื•ืŸ, ื“ืึธืก ืื™ื–, ื–ื™ื™ ืงืขื ืขืŸ ืœื™ื™ืขื ืขืŸ ืขืก ืื•ืŸ ื•ื™ืกืžืขืงืŸ ืขืก ืื™ื™ื“ืขืจ ืขืงืกืึทืงื™ื•ื˜ื™ื ื’ ืงื™ื™ืŸ ื™ื ืกื˜ืจืึทืงืฉืึทื ื–. ืคื•ืŸ ืงื•ืจืก, ืขื“ื™ื˜ื™ื ื’ ืึท ืžืขื ื’ืข ืื™ืŸ ื–ื™ืงืึธืจืŸ ืื™ื–, ื‘ื™ื™ึท ืึท ืžื™ื ื™ืžื•ื, ืึท ืฉืœืขื›ื˜ ืคึผืจืึธื’ืจืึทืžืžื™ื ื’ ืกื˜ื™ืœ, ืึธื‘ืขืจ ื•ื•ื™ ืงืขืŸ ื“ืึธืก ื”ืึทืœื˜ืŸ ืขืžืขืฆืขืจ ื•ื•ืืก ื˜ื•ื˜ ื ื™ืฉื˜ ื˜ืึทืงืข ื•ื•ื™ื ื˜ืฉืŸ ืื•ื ื“ื– ื’ืขื–ื•ื ื˜ ืกื™ื™ึท ื•ื•ื™ ืกื™ื™ึท?

ืฆื• ื˜ืึธืŸ ื“ืึธืก, ืžื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืฉืึทืคึฟืŸ ืื•ื ื“ื–ืขืจ ืื™ื™ื’ืขื ืข ืฉื•ื•ื™ื ื“ืœ ืคื•ื ืงืฆื™ืข ืื™ืŸ ื“ืขื(), ืื™ืŸ ื•ื•ืึธืก ืžื™ืจ ื™ื ื˜ืขืจืกืขืคึผื˜ ื“ื™ ืื™ื ืกื˜ืึทืœื™ืจืŸ 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;
}

ืžื™ืจ ื•ื™ืกืคื™ืจืŸ ืื•ืŸ ืงืึธื ื˜ืจืึธืœื™ืจืŸ:

$ 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, ืขืก ืื™ื– ืื•ื™ืš /ืคึผืจืึธืง/. ื–ืืœ ืก ืึธื ื”ื™ื™ื‘ืŸ ืžื™ื˜ ื“ื™ ืงืœืึธืจ ื•ื•ื™ ื“ืขืจ ื˜ืึธื’ /ืคึผืจืึธืง/{PID}/ืขื ื•ื•ื™ืจืึธืŸ.

ืื™ืŸ ืคืึทืงื˜, ืขืก ืื™ื– ืึท ื•ื ื™ื•ื•ืขืจืกืึทืœ ืœื™ื™ื–ื•ื ื’ ืคึฟืึทืจ ืึทื ื“ื™ื˜ืขืงื˜ **ืกื‘ื™ื‘ ะธ /proc/self/environ. ื“ื™ ืคึผืจืึธื‘ืœืขื ืื™ื– ื“ื™ "ืคืึทืœืฉ" ื ืึทื˜ื•ืจ unsetenv (env).

ืจื™ื›ื˜ื™ืง ืึธืคึผืฆื™ืข

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
$

ืื‘ืขืจ ืœืืžื™ืจ ื–ื™ืš ืคืืจืฉื˜ืขืœืŸ ืื– ืžื™ืจ ื”ืื‘ืŸ ืขืก ื ื™ืฉื˜ ื’ืขืคื•ื ืขืŸ ืื•ืŸ /proc/self/environ ื›ึผื•ืœืœ "ืคึผืจืึธื‘ืœืขืžืึทื˜ื™ืง" ื“ืึทื˜ืŸ.

ืœืืžื™ืจ ืงื•ื“ื ืคืจื•ื‘ื™ืจืŸ ืžื™ื˜ ืื•ื ื–ืขืจ ืคืจื™ืขืจื“ื™ื’ืขืจ "ืคืึทืจืฉื˜ืขืœื•ื ื’":

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

ืงืึทืฅ ื ื™ืฆื˜ ื“ื™ ื–ืขืœื‘ืข ืฆื• ืขืคืขื ืขืŸ ื“ื™ ื˜ืขืงืข ืขืคืขื ืขืŸ (), ืึทื–ื•ื™ ื“ื™ ืœื™ื™ื–ื•ื ื’ ืื™ื– ืขื ืœืขืš ืฆื• ื•ื•ืึธืก ืื™ื– ืฉื•ื™ืŸ ื’ืขื˜ืืŸ ืื™ืŸ ืึธืคึผื˜ื™ื™ืœื•ื ื’ 2.1, ืึธื‘ืขืจ ืื™ืฆื˜ ืžื™ืจ ืžืึทื›ืŸ ืึท ืฆื™ื™ึทื˜ื•ื•ื™ื™ึทืœื™ืง ื˜ืขืงืข ื•ื•ื• ืžื™ืจ ื ืึธื›ืžืึทื›ืŸ ื“ื™ ื•ื•ืึทืœื•ืขืก ืคื•ืŸ ื“ื™ ืืžืช ื–ื›ึผืจื•ืŸ ืึธืŸ ืฉื•ืจื•ืช ืžื™ื˜ 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);
}

ืื•ืŸ ื“ืขื ื‘ื™ื ืข ืื™ื– ื“ื•ืจื›ื’ืขื’ืื ื’ืขืŸ:

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

ื“ืขืจ ื•ื•ื™ื™ึทื˜ืขืจ ืงืœืึธืจ ื•ื•ื™ ื“ืขืจ ื˜ืึธื’ ืึธืจื˜ ืื™ื– /proc/self/maps. ืขืก ืื™ื– ืงื™ื™ืŸ ืคื•ื ื˜ ืฆื• ื•ื•ื•ื™ื ืขืŸ ืื•ื™ืฃ ืื™ื. ื“ื™ ืœื™ื™ื–ื•ื ื’ ืื™ื– ืœืขื’ืึทืžืจืข ื™ื™ื“ืขื ื™ืงืึทืœ ืฆื• ื“ื™ ืคืจื™ืขืจื“ื™ืงืข: ื ืึธื›ืžืึทื›ืŸ ื“ื™ ื“ืึทื˜ืŸ ืคึฟื•ืŸ ื“ืขืจ ื˜ืขืงืข ืžื™ื ื•ืก ื“ื™ ืฉื•ืจื•ืช ืฆื•ื•ื™ืฉืŸ libc.so ะธ ld.so.

2.4. ืึธืคึผืฆื™ืข ืคึฟื•ืŸ Chokepoint

ืื™ืš ืกืคึผืขืฆื™ืขืœ ืœื™ื™ืงื˜ ื“ืขื ืœื™ื™ื–ื•ื ื’ ืคึฟืึทืจ ื–ื™ื™ึทืŸ ืคึผืึทืฉื˜ืขืก. ืžื™ืจ ืคืึทืจื’ืœื™ื™ึทื›ืŸ ื“ื™ ืึทื“ืจืขืกืขืก ืคื•ืŸ ืคืึทื ื’ืงืฉืึทื ื– ืœืึธื•ื“ื™ื“ ื’ืœื™ื™ึทืš ืคึฟื•ืŸ libc, ืื•ืŸ "ื•ื•ื™ื™ึทื˜ืขืจ" ื•ื•ืขื ื“ื˜.

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

ืœืึธื•ื“ื™ื ื’ ื“ื™ ื‘ื™ื‘ืœื™ืึธื˜ืขืง ืžื™ื˜ ื™ื ื˜ืขืจืกืขืคึผืฉืึทืŸ "ืขืคืขื ืขืŸ ()" ืื•ืŸ ื˜ืฉืขืง:

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

ื“ื™ ืจื™ืคื™ื•ื˜ื™ื™ืฉืึทืŸ ืื™ื– ื’ืขื•ื•ืขืŸ ื ืึธืš ืกื™ืžืคึผืœืขืจ:

#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. ืกื™ืกืงืึทืœืœืก

ืขืก ื•ื•ืึธืœื˜ ื•ื™ืกืงื•ืžืขืŸ ืึทื– ื“ืึธืก ืื™ื– ืึทืœืข, ืึธื‘ืขืจ ืžื™ืจ ื•ื•ืขืœืŸ ื ืึธืš ืคืœืึธื•ื ื“ืขืจ. ืื•ื™ื‘ ืžื™ืจ ืคื™ืจืŸ ื“ื™ ืกื™ืกื˜ืขื ืจื•ืคืŸ ื’ืœื™ื™ึทืš ืฆื• ื“ื™ ืงืขืจืŸ, ื“ืึธืก ื•ื•ืขื˜ ื‘ื™ื™ืคึผืึทืก ื“ื™ ื’ืื ืฆืข ื™ื ื˜ืขืจืกืขืคึผืฉืึทืŸ ืคึผืจืึธืฆืขืก. ื“ื™ ืœื™ื™ื–ื•ื ื’ ืื•ื ื˜ืŸ ืื™ื–, ืคื•ืŸ ืงื•ืจืก, ืึทืจืงืึทื˜ืขืงื˜ืฉืขืจ-ืึธืคืขื ื’ื™ืง (ืงืก 86_64). ื–ืืœ ืก ืคึผืจื•ื‘ื™ืจืŸ ืฆื• ื™ื ืกื˜ืจื•ืžืขื ื˜ ืขืก ืฆื• ื“ืขื˜ืขืงื˜ ืึท ืขืคืŸ 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) [+]

ืื•ืŸ ื“ืขื ืคึผืจืึธื‘ืœืขื ื”ืื˜ ืึท ืœื™ื™ื–ื•ื ื’. ืื•ื™ืกืฆื•ื’ ืคื•ืŸ ืžืขื ื˜ืฉ'ื:

ptrace ืื™ื– ืึท ื’ืขืฆื™ื™ึทื’ ื•ื•ืึธืก ืึทืœืึทื•ื– ืึท ืคืึธื˜ืขืจ ืคึผืจืึธืฆืขืก ืฆื• ืึธื‘ืกืขืจื•ื•ื™ืจืŸ ืื•ืŸ ืงืึธื ื˜ืจืึธืœื™ืจืŸ ื“ื™ ืคึผืจืึธื’ืจืขืก ืคื•ืŸ ืืŸ ืื ื“ืขืจ ืคึผืจืึธืฆืขืก, ืงื•ืง ืื•ืŸ ื˜ื•ื™ืฉืŸ ื“ื™ ื“ืึทื˜ืŸ ืื•ืŸ ืจืขื“ื–ืฉื™ืกื˜ืขืจื–. ื˜ื™ืคึผื™ืงืึทืœืœื™, ื“ืขื ืคึฟื•ื ืงืฆื™ืข ืื™ื– ื’ืขื ื™ืฆื˜ ืฆื• ืฉืึทืคึฟืŸ ื‘ืจืขืึทืงืคึผืึธื™ื ืฅ ืื™ืŸ ืึท ื“ื™ื‘ืึทื’ื™ื ื’ ืคึผืจืึธื’ืจืึทื ืื•ืŸ ืžืึธื ื™ื˜ืึธืจ ืกื™ืกื˜ืขื ืงืึทืœืœืก.

ื“ืขืจ ืคืึธื˜ืขืจ ืคึผืจืึธืฆืขืก ืงืขื ืขืŸ ืึธื ื”ื™ื™ื‘ืŸ ื˜ืจื™ื™ืกื™ื ื’ ื“ื•ืจืš ืขืจืฉื˜ืขืจ ืจื•ืคืŸ ื’ืึธืคึผืœ (2), ืื•ืŸ ื“ืขืจ ืจื™ื–ืึทืœื˜ื™ื ื’ ืงื™ื ื“ ืคึผืจืึธืฆืขืก ืงืขื ืขืŸ ื•ื™ืกืคื™ืจืŸ PTRACE_TRACEME, ื ืื›ื’ืขื’ืื ื’ืขืŸ (ื™ื•ื–ืฉืึทื•ื•ืึทืœื™) ื“ื•ืจืš ืขืงืกืึทืงื™ื•ื˜ื™ื ื’ ืขืงืกืขืง (3). ืื•ื™ืฃ ื“ื™ ืื ื“ืขืจืข ื”ืึทื ื˜, ืึท ืคืึธื˜ืขืจ ืคึผืจืึธืฆืขืก ืงืขื ืขืŸ ืึธื ื”ื™ื™ื‘ืŸ ื“ื™ื‘ืึทื’ื™ื ื’ ืึท ื™ื’ื–ื™ืกื˜ื™ื ื’ ืคึผืจืึธืฆืขืก ื ื™ืฆืŸ PTRACE_ATTACH.

ื•ื•ืขืŸ ื˜ืจื™ื™ืกื™ื ื’, ื“ืขืจ ืงื™ื ื“ ืคึผืจืึธืฆืขืก ืกื˜ืึทืคึผืก ื™ืขื“ืขืจ ืžืึธืœ ืขืก ื ืขืžื˜ ืึท ืกื™ื’ื ืึทืœ, ืึทืคึฟื™ืœื• ืื•ื™ื‘ ื“ืขืจ ืกื™ื’ื ืึทืœ ืื™ื– ืื™ื’ื ืึธืจื™ืจื˜. (ื“ื™ ื•ื™ืกื ืขื ืื™ื– SIGKILL, ื•ื•ืึธืก ืึทืจื‘ืขื˜ ื ืึธืจืžืึทืœื™.) ื“ืขืจ ืคืึธื˜ืขืจ ืคึผืจืึธืฆืขืก ื•ื•ืขื˜ ื–ื™ื™ืŸ ื ืึธื•ื˜ืึทืคื™ื™ื“ ืคื•ืŸ ื“ืขื ื“ื•ืจืš ืจื•ืคืŸ ื•ื•ืึทืจื˜ืŸ (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);
    }
}

ืžื™ืจ ืงืึธื ื˜ืจืึธืœื™ืจืŸ:

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

+0-0=5

ื ื’ืจื•ื™ืกืŸ ืฉ 'ื›ื—

Charles Hubain
ื“ืขืจืฉื˜ื™ืงืŸ ืคื•ื ื˜
ValdikSS
Philippe Teuwen
ื“ืขืจื”ืึทืกืก

, ื•ื•ืขืžืขื ืก ืืจื˜ื™ืงืœืขืŸ, ืงื•ื•ืืœืŸ ืื•ืŸ ืงืืžืขื ื˜ืืจืŸ ื”ืื‘ืŸ ืืกืืš ืžืขืจ ื’ืขื˜ื•ืŸ ื•ื•ื™ ืื™ืš ื”ืื‘ ื’ืขื˜ื•ืŸ ื“ื™ ื“ืื–ื™ืงืข ื”ืขืจื” ืฆื• ื“ืขืจืฉื™ื ืขืŸ ื“ื.

ืžืงื•ืจ: www.habr.com

ืงื•ื™ืคืŸ ืคืึทืจืœืึธื–ืœืขืš ื”ืึธืกื˜ื™ื ื’ ืคึฟืึทืจ ื–ื™ื™ื˜ืœืขืš ืžื™ื˜ DDoS ืฉื•ืฅ, VPS VDS ืกืขืจื•ื•ืขืจืก ๐Ÿ”ฅ ืงื•ื™ืคื˜ ืคืึทืจืœืขืกืœืขื›ืข ื•ื•ืขื‘ื–ื™ื™ื˜ืœ ื”ืึธืกื˜ื™ื ื’ ืžื™ื˜ DDoS ืฉื•ืฅ, VPS VDS ืกืขืจื•ื•ืขืจืก | ProHoster