jak vytvořit antivirový engine
Úvod
když se potuluji po fórech techniků, často vidím některé lidi (a mnoho z nich není příliš zkušených), kteří se ptají na „Jak vytvořím antivirus“, někdy s nepříliš přizpůsobenými jazyky (bat, PHP,…) a mají špatnou představu o tom, co je antivirus a jak by měl být postaven.
také jsem viděl mnoho „antivirových softwarů“ od kiddies, s velmi málo lidí ve škole a asi 4 hodiny denně kódování na několik týdnů. Neříkám, že děti nejsou kvalifikované, ale říkám, že budování antivirového motoru potřebuje buď hodně kvalifikovaných lidí s prací na plný úvazek plus spoustu času na uvolnění slušného softwaru ,nebo spoustu peněz na jejich zaplacení 🙂 (v případě, že nejsou dobrovolníci).
takže zde budu pokrývat pokyny pro základní antivirové kódování, pro Windows a v c / c++. Jeden může najít zde ukazatele navrhnout antivirový engine, nebo jednoduše zjistit, jak většina z nich jsou postaveny.
ochrana
pro dobrou ochranu musí mít antivirový program alespoň jeden ovladač, aby mohl spouštět kód v jádře a celkově mít přístup k API jádra. Počínaje Vista Microsoft pochopil, že antivirový průmysl potřebuje klíče pro vstup do jádra a aktivaci filtrů na strategických místech, jako je souborový systém, registr a síť. Nenechte se ohromit, pokud budování antiviru pro systémy pre-Vista může být skutečnou bolestí, protože pro to nebyl navržen.
- v systémech Pre-Vista však antivirové společnosti používaly funkce podobné rootkitům k ochraně dveří(i když to Microsoft vůbec nedoporučoval) a být schopen chránit váš systém. Použili to, čemu říkáme „háčky“ (objížďky API pro účely filtrování).
- v systému Vista + společnost Microsoft poskytla rozhraní API pro vložení ovladače nízké úrovně mezi hovory userland a API jádra. Tímto způsobem je snadné zaregistrovat antivirový produkt do jádra. Více, tento druh registrace založený systém nám umožňuje expedovat naše zabezpečení systému do vrstev, kde několik produktů s různými cíli může žít společně. To nebyl případ háčků, protože implementace byla zcela závislá na produktu.
poznámka: Nebudu pokrývat řešení háčky pro systémy pre-Vista, protože je snadné je najít na internetu a protože by to vyžadovalo celou kapitolu, která by vysvětlila, jak zavěsit, kam zavěsit a tak… ale musíte vědět, že je to stejný nápad než API jádra, kromě toho, že musíte implementovat sami to, co společnost Microsoft poskytla na systémech Vista+.
Chcete-li se dozvědět o ovladačích kódování, můžete zkontrolovat, zda jsou užitečné odkazy:
http://msdn.microsoft.com/en-us/library/windows/hardware/gg490655.aspx
http://www.codeproject.com/Articles/9504/Driver-Development-Part-1-Introduction-to-Drivers
Chcete-li se dozvědět o háčky, můžete zkontrolovat, že základní příklad:
http://www.unknowncheats.me/forum/c-and-c/59147-writing-drivers-perform-kernel-level-ssdt-hooking.html
proces
první věc, která chrání uživatele Před, je spuštění škodlivých procesů. To je základní věc. Antivirus by měl zaregistrovat zpětné volání PsSetCreateProcessNotifyRoutineEx. Tímto způsobem je při každém vytvoření procesu a před spuštěním hlavního vlákna (a způsobením škodlivých věcí) oznámeno antivirové zpětné volání a obdrží všechny potřebné informace.
obdrží název procesu, objekt souboru, PID a tak dále. Vzhledem k tomu, že proces čeká, může řidič sdělit své službě, aby analyzovala paměť procesu pro cokoli škodlivého. To něco najde, řidič jednoduše nastaví CreationStatus na FALSE a vrátí se.
NTSTATUS PsSetCreateProcessNotifyRoutineEx( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, _In_ BOOLEAN Remove);
VOID CreateProcessNotifyEx( _Inout_ PEPROCESS Process, _In_ HANDLE ProcessId, _In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo);
typedef struct _PS_CREATE_NOTIFY_INFO { SIZE_T Size; union { ULONG Flags; struct { ULONG FileOpenNameAvailable :1; ULONG Reserved :31; }; }; HANDLE ParentProcessId; CLIENT_ID CreatingThreadId; struct _FILE_OBJECT *FileObject; PCUNICODE_STRING ImageFileName; PCUNICODE_STRING CommandLine; NTSTATUS CreationStatus;} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;
vlákna
ve stejné myšlence než pro procesy mohou být vlákna způsobem, jak škodlivé věci způsobit škody. Například jeden může vložit nějaký kód do legitimního procesu a spustit vzdálené vlákno na tomto kódu v kontextu procesu (snadné sledovat? 🙂 ). Tímto způsobem může legitimní proces dělat škodlivé věci.
můžeme filtrovat nová vlákna pomocí zpětného volání PsSetCreateThreadNotifyRoutine. Při každém vytvoření podprocesu je antivirový program upozorněn TID a PID. Je tedy schopen nahlédnout do kódu počáteční adresy vlákna, analyzovat jej a buď vlákno zastavit, nebo jej obnovit.
NTSTATUS PsSetCreateThreadNotifyRoutine( _In_ PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine);
VOID(*PCREATE_THREAD_NOTIFY_ROUTINE) ( IN HANDLE ProcessId, IN HANDLE ThreadId, IN BOOLEAN Create );
obrázky
třetí dynamická hrozba se týká obrázků, které lze načíst do paměti. Obrázek je soubor PE, buď EXE, DLL nebo SYS soubor. Chcete-li být upozorněni na načtených obrázků, jednoduše zaregistrovat PsSetLoadImageNotifyRoutine. Toto zpětné volání nám umožňuje být upozorněni, když je obraz načten do virtuální paměti, i když není nikdy spuštěn. Poté můžeme zjistit, kdy se proces pokusí načíst DLL, načíst ovladač nebo spustit nový proces.
zpětné volání získá informace o úplné cestě obrazu (užitečné pro statickou analýzu) a důležitější podle mého názoru je adresa základny obrazu(pro analýzu v paměti). Pokud je obrázek škodlivý, antivirus může použít malé triky, aby se vyhnul spuštění, jako je analýza obrazu v paměti a přechod na entrypoint, pak zavolejte opcode sestavy „ret“, abyste jej zrušili.
NTSTATUS PsSetLoadImageNotifyRoutine( _In_ PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine);
VOID (*PLOAD_IMAGE_NOTIFY_ROUTINE)( __in_opt PUNICODE_STRING FullImageName, __in HANDLE ProcessId, __in PIMAGE_INFO ImageInfo );
typedef struct _IMAGE_INFO { union { ULONG Properties; struct { ULONG ImageAddressingMode : 8; //code addressing mode ULONG SystemModeImage : 1; //system mode image ULONG ImageMappedToAllPids : 1; //mapped in all processes ULONG Reserved : 22; }; }; PVOID ImageBase; ULONG ImageSelector; ULONG ImageSize; ULONG ImageSectionNumber;} IMAGE_INFO, *PIMAGE_INFO;
souborový systém
jakmile je každá dynamická věc zabezpečena, antivirový program by měl být schopen upozornit uživatele na škodlivé věci za běhu, a to nejen tehdy, když se chystají začít. Antivirus by měl být schopen skenovat soubory, když uživatel otevře složku, archiv nebo když je stažen na disk. Antivirový program by měl být schopen se chránit tím, že zakáže jakémukoli programu mazat jeho soubory.
způsob, jak to udělat, je nainstalovat ovladač do systému souborů a konkrétněji minifilter staršího filtru (old way). Zde budeme hovořit o minifilteru.
minifilter je specifický druh ovladače, který je schopen registrovat zpětná volání při každé operaci čtení / zápisu provedené v systému souborů (IRP major functions). IRP (Interrupt Request Paquet) je objekt používaný k popisu operace čtení/zápisu na disku, který je přenášen spolu se zásobníkem ovladačů. Minifilter bude jednoduše vložen do tohoto zásobníku a obdrží IRP, aby se rozhodl, co s ním dělat (povolit/zakázat operaci).
pro malý příklad minifilteru zkontrolujte prosím ten užitečný odkaz nebo ten. Pokyny společnosti microsoft jsou zde.
zde a zde najdete také 2 příklady dokumentace WDK.
základní zpětné volání minifilteru vypadá takto. Existují 2 druhy zpětného volání, před operací a po operaci, které jsou schopny filtrovat před po dotazu. Zde je pseudo kód předoperace:
FLT_PREOP_CALLBACK_STATUS PreOperationCallback (__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext){ ... if ( all_good ) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } else { // Access denied Data->IoStatus.Information = 0; Data->IoStatus.Status = STATUS_ACCESS_DENIED; return FLT_PREOP_COMPLETE; } }
registr
registr je jedním z nejkritičtějších míst k ochraně. Existuje mnoho způsobů, jak malware udržet trvalou ruku v systému registrací jednoho (nebo několika) klíčů / hodnot do registru. Nejznámějšími místy jsou spouštěcí klíče a služby. Toto je také místo, kde lze antivirový program porazit (spolu se systémem souborů) jednoduchým odstraněním jeho ovladačů/servisních klíčů, takže se již nebude restartovat při spuštění systému.
Toto není skutečná nutnost, aby antivirový program chránil místa restartu, většina z nich ne. ale musí chránit své instalační klíče registru, aby se zabránilo snadné porážce malwarů. To lze provést registrací CmRegisterCallback.
zpětné volání poskytuje dostatek informací pro získání úplného názvu klíče, druhu přístupu (vytvoření, Přejmenování, Odstranění, … ) a PID volajícího. Tímto způsobem je snadné udělit přístup k hovoru nebo ne, nastavením stavového pole po operaci zpětné volání.
NTSTATUS CmRegisterCallbackEx(_In_ PEX_CALLBACK_FUNCTION Function,_In_ PCUNICODE_STRING Altitude,_In_ PVOID Driver,_In_opt_ PVOID Context,_Out_ PLARGE_INTEGER Cookie,_Reserved_ PVOID Reserved);
EX_CALLBACK_FUNCTION RegistryCallback;NTSTATUS RegistryCallback( _In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2){ ... }Argument1 = typedef enum _REG_NOTIFY_CLASS { RegNtDeleteKey, RegNtPreDeleteKey = RegNtDeleteKey,...Argument2 = typedef struct _REG_POST_OPERATION_INFORMATION { PVOID Object; NTSTATUS Status; PVOID PreInformation; NTSTATUS ReturnStatus; PVOID CallContext; PVOID ObjectContext; PVOID Reserved;} REG_POST_OPERATION_INFORMATION, *PREG_POST_OPERATION_INFORMATION;
síť (Firewall)
Chcete-li chránit dveře celého internetového provozu, který může být v určitých systémech (servery, uživatelé s velkou šířkou pásma) obrovský, aniž by byl zpomalen přepínáním kontextu, ke kterému dochází v userland, nedoporučuje se instalovat firewall, který nemá žádný základní ovladač, s výjimkou některých filtrů webového prohlížeče, které mohou stačit pro provoz http, ale které nebudou chránit před malwarovou komunikací dovnitř/ven.
aby bylo možné správně implementovat firewall, je třeba kódovat NDIS, TDI nebo jinou metodu pro ovladač filtrování IP nízké úrovně. NDIS / TDI je trochu složitější a vyžaduje hodně znalostí(podle mého názoru více než jiné filtry).
Každopádně je zde několik ukazatelů, jak začít kódovat takový ovladač, pokyny společnosti microsoft a starý tutoriál codeproject (ale stále je dobré číst), příklad brány NDIS firewall a příklad brány TDI firewall. Zde je také dobré psaní o triku NDIS firewall bypass a malé vysvětlení o zásobníku síťových ovladačů,
ochrana uživatelů
ochrana uživatelů není nutností, ale může být dalším modulem proti trojským bankéřům a konkrétněji proti procesním špionům. Obvykle se injektují do každého procesu z několika důvodů.
nejprve jsou schopni (na vyžádání) zabít proces, pokud byl identifikován jako malware(to by se nemělo stát ,protože AVs ho mají zastavit dříve, než začne). Vždy je snazší zastavit proces, když jste v jeho kontextu.
za druhé jsou schopni chránit kritický proces, jako webové prohlížeče, proti hákování malwarů schopných objíždět a filtrovat volání API za účelem shromažďování hesel, bankovních informací a přesměrování internetového toku na malware servery. Sledují pouze modifikaci IAT, sestřih, a mohou také nastavit háčky sami, aby se zabránilo LoadLibray malware DLL, a tak zakázat určité metody vstřikování kódu.
snadný způsob, jak vložit Protector DLL do všech procesů, je použít klíč registru AppInitDll k registraci Protector DLL. Načte DLL do každého procesu spuštěného v systému, jakmile propojí User32.dll image (většina z nich dělá).
analytický motor
analytický motor je jednou z nejdůležitějších částí, je zodpovědný za analýzu vzorků souborů / paměti pocházejících z ovladačů. Pokud musí být rychlý (i s obrovskou databází), a měl by být schopen zvládnout většinu typů souborů (Samostatně extrahované spustitelné soubory, archivy-RAR, ZIP, zabalené soubory-UPX,…), a proto by měl mít mnoho modulů k tomu:
- Rozbalovač: tento modul musí být schopen detekovat a rozbalit většinu známých baličů (UPX, Armadillo, ASPack, …)
- podpisový motor: databáze antiviru obsahuje miliony podpisů a motor by měl být schopen je rychle vyhledat do vzorku. Jeho součástí by tedy měl být velmi silný algoritmus. Příklad : AhoCorasick, RabinKarp, řetězce odpovídající algoritmy.
- Sandbox: tento modul není nutný , ale byl by plus, aby bylo možné spouštět vzorky do omezené paměti bez vlivu na systém. To by mohlo pomoci rozbalit vzorky zabalené s neznámými baliči a pomoci heuristickému motoru (viz dále) detekovat volání API, která by mohla být považována za podezřelá nebo škodlivá. Nějaké dobré pískoviště zde.
- heuristický motor: jak bylo uvedeno výše, heuristický motor nehledá podpisy, ale spíše hledá podezřelé chování (tj. ukázka, která otevře připojení na webových stránkách hxxp: / / malware_besite. com). To lze provést statickou analýzou nebo pomocí karantény.
syntaxe podpisu
syntaxe podpisu je „slovník“ jazyka, kterému podpisový motor rozumí. Je to způsob, jak formalizovat, co je vzor najít, jak ji hledat a kde ji hledat do vzorku. Syntaxe musí být dostatečně jednoduchá, aby vědci pochopili, dostatečně silná, aby zvládla každý případ použití, a snadno analyzovat pro lepší výkon motoru.
VirusTotal vyvinul dobrou syntaxi a engine (Yara project), což je open source. To by mělo být dobrým ukazatelem pro vytvoření vlastní syntaxe, nebo ji jednoduše použít. Zde je také dobrý příspěvek blog o tom, jak vytvářet podpisy pro antivirus.
příklad podpisu:
rule silent_banker : banker{ meta: description = "This is just an example" thread_level = 3 in_the_wild = true strings: $a = {6A 40 68 00 30 00 00 6A 14 8D 91} $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" condition: $a or $b or $c}
vlastní ochrana
vlastní ochrana je pro antivirový program velmi důležitá, aby nedošlo k porážce malwarem a nadále chránila uživatele. To je důvod, proč by antivirový program měl být schopen chránit svou vlastní instalaci a udržovat vytrvalost při restartu.
existuje několik míst k ochraně: soubory, klíče registru, procesy/vlákna, paměť.
- Ochrana souborů je implementována do minifilteru, se zvláštními pravidly pro soubory antiviru (žádný přístup k mazání, přejmenování, přesunutí, zápis).
- ochrana registru je provedena do filtru registru, přičemž přístup byl odepřen pro klíče registru ovladače a služby.
- vlákna ovladačů jsou chráněna, protože je zcela nemožné uvolnit modul jádra bez zhroucení systému
- , aby bylo možné chránit službu, což je proces userland, řešení 2:
- nejjednodušší by bylo přidat pravidla pro selhání ve Správci služeb a nastavit každé pravidlo selhání na „restartovat službu“. Tímto způsobem, když služba není zastavena správcem služeb, restartuje se. Služba by samozřejmě neměla být schopna přijímat příkazy, dokud se systém nerestartuje (nebo nezastaví).
- druhou metodou, která je obecnější, by bylo nastavení zpětných volání na procesní kliky s ObRegisterCallbacks.
nastavením ObjectType na PsProcessType a operace na OB_OPERATION_HANDLE_CREATE obdržíte zpětné volání před a po operaci a můžete vrátit ACCESS_DENIED do ReturnStatus, pokud dotazovaný proces má GrantedAccess, které mají práva na ukončení procesu (nebo práva na zápis procesu nebo cokoli, co může vést k selhání/zabití), a samozřejmě pokud je proces takový, který antivirus potřebuje chránit(například jeho služba).
samozřejmě je třeba také chránit duplicitní rukojeť a PsThreadType, aby se zabránilo jakékoli metodě ukončení, která vyžaduje uchopení rukojeti procesu nebo vlákna. Zde je malý příklad použití tohoto zpětného volání.
NTSTATUS ObRegisterCallbacks( _In_ POB_CALLBACK_REGISTRATION CallBackRegistration, _Out_ PVOID *RegistrationHandle);
typedef struct _OB_CALLBACK_REGISTRATION { USHORT Version; USHORT OperationRegistrationCount; UNICODE_STRING Altitude; PVOID RegistrationContext; OB_OPERATION_REGISTRATION *OperationRegistration;} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
typedef struct _OB_OPERATION_REGISTRATION { POBJECT_TYPE *ObjectType; OB_OPERATION Operations; POB_PRE_OPERATION_CALLBACK PreOperation; POB_POST_OPERATION_CALLBACK PostOperation;} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
VOID ObjectPostCallback( _In_ PVOID RegistrationContext, _In_ POB_POST_OPERATION_INFORMATION OperationInformation);
typedef struct _OB_POST_OPERATION_INFORMATION { OB_OPERATION Operation; union { ULONG Flags; struct { ULONG KernelHandle :1; ULONG Reserved :31; }; }; PVOID Object; POBJECT_TYPE ObjectType; PVOID CallContext; NTSTATUS ReturnStatus; POB_POST_OPERATION_PARAMETERS Parameters;} OB_POST_OPERATION_INFORMATION, *POB_POST_OPERATION_INFORMATION;
typedef union _OB_POST_OPERATION_PARAMETERS { OB_POST_CREATE_HANDLE_INFORMATION CreateHandleInformation; OB_POST_DUPLICATE_HANDLE_INFORMATION DuplicateHandleInformation;} OB_POST_OPERATION_PARAMETERS, *POB_POST_OPERATION_PARAMETERS;
typedef struct _OB_POST_CREATE_HANDLE_INFORMATION { ACCESS_MASK GrantedAccess;} OB_POST_CREATE_HANDLE_INFORMATION, *POB_POST_CREATE_HANDLE_INFORMATION;
GUI (Graphical User Interface)
Toto je viditelná část ledovce. Podle mého názoru jedna (možná) nejdůležitější část, pokud chcete svůj produkt prodat. Uživatelé milují to, co je krásné, snadno použitelné, intuitivní. I když to není 100% efektivní. GUI musí být sexy.
GUI je pouze prázdný shell, provádí pouze grafické zpracování a odesílá / přijímá příkazy do jádra (služby). Zobrazuje také ukazatele průběhu, to, co je analyzováno, poskytuje konfiguraci, a tak… tady je uživatelské rozhraní Avast. Sexy, že? 🙂
Architektura
globální architektura by mohla vypadat takto:
- GUI: žádná administrativní práva, slabá
- Guard DLL(y) : ochrana webového prohlížeče, střední
- služba : administrátorská práva. Slouží jako brána k jádrovému kódu a přijímá rozhodnutí spolu s nějakou databází, STRONG
- ovladač(y) : filtry jádra, STRONG
GUI nepotřebuje žádné administrativní právo, pouze provádí akce uživatele a přenáší je do služby. Zobrazuje také stav produktu. Nic víc, to není jeho cíl. Pokud je GUI zabito, není to problém, protože služba by měla být schopna jej restartovat.
Guard DLL (pokud existují), jsou masivně vstřikovány do všech procesů a měly by být schopny hledat IAT háčky a / nebo škodlivé vlákna. Měly by být docela těžké vyložit nebo porazit. Nejsou kritické, ale důležité.
služba je jádrem produktu. To by mělo být unkillable, nebo alespoň by měl být schopen self-restart na kill. Služba je zodpovědná za komunikaci mezi všemi moduly produktu, odesílá příkazy ovladačům, přijímá příkazy od uživatele a dotazuje databázi pro analýzu vzorků. Tohle je mozek.
ovladače jádra jsou také kritické. Jsou to chapadla, která shromažďují informace o všem, co se v systému děje, a předávají je službě k rozhodnutí. Na základě rozhodnutí služby mohou také odepřít přístup na střežená místa.
závěr
vytvoření silného, spolehlivého a stabilního antivirového motoru je komplikovaný úkol, který potřebuje experimentované lidi s velmi silnými znalostmi v programování jádra systému windows, programování aplikací systému windows, designu GUI, softwarové architektuře, analýze malwaru, …
budování stabilních ovladačů je také komplikovaný úkol, protože malé zrnko písku může selhat celý systém. Potřebuje testování, testování a spoustu testování. Když je váš motor hotový a funguje, stačí najmout výzkumníky, aby analyzovali malware a přidali podpisy do vaší databáze 🙂 na co čekáte? No tak! 😀
odkazy
- http://www.symantec.com/connect/articles/building-anti-virus-engine