Mar a nì thu tèarainte air pròiseasan agus leudachadh kernel ann am macOS

Halò, Habr! An-diugh bu mhath leam bruidhinn mu mar as urrainn dhut pròiseasan a dhìon bho ionnsaighean le luchd-ionnsaigh ann am macOS. Mar eisimpleir, tha seo feumail airson siostam anti-bhìoras no cùl-taic, gu sònraichte leis gu bheil grunn dhòighean ann airson pròiseas “marbhadh” fo macOS. Leugh mu dheidhinn seo agus dòighean dìon fon ghearradh.

Mar a nì thu tèarainte air pròiseasan agus leudachadh kernel ann am macOS

An dòigh clasaigeach air pròiseas “marbhadh”.

Is e dòigh ainmeil air pròiseas “marbhadh” a bhith a’ cur comharra SIGKILL chun phròiseas. Tro bash faodaidh tu an ìre àbhaisteach “marbhadh -SIGKILL PID” no “pkill -9 NAME” a mharbhadh. Tha an àithne “marbhadh” air a bhith aithnichte bho làithean UNIX agus tha e ri fhaighinn chan ann a-mhàin air macOS, ach cuideachd air siostaman eile coltach ri UNIX.

Dìreach mar ann an siostaman coltach ri UNIX, leigidh macOS leat comharran sam bith a chuir a-steach gu pròiseas ach a dhà - SIGKILL agus SIGSTOP. Bidh an artaigil seo gu sònraichte ag amas air comharra SIGKILL mar chomharradh a dh’ adhbhraicheas pròiseas a bhith air a mharbhadh.

mion-fhiosrachadh macOS

Air macOS, bidh gairm an t-siostam marbhadh anns an kernel XNU a ’gairm gnìomh psignal (SIGKILL, ...). Feuchaidh sinn ri faicinn dè na gnìomhan cleachdaiche eile ann an àite luchd-cleachdaidh a dh’ fhaodar a ghairm leis a’ ghnìomh psignal. Feuch an cuir sinn a-mach fiosan chun ghnìomh psignal ann an uidheamachdan a-staigh an kernel (ged a dh’ fhaodadh iad a bhith neo-bheag, fàgaidh sinn iad airson artaigil eile 🙂 - dearbhadh ainm-sgrìobhte, mearachdan cuimhne, làimhseachadh fàgail / crìochnachaidh, brisidhean dìon faidhle, msaa. .

Feuch an tòisich sinn air an ath-bhreithneachadh leis a 'ghnìomh agus a' ghairm siostam co-fhreagarrach crìoch_le_payload. Chithear, a bharrachd air a’ ghairm marbhadh clasaigeach, gu bheil dòigh-obrach eile ann a tha sònraichte do shiostam-obrachaidh macOS agus nach eil ri lorg ann am BSD. Tha prionnsabalan obrachaidh an dà chuid gairm siostam cuideachd coltach. Is e gairmean dìreach a th’ annta gu psignal gnìomh kernel. Thoir an aire cuideachd, mus tèid pròiseas a mharbhadh, gun tèid sgrùdadh “cansignal” a dhèanamh - an urrainn don phròiseas comharra a chuir gu pròiseas eile; chan eil an siostam a’ leigeil le tagradh sam bith pròiseasan siostam a mharbhadh, mar eisimpleir.

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

air bhog

Tha an dòigh àbhaisteach air daemons a chruthachadh aig toiseach tòiseachaidh an t-siostaim agus smachd a chumail air am beatha air a chuir air bhog. Thoir an aire gu bheil na stòran airson an t-seann dreach de launchctl suas gu macOS 10.10, tha eisimpleirean còd air an toirt seachad airson adhbharan mìneachaidh. Bidh launchctl ùr-nodha a’ cur comharran air bhog tro XPC, tha loidsig launchctl air a ghluasad thuige.

Bheir sinn sùil air mar a thèid stad a chuir air tagraidhean. Mus cuir thu an comharra SITERM, thathas a’ feuchainn ris an tagradh a stad le bhith a’ cleachdadh a’ ghairm siostam “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));
		} 
...
<>

Fon chochall, faodaidh proc_terminate, a dh’ aindeoin an ainm, chan e a-mhàin psignal a chuir le SITERM, ach cuideachd SIGKILL.

Marbh neo-dhìreach - Crìochan Ghoireasan

Chithear cùis nas inntinniche ann an gairm siostam eile pròiseas_poileasaidh. Is e cleachdadh cumanta den ghairm siostam seo a bhith a’ cuingealachadh ghoireasan tagraidh, leithid airson clàr-amais gus ùine CPU agus cuotathan cuimhne a chuingealachadh gus nach bi an siostam air a lughdachadh gu mòr le gnìomhan tasgadan faidhle. Ma tha tagradh air a’ chrìoch ghoireasan aige a ruighinn, mar a chithear bhon ghnìomh proc_apply_resource_actions, thèid comharra SIGKILL a chuir chun phròiseas.

Ged a dh'fhaodadh an gairm siostam seo pròiseas a mharbhadh, cha do rinn an siostam sgrùdadh iomchaidh air còraichean a 'phròiseas a' gairm gairm an t-siostaim. Dìreach sgrùdadh bha ann, ach tha e gu leòr a' bhratach eile PROC_POLICY_ACTION_SET a chleachdadh gus a dhol seachad air a' chumha seo.

Mar sin, ma tha thu “a’ cuingealachadh ”cuota cleachdaidh CPU an tagraidh (mar eisimpleir, a’ leigeil le dìreach 1 ns a ruith), faodaidh tu pròiseas sam bith san t-siostam a mharbhadh. Mar sin, faodaidh an malware pròiseas sam bith air an t-siostam a mharbhadh, a 'gabhail a-steach pròiseas antivirus. Cuideachd inntinneach tha a’ bhuaidh a bhios a’ tachairt nuair a thathar a’ marbhadh pròiseas le pid 1 (launchctl) - clisgeadh kernel nuair a thathar a’ feuchainn ri comharra SIGKILL a ghiullachd :)

Mar a nì thu tèarainte air pròiseasan agus leudachadh kernel ann am macOS

Ciamar a dh ’fhuasglas tu an duilgheadas?

Is e an dòigh as sìmplidh air casg a chuir air pròiseas a bhith air a mharbhadh a bhith a’ cur an àite a’ phuing gnìomh ann an clàr gairm an t-siostaim. Gu mì-fhortanach, tha an dòigh seo neo-bheag airson iomadach adhbhar.

An toiseach, chan e a-mhàin gu bheil an samhla a bhios a’ cumail smachd air suidheachadh cuimhne sysent prìobhaideach don t-samhla kernel XNU, ach chan fhaighear e ann an samhlaidhean kernel. Feumaidh tu dòighean sgrùdaidh heuristic a chleachdadh, leithid a bhith a’ cuir às do ghnìomh gu dinamach agus a’ lorg puing innte.

San dàrna h-àite, tha structar nan inntrigidhean sa chlàr an urra ris na brataichean leis an deach an kernel a chuir ri chèile. Ma thèid a' bhratach CONFIG_REQUIRES_U32_MUNGING fhoillseachadh, thèid meud an structair atharrachadh - thèid raon a bharrachd a chur ris sy_arg_munge32. Feumar sgrùdadh a bharrachd a dhèanamh gus faighinn a-mach dè am bratach a chaidh an kernel a chuir ri chèile, no air an làimh eile, sùil a thoirt air comharran gnìomh an aghaidh feadhainn aithnichte.

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
                                         */
};

Gu fortanach, ann an dreachan ùr-nodha de macOS, tha Apple a’ toirt seachad API ùr airson obrachadh le pròiseasan. Tha an Endpoint Security API a’ leigeil le teachdaichean mòran iarrtasan a cheadachadh gu pròiseasan eile. Mar sin, faodaidh tu casg a chuir air comharran sam bith gu pròiseasan, a’ toirt a-steach comharra SIGKILL, a ’cleachdadh an API gu h-àrd.

#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;
}

San aon dòigh, faodar Poileasaidh MAC a chlàradh anns an kernel, a bheir seachad dòigh dìon chomharran (poileasaidh proc_check_signal), ach chan eil an API a’ faighinn taic oifigeil.

Dìon leudachadh kernel

A bharrachd air a bhith a 'dìon phròiseasan san t-siostam, tha e riatanach cuideachd an leudachadh kernel fhèin (kext) a dhìon. Tha macOS a’ toirt seachad frèam do luchd-leasachaidh gus draibhearan inneal IOKit a leasachadh gu furasta. A bharrachd air a bhith a’ toirt seachad innealan airson a bhith ag obair le innealan, tha IOKit a’ toirt seachad dòighean airson cruachadh dhràibhearan a’ cleachdadh eisimpleirean de chlasaichean C ++. Bidh e comasach do thagradh san àite-cleachdaidh “eisimpleir clàraichte den chlas a lorg gus dàimh kernel-userspace a stèidheachadh.

Gus an àireamh de shuidheachaidhean clas san t-siostam a lorg, tha goireas ioclasscount ann.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Feumaidh leudachadh kernel sam bith a tha airson clàradh leis an stac dhràibhearan clas ainmeachadh a thig bho IOService, mar eisimpleir my_kext_ioservice sa chùis seo.

Nuair a dh’ fheuchas tu ri draibhear a luchdachadh bhon t-siostam (kextunload command), canar an gnìomh brìgheil “bool termminate (roghainnean IOOptionBits)”. Tha e gu leòr meallta a thilleadh air a’ ghairm gus crìochnachadh nuair a thathar a’ feuchainn ri luchdachadh sìos gus kextunload a chur à comas.

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

Faodar bratach IsUnloadAllowed a shuidheachadh leis an IOUserClient nuair a thèid a luchdachadh. Nuair a tha crìoch luchdachadh sìos, tillidh an àithne kextunload an toradh a leanas:

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.

Feumar dìon coltach ris a dhèanamh airson IOUserClient. Faodar cùisean de chlasaichean a luchdachadh sìos le bhith a’ cleachdadh gnìomh àite-cleachdaidh IOKitLib “IOCatalogueTerminate (mach_port_t, bratach uint32_t, tuairisgeul io_name_t);”. Faodaidh tu meallta a thilleadh nuair a chuireas tu fios chun àithne “crìochnachaidh” gus am bàsaich an aplacaid userspace, is e sin, chan eil an gnìomh “clientDied” air a ghairm.

Dìon faidhle

Gus faidhlichean a dhìon, tha e gu leòr an Kauth API a chleachdadh, a leigeas leat ruigsinneachd air faidhlichean a chuingealachadh. Bidh Apple a’ toirt fios do luchd-leasachaidh mu dhiofar thachartasan san raon; dhuinne, tha gnìomhachd KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA agus KAUTH_VNODE_DELETE_CHILD cudromach. Is e slighe an dòigh as fhasa air ruigsinneachd air faidhlichean a chuingealachadh - bidh sinn a’ cleachdadh an API “vn_getpath” gus an t-slighe chun fhaidhle fhaighinn agus coimeas a dhèanamh eadar ro-leasachan na slighe. Thoir an aire, gus ath-ainmeachadh slighean pasgan faidhle a bharrachadh, nach eil an siostam a’ ceadachadh ruigsinneachd air gach faidhle, ach a-mhàin don phasgan fhèin a chaidh ath-ainmeachadh. Feumar coimeas a dhèanamh eadar an t-slighe phàrant agus casg a chuir air KAUTH_VNODE_DELETE air a shon.

Mar a nì thu tèarainte air pròiseasan agus leudachadh kernel ann am macOS

Is dòcha gur e ana-cothrom an dòigh-obrach seo coileanadh ìosal leis gu bheil an àireamh de ro-leasachain ag àrdachadh. Gus dèanamh cinnteach nach eil an coimeas co-ionann ri O (ro-leasachan * fad), far a bheil ro-leasachan an àireamh de ro-leasachain, is e fad fad an t-sreang, faodaidh tu automaton crìochnaichte dearbhte (DFA) a chleachdadh air a thogail le ro-leasachain.

Beachdaichidh sinn air dòigh airson DFA a thogail airson seata sònraichte de ro-leasachain. Tòisichidh sinn na cursors aig toiseach gach ro-leasachan. Ma tha a h-uile cursair a 'comharrachadh an aon charactar, an uairsin àrdaich gach cursair le aon charactar agus cuimhnich gu bheil fad an aon loidhne nas motha le aon. Ma tha dà chursair ann le samhlaidhean eadar-dhealaichte, roinn na cursors ann am buidhnean a rèir an t-samhla a tha iad a’ comharrachadh agus cuir a-rithist an algairim airson gach buidheann.

Anns a 'chiad chùis (tha na caractaran gu lèir fo na cursors mar an ceudna), gheibh sinn stàit DFA aig nach eil ach aon ghluasad air an aon loidhne. Anns an dàrna cùis, gheibh sinn clàr de ghluasadan meud 256 (àireamh charactaran agus an àireamh as motha de bhuidhnean) gu stàitean às deidh sin a gheibhear le bhith a ’gairm a’ ghnìomh gu ath-chuairteach.

Bheir sinn sùil air eisimpleir. Airson seata de ro-leasachain (“/ foo/bar/tmp/”, “/var/db/foo/”, “/ foo/bar/aba/”, “foo/bar/aac/”) gheibh thu na leanas DFA. Tha am figear a’ sealltainn dìreach eadar-ghluasadan a’ leantainn gu stàitean eile; cha bhi eadar-ghluasadan eile deireannach.

Mar a nì thu tèarainte air pròiseasan agus leudachadh kernel ann am macOS

Nuair a thèid thu tro stàitean DKA, dh’ fhaodadh gum bi 3 cùisean ann.

  1. Chaidh an staid mu dheireadh a ruighinn - tha an t-slighe air a dhìon, bidh sinn a’ cuingealachadh gnìomhachd KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA agus KAUTH_VNODE_DELETE_CHILD
  2. Cha deach an stàit mu dheireadh a ruighinn, ach chaidh an t-slighe “crìochnaichte” (chaidh an neach-crìochnachaidh null a ruighinn) - is e pàrant a th ’anns an t-slighe, feumar KAUTH_VNODE_DELETE a chuingealachadh. Thoir an aire mas e pasgan a th’ ann an vnode, feumaidh tu ‘/’ a chuir ris aig an deireadh, air neo faodaidh e a chuingealachadh ris an fhaidhle “/ foor/bar/t”, a tha ceàrr.
  3. Cha deach an staid mu dheireadh a ruighinn, cha tàinig an t-slighe gu crìch. Chan eil gin de na ro-leasachain a’ freagairt ris an fhear seo, cha bhith sinn a’ toirt a-steach cuingealachaidhean.

co-dhùnadh

Is e amas nam fuasglaidhean tèarainteachd a thathar a’ leasachadh ìre tèarainteachd an neach-cleachdaidh agus an dàta aige àrdachadh. Air an aon làimh, tha an amas seo air a choileanadh le bhith a’ leasachadh toradh bathar-bog Acronis, a dhùineas na so-leòntachd sin far a bheil an siostam-obrachaidh fhèin “lag”. Air an làimh eile, cha bu chòir dhuinn dearmad a dhèanamh air neartachadh nan taobhan tèarainteachd sin a ghabhas leasachadh air taobh an OS, gu h-àraidh leis gu bheil a bhith a’ dùnadh leithid de chugallachd ag àrdachadh ar seasmhachd fhèin mar thoradh. Chaidh aithris air an so-leòntachd do Sgioba Tèarainteachd Bathar Apple agus chaidh a shuidheachadh ann am macOS 10.14.5 ( https://support.apple.com/en-gb/HT210119).

Mar a nì thu tèarainte air pròiseasan agus leudachadh kernel ann am macOS

Chan urrainnear seo uile a dhèanamh ach ma tha an goireas agad air a chuir a-steach gu h-oifigeil san kernel. Is e sin, chan eil beàrnan mar sin ann airson bathar-bog taobh a-muigh agus gun iarraidh. Ach, mar a chì thu, tha feum air obair eadhon gus prògraman dligheach leithid antivirus agus siostaman cùl-taic a dhìon. Ach a-nis bidh dìon a bharrachd aig toraidhean ùra Acronis airson macOS an aghaidh luchdachadh sìos bhon t-siostam.

Source: www.habr.com

Cuir beachd ann