Author:  sinister
Email:   sinister@whitecell.org
Homepage:http://www.whitecell.org
Date:    2007-02-26

/*******************************************************************
            这个键盘过滤驱动是一个定时锁定计算机程序的功能部分,以前 lgx
            写过一个 linux 版,现在我们需要实现一个 windows 版。这部分的
            功能要求如下:
            1、强制锁定键盘/鼠标。
            2、可动态加/解锁
            3、兼容所有 NT 系列的操作系统。
            就这个需求而言,能马上能想到的就有7,8种方案,这些方案可以说都能够实
            现,但如何更合理,更稳定、更彻底的实现,如何尽量少的消耗系统资源,如
            何保证其兼容性,等一系列问题不得不让我们去重新评估这几种方法。首先在
            上层实现,一是怕被饶过,二是怕调用频繁影响系统性能。在底层实现,一是
            怕考虑不周有兼容性问题,二是怕过多使用未公开方法导致系统不稳定。下面
            就来看一下我想到的几种实现方法:
            1、全局键盘/鼠标钩子
            2、BlockInput() API
            3、使用 setupapi 进行控制
            4、全局键盘/鼠标钩子+远线程插入 WINLOGON 进程屏蔽 CTRL+AL+DEL
            5、拦截 win23k!RawInputThread() 函数
            6、修改 DDK 中自带的 kbfilter 的键盘(Port Driver)过滤驱动
            7、拦截 kdbclass 驱动的 driver dispatch routine
            8、实现一个 PS/2 与 USB 键盘过滤驱动
            我们先看一下以上这些方案的实用性与通用性。第1,2套方案不在考虑
            之内了,因为有办法解锁,屏蔽不了 CTRL+ALT+DEL 组合键。第3套方
            案经过我的测试使用 Keyboard 的 CLASSID 不是什么环境都好使,存在
            兼容性的问题。第4套方案系统效率会大大降低,而且存在很多不稳定因
            素,对于全局钩子这种东西我一直很排斥。第5套方案,同样存在兼容性
            问题和不稳定因素。第6套方案看似完美,但无法实现动态卸载,无法卸
            载就意味着你需要一个开关来控制是否锁定,这样还要与应用层通讯,我
            的目的是不让应用层与驱动有任何交互。且使用 WDM 形式这种安装起来
            也很麻烦,要么 INF 要么自己 setupapi,这都不是我想看到的,还有如
            果仅为实现这么一个功能,就让一个核心驱动一直存在系统中的话,我有
            障碍。第7套方案看似实现起来很简单,其实有很多问题。如仅是拦截
            IRP_MJ_READ 并粗暴的返回拒绝后,系统无法恢复到初始状态。且对于
            USB 键盘存在兼容性问题。那么最后只有自己实现一个 PS/2 与 USB 键
            盘过滤驱动了,既然要实现这么一个驱动,那么就必须能实现到第6套方
            案的全部功能且不存在它所带来的问题,否则就没有什么意义了。
            我们都知道实现一个可直接使用 SERVICE API 来动态装载的 KMD 键盘过
            滤驱动,首先需要先 ATTACH 到 \\Device\\KeyboardClass0 设备上再进
            行按键过滤。但如果仅 ATTACH 这个设备的话,会存在很多问题,那就是
            只能过滤到 PS/2 键盘,而对于使用 USB 键盘的机器毫无作用。现在越
            来越多的品牌机都预配的是 USB 键盘(如:DELL)。大家可能会想,从
            KeyboardClass0 一直到 N 都 ATTACH 不就可以了么?总有一个是 USB
            键盘设备,经过实践这是不可行的,只要是 USB 键盘设备的话,在使用
            IoGetDeviceObjectPointer() 函数从设备名得到设备对象都会获取失败,
            我还曾尝试使用 USB 键盘设备名来转换,还是一样失败。还有一个问题
            就是 USB 键盘设备不是都有名称的,即使有它的名称也都是动态生成的
            而不是固定的。那么这就带来了一个问题,既然系统提供的函数无法使
            用,且我们又是为了动态安装/卸载,使用的是 KMD 类型驱动,无法通
            过 AddDevice 例程来获得 USB 键盘的设备对象进行挂接。那么如何来
            屏蔽 USB 键盘按键?要达到这个目的只有自己分析下 USB 协议栈,通
            过使用 DriverTree 观察发现,所有 USB 外设都挂在了 \Driver\hidusb
            上面,USB 键盘驱动名为 \Driver\kbdhid,而它则是 \Driver\kbdhid
            的一个 FilterDriver,且这个 \Driver\kbdhid 没有设备名称,也就意
            味着,我们无法 IoGetDeviceObjectPointer() 得到设备对象并 ATTACH。
            经过对多个系统多台使用 USB 键盘机器的分析,可以确定让我使用它们
            来作为得到 USB 键盘设备的依据。(这里仅是对 USB 键盘设备很功利
            的分析,如果想了解 WINDOWS 的 USB 设备栈如何组建,请阅读 tiamo
            的 《Windows 的 USB 体系结构》。在此向所有公开研究成果的人致
            敬!)有了这些依据,下面就没什么好说的了,自己遍历 USB 设备栈,
            根据驱动名称获得 USB 设备对象,然后 ATTACH,过滤按键。具体流程
            见下面代码。
            这里有必要说下动态卸载,我尝试了两种方式,一种是在 UNLOAD 例程
            里直接取消 IRP,这种方法在 W2K 系统下,无论是 PS/2 还是 USB 键
            盘都可以很好的实现。但在 XP/2003 系统上则无法成功,在 XP/2003
            上暂时使用一个 IRP 计数器,在 UNLOAD 例程里判断如果还有一个没有
            完成的 IRP 则等待,这样的话,需要在 UNLOAD 后用户按下任意键才可
            继续,虽然能够安全卸载但还需要一次用户介入。考虑实现的仅是一个
            锁定功能,这样也算是能够忍受了。以后考虑在驱动中直接模拟用户按
            键来实现,当然这种按键要有通用性和兼容性,支持 PS/2 与 USB 键盘。
            完成了上述工作后看起来好象完美了,其实不然,当你屏蔽了当前使用
            的键盘时别忘了还可以再插入一个 USB 键盘,而后续插入的这个键盘是
            可以被识别的。这就需要我们处理 IRP_MJ_PNP 选项,对其中我们有兴趣
            的 IRP_MN_XXX 做相应处理,可以处理 IRP_MN_START_DEVICE,在这时我
            们动态挂接。还可以处理其他的 IRP,索性返回错误,让识别失效。但我
            们的驱动是 KMD 类型,只要加上一句对 DriverObject->DriverExtension
            ->AddDevice 的赋值操作则无法直接使用 SERVICE API 来动态加载了。
            如何保持 KMD 又可以获得 PNP 的处理权呢?这可能要直接对 PnpManager
            进行操作了。这个问题有待大家来完善了。
            要问为什么把文章插在代码当中,那可能是我觉得,既然把全部代码都贴出
            来了,写文章就不如直接看代码来的真切。我这里所写也仅仅是对这些天的
            分析做个记录而已。我更愿意把它看做是一段注释。
            最后在此代码中要
            感谢:PolyMeta,他在放假前提醒我 USB 键盘的不同。
            感谢:lgx,过节前给我找了些事,以至于没有让我觉得过节那么无聊。
            感谢:齐佳佳,过节请我吃好吃的。
            崞類浶愭蝰櫉炈棡溫滠飲钕唹徕熸唹戹樤樯殢餀膑?崞烊旡唹澾崞懽碡飲嵯
            愥撫剢淦泮嵯駨耒栃撣
            ******************************************************************/
            /*****************************************************************
            文件名        : WssLockKey.c
            描述          : 键盘过滤驱动
            作者          : sinister
            最后修改日期  : 2007-02-26
            *****************************************************************/
            #include "WssLockKey.h"
            NTSTATUS
            DriverEntry( IN PDRIVER_OBJECT KeyDriverObject,
            IN PUNICODE_STRING RegistryPath )
            {
            UNICODE_STRING KeyDeviceName;
            PDRIVER_OBJECT KeyDriver;
            PDEVICE_OBJECT UsbDeviceObject;
            NTSTATUS ntStatus;
            ULONG i;
            //
            // 保存设备名,调试使用
            //
            WCHAR szDeviceName[MAXLEN + MAXLEN] =
            {
            0
            };
            KeyDriverObject->DriverUnload = KeyDriverUnload;
            //
            // 先尝试获得 USB 键盘设备对象,如果成功则挂接 USB 键盘
            //
            // 注意:因为 USB 键盘设备名不固定,且即使得到名称也无法
            // 使用 IoGetDeviceObjectPointer() 函数根据设备名称得到其
            // 设备对象,所以这里我们只能自己枚举 USB 设备栈,并得到
            // USB 键盘设备来进行挂接
            //
            ntStatus = GetUsbKeybordDevice( &UsbDeviceObject );
            if ( NT_SUCCESS( ntStatus ) && UsbDeviceObject != NULL )
            {
            //
            // 调试使用,USB 键盘设备 kbdhid 没有设备名只有驱动名
            // 所以这里打印为空
            //
            RtlInitUnicodeString( &KeyDeviceName, szDeviceName );  // USB KEYBOARD
            DbgPrint( "KeyDeviceName:%S\n", KeyDeviceName.Buffer );
            //
            // 挂接 USB 键盘设备
            //
            ntStatus = AttachUSBKeyboardDevice( UsbDeviceObject, KeyDriverObject );
            if ( !NT_SUCCESS( ntStatus ) )
            {
            DbgPrint( "Attach USB Keyboard Device to failed!\n" );
            return STATUS_INSUFFICIENT_RESOURCES;
            }
            }
            else
            {
            //
            // 如果没有 USB 键盘,则尝试挂接 PS/2 键盘设备
            //
            RtlInitUnicodeString( &KeyDeviceName, PS2KEYBOARDNAME );
            ntStatus = AttachPS2KeyboardDevice( &KeyDeviceName,
            KeyDriverObject,
            &KeyDriver );
            if ( !NT_SUCCESS( ntStatus ) || KeyDriver == NULL )
            {
            DbgPrint( "Attach PS2 Keyboard Device to failed!\n" );
            return STATUS_INSUFFICIENT_RESOURCES;
            }
            }
            //
            // 这里没有过滤其他例程,仅处理了按键操作。这样处理会禁止
            // 休眠。因在锁定时不允许休眠,所以也就无须处理其他例程
            //
            KeyDriverObject->MajorFunction[IRP_MJ_READ] = KeyReadPassThrough;
            return STATUS_SUCCESS;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 系统函数
            // 函数模块 : 键盘过滤模块
            ////////////////////////////////////////////////////////////////
            // 功能 : 尝试取消队列里的异步 IRP,如果失败则等待用户按键,
            //        卸载键盘过滤驱动
            // 注意 : 取消 IRP 操作在 2000 系统上可以成功,在 XP / 2003 上
            //        则需要等待用户按键,以后有待完善
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2005.12.27
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            ////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            VOID
            KeyDriverUnload( PDRIVER_OBJECT KeyDriver )
            {
            PDEVICE_OBJECT KeyFilterDevice ;
            PDEVICE_OBJECT KeyDevice ;
            PDEVICE_EXTENSION KeyExtension;
            PIRP Irp;
            NTSTATUS ntStatus;
            KeyFilterDevice = KeyDriver->DeviceObject;
            KeyExtension = ( PDEVICE_EXTENSION ) KeyFilterDevice->DeviceExtension;
            KeyDevice = KeyExtension->TargetDevice;
            IoDetachDevice( KeyDevice );
            //
            // 如果还有 IRP 未完成,且当前 IRP 有效则尝试取消这个 IRP
            //
            if ( KeyExtension->IrpsInProgress > 0 && KeyDevice->CurrentIrp != NULL )
            {
            if ( CancelKeyboardIrp( KeyDevice->CurrentIrp ) )
            {
            //
            // 成功则直接退出删除键盘过滤设备
            //
            DbgPrint( "CancelKeyboardIrp() is ok\n" );
            goto __End;
            }
            }
            //
            // 如果取消失败,则一直等待按键
            //
            while ( KeyExtension->IrpsInProgress > 0 )
            {
            DbgPrint( "Irp Count:%d\n", KeyExtension->IrpsInProgress );
            }
            __End:
            IoDeleteDevice( KeyFilterDevice );
            return ;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 键盘过滤模块
            /////////////////////////////////////////////////////////////////
            // 功能 : 取消 IRP 操作
            // 注意 : 这个函数仅是为配合在 UNLOAD 例程使用,其他例程中不能
            //        使用此方法来取消 IRP
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2007.02.20
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            /////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            BOOLEAN
            CancelKeyboardIrp( IN PIRP Irp )
            {
            if ( Irp == NULL )
            {
            DbgPrint( "CancelKeyboardIrp: Irp error\n" );
            return FALSE;
            }
            //
            // 这里有些判断应该不是必须的,比如对 CancelRoutine 字段,
            // 因为 IoCancelIrp() 函数中有判断了。但只有偏执狂才能生存 :)。
            // 小波说 低智、偏执、思想贫乏是最不可容忍的。我这一行代码就占
            // 了两条 :D,不知 xiaonvwu 看过后会作何感想?:DDD
            //
            //
            // 如果正在取消或没有取消例程则直接返回 FALSE
            //
            if ( Irp->Cancel || Irp->CancelRoutine == NULL )
            {
            DbgPrint( "Can't Cancel the irp\n" );
            return FALSE;
            }
            if ( FALSE == IoCancelIrp( Irp ) )
            {
            DbgPrint( "IoCancelIrp() to failed\n" );
            return FALSE;
            }
            //
            // 取消后重设此例程为空
            //
            IoSetCancelRoutine( Irp, NULL );
            return TRUE;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 设备栈信息模块
            /////////////////////////////////////////////////////////////////
            // 功能 : 遍历 DEVICE_OBJECT 中 AttachedDevice 域,找到 USB 键盘
            //        设备上名为 kbdhid 的过滤驱动(Upper Filter Driver)
            // 注意 :
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2005.06.02
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            /////////////////////////////////////////////////////////////////
            // 修改者 : sinister
            // 修改日期 : 2007.2.12
            // 修改内容 : 为匹配 USB 键盘驱动做了相应的修改
            /////////////////////////////////////////////////////////////////
            BOOLEAN
            GetAttachedDeviceInfo( IN PDEVICE_OBJECT DevObj )
            {
            PDEVICE_OBJECT DeviceObject;
            BOOLEAN bFound = FALSE;
            if ( DevObj == NULL )
            {
            DbgPrint( "DevObj is NULL!\n" );
            return FALSE;
            }
            DeviceObject = DevObj->AttachedDevice;
            while ( DeviceObject )
            {
            //
            // 一些 OBJECT 的名称都存在分页区,虽然大部分时候不会被交换出去,但
            // 有一次足够了。这算是经验之谈
            //
            if ( MmIsAddressValid( DeviceObject->DriverObject->DriverName.Buffer ) )
            {
            DbgPrint( "Attached Driver Name:%S,Attached Driver Address:0x%x,Attached DeviceAddress:0x%x\n",
            DeviceObject->DriverObject->DriverName.Buffer,
            DeviceObject->DriverObject,
            DeviceObject );
            //
            // 找到 USB 键盘驱动的 kbdhid 设备了么?找到了就不继续了
            //
            if ( _wcsnicmp( DeviceObject->DriverObject->DriverName.Buffer,
            KDBDEVICENAME,
            wcslen( KDBDEVICENAME ) ) == 0 )
            {
            DbgPrint( "Found kbdhid Device\n" );
            bFound = TRUE;
            break;
            }
            }
            DeviceObject = DeviceObject->AttachedDevice;
            }
            return bFound;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 设备栈信息模块
            /////////////////////////////////////////////////////////////////
            // 功能 : 从 DEVICE_OBJECT 中得到设备与驱动名称并打印地址
            // 注意 : 函数功能只是打印信息,不同环境使用中应该会做修改
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2006.05.02
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            /////////////////////////////////////////////////////////////////
            // 修改者 : sinister
            // 修改日期 : 2007.2.12
            // 修改内容 : 打印出 USB 键盘驱动的设备名称,仅作调试使用
            /////////////////////////////////////////////////////////////////
            VOID
            GetDeviceObjectInfo( IN PDEVICE_OBJECT DevObj )
            {
            POBJECT_HEADER ObjectHeader;
            POBJECT_HEADER_NAME_INFO ObjectNameInfo;
            if ( DevObj == NULL )
            {
            DbgPrint( "DevObj is NULL!\n" );
            return;
            }
            //
            // 得到对象头
            //
            ObjectHeader = OBJECT_TO_OBJECT_HEADER( DevObj );
            if ( ObjectHeader )
            {
            //
            // 查询设备名称并打印
            //
            ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
            if ( ObjectNameInfo && ObjectNameInfo->Name.Buffer )
            {
            DbgPrint( "Device Name:%S - Device Address:0x%x\n",
            ObjectNameInfo->Name.Buffer,
            DevObj );
            //
            // 复制 USB 键盘设备名到一个全局 BUFFER 里,为调试时显示
            // 用,没有实际的功能用途
            //
            RtlZeroMemory( szUsbDeviceName, sizeof( szUsbDeviceName ) );
            wcsncpy( szUsbDeviceName,
            ObjectNameInfo->Name.Buffer,
            ObjectNameInfo->Name.Length / sizeof( WCHAR ) );
            }
            //
            // 对于没有名称的设备,则打印 NULL
            //
            else if ( DevObj->DriverObject )
            {
            DbgPrint( "Driver Name:%S - Device Name:%S - Driver Address:0x%x - Device Address:0x%x\n",
            DevObj->DriverObject->DriverName.Buffer,
            L"NULL",
            DevObj->DriverObject,
            DevObj );
            }
            }
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 键盘过滤模块
            /////////////////////////////////////////////////////////////////
            // 功能 : 得到 USB 驱动 hidusb 的驱动对象,并遍历以上所有设备
            //        对象,过滤出 USB 键盘设备,将其设备对象返回
            // 注意 :
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2007.02.13
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            /////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            NTSTATUS
            GetUsbKeybordDevice( OUT PDEVICE_OBJECT* UsbDeviceObject )
            {
            UNICODE_STRING DriverName;
            PDRIVER_OBJECT DriverObject = NULL;
            PDEVICE_OBJECT DeviceObject = NULL;
            BOOLEAN bFound = FALSE;
            RtlInitUnicodeString( &DriverName, USBKEYBOARDNAME );
            ObReferenceObjectByName( &DriverName,
            OBJ_CASE_INSENSITIVE,
            NULL,
            0,
            ( POBJECT_TYPE ) IoDriverObjectType,
            KernelMode,
            NULL,
            &DriverObject );
            if ( DriverObject == NULL )
            {
            DbgPrint( "Not found USB Keyboard Device hidusb!\n" );
            return STATUS_UNSUCCESSFUL;
            }
            DeviceObject = DriverObject->DeviceObject;
            while ( DeviceObject )
            {
            GetDeviceObjectInfo( DeviceObject );
            if ( DeviceObject->AttachedDevice )
            {
            //
            // 查找 USB 键盘设备
            //
            if ( GetAttachedDeviceInfo( DeviceObject ) )
            {
            bFound = TRUE;
            goto __End;
            }
            }
            DeviceObject = DeviceObject->NextDevice;
            }
            __End:
            if ( bFound )
            {
            //
            // 找到则返回 USB 键盘设备对象
            //
            *UsbDeviceObject = DeviceObject;
            }
            else
            {
            *UsbDeviceObject = NULL;
            }
            return STATUS_SUCCESS;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 键盘过滤模块
            ////////////////////////////////////////////////////////////////
            // 功能 : 创建过滤设备将其附加到需要跟踪的设备上,保存设备相关
            //        信息,返回附加后的驱动对象
            // 注意 : 此函数仅挂接 USB 键盘设备
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2005.12.27
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            ////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            NTSTATUS
            AttachUSBKeyboardDevice( IN PDEVICE_OBJECT UsbDeviceObject,
            IN PDRIVER_OBJECT  DriverObject )
            {
            PDEVICE_OBJECT DeviceObject;
            PDEVICE_OBJECT TargetDevice;
            PDEVICE_EXTENSION DevExt;
            NTSTATUS ntStatus;
            //
            // 创建过滤设备对象
            //
            ntStatus = IoCreateDevice( DriverObject,
            sizeof( DEVICE_EXTENSION ),
            NULL,
            FILE_DEVICE_UNKNOWN,
            0,
            FALSE,
            &DeviceObject );
            if ( !NT_SUCCESS( ntStatus ) )
            {
            DbgPrint( "IoCreateDevice() 0x%x!\n", ntStatus );
            return ntStatus;
            }
            DevExt = ( PDEVICE_EXTENSION ) DeviceObject->DeviceExtension;
            //
            // 初始化自旋锁
            //
            KeInitializeSpinLock( &DevExt->SpinLock );
            //
            // 初始化 IRP 计数器
            //
            DevExt->IrpsInProgress = 0;
            //
            // 将过滤设备对象附加在目标设备对象之上,并返回附加后的原设备对象
            //
            TargetDevice = IoAttachDeviceToDeviceStack( DeviceObject, UsbDeviceObject );
            if ( !TargetDevice )
            {
            IoDeleteDevice( DeviceObject );
            DbgPrint( "IoAttachDeviceToDeviceStack() 0x%x!\n", ntStatus );
            return STATUS_INSUFFICIENT_RESOURCES;
            }
            //
            // 保存过滤设备信息
            //
            DevExt->DeviceObject = DeviceObject;
            DevExt->TargetDevice = TargetDevice;
            //
            // 设置过滤设备相关信息与标志
            //
            DeviceObject->Flags |= ( DO_BUFFERED_IO | DO_POWER_PAGABLE );
            DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
            return STATUS_SUCCESS;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 键盘过滤模块
            ////////////////////////////////////////////////////////////////
            // 功能 : 创建过滤设备将其附加到需要跟踪的设备上,保存设备相关
            //        信息,返回附加后的驱动对象
            // 注意 : 此函数仅挂接 PS/2 键盘设备
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2005.12.27
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            ////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            NTSTATUS
            AttachPS2KeyboardDevice( IN UNICODE_STRING* DeviceName, // 需要跟踪的设备名
            IN PDRIVER_OBJECT  DriverObject, // 过滤驱动也就是本驱动的驱动对象
            OUT PDRIVER_OBJECT* FilterDriverObject ) // 返回附加后的驱动对象
            {
            PDEVICE_OBJECT DeviceObject;
            PDEVICE_OBJECT FilterDeviceObject;
            PDEVICE_OBJECT TargetDevice;
            PFILE_OBJECT FileObject;
            PDEVICE_EXTENSION DevExt;
            NTSTATUS ntStatus;
            //
            // 根据设备名称找到需要附加的设备对象
            //
            ntStatus = IoGetDeviceObjectPointer( DeviceName,
            FILE_ALL_ACCESS,
            &FileObject,
            &DeviceObject );
            if ( !NT_SUCCESS( ntStatus ) )
            {
            DbgPrint( "IoGetDeviceObjectPointer() 0x%x\n", ntStatus );
            return ntStatus;
            }
            //
            // 创建过滤设备对象
            //
            ntStatus = IoCreateDevice( DriverObject,
            sizeof( DEVICE_EXTENSION ),
            NULL,
            FILE_DEVICE_KEYBOARD,
            0,
            FALSE,
            &FilterDeviceObject );
            if ( !NT_SUCCESS( ntStatus ) )
            {
            ObDereferenceObject( FileObject );
            DbgPrint( "IoCreateDevice() 0x%x!\n", ntStatus );
            return ntStatus;
            }
            //
            // 得到设备扩展结构,以便下面保存过滤设备信息
            //
            DevExt = ( PDEVICE_EXTENSION ) FilterDeviceObject->DeviceExtension;
            //
            // 初始化自旋锁
            //
            KeInitializeSpinLock( &DevExt->SpinLock );
            //
            // 初始化 IRP 计数器
            //
            DevExt->IrpsInProgress = 0;
            //
            // 将过滤设备对象附加在目标设备对象之上,并返回附加后的原设备对象
            //
            TargetDevice = IoAttachDeviceToDeviceStack( FilterDeviceObject,
            DeviceObject );
            if ( !TargetDevice )
            {
            ObDereferenceObject( FileObject );
            IoDeleteDevice( FilterDeviceObject );
            DbgPrint( "IoAttachDeviceToDeviceStack() 0x%x!\n", ntStatus );
            return STATUS_INSUFFICIENT_RESOURCES;
            }
            //
            // 保存过滤设备信息
            //
            DevExt->DeviceObject = FilterDeviceObject;
            DevExt->TargetDevice = TargetDevice;
            DevExt->pFilterFileObject = FileObject;
            //
            // 设置过滤设备相关信息与标志
            //
            FilterDeviceObject->DeviceType = TargetDevice->DeviceType;
            FilterDeviceObject->Characteristics = TargetDevice->Characteristics;
            FilterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
            FilterDeviceObject->Flags |= ( TargetDevice->Flags & ( DO_DIRECT_IO |
            DO_BUFFERED_IO ) );
            //
            // 返回附加后的驱动对象
            //
            *FilterDriverObject = TargetDevice->DriverObject;
            ObDereferenceObject( FileObject );
            return STATUS_SUCCESS;
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 : 自定义工具函数
            // 函数模块 : 键盘过滤模块
            ////////////////////////////////////////////////////////////////
            // 功能 : 键盘过滤驱动的 IRP_MJ_READ 派遣例程,所有按键将触发
            //        这个 IRP 的完成
            // 注意 :
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2007.2.15
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            ////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            NTSTATUS
            KeyReadPassThrough( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
            {
            NTSTATUS status;
            KIRQL IrqLevel;
            PDEVICE_OBJECT pDeviceObject;
            PDEVICE_EXTENSION KeyExtension = ( PDEVICE_EXTENSION )
            DeviceObject->DeviceExtension;
            IoCopyCurrentIrpStackLocationToNext( Irp );
            //
            // 将 IRP 计数器加一,为支持 SMP 使用自旋锁
            //
            KeAcquireSpinLock( &KeyExtension->SpinLock, &IrqLevel );
            InterlockedIncrement( &KeyExtension->IrpsInProgress );
            KeReleaseSpinLock( &KeyExtension->SpinLock, IrqLevel );
            IoSetCompletionRoutine( Irp,
            KeyReadCompletion,
            DeviceObject,
            TRUE,
            TRUE,
            TRUE );
            return IoCallDriver( KeyExtension->TargetDevice, Irp );
            }
            /////////////////////////////////////////////////////////////////
            // 函数类型 :系统回调函数
            // 函数模块 : 键盘过滤模块
            ////////////////////////////////////////////////////////////////
            // 功能 : 获得键盘按键,用无效扫描码替换,以达到屏蔽键盘的目的
            // 注意 :
            /////////////////////////////////////////////////////////////////
            // 作者 : sinister
            // 发布版本 : 1.00.00
            // 发布日期 : 2007.2.12
            /////////////////////////////////////////////////////////////////
            // 重   大   修   改   历   史
            ////////////////////////////////////////////////////////////////
            // 修改者 :
            // 修改日期 :
            // 修改内容 :
            /////////////////////////////////////////////////////////////////
            NTSTATUS
            KeyReadCompletion( IN PDEVICE_OBJECT DeviceObject,
            IN PIRP Irp,
            IN PVOID Context )
            {
            PIO_STACK_LOCATION IrpSp;
            PKEYBOARD_INPUT_DATA KeyData;
            PDEVICE_EXTENSION KeyExtension = ( PDEVICE_EXTENSION )
            DeviceObject->DeviceExtension;
            int numKeys, i;
            KIRQL IrqLevel;
            IrpSp = IoGetCurrentIrpStackLocation( Irp );
            if ( Irp->IoStatus.Status != STATUS_SUCCESS )
            {
            DbgPrint( "ntStatus:0x%x", Irp->IoStatus.Status );
            goto __RoutineEnd;
            }
            //
            // 系统在 SystemBuffer 中保存按键信息
            //
            KeyData = Irp->AssociatedIrp.SystemBuffer;
            if ( KeyData == NULL )
            {
            DbgPrint( "KeyData is NULL\n" );
            goto __RoutineEnd;
            }
            //
            // 得到按键数
            //
            numKeys = Irp->IoStatus.Information / sizeof( KEYBOARD_INPUT_DATA );
            if ( numKeys < 0 )
            {
            DbgPrint( "numKeys less zero\n" );
            goto __RoutineEnd;
            }
            //
            // 使用 0 无效扫描码替换,屏蔽所有按键
            //
            for ( i = 0; i < numKeys; i++ )
            {
            DbgPrint( "KeyDwon: 0x%x\n", KeyData[i].MakeCode );
            KeyData[i].MakeCode = 0x00;
            }
            __RoutineEnd :
            if ( Irp->PendingReturned )
            {
            IoMarkIrpPending( Irp );
            }
            //
            // 将 IRP 计数器减一,为支持 SMP 使用自旋锁
            //
            KeAcquireSpinLock( &KeyExtension->SpinLock, &IrqLevel );
            InterlockedDecrement( &KeyExtension->IrpsInProgress );
            KeReleaseSpinLock( &KeyExtension->SpinLock, IrqLevel );
            return Irp->IoStatus.Status ;
            }
            /*****************************************************************
            文件名        : WssLockKey.h
            描述          : 键盘过滤驱动
            作者          : sinister
            最后修改日期  : 2007-02-26
            *****************************************************************/
            #ifndef __WSS_LOCKKEY_H_
            #define __WSS_LOCKKEY_H_
            #include "ntddk.h"
            #include "ntddkbd.h"
            #include "string.h"
            #include 
            #define MAXLEN 256
            #define KDBDEVICENAME L"\\Driver\\kbdhid"
            #define USBKEYBOARDNAME L"\\Driver\\hidusb"
            #define PS2KEYBOARDNAME L"\\Device\\KeyboardClass0"
            typedef struct _OBJECT_CREATE_INFORMATION
            {
            ULONG Attributes;
            HANDLE RootDirectory;
            PVOID ParseContext;
            KPROCESSOR_MODE ProbeMode;
            ULONG PagedPoolCharge;
            ULONG NonPagedPoolCharge;
            ULONG SecurityDescriptorCharge;
            PSECURITY_DESCRIPTOR SecurityDescriptor;
            PSECURITY_QUALITY_OF_SERVICE SecurityQos;
            SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
            } OBJECT_CREATE_INFORMATION, * POBJECT_CREATE_INFORMATION;
            typedef struct _OBJECT_HEADER
            {
            LONG PointerCount;
            union
            {
            LONG HandleCount;
            PSINGLE_LIST_ENTRY SEntry;
            };
            POBJECT_TYPE Type;
            UCHAR NameInfoOffset;
            UCHAR HandleInfoOffset;
            UCHAR QuotaInfoOffset;
            UCHAR Flags;
            union
            {
            POBJECT_CREATE_INFORMATION ObjectCreateInfo;
            PVOID QuotaBlockCharged;
            };
            PSECURITY_DESCRIPTOR SecurityDescriptor;
            QUAD Body;
            } OBJECT_HEADER, * POBJECT_HEADER;
            #define NUMBER_HASH_BUCKETS 37
            typedef struct _OBJECT_DIRECTORY
            {
            struct _OBJECT_DIRECTORY_ENTRY* HashBuckets[NUMBER_HASH_BUCKETS];
            struct _OBJECT_DIRECTORY_ENTRY** LookupBucket;
            BOOLEAN LookupFound;
            USHORT SymbolicLinkUsageCount;
            struct _DEVICE_MAP* DeviceMap;
            } OBJECT_DIRECTORY, * POBJECT_DIRECTORY;
            typedef struct _OBJECT_HEADER_NAME_INFO
            {
            POBJECT_DIRECTORY Directory;
            UNICODE_STRING Name;
            ULONG Reserved;
            #if DBG
            ULONG Reserved2 ;
            LONG DbgDereferenceCount ;
            #endif
            } OBJECT_HEADER_NAME_INFO, * POBJECT_HEADER_NAME_INFO;
            #define OBJECT_TO_OBJECT_HEADER( o ) \
            CONTAINING_RECORD( (o), OBJECT_HEADER, Body )
            #define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) \
            ((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))
            typedef struct _DEVICE_EXTENSION
            {
            PDEVICE_OBJECT DeviceObject;
            PDEVICE_OBJECT TargetDevice;
            PFILE_OBJECT pFilterFileObject;
            ULONG DeviceExtensionFlags;
            LONG IrpsInProgress;
            KSPIN_LOCK SpinLock;
            }DEVICE_EXTENSION, * PDEVICE_EXTENSION;
            VOID
            KeyDriverUnload( PDRIVER_OBJECT KeyDriver );
            BOOLEAN
            CancelKeyboardIrp( IN PIRP Irp );
            extern POBJECT_TYPE* IoDriverObjectType;
            NTSYSAPI
            NTSTATUS
            NTAPI ObReferenceObjectByName( IN PUNICODE_STRING ObjectName,
            IN ULONG Attributes,
            IN PACCESS_STATE AccessState OPTIONAL,
            IN ACCESS_MASK DesiredAccess OPTIONAL,
            IN POBJECT_TYPE ObjectType,
            IN KPROCESSOR_MODE AccessMode,
            IN OUT PVOID ParseContext OPTIONAL,
            OUT PVOID* Object );
            NTSTATUS
            GetUsbKeybordDevice( OUT PDEVICE_OBJECT* UsbDeviceObject );
            BOOLEAN
            GetAttachedDeviceInfo( IN PDEVICE_OBJECT DevObj );
            VOID
            GetDeviceObjectInfo( IN PDEVICE_OBJECT DevObj );
            NTSTATUS
            AttachUSBKeyboardDevice( IN PDEVICE_OBJECT UsbDeviceObject,
            IN PDRIVER_OBJECT  DriverObject );
            NTSTATUS
            AttachPS2KeyboardDevice( IN UNICODE_STRING* DeviceName,
            IN PDRIVER_OBJECT  DriverObject,
            OUT PDRIVER_OBJECT* FilterDriverObject );
            NTSTATUS
            KeyReadCompletion( IN PDEVICE_OBJECT DeviceObject,
            IN PIRP Irp,
            IN PVOID Context );
            NTSTATUS
            KeyReadPassThrough( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
            WCHAR szUsbDeviceName[MAXLEN];
            #endif
            


WSS(Whitecell Security Systems),一个非营利性民间技术组织,致力于各种系统安全技术的研究。坚持传统的hacker精神,追求技术的精纯。
WSS 主页:http://www.whitecell.org/
WSS 论坛:http://www.whitecell.org/forums/
posted @ 2007-07-20 15:43 阿牛 阅读(2259) 评论(0)  编辑
      我家里的网络不好,只能上baidu,sina,126...此类的大门户,有的时候想上传点程序到网上,也没有共用的空间,也没有可以共享的网络硬盘,可是我发现baidu还是有100M的相册可用,改个程序的扩展名到jpg,发现也不能上传.
     "安全性做得不错呀",我再看看baidu的修行,进行如下操作:jpg + exe = jpg ,哈哈,可以上传了.我的程序也上传了.可是一般却不知道如何 jpg - jpg = exe ,看来只好写一段脚本来完成这样的任务了.(为什么写脚本?因为别的程序也没有地方上传呀,脚本可以复制,粘贴,保存成js呀,哈哈)
      先看一下使用方法:
      1. jpg + exe = jpg
          [Win] + [R], cmd ,输入:
          jpgexe.js jpg1.jpg + exe1.exe jpgout.jpg
          程序exe1已经到图片jpgout.jpg 中了.看一下图片,正常呀,上传到baidu试试(记得选原始大小)也可以了吧.
      2. jpg - jpg = exe 
         [Win] + [R], cmd ,输入:
         jpgexe.js jpgout.jpg  exe2.exe
         程序exe2已经出来了,试一下,还是你的exe1吧.
 
      好了, 看一下脚本:
      
/*
    程序:evlon(阿牛)
    邮箱:evlon@126.com
    QQ  :273352165 
*/
function existsArg(args,argValue)
{
    
for(var i = 0;i<args.length; ++i)
    {
        
if(args.item(i) == argValue)
        {
            
return true;
        }
    }
    
    
return false;
}

Number.prototype.toBytes 
= function()
{
    
var n = this;
    
var s = new ActiveXObject("adodb.stream");
    s.Charset 
= "ASCII";
    s.Type 
= 2;
    s.Open();
    s.Position 
= 0;
    
    s.WriteText(String.fromCharCode(n 
& 0xff));
    s.WriteText(String.fromCharCode((n 
>> 8& 0xff));
    s.WriteText(String.fromCharCode((n 
>> 16& 0xff));
    s.WriteText(String.fromCharCode((n 
>> 24& 0xff));
    s.Position 
= 0;
    s.Type 
= 1;
    
var buf = s.Read(4);
    
    s.Close();
    
return buf;    
}

Number.fromBytes 
= function(buf)
{
    
var s = new ActiveXObject("adodb.stream");
    s.Type 
= 1;
    s.Open();
    s.Write(buf);
    
if(s.Size != 4)
        
throw 'Number.fromByte函数中,buf长度不对';
    s.Position 
= 0;
    s.Type 
= 2;
    s.Charset 
= "ASCII";

    
var str = s.ReadText(4);
    
var n = str.charCodeAt(0);    
    n 
|= (str.charCodeAt(1<< 8);
    n 
|= (str.charCodeAt(2<< 16);
    n 
|= (str.charCodeAt(3<< 24);
    s.Close();
    
    
return n;
}

function bindFile(picFile,exeFile,outFile)
{
    
var streamPic = new ActiveXObject("adodb.stream");
    streamPic.Type 
= 1;
    streamPic.Open();
    streamPic.LoadFromFile(picFile);
    streamPic.Position 
= streamPic.Size;
    
    
var streamExe = new ActiveXObject("adodb.stream");
    streamExe.Type 
= 1;
    streamExe.Open();
    streamExe.LoadFromFile(exeFile);
    streamExe.Position 
= 0;
    streamExe.CopyTo(streamPic,streamExe.Size);
    streamPic.Write(streamExe.Size.toBytes());
    streamExe.Close();
    streamPic.SaveToFile(outFile);
    streamPic.Close();

}

function exportExe(picFile,outFile)
{
    
var bRet = false;
    
var s = new ActiveXObject("adodb.stream");
    s.Type 
= 1;
    s.Open();
    s.LoadFromFile(picFile);
    s.Position 
= s.Size - 4;
    
var buf = s.Read(4);
    
var size = Number.fromBytes(buf);
    
if(size > 0)
    {
        
var pos =  s.Size - 4 - size;
        
if(pos >= 0)
        {
            s.Position 
= pos;
            
var exeData = s.Read(size);
            s.Close();
            s.Open();
            s.Write(exeData);
            s.SaveToFile(outFile);
            bRet 
= true;
        }
    }
    
    s.Close();
    
    
return bRet;
}

function main(args)
{
    
if(existsArg(args,"+"))
    {
        
var picFile = args.item(0).toString();
        
var exeFile = args.item(2).toString();
        
var outFile = args.item(3).toString();
        bindFile(picFile,exeFile,outFile);
    }
    
else
    {
        
var picFile = args.item(0).toString();
        
var outFile = args.item(1).toString();
        exportExe(picFile, outFile);
        
    }
}

main(WScript.Arguments);
    最好,祝大家愉快
posted @ 2006-11-06 09:34 阿牛 阅读(131) 评论(3)  编辑
在我们使前后台分开的同时,有时我们想也用CSS来实现只有在JS里才能实现的动作,看似不可能的事情,但经过我的努力,但很好的工作了.

        我们知道 CSS 的Exprssion 在IE窗体需要重画时以及有鼠标动作时执行.所以不能直接用它来实现,这样当你的内容多时再快的计算机也受不了(原因是你的鼠标动一下,Expression就执行好几百次).

        为了避免这种情况,我们让我们的Expression第一次执行一次操作,以后就简单的返回,这样就可以大大的节省CPU.

       费话少说,下面是示例代码(偶是程序员,也不知道说什么了!):

文件名:myfont.css
-----------------------------------------------------------

body
{
}


/*
作者:阿牛(牛昆亮) QQ:273352165 MSN:niukl@hotmail.com

声明:可以免费使用,请您保留此信息(大家都是作程序的,帮个忙了).
 如果您有什么改过,记得告诉我!
*/


.dgInit
{
 over
:expression(((this.readyState=="complete") && (this.className=="dg")) || (
 (
 __evlon_init_tr=function(objTable){
 var i
;
 for(i=0;i<objTable.rows.length;i++){
  objTable.rows[i].onmouseover=function(){this.className="dg_tr_mouseover"
}
;
  objTable.rows[i].onmouseout=function()
{this.className="dg_tr_normal"};
  objTable.rows[i].className="dg_tr_normal";
 }
 
 } 
 ) ,(__evlon_init_tr(this)), (this.className="dg")));
}


.dg
{
  
}


/*表格行的全局CSS设置*/
.dg_tr_mouseover,.dg_tr_normal
{
 font-style
: italic;
 color
:blue;

}

.dg_tr_normal
{
 background-color
:#ffffff;
 
}


/*表格行的 OnMouseOver 时的CSS设置*/
.dg_tr_mouseover
{
 background-color
:#cccccc;
 
}


文件名:hello.htm
------------------------------------------------------------------
<html>
<head>
<title></title>
<link href="myfont.css" rel="stylesheet" type="text/css">
</head>
<body >
<table class="dgInit"><!--只要这里加上 Class 就行了-->
  
<tr >  
    
<td> ni hao </td>
    
<td> ni hao </td>
    
<td> ni hao </td>
  
</tr>
  
<tr >  
    
<td> ni hao </td>
    
<td> ni hao </td>
    
<td> ni hao </td>
  
</tr>
</table>
</body>
</html> 
posted @ 2006-09-30 11:09 阿牛 阅读(185) 评论(0)  编辑
    BOOL CreateDirectories(LPCTSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes)
    {
        int nPos 
= 0;
        BOOL bCreated 
= FALSE;
        CString strPath 
= lpPathName;
        strPath
.Append("\\");
        strPath
.Replace("\\\\","\\");
        CString strTemp 
= strPath.Tokenize(_T("/\\"),nPos);

        
while(strTemp != "")
        {
            CString strCurrPath(strPath
.Mid(0,nPos));
            
if(!::SetCurrentDirectory(strCurrPath))
            {
                
if(!::CreateDirectory(strCurrPath,lpSecurityAttributes))
                {
                    
return FALSE;
                }
            }

            strTemp 
= strPath.Tokenize(_T("/\\"),nPos);
        }
        
return TRUE;    
    }

    
/*
    删除除指定类型文件的指定类型的文件,可指定是否包括子目录
    
*/
    BOOL DeleteFiles(LPCTSTR lpFilePatten
,LPCTSTR lpExceptFilePatten,LPCTSTR lpFilePath,BOOL bIncludeSubDir)
    {
        INT nPos 
= 0;
        TCHAR szOldPath[MAX_PATH];
        
::GetCurrentDirectory(MAX_PATH,szOldPath);
        CFileFind ff;
        CList
<CString> FilePathList;
        CMapStringToPtr mapExceptFileName;
        FilePathList
.AddTail(lpFilePath);
        BOOL nRet 
= TRUE;
        BOOL bFinded 
= FALSE;
        BOOL bUseExcept 
= _tcslen(lpExceptFilePatten) > 0;
        
while(FilePathList.GetCount() > 0)
        {
            CString strPath(FilePathList
.RemoveHead());
            
if(!::SetCurrentDirectory(strPath))
            {
                nRet 
=  FALSE;
                
break;
            }

            
if(bUseExcept > 0)
            {
                CString strEfp(lpExceptFilePatten)
,strEach;
                INT iPos 
= 0;
                strEach 
= strEfp.Tokenize(";",iPos);
                
while(strEach != "")
                {
                    bFinded 
= ff.FindFile(strEach);
                    
while(bFinded)
                    {
                        bFinded 
= ff.FindNextFile();
                        
if(!ff.IsDirectory())
                        {
                            mapExceptFileName
.SetAt(ff.GetFileName(),NULL);
                        }

                    }

                    ff
.Close();
                    
//下一个
                    strEach = strEfp.Tokenize(";",iPos);
                }


            }

            CString strfp(lpFilePatten)
,strEach;
            INT iPos 
= 0;
            strEach 
= strfp.Tokenize(";",iPos);
            
while(strEach != "")
            {

                bFinded 
= ff.FindFile(strEach);
                
while(bFinded)
                {
                    bFinded 
= ff.FindNextFile();
                    
if(!ff.IsDirectory())
                    {
                        
if(bUseExcept)
                        {
                            LPVOID value;
                            CString strKey(ff
.GetFileName());
                            
if(mapExceptFileName.Lookup(strKey,value))
                            {
                                mapExceptFileName
.RemoveKey(strKey);
                            }
                            
else
                            {
                                
::DeleteFile(strKey);
                            }
                        }
                        
else
                        {
                            
::DeleteFile(ff.GetFileName());
                        }
                    }

                }

                ff
.Close();
                
//下一个
                strEach = strfp.Tokenize(";",iPos);
            }

            
if(bIncludeSubDir)
            {
                bFinded 
= ff.FindFile(_T("*.*"));
                
while( bFinded)
                {
                    bFinded 
= ff.FindNextFile();
                    
if(ff.IsDirectory())
                    {
                        CString strPathName 
= ff.GetFileName();
                        
if(strPathName != "." && strPathName != "..")
                        {
                            FilePathList
.AddTail(strPath +"\\" +  ff.GetFileName());
                        }
                    }
                }

                ff
.Close();
            }

        }

        
if(_tcslen(szOldPath) > 0)
        {
            
::SetCurrentDirectory(szOldPath);    
        }
    
        
return nRet;
    }

    BOOL ReadHLMRegKey(LPSTR pPath
, LPSTR pKey, LPVOID pValue /*最长512Byte*/)
    {
        HKEY    hKey;
        DWORD    dwValType
, 
                dwBuffLen 
= 512;

        
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, pPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 
        {
            
if(RegQueryValueEx(hKey, pKey, NULL, &dwValType, (LPBYTE) pValue, &dwBuffLen) == ERROR_SUCCESS)
            {
                RegCloseKey(hKey);
                
return TRUE;
            }
            RegCloseKey(hKey);
        }
        
return FALSE;
    }
posted @ 2006-09-30 10:57 阿牛 阅读(155) 评论(0)  编辑

在写SQL语句时,我们经常用到如下的语句:

dim collIds

collIds=“2,3,4,5,..........8999“

sql=“delete form  TableA where a.nid in (“ & collIds & “)“

conn.execute sql

''  这时,如果 collIds 太长,我们需要分多次执行才能成功, SQL语名最多才4000行,如果超出去,要失败的.

这时我们可能想这样执行:

sql=“delete form  TableA where a.nid in (1,2,3)“

rs.open sql ,conn,1,1

sql=“delete form  TableA where a.nid in (4,52,7)“

rs.open sql ,conn,1,1

但是如何正确的分隔这些串呢?  我写了一个函数 :

写一个截字串的函数,方便组成SQL字串 
--------------------------------------------------------------------------------
 
在写SQL语句时,我们经常用到如下的语句:

dim collIds

collIds
=2,3,4,5,.8999

sql
=“delete form  TableA where a.nid in (“ & collIds & “)“

conn.execute sql 

''  这时,如果 collIds 太长,我们需要分多次执行才能成功, SQL语名最多才4000行,如果超出去,要失败的.

这时我们可能想这样执行:

sql
=“delete form  TableA where a.nid in (1,2,3)“

rs.open sql ,conn,
1,1

sql
=“delete form  TableA where a.nid in (4,52,7)“

rs.open sql ,conn,
1,1

但是如何正确的分隔这些串呢?  我写了一个函数 :

function mySplit(str,span,maxLenPerEle)
 
dim pos,temp,i
 
dim arr()
 
redim arr(len(str)/maxLenPerEle + 1)
 temp
=str
 i
=0
 
while(len(temp) > maxLenPerEle)
  pos
=instrRev(temp,span,maxLenPerEle,1)
  
if(pos>0then 
   arr(i)
=mid(temp,1,pos-1)
   temp
=mid(temp,pos+1)
   i
=i+1
  
end if
 
wend
 
if(len(temp)>0then
  arr(i)
=temp
 
end if
 
redim preserve arr(i)
 mySplit
=arr
end function 


'' 在使用时,我们这样

 arr
=mysplit(ygbhs,",",2000)
 
for each s in arr
  sql
="delete from table where nid in (" & s & ")"
  conn.execute sql 
 
next


 
posted @ 2006-09-30 10:54 阿牛 阅读(276) 评论(0)  编辑
问:怎么才能关掉一个用任务管理器关不了的进程?我前段时间发现我的机子里多了一个进程,只要开机就在,我用任务管理器却怎么关也关不了。  

  答1:杀进程很容易,随便找个工具都行。比如IceSword。关键是找到这个进程的启动方式,不然下次重启它又出来了。顺便教大家一招狠的。其实用Windows自带的工具就能杀大部分进程:
  c:\> ntsd -c q -p PID  

  只有System、SMSS.EXE和CSRSS.EXE不能杀。前两个是纯内核态的,最后那个是Win32子系统,ntsd本身需要它。ntsd从2000开始就是系统自带的用户态调试工具。被调试器附着(attach)的进程会随调试器一起退出,所以可以用来在命令行下终止进程。使用ntsd自动就获得了debug权限,从而能杀掉大部分的进程。ntsd会新开一个调试窗口,本来在纯命令行下无法控制,但如果只是简单的命令,比如退出(q),用-c参数从命令行传递就行了。Ntsd 按照惯例也向软件开发人员提供。只有系统开发人员使用此命令。用法:开个cmd.exe窗口,输入:  

  ntsd -c q -p PID  

  把最后那个PID,改成你要终止的进程的ID。如果你不知道进程的ID,任务管理器-> 进程选项卡-> 查看-> 选择列-> 勾上"PID(进程标识符)",然后就能看见了。

  答2:xp和win2003下还有两个好东东tasklist和tskill。tasklist能列出所有的进程,和相应的信息。tskill能查杀进程,语法很简单:tskill 程序名。
posted @ 2006-05-11 17:09 阿牛 阅读(119) 评论(0)  编辑
  一 前言
  
  首先要澄清一下名字的混淆:
  1 SSL(Secure Socket Layer)是netscape公司设计的主要用于web的安全传输协议。这种协议在WEB上获得了广泛的应用。
  2 IETF(www.ietf.org)将SSL作了标准化,即RFC2246,并将其称为TLS(Transport Layer Security),从技术上讲,TLS1.0与SSL3.0的差别非常微小。由于本文中没有涉及两者间的细小差别,本文中这两个名字等价。
  3 在WAP的环境下,由于手机及手持设备的处理和存储能力有限,wap论坛(www.wapforum.org)在TLS的基础上做了...S协议(Wireless Transport Layer Security),以适应无线的特殊环境。
  
  我们从各式各样的文章中得知,SSL可以用于保密的传输,这样我们与web server之间传输的消息便是“安全的”。
  而这种“安全”究竟是怎么实现的,最终有能实现多大程度的保密?本文希望能用通俗的语言阐明其实现原理。
  
  
  二 整体结构概览
  
  SSL是一个介于HTTP协议与TCP之间的一个可选层,其位置大致如下:
  
  ---------
  | HTTP |
  ---------
  | SSL |
  ---------
  | TCP |
  ---------
  | IP |
  ---------
  
  如果利用SSL协议来访问网页,其步骤如下:
  用户:在浏览器的地址栏里输入https://www.sslserver.com
  HTTP层:将用户需求翻译成HTTP请求,如
  GET /index.htm HTTP/1.1
  Host http://www.sslserver.com
  
  SSL层: 借助下层协议的的信道安全的协商出一份加密密钥,并用此密钥来加密HTTP请求。
  TCP层:与web server的443端口建立连接,传递SSL处理后的数据。
  
  接收端与此过程相反。
  
  SSL在TCP之上建立了一个加密通道,通过这一层的数据经过了加密,因此达到保密的效果。
  
  SSL协议分为两部分:Handshake Protocol和Record Protocol,。其中Handshake Protocol用来协商密钥,协议的大部分内容就是通信双方如何利用它来安全的协商出一份密钥。 Record Protocol则定义了传输的格式。
  
  
  三 需要的加密方面的基础知识
  了解SSL原理需要一点点加密的概念,这里把需要的概念做一下简单阐述:
  
  加密一般分为三类,对称加密,非对称加密及单向散列函数。
  
  对称加密:又分分组密码和序列密码。
  分组密码是将明文按一定的位长分组,明文组经过加密运算得到密文组,密文组经过解密运算
  (加密运算的逆运算),还原成明文组。
  序列密码是指利用少量的密钥(制乱元素)通过某种复杂的运算(密码算法)产生大量的伪随机位流,用于对明文位流的加密。
  解密是指用同样的密钥和密码算法及与加密相同的伪随机位流,用以还原明文位流。
  
  CBC(Cipher Block Chaining)模式这个词在分组密码中经常会用到,它是指一个明文分组在被加密之前要与前一个的密文分组进行异或运算。当加密算法用于此模式的时候除密钥外,还需协商一个初始化向量(IV),这个IV没有实际意义,只是在第一次计算的时候需要用到而已。采用这种模式的话安全性会有所提高。
  
  分组密码的典型例子为DES,RC5,IDEA。
  序列密码的典型例子为RC4。
  
  公钥加密:
  简单的说就是加密密钥与解密密钥不同,分私钥和公钥。这种方法大多用于密钥交换,RSA便是一个我们熟知的例子。
  还有一个常用的称作DH,它只能用于密钥交换,不能用来加密。
  
  单向散列函数:
  由于信道本身的干扰和人为的破坏,接受到的信息可能与原来发出的信息不同,一个通用的办法就是加入校验码。
  单向散列函数便可用于此用途,一个典型的例子是我们熟知的MD5,它产生128位的摘要,在现实中用的更多的是安全散列算法(SHA),SHA的早期版本存在问题,目前用的实际是SHA-1,它可以产生160位的摘要,因此比128位散列更能有效抵抗穷举攻击。
  
  由于单向散列的算法都是公开的,所以其它人可以先改动原文,再生成另外一份摘要。解决这个问题的办法可以通过HMAC(RFC 2104),它包含了一个密钥,只有拥有相同密钥的人才能鉴别这个散列。
  
  
  四 密钥协商过程
  
  由于对称加密的速度比较慢,所以它一般用于密钥交换,双方通过公钥算法协商出一份密钥,然后通过对称加密来通信,当然,为了保证数据的完整性,在加密前要先经过HMAC的处理。
  
  
  SSL缺省只进行server端的认证,客户端的认证是可选的。以下是其流程图(摘自TLS协议)。
  
  
  Client Server
  
  Clienth*llo -------->
  Serverh*llo
  Certificate*
  ServerKeyExchange*
  CertificateRequest*
  <-------- Serverh*lloDone
  Certificate*
  ClientKeyExchange
  CertificateVerify*
  [ChangeCipherSpec]
  Finished -------->
  [ChangeCipherSpec]
  <-------- Finished
  Application Data <-------> Application Data
  
  简单的说便是:SSL客户端(也是TCP的客户端)在TCP链接建立之后,发出一个Clienth*llo来发起握手,这个消息里面包含了自己可实现的算法列表和其它一些需要的消息,SSL的服务器端会回应一个Serverh*llo,这里面确定了这次通信所需要的算法,然后发过去自己的证书(里面包含了身份和自己的公钥)。Client在收到这个消息后会生成一个秘密消息,用SSL服务器的公钥加密后传过去,SSL服务器端用自己的私钥解密后,会话密钥协商成功,双方可以用同一份会话密钥来通信了。
  
  
  五 密钥协商的形象化比喻
  
  如果上面的说明不够清晰,这里我们用个形象的比喻,我们假设A与B通信,A是SSL客户端,B是SSL服务器端,加密后的消息放在方括号[]里,以突出明文消息的区别。双方的处理动作的说明用圆括号()括起。
  
  A:我想和你安全的通话,我这里的对称加密算法有DES,RC5,密钥交换算法有RSA和DH,摘要算法有MD5和SHA。
  
  B:我们用DES-RSA-SHA这对组合好了。
  这是我的证书,里面有我的名字和公钥,你拿去验证一下我的身份(把证书发给A)。
  目前没有别的可说的了。
  
  A:(查看证书上B的名字是否无误,并通过手头早已有的CA的证书验证了B的证书的真实性,如果其中一项有误,发出警告并断开连接,这一步保证了B的公钥的真实性)
  (产生一份秘密消息,这份秘密消息处理后将用作加密密钥,加密初始化向量和hmac的密钥。将这份秘密消息-协议中称为per_master_secret-用B的公钥加密,封装成称作ClientKeyExchange的消息。由于用了B的公钥,保证了第三方无法窃听)
  我生成了一份秘密消息,并用你的公钥加密了,给你(把ClientKeyExchange发给B)
  注意,下面我就要用加密的办法给你发消息了!
  (将秘密消息进行处理,生成加密密钥,加密初始化向量和hmac的密钥)
  [我说完了]
  
  B:(用自己的私钥将ClientKeyExchange中的秘密消息解密出来,然后将秘密消息进行处理,生成加密密钥,加密初始化向量和hmac的密钥,这时双方已经安全的协商出一套加密办法了)
  注意,我也要开始用加密的办法给你发消息了!
  [我说完了]
  
  A: [我的秘密是...]
  
  B: [其它人不会听到的...]
  
  
  六 加密的计算
  上一步讲了密钥的协商,但是还没有阐明是如何利用加密密钥,加密初始化向量和hmac的密钥来加密消息的。
  其实其过程不过如此:
  1 借助hmac的密钥,对明文的消息做安全的摘要处理,然后和明文放到一起。
  2 借助加密密钥,加密初始化向量加密上面的消息。
  
  
  七 安全性
  SecurityPortal在2000年底有一份文章《The End of SSL and SSH?》激起了很多的讨论,
  目前也有一些成熟的工具如dsniff(http://www.monkey.org/~dugsong/dsniff/)可以
  通过man in the middle攻击来截获https的消息。
  
  从上面的原理可知,SSL的结构是严谨的,问题一般出现在实际不严谨的应用中。常见的攻击就是
  middle in the middle攻击,它是指在A和B通信的同时,有第三方C处于信道的中间,可以完全
  听到A与B通信的消息,并可拦截,替换和添加这些消息。
  
  1 SSL可以允许多种密钥交换算法,而有些算法,如DH,没有证书的概念,这样A便无法验证B的公钥
  和身份的真实性,从而C可以轻易的冒充,用自己的密钥与双方通信,从而窃听到别人谈话的内容。
  而为了防止middle in the middle攻击,应该采用有证书的密钥交换算法。
  2 有了证书以后,如果C用自己的证书替换掉原有的证书之后,A的浏览器会弹出一个警告框进行警告,但又有多少人会注意这个警告呢?
  3 由于美国密码出口的限制,IE,netscape等浏览器所支持的加密强度是很弱的,如果只采用浏览器自带的加密功能的话,理论上存在被破解可能。
  
  
  八 代理
  下面探讨一下SSL的代理是怎样工作的(可参见[6])。这可能与你开始想的不太一样:)
  当在浏览器里设置了https的代理,而且在浏览器里输入了https://www.example.com之后,
  浏览器会与proxy建立tcp链接,然后向其发出这么一段消息:
  CONNECT server.example.com:443 HTTP/1.1
  Host: server.example.com:443
  
  然后proxy会向webserver端建立tcp连接,之后,这个代理便完全成了个内容转发装置。浏览器
  与web server会建立一个安全通道,因此这个安全通道是端到端的,尽管所有的信息流过了proxy,
  但其内容proxy是无法解密和改动的(当然要由证书的支持,否则这个地方便是个man in the middle攻击的好场所,见上面的讨论)。
  
  
  九 关于证书
  
  注意,如果对于一般的应用,管理员只需生成“证书请求”(后缀大多为.csr),它包含你的名字和公钥,然后把这份请求交给诸如verisign等有CA服务公司(当然,连同几百美金),
  你的证书请求经验证后,CA用它的私钥签名,形成正式的证书发还给你。管理员再在web server上导入这个证书就行了。如果你不想花那笔钱,或者想了解一下原理,可以自己做CA。
  从ca的角度讲,你需要CA的私钥和公钥。从想要证书的服务器角度将,需要把服务器的证书请求交给CA.
  
  如果你要自己做CA,别忘了客户端需要导入CA的证书(CA的证书是自签名的,导入它意味着你“信任”这个CA签署的证书)。
  而商业CA的一般不用,因为它们已经内置在你的浏览器中了。

=======

 
 
SSL认证机构是干什么的,在电子商务中如何实现?
来源:ChinaITLab
2003-1-15 0:52:00
 

  一.协议的起源
  随着计算机网络技术向整个经济社会各层次延伸,整个社会表现对Internet、Intranet
  、Extranet等使用的更大的依赖性。随着企业间信息交互的不断增加,任何一种网络应用和增值服务的使用程度将取决于所使用网络的信息安全有无保障,网络安全已成为现代计算机网络应用的最大障碍,也是急需解决的难题之一。
  由于Web上有时要传输重要或敏感的数据,因此Netscape公司在推出Web浏览器首版的同时,提出了安全通信协议SSL(Secure Socket Layer),目前已有2.0和3.0版本。SSL采用公开密钥技术。其目标是保证两个应用间通信的保密性和可靠性,可在服务器和客户机两端同时实现支持。目前,利用公开密钥技术的SSL协议,并已成为Internet上保密通讯的工业标准。现行Web浏览器普遍将HTTP和SSL相结合,从而实现安全通信。
  二.协议概述
  安全套接层协议(SSL)是在Internet基础上提供的一种保证私密性的安全协议。它能使客户/服务器应用之间的通信不被攻击者窃听,并且始终对服务器进行认证,还可选择对客户进行认证。SSL协议要求建立在可靠的传输层协议(例如:TCP)之上。SSL协议的优势在于它是与应用层协议独立无关的。高层的应用层协议(例如:HTTP,FTP,TELNET。。。
  。。。)能透明的建立于SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商以及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。
  通过以上叙述,SSL协议提供的安全信道有以下三个特性:
  ? 私密性。因为在握手协议定义了会话密钥后,所有的消息都被加密。
  ? 确认性。因为尽管会话的客户端认证是可选的,但是服务器端始终是被认证的。
  ? 可靠性。因为传送的消息包括消息完整性检查(使用MAC)。
  三.协议规范
  SSL协议由SSL记录协议和SSL握手协议两部分组成。
  1. SSL记录协议:
  在SSL协议中,所有的传输数据都被封装在记录中。记录是由记录头和长度不为0的记录数据组成的。所有的SSL通信包括握手消息、安全空白记录和应用数据都使用SSL记录层。SSL记录协议包括了记录头和记录数据格式的规定。
  1) SSL记录头格式:
  SSL的记录头可以是两个或三个字节长的编码。SSL记录头的包含的信息包括:记录头的
  长度、记录数据的长度、记录数据中是否有粘贴数据。其中粘贴数据是在使用块加密算
  法时,填充实际数据,使其长度恰好是块的整数倍。最高位为1时,不含有粘贴数据,记
  录头的长度为两个字节,记录数据的最大长度为32767个字节;最高位为0时,含有粘贴
  数据,记录头的长度为三个字节,记录数据的最大长度为16383个字节。
  当数据头长度是三个字节时,次高位有特殊的含义。次高位为1时,标识所传输的记录是
  普通的数据记录;次高位为0时,标识所传输的记录是安全空白记录(被保留用于将来协
  议的扩展)。
  记录头中数据长度编码不包括数据头所占用的字节长度。记录头长度为两个字节的记录长度的计算公式:记录长度=((byte[0] ; 0x7f) <;<; 8)) | byte[1]。其中byte[0]、byte[1]分别表示传输的第一个、第二个字节。记录头长度为三个字节的记录长度的计算公式:记录长度=((byte[0] ; 0x3f) <;<; 8)) | byte[1]。其中byte[0]、byte[1]的含义同上。判断是否是安全空白记录的计算公式:(byte[0] ; 0x40) != 0。粘贴数据的长度为传输的第三个字节。
  2) SSL记录数据的格式:
  SSL的记录数据包含三个部分:MAC数据、实际数据和粘贴数据。
  MAC数据用于数据完整性检查。计算MAC所用的散列函数由握手协议中的CIPHER-CHOICE消息确定。若使用MD2和MD5算法,则MAC数据长度是16个字节。MAC的计算公式:MAC数据=HASH[密钥,实际数据,粘贴数据,序号]。当会话的客户端发送数据时,密钥是客户的写密钥(服务器用读密钥来验证MAC数据);而当会话的客户端接收数据时,密钥是客户的读密钥(服务器用写密钥来产生MAC数据)。序号是一个可以被发送和接收双方递增的计数器。每个通信方向都会建立一对计数器,分别被发送者和接收者拥有。计数器有32位,计数值循环使用,每发送一个记录计数值递增一次,序号的初始值为0。
  2. SSL握手协议:
  SSL握手协议包含两个阶段,第一个阶段用于建立私密性通信信道,第二个阶段用于客户认证。
  1) 第一阶段:
  第一阶段是通信的初始化阶段,通信双方都发出HELLO消息。当双方都接收到HELLO消息时,就有足够的信息确定是否需要一个新的密钥。若不需要新的密钥,双方立即进入握手协议的第二阶段。否则,此时服务器方的SERVER-HELLO消息将包含足够的信息使客户方产生一个新的密钥。这些信息包括服务器所持有的证书、加密规约和连接标识。若密钥产生成功,客户方发出CLIENT-MASTER-KEY消息,否则发出错误消息。最终当密钥确定以后,服务器方向客户方发出SERVER-VERIFY消息。因为只有拥有合适的公钥的服务器才能解开密钥。下图为第一阶段的流程:
  需要注意的一点是每一通信方向上都需要一对密钥,所以一个连接需要四个密钥,分别为客户方的读密钥、客户方的写密钥、服务器方的读密钥、服务器方的写密钥。
  2) 第二阶段:
  第二阶段的主要任务是对客户进行认证,此时服务器已经被认证了。服务器方向客户发出认证请求消息:REQUEST-CERTIFICATE。当客户收到服务器方的认证请求消息,发出
  自己的证书,并且监听对方回送的认证结果。而当服务器收到客户的认证,认证成功返回SERVER-FINISH消息,否则返回错误消息。到此为止,握手协议全部结束。
  3. 典型的协议消息流程:
  消息名 方向 内容
  不需要新密钥
  CLIENT-HELLO C->;S challenge, session_id, cipher_specs
  SERVER-HELLO S->;C connection-id, session_id_hit
  CLIENT-FINISH C->;S Eclient_write_key[connection-id]
  SERVER-VERIFY S->;C Eserver_write_key[challenge]
  SERVER-FINISH S->;C Eserver_write_key[session_id]
  需要新密钥
  CLIENT-HELLO C->;S challenge, cipher_specs
  SERVER-HELLO S->;C connection-id,server_certificate,cipher_specs
  CLIENT-MASTER-KEY C->;S Eserver_public_key[master_key]
  CLIENT-FINISH C->;S Eclient_write_key[connection-id]
  SERVER-VERIFY S->;C Eserver_write_key[challenge]
  SERVER-FINISH S->;C Eserver_write_key[new_session_id]
  需要客户认证
  CLIENT-HELLO C->;S challenge, session_id, cipher_specs
  SERVER-HELLO S->;C connection-id, session_id_hit
  CLIENT-FINISH C->;S Eclient_write_key[connection-id]
  SERVER-VERIFY S->;C Eserver_write_key[challenge]
  REQUEST-CERTIFICATE S->;C Eserver_write_key[auth_type,challenge']
  CLIENT-CERTIFICATE C->;S Eclient_write_key[cert_type,client_cert,response_data]
  SERVER-FINISH S->;C Eserver_write_key[session_id]
  四.相关技术:
  1. 加密算法和会话密钥:
  如前所述,加密算法和会话密钥是在握手协议中协商并有CIPHER-CHOICE指定的。现有的SSL版本中所用到的加密算法包括:RC4、RC2、IDEA和DES,而加密算法所用的密钥由消息散列函数MD5产生。RC4、RC2是由RSA定义的,其中RC2适用于块加密,RC4适用于流加密。下述为CIPHER-CHIOCE的可能取值和会话密钥的计算:
  SSL_CK_RC4_128_WITH_MD5
  SSL_CK_RC4_128_EXPORT40_WITH_MD5
  SSL_CK_RC2_128_CBC_WITH_MD5
  SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5
  SSL_CK_IDEA_128_CBC_WITH_MD5
  KEY-MATERIAL-0 = MD5[ MASTER-KEY, ";0";, CHALLENGE, CONNECTION-ID ]
  KEY-MATERIAL-1 = MD5[ MASTER-KEY, ";1";, CHALLENGE, CONNECTION-ID ]
  CLIENT-READ-KEY = KEY-MATERIAL-0[0-15]
  CLIENT-WRITE-KEY = KEY-MATERIAL-1[0-15]
  SSL_CK_DES_64_CBC_WITH_MD5
  KEY-MATERIAL-0 = MD5[ MASTER-KEY, CHALLENGE, CONNECTION-ID ]
  CLIENT-READ-KEY = KEY-MATERIAL-0[0-7]
  CLIENT-WRITE-KEY = KEY-MATERIAL-0[8-15]
  SSL_CK_DES_192_EDE3_CBC_WITH_MD5
  KEY-MATERIAL-0 = MD5[ MASTER-KEY, ";0";, CHALLENGE, CONNECTION-ID ]
  KEY-MATERIAL-1 = MD5[ MASTER-KEY, ";1";, CHALLENGE, CONNECTION-ID ]
  KEY-MATERIAL-2 = MD5[ MASTER-KEY, ";2";, CHALLENGE, CONNECTION-ID ]
  CLIENT-READ-KEY-0 = KEY-MATERIAL-0[0-7]
  CLIENT-READ-KEY-1 = KEY-MATERIAL-0[8-15]
  CLIENT-READ-KEY-2 = KEY-MATERIAL-1[0-7]
  CLIENT-WRITE-KEY-0 = KEY-MATERIAL-1[8-15]
  CLIENT-WRITE-KEY-1 = KEY-MATERIAL-2[0-7]
  CLIENT-WRITE-KEY-2 = KEY-MATERIAL-2[8-15]其中KEY-MATERIAL-0[0-15]表示KEY-MATERIAL-0中的16个字节,KEY-MATERIAL-0[0-7]表示KEY-MATERIAL-0中的头8个字节,KEY-MATERIAL-1[8-15]表示KEY-MATERIAL-0中的第9个字节到第15个字节。其他类似形式有相同的含义。";0";、";1";表示数字0、1的ASCII码0x30、0x31。
  2. 认证算法:
  认证算法采用X。509电子证书标准,通过使用RSA算法进行数字签名来实现的。
  1) 服务器的认证:
  在上述的两对密钥中,服务器方的写密钥和客户方的读密钥、客户方的写密钥和服务器方的读密钥分别是一对私有、公有密钥。对服务器进行认证时,只有用正确的服务器方写密钥加密CLIENT-HELLO消息形成的数字签名才能被客户正确的解密,从而验证服务器的身分。
  若通信双方不需要新的密钥,则它们各自所拥有的密钥已经符合上述条件。若通信双方需要新的密钥。首先服务器方在SERVER-HELLO消息中的服务器证书中提供了服务器的公
  有密钥,服务器用其私有密钥才能正确的解密由客户方使用服务器的公有密钥加密的MASTER-KEY

posted @ 2006-03-27 13:54 阿牛 阅读(719) 评论(0)  编辑
posted @ 2006-03-22 10:09 阿牛 阅读(257) 评论(0)  编辑