په macOS کې د پروسو او د کرنل توسیعونو ساتلو څرنګوالی

سلام، حبر! نن زه غواړم په دې اړه وغږیږم چې تاسو څنګه کولی شئ په macOS کې د برید کونکو لخوا د بریدونو څخه پروسې خوندي کړئ. د مثال په توګه ، دا د انټي ویروس یا بیک اپ سیسټم لپاره ګټور دی ، په ځانګړي توګه ځکه چې د macOS لاندې د پروسې "وژنې" لپاره ډیری لارې شتون لري. د دې په اړه ولولئ او د کټ لاندې د ساتنې میتودونه.

په macOS کې د پروسو او د کرنل توسیعونو ساتلو څرنګوالی

د پروسې "وژنې" لپاره کلاسیک لاره

د پروسې "وژلو" لپاره یوه پیژندل شوې لاره دا ده چې پروسې ته د سیګکیل سیګنال لیږل کیږي. د باش له لارې تاسو کولی شئ د وژلو لپاره معیاري "kill -SIGKILL PID" یا "pkill -9 NAME" ته زنګ ووهئ. د "وژنې" کمانډ د UNIX له ورځو راهیسې پیژندل شوی او نه یوازې په macOS کې شتون لري ، بلکه د UNIX په څیر نورو سیسټمونو کې هم شتون لري.

لکه څنګه چې د UNIX په څیر سیسټمونو کې، macOS تاسو ته اجازه درکوي چې پروسې ته کوم سیګنالونه ودروي پرته له دوو - SIGKILL او SIGSTOP. دا مقاله به په ابتدايي توګه د SIGKILL سیګنال ته د سیګنال په توګه تمرکز وکړي چې د پروسې د وژلو لامل کیږي.

د macOS مشخصات

په MacOS کې، په XNU کرنل کې د وژنې سیسټم زنګ د psignal(SIGKILL،...) فنکشن ته زنګ وهي. راځئ هڅه وکړو چې وګورو چې په یوزر اسپیس کې د کارونکي نور عملونه د سیګنال فنکشن لخوا ویل کیدی شي. راځئ چې د کرنل په داخلي میکانیزمونو کې د سیګنال فنکشن ته زنګونه له مینځه یوسو (که څه هم دوی ممکن غیر معمولي وي، موږ به یې د بلې مقالې لپاره پریږدو 🙂 - د لاسلیک تایید، د حافظې تېروتنې، د وتلو / ختمولو اداره کول، د فایل محافظت سرغړونه، او نور .

راځئ چې بیاکتنه د فنکشن او اړوند سیسټم زنګ سره پیل کړو د پایلوډ سره ختمول. دا لیدل کیدی شي چې د کلاسیک وژنې کال سربیره، یو بدیل طریقه شتون لري چې د MacOS عملیاتي سیسټم لپاره ځانګړی دی او په BSD کې نه موندل کیږي. د دواړو سیسټم کالونو عملیاتي اصول هم ورته دي. دا د کرنل فنکشن psignal ته مستقیم زنګونه دي. دا هم په یاد ولرئ چې د پروسې له وژلو دمخه، د "کین سیګنال" چک ترسره کیږي - ایا پروسه کولی شي بل پروسې ته سیګنال واستوي؛ سیسټم هیڅ غوښتنلیک ته اجازه نه ورکوي چې د سیسټم پروسې وژني، د بیلګې په توګه.

static int
terminate_with_payload_internal(struct proc *cur_proc, int target_pid, uint32_t reason_namespace,
				uint64_t reason_code, user_addr_t payload, uint32_t payload_size,
				user_addr_t reason_string, uint64_t reason_flags)
{
...
	target_proc = proc_find(target_pid);
...
	if (!cansignal(cur_proc, cur_cred, target_proc, SIGKILL)) {
		proc_rele(target_proc);
		return EPERM;
	}
...
	if (target_pid == cur_proc->p_pid) {
		/*
		 * psignal_thread_with_reason() will pend a SIGKILL on the specified thread or
		 * return if the thread and/or task are already terminating. Either way, the
		 * current thread won't return to userspace.
		 */
		psignal_thread_with_reason(target_proc, current_thread(), SIGKILL, signal_reason);
	} else {
		psignal_with_reason(target_proc, SIGKILL, signal_reason);
	}
...
}

په لاره اچول شوی

د سیسټم په پیل کې د ډیمونونو رامینځته کولو معیاري لاره او د دوی ژوند کنټرول پیل شو. مهرباني وکړئ په یاد ولرئ چې سرچینې د macOS 10.10 پورې د لانچټیکل زاړه نسخې لپاره دي ، د کوډ مثالونه د توضیحي موخو لپاره چمتو شوي. عصري لانچکټیل د XPC له لارې لانچ شوي سیګنالونه لیږي ، لانچ سیټل منطق دې ته لیږدول شوی.

راځئ وګورو چې دقیقا غوښتنلیکونه څنګه ودرول شوي. د SIGTERM سیګنال لیږلو دمخه، غوښتنلیک هڅه کیږي چې د "proc_terminate" سیسټم کال په کارولو سره ودرول شي.

<launchctl src/core.c>
...
	error = proc_terminate(j->p, &sig);
	if (error) {
		job_log(j, LOG_ERR | LOG_CONSOLE, "Could not terminate job: %d: %s", error, strerror(error));
		job_log(j, LOG_NOTICE | LOG_CONSOLE, "Using fallback option to terminate job...");
		error = kill2(j->p, SIGTERM);
		if (error) {
			job_log(j, LOG_ERR, "Could not signal job: %d: %s", error, strerror(error));
		} 
...
<>

د هوډ لاندې، proc_terminate، د دې نوم سره سره، نه یوازې د SIGTERM سره psignal، بلکې SIGKILL هم لیږلی شي.

غیر مستقیم وژنه - د سرچینې حد

یو ډیر په زړه پوری قضیه په بل سیسټم کال کې لیدل کیدی شي پروسه_پالیسی. د دې سیسټم کال یو عام کارول د غوښتنلیک سرچینې محدودول دي ، لکه د انډیکسر لپاره د CPU وخت او حافظې کوټې محدودوي ترڅو سیسټم د فایل کیچ کولو فعالیتونو لخوا د پام وړ ورو نه شي. که یو غوښتنلیک د سرچینې حد ته رسیدلی وي، لکه څنګه چې د proc_apply_resource_actions فعالیت څخه لیدل کیدی شي، د SIGKILL سیګنال پروسې ته لیږل کیږي.

که څه هم دا سیسټم زنګ کولی شي په احتمالي توګه یوه پروسه ووژني، سیسټم په سمه توګه د پروسې حقونه نه دي چک کړي چې د سیسټم کال غږوي. په حقیقت کې چک کول شتون درلود, مګر دا د دې حالت څخه د تیریدو لپاره د بدیل بیرغ PROC_POLICY_ACTION_SET کارولو لپاره کافی دی.

لدې امله، که تاسو د غوښتنلیک د CPU کارولو کوټه "محدود" کړئ (د مثال په توګه، یوازې 1 ns ته اجازه ورکول)، نو تاسو کولی شئ په سیسټم کې هر ډول پروسې وژنئ. پدې توګه ، مالویر کولی شي په سیسټم کې هر ډول پروسه وژني ، پشمول د انټي ویروس پروسې. همدارنګه په زړه پورې اغیزه هغه وخت رامینځته کیږي کله چې د pid 1 (launchctl) سره پروسه وژني - د کرنل ویره کله چې د SIGKILL سیګنال پروسس کولو هڅه کوي :)

په macOS کې د پروسو او د کرنل توسیعونو ساتلو څرنګوالی

ستونزه څنګه حل کړو؟

د پروسې د وژل کیدو څخه د مخنیوي ترټولو ساده لاره د سیسټم کال جدول کې د فنکشن پوائنټر ځای په ځای کول دي. له بده مرغه، دا طریقه د ډیری دلیلونو لپاره غیر معمولي ده.

لومړی، هغه سمبول چې د سیسینټ د حافظې موقعیت کنټرولوي نه یوازې د XNU کرنل سمبول لپاره شخصي دی، مګر د کرنل سمبولونو کې نشي موندل کیدی. تاسو باید د هیوریسټیک لټون میتودونه وکاروئ ، لکه په متحرک ډول د فنکشن جلا کول او په دې کې د پوائنټر لټون.

دوهم، په جدول کې د ننوتلو جوړښت په هغه بیرغونو پورې اړه لري چې د کرنل سره جوړه شوې وه. که د CONFIG_REQUIRES_U32_MUNGING بیرغ اعلان شي، د جوړښت اندازه به بدل شي - یو اضافي ساحه به اضافه شي sy_arg_munge32. دا اړینه ده چې یو اضافي چک ترسره کړئ ترڅو معلومه کړي چې کوم بیرغ د کوم بیرغ سره جوړ شوی، یا په بدیل توګه، د پیژندل شویو کسانو په وړاندې د فعالیت پوائنټر چیک کړئ.

struct sysent {         /* system call table */
        sy_call_t       *sy_call;       /* implementing function */
#if CONFIG_REQUIRES_U32_MUNGING || (__arm__ && (__BIGGEST_ALIGNMENT__ > 4))
        sy_munge_t      *sy_arg_munge32; /* system call arguments munger for 32-bit process */
#endif
        int32_t         sy_return_type; /* system call return types */
        int16_t         sy_narg;        /* number of args */
        uint16_t        sy_arg_bytes;   /* Total size of arguments in bytes for
                                         * 32-bit system calls
                                         */
};

خوشبختانه، د MacOS په عصري نسخو کې، ایپل د پروسو سره کار کولو لپاره نوی API چمتو کوي. د پای ټکی امنیت API پیرودونکو ته اجازه ورکوي چې نورو پروسو ته ډیری غوښتنې تصویب کړي. په دې توګه، تاسو کولی شئ پروسو ته هر ډول سیګنالونه بند کړئ، په شمول د SIGKILL سیګنال، د پورته ذکر شوي API په کارولو سره.

#include <bsm/libbsm.h>
#include <EndpointSecurity/EndpointSecurity.h>
#include <unistd.h>

int main(int argc, const char * argv[]) {
    es_client_t* cli = nullptr;
    {
        auto res = es_new_client(&cli, ^(es_client_t * client, const es_message_t * message) {
            switch (message->event_type) {
                case ES_EVENT_TYPE_AUTH_SIGNAL:
                {
                    auto& msg = message->event.signal;
                    auto target = msg.target;
                    auto& token = target->audit_token;
                    auto pid = audit_token_to_pid(token);
                    printf("signal '%d' sent to pid '%d'n", msg.sig, pid);
                    es_respond_auth_result(client, message, pid == getpid() ? ES_AUTH_RESULT_DENY : ES_AUTH_RESULT_ALLOW, false);
                }
                    break;
                default:
                    break;
            }
        });
    }

    {
        es_event_type_t evs[] = { ES_EVENT_TYPE_AUTH_SIGNAL };
        es_subscribe(cli, evs, sizeof(evs) / sizeof(*evs));
    }

    printf("%dn", getpid());
    sleep(60); // could be replaced with other waiting primitive

    es_unsubscribe_all(cli);
    es_delete_client(cli);

    return 0;
}

په ورته ډول ، د MAC پالیسي په کرنل کې راجستر کیدی شي ، کوم چې د سیګنال محافظت میتود چمتو کوي (د پالیسي proc_check_signal) ، مګر API په رسمي ډول نه ملاتړ کیږي.

د کرنل توسیع محافظت

په سیسټم کې د پروسو د ساتنې سربیره، پخپله د کرنل توسیع (کیکټ) ساتنه هم اړینه ده. macOS د پراختیا کونکو لپاره یو چوکاټ چمتو کوي ترڅو په اسانۍ سره د IOKit وسیله ډرایور رامینځته کړي. د وسیلو سره کار کولو لپاره د وسیلو چمتو کولو سربیره ، IOKit د C++ ټولګیو مثالونو په کارولو سره د ډرایور سټیکینګ لپاره میتودونه چمتو کوي. د کارن ځای کې یو غوښتنلیک به وکوالی شي د کرنل - کارن ځای اړیکې رامینځته کولو لپاره د ټولګي راجسټر شوي مثال "موند" کړي.

په سیسټم کې د ټولګیو مثالونو شمیر معلومولو لپاره، د ioclasscount اسانتیا شتون لري.

my_kext_ioservice = 1
my_kext_iouserclient = 1

هر د کرنل توسیع چې غواړي د ډرایور سټیک سره راجستر شي باید یو ټولګي اعلان کړي چې د IOService څخه په میراث کې دي، د بیلګې په توګه my_kext_ioservice پدې حالت کې. د کارن غوښتنلیکونو سره نښلول د ټولګي د نوي مثال رامینځته کولو لامل کیږي چې د IOUserClient څخه په میراث کې دی، د مثال په توګه my_kext_iouserclient.

کله چې د سیسټم څخه د ډرایور د خلاصولو هڅه وکړئ (kextunload کمانډ) ، مجازی فنکشن "بول ټرمینیټ (IOOptionBits اختیارونه)" ویل کیږي. د ختمولو لپاره په زنګ کې د غلط بیرته راستنیدو لپاره کافي دي کله چې د کیسټونلوډ غیر فعالولو لپاره د پورته کولو هڅه کوئ.

bool Kext::terminate(IOOptionBits options)
{

  if (!IsUnloadAllowed)
  {
    // Unload is not allowed, returning false
    return false;
  }

  return super::terminate(options);
}

د IsUnloadAllowed بیرغ د IOUserClient لخوا د بارولو پرمهال تنظیم کیدی شي. کله چې د ډاونلوډ حد شتون ولري، د کیسټونلوډ کمانډ به لاندې محصول بیرته راولي:

admin@admins-Mac drivermanager % sudo kextunload ./test.kext
Password:
(kernel) Can't remove kext my.kext.test; services failed to terminate - 0xe00002c7.
Failed to unload my.kext.test - (iokit/common) unsupported function.

ورته محافظت باید د IOUserClient لپاره ترسره شي. د ټولګیو مثالونه د IOKitLib Userspace فنکشن "IOCatalogueTerminate(mach_port_t، uint32_t پرچم، io_name_t توضیح)" په کارولو سره پورته کیدی شي. تاسو کولی شئ غلط بیرته راشئ کله چې د "ټرمینیټ" کمانډ زنګ ووهئ تر هغه چې د کارونکي ځای غوښتنلیک "مړ" نه وي ، دا د "کلینټ ډیډ" فنکشن نه بلل کیږي.

د فایل محافظت

د فایلونو د ساتنې لپاره، دا د Kauth API کارولو لپاره کافي ده، کوم چې تاسو ته اجازه درکوي فایلونو ته لاسرسی محدود کړئ. ایپل پراختیا کونکو ته په دائره کې د مختلف پیښو په اړه خبرتیاوې چمتو کوي؛ زموږ لپاره ، KAUTH_VNODE_DELETE، KAUTH_VNODE_WRITE_DATA او KAUTH_VNODE_DELETE_CHILD عملیات مهم دي. فایلونو ته د لاسرسي محدودولو ترټولو اسانه لار د لارې په واسطه ده - موږ فایل ته د لارې ترلاسه کولو لپاره د "vn_getpath" API کاروو او د لارې مخکینۍ پرتله کوو. په یاد ولرئ چې د فایل فولډر لارو نوم بدلولو لپاره، سیسټم هر فایل ته د لاسرسي اجازه نه ورکوي، مګر یوازې هغه فولډر ته چې نوم یې بدل شوی. دا اړینه ده چې اصلي لاره پرتله کړئ او د هغې لپاره KAUTH_VNODE_DELETE محدود کړئ.

په macOS کې د پروسو او د کرنل توسیعونو ساتلو څرنګوالی

د دې طریقې زیان ممکن د ټیټ فعالیت وي ځکه چې د مخکینیو شمیر زیاتیږي. د دې لپاره چې ډاډ ترلاسه شي چې پرتله کول د O (prefix* اوږدوالی) سره مساوي ندي، چیرته چې مختګ د مخکینیو شمیر دی، اوږدوالی د تار اوږدوالی دی، تاسو کولی شئ د مخکینیو لخوا جوړ شوي د ټاکل شوي محدود اتوماتیک (DFA) څخه کار واخلئ.

راځئ چې د ورکړل شوي مخکیني سیټ لپاره د DFA جوړولو لپاره میتود په پام کې ونیسو. موږ د هر مختګ په پیل کې کرسر پیل کوو. که ټول کرسر ورته کریکٹر ته اشاره وکړي، نو بیا هر کرسر د یو کریکټر لخوا زیات کړئ او په یاد ولرئ چې د ورته کرښې اوږدوالی د یو لخوا لوی دی. که چیرې دوه کرسرونه د مختلف سمبولونو سره وي، نو کرسرونه په ګروپونو ویشئ د هغه سمبول له مخې چې دوی ورته اشاره کوي او د هرې ډلې لپاره الګوریتم تکرار کړئ.

په لومړي حالت کې (د کرسر لاندې ټول کرکټرونه یو شان دي)، موږ د DFA حالت ترلاسه کوو چې د ورته کرښې سره یوازې یو لیږد لري. په دوهم حالت کې، موږ د 256 اندازې د لیږد جدول (د حروفونو شمیر او د ډیری ګروپونو شمیر) راتلونکو ریاستونو ته د فنکشن په تکراري ډول ویلو سره ترلاسه کوو.

راځئ چې یو مثال وګورو. د مختګونو سیټ لپاره ("/foo/bar/tmp/"، "/var/db/foo/"، "/foo/bar/aba/"، "foo/bar/aac/") تاسو کولی شئ لاندې ترلاسه کړئ د ‏‎DFA‎‏ پاڼې اړوند نور معلومات په فسبوک کې اوګورئ ارقام یوازې هغه لیږدونه ښیې چې نورو ایالتونو ته رهبري کیږي؛ نور لیږدونه به حتمي نه وي.

په macOS کې د پروسو او د کرنل توسیعونو ساتلو څرنګوالی

کله چې د DKA ایالتونو څخه تیریږي ، ممکن 3 قضیې شتون ولري.

  1. وروستي حالت ته رسیدلي - لاره خوندي ده، موږ KAUTH_VNODE_DELETE، KAUTH_VNODE_WRITE_DATA او KAUTH_VNODE_DELETE_CHILD عملیات محدود کوو
  2. وروستي حالت ته نه و رسیدلی، مګر لاره "پای ته رسیدلې" (نال ټرمینټر ته رسیدلی) - لاره یو مور او پلار دی، دا اړینه ده چې KAUTH_VNODE_DELETE محدود کړئ. په یاد ولرئ چې که vnode یو فولډر وي، تاسو اړتیا لرئ چې په پای کې '/' اضافه کړئ، که نه نو دا ممکن دا د "/foor/bar/t" فایل پورې محدود کړي، کوم چې غلط دی.
  3. وروستي حالت ته نه و رسیدلی، لاره پای ته نه ده رسیدلې. هیڅ یو مخکی له دې سره سمون نه خوري، موږ محدودیتونه نه معرفي کوو.

پایلې

د رامینځته شوي امنیتي حلونو هدف د کارونکي او د هغه ډیټا د امنیت کچې لوړول دي. له یوې خوا ، دا هدف د اکرونیس سافټویر محصول پراختیا لخوا ترلاسه کیږي ، کوم چې هغه زیانونه وتړي چیرې چې عملیاتي سیسټم پخپله "کمزور" دی. له بلې خوا، موږ باید د هغو امنیتي اړخونو په پیاوړتیا کې غفلت ونه کړو چې په OS اړخ کې ښه کیدی شي، په ځانګړې توګه له هغه وخته چې د داسې زیانونو تړل د محصول په توګه زموږ خپل ثبات زیاتوي. زیانمنتیا د ایپل محصول امنیت ټیم ته راپور شوې او په macOS 10.14.5 (https://support.apple.com/en-gb/HT210119) کې ټاکل شوې.

په macOS کې د پروسو او د کرنل توسیعونو ساتلو څرنګوالی

دا ټول یوازې هغه وخت ترسره کیدی شي کله چې ستاسو یوټیلیټ په رسمي ډول د کرنل کې نصب شوی وي. دا د بهرني او ناغوښتل شوي سافټویر لپاره هیڅ ډول نیمګړتیاوې شتون نلري. په هرصورت، لکه څنګه چې تاسو لیدلی شئ، حتی د مشروع پروګرامونو ساتنه لکه د انټي ویروس او بیک اپ سیسټمونو کار ته اړتیا لري. مګر اوس د MacOS لپاره نوي Acronis محصولات به د سیسټم څخه د پورته کولو پروړاندې اضافي محافظت ولري.

سرچینه: www.habr.com

Add a comment