Yadda ake kare matakai da haɓaka kernel akan macOS

Hello, Habr! A yau zan so in yi magana game da yadda zaku iya kare tsari daga harin maharan a cikin macOS. Misali, wannan yana da amfani ga tsarin rigakafi ko tsarin ajiya, musamman tunda a ƙarƙashin macOS akwai hanyoyi da yawa don “kashe” tsari. Karanta game da wannan da hanyoyin kariya a ƙarƙashin yanke.

Yadda ake kare matakai da haɓaka kernel akan macOS

Hanyar gargajiya don "kashe" tsari

Wata sanannen hanyar "kashe" tsari shine aika siginar SIGKILL zuwa tsarin. Ta hanyar bash zaka iya kiran daidaitaccen "kill -SIGKILL PID" ko "pkill -9 NAME" don kashe. An san umarnin "kashe" tun zamanin UNIX kuma yana samuwa ba kawai a kan macOS ba, har ma a kan sauran tsarin UNIX.

Kamar dai a cikin tsarin UNIX, macOS yana ba ku damar kutse kowane sigina zuwa tsari sai biyu - SIGKILL da SIGSTOP. Wannan labarin zai fara mayar da hankali kan siginar SIGKILL azaman sigina wanda ke haifar da kashe wani tsari.

macOS takamaiman

A kan macOS, tsarin kisa yana kira a cikin XNU kernel yana kiran aikin psignal (SIGKILL, ...). Bari mu yi ƙoƙari mu ga abin da sauran ayyukan mai amfani a cikin sararin mai amfani za a iya kira ta aikin psignal. Bari mu kawar da kira zuwa aikin psignal a cikin hanyoyin ciki na kernel (ko da yake suna iya zama marasa mahimmanci, za mu bar su don wani labarin 🙂 - Tabbatar da sa hannu, kurakuran ƙwaƙwalwar ajiya, fitarwa / ƙare sarrafawa, keta kariyar fayil, da sauransu. .

Bari mu fara bita tare da aikin da kiran tsarin da ya dace ƙare_da_load_load. Ana iya ganin cewa ban da kiran kisa na al'ada, akwai wata hanya ta dabam wacce ta keɓance ga tsarin aiki na macOS kuma ba a samu a cikin BSD ba. Ka'idodin aiki na duka tsarin kiran kira iri ɗaya ne. Kira ne kai tsaye zuwa siginar aikin kwaya. Har ila yau, lura cewa kafin kashe wani tsari, ana yin rajistan "cansignal" - ko tsarin zai iya aika sigina zuwa wani tsari; tsarin ba ya ƙyale kowane aikace-aikacen kashe tsarin tsarin, misali.

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

kaddamar

An ƙaddamar da daidaitaccen hanyar ƙirƙirar daemon a farawa tsarin da sarrafa rayuwarsu. Da fatan za a lura cewa kafofin sun kasance don tsohuwar sigar launchctl har zuwa macOS 10.10, ana ba da misalan lambobin don dalilai na misali. Launchtl na zamani yana aika sigina da aka ƙaddamar ta hanyar XPC, ƙaddamar da dabaru an motsa shi zuwa gare shi.

Bari mu kalli yadda ake dakatar da aikace-aikacen daidai. Kafin aika siginar SIGTERM, ana ƙoƙarin dakatar da aikace-aikacen ta amfani da tsarin "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));
		} 
...
<>

Ƙarƙashin murfin, proc_terminate, duk da sunansa, zai iya aika ba kawai tare da SIGTERM ba, har ma da SIGKILL.

Kashe Kai tsaye - Iyakar albarkatun

Ana iya ganin shari'ar mai ban sha'awa a cikin wani tsarin kira tsari_siyasa. Amfani na yau da kullun na wannan tsarin kiran shine iyakance albarkatun aikace-aikacen, kamar don mai ƙididdigewa don iyakance lokacin CPU da adadin ƙwaƙwalwar ajiya don kada tsarin ya ragu sosai ta ayyukan caching fayil. Idan aikace-aikacen ya kai iyakar albarkatun sa, kamar yadda ake iya gani daga aikin proc_apply_resource_actions, ana aika siginar SIGKILL zuwa aikin.

Kodayake wannan kiran tsarin na iya yin yuwuwar kashe wani tsari, tsarin bai bincikar haƙƙin tsarin kiran tsarin ba. Ainihin dubawa ya wanzu, amma ya isa a yi amfani da madadin tuta PROC_POLICY_ACTION_SET don tsallake wannan yanayin.

Don haka, idan kun “iyakance” adadin amfanin CPU na aikace-aikacen (misali, kyale 1 ns kawai yayi aiki), to zaku iya kashe kowane tsari a cikin tsarin. Don haka, malware na iya kashe kowane tsari akan tsarin, gami da tsarin riga-kafi. Hakanan mai ban sha'awa shine tasirin da ke faruwa lokacin kashe tsari tare da pid 1 (launchctl) - fargabar kernel lokacin ƙoƙarin aiwatar da siginar SIGKILL:)

Yadda ake kare matakai da haɓaka kernel akan macOS

Yadda za a magance matsalar?

Hanya mafi sauƙi don hana tsari daga kashe shi shine maye gurbin mai nuna aikin a cikin tsarin kiran tsarin. Abin takaici, wannan hanyar ba ta da mahimmanci saboda dalilai da yawa.

Na farko, alamar da ke sarrafa wurin ƙwaƙwalwar ajiyar sysent ba ta sirri ce kawai ga alamar kernel ta XNU ba, amma ba za a iya samun ta a cikin alamun kwaya ba. Dole ne ku yi amfani da hanyoyin bincike na heuristic, kamar tarwatsa aikin a hankali da neman mai nuni a ciki.

Na biyu, tsarin shigarwar a cikin tebur ya dogara da tutocin da aka haɗa kwaya da su. Idan an ayyana tutar CONFIG_REQUIRES_U32_MUNGING, za a canza girman tsarin - za a ƙara ƙarin filin sy_arg_munge32. Wajibi ne a gudanar da ƙarin bincike don sanin ko wace tutar kernel ɗin aka haɗa tare da, ko a madadin, bincika masu nunin ayyuka akan sanannun.

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

Abin farin ciki, a cikin nau'ikan macOS na zamani, Apple yana ba da sabon API don aiki tare da matakai. API ɗin Tsaro na Ƙarshen Yana ba abokan ciniki damar ba da izinin buƙatun da yawa zuwa wasu matakai. Don haka, zaku iya toshe kowace sigina zuwa tsari, gami da siginar SIGKILL, ta amfani da API ɗin da aka ambata a sama.

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

Hakazalika, ana iya yin rajistar Manufofin MAC a cikin kernel, wanda ke ba da hanyar kariya ta sigina (manufa proc_check_signal), amma API ɗin ba ta da tallafi a hukumance.

Kariyar tsawan kwaya

Baya ga tsare-tsare a cikin tsarin, kare haɓakar kwaya da kanta (kext) shima wajibi ne. macOS yana ba da tsari don masu haɓakawa don haɓaka direbobin na'urar IOKit cikin sauƙi. Baya ga samar da kayan aiki don aiki tare da na'urori, IOKit yana ba da hanyoyi don tarawa direba ta amfani da misalin azuzuwan C++. Aikace-aikace a cikin sararin mai amfani zai iya "nemo" misali mai rijista na ajin don kafa dangantakar kernel-space.

Don gano adadin lokutan aji a cikin tsarin, akwai mai amfani da ioclasscount.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Duk wani tsawo na kernel da ke son yin rajista tare da tarin direba dole ne ya bayyana wani aji wanda ya gaji daga sabis na IOS, misali my_kext_ioservice a wannan yanayin. Haɗin aikace-aikacen mai amfani yana haifar da sabon misali na ajin da ya gaji daga IOUserClient, a cikin misali my_kext_iouserclient.

Lokacin ƙoƙarin sauke direba daga tsarin (umarnin kextunload), ana kiran aikin kama-da-wane “bool terminate (zaɓuɓɓukan IOOptionBits)”. Ya isa a mayar da karya akan kira don ƙarewa lokacin ƙoƙarin saukewa don kashe kextunload.

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

IOUserClient na iya saita tutar IsUnloadAllowed lokacin lodawa. Lokacin da aka sami iyakar saukewa, umarnin kextunload zai dawo da fitarwa mai zuwa:

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.

Dole ne a yi irin wannan kariyar ga IOUserClient. Ana iya sauke misalan azuzuwan ta amfani da aikin IOKitLib mai amfani "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t description);". Kuna iya dawo da karya lokacin kiran umarnin “kashe” har sai aikace-aikacen sarari “mutuwa”, wato, aikin “clientDied” ba a kira ba.

Kariyar Fayil

Don kare fayiloli, ya isa a yi amfani da Kauth API, wanda ke ba ku damar ƙuntata damar yin amfani da fayiloli. Apple yana ba masu haɓaka sanarwar sanarwa game da abubuwan da suka faru daban-daban a cikin iyaka; a gare mu, ayyukan KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA da KAUTH_VNODE_DELETE_CHILD suna da mahimmanci. Hanya mafi sauƙi don ƙuntata damar yin amfani da fayiloli ita ce ta hanya - muna amfani da API "vn_getpath" don samun hanyar zuwa fayil kuma kwatanta prefix na hanya. Lura cewa don inganta sake suna na hanyoyin babban fayil ɗin, tsarin ba ya ba da izini ga kowane fayil, amma ga babban fayil ɗin da aka sake masa suna. Wajibi ne a kwatanta hanyar iyaye kuma a taƙaita KAUTH_VNODE_DELETE don ita.

Yadda ake kare matakai da haɓaka kernel akan macOS

Rashin lahani na wannan hanya na iya zama ƙarancin aiki yayin da adadin prefixes ke ƙaruwa. Don tabbatar da cewa kwatancen bai yi daidai da O (prefix * tsayi), inda prefix shine adadin prefixes, tsayi shine tsayin kirtani, zaku iya amfani da ƙayyadaddun iyaka ta atomatik (DFA) wanda aka gina ta prefixes.

Bari mu yi la'akari da hanya don gina DFA don wani saitin prefixes. Muna fara siginan kwamfuta a farkon kowane prefix. Idan duk masu siginan kwamfuta suna nuni zuwa hali iri ɗaya, to ƙara kowane siginan kwamfuta da haruffa ɗaya kuma ku tuna cewa tsayin layin ɗaya ya fi girma da ɗaya. Idan akwai lambobi biyu masu alamomi daban-daban, raba masu siginan kwamfuta zuwa rukuni bisa ga alamar da suke nunawa kuma a maimaita algorithm na kowane rukuni.

A cikin shari'ar farko (duk haruffan da ke ƙarƙashin siginan kwamfuta iri ɗaya ne), muna samun yanayin DFA wanda ke da sauyi ɗaya kawai tare da layi ɗaya. A cikin akwati na biyu, muna samun tebur na jujjuyawar girman 256 (yawan haruffa da matsakaicin adadin ƙungiyoyi) zuwa jihohin da aka samu ta hanyar kiran aikin akai-akai.

Bari mu kalli misali. Don saitin prefixes ("/foo/bar/tmp/", "/var/db/foo/", "/foo/bar/aba/", "foo/bar/aac/") zaka iya samun wadannan DFA. Adadin ya nuna kawai sauye-sauyen da za su kai ga wasu jihohi; sauran sauye-sauyen ba za su kasance na ƙarshe ba.

Yadda ake kare matakai da haɓaka kernel akan macOS

Lokacin shiga cikin jihohin DKA, ana iya samun lokuta 3.

  1. An kai ga ƙarshe - hanyar tana da kariya, muna iyakance ayyukan KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA da KAUTH_VNODE_DELETE_CHILD
  2. Ba a kai ga ƙarshe na jihar ba, amma hanyar "ya ƙare" (an kai ga ƙarshen ƙarshen) - hanyar ita ce iyaye, wajibi ne a iyakance KAUTH_VNODE_DELETE. Lura cewa idan vnode babban fayil ne, kuna buƙatar ƙara '/' a ƙarshe, in ba haka ba yana iya iyakance shi zuwa fayil ɗin “/foor/bar/t”, wanda ba daidai bane.
  3. Ba a kai ga ƙarshe ba, hanyar ba ta ƙare ba. Babu ɗaya daga cikin prefixes da ya dace da wannan, ba mu gabatar da hani.

ƙarshe

Manufar hanyoyin samar da tsaro shine haɓaka matakin tsaro na mai amfani da bayanansa. A gefe guda, an cimma wannan burin ta hanyar haɓaka samfurin software na Acronis, wanda ke rufe waɗannan raunin inda tsarin aiki da kansa ya kasance "rauni". A gefe guda, bai kamata mu yi sakaci da ƙarfafa waɗannan abubuwan tsaro waɗanda za a iya inganta su ta bangaren OS ba, musamman tunda rufe irin wannan raunin yana ƙara kwanciyar hankalinmu azaman samfuri. An ba da rahoton raunin ga Ƙungiyar Tsaron Samfurin Apple kuma an daidaita shi a cikin macOS 10.14.5 (https://support.apple.com/en-gb/HT210119).

Yadda ake kare matakai da haɓaka kernel akan macOS

Duk waɗannan za a iya yi kawai idan an shigar da kayan aikin ku a hukumance a cikin kwaya. Wato babu irin wannan madogara na software na waje da maras so. Koyaya, kamar yadda kuke gani, ko da kare halaltattun shirye-shirye kamar su riga-kafi da tsarin ajiya yana buƙatar aiki. Amma yanzu sabbin samfuran Acronis na macOS za su sami ƙarin kariya daga saukewa daga tsarin.

source: www.habr.com

Add a comment