Meriv çawa pêvajo û dirêjkirina kernelê li ser macOS-ê diparêze

Silav Habr! Îro ez dixwazim bipeyivim ka hûn çawa dikarin pêvajoyên ji êrîşên ji hêla êrîşkaran ve di macOS-ê de biparêzin. Mînakî, ev ji bo pergalek antivirus an paşvekişandinê bikêr e, nemaze ji ber ku di bin macOS de çend awayên "kuştina" pêvajoyek hene. Li ser vê û rêbazên parastinê di bin qutkirinê de bixwînin.

Meriv çawa pêvajo û dirêjkirina kernelê li ser macOS-ê diparêze

Riya klasîk a "kuştina" pêvajoyek

Rêbazek naskirî ya "kuştina" pêvajoyek şandina sînyalek SIGKILL ji pêvajoyê re ye. Bi bash hûn dikarin standarda "bikujin -SIGKILL PID" an "pkill -9 NAME" ji bo kuştinê bi nav bikin. Fermana "kuştin" ji rojên UNIX-ê ve tê zanîn û ne tenê li ser macOS-ê, lê di heman demê de li ser pergalên din ên mîna UNIX-ê jî heye.

Mîna di pergalên mîna UNIX-ê de, macOS dihêle hûn pêvajoyek ji bilî duyan - SIGKILL û SIGSTOP-ê nîşan bidin. Ev gotar dê di serî de li ser sînyala SIGKILL wekî nîşanek ku dibe sedema kuştina pêvajoyek bisekine.

taybetmendiyên macOS

Li ser macOS, banga pergala kuştinê ya di kernel XNU de fonksiyona psignal (SIGKILL,...) vedibêje. Ka em hewl bidin ku bibînin ka çi kiryarên bikarhênerên din ên di cîhê bikarhêner de dikare ji hêla fonksiyona psignal ve were gotin. Werin em bangên fonksiyona psignalê di mekanîzmayên hundurîn ên kernelê de ji holê rakin (her çend ew ne hindik bin jî, em ê wan ji bo gotarek din bihêlin 🙂 - verastkirina îmzeyê, xeletiyên bîranînê, destwerdana derketin/dawîkirinê, binpêkirinên parastina pelan, hwd. .

Ka em vekolînê bi fonksiyon û banga pergala têkildar re dest pê bikin terminate_with_payload. Tê dîtin ku ji bilî banga kuştina klasîk, nêzîkatiyek alternatîf heye ku ji pergala xebitandina macOS-ê re taybetî ye û di BSD de nayê dîtin. Prensîbên xebitandinê yên her du bangên pergalê jî dişibin hev. Ew bangên rasterast ên psînyala fonksiyona kernel in. Di heman demê de bala xwe bidin ku berî kuştina pêvajoyek, kontrolek "cansignal" tête kirin - gelo pêvajo dikare îşaretek ji pêvajoyek din re bişîne; pergal rê nade tu serîlêdanek ku pêvajoyên pergalê bikuje, mînakî.

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

destpêkirin

Rêbaza standard a afirandina şeytan di destpêka pergalê de û kontrolkirina jiyana wan dest pê dike. Ji kerema xwe not bikin ku çavkanî ji bo guhertoya kevn a launchctl-ê heya macOS 10.10-ê ne, mînakên kodê ji bo mebestên ronî têne peyda kirin. Launchctl ya nûjen bi XPC-ê îşaretên dest pêkirî dişîne, mantiqa launchctl li wê hatî veguheztin.

Ka em binihêrin ka tam serlêdan çawa têne sekinandin. Berî şandina sînyala SIGTERM, bi karanîna banga pergala "proc_terminate" hewl tê dayîn ku serîlêdan were sekinandin.

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

Di bin hoodê de, proc_terminate, tevî navê xwe, dikare ne tenê psignalê bi SIGTERM, lê di heman demê de SIGKILL jî bişîne.

Kuştina nerasterast - Sînorê çavkaniyê

Di bangewaziya pergalek din de dozek balkêştir tê dîtin pêvajoya_polîtîka. Bikaranîna hevpar a vê banga pergalê sînorkirina çavkaniyên serîlêdanê ye, wek mînak ji bo nîşankerek ku dema CPU û kotayên bîranînê sînordar bike da ku pergal ji hêla çalakiyên vekêşana pelan ve bi girîngî hêdî nebe. Ger serîlêdanek gihîştibe sînorê çavkaniya xwe, wekî ku ji fonksiyona proc_apply_resource_actions tê dîtin, îşaretek SIGKILL ji pêvajoyê re tê şandin.

Her çend ev banga pergalê bi potansiyel dikare pêvajoyek bikuje jî, pergalê bi têra xwe mafên pêvajoya ku bangî pergalê dike kontrol nekir. Bi rastî kontrol dikin hebûn, lê bes e ku hûn ala alternatîf PROC_POLICY_ACTION_SET bikar bînin da ku vê şertê derbas bikin.

Ji ber vê yekê, heke hûn kotaya karanîna CPU ya serîlêdanê "sînor bikin" (mînakî, destûr bidin ku tenê 1 ns bixebitin), wê hingê hûn dikarin her pêvajoyê di pergalê de bikujin. Bi vî rengî, malware dikare her pêvajoyê li ser pergalê bikuje, tevî pêvajoya antivirus. Di heman demê de balkêş bandorek e ku dema ku pêvajoyek bi pid 1 (destpêkirin) dikuje çêdibe - panika kernel dema ku hewl dide ku nîşana SIGKILL pêvajoyê bike :)

Meriv çawa pêvajo û dirêjkirina kernelê li ser macOS-ê diparêze

Meriv çawa pirsgirêkê çareser bike?

Rêya herî rast a ku pêşî li kuştina pêvajoyek bigire ev e ku meriv nîşana fonksiyonê di tabloya banga pergalê de biguhezîne. Mixabin, ev rêbaz ji ber gelek sedeman ne hindik e.

Ya yekem, sembola ku cîhê bîranîna sysent kontrol dike ne tenê ji bo sembola kernelê XNU taybet e, lê di sembolên kernel de nayê dîtin. Pêdivî ye ku hûn rêbazên lêgerînê yên heurîstîkî bikar bînin, wek mînak bi dînamîk veqetandina fonksiyonê û lêgerîna nîşanek tê de.

Ya duyemîn, avahiya navnîşên di tabloyê de bi alayên ku kernel pê hatine berhev kirin ve girêdayî ye. Ger ala CONFIG_REQUIRES_U32_MUNGING were ragihandin, mezinahiya avahiyê dê were guheztin - qadek din dê were zêdekirin sy_arg_munge32. Pêdivî ye ku kontrolek zêde were kirin da ku diyar bike ka kernel bi kîjan ala ve hatî berhev kirin, an wekî din, nîşangirên fonksiyonê li hember yên naskirî kontrol bikin.

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

Xwezî, di guhertoyên nûjen ên macOS de, Apple ji bo xebata bi pêvajoyan re API-ya nû peyda dike. Endpoint Ewlekariya API destûrê dide xerîdaran ku destûr bidin gelek daxwaznameyên pêvajoyên din. Bi vî rengî, hûn dikarin bi karanîna API-ya ku li jor behs kirî, her îşaretek pêvajoyê asteng bikin, tevî nîşana 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;
}

Bi heman rengî, Siyasetek MAC dikare di kernelê de were tomar kirin, ku rêbazek parastina nîşanê peyda dike (polîtîka proc_check_signal), lê API bi fermî nayê piştgirî kirin.

Parastina dirêjkirina Kernel

Ji bilî parastina pêvajoyên di pergalê de, parastina dirêjkirina kernel bixwe (kext) jî hewce ye. macOS ji bo pêşdebiran çarçoveyek peyda dike ku bi hêsanî ajokarên cîhaza IOKit pêşve bibin. Digel peydakirina amûrên ji bo xebata bi cîhazan re, IOKit bi karanîna nimûneyên çînên C++ re rêbazên ji bo stackkirina ajokar peyda dike. Serlêdanek di qada bikarhêner de dê bikaribe mînakek qeydkirî ya polê "bibîne" da ku têkiliyek kernel-bikarhênerî saz bike.

Ji bo tesbîtkirina hejmara mînakên pola di pergalê de, kargêriya ioclasscount heye.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Berfirehkirina kernelê ya ku bixwaze bi staka ajokerê re qeyd bike, divê çînek ku ji IOService mîras digire, diyar bike, mînakî my_kext_ioservice di vê rewşê de. Girêdana sepanên bikarhêner dibe sedema afirandina mînakek nû ya çîna ku ji IOUserClient mîras digire, di mînaka my_kext_iouserclient de.

Dema ku hûn hewl didin ku ajokerek ji pergalê dakêşin (fermana kextunload), fonksiyona virtual "bool terminate (vebijarkên IOOptionBits)" tê gotin. Dema ku hewl didin dakêşandinê ji bo neçalakkirina kextunloadê vegerînin derewîn li ser bangê bes e ku biqede.

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

Ala IsUnloadAllowed dikare dema barkirinê ji hêla IOUserClient ve were danîn. Dema ku sînorek dakêşanê hebe, emrê kextunload dê encamek jêrîn vegerîne:

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.

Pêdivî ye ku parastinek wusa ji bo IOUserClient were kirin. Mînakên dersan dikarin bi karanîna fonksiyona cîhê bikarhênerê IOKitLib "IOCatalogueTerminate(mach_port_t, ala uint32_t, danasîna io_name_t);" werin rakirin. Hûn dikarin dema ku emrê "bidawîkirin" vedigirin heya ku serîlêdana cîhê bikarhêner "bimire", ango fonksiyona "clientDied" neyê gazî kirin.

Parastina pelê

Ji bo parastina pelan, bes e ku hûn API-ya Kauth bikar bînin, ku dihêle hûn gihîştina pelan sînordar bikin. Apple ji pêşdebiran re di derheqê bûyerên cihêreng ên di çarçovê de agahdariyan peyda dike; ji bo me, operasyonên KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA û KAUTH_VNODE_DELETE_CHILD girîng in. Rêya herî hêsan a sînorkirina gihîştina pelan bi rê ye - em API-ya "vn_getpath" bikar tînin da ku rê li pelê bigirin û pêşgira rê bidin ber hev. Bala xwe bidinê ku ji bo veguherandina navên riyên peldanka pelan xweşbîn bikin, pergal destûr nade ku bigihîje her pelê, lê tenê peldanka ku hatî guheztin bixwe. Pêdivî ye ku hûn riya dêûbav bidin ber hev û ji bo wê KAUTH_VNODE_DELETE sînordar bikin.

Meriv çawa pêvajo û dirêjkirina kernelê li ser macOS-ê diparêze

Kêmasiya vê nêzîkbûnê dibe ku performansa kêm be ji ber ku hejmara pêşgiran zêde dibe. Ji bo ku berhevok ne wekhevî O (pêşgir* dirêjahî) ye, li cihê ku pêşgir hejmara pêşgiran e, dirêjî dirêjahiya rêzê ye, hûn dikarin otomatek bêdawî ya diyarker (DFA) ku ji hêla pêşgiran ve hatî çêkirin bikar bînin.

Ka em rêbazek ji bo avakirina DFA-yê ji bo komek pêşgirek diyar binirxînin. Em li destpêka her pêşgirek kursoran destnîşan dikin. Heger hemû nîşangir nîşanî heman karakterê bidin, wê hingê her nîşanderê bi yek karakterek zêde bikin û ji bîr nekin ku dirêjahiya heman rêzê yek bi yek mezintir e. Ger du cursorên bi sembolên cuda hebin, li gorî sembola ku nîşanî wan didin, kursoran li koman dabeş bikin û ji bo her komê algorîtmayê dubare bikin.

Di doza yekem de (hemû karakterên di binê şanokan de yek in), em rewşek DFA-yê digirin ku li ser heman xetê tenê veguheztinek heye. Di rewşa duyemîn de, em tabloyek veguheztina mezinahiya 256 (hejmara tîpan û hejmara herî zêde ya koman) berbi dewletên paşîn ên ku bi gazîkirina paşverû ya fonksiyonê têne wergirtin, digirin.

Ka em li mînakekê binêrin. Ji bo komek pêşgiran ("/foo/bar/tmp/", "/var/db/foo/", "/foo/bar/aba/", "foo/bar/aac/") hûn dikarin jêrîn bistînin DFA. Di jimarê de tenê veguherînên ku berbi dewletên din ve diçin nîşan dide; veguheztinên din dê ne dawî bin.

Meriv çawa pêvajo û dirêjkirina kernelê li ser macOS-ê diparêze

Dema ku di nav dewletên DKA re derbas dibe, dibe ku 3 bûyer hebin.

  1. Rewşa dawîn gihîştiye - rê parastî ye, em operasyonên KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA û KAUTH_VNODE_DELETE_CHILD sînordar dikin
  2. Rewşa dawîn negihîştiye, lê rê "bi dawî bû" (dawkarê null hat gihîştin) - rê dêûbav e, pêdivî ye ku KAUTH_VNODE_DELETE sînordar bike. Bala xwe bidinê ku ger vnode peldankek be, divê hûn li dawiyê '/' lê zêde bikin, wekî din ew dikare wê bi pelê "/foor/bar/t" ve sînordar bike, ku xelet e.
  3. Rewşa dawî nehat, rê neqediya. Yek ji pêşgiran bi vê yekê re nagihêje hev, em sînordar nakin.

encamê

Armanca çareseriyên ewlehiyê yên ku têne pêşve xistin ew e ku asta ewlehiya bikarhêner û daneyên wî zêde bikin. Ji aliyek ve, ev armanc bi pêşkeftina hilbera nermalava Acronis ve tê bidestxistin, ku wan qelsiyên ku pergala xebitandinê bixwe "qels e" digire. Ji aliyek din ve, nabe ku em ji bihêzkirina wan aliyên ewlehiyê yên ku dikarin di aliyê OS-ê de bêne baştir kirin îhmal nekin, nemaze ji ber ku girtina lawaziyên weha aramiya me wekî hilberek zêde dike. Zelalbûn ji Tîma Ewlekariya Hilbera Apple re hate ragihandin û di macOS 10.14.5 (https://support.apple.com/en-gb/HT210119) de hatî rast kirin.

Meriv çawa pêvajo û dirêjkirina kernelê li ser macOS-ê diparêze

Hemî ev tenê dikare were kirin heke amûra we bi fermî di kernelê de hatî saz kirin. Ango ji bo nermalava derve û nexwestî qulên weha tune. Lêbelê, wekî ku hûn dibînin, tewra parastina bernameyên rewa yên wekî pergalên antivirus û hilanînê jî xebat hewce dike. Lê naha hilberên nû yên Acronis ji bo macOS-ê dê li hember dakêşana pergalê xwedî parastinek zêde bin.

Source: www.habr.com

Add a comment