2015年12月14日星期一

打破C++之类外不能访问私有成员的限制

#include "stdafx.h"


/*
标题:打破C++之类外不能访问私有成员的限制。

C++规则之一就是私有的成员变量/函数,对于类外是不可访问的。
对于C++的你,这个简单的规则你想过没有,这是如何实现的?

经测试发现,类的成员变量的是放置在一起的,不论其是私有的,功能的还是保护的。
所以从这里可以看出,他们的内存属性是一样的。
因为私有的变量也有修改的属性。
这可以检测的。

所以只能说这是C++的语法或者编译器实现的。
对于操作系统来说,类的私有,功能,保护的变量是一样的。
这是可以通过别的手法,或者变相的方式来修改/实现/突破的。

顺便说下:C++就是C++思想的对C的封装,不信你看C++的反汇编代码。

made by correy
made at 2015.12.14
http://correy.webs.com
*/


#include <Windows.h>
#include <assert.h>


class test
{
public:
    test(void);
    ~test(void);
    int get();
    int set();

    //int p;
private:
    int i;
};


test::test(void)
{
    i = 0x99999999;
    //p = 0x88888888;
}


test::~test(void)
{

}


int test::get(void)
{
    return i;
}


int test::set(void)
{
    return ++i;
}


int _tmain(int argc, _TCHAR* argv[])
{
    test t;

    printf("%p\n", t ); //这个其实是打印的类的第一个成员变量的值,不论是私有,公共还是保护。
    printf("%p\n", &t );//看看内存布局,看看反汇编。

    printf("%p\n", sizeof(test) );//不包含成员函数。

    //printf("%p\n", t.i );//无法访问 private 成员
    printf("%p\n", t.get() );
   
    //t.get();//和主题没用的函数。
    //t.set();

    void * p = &t;
    *(int *)p = 0;//这个是可以修改的,而且也没有发生异常。

    printf("%p\n", t.get() );//看看结果是否变了?

    //看内存属性吧!如果是WINDBG你还可以敲命令看。
    MEMORY_BASIC_INFORMATION mbi = {0};
    SIZE_T s = VirtualQuery(p, &mbi, sizeof (MEMORY_BASIC_INFORMATION));
    assert(s);
    printf("%p\n", mbi.AllocationProtect);

    return 0;
}

2015年11月13日星期五

内核中的splay trees和AVL trees

#include <ntifs.h>
#include <windef.h>

/*
内核中的二叉树之splay link tree。

发现内核中有操作以下树的函数。
splay link tree。
Adelson-Velsky/Landis (AVL) trees。
以后可以用AVL函数遍历进程的地址空间了,可能还需要知道数据结构(树的结构,进程对象,寄存器)。

splay link tree的配合函数。
RtlRandom
ExInitializeFastMutex
此文仅仅示例splay link tree的用法。

更多信息:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff553327(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff553345(v=vs.85).aspx

made by correy
made at 2014.08.22
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#define TAG   'tset' //test

typedef struct _BinTree {
    RTL_SPLAY_LINKS rsl;//注意这个不是指针,这个和下面的成员是并排的,且是第一个成员保持不变。
    int i;
} BinTree;
typedef BinTree *PBinTree;

BinTree g_bt;


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


VOID traversal(IN BinTree * t)
{
    if ( t != 0)
    {
        KdPrint(("%d\n",t->i));
        traversal((BinTree *) t->rsl.LeftChild);
        traversal((BinTree *) t->rsl.RightChild);
    }
}


BOOL InsertChild(IN BinTree * g , IN BinTree * t )
{
    BOOL B = FALSE ;
    BinTree * /*PRTL_SPLAY_LINKS*/ p ;

    if (RtlLeftChild(&g->rsl) == 0)
    {
        RtlInsertAsLeftChild(&g->rsl, &t->rsl);
        return TRUE ;
    }

    if (RtlRightChild(&g->rsl) == 0)
    {
        RtlInsertAsRightChild(&g->rsl, &t->rsl);
        return TRUE ;
    }  

    p  = (BinTree *)RtlRightChild(&g->rsl); //这个在前,下面的在后,这样遍历出的结果是顺序的。
    if (InsertChild(p, t ) == TRUE )
    {
        return TRUE ;
    }

    p  = (BinTree *)RtlLeftChild(&g->rsl);
    if (InsertChild(p, t ) == TRUE )
    {
        return TRUE ;
    }

    return B ;
}


BOOL DeleteOne()
{
    BOOL B = FALSE ;

    return B ;
}


BOOL DeleteALL()
{
    BOOL B = FALSE ;

    return B ;
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    BOOLEAN B = FALSE;
    PRTL_SPLAY_LINKS t;
    int i;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;
 
    //RtlInitializeSplayLinks(&g_bt.rsl);//设置上级为自己,其实源码也是这样的。
    //RtlInsertAsRightChild(&g_bt.rsl, &g_bt1.rsl);//设置上级的右孩子为自己,同时设置自己的上级为第一个参数,其实源码也是这样的。
    //RtlInsertAsLeftChild(&g_bt.rsl, &g_bt2.rsl);//同上,不再解释。

    //B = RtlIsRoot(&g_bt.rsl);//有源码。
    //t = RtlParent(&g_bt1.rsl);//有源码。
    //t = RtlRightChild(&g_bt.rsl);//有源码。
    //t = RtlLeftChild(&g_bt.rsl);//有源码。
    //B = RtlIsLeftChild//有源码。
    //B = RtlIsRightChild //有源码。

    //RtlDeleteNoSplay(&g_bt.rsl, &t);//没有源码。
    //t = RtlSubtreeSuccessor(&g_bt.rsl);//没有源码。
    //t = RtlSubtreePredecessor(&g_bt.rsl);//没有源码。
    //t = RtlRealSuccessor(&g_bt.rsl);//没有源码。
    //t = RtlRealPredecessor(&g_bt.rsl);//没有源码。
    //t = RtlSplay(&g_bt.rsl);//没有源码。
    //t = RtlDelete(&g_bt.rsl);//没有源码。保持平衡

    //创建
    g_bt.i = 10;
    RtlInitializeSplayLinks(&g_bt.rsl);

    //插入
    for (i = 0 ; i < 10; i++)
    {
        BinTree * btt = (BinTree *)ExAllocatePoolWithTag(NonPagedPool, sizeof(BinTree), TAG); //这里不能用全局变量,否则栈溢出。
        if (btt == NULL) {
            break;
        }
        RtlZeroMemory(btt, sizeof(BinTree));

        btt->i = i;
        InsertChild(&g_bt, btt);
    }

    //遍历
    traversal(&g_bt);

    //删除  
 
    return status;//STATUS_SUCCESS
}



--------------------------------------------------------------------------------------------------------------------------------



/*
By default, the operating system uses splay trees to implement generic tables.
Under some circumstances, operations on a splay tree will make the tree deep and narrow and might even turn it into a straight line.
Very deep trees degrade the performance of searches.
You can ensure a more balanced, shallower tree implementation of generic tables by using Adelson-Velsky/Landis (AVL) trees.
If you want to configure the generic table routines to use AVL trees instead of splay trees in your driver, insert the following define statement in a common header file before including Ntddk.h:
*/
//#define RTL_USE_AVL_TABLES 0
/*
If RTL_USE_AVL_TABLES is not defined, you must use the AVL form of the generic table routines.
For example, use the RtlInitializeGenericTableAvl routine instead of RtlInitializeGenericTable.
RtlInitializeGenericTableAvl returns an initialized RTL_AVL_TABLE table structure in the buffer to which the Table parameter points.
In the call to RtlInitializeGenericTableAvl, the caller must pass a PRTL_AVL_COMPARE_ROUTINE-typed comparison callback routine,
a PRTL_AVL_ALLOCATE_ROUTINE-typed allocation callback routine, and a PRTL_AVL_FREE_ROUTINE-typed deallocation callback routine rather than the similar PRTL_GENERIC_Xxx-typed routines.
*/

#include <ntifs.h>
#include <windef.h>

#define TAG 'tset' //test

/*
功能:内核中的splay trees和Adelson-Velsky/Landis (AVL) trees的用法示例。

内核中的splay trees和Adelson-Velsky/Landis (AVL) trees知道久矣!一直没有机会去做实验。
微软好像建议用AVL trees,不建议用splay trees。个人感觉AVL trees比splay trees快。
不过会用了,那就想用哪个就用哪个。

我们平常应该使用最多的应该是:RtlGetElementGenericTable,这个可能很快,不用再自己遍历链表和匹配了,
其次是RtlGetElementGenericTable,
RtlEnumerateGenericTable和RtlEnumerateGenericTableWithoutSplaying应该是用的最少的。
但是RtlDeleteElementGenericTable和RtlInsertElementGenericTable和RtlInitializeGenericTable是必须的。

示例工程:
1.Windows 8 Driver Samples\ClassPnP Storage Class Driver Library,注意:7600.16385.1\src\storage\class\classpnp没有。
2.Windows 8 Driver Samples\AvScan File System Minifilter Driver
3.https://github.com/desowin/usbpcap/blob/master/USBPcapDriver/USBPcapTables.c

Callers of RtlInitializeGenericTable must be running at IRQL <= DISPATCH_LEVEL.
Note that if Rtl...GenericTable routines are to be used at IRQL DISPATCH_LEVEL, the CompareRoutine, AllocateRoutine, and FreeRoutine must all be nonpageable code,
and the AllocateRoutine should allocate memory from nonpaged pool.

RtlDeleteElementGenericTableAvl
RtlEnumerateGenericTableAvl
RtlEnumerateGenericTableLikeADirectory
RtlEnumerateGenericTableWithoutSplayingAvl
RtlGetElementGenericTableAvl
RtlInsertElementGenericTableAvl
RtlInsertElementGenericTableFullAvl
RtlIsGenericTableEmptyAvl
RtlLookupElementGenericTableAvl
RtlLookupElementGenericTableFullAvl
RtlLookupFirstMatchingElementGenericTableAvl
RtlNumberGenericTableElementsAvl

made by correy
made at 2015.11.12
homepage:http://correy.webs.com
*/

#ifdef RTL_USE_AVL_TABLES
RTL_AVL_TABLE g_Table = {0}; //编译时RtlInitializeGenericTable第一个参数类型不对。
#else
RTL_GENERIC_TABLE g_Table = {0};//WDK 7600.16385.1的文档上没有公开这个结构(搞得好乖神秘的),MSDN上公开了。
#endif

/*
有的说这个结构不可过小,可是经测试也没事。
有的在结构的头部添加:RTL_SPLAY_LINKS和LIST_ENTRY两成员。
*/
typedef struct _content{
    int i;
    //...
}content, *Pcontent;

#define BUFFERSIZE (sizeof(RTL_SPLAY_LINKS) + sizeof(LIST_ENTRY) + sizeof(content))

FAST_MUTEX  g_FastMutex;


RTL_GENERIC_COMPARE_RESULTS CompareRoutine (__in struct _RTL_GENERIC_TABLE  *Table, __in PVOID  FirstStruct, __in PVOID  SecondStruct)
    /*
    The caller-supplied CompareRoutine is called before the AllocateRoutine to locate an appropriate location at which a new element should be inserted.
    The CompareRoutine also is called before the FreeRoutine to locate an element to be deleted.

    Arguments:
    Table        A pointer to the generic table.
    FirstStruct  A pointer to the first item to be compared.
    SecondStruct A pointer to the second item to be compared.

    The CompareRoutine must strictly track the ordering of all elements in the generic table so that it can identify any particular element.
    The caller-defined structure for element data usually includes a member whose value is unique and can be used as a sorting key.
    All Rtl...GenericTable routines that call the CompareRoutine take a buffer pointer as a parameter, which is passed in turn to the CompareRoutine.
    The buffer contains a caller-supplied key value to be matched by the CompareRoutine to the key of the element that is being searched for.
 
    Given two such key values, the CompareRoutine returns GenericLessThan, GenericGreaterThan, or GenericEqual.

    RtlInsertElementGenericTable的第一次调用不会走这里,可能发现表是空的。
    */
{
    Pcontent p1 = (Pcontent)FirstStruct;
    Pcontent p2 = (Pcontent)SecondStruct;

    if (p1->i < p2->i)
    {
        return GenericLessThan;
    }
    else if (p1->i > p2->i)
    {
        return GenericGreaterThan;
    }
    else
    {
        return GenericEqual;
    }
}


PVOID AllocateRoutine (__in struct _RTL_GENERIC_TABLE  *Table, __in CLONG  ByteSize)
    /*
    调用RtlInsertElementGenericTable会走这里。

    Arguments:
    Table    A pointer to the generic table.
    ByteSize The number of bytes to allocate.

    For each new element, the AllocateRoutine is called to allocate memory for caller-supplied data plus some additional memory for use by the Rtl...GenericTable routines.
    Note that because of this "additional memory," caller-supplied routines must not access the first (sizeof(RTL_SPLAY_LINKS) + sizeof(LIST_ENTRY)) bytes of any element in the generic table.
    */
{
    return ExAllocatePoolWithTag(NonPagedPool, ByteSize, TAG);
}


VOID FreeRoutine (__in struct _RTL_GENERIC_TABLE  *Table, __in PVOID  Buffer)
    /*
    调用RtlDeleteElementGenericTable会走这里。

    Arguments:
    Table  A pointer to the generic table.
    Buffer A pointer to the element that is being deleted.

    Rtl...GenericTable routines call the FreeRoutine to deallocate memory for elements to be deleted from the generic table.
    The FreeRoutine is the opposite of the AllocateRoutine.
    */
{
    ExFreePoolWithTag(Buffer, TAG);
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
}


void InitializeGenericTable()
{
    ExInitializeFastMutex(&g_FastMutex);

    RtlInitializeGenericTable(&g_Table, (PRTL_GENERIC_COMPARE_ROUTINE)CompareRoutine, (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocateRoutine, (PRTL_GENERIC_FREE_ROUTINE)FreeRoutine, NULL);
}


void InsertElementGenericTable()
{
    PVOID p = NULL;
    PVOID              Buffer = NULL;
    BOOLEAN            NewElement = FALSE;
    int i = 0;

    Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(content), TAG);
    ASSERT(Buffer != NULL);

    for ( ; i < 9; i++)
    {
        Pcontent pc = (Pcontent)Buffer;
        RtlZeroMemory(Buffer, sizeof(content));      
        pc->i = i;//设置内容,因为不准重复的元素。

        ExAcquireFastMutex(&g_FastMutex);
        p = RtlInsertElementGenericTable(&g_Table, Buffer, sizeof(content), &NewElement);
        ASSERT(p != NULL);
        //ASSERT(NewElement == TRUE );
        ExReleaseFastMutex(&g_FastMutex);
    }

    ExFreePoolWithTag(Buffer, TAG);
}


void GetElementGenericTable()
{
    PVOID p = NULL;
    ULONG I = 0;
    Pcontent pc = NULL;

    ExAcquireFastMutex(&g_FastMutex);

    I = RtlNumberGenericTableElements(&g_Table) - 1;

    p = RtlGetElementGenericTable(&g_Table, I);
    ASSERT(p != NULL);

    pc = (Pcontent)p;

    ExReleaseFastMutex(&g_FastMutex);
}


void LookupElementGenericTable()
{
    PVOID p = NULL;
    content test = {0};
    Pcontent pc = NULL;

    ExAcquireFastMutex(&g_FastMutex);

    test.i = 1;

    p = RtlLookupElementGenericTable(&g_Table, &test);
    ASSERT(p != NULL);

    pc = (Pcontent)p;
    ASSERT(pc->i == 1);

    ExReleaseFastMutex(&g_FastMutex);
}


void EnumerateGenericTable()
{
    PVOID p = NULL;

    ExAcquireFastMutex(&g_FastMutex);
    for (p = RtlEnumerateGenericTable ( &g_Table, TRUE ); p != NULL; p = RtlEnumerateGenericTable ( &g_Table, FALSE ))
    {
        // Process the element pointed to by p
        Pcontent pc = (Pcontent)p;

        KdPrint(("%d.\r\n", pc->i));
    }
    ExReleaseFastMutex(&g_FastMutex);
}


void EnumerateGenericTableWithoutSplaying()
{
    PVOID ptr = NULL;
    PVOID RestartKey = NULL;

    ExAcquireFastMutex(&g_FastMutex);
    for (ptr = RtlEnumerateGenericTableWithoutSplaying(&g_Table, &RestartKey); ptr != NULL; ptr = RtlEnumerateGenericTableWithoutSplaying(&g_Table, &RestartKey))
    {
        // Process the element pointed to by ptr
        Pcontent pc = (Pcontent)ptr;

        KdPrint(("%d.\r\n", pc->i));
    }
    ExReleaseFastMutex(&g_FastMutex);
}


void EnumerateGenericTableEx()
{
    ULONG i = 0;

    ExAcquireFastMutex(&g_FastMutex);
    for ( ; i < RtlNumberGenericTableElements(&g_Table); i++)
    {
        // Process the element pointed to by p
        Pcontent pc = (Pcontent)RtlGetElementGenericTable(&g_Table, i);

        KdPrint(("%d.\r\n", pc->i));
    }
    ExReleaseFastMutex(&g_FastMutex);
}


void DeleteElementGenericTable1()
    /*
    功能:删除整个表。
    参考:https://msdn.microsoft.com/en-us/library/windows/hardware/ff552243(v=vs.85).aspx
    因为:RtlEnumerateGenericTable returns a pointer to the next element,所以这没有走完就退出了,结果是没有删除完毕。
          要做还得改进。
    */
{
    PVOID p = NULL;

    ExAcquireFastMutex(&g_FastMutex);
    for (p = RtlEnumerateGenericTable ( &g_Table, TRUE );
        p != NULL;
        p = RtlEnumerateGenericTable ( &g_Table, FALSE ))
    {      
        // Process the element pointed to by p
        BOOLEAN B = RtlDeleteElementGenericTable(&g_Table, p);
        ASSERT(B != TRUE );
    }
    ExReleaseFastMutex(&g_FastMutex);
}


void DeleteElementGenericTable2()
    /*
    功能:删除整个表。
    参考:https://msdn.microsoft.com/en-us/library/windows/hardware/ff552247(v=vs.85).aspx
    原因:同上,要做还有很多改进的余地。
    */
{
    PVOID ptr = NULL;
    PVOID RestartKey = NULL;

    ExAcquireFastMutex(&g_FastMutex);
    for (ptr = RtlEnumerateGenericTableWithoutSplaying(&g_Table, &RestartKey);
        ptr != NULL;
        ptr = RtlEnumerateGenericTableWithoutSplaying(&g_Table, &RestartKey))
    {
        // Process the element pointed to by ptr
        BOOLEAN B = RtlDeleteElementGenericTable(&g_Table, ptr);
        ASSERT(B != TRUE );
    }
    ExReleaseFastMutex(&g_FastMutex);
}


void DeleteElementGenericTable3()
    /*
    功能:删除整个表。
    摘自:Windows 8 Driver Samples\AvScan File System Minifilter Driver\C++\filter\avscan.c
    */
{
    ExAcquireFastMutex(&g_FastMutex);
    while (!RtlIsGenericTableEmpty( &g_Table ) )
    {
        PVOID entry = RtlGetElementGenericTable(&g_Table, 0);          
        RtlDeleteElementGenericTable(&g_Table, entry);
    }
    ExReleaseFastMutex(&g_FastMutex);
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
 
    KdBreakPoint();

    DriverObject->DriverUnload = Unload;  

    InitializeGenericTable();

    InsertElementGenericTable();

    GetElementGenericTable();

    LookupElementGenericTable();

    EnumerateGenericTable();

    EnumerateGenericTableWithoutSplaying();

    EnumerateGenericTableEx();

    //DeleteElementGenericTable1();
    //DeleteElementGenericTable2();
    DeleteElementGenericTable3();

    return status;
}

2015年10月22日星期四

查看minifilter的Context的UseCount

标题:查看minifilter的Context的UseCount。

因为Context是自己申请和定义的结构,如何查看呢?
因为他们的前面都有一个统一的结构,或者说是头。
如何查看呢?

!fltkd.help命令可打印出:
......
ctx [addr] [detail]                       Dump CONTEXT_NODE
......

注意,还有个:
contextlist [addr] [detail]               Dump CONTEXT_LIST_CTRL

注意命令的格式及参数的个数。

1.instanceContext示例。
0: kd> dt _context_node (instanceContext - @@(sizeof(_context_node)))
fltMgr!_CONTEXT_NODE
   +0x000 RegInfo          : 0x805372c4 _ALLOCATE_CONTEXT_HEADER
   +0x004 AttachedObject   : __unnamed
   +0x008 TreeLink         : _TREE_NODE
   +0x008 WorkItem         : _WORK_QUEUE_ITEM
   +0x024 UseCount         : 0n26
0: kd> !fltkd.ctx (poi(instanceContext)-@@(sizeof(_context_node)))

CONTEXT_NODE: 822421b8  [0002] InstanceContext NonPagedPool
   ALLOCATE_CONTEXT_NODE: 81cc4768 "test" [01] LookasideList
Could not read field "NonPaged.L.Size" of FltMgr!_ALLOCATE_CONTEXT_LOOKASIDE from address: 81cc4768
   AttachedObject           : 81cfe550
   UseCount                 : 2
   TREE_NODE: 822421c0 (k1=00690044, k2=00700073) [00010000] InTree
   UserData                 : 822421e0

2.streamContext示例。
1: kd> dt _context_node (streamContext - @@(sizeof(_context_node)))
fltMgr!_CONTEXT_NODE
   +0x000 RegInfo          : 0xef90d978 _ALLOCATE_CONTEXT_HEADER
   +0x004 AttachedObject   : __unnamed
   +0x008 TreeLink         : _TREE_NODE
   +0x008 WorkItem         : _WORK_QUEUE_ITEM
   +0x024 UseCount         : 0n1
1: kd> !fltkd.ctx (poi(streamContext)-@@(sizeof(_context_node)))

CONTEXT_NODE: e1c6d6a8  [0008] StreamContext PagedPool
   ALLOCATE_CONTEXT_NODE: 81cc48f8 "test" [01] LookasideList
Could not read field "NonPaged.L.Size" of FltMgr!_ALLOCATE_CONTEXT_LOOKASIDE from address: 81cc48f8
   AttachedObject           : 81e0aa48
   UseCount                 : 2
   TREE_NODE: e1c6d6b0 (k1=81cf8008, k2=00000000) [00010001] InTree
   UserData                 : e1c6d6d0

3.streamHandleContext示例。
1: kd>  dt _context_node (streamHandleContext - @@(sizeof(_context_node)))
fltMgr!_CONTEXT_NODE
   +0x000 RegInfo          : 0x00000001 _ALLOCATE_CONTEXT_HEADER
   +0x004 AttachedObject   : __unnamed
   +0x008 TreeLink         : _TREE_NODE
   +0x008 WorkItem         : _WORK_QUEUE_ITEM
   +0x024 UseCount         : 0n0
1: kd> !fltkd.ctx (poi(streamHandleContext)-@@(sizeof(_context_node)))

CONTEXT_NODE: e247d728  [0010] StreamHandleContext PagedPool
   ALLOCATE_CONTEXT_NODE: 81cc49c0 "test" [01] LookasideList
Could not read field "NonPaged.L.Size" of FltMgr!_ALLOCATE_CONTEXT_LOOKASIDE from address: 81cc49c0
   AttachedObject           : 81e0aa48
   UseCount                 : 2
   TREE_NODE: e247d730 (k1=81d525e8, k2=81cf8008) [00010001] InTree
   UserData                 : e247d750

更多的还有FLT_VOLUME_CONTEXT,FLT_FILE_CONTEXT,FLT_TRANSACTION_CONTEXT的查看。

注意:
1.用过CONTEXT之后,无论是设置还是获取,都把UseCount减一。
2.在卸载驱动之前应该把所有的CONTEXT释放完毕,否则FltUnregisterFilter永远等待。
3.建议用!fltkd.ctx,而不建议用dt _context_node。

获取结构的大小是这样用的。
0: kd> ?? sizeof(_context_node)
unsigned int 0x28

参考资料:
http://blogs.msdn.com/b/alexcarp/archive/2009/07/01/filter-manager-concepts-part-5-context-node.aspx

made by correy
made at 10:31 2015/10/22
homepage:http://correy.webs.com

2015年9月20日星期日

根据PEB获取命令行参数

#include <ntifs.h>
//#include <ntddk.h> //这两个次序不能乱(乱会出错的),有上面的,这个可以注释掉。
//#include <winternl.h> //在Windows Kits\8.0\Include\um\winternl.h。可是不能用:fatal error C1083: 无法打开包括文件:“winternl.h”: No such file or directory
#include <windef.h>

/*
功能:获取程序的命令行参数。

尽管有Windows Kits\8.0\Include\um\winternl.h。
但是:不包含64位的,因为:

32位系统下:
kd> dt _PEB ProcessParameters
ntdll!_PEB
   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
64位系统下:
0: kd> dt _PEB ProcessParameters
nt!_PEB
   +0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
并且64位系统下的WOW64也是这样的。

注意:WDK7600.16385.1这个是没有的PEB的定义的。

made by correy
made at 2015.08.13
*/

#define tag  'tset' //test

//https://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx
typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];
  PVOID      Reserved2[3];
  LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

//https://msdn.microsoft.com/en-us/library/windows/desktop/aa813741(v=vs.85).aspx
typedef struct _RTL_USER_PROCESS_PARAMETERS {
  BYTE           Reserved1[16];
  PVOID          Reserved2[10];
  UNICODE_STRING ImagePathName;
  UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

//Windows Kits\8.0\Include\um\winternl.h
typedef
VOID
(NTAPI *PPS_POST_PROCESS_INIT_ROUTINE) (
    VOID
    );

#if defined(_WIN64) //defined(_AMD64_) || defined(_IA64_) //

//https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706(v=vs.85).aspx
typedef struct _PEB {
    BYTE Reserved1[2];
    BYTE BeingDebugged;
    BYTE Reserved2[21];
    PPEB_LDR_DATA LoaderData;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    BYTE Reserved3[520];
    PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
    BYTE Reserved4[136];
    ULONG SessionId;
} PEB;

#else

//https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706(v=vs.85).aspx
typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

#endif


/*
摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\inc\ps.h
此函数在XP 32上就已经导出,应该可以放心使用。
或者ZwQueryInformationProcess 的 ProcessBasicInformation.
*/
NTKERNELAPI
PPEB
PsGetProcessPeb(
    __in PEPROCESS Process
    );

//--------------------------------------------------------------------------------------

/*
这个是ZwQuerySystemInformation用的结构。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx
*/
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    PVOID Reserved2[3];
    HANDLE UniqueProcessId;
    PVOID Reserved3;
    ULONG HandleCount;
    BYTE Reserved4[4];
    PVOID Reserved5[11];
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION;


/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h
更多的信息,可看:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/SYSTEM_INFORMATION_CLASS.html#SystemProcessInformation
http://doxygen.reactos.org/d2/d5c/ntddk__ex_8h_source.html
*/
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;


/*
摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
有修改。
*/
NTSTATUS /* WINAPI NtQuerySystemInformation */ ZwQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);


VOID print_commandLine(IN HANDLE PId)
/*
注意:
1.用这个办法取ImagePathName,IDLE和system这两个应该获取不到。
2.此函数用在进程回调中获取不到内容,线程回调的就不说了。
3.添加对类似进程回调等类似的情况,正常情况下没有试验。
*/
{
    PEPROCESS    m_process;
    NTSTATUS     status = STATUS_SUCCESS;
    KAPC_STATE   m_kapc_state;
    PPEB peb = 0;
    PRTL_USER_PROCESS_PARAMETERS  ProcessParameters = 0;
    UNICODE_STRING CommandLine = {0};
    PPEB_LDR_DATA LoaderData = 0;

    if (0 == PId)
    {
        return ;//IDLE
    }

    if (PsGetProcessId(PsInitialSystemProcess) == PId) //PsIsSystemThread
    {
        return;//system
    }

    status=PsLookupProcessByProcessId(PId, &m_process);
    if(!NT_SUCCESS(status))
    {
        return ;//无效进程。
    }

    KeStackAttachProcess (m_process,&m_kapc_state);

    peb = PsGetProcessPeb(m_process);//注意:IDLE和system这两个应该获取不到。

    ProcessParameters = peb->ProcessParameters;

#if defined(_WIN64)

    //LoaderData = peb->LoaderData;//64位下这个是有的,不用判断。
    KdPrint(("ProcessParameters->CommandLine:%wZ\r\n", &ProcessParameters->CommandLine));//WOW64进程也是这样的。

#else
    LoaderData = peb->Ldr;

    //32位下,至少XP这样,!PEB可显示CommandLine,但是_PEB的结构下的ProcessParameters看到的内容为空。
    if(LoaderData == NULL) //http://bbs.pediy.com/showthread.php?t=88730&page=2
    {
        if(ProcessParameters != NULL && ProcessParameters->CommandLine.Length != 0 && ProcessParameters->CommandLine.MaximumLength != 0 && ProcessParameters->CommandLine.Buffer != NULL)
        {
            //思路参考:http://www.douban.com/note/176759449/
            CommandLine.Buffer = (PWCH)((SIZE_T)ProcessParameters + (SIZE_T)ProcessParameters->CommandLine.Buffer);
            CommandLine.Length = ProcessParameters->CommandLine.Length;
            CommandLine.MaximumLength = ProcessParameters->CommandLine.MaximumLength;

            KdPrint(("ProcessParameters->CommandLine:%wZ\r\n", &CommandLine));
        }
    }
    else
    {
        KdPrint(("ProcessParameters->CommandLine:%wZ\r\n", &ProcessParameters->CommandLine));
    }

#endif  

    KeUnstackDetachProcess(&m_kapc_state);

    ObDereferenceObject(m_process);  
}


VOID ProcessCreateMon ( IN HANDLE hParentId, IN HANDLE PId,IN BOOLEAN bCreate )
{
    UCHAR * lpCurProc;

    if ( bCreate )
    {
        print_commandLine(PId);
    }
}


NTSTATUS show_all_process_commandLine(VOID)
    /*
    功能:
    */
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    SYSTEM_PROCESS_INFORMATION * pspi = 0;
    SYSTEM_PROCESS_INFORMATION * pspi_temp = 0;
    ULONG SystemInformationLength = 0;
    ULONG ReturnLength = 0;
 
    //获取需要的内存。
    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    {
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        return status;
    }
    ReturnLength *= 2;//第一次需求0x9700,第二次需求0x9750,所以乘以2.
    SystemInformationLength = ReturnLength;
    pspi = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (pspi == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(pspi, ReturnLength);  

    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( pspi, tag );
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    for (pspi_temp = pspi ; /* pspi_temp->NextEntryOffset != 0 */; /*pspi_temp++*/) //注释的都是有问题的,如少显示一个等。
    {
        print_commandLine(pspi_temp->UniqueProcessId);    

        //KdPrint(("PID:%d\tNumberOfThreads:%d\tHandleCount:%d\n",pspi_temp->UniqueProcessId, pspi_temp->NumberOfThreads, pspi_temp->HandleCount));
       
        /*
        The start of the next item in the array is the address of the previous item plus the value in the NextEntryOffset member.
        For the last item in the array, NextEntryOffset is 0.
        摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
        说明:NextEntryOffset的值是不固定的,更不是SYSTEM_PROCESS_INFORMATION结构的大小。所以不能加一个结构的大小来遍历。
        */

        if (pspi_temp->NextEntryOffset == 0)
        {
            break;
        }

        pspi_temp = (SYSTEM_PROCESS_INFORMATION *)((char *)pspi_temp + pspi_temp->NextEntryOffset);
    }

    ExFreePoolWithTag( pspi, tag );

    return status;//STATUS_SUCCESS
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, TRUE);
    if (!NT_SUCCESS( status ))
    {
        DbgPrint( "PsSetCreateProcessNotifyRoutine fail %d\n", status);
    }
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    BOOLEAN b = 0;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;  

    status = show_all_process_commandLine();  
    if (!NT_SUCCESS( status ))
    {
        DbgPrint("fail %d\n", status);
        //return status;
    }

    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);  
    if (!NT_SUCCESS( status ))
    {
        DbgPrint( "PsSetCreateProcessNotifyRoutine fail %d\n", status);
    }

    return status;
}

2015年8月8日星期六

遍历每个CPU的GDT信息

/*
功能:显示每个CPU的GDT信息。
注释:以下结构摘自WRK。

made by correy.
made at 2015.01.11.
*/

#include <ntifs.h>
#include <windef.h>


#if defined(_AMD64_) || defined(_IA64_) //defined(_WIN64)

// Special Registers for AMD64.
typedef struct _AMD64_DESCRIPTOR {
    USHORT  Pad[3];
    USHORT  Limit;
    ULONG64 Base;
} AMD64_DESCRIPTOR, *PAMD64_DESCRIPTOR;

typedef union _KGDTENTRY64 {
    struct {
        USHORT  LimitLow;
        USHORT  BaseLow;
        union {
            struct {
                UCHAR   BaseMiddle;
                UCHAR   Flags1;
                UCHAR   Flags2;
                UCHAR   BaseHigh;
            } Bytes;

            struct {
                ULONG   BaseMiddle : 8;
                ULONG   Type : 5;//把S位包含进去了,也就是是否为系统段描述符的位。
                ULONG   Dpl : 2;
                ULONG   Present : 1;
                ULONG   LimitHigh : 4;
                ULONG   System : 1;//即AVL,系统软件自定义的。
                ULONG   LongMode : 1;
                ULONG   DefaultBig : 1;//即INTEL的D/B (default operation size/default stack pointer size and/or upper bound) flag。
                ULONG   Granularity : 1;
                ULONG   BaseHigh : 8;
            } Bits;
        };

        //ULONG BaseUpper;/*经观察,64下的结构的长度是6字节,不是上面定义的16字节。*/
        //ULONG MustBeZero;
    };

    //ULONG64 Alignment;
} KGDTENTRY64, *PKGDTENTRY64;


#else

// Special Registers for i386
typedef struct _X86_DESCRIPTOR {
    USHORT  Pad;
    USHORT  Limit;
    ULONG   Base;
} X86_DESCRIPTOR, *PX86_DESCRIPTOR;

typedef struct _X86_KSPECIAL_REGISTERS {
    ULONG Cr0;
    ULONG Cr2;
    ULONG Cr3;
    ULONG Cr4;
    ULONG KernelDr0;
    ULONG KernelDr1;
    ULONG KernelDr2;
    ULONG KernelDr3;
    ULONG KernelDr6;
    ULONG KernelDr7;
    X86_DESCRIPTOR Gdtr;
    X86_DESCRIPTOR Idtr;//由此可知,GDT和IDT的结构是一样的。
    USHORT Tr;
    USHORT Ldtr;
    ULONG Reserved[6];
} X86_KSPECIAL_REGISTERS, *PX86_KSPECIAL_REGISTERS;

// GDT Entry
typedef struct _KGDTENTRY {
    USHORT  LimitLow;
    USHORT  BaseLow;
    union {
        struct {
            UCHAR   BaseMid;
            UCHAR   Flags1;     // Declare as bytes to avoid alignment
            UCHAR   Flags2;     // Problems.
            UCHAR   BaseHi;
        } Bytes;
        struct {
            ULONG   BaseMid : 8;
            ULONG   Type : 5;//把S位包含进去了,也就是是否为系统段描述符的位。
            ULONG   Dpl : 2;
            ULONG   Pres : 1;
            ULONG   LimitHi : 4;
            ULONG   Sys : 1;//即AVL,系统软件自定义的。
            ULONG   Reserved_0 : 1;//LongMode
            ULONG   Default_Big : 1;//即INTEL的D/B (default operation size/default stack pointer size and/or upper bound) flag。
            ULONG   Granularity : 1;
            ULONG   BaseHi : 8;
        } Bits;
    } HighWord;
} KGDTENTRY, *PKGDTENTRY;

#endif

/*
根据:Table 3-1. Code- and Data-Segment Types,仿照WINDBG的dg命令定义。
*/
char SegmentTypes[][256] = {
"<Reserved>",//Data Read-Only缩写是:Data RO,也可认为是: <Reserved>。如果结构(UINT64)全部为零,也可认为是Reserved。
"Data RO AC",//Data Read-Only, accessed
"Data RW",//Data Read/Write
"Data RW AC",//Data Read/Write, accessed
"Data RO ED",//Data Read-Only, expand-down
"Data RO ED AC",//Data Read-Only, expand-down, accessed
    "Data RW ED",//Data Read/Write, expand-down
    "Data RW ED AC",//Data Read/Write, expand-down, accessed

    "Code EO",//Code Execute-Only
    "Code EO AC",//Code Execute-Only, accessed
    "Code RE",//Code Execute/Read 加空格以便显示的对齐。
    "Code RE AC",//Code Execute/Read, accessed
    "Code EO CO",//Code Execute-Only, conforming
    "Code EO CO AC",//Code Execute-Only, conforming, accessed
    "Code RE CO",//Code Execute/Read, conforming
    "Code RE CO AC",//Code Execute/Read, conforming, accessed
    "TSS32 Busy ",//这个也可显示只要识别了TSS及内容。
    "TSS32 Avl" //这个在X86上出现了。
};


DRIVER_UNLOAD DriverUnload;
VOID DriverUnload(__in PDRIVER_OBJECT DriverObject)
{  

}


#ifdef _X86_
__forceinline PKPCR KeGetPcr (VOID)
{
    return (PKPCR)__readfsdword(FIELD_OFFSET(KPCR, SelfPcr));
}
#endif


USHORT NTAPI GetGdtLimit ();//汇编函数。


#if defined(_WIN64)
void show_gdt(int i)
    /*
    i的取值可以是0.
    */
{
    //SIZE_T IDTR;
    //X86_DESCRIPTOR gdtr = {0};//A pointer to the memory location where the IDTR is stored.
    //KGDTENTRY * GDT = 0;
    USHORT GdtLimit = 0;

    SIZE_T r = 0;
    PVOID p = 0;
    int index = 0;
    int maximun = 0;

    PKGDTENTRY64 pkgdte;
    SIZE_T ISR = 0;
   
    KeSetSystemAffinityThread(i + 1);
    pkgdte = KeGetPcr()->GdtBase;//没有__sgdt,也不用sgdt汇编指令的办法。但是这个获取的没有长度。
    GdtLimit = GetGdtLimit ();//一般等于0x7f.
    KeRevertToUserAffinityThread();

    //p = &gdtr.Limit;
    //r = * (SIZE_T *)p;
    //pkgdte = (PKGDTENTRY)r;

    /*
    其实直接:
    maximun = (idtr.Base + 1) / sizeof(KIDTENTRY);
    也可以。
    maximun一般等于256.
    */
    //if (gdtr.Pad % sizeof(KIDTENTRY) == 0) {
    //    maximun = gdtr.Pad / sizeof(KIDTENTRY);
    //} else {
    //    maximun = gdtr.Pad / sizeof(KIDTENTRY);
    //    maximun++;
    //}

    //if (GdtLimit % sizeof(KGDTENTRY64) == 0) {
    //    maximun = GdtLimit / sizeof(KGDTENTRY64);
    //} else {
    //    maximun = GdtLimit / sizeof(KGDTENTRY64);
    //    maximun++;//一般是128.
    //}

    maximun = (GdtLimit + 1) / sizeof(KGDTENTRY64);

    /*
    显示格式:  
    CPU SN Sel        Base              Limit          Type    Pl Size Gran Pres Long Flags
    --- -- ---- ----------------- ----------------- ---------- -- ---- ---- ---- ---- --------

    注释:CPU和SN是自己添加的。SN即Segment Name,如:CS,DS,FS等.
    */
    KdPrint(("Sel        Base             Limit             Type   DPl Size Gran Pres Long Flags\n"));//CPU SN
    KdPrint(("---- ---------------- ---------------- ------------- --- ---- ---- ---- ---- --------\n"));//--- --
    KdPrint(("\n"));

    for ( ;index < maximun ;index++ )
    {
        PKGDTENTRY64 pkgdte_t = &pkgdte[index];
        SIZE_T Base = 0;
        SIZE_T Limit = 0;
        ULONG  Type = 0;
        char * size = NULL;
        char * Granularity = NULL;
        char * Present = NULL;
        char * LongMode = NULL;
        int    Flags = 0;      

        Base = pkgdte_t->Bits.BaseHigh;
        Base = (Base << 24);
        Base += (pkgdte_t->BaseLow + (pkgdte_t->Bits.BaseMiddle << 16));

        Limit = pkgdte_t->LimitLow + (pkgdte_t->Bits.LimitHigh << 16);
       
        if (pkgdte_t->Bits.DefaultBig && Base)
        {
            //扩充高位为1.即F.
            Base += 0xffffffff00000000;
        }    

        if (pkgdte_t->Bits.DefaultBig && pkgdte_t->Bits.Granularity)
        {
            //扩充高位为1.即F.
            SIZE_T t = Limit;
            Limit = (Limit << 12);
            Limit += PAGE_SIZE - 1;
        }

        Type = pkgdte_t->Bits.Type;
        _bittestandreset(&Type, 4);//因为这个包含了S位,所以要清除这个位标志。

        if (pkgdte_t->Bits.DefaultBig)
        {
            size = "Bg  ";//Big 加空格是为了对齐显示。
        }
        else
        {
            size = "Nb  ";//Not Big 加空格是为了对齐显示。
        }

        if (pkgdte_t->Bits.Granularity)
        {
            Granularity = "Pg  ";//Page 加空格是为了对齐显示。
        }
        else
        {
            Granularity = "By  ";//Byte 加空格是为了对齐显示。
        }

        if (pkgdte_t->Bits.Present)
        {
            Present = "P   ";//Present 加空格是为了对齐显示。
        }
        else
        {
            Present = "NP  ";//NO Present 加空格是为了对齐显示。
        }

        if (pkgdte_t->Bits.LongMode)
        {
            LongMode = "Lo  ";//Long 加空格是为了对齐显示。
        }
        else
        {
            LongMode = "Nl  ";//NO long 加空格是为了对齐显示。
        }
       
        Flags = (pkgdte_t->Bytes.Flags2 >> 4);//去掉Segment limit的那几位。
        Flags = Flags << 8;
        Flags = Flags + pkgdte_t->Bytes.Flags1;

        KdPrint(("%04x %p %p %13s %03x %s %s %s %s 0x%04x\n",
            index * 8, //sizeof (KGDTENTRY)
            Base,
            Limit,
            SegmentTypes[Type],
            pkgdte_t->Bits.Dpl,
            size,
            Granularity,
            Present,          
            LongMode,
            Flags
            ));

        //if (pkgdte_t->Bits.Present)
        //{
        //    KdPrint(("第%d号CPU的GDT的Sel:0x%03x, Base:0x%016p, Limit:0x%016p, type:0x%02x, Dpl:0x%x, Pres:0x%x, Sys:0x%x, LongMode:0x%x, Default_Big:0x%x, Granularity:0x%x.\n",
        //        i, index * sizeof (KGDTENTRY64), Base, Limit,
        //        pkgdte_t->Bits.Type,
        //        pkgdte_t->Bits.Dpl,
        //        pkgdte_t->Bits.Present,//再打印一次吧!
        //        pkgdte_t->Bits.System,
        //        pkgdte_t->Bits.LongMode,
        //        pkgdte_t->Bits.DefaultBig,
        //        pkgdte_t->Bits.Granularity
        //        ));
        //}
        //else //<Reserved>
        //{
        //    KdPrint(("第%d号CPU的GDT的Sel:0x%03x is Reserved!\n", i, index * sizeof (KGDTENTRY64)));
        //}


        ////偶尔出现有一个不对,即0x38的值不对,
        //Base = pkgdte_t->BaseLow + (pkgdte_t->HighWord.Bits.BaseHi << 24) + (pkgdte_t->HighWord.Bits.BaseMid << 16);//其实用位与更快 | 。

        //if (pkgdte_t->HighWord.Bits.Granularity && BooleanFlagOn(pkgdte_t->HighWord.Bits.Type, 2 ) ) {//关于标志位及算法,见权威资料。
        //    Limit = pkgdte_t->LimitLow + (pkgdte_t->HighWord.Bits.LimitHi << 16);
        //    Limit *= PAGE_SIZE;
        //    Limit += PAGE_SIZE - 1;
        //} else {
        //    Limit = pkgdte_t->LimitLow + (pkgdte_t->HighWord.Bits.LimitHi << 16);
        //}

        //KdPrint(("第%d号CPU的GDT的Sel:0x%03x, Base:0x%08x, Limit:0x%08x, type:0x%02x, Dpl:0x%x, Pres:0x%x, Sys:0x%x,Default_Big:0x%x, Granularity:0x%x.\n",
        //    i, index * sizeof (KGDTENTRY), Base, Limit,
        //    pkgdte_t->HighWord.Bits.Type,
        //    pkgdte_t->HighWord.Bits.Dpl,
        //    pkgdte_t->HighWord.Bits.Pres,
        //    pkgdte_t->HighWord.Bits.Sys,
        //    pkgdte_t->HighWord.Bits.Default_Big,
        //    pkgdte_t->HighWord.Bits.Granularity
        //    ));

        /*
        这里的Default_Big对应dg命令的size.
        这里的Sys对应dg命令的long.
        Flags的值等于变相打印了,这里就不再打印了。
        */
    }
}
#else
void show_gdt(int i)
    /*
    i的取值可以是0.
    */
{
    //SIZE_T IDTR;
    //X86_DESCRIPTOR gdtr = {0};//A pointer to the memory location where the IDTR is stored.
    //KGDTENTRY * GDT = 0;
    USHORT GdtLimit = 0;

    SIZE_T r = 0;
    PVOID p = 0;
    int index = 0;
    int maximun = 0;

    PKGDTENTRY pkgdte;
    SIZE_T ISR = 0;
   
    KeSetSystemAffinityThread(i + 1);
    pkgdte = KeGetPcr()->GDT;//没有__sgdt,也不用sgdt汇编指令的办法。但是这个获取的没有长度。
    GdtLimit = GetGdtLimit ();//一般等于0x3ff.
    KeRevertToUserAffinityThread();

    //p = &gdtr.Limit;
    //r = * (SIZE_T *)p;
    //pkgdte = (PKGDTENTRY)r;

    /*
    其实直接:
    maximun = (idtr.Base + 1) / sizeof(KIDTENTRY);
    也可以。
    maximun一般等于256.
    */
    //if (gdtr.Pad % sizeof(KIDTENTRY) == 0) {
    //    maximun = gdtr.Pad / sizeof(KIDTENTRY);
    //} else {
    //    maximun = gdtr.Pad / sizeof(KIDTENTRY);
    //    maximun++;
    //}

    if (GdtLimit % sizeof(KGDTENTRY) == 0) {
        maximun = GdtLimit / sizeof(KGDTENTRY);
    } else {
        maximun = GdtLimit / sizeof(KGDTENTRY);
        maximun++;//一般是128.
    }

    /*
    显示格式:  
    CPU SN Sel        Base              Limit          Type    Pl Size Gran Pres Long Flags
    --- -- ---- ----------------- ----------------- ---------- -- ---- ---- ---- ---- --------

    注释:CPU和SN是自己添加的。SN即Segment Name,如:CS,DS,FS等.
    */
    KdPrint(("Sel  Base             Limit          Type DPl Size Gran Pres Long Flags\n"));//CPU SN
    KdPrint(("---- -------- ------------- ------------- --- ---- ---- ---- ---- --------\n"));//--- --
    KdPrint(("\n"));

    for ( ;index < maximun ;index++ )
    {
        PKGDTENTRY pkgdte_t = &pkgdte[index];
        SIZE_T Base = 0;
        SIZE_T Limit = 0;
        ULONG  Type = 0;
        char * size = NULL;
        char * Granularity = NULL;
        char * Present = NULL;
        char * LongMode = NULL;
        int    Flags = 0;  

        //注意:0x38处的值不停的变化。
        USHORT  BaseLow = pkgdte_t->BaseLow;
        ULONG   BaseMid = pkgdte_t->HighWord.Bits.BaseMid;
        ULONG   BaseHi = pkgdte_t->HighWord.Bits.BaseHi;
        Base = (BaseHi << 24) + (BaseMid << 16) + BaseLow;//其实用位与更快 | 。

        if (pkgdte_t->HighWord.Bits.Granularity && BooleanFlagOn(pkgdte_t->HighWord.Bits.Type, 2 ) ) {//关于标志位及算法,见权威资料。
            Limit = pkgdte_t->LimitLow + (pkgdte_t->HighWord.Bits.LimitHi << 16);
            Limit *= PAGE_SIZE;
            Limit += PAGE_SIZE - 1;
        } else {
            Limit = pkgdte_t->LimitLow + (pkgdte_t->HighWord.Bits.LimitHi << 16);
        }

        //if (pkgdte_t->HighWord.Bits.Default_Big && Base)
        //{
        //    //扩充高位为1.即F.
        //    Base += 0xffff0000;
        //}    

        //if (pkgdte_t->Bits.DefaultBig && pkgdte_t->Bits.Granularity)
        //{
        //    //扩充高位为1.即F.
        //    SIZE_T t = Limit;
        //    Limit = (Limit << 12);
        //    Limit += PAGE_SIZE - 1;
        //}

        Type = pkgdte_t->HighWord.Bits.Type;
        _bittestandreset(&Type, 4);//因为这个包含了S位,所以要清除这个位标志。

        if (pkgdte_t->HighWord.Bits.Default_Big)
        {
            size = "Bg  ";//Big 加空格是为了对齐显示。
        }
        else
        {
            size = "Nb  ";//Not Big 加空格是为了对齐显示。
        }

        if (pkgdte_t->HighWord.Bits.Granularity)
        {
            Granularity = "Pg  ";//Page 加空格是为了对齐显示。
        }
        else
        {
            Granularity = "By  ";//Byte 加空格是为了对齐显示。
        }

        if (pkgdte_t->HighWord.Bits.Pres)
        {
            Present = "P   ";//Present 加空格是为了对齐显示。
        }
        else
        {
            Present = "NP  ";//NO Present 加空格是为了对齐显示。
        }

        if (pkgdte_t->HighWord.Bits.Reserved_0)
        {
            LongMode = "Lo  ";//Long 加空格是为了对齐显示。
        }
        else
        {
            LongMode = "Nl  ";//NO long 加空格是为了对齐显示。
        }
       
        Flags = (pkgdte_t->HighWord.Bytes.Flags2 >> 4);//去掉Segment limit的那几位。
        Flags = Flags << 8;
        Flags = Flags + pkgdte_t->HighWord.Bytes.Flags1;

        KdPrint(("%04x %p %p %13s %03x %s %s %s %s 0x%04x\n",
            index * 8, //sizeof (KGDTENTRY)
            Base,
            Limit,
            SegmentTypes[Type],
            pkgdte_t->HighWord.Bits.Dpl,
            size,
            Granularity,
            Present,          
            LongMode,
            Flags
            ));

        //KdPrint(("第%d号CPU的GDT的Sel:0x%03x, Base:0x%08x, Limit:0x%08x, type:0x%02x, Dpl:0x%x, Pres:0x%x, Sys:0x%x,Default_Big:0x%x, Granularity:0x%x.\n",
        //    i, index * sizeof (KGDTENTRY), Base, Limit,
        //    pkgdte_t->HighWord.Bits.Type,
        //    pkgdte_t->HighWord.Bits.Dpl,
        //    pkgdte_t->HighWord.Bits.Pres,
        //    pkgdte_t->HighWord.Bits.Sys,
        //    pkgdte_t->HighWord.Bits.Default_Big,
        //    pkgdte_t->HighWord.Bits.Granularity
        //    ));

        /*
        这里的Default_Big对应dg命令的size.
        这里的Sys对应dg命令的long.
        Flags的值等于变相打印了,这里就不再打印了。
        */
    }
}
#endif


#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    int i = 0;

    KdBreakPoint();

    DriverObject->DriverUnload = DriverUnload;

    for ( ;i < KeNumberProcessors ;i++ )//KeQueryMaximumProcessorCount()  KeGetCurrentProcessorNumber
    {      
        show_gdt(i);      
    }

    return STATUS_SUCCESS;
}

/*
0: kd> dg 0 256
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0000 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P  Nl 00000c9b
0010 00000000 ffffffff Data RW Ac 0 Bg Pg P  Nl 00000c93
0018 00000000 ffffffff Code RE Ac 3 Bg Pg P  Nl 00000cfb
0020 00000000 ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3
0028 80042000 000020ab TSS32 Busy 0 Nb By P  Nl 0000008b
0030 ffdff000 00001fff Data RW Ac 0 Bg Pg P  Nl 00000c93
0038 00000000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3
0040 00000400 0000ffff Data RW    3 Nb By P  Nl 000000f2
0048 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0050 80552700 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
0058 80552768 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
0060 00022f40 0000ffff Data RW Ac 0 Nb By P  Nl 00000093
0068 000b8000 00003fff Data RW    0 Nb By P  Nl 00000092
0070 ffff7000 000003ff Data RW    0 Nb By P  Nl 00000092
0078 80400000 0000ffff Code RE    0 Nb By P  Nl 0000009a
0080 80400000 0000ffff Data RW    0 Nb By P  Nl 00000092
0088 00000000 00000000 Data RW    0 Nb By P  Nl 00000092
0090 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0098 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00A0 82181238 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
00A8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00B0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00B8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00C0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00C8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00D0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00D8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00E0 f851f000 0000ffff Code RE Ac 0 Nb By P  Nl 0000009f
00E8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092
00F0 804fd040 000003b7 Code EO    0 Nb By P  Nl 00000098
00F8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092
0100 ba4bd400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
0108 ba4bd400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
0110 ba4bd400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
0118 00008003 0000f120 <Reserved> 0 Nb By Np Nl 00000000
0120 00008003 0000f128 <Reserved> 0 Nb By Np Nl 00000000
0128 00008003 0000f130 <Reserved> 0 Nb By Np Nl 00000000
0130 00008003 0000f138 <Reserved> 0 Nb By Np Nl 00000000
0138 00008003 0000f140 <Reserved> 0 Nb By Np Nl 00000000
0140 00008003 0000f148 <Reserved> 0 Nb By Np Nl 00000000
0148 00008003 0000f150 <Reserved> 0 Nb By Np Nl 00000000
0150 00008003 0000f158 <Reserved> 0 Nb By Np Nl 00000000
0158 00008003 0000f160 <Reserved> 0 Nb By Np Nl 00000000
0160 00008003 0000f168 <Reserved> 0 Nb By Np Nl 00000000
0168 00008003 0000f170 <Reserved> 0 Nb By Np Nl 00000000
0170 00008003 0000f178 <Reserved> 0 Nb By Np Nl 00000000
0178 00008003 0000f180 <Reserved> 0 Nb By Np Nl 00000000
0180 00008003 0000f188 <Reserved> 0 Nb By Np Nl 00000000
0188 00008003 0000f190 <Reserved> 0 Nb By Np Nl 00000000
0190 00008003 0000f198 <Reserved> 0 Nb By Np Nl 00000000
0198 00008003 0000f1a0 <Reserved> 0 Nb By Np Nl 00000000
01A0 00008003 0000f1a8 <Reserved> 0 Nb By Np Nl 00000000
01A8 00008003 0000f1b0 <Reserved> 0 Nb By Np Nl 00000000
01B0 00008003 0000f1b8 <Reserved> 0 Nb By Np Nl 00000000
01B8 00008003 0000f1c0 <Reserved> 0 Nb By Np Nl 00000000
01C0 00008003 0000f1c8 <Reserved> 0 Nb By Np Nl 00000000
01C8 00008003 0000f1d0 <Reserved> 0 Nb By Np Nl 00000000
01D0 00008003 0000f1d8 <Reserved> 0 Nb By Np Nl 00000000
01D8 00008003 0000f1e0 <Reserved> 0 Nb By Np Nl 00000000
01E0 00008003 0000f1e8 <Reserved> 0 Nb By Np Nl 00000000
01E8 00008003 0000f1f0 <Reserved> 0 Nb By Np Nl 00000000
01F0 00008003 0000f1f8 <Reserved> 0 Nb By Np Nl 00000000
01F8 00008003 0000f200 <Reserved> 0 Nb By Np Nl 00000000
0200 00008003 0000f208 <Reserved> 0 Nb By Np Nl 00000000
0208 00008003 0000f210 <Reserved> 0 Nb By Np Nl 00000000
0210 00008003 0000f218 <Reserved> 0 Nb By Np Nl 00000000
0218 00008003 0000f220 <Reserved> 0 Nb By Np Nl 00000000
0220 00008003 0000f228 <Reserved> 0 Nb By Np Nl 00000000
0228 00008003 0000f230 <Reserved> 0 Nb By Np Nl 00000000
0230 00008003 0000f238 <Reserved> 0 Nb By Np Nl 00000000
0238 00008003 0000f240 <Reserved> 0 Nb By Np Nl 00000000
0240 00008003 0000f248 <Reserved> 0 Nb By Np Nl 00000000
0248 00008003 0000f250 <Reserved> 0 Nb By Np Nl 00000000
0250 00008003 0000f258 <Reserved> 0 Nb By Np Nl 00000000
0: kd> dg 0 256
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0000 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0008 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P  Lo 0000029b
0018 00000000`00000000 00000000`ffffffff Data RW Ac 0 Bg Pg P  Nl 00000c93
0020 00000000`00000000 00000000`ffffffff Code RE    3 Bg Pg P  Nl 00000cfa
0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3
0030 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P  Lo 000002fb
0038 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0040 00000000`01794080 00000000`00000067 TSS32 Busy 0 Nb By P  Nl 0000008b
0048 00000000`0000ffff 00000000`0000f800 <Reserved> 0 Nb By Np Nl 00000000
0050 ffffffff`fffa0000 00000000`00003c00 Data RW Ac 3 Bg By P  Nl 000004f3
0058 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0060 00000000`00000000 00000000`ffffffff Code RE    0 Bg Pg P  Nl 00000c9a
0068 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0070 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0078 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
0080 Unable to get descriptor

kd> r GDTR
gdtr=fffff80004289000
kd> db fffff80004289000
fffff800`04289000  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fffff800`04289010  00 00 00 00 00 9b 20 00-ff ff 00 00 00 93 cf 00  ...... .........
fffff800`04289020  ff ff 00 00 00 fb cf 00-ff ff 00 00 00 f3 cf 00  ................
fffff800`04289030  00 00 00 00 00 fb 20 00-00 00 00 00 00 00 00 00  ...... .........
fffff800`04289040  67 00 70 a0 28 8b 00 04-00 f8 ff ff 00 00 00 00  g.p.(...........
fffff800`04289050  00 3c 00 00 fe f3 40 ff-00 00 00 00 00 00 00 00  .<....@.........
fffff800`04289060  ff ff 00 00 00 9a cf 00-00 00 00 00 00 00 00 00  ................
fffff800`04289070  40 bf 10 00 00 8e a5 01-00 f8 ff ff 00 00 00 00  @...............
kd> r gdtl
gdtl=006f

kd> dg @cs
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P  Lo 0000029b
kd> r cs
cs=0010
*/


----------------------------------------------------------------------------------------
;.\i386\asm.asm 的内容如下:


.686p
.model flat,StdCall
option casemap:none

.CODE

;摘自:nbp-0.32-public
GetGdtLimit PROC
LOCAL gdtr[10]:BYTE

sgdt gdtr
mov ax, WORD PTR gdtr[0]
ret
GetGdtLimit ENDP

END


----------------------------------------------------------------------------------------
:.\amd64\asm.asm的内容如下:


.CODE

;摘自:nbp-0.32-public
GetGdtLimit PROC
LOCAL gdtr[10]:BYTE

sgdt gdtr
mov ax, WORD PTR gdtr[0]
ret
GetGdtLimit ENDP

END



----------------------------------------------------------------------------------------
#source文件的内容如下:


TARGETNAME=test

TARGETTYPE=DRIVER

SOURCES=test.C

AMD64_SOURCES=.\amd64\asm.asm

I386_SOURCES=.\i386\asm.asm

TARGETPATH=obj



----------------------------------------------------------------------------------------

2015年7月23日星期四

Base64加解密

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

#pragma comment(lib, "Dbghelp.lib")
#pragma comment(lib, "Imagehlp.lib")

#include <Wincrypt.h>
#pragma comment(lib, "Crypt32.lib")

#pragma warning(disable:4995)
#pragma warning(disable:4996)

/*
目的:主要示例Base64的转换。
实现:解密Base64。

系统的接口:
CryptStringToBinary
CryptBinaryToString

微软的编码:
http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crypto/cyphers/base64/base64.c.htm
如果真想找到微软的东西,那就在sdk 6.0 Samples里面搜索Base64吧!

其实系统也有自带的命令的,用法如下:
CertUtil -encode InFile OutFile 将文件编码为 Base64
CertUtil -decode InFile OutFile 解码 Base64 编码的文件

made by corey
made at 2015.05.14
*/


void main()
{
    //DebugBreak();
    //__debugbreak();

    //摘自:http://zh.wikipedia.org/wiki/Base64
    LPCTSTR pszString = L"Man is distinguished, not only by his reason, "
        L"but by this singular passion from other animals, "
        L"which is a lust of the mind, that by a perseverance of delight in "
        L"the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";

    DWORD   cchString = lstrlen(pszString) * sizeof(wchar_t);
    DWORD   dwFlags   = CRYPT_STRING_BASE64;
 
    BOOL B = 0;

    LPTSTR pszString2 = 0;
    DWORD  pcchString = 0;
    B = CryptBinaryToString((BYTE *)pszString, cchString, dwFlags, pszString2, &pcchString);
    if (B == false)
    {
        return;
    }

    pcchString = pcchString * sizeof(wchar_t);
    pszString2 = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pcchString);
    if (pszString2 == NULL)
    {
        printf ("Failed to allocate on heap.\n");
        return;
    }

    //注意单字符和宽字符的编码是不一样的。
    B = CryptBinaryToString((BYTE *)pszString, cchString, dwFlags, pszString2, &pcchString);
    if (B == false)
    {
        HeapFree(GetProcessHeap(), 0, pszString2);
        return;
    }

    HeapFree(GetProcessHeap(), 0, pszString2);
    return;
}


--------------------------------------------------------------------------------------------------------------------------------


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

#pragma comment(lib, "Dbghelp.lib")
#pragma comment(lib, "Imagehlp.lib")

#include <Wincrypt.h>
#pragma comment(lib, "Crypt32.lib")

#pragma warning(disable:4995)
#pragma warning(disable:4996)

/*
目的:主要示例Base64的转换。
实现:解密Base64。

CryptStringToBinary
CryptBinaryToString

made by corey
made at 2015.05.14
*/


void main()
{
    //DebugBreak();
    //__debugbreak();

    //这个必须是相应的编码,如:Base64,否则下面的转换失败。
    //摘自:http://zh.wikipedia.org/wiki/Base64
    //LPCTSTR pszString = L"madebycorrey";
    LPCTSTR pszString = L"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"
        L"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"
        L"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu"
        L"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"
        L"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";

    ////////////////////////////////////////////////////////////////////////////////////////////////////////
    //第一步:把这个编码(Base64)转换为加密的二进制。

    DWORD   cchString = lstrlen(pszString);
    DWORD   dwFlags   = CRYPT_STRING_BASE64;
    BYTE  * pbBinary  = NULL;
    DWORD   pcbBinary = 0;
    DWORD   pdwSkip   = 0;
    DWORD   pdwFlags  = 0;

    BOOL B = CryptStringToBinary(
        pszString,

        //The number of characters of the formatted string to be converted, not including the terminating NULL character.
        //If this parameter is zero, pszString is considered to be a null-terminated string.      
        cchString,

        dwFlags,

        pbBinary,

        _Inout_ &pcbBinary,

        _Out_   & pdwSkip,
        _Out_   & pdwFlags
        );
    if (B == false)
    {
        int x = GetLastError();
        return;
    }

    pcbBinary = pcbBinary * sizeof(wchar_t);
    pbBinary = (BYTE *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pcbBinary);
    if (pbBinary == NULL)
    {
        printf ("Failed to allocate on heap.\n");
        return;
    }

    B = CryptStringToBinary(pszString, cchString, dwFlags, pbBinary, &pcbBinary, &pdwSkip, &pdwFlags);
    if (B == false)
    {
        HeapFree(GetProcessHeap(), 0, pbBinary);
        return;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////
    //第二步:把上一步的内容这个转换为原文。

    LPTSTR pszString2 = 0;
    DWORD  pcchString = 0;
    B = CryptBinaryToString(pbBinary, pcbBinary, dwFlags,
        _Out_opt_       pszString2,
        _Inout_         &pcchString
        );
    if (B == false)
    {
        HeapFree(GetProcessHeap(), 0, pbBinary);
        return;
    }

    pcchString = pcchString * sizeof(wchar_t);
    pszString2 = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pcchString);
    if (pszString2 == NULL)
    {
        HeapFree(GetProcessHeap(), 0, pbBinary);
        printf ("Failed to allocate on heap.\n");
        return;
    }

    B = CryptBinaryToString(pbBinary, pcbBinary, dwFlags,
        _Out_opt_       pszString2,
        _Inout_         &pcchString
        );//这里把空格给去掉了,多个回车换行。如果有-,后面的都截取了。总是多个回车换行。
    if (B == false)
    {
        HeapFree(GetProcessHeap(), 0, pbBinary);
        HeapFree(GetProcessHeap(), 0, pszString2);
        return;
    }

    HeapFree(GetProcessHeap(), 0, pbBinary);
    HeapFree(GetProcessHeap(), 0, pszString2);
    return;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////
}

2015年6月24日星期三

IDA-PRO调试MBR

环境/工具:IDAPRO+VMWARE(windows XP 32环境)。

步骤:
1.VMware的.vmx文件的配置。
  这个就不说了,假定你已经会了。
  例如:
  debugStub.listen.guest32 = "TRUE"
  debugStub.hideBreakpoints= "TRUE"
  还如:
  debugStub.listen.guest32.remote = "TRUE"
  debugStub.listen.guest64.remote = "TRUE"
  monitor.debugOnStartGuest32 = "TRUE"
  debugStub.hideBreakpoints = "TRUE"
  bios.bootDelay = "3000"

  具体的可参观官网的:Debugging Windows kernel under VMWare using IDA's GDB debugger.PDF
  其中就有如下经典的两行:
  debugStub.listen.guest32 = "TRUE"
  debugStub.hideBreakpoints= "TRUE"
2.开启IDA->debugger->attach->remote GDB debugger.
  填写好,名字是loacalhost,端口是8832.
  注意此时填写好之后不要点击OK。因为虚拟机还没有启动。
3.开启VMWARE->电源->打开电源时进入固件。
  之所以这样做是因为好控制,否则时机很难掌握。
  此时虚拟机停止在BIOS里运行。
4.点击第二步出现OK。
  也就是IDA的那个OK按钮。
  弹出个提示框,我没有看,是英文,继续点击OK。
  之后又出现个选择框,选择ID为0的那个,然后点击OK。
  此时有弹出个提示框,提示成功了,点击OK。
  此时弹出了一个界面,此时最好要等待会,可能是在分析。
  其实此时也不用等待,直接点击取消按钮,即进入了调试界面。
5.在调试界面的反汇编窗口的地址上右键,然后选择jump to address,在弹出的界面中输入:MEMORY:00007C00。
  然后点击OK。此时定位到这个指令。
  注意:此时因为还在BIOS里运行,MBR还没有运行,所以这里的内容是空的。
  不过,在这里可以先设置断点。设置断点的做法就不说了。
  设置完毕之后按F9,让她继续运行。
6.切换/进入IDA,也就是在IDA中点击那个绿色的三角箭头。
  此时还在BIOS里运行,所以要继续运行。
  我是点击F10,然后选择保存就运行了。
7.因为刚才设置的IDA断点,此时IDA段下来了。此时VMWARE出现绿色的三角箭头并停止运行。
  此时IDA的MEMORY:00007C00处也有内容了。
  但是此时是32位的汇编。
  此时按下alt + s,然后选16-bit segment。
  此时变成了数据,然后再右键选择代码就可以了。
  此时变成了16位的汇编了。
  从此开始你的系统之旅吧!
  MBR->BPR->直至系统加载成功。


made by correy
made at 9:29 2015/6/3.

2015年5月29日星期五

一种minifilter驱动保护的方案

/*
通常的保护驱动的思路是在驱动入口不设置驱动对象的卸载函数的成员。

minifilter框架也类似。

开始的思路也是这样的,
可是经测试不行,因为通常minifilter不设置驱动对象的卸载函数,而是设置FLT_REGISTRATION的卸载函数。
经分析FltRegisterFilter是把自己的_FLT_REGISTRATION复制/修改到_FLT_FILTER。
最后经分析和原始的想法是一样的。
不罗嗦了,直接见要点.

具体的做法是:
1.FLT_REGISTRATION的Flags包含FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP。
  这是通过逆向分析出的。
  MSDN是这样说的:
  If this flag is set, the minifilter is not unloaded in response to service stop requests, even if the FilterUnloadCallback member is not NULL.
  也就是说,如果这样了即使设置了FilterUnloadCallback成员,FilterUnloadCallback成员也是无效的。
  具体的键反汇编。
  还有一个值是:FLTFL_REGISTRATION_SUPPORT_NPFS_MSFS,这个早就研究了。
2.驱动不能停止咋办?(不同于卸载,禁止卸载可以通过注册表回调来实现,更不是隐藏等别的功能)
  此时驱动还在运行,我们可以和他通讯呀!
  所以可选的思路有:
  1)设置驱动对象的卸载函数为FLT_REGISTRATION的FilterUnloadCallback应该设置的函数。
  2)设置驱动对象的卸载函数为fltmgr!FltpMiniFilterDriverUnload。
  3)设置驱动对象的卸载函数为nt!IopInvalidDeviceRequest。
  经测试:
  方法三是不可行的,这个会蓝屏,蓝屏原因就不说了,你分析吧!
  方法二是不可取的,因为那个函数是未公开的,函数的地址不好获取。
  方法以是可行的,建议的。

made by correy
made at 2015.05.29

下面附下IDA分析的FltRegisterFilter函数:
*/

NTSTATUS __stdcall FltRegisterFilter(PDRIVER_OBJECT Driver, _FLT_REGISTRATION *Registration, _FLT_FILTER **RetFilter)
    /*
    略有改动,改为自己的编码风格。
    里面还有一些数字的含义,请自己修改。
    */
{
    NTSTATUS result; // eax@2
    _FLT_REGISTRATION *P_FLT_REGISTRATION; // esi@3
    int n; // eax@10
    _FLT_OPERATION_REGISTRATION *OperationRegistration; // ecx@10
    _FLT_FILTER *Ret_Filter; // ebx@14
    _FLT_MUTEX_LIST_HEAD *ActiveOpens; // ST28_4@16
    _FLT_MUTEX_LIST_HEAD *PortList; // ST20_4@16
    _FLT_OPERATION_REGISTRATION *i; // eax@19
    char MajorFunction; // cl@20
    int temp; // ST44_4@28
    unsigned int OperationRegistration_length; // [sp+30h] [bp-24h]@14
    _FLT_OPERATION_REGISTRATION *P_FLT_OPERATION_REGISTRATION; // [sp+34h] [bp-20h]@16
    NTSTATUS result_2; // [sp+38h] [bp-1Ch]@17
    BOOL B = FALSE;

    *RetFilter = 0;

    if ( !(g_dword_BIT & 1) )
        return 0xC01C0007;                          // 见ntstatus.h的定义。

    P_FLT_REGISTRATION = Registration;

    if ( (Registration->Version & 0xFF00) != 512 )
        return 0xC000000D;  // 见ntstatus.h的定义。

    result = FltpRestoreFltMgrsPageableState();
    if ( result < 0 )
        return result;

    B = (Registration->GenerateFileNameCallback || !Registration->NormalizeNameComponentCallback) && (Registration->NormalizeNameComponentCallback || !Registration->NormalizeContextCleanupCallback);
    if ( !B )
    {
        return 0xC000000D;  // 见ntstatus.h的定义。
    }

    n = 0;
    OperationRegistration = Registration->OperationRegistration;
    if ( OperationRegistration )
    {
        while ( 1 )
        {
            ++n;
            if ( OperationRegistration->MajorFunction == -128 )
                break;
            ++OperationRegistration;
        }
    }

    OperationRegistration_length = 20 * n;

    Ret_Filter = (_FLT_FILTER *)ExAllocatePoolWithTag(0, 20 * n + Driver->DriverExtension->ServiceKeyName.Length + 288, 0x6C664D46u);
    if ( !Ret_Filter )
    {
        return 0xC000009A;
    }

    memset(Ret_Filter, 0, 0x120u);
    Ret_Filter->FilterUnload = Registration->FilterUnloadCallback;
    Ret_Filter->InstanceSetup = Registration->InstanceSetupCallback;
    Ret_Filter->InstanceQueryTeardown = Registration->InstanceQueryTeardownCallback;
    Ret_Filter->InstanceTeardownStart = Registration->InstanceTeardownStartCallback;
    Ret_Filter->InstanceTeardownComplete = Registration->InstanceTeardownCompleteCallback;
    Ret_Filter->GenerateFileName = Registration->GenerateFileNameCallback;
    Ret_Filter->NormalizeNameComponent = Registration->NormalizeNameComponentCallback;
    Ret_Filter->NormalizeContextCleanup = Registration->NormalizeContextCleanupCallback;
    P_FLT_OPERATION_REGISTRATION = (_FLT_OPERATION_REGISTRATION *)&Ret_Filter[1];
    Ret_Filter->Base.Flags = 0x2000000;
    Ret_Filter->Base.PointerCount = 1;
    FltpExInitializeRundownProtection(&Ret_Filter->Base.RundownRef);
    Ret_Filter->Base.PrimaryLink.Flink = 0;
    FltObjectReference((int)Ret_Filter);
    Ret_Filter->DriverObject = Driver;
    Ret_Filter->InstanceList.rCount = 0;
    ExInitializeResourceLite(&Ret_Filter->InstanceList.rLock);
    InitializeListHead(&Ret_Filter->InstanceList.rList);
    ActiveOpens = &Ret_Filter->ActiveOpens;
    ActiveOpens->mCount = 0;
    ActiveOpens->mLock.Count = 1;
    ActiveOpens->mLock.Owner = 0;
    ActiveOpens->mLock.Contention = 0;
    KeInitializeEvent(&Ret_Filter->ActiveOpens.mLock.Event, SynchronizationEvent, 0);
    InitializeListHead(&Ret_Filter->ActiveOpens.mList);
    PortList = &Ret_Filter->PortList;
    PortList->mCount = 0;
    PortList->mLock.Count = 1;
    PortList->mLock.Owner = 0;
    PortList->mLock.Contention = 0;
    KeInitializeEvent(&Ret_Filter->PortList.mLock.Event, SynchronizationEvent, 0);
    InitializeListHead(&Ret_Filter->PortList.mList);
    Ret_Filter->PortLock.Value = 0;

    if ( !Registration->ContextRegistration || (result_2 = FltpProcessContextRegistration((int)Ret_Filter, &Registration->ContextRegistration->ContextType), result_2 >= 0) )
    {
        if ( Registration->OperationRegistration )//各个操作的前后操作。
        {
            Ret_Filter->Operations = P_FLT_OPERATION_REGISTRATION;
            P_FLT_OPERATION_REGISTRATION = (_FLT_OPERATION_REGISTRATION *)((char *)P_FLT_OPERATION_REGISTRATION + OperationRegistration_length);
            qmemcpy(&Ret_Filter[1], Registration->OperationRegistration, OperationRegistration_length);
            for ( i = Ret_Filter->Operations; ; ++i )
            {
                MajorFunction = i->MajorFunction;
                if ( i->MajorFunction == -128 )
                    break;

                if ( MajorFunction == -19 )
                {
                    Ret_Filter->PreVolumeMount = i->PreOperation;
                    Ret_Filter->PostVolumeMount = i->PostOperation;
                }
                else if ( MajorFunction != -20 && MajorFunction == 16 )//#define IRP_MJ_SHUTDOWN                 0x10.关机是没有后操作的,有了,按思想是笑话。你设置了,这里也会给抹掉。
                {
                    i->PostOperation = 0;
                }
            }

            P_FLT_REGISTRATION = Registration;
        }

        Ret_Filter->Name.Buffer = (unsigned __int16 *)P_FLT_OPERATION_REGISTRATION;
        Ret_Filter->Name.Length = 0;
        Ret_Filter->Name.MaximumLength = Driver->DriverExtension->ServiceKeyName.Length;
        temp = (int)(&P_FLT_OPERATION_REGISTRATION->MajorFunction + Driver->DriverExtension->ServiceKeyName.Length);
        RtlCopyUnicodeString((PUNICODE_STRING)&Ret_Filter->Name, (PCUNICODE_STRING)&Driver->DriverExtension->ServiceKeyName);
        result_2 = FltpInitializeFilterVerifier(Ret_Filter);
        if ( result_2 >= 0 )
        {
            result_2 = FltpGetInstanceAltitude(Ret_Filter, 0, 0, (PUNICODE_STRING)&Ret_Filter->DefaultAltitude);
            if ( result_2 >= 0 )
            {
                result_2 = FltpFindFrameForFilter(Ret_Filter, &Ret_Filter->DefaultAltitude);
                if ( result_2 >= 0 )
                {
                    result_2 = FltpLinkFilterIntoFrame(Ret_Filter);
                    if ( result_2 >= 0 )
                    {
                        Ret_Filter->OldDriverUnload = Driver->DriverUnload;
                        if ( !P_FLT_REGISTRATION->FilterUnloadCallback || P_FLT_REGISTRATION->Flags & 1 )//#define FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP  0x00000001
                        {//If this flag is set, the minifilter is not unloaded in response to service stop requests, even if the FilterUnloadCallback member is not NULL.
                            Driver->DriverUnload = 0;
                            DriverObject->DriverUnload = 0;
                        }
                        else
                        {
                            Driver->DriverUnload = (void (__stdcall *)(_DRIVER_OBJECT *))FltpMiniFilterDriverUnload;
                        }
                        if ( !(g_dword_BIT & 0x20) )
                            g_dword_BIT |= 0x20u;

                        *RetFilter = Ret_Filter;
                    }
                }
            }
        }
    }

    if ( result_2 < 0 )
    {
        ExDeleteResourceLite(&Ret_Filter->InstanceList.rLock);
        FltpCleanupContextRegistration(Ret_Filter);
        FltpCleanupFilterVerifier(Ret_Filter);
        FltpFreeUnicodeString(&Ret_Filter->DefaultAltitude);
        ExFreePoolWithTag(Ret_Filter, 0);
    }

    result = result_2;

    return result;
}


/*
3.注意:
  文件微过滤驱动的卸载函数的原型是:
  typedef NTSTATUS (*PFLT_FILTER_UNLOAD_CALLBACK) ( FLT_FILTER_UNLOAD_FLAGS Flags );
  这个不同于常规驱动的的卸载函数。
  VOID DRIVER_UNLOAD ( _In_ struct _DRIVER_OBJECT *DriverObject );
  区别是返回值和参数。

  这里有一个值:FLTFL_FILTER_UNLOAD_MANDATORY。

  这个函数的说明是:
  Minifilter drivers are not required to register a FilterUnloadCallback routine.
  However, registering an unload routine is strongly recommended.
  If a minifilter driver does not register a FilterUnloadCallback routine, it cannot be unloaded.
  卸载函数不是必须的,但是强烈建议加上,如果没有就不能卸载。

  注意:FLTFL_FILTER_UNLOAD_MANDATORY和STATUS_FLT_DO_NOT_DETACH的关系。
  如果:是FLTFL_FILTER_UNLOAD_MANDATORY必须返回成功,如果返回STATUS_FLT_DO_NOT_DETACH会蓝屏。
        可是用net stop每次都是FLTFL_FILTER_UNLOAD_MANDATORY,sc stop没有试验,但是fltmc unload 却不是。
        所以此思路无效不可行。
*/