በ macOS ውስጥ ሂደቶችን እና የከርነል ቅጥያዎችን እንዴት እንደሚጠብቁ

ሃይ ሀብር! ዛሬ በ macOS ውስጥ ሂደቶችን ከአጥቂዎች እንዴት መጠበቅ እንደሚችሉ ማውራት እፈልጋለሁ። ለምሳሌ, ይህ ለፀረ-ቫይረስ ወይም ለመጠባበቂያ ስርዓት ጠቃሚ ነው, በተለይም በማክሮስ ስር አንድን ሂደት በአንድ ጊዜ "ለመግደል" በርካታ መንገዶች አሉ. ስለዚህ እና ስለ መከላከያ ዘዴዎች በቆራጩ ስር ያንብቡ.

በ macOS ውስጥ ሂደቶችን እና የከርነል ቅጥያዎችን እንዴት እንደሚጠብቁ

አንድን ሂደት "ለመግደል" የሚታወቀው መንገድ

አንድን ሂደት "ለመግደል" በጣም የታወቀ መንገድ የ SIGKILL ምልክት ወደ ሂደቱ መላክ ነው. በ bash በኩል፣ ለመግደል መደበኛውን "kill -SIGKILL PID" ወይም "pkill -9 NAME" መደወል ይችላሉ። የ "ገዳይ" ትዕዛዝ ከ UNIX ዘመን ጀምሮ ይታወቃል እና በ macOS ላይ ብቻ ሳይሆን በሌሎች UNIX መሰል ስርዓቶች ላይም ይገኛል.

እንዲሁም በ UNIX መሰል ስርዓቶች ውስጥ, MacOS ከሁለት በስተቀር - SIGKILL እና SIGSTOP የሂደቱን ማንኛውንም ምልክቶች ለመጥለፍ ይፈቅድልዎታል. ይህ መጣጥፍ በዋናነት የ SIGKILL ምልክት ሂደትን እንዲገደል የሚያደርገውን ምልክት አድርጎ ይመለከታል።

የ macOS ዝርዝሮች

በማክሮስ ላይ፣ በXNU ከርነል ውስጥ ያለው የግድያ ስርዓት ጥሪ psignal(SIGKILL፣…) ተግባርን ይጠራል። ሌሎች የተጠቃሚ እርምጃዎች በተጠቃሚ ቦታ ላይ የ psignal ተግባር ምን ሊጠራ እንደሚችል ለማየት እንሞክር። በከርነል ውስጣዊ አሠራሮች ውስጥ ወደ ፒሲናል ተግባር ጥሪዎችን እናጣራ (ምንም እንኳን ቀላል ያልሆኑ ሊሆኑ ይችላሉ ፣ ግን ለሌላ ጽሑፍ እንተወዋቸዋለን 🙂 - የፊርማ ማረጋገጫ ፣ የማስታወስ ስህተቶች ፣ የመውጣት / ማቋረጥ ሂደት ፣ የፋይል ደህንነት ጥሰቶች ፣ ወዘተ. .

አጠቃላይ እይታውን በተግባሩ እና በተዛማጅ የስርዓት ጥሪ እንጀምር በተከፈለ_ጭነት_ያቋርጥ. ከጥንታዊው የግድያ ጥሪ በተጨማሪ ለማክሮ ኦፕሬቲንግ ሲስተም የተለየ እና በ BSD ውስጥ የማይገኝ አማራጭ አቀራረብ እንዳለ ማየት ይቻላል። የሁለቱም የስርዓት ጥሪዎች አሠራር መርሆዎችም ተመሳሳይ ናቸው. ወደ psignal kernel ተግባር ቀጥተኛ ጥሪዎች ናቸው። እንዲሁም ሂደቱን ከመግደልዎ በፊት የ "ካንሲንግ" ፍተሻ መደረጉን ልብ ይበሉ - ሂደቱ ወደ ሌላ ሂደት ምልክት መላክ ይችል እንደሆነ, ስርዓቱ ማንኛውንም መተግበሪያ የስርዓት ሂደቶችን ለመግደል አይፈቅድም.

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);
	}
...
}

ተጀመረ

በሲስተም ጅምር ላይ ዲሞኖችን ለመፍጠር እና ህይወታቸውን ለመቆጣጠር መደበኛው መንገድ ተጀመረ። ምንጮቹ ከማክኦኤስ 10.10 በፊት ለቀድሞው የ launchctl ስሪት መሰጠታቸውን ወደ እርስዎ ትኩረት ለመሳብ እፈልጋለሁ ፣ የኮድ ምሳሌዎች እንደ ምሳሌ ተሰጥተዋል ። ዘመናዊው launchctl በXPC በኩል ለመጀመር ምልክቶችን ይልካል፣ launchctl አመክንዮ ወደ እሱ ተወስዷል።

አፕሊኬሽኖች እንዴት እንደሚቆሙ እንመልከት። የ 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 ብቻ ሳይሆን SIGKILLንም መላክ ይችላል።

ቀጥተኛ ያልሆነ ግድያ - የንብረት ካፕ

የበለጠ አስደሳች ጉዳይ በሌላ የስርዓት ጥሪ ውስጥ ሊታይ ይችላል። የሂደት_ፖሊሲ. ለዚህ የሥርዓት ጥሪ የተለመደው የመተግበሪያ ሃብቶችን መገደብ ነው፣ ለምሳሌ ሲፒዩ እና የማስታወሻ ኮታ መረጃ ጠቋሚን መገደብ፣ ስርዓቱ በፋይል መሸጎጫ እንቅስቃሴዎች በከፍተኛ ሁኔታ እንዳይቀንስ። ከproc_apply_resource_actions ተግባር እንደሚታየው አፕሊኬሽኑ የግብአት ገደቡ ላይ ከደረሰ፣ SIGKILL ምልክት ወደ ሂደቱ ይላካል።

ምንም እንኳን ይህ የስርዓት ጥሪ ሂደትን የመግደል አቅም ቢኖረውም ሥርዓቱ የስርዓት ጥሪውን የመጥራት ሂደት መብቶችን በበቂ ሁኔታ አላጣራም። በእውነቱ በማጣራት ላይ ነበረነገር ግን ይህንን ሁኔታ ለማለፍ የአማራጭ ባንዲራ PROC_POLICY_ACTION_SET መጠቀም በቂ ነው።

ስለዚህ የCPU አጠቃቀምን ኮታ በመተግበሪያ “ከገደቡ” (ለምሳሌ 1 ns ብቻ እንዲሰራ ከፈቀዱ) በሲስተሙ ውስጥ ያለውን ማንኛውንም ሂደት መግደል ይችላሉ። ስለዚህ ማልዌር የጸረ-ቫይረስ ሂደትን ጨምሮ በሲስተሙ ላይ ያለውን ማንኛውንም ሂደት ሊገድል ይችላል። እንዲሁም ሂደቱን በ pid 1 (launchctl) ሲገድሉ የተገኘው ውጤት - የ SIGKILL ምልክትን ለማስኬድ በሚሞከርበት ጊዜ የከርነል ፍርሃት 🙂

በ macOS ውስጥ ሂደቶችን እና የከርነል ቅጥያዎችን እንዴት እንደሚጠብቁ

ችግሩን እንዴት መፍታት ይቻላል?

ሂደትን መግደልን ለመከላከል በጣም ቀላሉ መንገድ በስርዓት ጥሪ ሠንጠረዥ ውስጥ ያለውን የተግባር ጠቋሚ መተካት ነው። በሚያሳዝን ሁኔታ, ይህ ዘዴ ለብዙ ምክንያቶች ቀላል አይደለም.

በመጀመሪያ ፣ የማህደረ ትውስታ ቦታን የሚይዘው ምልክት የ XNU kernel የግል ምልክት ብቻ ሳይሆን በከርነል ምልክቶች ውስጥም ሊገኝ አይችልም። ሂዩሪስቲክ የፍለጋ ዘዴዎችን መጠቀም አለብህ፣ ለምሳሌ፣ የተግባርን ተለዋዋጭ መፍታት እና በውስጡ ጠቋሚን መፈለግ።

በሁለተኛ ደረጃ, በሠንጠረዡ ውስጥ ያሉት የመግቢያዎች መዋቅር ከርነል በተጠናቀረባቸው ባንዲራዎች ላይ ይወሰናል. የ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
                                         */
};

እንደ እድል ሆኖ፣ በዘመናዊ የማክሮስ ስሪቶች አፕል አዲስ የሂደት ኤፒአይ ይሰጣል። የEndpoint Security API ደንበኞች ብዙ ጥያቄዎችን ለሌሎች ሂደቶች ፍቃድ እንዲሰጡ ያስችላቸዋል። ስለዚህ፣ ከላይ ያለውን ኤፒአይ በመጠቀም የSIGKILL ምልክትን ጨምሮ ማንኛውንም የሂደት ምልክቶችን ማገድ ይችላሉ።

#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) ግን ኤፒአይ በይፋ አይደገፍም።

የከርነል ማራዘሚያ ጥበቃ

በስርአቱ ውስጥ ያሉትን ሂደቶች ከመጠበቅ በተጨማሪ የከርነል ማራዘሚያው እራሱ (ኬክስት) መከላከል አስፈላጊ ነው. macOS ለገንቢዎች የ IOKit መሣሪያ ሾፌሮችን በቀላሉ እንዲያዳብሩ ማዕቀፍ ያቀርባል። የመሳሪያ አያያዝን ከማቅረብ በተጨማሪ IOKit የ C++ ክፍል አጋጣሚዎችን በመጠቀም የአሽከርካሪ መቆለልያ ዘዴዎችን ይሰጣል። በተጠቃሚ ቦታ ላይ ያለ አፕሊኬሽን የከርነል የተጠቃሚ ቦታ ማህበር ለመመስረት የክፍሉን የተመዘገበ ምሳሌ "ማግኘት" ይችላል።

የioclasscount መገልገያ በአንድ ሥርዓት ውስጥ ያሉትን የክፍል አጋጣሚዎች ብዛት ለማወቅ አለ።

my_kext_ioservice = 1
my_kext_iouserclient = 1

በሹፌሩ ቁልል ለመመዝገብ የሚፈልግ ማንኛውም የከርነል ቅጥያ ከአይኦኤስ አገልግሎት የሚወርስ ክፍልን ማወጅ አለበት ለምሳሌ my_kext_ioservice በዚህ ጉዳይ ላይ የተጠቃሚ መተግበሪያዎችን ማገናኘት ከIOUserClient የተወረሰ ክፍል አዲስ ለምሳሌ my_kext_iouserclient እንዲፈጠር ያደርጋል። .

ሾፌሩን ከሲስተሙ ለማውረድ ሲሞክሩ (የ kextunload ትዕዛዝ) ምናባዊ ተግባር "ቦል ማቋረጥ (IOOptionBits አማራጮች)" ይባላል. kextunload ን ለማሰናከል ለማውረድ በሚሞከርበት ጊዜ የማቋረጡ ተግባር ጥሪ ላይ ሐሰት መመለስ በቂ ነው።

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

የ IsUnloadAllowed ባንዲራ በ IOUserClient ሊዘጋጅ ይችላል። ጭነቱ ሲገደብ የ kextunload ትዕዛዙ የሚከተለውን ውጤት ይመልሳል፡-

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 የተጠቃሚ ቦታ ተግባርን በመጠቀም ማውረድ ይቻላል "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t መግለጫ)"። የተጠቃሚ ቦታ አፕሊኬሽኑ "ይሞታል" ማለትም "clientDied" ተግባር እስካልተጠራ ድረስ ወደ "ማቋረጥ" ትእዛዝ በሚደረግ ጥሪ ላይ የውሸት መመለስ ይቻላል::

የፋይል ጥበቃ

ፋይሎችን ለመጠበቅ የፋይሎችን መዳረሻ ለመገደብ የሚያስችልዎትን የ Kauth API መጠቀም በቂ ነው። አፕል በየአካባቢው ስላሉ የተለያዩ ክስተቶች ማሳወቂያዎችን ለገንቢዎች ያቀርባል፣ KAUTH_VNODE_DELETE፣ KAUTH_VNODE_WRITE_DATA እና KAUTH_VNODE_DELETE_CHILD ስራዎች ለእኛ አስፈላጊ ናቸው። የፋይሎች መዳረሻን ለመገደብ ቀላሉ መንገድ መንገድ ነው - ወደ ፋይሉ የሚወስደውን መንገድ ለማግኘት እና የመንገዱን ቅድመ ቅጥያ ለማነፃፀር የ"vn_getpath" API እንጠቀማለን። የአቃፊ ዱካዎችን በፋይሎች መቀየርን ለማመቻቸት ስርዓቱ ለእያንዳንዱ ፋይል መዳረሻ አይሰጥም ነገር ግን የተሰየመው አቃፊ ራሱ ብቻ መሆኑን ልብ ይበሉ። የወላጅ መንገድን ማወዳደር እና ለእሱ KAUTH_VNODE_DELETE መገደብ አስፈላጊ ነው።

በ macOS ውስጥ ሂደቶችን እና የከርነል ቅጥያዎችን እንዴት እንደሚጠብቁ

የቅድመ-ቅጥያዎች ብዛት ሲጨምር የዚህ አካሄድ ጉዳቱ ደካማ አፈፃፀም ሊሆን ይችላል። ንጽጽሩ ከኦ (ቅድመ ቅጥያ * ርዝመት) ጋር እኩል አለመሆኑን ለማረጋገጥ ቅድመ ቅጥያ የቅድመ-ቅጥያዎች ብዛት፣ ርዝመቱ የሕብረቁምፊው ርዝመት ከሆነ ፣በቅድመ-ቅጥያዎች ላይ የተገነባ ቆራጥ ፊኒት አውቶሜትቶን (DFA) መጠቀም ይችላሉ።

ለተወሰነ ቅድመ-ቅጥያዎች ዲኤፍኤ የመገንባት ዘዴን አስቡበት። በእያንዳንዱ ቅድመ ቅጥያ መጀመሪያ ላይ ጠቋሚዎችን እናስጀምራለን. ሁሉም ጠቋሚዎች ወደ አንድ አይነት ባህሪ የሚያመለክቱ ከሆነ እያንዳንዱን ጠቋሚ በአንድ ቁምፊ እንጨምራለን እና የአንድ መስመር ርዝመት አንድ በአንድ እንደሚበልጥ እናስታውሳለን. ሁለት ጠቋሚዎች ካሉ, ከስር ያሉት ቁምፊዎች የተለያዩ ናቸው, ጠቋሚዎቹን በተጠቆሙት ባህሪ መሰረት በቡድን እንከፋፍለን እና ለእያንዳንዱ ቡድን አልጎሪዝምን እንደግማለን.

በመጀመሪያው ሁኔታ (ከጠቋሚዎቹ ስር ያሉ ሁሉም ቁምፊዎች ተመሳሳይ ናቸው), የዲኤፍኤ ሁኔታን እናገኛለን, በተመሳሳይ መስመር ላይ አንድ ሽግግር ብቻ ነው ያለው. በሁለተኛው ጉዳይ ላይ 256 መጠን (የቁምፊዎች ብዛት እና ከፍተኛው የቡድኖች ብዛት) ወደ ተከታይ ግዛቶች የሚሸጋገረውን ሠንጠረዥ እናገኛለን ።

አንድ ምሳሌ እንመልከት። ለቅድመ-ቅጥያዎች ስብስብ ("/foo/bar/tmp/"፣ "/var/db/foo/", "/foo/bar/aba/", "foo/bar/aac/")፣ የሚከተለው ዲኤፍኤ ይችላል ማግኘት. ስዕሉ የሚያሳየው ወደ ሌሎች ግዛቶች የሚደረጉ ሽግግሮችን ብቻ ነው፣ ሌሎች ሽግግሮች የመጨረሻ ሊሆኑ አይችሉም።

በ macOS ውስጥ ሂደቶችን እና የከርነል ቅጥያዎችን እንዴት እንደሚጠብቁ

በዲኤፍኤ ግዛቶች ውስጥ በሚያልፉበት ጊዜ, 3 ጉዳዮች ሊኖሩ ይችላሉ.

  1. የመጨረሻው ሁኔታ ላይ ደርሷል - መንገዱ የተጠበቀ ነው፣ ክዋኔዎቹን ይገድቡ KAUTH_VNODE_DELETE፣ KAUTH_VNODE_WRITE_DATA እና KAUTH_VNODE_DELETE_CHILD
  2. የመጨረሻው ሁኔታ አልደረሰም ነገር ግን ዱካው "አልቋል" ( ባዶ ተርሚነተር ደርሷል) - መንገዱ ወላጅ ነው፣ KAUTH_VNODE_DELETE መገደብ አለበት። ማስታወሻው vnode አቃፊ ከሆነ ወደ መጨረሻው '/' ማከል አለብህ አለበለዚያ ግን በፋይሉ "/foor/bar/t" ላይ ሊገድብ ይችላል፣ ይህ ትክክል አይደለም።
  3. የመጨረሻው ግዛት አልደረሰም, መንገዱ አላለቀም. የትኛውም ቅድመ ቅጥያ ከተሰጠው ጋር አይዛመድም፣ ገደቦችን አናስተዋውቅም።

መደምደሚያ

የተዘጋጁት የደህንነት መፍትሄዎች ዓላማ የተጠቃሚውን እና የእሱን ውሂብ የደህንነት ደረጃ ማሳደግ ነው. በአንድ በኩል, ይህ ግብ የተረጋገጠው በአክሮኒስ ሶፍትዌር ምርት እድገት ነው, ይህም ስርዓተ ክወናው ራሱ "ደካማ" ያለበትን እነዚያን ድክመቶች ይዘጋዋል. በሌላ በኩል፣ በስርዓተ ክወናው በኩል ሊሻሻሉ የሚችሉትን የደህንነት ገጽታዎች ማጠናከርን ችላ ማለት የለብንም ፣ በተለይም እንደዚህ ያሉ ተጋላጭነቶችን መዝጋት እንደ ምርት የራሳችንን መረጋጋት ይጨምራል። ተጋላጭነቱ ለአፕል ምርት ደህንነት ቡድን ሪፖርት ተደርጓል እና በ macOS 10.14.5 (https://support.apple.com/en-gb/HT210119) ላይ ተስተካክሏል።

በ macOS ውስጥ ሂደቶችን እና የከርነል ቅጥያዎችን እንዴት እንደሚጠብቁ

ይህ ሁሉ ሊደረግ የሚችለው መገልገያዎ በከርነል ውስጥ በይፋ ከተጫነ ብቻ ነው. ማለትም ለውጭ እና ያልተፈለገ ሶፍትዌር እንደዚህ አይነት ክፍተቶች የሉም። ነገር ግን፣ እርስዎ እንደሚመለከቱት፣ እንደ ጸረ-ቫይረስ እና የመጠባበቂያ ስርዓቶች ያሉ ህጋዊ ፕሮግራሞችን መጠበቅ እንኳን የተወሰነ ስራ ይወስዳል። አሁን ግን አዲሱ የማክሮስ አክሮኒስ ምርቶች ከስርዓቱ ማራገፍ ላይ ተጨማሪ ጥበቃ ይኖራቸዋል።

ምንጭ: hab.com

አስተያየት ያክሉ