• 在Windows 2003中HOOK ZwCreateProcessEx


    作者:ZwelL

    工作需要,想控制进程的创建,于是HOOK了ZwCreateProcess,后来发现xp和2003中创建进程的都用NtCreateProcessEx(参见[1])。
    但是ZwCreateProcessEx未被ntoskrnl.exe导出,用softice的ntcall命令也没有看到,网上也没有找到相关代码。没办法,跟踪ntoskrnl!ZwCreateProcess
    >u ntoskrnl!ZwCreateProcessEx

    _ZwCreateProcess
    0008:804e7ae2    bb32000000    mov eax, 00000032

    但是ZwCreateProcessEx有9个参数,最后一个未知,4字节,猜成HANDLE型。
    原型如下:
    typedef NTSTATUS (*NTCREATEPROCESSEX)(
        OUT PHANDLE ProcessHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN HANDLE ParentProcess,
        IN BOOLEAN InheritObjectTable,
        IN HANDLE SectionHandle OPTIONAL,
        IN HANDLE DebugPort OPTIONAL,
        IN HANDLE ExceptionPort OPTIONAL,
        IN HANDLE Unknown );  
    最终用硬编码HOOK 成功,代码如下:


    #include "ntddk.h"
    #include "stdarg.h"
    #include "stdio.h"
    #include "ntiologc.h"

    #define DWORD unsigned long
    #define WORD unsigned short
    #define BOOL unsigned long

    typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //Used only in checked build
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
    } ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

    extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

    typedef NTSTATUS (*NTCREATEPROCESSEX)(
    OUT PHANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ParentProcess,
    IN BOOLEAN InheritObjectTable,
    IN HANDLE SectionHandle OPTIONAL,
    IN HANDLE DebugPort OPTIONAL,
    IN HANDLE ExceptionPort OPTIONAL,
    IN HANDLE Unknown );

    NTCREATEPROCESSEX    OldNtCreateProcessEx;

    // Length of process name (rounded up to next DWORD)
    #define PROCNAMELEN     20
    // Maximum length of NT process name
    #define NT_PROCNAMELEN  16
    ULONG gProcessNameOffset;

    void GetProcessNameOffset()
    {
        
        PEPROCESS curproc;
        int i;
        curproc = PsGetCurrentProcess();
        for( i = 0; i < 3*PAGE_SIZE; i++ )
        {
            if( !strncmp( "System", (PCHAR) curproc + i, strlen("System") ))
            {
                gProcessNameOffset = i;
            }
        }
    }

    BOOL GetProcessName( PCHAR theName )
    {
        PEPROCESS       curproc;
        char            *nameptr;
        ULONG           i;
        KIRQL           oldirql;

        if( gProcessNameOffset )
        {
            curproc = PsGetCurrentProcess();
            nameptr   = (PCHAR) curproc + gProcessNameOffset;
            strncpy( theName, nameptr, NT_PROCNAMELEN );
            theName[NT_PROCNAMELEN] = 0; /* NULL at end */
            return TRUE;
        }
        return FALSE;
    }

    NTSTATUS NewNtCreateProcessEx(
    OUT PHANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ParentProcess,
    IN BOOLEAN InheritObjectTable,
    IN HANDLE SectionHandle OPTIONAL,
    IN HANDLE DebugPort OPTIONAL,
    IN HANDLE ExceptionPort OPTIONAL,
    IN HANDLE Unknown OPTIONAL)
    {
        CHAR aProcessName[PROCNAMELEN];
            
        GetProcessName( aProcessName );
        DbgPrint("rootkit: NewNtCreateProcessEx() from %s\n", aProcessName);
        //DbgPrint("ok");
        return OldNtCreateProcessEx(ProcessHandle,DesiredAccess,
                ObjectAttributes,ParentProcess,InheritObjectTable,SectionHandle,DebugPort,ExceptionPort,Unknown);
    }

    NTSTATUS
    OnStubDispatch(
        IN PDEVICE_OBJECT DeviceObject,
        IN PIRP           Irp
        )
    {
        Irp->IoStatus.Status      = STATUS_SUCCESS;
        IoCompleteRequest (Irp,
                           IO_NO_INCREMENT
                           );
        return Irp->IoStatus.Status;
    }

    VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
    {
        DbgPrint("ROOTKIT: OnUnload called\n");

        _asm
        {
            CLI                    //dissable interrupt
            MOV    EAX, CR0        //move CR0 register into EAX
            AND EAX, NOT 10000H //disable WP bit
            MOV    CR0, EAX        //write register back
        }

        (NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32))=OldNtCreateProcessEx;

        _asm
        {
            MOV    EAX, CR0        //move CR0 register into EAX
            OR    EAX, 10000H        //enable WP bit     
            MOV    CR0, EAX        //write register back        
            STI                    //enable interrupt
        }
    }

    NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
    {
        int i;

        DbgPrint("My Driver Loaded!");
        GetProcessNameOffset();

        // Register a dispatch function
        for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
        {
                theDriverObject->MajorFunction[i] = OnStubDispatch;
        }

        theDriverObject->DriverUnload  = OnUnload;

        // save old system call locations
        //OldNtCreateProcessEx=(NTCREATEPROCESSEX)(SYSTEMSERVICE(0x32));
        OldNtCreateProcessEx=(NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32));


        _asm
        {
            CLI                    //dissable interrupt
            MOV    EAX, CR0        //move CR0 register into EAX
            AND EAX, NOT 10000H //disable WP bit
            MOV    CR0, EAX        //write register back
        }

        (NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32))=  NewNtCreateProcessEx;

        _asm
        {
            MOV    EAX, CR0        //move CR0 register into EAX
            OR    EAX, 10000H        //enable WP bit     
            MOV    CR0, EAX        //write register back        
            STI                    //enable interrupt
        }
                        
        return STATUS_SUCCESS;
    }

    这样很不爽,每次都要这样看索引号,问了SOBEIT,可以通过从NTDLL中这样获取服务索引号:
    来自rookkit:

    #include <windows.h>
    #include <stdio.h>

    BOOL GetId( char *FuncName, ULONG *FunctionID )
    {
        //get the function's address
        PBYTE Function = (PBYTE)GetProcAddress( GetModuleHandle( "ntdll.dll" ), FuncName );
        /*
        do some sanity checks,
        make sure this function
        has a corresponding kernel
        level function
        */

        *FunctionID = 0;

        //func not found...
        if ( Function == NULL )
        {
            return FALSE;
        }

        /*
        77F5B438   B8 00000000    MOV EAX, _FUNCTION_ID_
        77F5B43D   BA 0003FE7F    MOV EDX,7FFE0300
        77F5B442   FFD2           CALL EDX
        77F5B444   C2 1800        RETN XX
         */

        //mov eax
        if ( *Function != 0xB8 )
        {
            return FALSE;
        }
        /*
        since the address of
        the function which
        actually makes the call
        (SYSCALL) may change, we just
        check for mov edx
        */
        if ( *(Function + 5) != 0xBA )
        {
            return FALSE;
        }

        //call edx
        /*if ( *(PWORD)(Function + 10) != 0xD2FF )
        {
            return FALSE;
        }
        //retn
        if ( *(Function + 12) != 0xC2 )
        {
            return FALSE;
        }*/

        *FunctionID = *(PDWORD)(Function + 1);
        return TRUE;
    }

    int main(int argc, char* argv[])
    {
        ULONG Id;
        
        printf( "function name: NtCreateProcessEx\n" );

        GetId( "NtCreateProcessEx", &Id );
        printf( "function id: %08X\n", Id );
        return 0;
    }
    ///////////////////////////////////////////////////////////////////////

    这样也不爽,要从用户态传到驱动层不方便,最后,用这个代码:

    #include "ntddk.h"
    #include "stdarg.h"
    #include "stdio.h"
    #include "ntiologc.h"
    #include "ntimage.h"


    #define DWORD unsigned long
    #define WORD unsigned short
    #define BOOL unsigned long
    #define BYTE unsigned char

    #define SEC_IMAGE    0x01000000

    typedef struct _SECTION_IMAGE_INFORMATION {
    PVOID EntryPoint;
    ULONG StackZeroBits;
    ULONG StackReserved;
    ULONG StackCommit;
    ULONG ImageSubsystem;
    WORD SubsystemVersionLow;
    WORD SubsystemVersionHigh;
    ULONG Unknown1;
    ULONG ImageCharacteristics;
    ULONG ImageMachineType;
    ULONG Unknown2[3];
    } SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

    DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)
    {
        HANDLE hThread, hSection, hFile, hMod;
        SECTION_IMAGE_INFORMATION sii;
        IMAGE_DOS_HEADER* dosheader;
        IMAGE_OPTIONAL_HEADER* opthdr;
        IMAGE_EXPORT_DIRECTORY* pExportTable;
        DWORD* arrayOfFunctionAddresses;
        DWORD* arrayOfFunctionNames;
        WORD* arrayOfFunctionOrdinals;
        DWORD functionOrdinal;
        DWORD Base, x, functionAddress;
        char* functionName;
        STRING ntFunctionName, ntFunctionNameSearch;
        PVOID BaseAddress = NULL;
        SIZE_T size=0;

        OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};

        IO_STATUS_BLOCK iosb;

        //_asm int 3;
        ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

        oa.ObjectName = 0;

        ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);
        
        ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);
        
        ZwClose(hFile);
        
        hMod = BaseAddress;
        
        dosheader = (IMAGE_DOS_HEADER *)hMod;
        
        opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

        pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);

        // now we can get the exported functions, but note we convert from RVA to address
        arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);

        arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);

        arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);

        Base = pExportTable->Base;

        RtlInitString(&ntFunctionNameSearch, lpFunctionName);

        for(x = 0; x < pExportTable->NumberOfFunctions; x++)
        {
            functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);

            RtlInitString(&ntFunctionName, functionName);

            functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; // always need to add base, -1 as array counts from 0
            // this is the funny bit.  you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...
            // oh no... thats too simple.  it is actually arrayOfFunctionAddresses[functionOrdinal]!!
            functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
            if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
            {
                ZwClose(hSection);
                return functionAddress;
            }
        }

        ZwClose(hSection);
        return 0;
    }

    NTSTATUS
    OnStubDispatch(
        IN PDEVICE_OBJECT DeviceObject,
        IN PIRP           Irp
        )
    {
        Irp->IoStatus.Status      = STATUS_SUCCESS;
        IoCompleteRequest (Irp,
                           IO_NO_INCREMENT
                           );
        return Irp->IoStatus.Status;
    }

    VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
    {
        DbgPrint("ROOTKIT: OnUnload called\n");
    }

    NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
    {
        int i;
        UNICODE_STRING dllName;
        DWORD functionAddress;
        int    position;
        DbgPrint("My Driver Loaded!");
        theDriverObject->DriverUnload  = OnUnload;
        RtlInitUnicodeString(&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");
        functionAddress = GetDllFunctionAddress("ZwCreateProcessEx", &dllName);
        position = *((WORD*)(functionAddress+1));

        DbgPrint("Id:%d\n", position);
                        
        return STATUS_SUCCESS;
    }

    上面的代码从驱动层加载NTDLL,再从输出表中找出函数地址,mov eax,[ID]对应的b8后面的字就是索引号,其实跟前一个代码作用是相似的,
    只是驱动层没有LoadLibrary,只能这样解决了。
  • 相关阅读:
    NEO发行资产Token
    OSCP考试回顾
    Windows降权
    Mimikatz.ps1本地执行
    MS16-032提权正确方法
    一种通过HTTP传文件出网的姿势
    mac chromedriver error
    关于websocket 在生产环境中遇到的问题 及 解决办法
    how to install protobuff python
    Git 使用疑问
  • 原文地址:https://www.cnblogs.com/Safe3/p/1334828.html
Copyright © 2020-2023  润新知