linux - टरफ - हिन्दी में लिनक्स बूटिंग प्रक्रिया



द्विआधारी निष्पादन के दौरान सभी लिनक्स सिस्टम को हुक कैसे करें (1)

एलडी में रैपिंग के लिए एक विकल्प है, मैन्युअल से उद्धरण:

- लपेटें प्रतीक

प्रतीक के लिए आवरण फ़ंक्शन का उपयोग करें प्रतीक के लिए कोई भी अनिर्धारित संदर्भ __wrap_symbol के लिए हल किया जाएगा। __real_symbol के लिए कोई भी अनिर्धारित संदर्भ प्रतीक को हल किया जाएगा। यह सिस्टम फ़ंक्शन के लिए आवरण प्रदान करने के लिए उपयोग किया जा सकता है। आवरण समारोह को __wrap_symbol कहा जाना चाहिए। यदि वह सिस्टम फ़ंक्शन को कॉल करना चाहता है, तो उसे __real_symbol पर कॉल करना चाहिए।

यह सिस्टम कॉल के साथ भी ठीक काम करता है readlink साथ यहां एक उदाहरण है:

#include <stdio.h>
#include <string.h>
#include <unistd.h>

ssize_t __real_readlink(const char *path, char *buf, size_t bufsiz);

ssize_t __wrap_readlink(const char *path, char *buf, size_t bufsiz) {
    puts("Hello from the wrapped readlink :з");
    __real_readlink(path, buf, bufsiz);
}

int main(void) {
    const char testLink[] = "/usr/bin/gnome-www-browser";
    char buf[256];
    memset(buf, 0, sizeof(buf));
    readlink(testLink, buf, sizeof(buf)-1);
    puts(buf);
}

संकलक के उपयोग से लिंकर को विकल्प पास करने के -Wl विकल्प:

$ gcc test.c -o a -Wl,--wrap=readlink
$ ./a
Hello from the wrapped readlink 
/etc/alternatives/gnome-www-browser

यह विचार यह है कि __wrap_func आपका फ़ंक्शन आवरण है। __real_func लिंकर वास्तविक फ़ंक्शन __real_func साथ लिंक करेगा। और कोड में __wrap_func लिए हर कॉल को __wrap_func बदल दिया जाएगा।

यूपीडी: कोई यह देख सकता है कि एक द्विआधारी संकलित किया जा रहा है, एक अन्य readlink कॉल readlink , जिसे इंटरसेप्टेड नहीं किया जा रहा है। कारण समझने के लिए, बस थोड़ा सा प्रयोग करें - ऑब्जेक्ट फ़ाइल में कोड संकलित करें, और प्रतीकों की सूची बनाएं, जैसे:

$ gcc test.c -c -o a.o -Wl,--wrap=readlink
$ nm a.o
0000000000000037 T main
                 U memset
                 U puts
                 U readlink
                 U __real_readlink
                 U __stack_chk_fail
0000000000000000 T __wrap_readlink

यहां दिलचस्प बात यह है कि आप मुख्य फ़ंक्शन में प्रवेश करने से पहले स्ट्रैस के साथ देखे जा रहे कार्यों के एक समूह के संदर्भ नहीं देखेंगे - जैसे कि uname() , brk() , access() , आदि। यह मुख्य कारण है ऐसा पहला कोड नहीं है जिसे आपके बाइनरी में बुलाया जा रहा है _start साथ थोड़ा सा अनुसंधान आपको दिखाएगा, कि पहला कार्य _start नामक है।

अब, एक और उदाहरण दें - _start फ़ंक्शन को ओवरराइड करें:

$ cat test2.c
#include <stdio.h>
#include <unistd.h>

void _start() {
        puts("Hello");
        _exit(0);
}
$ gcc test2.c -o a -nostartfiles
$ strace ./a
execve("./a", ["./a"], [/* 69 vars */]) = 0
brk(0)                                  = 0x150c000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3ece55d000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=177964, ...}) = 0
mmap(NULL, 177964, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3ece531000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0
mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3ecdf78000
mprotect(0x7f3ece133000, 2093056, PROT_NONE) = 0
mmap(0x7f3ece332000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7f3ece332000
mmap(0x7f3ece338000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f3ece338000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3ece530000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3ece52e000
arch_prctl(ARCH_SET_FS, 0x7f3ece52e740) = 0
mprotect(0x7f3ece332000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f3ece55f000, 4096, PROT_READ) = 0
munmap(0x7f3ece531000, 177964)          = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 10), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3ece55c000
write(1, "Hello\n", 6Hello
)                  = 6
exit_group(0)                           = ?
+++ exited with 0 +++
$

यह क्या था?! हम द्विआधारी में पहले फ़ंक्शन को ओवरराइड कर चुके हैं, और अभी भी सिस्टम कॉल देख रहे हैं - क्यों?

दरअसल यह इसलिए है क्योंकि कॉल आपके आवेदन द्वारा नहीं कार्यान्वित की जा रही है, बल्कि आपके आवेदन को मेमोरी में लोड होने से पहले कर्नेल द्वारा, और चलाने की अनुमति है।

यूपीडी: जैसा हमने पहले देखा था, फ़ंक्शन आपके एप्लिकेशन द्वारा नहीं बुलाए गए हैं। ईमानदारी से, मैं अपने एप के लिए शेल कॉल execve होने के बाद execve बायनेरिज़ के लिए क्या किया जा रहा execve , लेकिन सूची से ऐसा लगता है कि आप प्रत्येक कॉल को देख रहे हैं जो कि कर्नेल द्वारा किया जा रहा है - बिना किसी साइड एप्लीकेशन के जैसे, डायनेमिक लिंकर की तरह 'स्टेटिक बायनेरिज़ के लिए आवश्यक नहीं है (और क्योंकि brk जैसी फ़ंक्शन जैसी डेटा सेगमेंट के साथ काम करता है)

जो कुछ भी हो, आप निश्चित रूप से इस व्यवहार को संशोधित नहीं कर सकते, यह आसान है, आपको कुछ हैकिंग की आवश्यकता होगी। क्योंकि अगर आप आसानी से उस कोड के फ़ंक्शन को ओवरराइड कर सकते हैं जो आपके द्विआधारी चाल से पहले निष्पादित होता है - यानी अन्य द्विआधारी से - यह सुरक्षा में एक बड़ा ब्लैक होल होगा, बस कल्पना करें: एक बार जब आपको जड़ अधिकार की आवश्यकता होती है, तो आप फ़ंक्शन को ओवरराइड कर देते हैं एक को अपना कोड निष्पादित करने के लिए, थोड़ी देर प्रतीक्षा करें, जबकि रूट के साथ कुछ डेमन एक स्क्रिप्ट निष्पादित होते हैं, और इस तरह आपके कोड को खेलने में ट्रिगर होता है।

मैं लिनक्स सिस्टम कॉल के डिफ़ॉल्ट व्यवहार को संशोधित करने का प्रयास कर रहा हूं फिलहाल मैं हुक करने की कोशिश कर रहा हूं और वास्तव में प्रारंभ होने से पहले एक सरल प्रिंट स्टेटमेंट जोड़ता हूं। मैं जीसीसी लिंकर के मानक 'रैप' विकल्प के बारे में जानता हूं और इसे कैसे लपेट करने के लिए इस्तेमाल किया जा सकता है जीसीसी लिंकर विकल्प लिंक करें यह पूरी तरह से खुले (), fstat (), fwrite () आदि (जहां मैं वास्तव में libc wrappers hooking हूँ) के लिए काम करता है।

अद्यतन करें:

सीमा यह है कि इस दृष्टिकोण के साथ सभी सिस्टम कॉलों को झुकाया नहीं जाता है यह समझाने के लिए कि हम एक साधारण स्थिर संकलित बाइनरी लेते हैं। जब हम रैपर जोड़ने की कोशिश करते हैं, तो वे कॉल से प्रभावी हो रहे हैं जो हम मुख्य () के बाद पेश करते हैं (कृपया नीचे दिखाए गए स्ट्रेस आउटपुट देखें)

> strace ./sample 

execve("./sample", ["./sample"], [/* 72 vars */]) = 0
uname({sys="Linux", node="kumar", ...})   = 0
brk(0)                                  = 0x71f000
brk(0x7201c0)                           = 0x7201c0
arch_prctl(ARCH_SET_FS, 0x71f880)       = 0
readlink("/proc/self/exe", "/home/admin/sample"..., 4096) = 41
brk(0x7411c0)                           = 0x7411c0
brk(0x742000)                           = 0x742000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbcc54d1000
write(1, "Hello from the wrapped readlink "..., 36Hello from the wrapped readlink 
) = 36
readlink("/usr/bin/gnome-www-browser", "/etc/alternatives/gnome-www-brow"..., 255) = 35
write(1, "/etc/alternatives/gnome-www-brow"..., 36/etc/alternatives/gnome-www-browser
) = 36
exit_group(36)                          = ?
+++ exited with 36 +++

अगर हम द्विपदीय को ध्यान से पहले "अन-इंटरसेप्टेड" कॉल रीडलिंक () (सिस्टम कॉल 89 या 0x59) इन लाइनों से आता है - कुछ लिंकर से संबंधित कोड भाग (यानी _ डीएल_गेट_ओरीगिन ) इसके कार्यशीलता के लिए एक पठनलिंक () करता है। ये अंतर्निहित syscall (यद्यपि बाइनरी कोड में मौजूद है) कभी हमारे "लपेटें" दृष्टिकोण से जुदा नहीं हो रहा है

  000000000051875c <_dl_get_origin>:
  51875c:       b8 59 00 00 00          mov    $0x59,%eax
  518761:       55                      push   %rbp
  518762:       53                      push   %rbx
  518763:       48 81 ec 00 10 00 00    sub    $0x1000,%rsp
  51876a:       48 89 e6                mov    %rsp,%rsi
  51876d:       0f 05                   syscall 

रीडलिंक () (जैसे सभी निहित लोगों को शामिल किया गया है) जैसे सिस्टम कॉल के लिए रैपिंग विचार का विस्तार करना है?






binutils