NTHANDLE的实现过程和反汇编的C源代码


创建时间:2002-10-18
文章属性:原创
文章提交:flashsky (flashsky1_at_sina.com)

NTHANDLE的实现过程和反汇编的C源代码
作者:FLASHSKY
EMAIL:FLASHSKY@XFOCUS.NET
转载请注名源作者和安全焦点

NTHANDLE是www.sysinternals.com一个可以查看进程打开的内核句柄信息的工具。其实现主要过程是:
首先将两个驱动程序文件当作资源拷贝到自己的程序节内,这两个文件是nthandle.sys和nthandle.vdx,分别用于WINNT(2000)下的驱动和WIN9X下的驱动,程序在运行的时候通过判断操作系统版本来将对应的驱动文件拷贝到相应的系统驱动目录下,然后程序修改驱动服务的注册表项,然后利用未存挡的NtLoadDrive API启动驱动程序,然后建立一个设备连接。
然后程序用大家熟悉的NTQUERYSYSTEMINFORATION获得所有句柄的信息结构数组,然后将句柄复制到自己的进程空间,又利用一个未存档的API NtQueryObject就可以获取对应的类型名字等信息,如果该名字是process和thread,那么就可以使用NtQueryInformationProcess或NtQueryInformationThread查询其信息,检查打开其句柄的进程号是否于原句柄一样,就可以判断这个进程或线程是本来进程中的一个,还是打开的其他进程或线程的句柄。
对于非线程和进程句柄对象,则需要使用刚才提到的拷贝的驱动程序去查询其信息了。
在驱动程序中,首先根据传开的句柄所属的进程ID判断是否小于8(除了0外我不知道哪个进程还比8小),对于这种进程的句柄则使用未存档的PsLookupProcessByProcessId和KeAttachProcess连接以后,使用ObReferenceObjectByHandle获取句柄的引用的地址信息,对于其他的进程则直接使用ZwOpenProcess和ZwDuplicateObject复制句柄,然后使用ObReferenceObjectByHandle获取句柄的引用的地址信息。
对于获得的内核句柄的第一个DWORD,会比较是否等于0x700005,这个属于什么类型的内核对象不太清楚,这种对象的描述信息是由许多链表结构组成的,需要进行链表操作,将多个链表中的描述信息拷贝到一起来形成一个完整的描述,对于非这种类型的对象,则直接按如下方式操作:
利用ObQueryNameString API就可以获取对象具体使用的名字(也就是具体的描述信息了),然后将对应的信息拷贝到输出缓冲来,对于调用失败的处理,则通过MmIsAddressValid检查连接的指针是否有效来判断是否是属于一个链表组成的描述对象,是的话调用链表操作查询的子过程。
以上过程比较有趣的地方是:
1是把驱动当做资源文件,然后运行的时候拷贝,2是程序运行时通过注册表修改和调用NTLOADDRIVER启动驱动程序,这有点象驱动类型病毒的特征。

下面就是具体的C代码,由于没有反汇编vdx的文件,所有只对NT,2000有效,另外在SYS提供了获取令牌信息的接口,而我程序中并没使用,而是直接获取,对0,8号进程是无法正确获取运行用户身份的,如果需要则可以修改此处为调用驱动对应的接口来处理,另外驱动中虽然有对小于8(0)号进程处理的过程,但实际无论是我写的,还是NTHANDLE本身都无法列出0号进程具体打开句柄的更多的信息,具体原因还有待于深入研究。由于是反汇编而来,不免存在一些错误,而且对于驱动的反汇编,由于其是不带调试信息的驱动,无法加载符号表进行动态跟踪和调式,是能一味的看汇编静态代码而来,本身对驱动也不是很熟悉,错误可能更多,调式自己写的驱动的时候,蓝屏N次,不过后来基本还稳定了,但肯定还是有很多错误和BUG,希望大家指正。

//HANDLE。EXE的C代码,需要将SYS编译好以后加入到对应的资源类型,需要修改生成的资源ID号为字符串并于程序中使用的名字一致。
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <Aclapi.h>
#include <stdio.h>
#include <winioctl.h>
#include <winerror.h>

#define NT_HANDLE_LIST        16
typedef struct _PEB {
    BYTE Reserved1[2];
    BYTE BeingDebugged;
    BYTE Reserved2[229];
    PVOID Reserved3[59];
    ULONG SessionId;
} PEB, *PPEB;

typedef struct _HandleInfo
{
    USHORT dwPid;                    
    USHORT CreatorBackTraceIndex;    
    BYTE   ObjType;
    BYTE   HandleAttributes;
    USHORT HndlOffset;
    DWORD  dwKeObject;
    ULONG  GrantedAccess;
}HANDLEINFO, *PHANDLEINFO;

typedef struct _LSA_UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PVOID  Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;

typedef struct _ANSI_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PCHAR Buffer;
}ANSI_STRING,*PANSI_STRING;

typedef struct _MYOBJECTINFO {
    DWORD pid;
    DWORD objaddr;
    DWORD objhandle;
} MYOBJECTINFO, *PMYOBJECTINFO;


typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    UNICODE_STRING *ObjectName;
    ULONG Attributes;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
} OBJECT_ATTRIBUTES,*POBJECT_ATTRIBUTES;

// 申明ntdll中使用的函数
typedef DWORD (CALLBACK* NTQUERYSYSTEMINFORMATION)( DWORD, PDWORD, DWORD, PVOID );
NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
typedef DWORD (CALLBACK* RTLANSISTRINGTOUNICODESTRING)(PVOID, PVOID,DWORD);
RTLANSISTRINGTOUNICODESTRING RtlAnsiStringToUnicodeString;
typedef DWORD (CALLBACK* NTLOADDRIVER)(PVOID);
NTLOADDRIVER NtLoadDriver;
typedef DWORD (CALLBACK* RTLFREEUNICODESTRING)(PVOID);
RTLFREEUNICODESTRING RtlFreeUnicodeString;
typedef DWORD (CALLBACK* RTLNTSTATUSTODOSERROR)(DWORD, PDWORD, DWORD, PVOID );
RTLNTSTATUSTODOSERROR RtlNtStatusToDosError;
typedef DWORD (CALLBACK* NTQUERYINFORMATIONTHREAD)(HANDLE,DWORD,PVOID,DWORD,PDWORD);
NTQUERYINFORMATIONTHREAD NtQueryInformationThread;
typedef DWORD (CALLBACK* NTQUERYINFORMATIONPROCESS)(HANDLE,DWORD,PVOID,DWORD,PDWORD);
NTQUERYINFORMATIONPROCESS NtQueryInformationProcess;
typedef DWORD (CALLBACK* NTQUERYDIRECTORYOBJECT)( DWORD, PDWORD, DWORD, PVOID );
NTQUERYDIRECTORYOBJECT NtQueryDirectoryObject;
typedef DWORD (CALLBACK* NTQUERYSYMBOLICLINKOBJECT)(HANDLE,PUNICODE_STRING,PULONG );
NTQUERYSYMBOLICLINKOBJECT NtQuerySymbolicLinkObject;
typedef DWORD (CALLBACK* NTOPNESYMBOLICLINKOBJECT)(PVOID, DWORD,PVOID);
NTOPNESYMBOLICLINKOBJECT NtOpenSymbolicLinkObject;
typedef DWORD (CALLBACK* NTOPNEDIRECTORYOBJECT)( DWORD, PDWORD, DWORD, PVOID );
NTOPNEDIRECTORYOBJECT NtOpenDirectoryObject;
typedef DWORD (CALLBACK* NTQUERYOBJECT)(HANDLE,DWORD, PVOID, DWORD,PDWORD);
NTQUERYOBJECT NtQueryObject;
typedef DWORD (CALLBACK* RTLFREEANSISTRING)(PVOID);
RTLFREEANSISTRING RtlFreeAnsiString;
typedef DWORD (CALLBACK* RTLUNICODESTRINGTOANSISTRING)(PANSI_STRING, PUNICODE_STRING,DWORD);
RTLUNICODESTRINGTOANSISTRING RtlUnicodeStringToAnsiString;
typedef DWORD (CALLBACK* RTLINITANSISTRING)(PVOID, PVOID);
RTLINITANSISTRING RtlInitAnsiString;
typedef VOID(CALLBACK* INITIALIZEOBJECTATTRIBUTES)(POBJECT_ATTRIBUTES,PUNICODE_STRING,ULONG,HANDLE,PSECURITY_DESCRIPTOR);
INITIALIZEOBJECTATTRIBUTES InitializeObjectAttributes;

HANDLE drv;
char workdir[256];
char sysdir[256];
char drivcedir[256];
HANDLE dh; //存放复制的对象句柄

void ChangePrivilege(HANDLE pmy,char * PrivilegeVal)
{
    int isok;
    TOKEN_PRIVILEGES NewState;
    HANDLE hToken;
    NewState.PrivilegeCount=1;
    NewState.Privileges[0].Attributes=2;
    NewState.Privileges[0].Luid.HighPart=0;
    NewState.Privileges[0].Luid.LowPart=0;
    isok=LookupPrivilegeValue(0,PrivilegeVal,&NewState.Privileges[0].Luid);
    isok=OpenProcessToken(pmy,0x20,&hToken);
    isok=AdjustTokenPrivileges(hToken,0,&NewState,0x10,0,0);
    CloseHandle(hToken);
}

void GetProcessAuth(long pid)
{
//获得运行进程的用户身份,此处对于8以上的进程没问题,对于8,0进程无法列出,可以替换成使用驱动对应的例程,就可以列举0,8进程运行的用户身份
    SID_NAME_USE peUse;
    HANDLE hp;
    HANDLE hToken;
    int isok;
    char buf[0x400];
    char buf1[100];
    char buf2[100];
    DWORD dwNumBytesRet;
    DWORD dwNumBytesRet1;

    hp=OpenProcess(0x400,0,pid);
    isok=OpenProcessToken(hp,0x20008,&hToken);
    isok=GetTokenInformation(hToken,TokenUser,&buf,0x400,&dwNumBytesRet);
    if(isok)
    {
        dwNumBytesRet = 100;
        dwNumBytesRet1 = 100;
        isok = LookupAccountSid(NULL,(DWORD *)(*(DWORD*)buf),buf1,&dwNumBytesRet,buf2,&dwNumBytesRet1,&peUse);
        printf("Run Auth:%s//%s /n",buf2,buf1);
        CloseHandle(hToken);
    }
    CloseHandle(hp);
}

int RegHandelDev(char * exename)
{
    //修改注册表启动NTHANDLE驱动程序
    char subkey[200];
    LSA_UNICODE_STRING buf1;
    LSA_UNICODE_STRING buf2;
    int buflen;
    HKEY hkResult;
    char Data[4];
    DWORD isok;
    buflen = sprintf(subkey,"System//CurrentControlSet//Services//%s",exename);
    subkey[buflen]=0;
    isok = RegCreateKey(HKEY_LOCAL_MACHINE,subkey,&hkResult);
    if(isok!=ERROR_SUCCESS)
        return false;
    Data[0]=1;
    Data[1]=0;
    Data[2]=0;
    Data[3]=0;
    isok=RegSetValueEx(hkResult,"Type",0,4,(const unsigned char *)Data,4);
    isok=RegSetValueEx(hkResult,"ErrorControl",0,4,(const unsigned char *)Data,4);
    isok=RegSetValueEx(hkResult,"Start",0,4,(const unsigned char *)Data,4);
    buflen = sprintf(drivcedir,"%s//Drivers//NTHANDLE.SYS",sysdir);
    buflen = sprintf(subkey,"//??//%s",drivcedir);
    subkey[buflen]=0;
    isok=RegSetValueEx(hkResult,"ImagePath",0,1,(const unsigned char *)subkey,buflen);
    RegCloseKey(hkResult);    
    buflen = sprintf(subkey,"//Registry//Machine//System//CurrentControlSet//Services//%s",exename);
    subkey[buflen]=0;
    buf2.Buffer = (PVOID)subkey;
    buf2.Length = buflen;
    RtlAnsiStringToUnicodeString(&buf1,&buf2,1);
//加载驱动程序
    isok = NtLoadDriver(&buf1);
    RtlFreeUnicodeString(&buf1);
    buflen=sprintf(subkey,"%s%s//Enum","System//CurrentControlSet//Services//",exename);
    subkey[buflen]=0;
//删除注册表项
    RegDeleteKey(HKEY_LOCAL_MACHINE,subkey);
    buflen=sprintf(subkey,"%s%s//Security","System//CurrentControlSet//Services//",exename);
    subkey[buflen]=0;
    RegDeleteKey(HKEY_LOCAL_MACHINE,subkey);
    buflen=sprintf(subkey,"%s%s","System//CurrentControlSet//Services//",exename);
    subkey[buflen]=0;
    RegDeleteKey(HKEY_LOCAL_MACHINE,subkey);
    buflen=sprintf(subkey,".//%s",exename);
    subkey[buflen]=0;
//建立设备连接
    drv = CreateFile(subkey,GENERIC_READ|GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(drv==INVALID_HANDLE_VALUE)
    {
        buflen=sprintf(subkey,".//Global//%s",exename);
        subkey[buflen]=0;
        drv = CreateFile(subkey,GENERIC_READ|GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        if(drv==INVALID_HANDLE_VALUE)
            return false;
    }
    return true;
}

int CopyMyDrivceNt()
{
    //将资源文件拷贝出来成为NTHANDLE。SYS驱动程序
    //源程序还区分是98就拷贝NTHANDLE。VDX。此处没有进行98的处理
    FILE * fp;
    HRSRC ntdrivce;
    long buflen;
    HGLOBAL re;
    DWORD    resize;
    LPVOID  readdr;
    GetSystemDirectory(sysdir,256);
    buflen = sprintf(drivcedir,"%s//Drivers//NTHANDLE.SYS",sysdir);
    //"NTDRV"是加入资源文件时定义的名字,"BINRES"是加入资源文件时定义的资源类名,可以修改,只要与你加入的定义一致就可以
    ntdrivce = FindResource(NULL,"NTDRV","BINRES");
    if(ntdrivce==NULL)
    {
        printf("don't load resource/n");
        return false;
    }
    re = LoadResource(NULL,ntdrivce);
    resize = SizeofResource(NULL,ntdrivce);
    readdr = LockResource(re);
    fp = fopen(drivcedir,"wb");
    if(fp==NULL)
        return false;
    fwrite(readdr,1,resize,fp);
    fclose(fp);
    return true;
}

DWORD callnthandle(DWORD opcode,PVOID inbuf,DWORD inbuflen,PVOID outbuf,DWORD outbuflen)
{
    DWORD returnnum=0;
    DWORD isok;
    isok=DeviceIoControl(drv,opcode,inbuf,inbuflen,outbuf,outbuflen,&returnnum,NULL);
    return isok;
}

int main(int argc,char *argv[])
{
    HMODULE hNtdll = NULL;
    PHANDLEINFO pHandleInfo;
    HANDLE pmy;
    hNtdll = LoadLibrary( "ntdll.dll" );    
    PDWORD pdwHandInfo;    

    DWORD isok;
    DWORD dwNumBytesRet;
    DWORD dwSize;    
    DWORD ver;

    if ( !hNtdll )
    {
        printf( "LoadLibrary( NTDLL.DLL ) Error:%d/n", GetLastError() );
        return false;
    }
    NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)
        GetProcAddress(    hNtdll,    "NtQuerySystemInformation");
    RtlAnsiStringToUnicodeString = (RTLANSISTRINGTOUNICODESTRING)
        GetProcAddress(    hNtdll,    "RtlAnsiStringToUnicodeString");
    RtlFreeUnicodeString = (RTLFREEUNICODESTRING)
        GetProcAddress(    hNtdll,    "RtlFreeUnicodeString");
    NtLoadDriver = (NTLOADDRIVER)
        GetProcAddress(    hNtdll,    "NtLoadDriver");
    NtOpenSymbolicLinkObject = (NTOPNESYMBOLICLINKOBJECT)
        GetProcAddress(    hNtdll,    "NtOpenSymbolicLinkObject");
    InitializeObjectAttributes = (INITIALIZEOBJECTATTRIBUTES)
        GetProcAddress(    hNtdll,    "InitializeObjectAttributes");
    NtQuerySymbolicLinkObject = (NTQUERYSYMBOLICLINKOBJECT)
        GetProcAddress(    hNtdll,    "NtQuerySymbolicLinkObject");
    NtQueryObject = (NTQUERYOBJECT)
        GetProcAddress(    hNtdll,    "NtQueryObject");
    NtQueryInformationThread = (NTQUERYINFORMATIONTHREAD)
        GetProcAddress(    hNtdll,    "NtQueryInformationThread");
    NtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)
        GetProcAddress(    hNtdll,    "NtQueryInformationProcess");
    RtlUnicodeStringToAnsiString = (RTLUNICODESTRINGTOANSISTRING)
            GetProcAddress(    hNtdll,    "RtlUnicodeStringToAnsiString");

    GetCurrentDirectory(256,workdir);
    ver = GetVersion();
    //把资源文件拷贝成驱动程序
    if(ver<0x80000000)
    {
    //NT OR 2000
        if(CopyMyDrivceNt()==false)
            return false;
    }
    //98下应该用nthandle.vdx,但是由于没反汇编,所以直接就返回,因此这个代码只适合NT和2000的
    else
        return false;
    //注册驱动程序
    if(RegHandelDev("NTHANDLE")==false)
        return false;
    pmy = GetCurrentProcess();
    ChangePrivilege(pmy,SE_DEBUG_NAME);
    ChangePrivilege(pmy,SE_LOAD_DRIVER_NAME);

    pdwHandInfo = (PDWORD)malloc(0x2048);
    PVOID handlebuf;
    PVOID paddr1;
    handlebuf = VirtualAlloc(0,0x200000,MEM_RESERVE,PAGE_READWRITE);
    if(handlebuf==NULL)
    {
        printf("VirtualAlloc error/n");
        return false;
    }
    dwSize = 0X4000;
    do
    {
        handlebuf = VirtualAlloc(handlebuf,dwSize,MEM_COMMIT,PAGE_READWRITE);
        //获取所有句柄信息
        isok = (*NtQuerySystemInformation)(0x10,(unsigned long *)handlebuf,dwSize,&dwNumBytesRet);    
        dwSize = dwSize+0x2000;
    }while(isok==0xc0000004);
    if(isok)
    {
        printf("NtQuerySystemInformation error/n");
        return false;
    }

    DWORD dwNumEntries=*(DWORD *)handlebuf;    
    dwNumEntries--;
    DWORD i;
    int j;
    HANDLE oph;
    MYOBJECTINFO mydrvobj;
    DWORD objlen;
    char printfbuf[0x4000];
    char deviobuf[0x800];
    char objbuf[0x1000];
    DWORD retunnum=0;
    PPEB pe;
    char prothrinfo[0x18];
    ZeroMemory(printfbuf,0x4000);
    ZeroMemory(deviobuf,0x800);
    pHandleInfo = ((PHANDLEINFO)((DWORD)handlebuf+4));
    GetProcessAuth(atoi(argv[1]));
    printf("Handle      Type             Desc/n");
    for (i = 1;i <=dwNumEntries; i++)
    {
        paddr1=(PVOID)((DWORD)handlebuf+(i*16));
        mydrvobj.pid=(*(WORD *)((DWORD)paddr1+4));
        mydrvobj.objaddr=*(DWORD *)((DWORD)paddr1+12);                
        mydrvobj.objhandle = (*(WORD *)((DWORD)paddr1+10));
        if(mydrvobj.pid == atoi(argv[1]))
        {
            oph=OpenProcess(PROCESS_DUP_HANDLE,0,mydrvobj.pid);
            isok =DuplicateHandle(oph,(HANDLE)mydrvobj.objhandle,pmy,&dh,NULL,NULL,NULL);
            CloseHandle(oph);
            if(isok)
            {
                //先获取查询对象需要的缓冲大小
                isok=NtQueryObject(dh,2,NULL,NULL,&objlen);            
                //ZeroMemory(objbuf,objlen);
                isok=NtQueryObject(dh,2,objbuf,objlen,NULL);
                DWORD tmp2=*(WORD*)((DWORD)objbuf);
                if(tmp2<0xfffffffe)
                {
                    DWORD tmp3=*(DWORD*)((DWORD)objbuf+4);        
                    //这里就是对象类型的UNICODE名字
                    for(j=1;j<((tmp2>>1)+1);j++)            
                        printfbuf[j-1]=*(char *)(tmp3+2*j-2);
                    printfbuf[j-1]=0;        
                    //比较对象类型的名字是否为process
                    if(_stricmp(printfbuf,"process")==0)
                    {
                        //比较对象类型的名字是否为process,用0X400访问权限复制句柄
                        CloseHandle(dh);
                        oph=OpenProcess(PROCESS_DUP_HANDLE,0,mydrvobj.pid);
                        isok =DuplicateHandle(oph,(HANDLE)mydrvobj.objhandle,pmy,&dh,0x400,NULL,NULL);
                        CloseHandle(oph);                        
                        isok=NtQueryInformationProcess(dh,0,prothrinfo,0x18,&retunnum);                        
                        if(isok==0)
                        {
                            //返回来的是一个结构。其中offset+4是被打开进程的PEB结构地址
                            printf("%08x:%s/n",mydrvobj.objhandle,printfbuf);
                            printf("     PebBaseAddress:%8x/n",*(DWORD *)(prothrinfo+4));
                            //显示PEB中的两个组员
                            pe = (PPEB)(*(DWORD *)(prothrinfo+4));
                            printf("            BeingDebugged:%02x/n",pe->BeingDebugged);
                            printf("            SessionId:%08x/n",pe->SessionId);
                            //打开的进程的ID号,如果不等于自己,说明打开了另一个进程的句柄
                            if(*(DWORD *)(prothrinfo+0x10)!=atoi(argv[1]))
                                printf("     Open Other Process is:%8d/n",*(DWORD *)(prothrinfo+0x10));
                            isok=CloseHandle(dh);
                        }
                        else
                            printf("%08x:error oprn process/n",mydrvobj.objhandle);
                    }
                    else if(_stricmp(printfbuf,"thread")==0)
                    {                                            
                        //比较对象类型的名字是否为thread,用0X40访问权限复制句柄
                        //isok=NtQueryInformationThread(dh,0,&b4[0],0x1c,&retunnum);
                        CloseHandle(dh);
                        oph=OpenProcess(PROCESS_DUP_HANDLE,0,mydrvobj.pid);
                        isok =DuplicateHandle(oph,(HANDLE)mydrvobj.objhandle,pmy,&dh,0x40,NULL,NULL);
                        CloseHandle(oph);                                
                        isok=NtQueryInformationThread(dh,0,prothrinfo,0x1c,&retunnum);
                        if(isok==0)
                        {
                            printf("%08x:%s/n",mydrvobj.objhandle,printfbuf);
                            printf("     TebBaseAddress:%8x/n",*(DWORD *)(prothrinfo+4));
                            //打开的进程的ID号和线城,如果不等于自己,说明打开了另一个进程的句柄
                            if(*(DWORD *)(prothrinfo+0x8)==atoi(argv[1]))
                                printf("     UniqueThreadId:%08d/n",*(DWORD *)(prothrinfo+12));                        
                            else
                                printf("     Open Process:%08d's Thread:%08d/n",*(DWORD *)(prothrinfo+8),*(DWORD *)(prothrinfo+12));                        
                            isok=CloseHandle(dh);
                        }
                        else
                            printf("%08x:error oprn process/n",mydrvobj.objhandle);
                    }
                    else
                    {
                        //通过NTHANDLE.SYS驱动设备进行进一步处理
                        deviobuf[0]=0;
                        isok = callnthandle(0x83350000,&mydrvobj,0xc,deviobuf,0x800);
                        printf("%08x:%s",mydrvobj.objhandle,printfbuf);
                        if(isok)
                            printf(",   %s/n",deviobuf);
                        else
                            printf("/n");
                        isok=CloseHandle(dh);
                    }                    
                }
            }
        }
    }    
    pHandleInfo = ((PHANDLEINFO)((DWORD)handlebuf+4)+1+i);
    VirtualFree(handlebuf,0,MEM_DECOMMIT| MEM_RELEASE);
    //VirtualFree(processbuf,0,MEM_DECOMMIT| MEM_RELEASE);
    free(pdwHandInfo);
    CloseHandle(drv);
    return true;
}

//NTHANDLE.SYS驱动的代码,需要DDK环境进行编译
//驱动程序头文件
#include "ntddk.h"
#ifndef __NTHANDLE_H
#define __NTHANDLE_H

#define NT_DEVICE_NAME L"//Device//NtHandle"
#define DOS_DEVICE_NAME L"//DosDevices//NtHandle"

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    );
    
NTSTATUS
HandleQuert(
    IN PVOID inbuf,
    IN OUT PVOID outbuf
    );

unsigned long
gethandleinfo(
    PFILE_OBJECT p1,
    unsigned long p2,
    PVOID p3,
    unsigned long * p4,
    PVOID p5,
    unsigned long * p6,
    unsigned long p7,
    PIO_STATUS_BLOCK p8,
    PDEVICE_OBJECT p9);

unsigned long
getinfo(
    PVOID p1,
    PVOID p2,
    unsigned long p3);

unsigned long
callmap(
    PVOID Object,
    PVOID p2,
    unsigned long p3);
#endif

//驱动程序C代码文件
#include "ntddk.h"
#include "nthandle.h"

//申明未存档的API函数
NTSYSAPI unsigned long NTAPI ZwOpenProcessToken(HANDLE,unsigned long,PHANDLE);
NTSYSAPI VOID NTAPI PsLookupProcessByProcessId(unsigned long,PHANDLE);
NTSYSAPI VOID NTAPI KeAttachProcess(HANDLE);
NTSYSAPI VOID NTAPI KeDetachProcess();
NTSYSAPI unsigned long NTAPI ZwOpenProcess(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PCLIENT_ID);
NTSYSAPI VOID NTAPI ZwDuplicateObject(HANDLE,HANDLE,HANDLE,PHANDLE,unsigned long,unsigned long,unsigned long);
NTSYSAPI unsigned long ObQueryNameString(PVOID,PUNICODE_STRING,unsigned long,unsigned long *);

typedef struct _MYOBJECTINFO {
    unsigned long pid;
    unsigned long objaddr;
    unsigned long objhandle;
} MYOBJECTINFO, *PMYOBJECTINFO;


//驱动程序主入口点
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS                        status = STATUS_SUCCESS;
    UNICODE_STRING                  ntDeviceName;
    UNICODE_STRING                  win32DeviceName;
    BOOLEAN                         fSymbolicLink = FALSE;
    PDEVICE_OBJECT                  deviceObject;
    
//创建设备和符号连接,申明使用的IOCONTROL代码点为0x8335xxxx
    RtlInitUnicodeString(&ntDeviceName, NT_DEVICE_NAME);
    status = IoCreateDevice (DriverObject,0,&ntDeviceName,0x8335,0,TRUE,&deviceObject);    
    if (!NT_SUCCESS (status)) {
        goto ERROR;
    }

    RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);
    status = IoCreateSymbolicLink( &win32DeviceName, &ntDeviceName );
    if (!NT_SUCCESS(status))    // If we couldn't create the link then
    {                           //  abort installation.
        goto ERROR;
    }

//驱动程序例程分派
    DriverObject->MajorFunction[IRP_MJ_CREATE] = HandleQuert;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = HandleQuert;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = HandleQuert;          
    return(STATUS_SUCCESS);
ERROR:
    if(deviceObject)
        IoDeleteDevice(deviceObject);
    //DbgPrint( "Leave DriverEntry failed/n" );
    return status;
}

//设备创建,关闭和IO操作的例程入口点
NTSTATUS
HandleQuert(
    PDEVICE_OBJECT        aa1,    // Our device object
    PIRP                aa2)
{
    NTSTATUS RC;
    unsigned long ret;
    //DbgPrint( "Entry HandleQuery, IRP : DO %x:%x/n", aa2,aa1 );
    RC = STATUS_SUCCESS;
    aa2->RequestorMode = 0;
    //比较是否是DEVICEIOCONTROL操作还是CREATE和CLOSE操作,后两个直接返回成功
    if(aa2->Tail.Overlay.CurrentStackLocation->MajorFunction==0xe)
    {    
        ret = gethandleinfo(
            aa2->Tail.Overlay.CurrentStackLocation->FileObject,
            1,
            aa2->AssociatedIrp.SystemBuffer, //使用的输入缓冲
            &(aa2->Tail.Overlay.CurrentStackLocation->Parameters.DeviceIoControl.InputBufferLength),
            aa2->AssociatedIrp.SystemBuffer, //使用的输出缓冲
            &(aa2->Tail.Overlay.CurrentStackLocation->Parameters.DeviceIoControl.OutputBufferLength),
            aa2->Tail.Overlay.CurrentStackLocation->Parameters.DeviceIoControl.IoControlCode,
            &(aa2->IoStatus),
            aa1);
        if(ret>0)
            RC=STATUS_INVALID_DEVICE_REQUEST;
        aa2->IoStatus.Status = ret;
    }
    //操作完成,返回IO完成例程,将systembuf中的内容拷贝到用户缓冲区中
    IofCompleteRequest(aa2,IO_NO_INCREMENT);
    //DbgPrint( "Leave HandleQuery/n" );
    return(RC);
}

//具体处理的例程
unsigned long gethandleinfo(PFILE_OBJECT p1,unsigned long p2,PVOID p3,unsigned long * p4,PVOID p5,unsigned long * p6,unsigned long p7,PIO_STATUS_BLOCK p8,PDEVICE_OBJECT p9)
{
    //p3就是DEVICEIOCONTROL传入的输入BUFFER
    unsigned long ret;    
    p8->Status = 0;
    p8->Information = 0;
    if(p7==0x83350000)
    {
//83350000就是我们查句柄信息的操作请求
        //p6就是输出长度字段的地址
        p8->Information = *p6;
        ret = getinfo(p3,p5,(unsigned long)(&(p8->Information)));        
        p8->Status = ret;
        return p8->Status;
    }
    else if(p7==0x83350008)
    {
        if(*(unsigned long *)p3==0xc8)
        {
            *(unsigned long *)p3=0xc8;
            p8->Information=0x4;
            return p8->Status;
        }
        else
        {
            p8->Status=0xC0000059;
            return p8->Status;
        }
    }
    else if(p7==0x8335000c)
    {        
//8335000c可以用来实现对0,8进程查找运行用户 身份的请求,直接返回内核模式下打开的句柄令牌的信息,避免用户模式下打开失败
        p8->Status = ZwOpenProcessToken(*(HANDLE *)p3,8,(PHANDLE)p5);
        p8->Information = 4;
    }
    else
    {
        return p8->Status;
    }    
    return 0;
}

unsigned long getinfo(PVOID p1,PVOID p2,unsigned long p3)
{    
//具体的查询句柄信息的程序
    HANDLE oph;
    HANDLE dh;
    CLIENT_ID a2;
    OBJECT_ATTRIBUTES a1;
    long ret;
    unsigned long pid;
    unsigned long handaddr;
    unsigned long handleid;

    PVOID Object;
    PVOID o2;
    unsigned long a4;
    unsigned long a5;    
    ANSI_STRING aObjName;
    a4 = 0;
    try
    {
    try{
        *(unsigned long *)p3=0;
        pid = ((PMYOBJECTINFO)p1)->pid;
        handleid = ((PMYOBJECTINFO)p1)->objhandle;
        handaddr = ((PMYOBJECTINFO)p1)->objaddr;        
        if(pid<8)
        {
            //处理小于8的系统进程
            PsLookupProcessByProcessId(pid,&oph);
            if(oph>=0)
            {
                KeAttachProcess(oph);
                ret = ObReferenceObjectByHandle((HANDLE)handleid,0x80000000,0,0,&Object,0);
                ZwClose(oph);
                if(ret<0 || ret>0x80000000)
                {                    
                    KeDetachProcess();                    
                    return 0x0C0000022;
                }
                if(*(unsigned long *)Object!=handaddr)
                {
                    ObfDereferenceObject(Object);
                    KeDetachProcess();                    
                    return 0x0C0000022;
                }
                KeDetachProcess();
            }
            else
                return 0xC0000022;
        }
        else
        {
            //大于等于8的进程在此处理
            a2.UniqueProcess = (HANDLE)pid;
            a2.UniqueThread = 0;
            a1.Length = 0x18;
            a1.RootDirectory = 0;
            a1.Attributes = 0;
            a1.ObjectName = 0;
            a1.SecurityDescriptor = 0;
            a1.SecurityQualityOfService = 0;
            ret = ZwOpenProcess(&oph,0x40,&a1,&a2);
            if(ret<0 || ret > 0x80000000)
                return 0xc0000022;
            else
            {
                ZwDuplicateObject(oph,(HANDLE)handleid,(HANDLE)0xFFFFFFFF,&dh,0,0,2);
                ZwClose(oph);
                if(dh!=0)
                {
                    ret = ObReferenceObjectByHandle(dh,0x80000000,0,0,&Object,0);
                    ZwClose(dh);
                    if(ret<0 || ret>0x80000000)
                        return 0xc0000022;
                    if((unsigned long)Object!=handaddr)
                    {
                        ObfDereferenceObject(Object);
                        return 0xc0000022;
                    }        
                }
                else
                    return 0xc0000022;
            }
        }    

        
        a4=0x800;
        ((PUNICODE_STRING)p2)->Length = 0;
        //OK,都执行到这点上,判断内核对象的地址上第一个4字节的内容,如果是0x700005,说明其组成是由一个链表组成的,需要调用链表处理的过程来处理
        if((unsigned long)Object==0x700005)
        {
            ret = callmap(Object,p2,p3);
            if(ret==0)
            {
                ObfDereferenceObject(Object);
                return 0;
            }
            else
            {
                ObfDereferenceObject(Object);
                return 0xFFFFFFFF;
            }
        }
        else
        {
            ret=ObQueryNameString(Object,(PUNICODE_STRING)p2,a4,&a5);
            if(ret>=0 && ((PUNICODE_STRING)p2)->Length>0)
            {                
                //DbgPrint(L"%S/n",ObjName.Buffer);                
                if(RtlUnicodeStringToAnsiString(&aObjName,(PUNICODE_STRING)p2,1)==0)
                {
                    *(unsigned long *)p2 = 0;
                    strncpy(p2,aObjName.Buffer,aObjName.Length);
                    ((char *)(p2))[aObjName.Length]=0;
                    *(unsigned long*)p3=aObjName.Length+1;
                    RtlFreeAnsiString(&aObjName);                                        
                }
                else
                {
                    ObfDereferenceObject(Object);
                    return 0xFFFFFFFF;
                }
            }
            else
            {
//如果ObQueryNameString失败,检查内核对象内容的组成是否是一个有效的连表组成形式
                o2 = (PVOID)((unsigned long)Object+0x14);
                if(MmIsAddressValid(o2))
                {
                    if(MmIsAddressValid(*(PVOID *)(o2)))
                    {
                        o2 = (PVOID)(*(unsigned long *)(o2)+0x18);
                        if(MmIsAddressValid(o2))
                        {
                            if(MmIsAddressValid(*(PVOID *)(o2)))
                            {
                                o2 = (PVOID)(*(unsigned long *)(o2)+0x24);
                                if(MmIsAddressValid(o2))
                                {
                                    if(MmIsAddressValid(*(PVOID *)(o2)))
                                    {
                                        o2 =*(PVOID *)(o2);
                                        if(*(USHORT *)o2==0x7005)
                                        {
                                            //然后判断是否是0x700005,调用连表处理的过程函数
                                            ret = callmap(o2,p2,p3);
                                            if(ret==0)
                                            {
                                                ObfDereferenceObject(Object);                
                                                return 0;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                ObfDereferenceObject(Object);
                return 0xFFFFFFFF;
            }            
        }    
        ObfDereferenceObject(Object);
    }
    except(EXCEPTION_EXECUTE_HANDLER){
        return 0xc0000005;
    }    
    }finally
    {
    }
    return 0;
}

unsigned long callmap(PVOID Object,PVOID p2,unsigned long p3)
{
//连表处理的函数
    unsigned long o1;
    PVOID o2;
    unsigned long o3;
    PVOID o4;
    USHORT o5;
    ANSI_STRING aObjName;
    unsigned long a4;
    unsigned long a5;
    long ret;

    try{
        *(unsigned long *)p3=0;
        a4 = 0x800;
        o2=*(PVOID *)((unsigned long)Object+4);
        if((unsigned long)o2!=0)
        {                
            o1=(unsigned long)p2;
            ret=ObQueryNameString(o2,(PUNICODE_STRING)p2,a4,&a5);
            if(ret>=0 && ((PUNICODE_STRING)p2)->Length>0)
            {
                RtlUnicodeStringToAnsiString(&aObjName,(PUNICODE_STRING)p2,1);
                *(unsigned long *)p2 = 0;
                strncpy((char *)p2,aObjName.Buffer,aObjName.Length+1);
                ((char *)(p2))[aObjName.Length]=0;
                o1=(unsigned long)p2+aObjName.Length;
                *(unsigned long *)p2=(unsigned long)o1;
                RtlFreeAnsiString(&aObjName);
            }
        }
        else
            o1=(unsigned long)p2;
        a5 = *(USHORT *)((unsigned long)Object+0x30);
        a5 = a5>>1;
        o3 = *(unsigned long *)((unsigned long)Object+0x20);
        if(a5!=0 || o3!=0)
        {
            //获得总的长度
            o4 = *(PVOID *)((unsigned long)Object+0x34);
            if(*(char *)o4!='//')
            {
                do{
                    if(o3==0)
                        break;
                    a5 = a5+1+((*(USHORT *)(o3+0x30))>>1);
                    o3 = *(unsigned long *)(o3+0x20);
                }while(1);
            }
        }
        o1=o1+a5-((*(USHORT *)((unsigned long)Object+0x30))>>1);
        RtlUnicodeStringToAnsiString(&aObjName,(PUNICODE_STRING)((unsigned long)Object+0x30),1);
        strncpy((char *)(o1),aObjName.Buffer,aObjName.Length+1);
        RtlFreeAnsiString(&aObjName);
        o3 = *(unsigned long *)((unsigned long)Object+0x20);
        o4 = *(PVOID *)((unsigned long)Object+0x34);
        if(*(char *)o4!='//')
        {
            //依次拷贝各个链表上的内容到输出缓冲区
            do{
                if(o3==0)
                    break;
                *(char *)(o1-1)='//';
                o5 = (*(USHORT *)(o3+0x30))>>1;
                o1 = o1-o5-1;
                RtlUnicodeStringToAnsiString(&aObjName,(PUNICODE_STRING)((unsigned long)o3+0x30),1);
                strncpy((char *)o1,aObjName.Buffer,aObjName.Length);
                RtlFreeAnsiString(&aObjName);
                o3 = *(unsigned long *)(o3+0x20);
            }while(1);
        }
        if(a5>3)
        {
            if(((char *)p2)[2]=='//')
                if(((char *)p2)[3]=='//')
                    memcpy((PVOID)((unsigned long)p2+2),(PVOID)((unsigned long)p2+3),a5-3);                    
        }
        *(unsigned long *)p3=a5;        
    }except(EXCEPTION_EXECUTE_HANDLER){
        return 0xc0000005;
    }    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值