分类

  • 软件天地

  • 基于fport软件谈进程与端口的映射‖
    fport是如何工作的.fport.
    放的端口都是由那些进程打
    的fport有出入,请检查fpor
    文章已经有很多了,我把我对fpo
    exe是由foundstone team出品的
    开的.而下面所描述的方法是基
    t版本.
    rt的分析也写出来,让大家知道
    免费软件,可以列出系统中所有开
    于fport v1.33的,如果和你机器上


      首先,它检测当前用户
    具有管理权限,请参考相关
    接着,用ZwOpenSection函数
    内存的访问.ZwOpenSection
    是否拥有管理员权限(通过读取
    历程),如果没有,打印一句提示
    打开内核对象DevicePhysical
    函数的原型如下:
    当前进程的令牌可知当前用户是否
    后退出,然后设置当前进程的令牌,
    Memory,这个对象用于对系统物理


      NTSYSAPI                                                              
      NTSTSTUS                                                              
      NTAPI                                                                    
      ZwOpenSection(                                                  
        Out PHANDLE sectionHandle;                      
        IN ACCESS_MASK DesiredAccess;                

        IN POBJECT_ATTRI
    BUTES ObjectAttributes
        };                                                                      
      (见ntddk.h)                                                          

      第一个参数得到函数执行成功后的句柄                                            
      第二个参数DesiredAccess为一个常数,可以是下列值:                
        #define SECTION_QUERY    0x0001            
        #define SECTION_MAP_WRITE  0x0002        
        #define SECTION_MAP_READ  0x0004          
        #define SECTION_MAP_EXECUTE 0x0008      
        #define SECTION_EXTEND_SIZE 0x0010      

        #define SECTION_ALL_ACCESS (
               SECTION_MAP_WR
    SECTION_MAP_READ |         
                 SECTION_EX
    STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|   
    ITE |                 
             SECTION_MAP_EXECUTE |   
    TEND_SIZE)
        (见ntddk.h)                                                      
      第三个参数是一个结构,包含要打开的对象类型等信息,结构定义如下:              
        typedef struct _OBJECT_ATTRIBUTES {    
          ULONG Length;                                            
          HANDLE RootDirectory;                            
          PUNICODE_STRING ObjectName;                
          ULONG Attributes;                                    
          PVOID SecurityDescriptor
    ;   ?/ Points to type SECURITY_DESCRIPTOR
          PVOID Securi
    ITY_QUALITY_OF_SERVICE
    tyQualityOfService; // Poin

    ts to type SECUR

        } OBJECT_ATTRIBUTES;                                  
        typedef OBJECT_ATTRIBUTES *P
    OBJECT_ATTRIBUTES;
        (见ntdef.h)                                                      
      对于这个结构的初始化用一个宏完成:                                            
        #define InitializeObjectAttributes( p, n, a, r, s ) {     (p)->Length = sizeof( OBJECT_ATTRIBUTES );         (p)->RootDirectory = r;                   (p)->Attributes = a;                   ?p)->ObjectName = n;                    (p)->SecurityDescriptor = s;                (p)->SecurityQualityOfService = NULL;            }

        (见ntdef.h)                                                      
      那么,打开内核对象DevicePhysicalMemory的语句如下:    
      WCHAR  PhysmemName
    [] =    L"\Device\Phys
    icalMemory";
      void * pMapPhysicalMemory;                          
      HANDLE pHandle;                                                

      bool  OpenPhysicalMemory()                          
      {                                                                            
        NTSTATUS  status;                                        
        UNICODE_STRING  physmemString;              
        OBJECT_ATTRIBUTES attributes;                
        RtlInitUnicodeSt
    ,函数原型见ntddk.h  
    ring( &physmemString, Physme

    mName ); //初始化Unicode字符串

        InitializeObject
    Attributes( &attributes, &ph
    ysmemString,
                 OBJ_CASE_IN
    OBJECT_ATTRIBUTES结构
    SENSITIVE, NULL, NULL ); //初始化

        status = ZwOpenSection(pHand
    核对象DevicePhysicalMemory,获得句
    le, SECTION_MAP_READ, &attributes ); //打开内

        if( !NT_SUCCESS( status ))                     
          return false;                                            
        pMapPhysicalMemo
    ry=MapViewOfFile(pHandle,FIL
    E_MAP_READ,
                    0,0x30000,0x1000);              
        //从内存地址0x30000开始映射0x1000个字节                    
        if( GetLastError()!=0)                             
          return false;                                 
        return true;                                                  
      }                                                                            

      为什么要从0x30000开
    模式和用户模式,也就是我
    进程都运行在Ring3下,一般
    地址为0x30000,或者说,系
    1024项组成,每项均指向一
    4K,1024*4=4096(0x1000),
    见WebCrazy的文章《小议Wi
    始映射呢,是这样,我们知道,在W
    们所说的Ring0和Ring3,在Windo
    情况下,系统进程(也就是System
    统中最小的页目录所在的物理地
    页表(PTE),每一页表也由1024个
    所以,上面从物理地址0x30000开
    ndows NT/2000的分页机制》)
    indows NT/2000下,系统分为内核
    ws NT/2000下,我们所能够看到的
    进程)的页目录(PDE)所在物理地址
    址为0x30000.而页目录(PDE)由
    页组成,而每页的大小为
    始映射了0x1000个字节.(具体描述


      程序打开打开内核对象DevicePhys
    DeviceTcp和DeviceUdp,ZwOpenFile函
    icalMemory后,继续用函数ZwOpenFile打开内核对象
    数的原型如下:
      NTSYSAPI                                                              
      NTSTATUS                                                              
      NTAPI                                                                    
      ZwOpenFile(                                                        
        OUT PHANDLE FileHandle,                            
        IN ACCESS_MASK DesiredAccess,                

        IN POBJECT_ATTRI
    BUTES ObjectAttributes,
        OUT PIO_STATUS_BLOCK IoStatusBlock,    
        IN ULONG ShareAccess,                                
        IN ULONG OpenOptions                                  
        );                                                                      
      (见ntddk.h)                                                          

      第一个参数返回打开对象的句柄                                                  
      第二个参数DesiredAccess为一个常数,可以是下列值:                
        #define FILE_REA
    D_DATA      ( 0x0001 )
      // file & pipe
        #define FILE_LIST_DIRECTORY
        ( 0x0001 )  // directory
        #define FILE_WRI
    TE_DATA      ( 0x0002 )
      // file & pipe
        #define FILE_ADD_FILE   
        ( 0x0002 )  // directory
        #define FILE_APP
    END_DATA     ( 0x0004 )
      // file
        #define FILE_ADD
    _SUBDIRECTORY   ( 0x0004 )
      // directory
        #define FILE_CREATE_PIPE_INS
    TANCE ( 0x0004 )  // named pipe
        #define FILE_REA
    D_EA       ( 0x0008 )
      // file & directory
        #define FILE_WRITE_EA   
        ( 0x0010 )  // file & directory
        #define FILE_EXECUTE    
       ( 0x0020 )  // file
        #define FILE_TRA
    VERSE       ( 0x0020 )
      // directory
        #define FILE_DEL
    ETE_CHILD     ( 0x0040 )
      // directory
        #define FILE_READ_ATTRIBUTES
       ( 0x0080 )  // all
        #define FILE_WRITE_ATTRIBUTE
    S   ( 0x0100 )  // all
        #define FILE_ALL
    _ACCESS (STANDARD_RIGHTS_REQ
    UIRED | SYNCHRONIZE | 0x1FF)
        #define FILE_GEN
                
          FILE_READ_ATT
    FILE_READ_EA      
    ERIC_READ     (STANDARD_
      FILE_READ_DATA     
    RIBUTES   |       
    |             
    RIGHTS_READ   |      
    |              
                
           SYNCHRONIZE)
        #define FILE_GEN
                
          FILE_WRITE_AT
    FILE_WRITE_EA     
    ILE_APPEND_DATA    
    ERIC_WRITE    (STANDARD_
      FILE_WRITE_DATA     
    TRIBUTES  |       
     |            
    |             
    RIGHTS_WRITE  |      
    |              
                
            F
           SYNCHRONIZE)
        #define FILE_GEN
                
          FILE_EXECUTE
    SYNCHRONIZE)
    ERIC_EXECUTE   (STANDARD_
      FILE_READ_ATTRIBUTES  
           |       

    RIGHTS_EXECUTE |      
    |              
                

          (见ntdef.h)                                                  
      第三个参数是一个结构,包含要打开的对象类型等信息,结构定义见上面所述          
      第四个参数返回打开对象的属性,是一个结构,定义如下:                          
        typedef struct _IO_STATUS_BLOCK {        
          union {                                                        
            NTSTATUS Status;                                  
            PVOID Pointer;                                      
          };                                                                  

          ULONG_PTR Information;                          
        } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

        #if defined(_WIN64)                                    
        typedef struct _IO_STATUS_BLOCK32 {    
          NTSTATUS Status;                                      
          ULONG Information;                                  

        } IO_STATUS_BLOC
    K32, *PIO_STATUS_BLOCK32;
        #endif                                                              
        (见ntddk.h)                                                      
      第五个参数ShareAccess是一个常数,可以是下列值:                    
        #define FILE_SHARE_READ  
           0x00000001 // winnt
        #define FILE_SHA
    RE_WRITE        0x00
    000002 // winnt
        #define FILE_SHA
    RE_DELETE        0x00
    000004 // winnt
        (见ntddk.h)                                                      
      第六个参数OpenOptions也是一个常数,可以是下列的值:                
        #define FILE_DIRECTORY_FILE
               0x00000001
        #define FILE_WRI
    TE_THROUGH         
      0x00000002
        #define FILE_SEQUENTIAL_ONLY
              0x00000004
        #define FILE_NO_
    INTERMEDIATE_BUFFERING   
      0x00000008
        #define FILE_SYN
    CHRONOUS_IO_ALERT     
       0x00000010
        #define FILE_SYNCHRONOUS_IO_
    NONALERT      0x00000020
        #define FILE_NON
    _DIRECTORY_FILE      
       0x00000040
        #define FILE_CREATE_TREE_CON
    NECTION       0x00000080
        #define FILE_COMPLETE_IF_OPL
    OCKED        0x00000100
        #define FILE_NO_
    EA_KNOWLEDGE        
      0x00000200
        #define FILE_OPEN_FOR_RECOVE
    RY         0x00000400
        #define FILE_RANDOM_ACCESS 
              0x00000800
        #define FILE_DELETE_ON_CLOSE
              0x00001000
        #define FILE_OPEN_BY_FILE_ID
              0x00002000
        #define FILE_OPEN_FOR_BACKUP
    _INTENT       0x00004000
        #define FILE_NO_
    COMPRESSION        
       0x00008000
        #define FILE_RES
    ERVE_OPFILTER       
       0x00100000
        #define FILE_OPEN_REPARSE_PO
    INT         0x00200000
        #define FILE_OPEN_NO_RECALL
               0x00400000
        #define FILE_OPEN_FOR_FREE_S
    PACE_QUERY     0x00800000
        #define FILE_COPY_STRUCTURED
    _STORAGE      0x00000041
        #define FILE_STR
    UCTURED_STORAGE      
       0x00000441
        #define FILE_VALID_OPTION_FL
    AGS         0x00ffffff
        #define FILE_VALID_PIPE_OPTI
    ON_FLAGS      0x00000032
        #define FILE_VAL
    ID_MAILSLOT_OPTION_FLAGS  
      0x00000032
        #define FILE_VALID_SET_FLAGS
              0x00000036
        (见ntddk.h)                                                      
                                                                                
      那么,打开内核对象De
    viceTcp和DeviceUdp的语句
    如下:  
      WCHAR physmemNameTcp[]=L"\Devic
    e\TCP";
      WCHAR physmemNameUdp[]=L"\Devic
    e\UDP";
      HANDLE pTcpHandle;                                          
      HANDLE pUdpHandle;                                          


      HANDLE OpenDeviceTcp
    Udp(WCHAR * deviceName)
      {                                                                            
        NTSTATUS  status;                                        
        UNICODE_STRING  physmemString;              
        OBJECT_ATTRIBUTES attributes;                
        IO_STATUS_BLOCK iosb;                                
        HANDLE pDeviceHandle;                                

        RtlInitUnicodeString(&physme
    mString, deviceName);  
        if(GetLastError()!=0)                                
          return NULL;                                              
        InitializeObjectAttributes(
    &attributes,&physmemString,
                
        OBJ_CASE_INSENSITIVE
    ,0, NULL );
        status = ZwOpenFile ( &pDevi
    ceHandle,0x100000, &attributes, &iosb, 3,0);
        if( !NT_SUCCESS( status ))                     
          return NULL;                                              
      }                                                                            

        接着,程序用ZwQue
    及其相关畔?函数的原型
    rySystemInformation函数获得
    如下:
    系统当前所以进程的所建立的句柄

      NTSYSAPI                                                              
      NTSTATUS                                                              
      NTAPI                                                                    
      ZwQuerySystemInformation(                            
        IN SYSTEM_INFORMATION_CLASS
    SystemInformationClass,
        IN OUT PVOID SystemInformation,            
        IN ULONG SystemInformationLength,        
        OUT PULONG ReturnLength OPTIONAL          
        };                                                                      
      (这个函数结构Microsoft没有公开,参见Gary Nebbett< >)


      第一个参数是一个枚举常数,设置要
    持54个系统信息的查询,我们要用到的是
    .
    查询的系统信息类型,ZwQuerySystemInformation支
    它的第16号功能,进行SystemHandleInformation查询

      SYSTEM_HANDLE_INFORMATION结构定义如下:              

        typedef struct _
    SYSTEM_HANDLE_INFORMATION{
          ULONG ProcessID;    //进程的标识ID            
          UCHAR ObjectTypeNumber;    //对象类型    
          UCHAR Flags;
           //0x01 = PROTEC
    T_FROM_CLOSE,0x02 = INHERIT
          USHORT Handle;       //对象句柄的数值          
          PVOID Object;      //对象句柄所指的内核对象地址  
          ACCESS_MASK
    GrantedAccess;   //创建句
    柄时所准许的对象的访问权
        }SYSTEM_HANDLE_INFORMATION,
    * PSYSTEM_HANDLE_INFORMATION;
        (这个函数结构Microsoft没有公开,参见Gary Nebbett< >)

      第二个参数输出查询的结果                                                      
      第三个参数设置缓冲区的长度                                                    
      第四个参数返回函数正确执行需要的缓冲区的大小                                  
      代码如下:                                                                    
      #define SystemHandleInformation 16          
      PULONG GetHandleList()                                  
      {                                                                            
        ULONG cbBuffer = 0x1000;  
    //先设定一个较小的缓冲空间
        PULONG pBuffer =
    new ULONG[cbBuffer]; //分配
    内存
        NTSTATUS Status;                                          

        do                                                                      
          {                                                                    
          Status = ZwQuerySystemInformation(  
                SystemHandleInformation,          
                
    pBuffer, cbBuffer * sizeof *
    pBuffer, NULL);

          if (Status =
    = STATUS_INFO_LENGTH_MISMATC
    H)
          {                                                                    
            //如果返回的错误信息为缓冲区长度不够,那么重新分配内存          
            delete [] pBuffer;                              

            pBuffer
    = new ULONG[cbBuffer *= 2];
          }                                                                    
          else if (!NT_SUCCESS(Status))            
          {                                                                    
            //如果是其他错误信息,返回                                      
            delete [] pBuffer;                              
            return false;                                        
          }                                                                    
          }                                                                    
          while (Status == STATUS_
    INFO_LENGTH_MISMATCH);
        return pBuffer;                                            
      }                                                                            

      因为如果一个进程打开
    核对象,所以,我们在当前进
    这样,我们可以在上面获得
    打开的内核对象的句柄数值
    了端口,那么它肯定会建立类型
    程中打开上述的两个内核对象,
    的句柄列表中的当前进程中查找
    相同的句柄,并得到其句柄所指
    为DeviceTcp和DeviceUdp的内
    在打开的同时保存了打开的句柄,
    对象句柄的数值和我们保存的两个
    向的内核对象的地址.代码如下:
      DWORD TcpHandle;                                              
      DWORD UdpHandle;                                              
      DWORD GetTcpUdpObjec
    t(PULONG pBuffer,HANDLE pHan
    dle,DWORD ProcessId)
      {                                                                            
        DWORD objTYPE1,objTYPE2,HandleObject;

        PSYSTEM_HANDLE_INFORMATION p
    DLE_INFORMATION)(pBuffer+1);
    Processes = (PSYSTEM_HAN

                                                                                  
        for (i=0;i< * pBuffer;i++)                
        {                                                                        
          if ((pProces
    ses[i].ProcessID) == Process
    Id)
          {                                                                    
            objTYPE1 = (DWORD)hDeviceTcpUdp;  
            objTYPE2
    = (DWORD)pProcesses[i].Hand
    le;
            if(objTYPE1==objTYPE2)                      
            {                                                                
              Hand
    leObject = (DWORD)pProcesses
    .Object;
              return HandleObject;                      
          }                                                                    
        }                                                                        
        return 0;                                                        
      }                                                                            

      这个内核对象地址是一个线性地址,我们需要把这个地址转换为物理地址,并得到一些相关的数据.在fport中,换算是这样进行的:(具体描述见WebCrazy的文章< < 小议Windows NT/2000的分页机制>>)

      void * NewmapPhy;                                            

      void GetPTE(DWORD objAddress)                    
      {                                                                            
        DWORD physmemBuff;                                      
        DWORD newAddress1,newAddress
    2,newAddress3,newAddress4;
        DWORD * newAddress;                                    

        physmemBuff = (DWORD)pMapPhy
    sicalMemory;
        newAddress1 = physmemBuff+(objAddress>>0x16)*4;

        newAddress = (DWORD *)newAddress1;      
        newAddress1 = * newAddress;                    
        newAddress2 = objAddress & 0x3FF000;  
        newAddress3 = newAddress1 &
    0x0FFFFF000;
        newAddress4 = newAddress2 +
    newAddress3;
        NewmapPhy = MapViewOfFile(gh
    READ,0,newAddress4,0x1000);
    PhysicalMemory,FILE_MAP_

        //重新映射物理内存,得到当前线性地址所指向的PTE的物理地址内容        
      }                                                                            

      然后在根据内核对象的线性地址得到
    容的页,其结构如下:
    这个地址所指向的物理页,得到体现当前内核对象内

      typedef struct {                                              
        ULONG Present;                                              
        ULONG WriteTable;                                        
        ULONG User;                                                    
        ULONG WriteThru;                                          
        ULONG NoCache;                                              
        ULONG Accessed;                                            
        ULONG Dirty;                                                  
        ULONG PageSize;                                            
        ULONG Global;                                                
        ULONG Available;                                          
        ULONG Pfn;                                                      
      } PTE, *PPTE;                                                    
      (注:我不能保证这个结
    是可以工作的)
    构的正确性,但我们只会用到其

    中的两个值,对程序来说,这个结构

      代码如下:                                                                    
      ULONG CurrWriteTable;                                    
      ULONG NoCache;                                                  

      void GetMustPar(DWORD objAddress)            
      {                                                                            
        DWORD CurrAddress;                                      
        CurrAddress = objAddress & 0xFFF;        
        PPTE pte = (PPTE)(VOID *)((D
    WORD)NewmapPhy+CurrAddress);
        CurrWriteTable = pte->WriteTable;

        CurrNoCache = Pte->NoCache;

      }                                                                            

      我们现在想要得到的都已经得到了,
    句柄(呵呵,不是每一个句柄,在Windows N
    0x16,在Windows 2000下这个值为0x1A)的
    WriteTable值,如果与内核对象DeviceT
    一个端口,再对这个句柄进行确认,就可以
    下面需要做的是遍历进程,用每一个进程中的每一个
    T下,DeviceTcp和DeviceUdp的句柄类型值为
    核心地址用上面所描述的办法得到其PTE内容,得到其
    cp和DeviceUdp相等,那么这个句柄就有可能打开了
    了.确认的代码如下:
      typedef struct _TDI_CONNECTION_INFO {   
        ULONG     State;                                         
        ULONG     Event;                                         
        ULONG     TransmittedTsdus;                   
        ULONG     ReceivedTsdus;                         
        ULONG     TransmissionErrors;               
        ULONG     ReceiveErrors;                         
        LARGE_INTEGER Throughput;                       
        LARGE_INTEGER Delay;                                 
        ULONG     SendBufferSize;                       
        ULONG     ReceiveBufferSize;                 
        BOOLEAN    Unreliable;                             
      } TDI_CONNECTION_INFO, *PTDI_CON
    NECTION_INFO;

      typedef struct _TDI_CONNECTION_I
    NFORMATION {
        LONG  UserDataLength;                               
        PVOID UserData;                                           
        LONG  OptionsLength;                                 
        PVOID Options;                                             
        LONG  RemoteAddressLength;                     
        PVOID RemoteAddress;                                 
      } TDI_CONNECTION_INFORMATION, *P
    TDI_CONNECTION_INFORMATION;
      (以上结构见tdi.h)                                                      

      void GetOpenPort(DWORD dwProcess
    esID,USHORT Handle,int NoCache)
      //dwProcessesID为进程标识ID                                  
      //Handle为进程打开的句柄,并且经
    过比较为DeviceTcp或DeviceUdp类型
      //NoCache为PTE结构中的一个值                                     
      {                                                                            
        HANDLE hProc,DupHandle=NULL;                  
        HANDLE hEven=NULL;                                      
          OVERLAPPED overlap;                                
        u_short openport;                                        
        int i=0;                                                          
        char procName[256]={0};                            
        int portflag=0;                                            

        overlap.Internal = 0;                                
        overlap.InternalHigh = 0;                        
        overlap.Offset = 0;                                    
        overlap.OffsetHigh = 0;                            
        hEven=CreateEvent(0,1,0,0);                    
        overlap.hEvent = hEven;                            


        hProc = OpenProc
    ess(PROCESS_DUP_HANDLE,
                  0,                                                  
                  dwProcessesID);                        
        if(hProc)                                                        
        {                                                                        
          DuplicateHandle(hProc,                          
                  (HANDLE)Handle,                        
                  GetCurrentProcess(),              
                  &DupHandle,                                
                  0,                                                  
                  FALSE,                                          
                  2);                                                
          CloseHandle( hProc );                            
          if(DupHandle)                                            
          {                                                                    
            TDI_CONN
    ECTION_INFO  TdiConnInfo={
    0};
            TDI_CONNECTION_INFOR
    MATION TdiConnInformation={0};
            DWORD dwRetu=0;                                  

            if(NoCache==0x2)                                  
            {                                                                
              TdiC
    onnInformation.RemoteAddress
    Length= 4;
              if(D
    eviceIoControl(DupHandle,0x2
    10012,
                
        &TdiConnInformation,
    sizeof(TdiConnInformation),
                    &Tdi
    ConnInfo,sizeof(TdiConnInfo),
                    0,&overlap))                          
              //进行TDI查询,得到连接的相关信息                        
              {                                                            
                openport = n
    tohs((u_short)TdiConnInfo.ReceivedTsdus);
                
    进程名称
    procname = GetProcName(dwPro

    cessesID); //得到进程标识ID的

                printf("PID
    %4dn",dwProcessesID,procName,openpo
    = %4d ProcessName = %15s PORT =
    rt);
              }                                                            
            }                                                                
            if(NoCache==0x1)                                  
            {                                                                
              TdiC
    onnInformation.RemoteAddress
    Length= 3;
              if(D
    eviceIoControl(DupHandle,0x2
    10012,
                
        &TdiConnInformation,
    sizeof(TdiConnInformation),
                    &Tdi
    ConnInfo,sizeof(TdiConnInfo),
                    0,&overlap))                          
              //进行TDI查询,得到连接的相匦畔?nbsp;                       
              {                                                            
                openport = n
    tohs((u_short)TdiConnInfo.ReceivedTsdus);
                procname = G
    进程名称
    etProcName(dwProcessesID); //得到进程标识ID的

                printf("PID
    %4dn",dwProcessesID,procName,openpo
    = %4d ProcessName = %15s PORT =
    rt);
              }                                                            
            }                                                                
          }                                                                    
        }                                                                        
        CloseHandle(hEven);                                    
        CloseHandle(DupHandle);                            
      }                                                                            

    上一页 下一页




    map