2012-06-18 10 views
5

मैं ऐसे प्रोग्राम को कोड करने का प्रयास कर रहा हूं जो सिस्टम कॉल के लिए खुद को ढूंढता है। मुझे यह काम करने में मुश्किल हो रही है। मैंने खुद को एक उदाहरण बनाने के लिए एक कांटा() को कॉल करने का प्रयास किया, फिर परिणामस्वरूप बाल प्रक्रिया की निगरानी करें।सिस्टम कॉल के लिए प्रक्रिया का पता लगाने के लिए कैसे?

लक्ष्य मूल प्रक्रिया के लिए बाल प्रक्रिया द्वारा किए गए प्रत्येक सिस्टम कॉल की अनुक्रमणिका को वापस करने और स्क्रीन पर आउटपुट करने के लिए है। किसी भी तरह से यह योजना के रूप में काम नहीं कर रहा है।

#include <unistd.h>  /* for read(), write(), close(), fork() */ 
#include <fcntl.h>  /* for open() */ 
#include <stdio.h> 
#include <sys/ptrace.h> 
#include <sys/reg.h> 
#include <sys/wait.h> 
#include <sys/types.h> 


int main(int argc, char *argv[]) { 
    pid_t child; 
    long orig_eax; 
    child = fork(); 

    if (0 == child) 
    { 
     ptrace(PTRACE_TRACEME, 0, NULL, NULL); 
     if (argc != 3) { 
      fprintf(stderr, "Usage: copy <filefrom> <fileto>\n"); 
      return 1; 
     } 

     int c; 
     size_t file1_fd, file2_fd; 
     if ((file1_fd = open(argv[1], O_RDONLY)) < 0) { 
      fprintf(stderr, "copy: can't open %s\n", argv[1]); 
      return 1; 
     } 

     if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) { 
      fprintf(stderr, "copy: can't open %s\n", argv[2]); 
      return 1; 
     } 

     while (read(file1_fd, &c, 1) > 0) 
     write(file2_fd, &c, 1); 
    } 
    else 
    { 
     wait(NULL); 
     orig_eax = ptrace (PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL); 
     printf("copy made a system call %ld\n", orig_eax); 
     ptrace(PTRACE_CONT, child, NULL, NULL); 
    }   
return 0; 
} 

इस कोड को इस कोड पर आधारित था::

#include <sys/ptrace.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <linux/user.h> /* For constants 
           ORIG_EAX etc */ 
int main() 
{ 
    pid_t child; 
    long orig_eax; 
    child = fork(); 
    if(child == 0) { 
     ptrace(PTRACE_TRACEME, 0, NULL, NULL); 
     execl("/bin/ls", "ls", NULL); 
    } 
    else { 
     wait(NULL); 
     orig_eax = ptrace(PTRACE_PEEKUSER, 
          child, 4 * ORIG_EAX, 
          NULL); 
     printf("The child made a " 
       "system call %ld\n", orig_eax); 
     ptrace(PTRACE_CONT, child, NULL, NULL); 
    } 
    return 0; 
} 

इस एक के उत्पादन में है:

यहाँ कोड है

The child made a system call 11 

जिसके लिए सूचकांक है निष्पादन प्रणाली कॉल।

प्रतीक्षा के लिए आदमी पृष्ठ() के अनुसार:

All of these system calls are used to wait for state changes in a child 
of the calling process, and obtain information about the child whose 
state has changed. A state change is considered to be: the child terminated; 
the child was stopped by a signal; or the child was resumed by 
a signal. 

तरह से मैं समझता हूँ कि यह है कि हर बार जब एक सिस्टम कॉल एक उपयोगकर्ता प्रोग्राम के द्वारा उत्पन्न होता है, कर्नेल पहले अगर प्रक्रिया किया जा रहा है निरीक्षण करेंगे सिस्टम कॉल रूटीन और विराम को निष्पादित करने से पहले पता लगाया गया है जो सिग्नल के साथ प्रक्रिया करता है और माता-पिता को नियंत्रण देता है। क्या यह पहले से ही एक राज्य परिवर्तन नहीं होगा?

+2

विस्तृत करने के लिए परवाह? आप क्या होने की उम्मीद करते हैं, और वास्तव में क्या होता है? टिप्पणी जोड़ने के लिए कृपया इसे जोड़ने के लिए प्रश्न संपादित करें। –

+7

इसके अलावा, आप मूल प्रक्रिया में पहली चीज करते हैं, 'प्रतीक्षा' को कॉल कर रहे हैं। यह फ़ंक्शन बिल्कुल ठीक है, बच्चे की प्रक्रिया समाप्त होने तक प्रतीक्षा करें, जिसका अर्थ है कि 'ptrace' कॉल ऐसी प्रक्रिया का पता लगाने की कोशिश करता है जो अब मौजूद नहीं है। –

+0

[इसे देखें] [1] मुझे लगता है, यह मदद कर सकता है। [1]: http://stackoverflow.com/questions/6468896/why-is-orig-eax-provided-in-addition-to-eax –

उत्तर

0

आपके माता-पिता में आप कितनी कॉल मॉनिटर करना चाहते हैं? यदि आप एक से अधिक चाहते हैं तो आपको किसी प्रकार की लूप की आवश्यकता होगी।

नोट उदाहरण में लाइन, यह महत्वपूर्ण है:

ptrace(PTRACE_TRACEME, 0, NULL, NULL); 

man page को देखते हुए बच्चे या तो एक PTRACE_TRACEME और एक कार्यकारी करने की जरूरत है या माता-पिता PTRACE_ATTACH का उपयोग कर पता लगाने की जरूरत है। मैं अपने कोड में नहीं दिखाई:

माता पिता कांटा को फोन करके एक निशान आरंभ कर सकते हैं (2) और होने जिसके परिणामस्वरूप बच्चे को एक PTRACE_TRACEME करते हैं, (आमतौर पर) का पालन एक कार्यकारी द्वारा (3)। वैकल्पिक रूप से, माता-पिता PTRACE_ATTACH का उपयोग कर मौजूदा प्रक्रिया का पता लगा सकते हैं।

+0

@ 1der, आपकी टिप्पणी का क्या मतलब है? –

+0

मैं ट्रेसीम भाग भूल गया लेकिन फिर भी यह काम नहीं करता है। – 1der

2

आप मूल रूप से लिनक्स में स्ट्रेस बाइनरी लिखने की कोशिश कर रहे हैं, जो प्रक्रिया की सिस्टम कॉल का पता लगाता है। लिनक्स इसके लिए ptrace (2) सिस्टम कॉल प्रदान करता है। ptrace system call 4 बहस लेता है और पहला बहस बताता है कि आपको क्या करना है। ओएस सिग्नल के साथ मूल प्रक्रिया के साथ संचार करता है और सिगस्टॉप भेजकर बाल प्रक्रिया रोक दी जाती है। मोटे तौर पर आपको नीचे दिए गए चरणों का पालन करना होगा।

if(fork() == 0) 

{ 
    //child process 

    ptrace(PTRACE_TRACEME, 0,0, 0); 
    exec(...); 
} 
else 
{ 

start: 

    wait4(...); 

    if (WIFSIGNALED(status)) { 
     //done 
    } 
    if (WIFEXITED(status)) { 
     //done 
    } 
    if(flag == startup) 
    { 
     flag = startupdone; 

     ptrace(PTRACE_SYSCALL, pid,0, 0) ; 
     goto start; 
    } 
    if (if (WSTOPSIG(status) == SIGTRAP) {) { 
      //extract the register 
      ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) 

    } 

नोट करें कि पंजीकरण पढ़ने और व्याख्या आपके आर्किटेक्चर पर निर्भर करेगी। उपर्युक्त कोड यह सही है कि इसे सही तरीके से प्राप्त करने के लिए आपको एक उदाहरण दिया गया है। आगे समझने के लिए स्ट्रेस कोड पर एक नज़र डालें।

+0

मैन पेज के अनुसार, केवल PTRACEME का पहला तर्क उपयोग किया जाता है और बाकी को अनदेखा किया जाता है। (Char *) 1 के साथ क्या है? – 1der

+0

हाँ आप सही addr को अनदेखा कर रहे हैं, इसे संपादित किया। –

5

समस्या यह है कि जब बच्चे ptrace(TRACEME) कॉल यह अपने आप सेट का पता लगाने के लिए, लेकिन वास्तव में नहीं रुकती है - जब तक यह कहता है exec (इस स्थिति में यह एक SIGTRAP साथ बंद हो जाता है) यह चलती है, या यह कुछ अन्य हो जाता है संकेत। तो आपके माता-पिता को यह देखने के लिए कि एक निष्पादन कॉल के बिना यह क्या करता है, आपको बच्चे को सिग्नल प्राप्त करने की व्यवस्था करने की आवश्यकता है।ऐसा करने का सबसे आसान तरीका संभव है कि ptrace(TRACEME)

अब माता-पिता में आप बस प्रतीक्षा करें (एक बार) और मान लें कि बच्चा अब सिस्टम कॉल पर रुक गया है । यदि यह सिग्नल पर रुक गया तो यह मामला नहीं होगा, इसलिए आपको बच्चे की स्थिति प्राप्त करने के लिए wait(&status) पर कॉल करने की आवश्यकता है और यह देखने के लिए WIFSTOPPED(status) और WSTOPSIG(status) पर कॉल करें। यदि यह एक सिस्कल के कारण बंद हो गया है, तो संकेत सिगट्रैप होगा।

यदि आप क्लाइंट में एकाधिक सिस्टम कॉल देखना चाहते हैं, तो आपको यह सब एक लूप में करना होगा; कुछ की तरह:

while(1) { 
    wait(&status); 
    if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { 
     // stopped before or after a system call -- query the child and print out info 
    } 
    if (WIFEXITED(status) || WIFSIGNALLED(status)) { 
     // child has exited or terminated 
     break; 
    } 
    ptrace(PTRACE_SYSCALL, 0, 0, 0); // ignore any signal and continue the child 
} 

ध्यान दें कि यह प्रत्येक प्रणाली कॉल के लिए दो बार बंद हो जाएगा - एक बार सिस्टम कॉल और दूसरी बार के तुरंत बाद सिस्टम कॉल पूरा करता है से पहले।

0

बस एक साथ डाल क्या क्रिस डोड ने कहा: "। किसी तरह यह योजना के अनुसार काम नहीं कर रहा"

#include <unistd.h>  /* for read(), write(), close(), fork() */ 
#include <fcntl.h>  /* for open() */ 
#include <stdio.h> 
#include <sys/ptrace.h> 
#include <sys/reg.h> 
#include <sys/wait.h> 
#include <sys/types.h> 

int main(int argc, char *argv[]) { 
pid_t child; 
int status; 
long orig_eax; 
child = fork(); 

if (0 == child) 
{ 
    ptrace(PTRACE_TRACEME, 0, NULL, NULL); 
    raise(SIGCONT); 
    if (argc != 3) { 
     fprintf(stderr, "Usage: copy <filefrom> <fileto>\n"); 
     return 1; 
    } 

    int c; 
    size_t file1_fd, file2_fd; 
    if ((file1_fd = open(argv[1], O_RDONLY)) < 0) { 
     fprintf(stderr, "copy: can't open %s\n", argv[1]); 
     return 1; 
    } 

    if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) { 
     fprintf(stderr, "copy: can't open %s\n", argv[2]); 
     return 1; 
    } 

    while (read(file1_fd, &c, 1) > 0) 
     write(file2_fd, &c, 1); 
} 
else 
{ 
    while(1){ 
     wait(&status); 
     if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){ 
      orig_eax = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_EAX, NULL); 
      printf("copy made a system call %ld\n", orig_eax); 
     } 
     if(WIFEXITED(status) || WIFSIGNALED(status)){ 
      break; 
     } 

     ptrace(PTRACE_SYSCALL, child, 0, 0); 
    }   
} 
return 0; 
}