首页
社区
课程
招聘
[求助]请教一个简单的驱动读写问题,一定有人遇到过的!
发表于: 2016-3-12 19:20 15451

[求助]请教一个简单的驱动读写问题,一定有人遇到过的!

2016-3-12 19:20
15451
ring0 下  GetProcessHandle() 返回进程句柄 (AA) 到 ring3
ring3 下 使用AA 调用 VirtualAllocEx() 申请到内存 BB
ring0 下 使用 BB 调用 DriverWrite() 就失效的

正常的的内存地址,是可以写入的,还一个读取测试是可以正常读取普通内存的.但是申请的内存就是读写不了,ring3下 OpenProcess 然后 VirtualProtectEx 申请的内存,ring0下也是不可以读写的.

问题来了,这是什么原因?

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 0
支持
分享
最新回复 (31)
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
还有,过了一段时间,就莫名其妙的就可以访问了.....
2016-3-12 19:25
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
才开始接触驱动,代码都是复制粘贴的多,只有几行是自己写的,大神来帮帮忙,看看是什么原因呗  .
- -

.
2016-3-12 19:55
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
谁来帮我看看什么情况啊
2016-3-12 22:38
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
5
这问题很简单,ring3是用户层的,其内存是处于分页内存界面的,在分页内存被交换磁盘中时,你读取这里的时候当然会失败啦!
2016-3-19 00:02
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
给你看看WINDOWS是怎么实现的!这是WINDOWS 2003的公开的代码,是windows的MSDN上的一个教学计划公开的代码,是windows2003的核心代码,很少见的windows自己公开的代码哦!

你可以看一下WINDOWS是怎么读写内存的

现在贴上代码!
/*++

Copyright (c) Microsoft Corporation. All rights reserved.

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.

Module Name:

   readwrt.c

Abstract:

    This module contains the routines which implement the capability
    to read and write the virtual memory of a target process.

--*/

#include "mi.h"

//
// The maximum amount to try to Probe and Lock is 14 pages, this
// way it always fits in a 16 page allocation.
//

#define MAX_LOCK_SIZE ((ULONG)(14 * PAGE_SIZE))

//
// The maximum to move in a single block is 64k bytes.
//

#define MAX_MOVE_SIZE (LONG)0x10000

//
// The minimum to move is a single block is 128 bytes.
//

#define MINIMUM_ALLOCATION (LONG)128

//
// Define the pool move threshold value.
//

#define POOL_MOVE_THRESHOLD 511

//
// Define forward referenced procedure prototypes.
//

ULONG
MiGetExceptionInfo (
    IN PEXCEPTION_POINTERS ExceptionPointers,
    IN PLOGICAL ExceptionAddressConfirmed,
    IN PULONG_PTR BadVa
    );

NTSTATUS
MiDoMappedCopy (
     IN PEPROCESS FromProcess,
     IN CONST VOID *FromAddress,
     IN PEPROCESS ToProcess,
     OUT PVOID ToAddress,
     IN SIZE_T BufferSize,
     IN KPROCESSOR_MODE PreviousMode,
     OUT PSIZE_T NumberOfBytesRead
     );

NTSTATUS
MiDoPoolCopy (
     IN PEPROCESS FromProcess,
     IN CONST VOID *FromAddress,
     IN PEPROCESS ToProcess,
     OUT PVOID ToAddress,
     IN SIZE_T BufferSize,
     IN KPROCESSOR_MODE PreviousMode,
     OUT PSIZE_T NumberOfBytesRead
     );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,MiGetExceptionInfo)
#pragma alloc_text(PAGE,NtReadVirtualMemory)
#pragma alloc_text(PAGE,NtWriteVirtualMemory)
#pragma alloc_text(PAGE,MiDoMappedCopy)
#pragma alloc_text(PAGE,MiDoPoolCopy)
#pragma alloc_text(PAGE,MmCopyVirtualMemory)
#endif

#define COPY_STACK_SIZE 64

NTSTATUS
NtReadVirtualMemory(
    __in HANDLE ProcessHandle,
    __in_opt PVOID BaseAddress,
    __out_bcount(BufferSize) PVOID Buffer,
    __in SIZE_T BufferSize,
    __out_opt PSIZE_T NumberOfBytesRead
    )

/*++

Routine Description:

    This function copies the specified address range from the specified
    process into the specified address range of the current process.

Arguments:

     ProcessHandle - Supplies an open handle to a process object.

     BaseAddress - Supplies the base address in the specified process
                   to be read.

     Buffer - Supplies the address of a buffer which receives the
              contents from the specified process address space.

     BufferSize - Supplies the requested number of bytes to read from
                  the specified process.

     NumberOfBytesRead - Receives the actual number of bytes
                         transferred into the specified buffer.

Return Value:

    NTSTATUS.

--*/

{
    SIZE_T BytesCopied;
    KPROCESSOR_MODE PreviousMode;
    PEPROCESS Process;
    NTSTATUS Status;
    PETHREAD CurrentThread;

    PAGED_CODE();

    //
    // Get the previous mode and probe output argument if necessary.
    //

    CurrentThread = PsGetCurrentThread ();
    PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
    if (PreviousMode != KernelMode) {

        if (((PCHAR)BaseAddress + BufferSize < (PCHAR)BaseAddress) ||
            ((PCHAR)Buffer + BufferSize < (PCHAR)Buffer) ||
            ((PVOID)((PCHAR)BaseAddress + BufferSize) > MM_HIGHEST_USER_ADDRESS) ||
            ((PVOID)((PCHAR)Buffer + BufferSize) > MM_HIGHEST_USER_ADDRESS)) {

            return STATUS_ACCESS_VIOLATION;
        }

        if (ARGUMENT_PRESENT(NumberOfBytesRead)) {
            try {
                ProbeForWriteUlong_ptr (NumberOfBytesRead);

            } except(EXCEPTION_EXECUTE_HANDLER) {
                return GetExceptionCode();
            }
        }
    }

    //
    // If the buffer size is not zero, then attempt to read data from the
    // specified process address space into the current process address
    // space.
    //

    BytesCopied = 0;
    Status = STATUS_SUCCESS;
    if (BufferSize != 0) {

        //
        // Reference the target process.
        //

        Status = ObReferenceObjectByHandle(ProcessHandle,
                                           PROCESS_VM_READ,
                                           PsProcessType,
                                           PreviousMode,
                                           (PVOID *)&Process,
                                           NULL);

        //
        // If the process was successfully referenced, then attempt to
        // read the specified memory either by direct mapping or copying
        // through nonpaged pool.
        //

        if (Status == STATUS_SUCCESS) {

            Status = MmCopyVirtualMemory (Process,
                                          BaseAddress,
                                          PsGetCurrentProcessByThread(CurrentThread),
                                          Buffer,
                                          BufferSize,
                                          PreviousMode,
                                          &BytesCopied);

            //
            // Dereference the target process.
            //

            ObDereferenceObject(Process);
        }
    }

    //
    // If requested, return the number of bytes read.
    //

    if (ARGUMENT_PRESENT(NumberOfBytesRead)) {
        try {
            *NumberOfBytesRead = BytesCopied;

        } except(EXCEPTION_EXECUTE_HANDLER) {
            NOTHING;
        }
    }

    return Status;
}

NTSTATUS
NtWriteVirtualMemory(
    __in HANDLE ProcessHandle,
    __in_opt PVOID BaseAddress,
    __in_bcount(BufferSize) CONST VOID *Buffer,
    __in SIZE_T BufferSize,
    __out_opt PSIZE_T NumberOfBytesWritten
    )

/*++

Routine Description:

    This function copies the specified address range from the current
    process into the specified address range of the specified process.

Arguments:

     ProcessHandle - Supplies an open handle to a process object.

     BaseAddress - Supplies the base address to be written to in the
                   specified process.

     Buffer - Supplies the address of a buffer which contains the
              contents to be written into the specified process
              address space.

     BufferSize - Supplies the requested number of bytes to write
                  into the specified process.

     NumberOfBytesWritten - Receives the actual number of bytes
                            transferred into the specified address space.

Return Value:

    NTSTATUS.

--*/

{
    SIZE_T BytesCopied;
    KPROCESSOR_MODE PreviousMode;
    PEPROCESS Process;
    NTSTATUS Status;
    PETHREAD CurrentThread;

    PAGED_CODE();

    //
    // Get the previous mode and probe output argument if necessary.
    //

    CurrentThread = PsGetCurrentThread ();
    PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
    if (PreviousMode != KernelMode) {

        if (((PCHAR)BaseAddress + BufferSize < (PCHAR)BaseAddress) ||
            ((PCHAR)Buffer + BufferSize < (PCHAR)Buffer) ||
            ((PVOID)((PCHAR)BaseAddress + BufferSize) > MM_HIGHEST_USER_ADDRESS) ||
            ((PVOID)((PCHAR)Buffer + BufferSize) > MM_HIGHEST_USER_ADDRESS)) {

            return STATUS_ACCESS_VIOLATION;
        }

        if (ARGUMENT_PRESENT(NumberOfBytesWritten)) {
            try {
                ProbeForWriteUlong_ptr(NumberOfBytesWritten);

            } except(EXCEPTION_EXECUTE_HANDLER) {
                return GetExceptionCode();
            }
        }
    }

    //
    // If the buffer size is not zero, then attempt to write data from the
    // current process address space into the target process address space.
    //

    BytesCopied = 0;
    Status = STATUS_SUCCESS;
    if (BufferSize != 0) {

        //
        // Reference the target process.
        //

        Status = ObReferenceObjectByHandle(ProcessHandle,
                                           PROCESS_VM_WRITE,
                                           PsProcessType,
                                           PreviousMode,
                                           (PVOID *)&Process,
                                           NULL);

        //
        // If the process was successfully referenced, then attempt to
        // write the specified memory either by direct mapping or copying
        // through nonpaged pool.
        //

        if (Status == STATUS_SUCCESS) {

            Status = MmCopyVirtualMemory (PsGetCurrentProcessByThread(CurrentThread),
                                          Buffer,
                                          Process,
                                          BaseAddress,
                                          BufferSize,
                                          PreviousMode,
                                          &BytesCopied);

            //
            // Dereference the target process.
            //

            ObDereferenceObject(Process);
        }
    }

    //
    // If requested, return the number of bytes read.
    //

    if (ARGUMENT_PRESENT(NumberOfBytesWritten)) {
        try {
            *NumberOfBytesWritten = BytesCopied;

        } except(EXCEPTION_EXECUTE_HANDLER) {
            NOTHING;
        }
    }

    return Status;
}

NTSTATUS
MmCopyVirtualMemory(
    IN PEPROCESS FromProcess,
    IN CONST VOID *FromAddress,
    IN PEPROCESS ToProcess,
    OUT PVOID ToAddress,
    IN SIZE_T BufferSize,
    IN KPROCESSOR_MODE PreviousMode,
    OUT PSIZE_T NumberOfBytesCopied
    )
{
    NTSTATUS Status;
    PEPROCESS ProcessToLock;

    if (BufferSize == 0) {
        ASSERT (FALSE);         // No one should call with a zero size.
        return STATUS_SUCCESS;
    }

    ProcessToLock = FromProcess;
    if (FromProcess == PsGetCurrentProcess()) {
        ProcessToLock = ToProcess;
    }

    //
    // Make sure the process still has an address space.
    //

    if (ExAcquireRundownProtection (&ProcessToLock->RundownProtect) == FALSE) {
        return STATUS_PROCESS_IS_TERMINATING;
    }

    //
    // If the buffer size is greater than the pool move threshold,
    // then attempt to write the memory via direct mapping.
    //

    if (BufferSize > POOL_MOVE_THRESHOLD) {
        Status = MiDoMappedCopy(FromProcess,
                                FromAddress,
                                ToProcess,
                                ToAddress,
                                BufferSize,
                                PreviousMode,
                                NumberOfBytesCopied);

        //
        // If the completion status is not a working quota problem,
        // then finish the service. Otherwise, attempt to write the
        // memory through nonpaged pool.
        //

        if (Status != STATUS_WORKING_SET_QUOTA) {
            goto CompleteService;
        }

        *NumberOfBytesCopied = 0;
    }

    //
    // There was not enough working set quota to write the memory via
    // direct mapping or the size of the write was below the pool move
    // threshold. Attempt to write the specified memory through nonpaged
    // pool.
    //

    Status = MiDoPoolCopy(FromProcess,
                          FromAddress,
                          ToProcess,
                          ToAddress,
                          BufferSize,
                          PreviousMode,
                          NumberOfBytesCopied);

    //
    // Dereference the target process.
    //

CompleteService:

    //
    // Indicate that the vm operation is complete.
    //

    ExReleaseRundownProtection (&ProcessToLock->RundownProtect);

    return Status;
}

ULONG
MiGetExceptionInfo (
    IN PEXCEPTION_POINTERS ExceptionPointers,
    IN OUT PLOGICAL ExceptionAddressConfirmed,
    IN OUT PULONG_PTR BadVa
    )

/*++

Routine Description:

    This routine examines a exception record and extracts the virtual
    address of an access violation, guard page violation, or in-page error.

Arguments:

    ExceptionPointers - Supplies a pointer to the exception record.

    ExceptionAddressConfirmed - Receives TRUE if the exception address was
                                reliably detected, FALSE if not.

    BadVa - Receives the virtual address which caused the access violation.

Return Value:

    EXECUTE_EXCEPTION_HANDLER

--*/

{
    PEXCEPTION_RECORD ExceptionRecord;

    PAGED_CODE();

    //
    // If the exception code is an access violation, guard page violation,
    // or an in-page read error, then return the faulting address. Otherwise.
    // return a special address value.
    //

    *ExceptionAddressConfirmed = FALSE;

    ExceptionRecord = ExceptionPointers->ExceptionRecord;

    if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
        (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
        (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR)) {

        //
        // The virtual address which caused the exception is the 2nd
        // parameter in the exception information array.
        //
        // The number of parameters will be zero if an exception handler
        // above us (like the one in MmProbeAndLockPages) caught the
        // original exception and subsequently just raised status.
        // This means the number of bytes copied is zero.
        //

        if (ExceptionRecord->NumberParameters > 1) {
            *ExceptionAddressConfirmed = TRUE;
            *BadVa = ExceptionRecord->ExceptionInformation[1];
        }
    }

    return EXCEPTION_EXECUTE_HANDLER;
}

NTSTATUS
MiDoMappedCopy (
    IN PEPROCESS FromProcess,
    IN CONST VOID *FromAddress,
    IN PEPROCESS ToProcess,
    OUT PVOID ToAddress,
    IN SIZE_T BufferSize,
    IN KPROCESSOR_MODE PreviousMode,
    OUT PSIZE_T NumberOfBytesRead
    )

/*++

Routine Description:

    This function copies the specified address range from the specified
    process into the specified address range of the current process.

Arguments:

     FromProcess - Supplies an open handle to a process object.

     FromAddress - Supplies the base address in the specified process
                   to be read.

     ToProcess - Supplies an open handle to a process object.

     ToAddress - Supplies the address of a buffer which receives the
                 contents from the specified process address space.

     BufferSize - Supplies the requested number of bytes to read from
                  the specified process.

     PreviousMode - Supplies the previous processor mode.

     NumberOfBytesRead - Receives the actual number of bytes
                         transferred into the specified buffer.

Return Value:

    NTSTATUS.

--*/

{
    KAPC_STATE ApcState;
    SIZE_T AmountToMove;
    ULONG_PTR BadVa;
    LOGICAL Moving;
    LOGICAL Probing;
    LOGICAL LockedMdlPages;
    CONST VOID *InVa;
    SIZE_T LeftToMove;
    PSIZE_T MappedAddress;
    SIZE_T MaximumMoved;
    PMDL Mdl;
    PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + (MAX_LOCK_SIZE >> PAGE_SHIFT) + 1];
    PVOID OutVa;
    LOGICAL MappingFailed;
    LOGICAL ExceptionAddressConfirmed;

    PAGED_CODE();

    MappingFailed = FALSE;

    InVa = FromAddress;
    OutVa = ToAddress;

    MaximumMoved = MAX_LOCK_SIZE;
    if (BufferSize <= MAX_LOCK_SIZE) {
        MaximumMoved = BufferSize;
    }

    Mdl = (PMDL)&MdlHack[0];

    //
    // Map the data into the system part of the address space, then copy it.
    //

    LeftToMove = BufferSize;
    AmountToMove = MaximumMoved;

    Probing = FALSE;

    //
    // Initializing BadVa & ExceptionAddressConfirmed is not needed for
    // correctness but without it the compiler cannot compile this code
    // W4 to check for use of uninitialized variables.
    //

    BadVa = 0;
    ExceptionAddressConfirmed = FALSE;

    while (LeftToMove > 0) {

        if (LeftToMove < AmountToMove) {

            //
            // Set to move the remaining bytes.
            //

            AmountToMove = LeftToMove;
        }

        KeStackAttachProcess (&FromProcess->Pcb, &ApcState);

        MappedAddress = NULL;
        LockedMdlPages = FALSE;
        Moving = FALSE;
        ASSERT (Probing == FALSE);

        //
        // We may be touching a user's memory which could be invalid,
        // declare an exception handler.
        //

        try {

            //
            // Probe to make sure that the specified buffer is accessible in
            // the target process.
            //

            if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
                Probing = TRUE;
                ProbeForRead (FromAddress, BufferSize, sizeof(CHAR));
                Probing = FALSE;
            }

            //
            // Initialize MDL for request.
            //

            MmInitializeMdl (Mdl, (PVOID)InVa, AmountToMove);

            MmProbeAndLockPages (Mdl, PreviousMode, IoReadAccess);

            LockedMdlPages = TRUE;

            MappedAddress = MmMapLockedPagesSpecifyCache (Mdl,
                                                          KernelMode,
                                                          MmCached,
                                                          NULL,
                                                          FALSE,
                                                          HighPagePriority);

            if (MappedAddress == NULL) {
                MappingFailed = TRUE;
                ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
            }

            //
            // Deattach from the FromProcess and attach to the ToProcess.
            //

            KeUnstackDetachProcess (&ApcState);
            KeStackAttachProcess (&ToProcess->Pcb, &ApcState);

            //
            // Now operating in the context of the ToProcess.
            //
            if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
                Probing = TRUE;
                ProbeForWrite (ToAddress, BufferSize, sizeof(CHAR));
                Probing = FALSE;
            }

            Moving = TRUE;
            RtlCopyMemory (OutVa, MappedAddress, AmountToMove);

        } except (MiGetExceptionInfo (GetExceptionInformation(),
                                      &ExceptionAddressConfirmed,
                                      &BadVa)) {

            //
            // If an exception occurs during the move operation or probe,
            // return the exception code as the status value.
            //

            KeUnstackDetachProcess (&ApcState);

            if (MappedAddress != NULL) {
                MmUnmapLockedPages (MappedAddress, Mdl);
            }
            if (LockedMdlPages == TRUE) {
                MmUnlockPages (Mdl);
            }

            if (GetExceptionCode() == STATUS_WORKING_SET_QUOTA) {
                return STATUS_WORKING_SET_QUOTA;
            }

            if ((Probing == TRUE) || (MappingFailed == TRUE)) {
                return GetExceptionCode();

            }

            //
            // If the failure occurred during the move operation, determine
            // which move failed, and calculate the number of bytes
            // actually moved.
            //

            *NumberOfBytesRead = BufferSize - LeftToMove;

            if (Moving == TRUE) {
                if (ExceptionAddressConfirmed == TRUE) {
                    *NumberOfBytesRead = (SIZE_T)((ULONG_PTR)BadVa - (ULONG_PTR)FromAddress);
                }
            }

            return STATUS_PARTIAL_COPY;
        }

        KeUnstackDetachProcess (&ApcState);

        MmUnmapLockedPages (MappedAddress, Mdl);
        MmUnlockPages (Mdl);

        LeftToMove -= AmountToMove;
        InVa = (PVOID)((ULONG_PTR)InVa + AmountToMove);
        OutVa = (PVOID)((ULONG_PTR)OutVa + AmountToMove);
    }

    //
    // Set number of bytes moved.
    //

    *NumberOfBytesRead = BufferSize;
    return STATUS_SUCCESS;
}

NTSTATUS
MiDoPoolCopy (
     IN PEPROCESS FromProcess,
     IN CONST VOID *FromAddress,
     IN PEPROCESS ToProcess,
     OUT PVOID ToAddress,
     IN SIZE_T BufferSize,
     IN KPROCESSOR_MODE PreviousMode,
     OUT PSIZE_T NumberOfBytesRead
     )

/*++

Routine Description:

    This function copies the specified address range from the specified
    process into the specified address range of the current process.

Arguments:

     ProcessHandle - Supplies an open handle to a process object.

     BaseAddress - Supplies the base address in the specified process
                   to be read.

     Buffer - Supplies the address of a buffer which receives the
              contents from the specified process address space.

     BufferSize - Supplies the requested number of bytes to read from
                  the specified process.

     PreviousMode - Supplies the previous processor mode.

     NumberOfBytesRead - Receives the actual number of bytes
                         transferred into the specified buffer.

Return Value:

    NTSTATUS.

--*/

{
    KAPC_STATE ApcState;
    SIZE_T AmountToMove;
    LOGICAL ExceptionAddressConfirmed;
    ULONG_PTR BadVa;
    PEPROCESS CurrentProcess;
    LOGICAL Moving;
    LOGICAL Probing;
    CONST VOID *InVa;
    SIZE_T LeftToMove;
    SIZE_T MaximumMoved;
    PVOID OutVa;
    PVOID PoolArea;
    LONGLONG StackArray[COPY_STACK_SIZE];
    ULONG FreePool;

    PAGED_CODE();

    ASSERT (BufferSize != 0);

    //
    // Get the address of the current process object and initialize copy
    // parameters.
    //

    CurrentProcess = PsGetCurrentProcess();

    InVa = FromAddress;
    OutVa = ToAddress;

    //
    // Allocate non-paged memory to copy in and out of.
    //

    MaximumMoved = MAX_MOVE_SIZE;
    if (BufferSize <= MAX_MOVE_SIZE) {
        MaximumMoved = BufferSize;
    }

    FreePool = FALSE;
    if (BufferSize <= sizeof(StackArray)) {
        PoolArea = (PVOID)&StackArray[0];
    } else {
        do {
            PoolArea = ExAllocatePoolWithTag (NonPagedPool, MaximumMoved, 'wRmM');
            if (PoolArea != NULL) {
                FreePool = TRUE;
                break;
            }

            MaximumMoved = MaximumMoved >> 1;
            if (MaximumMoved <= sizeof(StackArray)) {
                PoolArea = (PVOID)&StackArray[0];
                break;
            }
        } while (TRUE);
    }

    //
    // Initializing BadVa & ExceptionAddressConfirmed is not needed for
    // correctness but without it the compiler cannot compile this code
    // W4 to check for use of uninitialized variables.
    //

    BadVa = 0;
    ExceptionAddressConfirmed = FALSE;

    //
    // Copy the data into pool, then copy back into the ToProcess.
    //

    LeftToMove = BufferSize;
    AmountToMove = MaximumMoved;
    Probing = FALSE;

    while (LeftToMove > 0) {

        if (LeftToMove < AmountToMove) {

            //
            // Set to move the remaining bytes.
            //

            AmountToMove = LeftToMove;
        }

        KeStackAttachProcess (&FromProcess->Pcb, &ApcState);

        Moving = FALSE;
        ASSERT (Probing == FALSE);

        //
        // We may be touching a user's memory which could be invalid,
        // declare an exception handler.
        //

        try {

            //
            // Probe to make sure that the specified buffer is accessible in
            // the target process.
            //

            if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
                Probing = TRUE;
                ProbeForRead (FromAddress, BufferSize, sizeof(CHAR));
                Probing = FALSE;
            }

            RtlCopyMemory (PoolArea, InVa, AmountToMove);

            KeUnstackDetachProcess (&ApcState);

            KeStackAttachProcess (&ToProcess->Pcb, &ApcState);

            //
            // Now operating in the context of the ToProcess.
            //

            if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
                Probing = TRUE;
                ProbeForWrite (ToAddress, BufferSize, sizeof(CHAR));
                Probing = FALSE;
            }

            Moving = TRUE;

            RtlCopyMemory (OutVa, PoolArea, AmountToMove);

        } except (MiGetExceptionInfo (GetExceptionInformation(),
                                      &ExceptionAddressConfirmed,
                                      &BadVa)) {

            //
            // If an exception occurs during the move operation or probe,
            // return the exception code as the status value.
            //

            KeUnstackDetachProcess (&ApcState);

            if (FreePool) {
                ExFreePool (PoolArea);
            }
            if (Probing == TRUE) {
                return GetExceptionCode();

            }

            //
            // If the failure occurred during the move operation, determine
            // which move failed, and calculate the number of bytes
            // actually moved.
            //

            *NumberOfBytesRead = BufferSize - LeftToMove;

            if (Moving == TRUE) {

                //
                // The failure occurred writing the data.
                //

                if (ExceptionAddressConfirmed == TRUE) {
                    *NumberOfBytesRead = (SIZE_T)((ULONG_PTR)(BadVa - (ULONG_PTR)FromAddress));
                }

            }

            return STATUS_PARTIAL_COPY;
        }

        KeUnstackDetachProcess (&ApcState);

        LeftToMove -= AmountToMove;
        InVa = (PVOID)((ULONG_PTR)InVa + AmountToMove);
        OutVa = (PVOID)((ULONG_PTR)OutVa + AmountToMove);
    }

    if (FreePool) {
        ExFreePool (PoolArea);
    }

    //
    // Set number of bytes moved.
    //

    *NumberOfBytesRead = BufferSize;
    return STATUS_SUCCESS;
}
2016-3-19 00:04
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
7
我想,我知道你的函数为什么不会成功了,你不仅没有锁定内存页,而且写入数据的时候,你是直接跨进程读取的
你看一下这个函数

BOOLEAN DriverWrite(ULONG ProcessId,PVOID BaseAddress,PVOID Buffer,SIZE_T BufferSize)
{
     NTSTATUS ntStatus;
     PEPROCESS Perocess;
KAPC_STATE ApcState;
if(ProcessId ==0||BaseAddress==0)
{
return FALSE;
}
ntStatus=PsLookProcessByProcessId(ProcessId,&Perocess);//取得PCB,这里没错
if(!NT_SUCCESS(ntStatus))
{
return FALSE;
}
//关键是这里
KeStackAttachProcess((PKPROCESS)Perocess,&ApcState); //切换PCB,进入ProcessId的进程,可是你忘了一个问题!这时你的Buffer指向的是原来的进程的内存地址,当你切换进程之后这

个内存地址变得无效!第二,你没有判断你的目标进程,和Buffer所在的是否在同一个进程中,如果是同一个进程,就不需要切换进程,直接复制!第三,BaseAddress和Buffer指向的内存没

有进行锁定操作,而函数DriverWrite没有写类似的#pragma alloc_text(PAGE,你的函数)的一个指令,来告诉编译器,这个函数需要编译在分页内存上,你忘记这样做会导致编译器把你的函

数写在非分页内存上,这就导致一个问题,一个非分页内存上的函数要想访问一个非分页内存的地址,它是安全访问的,它需要锁定,需要使用MDL锁定之后才能访问,不然有可能会引发分页

错误的!

正确的做法是使用MDL将BaseAddress指向的地址,映射到内核内存空间,并且锁定,然后使用KeStackAttachProcess((PKPROCESS)Perocess,&ApcState);切换进程,然后也将Buffer锁定到内核内存空间,这样就可以使用RtlCopyMemory安全的复制了
_try
{

if(MmIsAddressValid(BaseAddress)
{
    ProbeForRead(BaseAddress,BufferSize,sizeof(char));
    RtlCopyMemory(BaseAddress,Buffer,BufferSize);
    KeUnstackDetachProcess(&ApcState);
return TRUE;
}
KeUnstackDetachProcess(&ApcState);
}__except(1)
{
KeUnstackDetachProcess(&ApcState);
return FALSE;
}
return FALSE;
}
2016-3-19 00:53
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
8
写错几个字了,这里"第三,BaseAddress和Buffer指向的内存没

有进行锁定操作,而函数DriverWrite没有写类似的#pragma alloc_text(PAGE,你的函数)的一个指令,来告诉编译器,这个函数需要编译在分页内存上,你忘记这样做会导致编译器把你的函

数写在非分页内存上,这就导致一个问题,一个非分页内存上的函数要想访问一个非分页内存的地址,它是安全访问的,它需要锁定,需要使用MDL锁定之后才能访问,不然有可能会引发分页"  应该改为 “第三,BaseAddress和Buffer指向的内存没

有进行锁定操作,而函数DriverWrite没有写类似的#pragma alloc_text(PAGE,你的函数)的一个指令,来告诉编译器,这个函数需要编译在分页内存上,你忘记这样做会导致编译器把你的函

数写在非分页内存上,这就导致一个问题,一个非分页内存上的函数要想访问一个分页内存的地址,它是可以访问的,但是它需要锁定才能安全访问,需要使用MDL锁定之后才能访问,不然有可能会引发分页

错误的!”
2016-3-19 00:56
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
9
这是我修改的函数,由于是晚上编写,没来得及编译和调试了所以里面可能有一些错误,但是原理没有错,你可以参考一下

#pragma alloc_text(PAGE,DriverWrite)//这个宏的作用是指示编译器将你的函数放入分页内存当中!
NTSTATUS NTAPI DriverWrite(ULONG ToProcessId,PVOID BaseAddress,ULONG FormProcessId,PVOID Buffer,SIZE_T BufferSize,SIZE_T *SizeWrite)
{
PVOID PoolArea = 0;
PEPROCESS ToPerocess;
PEPROCESS FormPerocess;
PAGED_CODE();//检查一下自己是否处于分页内存当中,如果不是处于分页内存当中的话,那么运行到这个宏时,会直接蓝屏,这样就可以提示你分页内存错误,可以促使你检查代码!
KAPC_STATE ApcState;
if((ProcessId ==0)||(BaseAddress==0)||(FormProcessId==0)||(Buffer==0))
{
return STATUS_INVALID_PARAMETER;
//return FALSE;
}
_try
{
ProbeForRead(SizeWrite,sizeof(SIZE_T),sizeof(char));
ProbeForRead(Buffer,BufferSize,sizeof(char));
ProbeForWrite(BaseAddress,BufferSize,sizeof(char));
}__except(1)
{
return STATUS_INVALID_PARAMETER;
}
*SizeWrite=0;
/////////
if(ProcessId==FormProcessId)
{
RtlCopyMemory(BaseAddress,Buffer,BufferSize);

}
///////////
else{
ntStatus=PsLookProcessByProcessId(FormProcessId,&FormPerocess);//取得PCB,这里没错
if(!NT_SUCCESS(ntStatus))
{
*SizeWrite = 0;
return ntStatus;
}
ntStatus=PsLookProcessByProcessId(ToProcessId,&ToPerocess);//取得PCB,这里没错
if(!NT_SUCCESS(ntStatus))
{
*SizeWrite = 0;
ObDereferenceObject(FormPerocess);
return ntStatus;
}
//本来还想使用MDL映射的,因为MDL太麻烦懒得写了,直接申请内存好了,使用申请内存的办法来突破进程限制是效率最底下的办法,效率最高的应该是使用MDL,但是MDL太麻烦了,不想写

MDL
PoolArea = ExAllocatePool (NonPagedPool, BufferSize);//申请一个非分页内存,分页内存中的函数访问非分页内存中的数据是安全的!
if(PoolArea)==0)
{
ObDereferenceObject(FormPerocess);//解除引用
ObDereferenceObject(ToPerocess);//解除引用
*SizeWrite = 0;
return STATUS_INVALID_PARAMETER;//内存资源不足的NTSTATUS值,我忘了是什么了,将就返回参数错误吧!记得该回来啊!
}
KeStackAttachProcess (&FormPerocess, &ApcState);//切换到需要复制的数据所在的进程
RtlCopyMemory (PoolArea, Buffer, BufferSize);//将数据临时复制到内核内存当中
KeUnstackDetachProcess (&ApcState);//复制好数据以后,将进程切换回来
KeStackAttachProcess (&ToProcess, &ApcState);//切换到目标进程
RtlCopyMemory (BaseAddress, PoolArea, BufferSize);//将内核内存中的临时数据复制到目标进程!
KeUnstackDetachProcess (&ApcState);//复制好数据以后,将进程切换回来
ObDereferenceObject(FormPerocess);//解除引用
ObDereferenceObject(ToPerocess);//解除引用
    if (FreePool) {
        ExFreePool (PoolArea);//销毁申请的内核内存
    }
}
*SizeWrite=BufferSize;//返回已经复制的数据的大小
return STATUS_SUCCESS;

}
2016-3-19 01:49
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
10
还有,以后记得贴代码上来的时候不要截图,要直接复制代码上来,否则人家帮你改代码还得手打一遍,很烦的啊!
2016-3-19 01:57
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
谢谢大神相助,说得很详细,学到了很多.

我想说的,我之前也自己摸索解决了,方法跟源码在下,能说明说明原因么.
方法真是自己胡乱测试出来的,真的有效!

HANDLE DriverAllocMem(ULONG ProcessId, ULONG RegionSize)
{
	
	NTSTATUS status;
	PEPROCESS Process ;
	HANDLE BaseAddr=NULL;
	KAPC_STATE ApcState;


	status = PsLookupProcessByProcessId(ProcessId, &Process);

	if (NT_SUCCESS(status))
	{
		
		KeStackAttachProcess((PKPROCESS)Process, &ApcState);
		_try
		{
	
			ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&BaseAddr,0,(PSIZE_T)&RegionSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
			MmProtectMdlSystemAddress(BaseAddr, PAGE_EXECUTE_READWRITE);
			RtlZeroMemory(BaseAddr, RegionSize); //关键点
			//这里是关键点,内存清理后,然后ring0下再调用 VirtualProtectEx() 修改内存属性,这样申请到的内存,用之前的代码,就莫名其妙的就可以访问了
			//原因我不懂,之前因为申请到的内存,不能访问,我就用CE查看内存,然后发现用CE访问过后的内存就可以驱动读写了
			//后来我就胡乱测试,发现这个方法可以,ring0申请内存,然后清零,然后ring3修改内存属性,就可以访问
			KeUnstackDetachProcess(&ApcState);
		}
		__except (EXCEPTION_EXECUTE_HANDLER)
		{
			KeUnstackDetachProcess(&ApcState);
			return 0;
		}

	}

	return BaseAddr;
}
2016-3-20 17:02
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
ObDereferenceObject(FormPerocess);//解除引用
像这种代码,我是真不懂,什么时候该用,什么时候不该用,很多还是要学习的.
之前测试过,胡乱用这个解除引用的话,就不能读写了,后来就去掉了很多.
内核方面的东西,还真的很多东西都没会.
C++也是自己学的,一路的艰辛不说了,现在弄驱动,难得遇到这么好的人指点,真的很感激
2016-3-20 17:09
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
13
这个简单啊!关键是这个ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&BaseAddr,0,(PSIZE_T)&RegionSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);这个API是进程上下文相关的,你上面已经切换了进程了,这个函数申请的内存就已经在目标进程的上下文了,当然成功啦!
2016-3-20 18:43
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
14
MmProtectMdlSystemAddress(BaseAddr, PAGE_EXECUTE_READWRITE);这个调用在我看来是多余的,切换进程上下文之后BaseAddr是可以直接调用的
2016-3-20 18:44
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
15
不对,代码感觉还有错误!
2016-3-20 18:51
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
16
第一,ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&BaseAddr,0,(PSIZE_T)&RegionSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);这个方法申请的不是内核内存,而是RING3的内存!第二,这个方法申请的内存只能在当前进程的上下文中使用!
2016-3-20 18:56
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
17
没错啊,我就是这么写的,之前新申请的内存,不能读写的地方,这种方式下确实是可以直接读写了啊!
2016-3-22 14:52
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
18
就是申请ring3的内存的,不是内核.
我之前说的问题就是申请ring3内存,然后内核下不能访问到.
2016-3-22 14:53
0
雪    币: 7498
活跃值: (5327)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
就像内存读写一样,通过驱动通信,我把申请内存也自己用驱动完成了的,然后代码都是百度找的资料,手打完成的.测试也没问题啊
2016-3-22 14:55
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
20
你的代码实现逻辑上暂时看不出什么问题,但是你写代码的时候却没有注意到几个问题,这些问题有可能会成为隐患所在,第一PsLookupProcessByProcessId引用的对象你没有释放掉,这很可能会造成内存泄漏,第二,我发现你整片的代码没有进行分页内存的测试,这是我目前发现的你的问题,当然,这这是我作为玩了几年内核的人提出的一点意见,也是我曾经犯过的错误!
2016-3-22 15:16
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
21
ObDereferenceObject(FormPerocess);//解除引用
这样的代码是在你确定你的对象在之后的过程中没有必要再使用,或者整个过程出错,需要回到过程之前的操作时进行的动作!
2016-3-22 15:18
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
22
对了,我差点忘了,你的程序逻辑上目前没有发现什么问题,但是有一点,你的这个程序通过 status = PsLookupProcessByProcessId(ProcessId, &Process);直接取得进程结构的指针,意味着,攻击者可以直接通过你的驱动访问任意权限的进程,这已经是一个权限提升漏洞,当然,如果这个程序是学习用的,也可以这样做,只不过如果以后是要编写发布版本的,你就不能这样做了!建议你的程序改为使用句柄来取得进程结构这样可以避免这个问题,我这只是个建议,要看看你是怎么玩的啦!当然,我给你的代码也有这个问题,哈哈!学习而已!
2016-3-22 15:27
0
雪    币: 581
活跃值: (215)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
23
就想看看你怎么权限提升。期待POC
2016-3-22 16:44
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
24
这只是一个可能,你可以直接在指定程序申请内存,可能会涉及权限提升,当然直接利用这个当然不行,我只是说可能,毕竟利用这些东西有时候也不是利用一个就可以的!

编程的话,要养成习惯,尽量检查自己程序的缺陷,尽量不要有任何可乘之机,也包括任意在指定进程中申请内存等!

强调一点,这里只是一个缺陷,单独利用这个缺陷只能在任意进程内申请内存,如果他余下的程序没有对调用者进行验证的话,就有可能使得申请的内存得以执行,当然,这只是我提出的一点可能!

你可以看看我贴出的WINDOWS2003的和楼主相同的功能的源代码,你可以看看人家的逻辑,人家的逻辑非常好,就没有非法在别的程序中申请内存的可能!这就避免了别的程序利用这个函数做坏事的可能!我们编程的时候难道不需要像windows这样做么?

当然,我只是提出我的建议,楼主可以视情况而定,况且,我本身也可能有错!
2016-3-22 17:39
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
25
看他的代码,利用起来也不是很难,在RING3下通过他的IO控制码调用他的这个GetProcessHandle取得句柄(比如CRESS.exe的句柄),这个可以实现吧?利用他的DriverAllocMem函数,可以直接申请到指定进程的内存,然后我是不是可以利用 DriverWrite向指定的进程中的内存写东西?写好代码之后,我是不是可以直接创建远程线程,然后将线程首地址直接指向前面申请到的内存?既然可以直接执行代码了,那我在代码里面直接提升权限还不是小菜一碟?
2016-3-22 17:52
0
游客
登录 | 注册 方可回帖
返回
//