it-swarm.dev

خلق الخفي في لينكس

في نظام Linux ، أريد إضافة برنامج خفي لا يمكن إيقافه والذي يراقب تغييرات نظام الملفات. في حالة اكتشاف أي تغييرات ، يجب أن تكتب المسار إلى وحدة التحكم حيث تم بدء تشغيله بالإضافة إلى سطر جديد.

لدي بالفعل نظام لتغيير كود الملفات جاهز تقريبًا ولكن لا يمكنني معرفة كيفية إنشاء برنامج خفي.

شفرتي من هنا: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

ماذا تفعل بعد الشوكة؟

int main (int argc, char **argv) {

  pid_t pID = fork();
  if (pID == 0)  {              // child
          // Code only executed by child process    
      sIdentifier = "Child Process: ";
    }
    else if (pID < 0) {
        cerr << "Failed to fork" << endl;
        exit(1);
       // Throw exception
    }
    else                                   // parent
    {
      // Code only executed by parent process

      sIdentifier = "Parent Process:";
    }       

    return 0;
}
86
chrisMe

في نظام Linux ، أريد إضافة برنامج خفي لا يمكن إيقافه والذي يراقب تغييرات نظام الملفات. إذا تم الكشف عن أي تغييرات ، فيجب أن تكتب المسار إلى وحدة التحكم حيث بدأت + سطر جديد.

تعمل الشياطين في الخلفية و (عادة ...) لا تنتمي إلى TTY لهذا السبب لا يمكنك استخدام stdout/stderr بالطريقة التي تريدها على الأرجح. عادةً ما يتم استخدام البرنامج الخفي syslog (syslogd) لتسجيل الرسائل إلى الملفات (تصحيح ، خطأ ، ...).

بالإضافة إلى ذلك ، هناك بعض {الخطوات المطلوبة لإخفاء العملية.


إذا كنت أتذكر بشكل صحيح هذه الخطوات هي:

  • شوكة إيقاف العملية الأصل واتركها تنتهي إذا كان التفرع ناجحًا. -> بسبب إنهاء العملية الأصل ، تعمل العملية الفرعية الآن في الخلفية.
  • setsid - إنشاء جلسة جديدة. تصبح عملية الاستدعاء هي قائد الجلسة الجديدة وقائد مجموعة العمليات في مجموعة العمليات الجديدة. يتم فصل العملية الآن من محطة التحكم الخاصة بها (CTTY).
  • إمساك الإشارات - تجاهل و/أو التعامل مع الإشارات.
  • fork مرة أخرى ودع العملية الأصل تنتهي لضمان التخلص من العملية الرائدة للجلسة. (يمكن لقادة الجلسة فقط الحصول على TTY مرة أخرى.)
  • chdir - تغيير دليل العمل من الخفي.
  • umask - تغيير قناع وضع الملف وفقًا لاحتياجات البرنامج الخفي.
  • close - أغلق جميع واصفات الملفات المفتوحة التي قد تكون موروثة من العملية الأصل.

لمنحك نقطة بداية: انظر إلى رمز الهيكل العظمي الذي يعرض الخطوات الأساسية:

/*
 * daemonize.c
 * This example daemonizes a process, writes a few log messages,
 * sleeps 20 seconds and terminates afterwards.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>

static void skeleton_daemon()
{
    pid_t pid;

    /* Fork off the parent process */
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* On success: The child process becomes session leader */
    if (setsid() < 0)
        exit(EXIT_FAILURE);

    /* Catch, ignore and handle signals */
    //TODO: Implement a working signal handler */
    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    /* Fork off for the second time*/
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* Set new file permissions */
    umask(0);

    /* Change the working directory to the root directory */
    /* or another appropriated directory */
    chdir("/");

    /* Close all open file descriptors */
    int x;
    for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
    {
        close (x);
    }

    /* Open the log file */
    openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
    skeleton_daemon();

    while (1)
    {
        //TODO: Insert daemon code here.
        syslog (LOG_NOTICE, "First daemon started.");
        sleep (20);
        break;
    }

    syslog (LOG_NOTICE, "First daemon terminated.");
    closelog();

    return EXIT_SUCCESS;
}


  • ترجمة الكود: gcc -o firstdaemon daemonize.c
  • بدء البرنامج الخفي: ./firstdaemon
  • تحقق مما إذا كان كل شيء يعمل بشكل صحيح: ps -xj | grep firstdaemon

  • يجب أن يكون الإخراج مشابهًا لهذا:

 + ------ + ------ + ------ + ------ + ----- + ------- + - ---- + ------ + ------ + ----- + 
 | PPID | PID | PGID | سيد | TTY | TPGID | STAT | UID | الوقت | CMD | 
 + ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- + 
 | 1 | 3387 | 3386 | 3386 | ؟ | -1 | S | 1000 | 0:00 | ./ | 
 + ------ + ------ + + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- + 

ما يجب أن تراه هنا هو:

  • البرنامج الخفي لا يحتوي على محطة مراقبة (TTY =؟)
  • معرف العملية الأصل (PPID) هو 1 (عملية التهيئة)
  • PID! = SID مما يعني أن عمليتنا ليست هي رئيس الجلسة
    (بسبب الشوكة الثانية ())
  • لأن PID! = SID عمليتنا لا يمكن السيطرة على TTY مرة أخرى

قراءة سجل النظام:

  • حدد موقع ملف syslog الخاص بك. الألغام هنا: /var/log/syslog
  • افعل: grep firstdaemon /var/log/syslog

  • يجب أن يكون الإخراج مشابهًا لهذا:

 firstdaemon [3387]: بدأ البرنامج الخفي الأول. 
 firstdaemon [3387]: تم إنهاء البرنامج الخفي الأول. 


ملاحظة: في الواقع ، قد ترغب أيضًا في تنفيذ معالج إشارة وإعداد التسجيل بشكل صحيح (الملفات ، مستويات السجل ...).

قراءة متعمقة:

182
Pascal Werkl

لا يمكنك إنشاء عملية في نظام Linux لا يمكن قتلها. يمكن للمستخدم الجذر (uid = 0) إرسال إشارة إلى عملية ، وهناك إشارتان لا يمكن اكتشافهما ، SIGKILL = 9 ، SIGSTOP = 19. ويمكن أن تؤدي الإشارات الأخرى (عندما تكون غير معلمة) إلى إنهاء العملية.

قد ترغب في الحصول على وظيفة خفية أكثر عمومية ، حيث يمكنك تحديد اسم للبرنامج/الخفي الخاص بك ، ومسار لتشغيل البرنامج (ربما "/" أو "/ tmp"). قد ترغب أيضًا في توفير ملف (ملفات) لـ stderr و stdout (وربما مسار تحكم باستخدام stdin).

فيما يلي ما يلي:

#include <stdio.h>    //printf(3)
#include <stdlib.h>   //exit(3)
#include <unistd.h>   //fork(3), chdir(3), sysconf(3)
#include <signal.h>   //signal(3)
#include <sys/stat.h> //umask(3)
#include <syslog.h>   //syslog(3), openlog(3), closelog(3)

وهنا هي وظيفة أكثر عمومية ،

int
daemonize(char* name, char* path, char* outfile, char* errfile, char* infile )
{
    if(!path) { path="/"; }
    if(!name) { name="medaemon"; }
    if(!infile) { infile="/dev/null"; }
    if(!outfile) { outfile="/dev/null"; }
    if(!errfile) { errfile="/dev/null"; }
    //printf("%s %s %s %s\n",name,path,outfile,infile);
    pid_t child;
    //fork, detach from process group leader
    if( (child=fork())<0 ) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if (child>0) { //parent
        exit(EXIT_SUCCESS);
    }
    if( setsid()<0 ) { //failed to become session leader
        fprintf(stderr,"error: failed setsid\n");
        exit(EXIT_FAILURE);
    }

    //catch/ignore signals
    signal(SIGCHLD,SIG_IGN);
    signal(SIGHUP,SIG_IGN);

    //fork second time
    if ( (child=fork())<0) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if( child>0 ) { //parent
        exit(EXIT_SUCCESS);
    }

    //new file permissions
    umask(0);
    //change to path directory
    chdir(path);

    //Close all open file descriptors
    int fd;
    for( fd=sysconf(_SC_OPEN_MAX); fd>0; --fd )
    {
        close(fd);
    }

    //reopen stdin, stdout, stderr
    stdin=fopen(infile,"r");   //fd=0
    stdout=fopen(outfile,"w+");  //fd=1
    stderr=fopen(errfile,"w+");  //fd=2

    //open syslog
    openlog(name,LOG_PID,LOG_DAEMON);
    return(0);
}

إليكم برنامج نموذجي ، يصبح خفيًا ، ويخيم حوله ، ثم يغادر.

int
main()
{
    int res;
    int ttl=120;
    int delay=5;
    if( (res=daemonize("mydaemon","/tmp",NULL,NULL,NULL)) != 0 ) {
        fprintf(stderr,"error: daemonize failed\n");
        exit(EXIT_FAILURE);
    }
    while( ttl>0 ) {
        //daemon code here
        syslog(LOG_NOTICE,"daemon ttl %d",ttl);
        sleep(delay);
        ttl-=delay;
    }
    syslog(LOG_NOTICE,"daemon ttl expired");
    closelog();
    return(EXIT_SUCCESS);
}

لاحظ أن SIG_IGN يشير إلى التقاط الإشارة وتجاهلها. يمكنك إنشاء معالج إشارة يمكنه تسجيل استلام الإشارة ، وتعيين العلامات (مثل إشارة للإشارة إلى إيقاف تشغيل محكم).

7
ChuckCottrill

يمكنني التوقف عند الشرط الأول "برنامج خفي لا يمكن إيقافه ..."

غير ممكن صديقي ومع ذلك ، يمكنك تحقيق ذلك باستخدام أداة أفضل بكثير ، وهي وحدة kernel.

http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring

جميع الشياطين يمكن وقفها. يتم إيقاف بعضها بسهولة أكثر من غيرها. حتى الزوج الخفي مع الشريك في الضغط باستمرار ، حيث يمكن إيقاف الشريك في حالة فقده. عليك فقط العمل بجهد أكبر.

5
Edwin Buck

حاول استخدام دالة daemon:

#include <unistd.h>

int daemon(int nochdir, int noclose);

من صفحة الرجل :

الوظيفة daemon () مخصصة للبرامج التي ترغب في فصل نفسها عن وحدة التحكم وتشغيلها في الخلفية كشياطين نظام.

إذا كانت nochdir تساوي صفر ، فإن daemon () يغير دليل العمل الحالي لعملية الاستدعاء إلى الدليل الجذر ("/") ؛ خلاف ذلك ، يتم ترك دليل العمل الحالي دون تغيير.

إذا كان noclose يساوي صفر ، يعيد daemon () إعادة توجيه الإدخال القياسي والإخراج القياسي والخطأ القياسي إلى/dev/null ؛ خلاف ذلك ، يتم إجراء أية تغييرات على واصفات الملفات هذه.

5
weiyin

إذا كان تطبيقك واحدًا من:

{
  ".sh": "bash",
  ".py": "python",
  ".rb": "Ruby",
  ".coffee" : "coffee",
  ".php": "php",
  ".pl" : "Perl",
  ".js" : "node"
}

ولا تمانع في تبعية NodeJS ثم تثبيت NodeJS ثم:

npm install -g pm2

pm2 start yourapp.yourext --name "fred" # where .yourext is one of the above

pm2 start yourapp.yourext -i 0 --name "fred" # run your app on all cores

pm2 list

للاحتفاظ بجميع التطبيقات قيد التشغيل عند إعادة التشغيل (و daemonise pm2):

pm2 startup

pm2 save

الآن انت تستطيع:

service pm2 stop|restart|start|status

(يسمح لك أيضًا بسهولة بمشاهدة تغييرات الرمز في دليل التطبيق وإعادة تشغيل عملية التطبيق تلقائيًا عند حدوث تغيير الرمز)

5
danday74

عن طريق استدعاء شوكة () قمت بإنشاء عملية تابعة. في حالة نجاح الشوكة (إرجاع الشوكة تنفيذ PID غير صفري) سيستمر تنفيذ من هذه النقطة من داخل العملية التابعة. في هذه الحالة ، نريد إنهاء عملية الوالدين بأمان ثم مواصلة عملنا في العملية الفرعية.

ربما هذا سوف يساعد: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html

2
Doug Morrow

الخفي هو مجرد عملية في الخلفية. إذا كنت ترغب في بدء تشغيل البرنامج عندما يقوم نظام التشغيل بالتمهيد ، في نظام التشغيل linux ، يمكنك إضافة أمر start الخاص بك إلى /etc/rc.d/rc.local (التشغيل بعد جميع البرامج النصية الأخرى) أو /etc/startup.sh

في Windows ، تقوم بإجراء خدمة وتسجيل الخدمة ، ثم تعيينها لبدء التشغيل تلقائيًا عند التمهيد في الإدارة -> لوحة الخدمات.

1
Magn3s1um