首页 > 编程语言 >驱动程序安装之设备协安装器

驱动程序安装之设备协安装器

时间:2022-11-07 21:40:18浏览次数:36  
标签:驱动程序 00000000 安装 DrvInst Device SampleChar NT 设备


    年前想把一个功能驱动和过滤驱动传到wu上,但是因为过滤驱动和第三方厂商驱动的hardwareid值相同,直接传到wu上后用户一旦更新会有问题。一个同事提到一个解决方案:把过滤驱动的hardwareid改成一个无关紧要的id,然后为功能驱动的inf文件附加一个协安装器(coinstaller),把他们一起传到wu上。这样,当用户更新功能驱动时,通过coinstaller启动过滤驱动安装程序来加载过滤驱动。

    这样说可能还是有点空洞,让我用前面的SampleChar驱动来解释同事的方法。SampleChar是一个功能驱动,这个驱动安装包中只有sys/inf文件(测试驱动不包含cat文件):SampleChar.sys/SampleChar.inf,用户通过inf来安装功能驱动。以下是SampleChar.inf的内容:

[Version]
Signature="$WINDOWS NT$"
Class=System
ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}
Provider=%ProviderName%
DriverVer=12/19/2016,15.52.17.267
CatalogFile=SampleChar.cat

[DestinationDirs]
DefaultDestDir = 12

[SourceDisksNames]
1 = %DiskName%,,,""

[SourceDisksFiles]
SampleChar.sys = 1,,

[Manufacturer]
%ManufacturerName%=Standard

[Standard]
%SampleChar_Desc%=SampleChar_Device, ROOT\Sample

[SampleChar_Device.NT]
CopyFiles=Drivers_Dir

[SampleChar_Device.NT.HW]
AddReg=SampleChar_Device.NT.AddReg

[SampleChar_Device.NT.AddReg]
HKR,,DeviceCharacteristics,0x10001,0x0100
HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)"

[Drivers_Dir]
SampleChar.sys

[SampleChar_Device.NT.Services]
AddService=SampleChar,%SPSVCINST_ASSOCSERVICE%,SampleChar_Service_Inst

[SampleChar_Service_Inst]
DisplayName = %sampleChar.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\SampleChar.sys
LoadOrderGroup = Extended Base

[Strings]
ManufacturerName="Eugen"
ClassName=""
DiskName="SampleChar Source Disk"
ProviderName="Eugen"
SampleChar_Desc="SampleChar"
sampleChar.SVCDESC="Sample char driver"
SPSVCINST_ASSOCSERVICE= 0x00000002

    为了能在安装SampleChar.sys过程中运行设备协安装器,就需要修改inf文件的内容,为drvinst.exe(windows驱动安装程序)指明安装过程中用到的协安装器文件名及其入口点。

[Version]
Signature="$WINDOWS NT$"
Class=System
ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}
Provider=%ProviderName%
DriverVer=2016/11/18, 1.0.0
CatalogFile=SampleChar.cat

[DestinationDirs]
DefaultDestDir = 12
CoInstaller_CopyFiles=11 ;协安装器文件拷贝相关内容

[SourceDisksNames]
1 = %DiskName%,,,""

[SourceDisksFiles]
SampleChar.sys = 1,,
ConInstall.dll=1,, ;协安装器源文件列表

[Manufacturer]
%ManufacturerName%=Standard

[Standard]
%SampleChar_Desc%=SampleChar_Device, ROOT\Sample

[SampleChar_Device.NT]
CopyFiles=SampleChar_Device.NT.Copy

[SampleChar_Device.NT.HW]
AddReg=SampleChar_Device.NT.HW.AddReg

[SampleChar_Device.NT.HW.AddReg]
HKR,,DeviceCharacteristics,0x10001,0x0100
HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)"

[SampleChar_Device.NT.Copy]
SampleChar.sys

[SampleChar_Device.NT.Services]
AddService=SampleChar,%SPSVCINST_ASSOCSERVICE%,SampleChar_Service_Inst

[SampleChar_Service_Inst]
DisplayName = %sampleChar.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\SampleChar.sys
LoadOrderGroup = Extended Base

[SampleChar_Device.NT.CoInstallers] ;设备协安装器安装节
AddReg=CoInstaller_AddReg
CopyFiles=CoInstaller_CopyFiles

[CoInstaller_CopyFiles]
ConInstall.dll

[CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000,"ConInstall.dll,CoInstaller" ;指明协安装器文件名和入口函数名

    仅仅有inf文件还不够,还需要提供dll形式的协安装器并导出函数名。以下是我自定义的协安装器,其目的是在驱动安装过程中创建notepad子程序。

DWORD CALLBACK CoInstaller(DI_FUNCTION DifCode, 
HDEVINFO devInfoset,
PSP_DEVINFO_DATA devInfoData,
PCOINSTALLER_CONTEXT_DATA Context)
{
FILE* fp = NULL;
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;

_asm int 3;

switch(DifCode)
{
case DIF_INSTALLDEVICE:
CreateProcess(NULL,
"notepad",
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
DbgOut("DIF_INSTALLDEVICE");
break;

default:
DbgOut("?????");
break;
}

return NO_ERROR;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved)
{
_asm int 3;
return TRUE;
}



   函数本身很简单,但需要注意的地方有很多:

1.函数的接口形式。设备协安装器的接口形式和类安装器的接口形式有点相像,

类安装器的接口形式:

DWORD CALLBACK ClassInstaller(DI_FUNCTION,HDEVINFO,PSP_DEVINFO_DATA);

如果inf文件中用到了[classinstall32]节,那么就需要以这种形式提供类安装器。


本文提到的设备协安装器的接口形式,比类安装器多一个参数:

DWORD CALLBACK DevInstaller(DI_FUNCTION,HDEVINFO,PSP_DEVINFO_DATA,PCOINSTALLER_CONTEXT_DATA);

如果inf文件中用到了[.CoInstallers]节,就需要提供这种形式的设备安装器。如果不加以区分,会导致安装失败。

2.函数导出名字。一般大家都会用vs编译生成协安装器DLL,默认导出的函数名是c++形式的,即_func@nXYZ的形式。会和inf文件中指定的函数名不一致,导致无法安装成功。因此建议大家在dll生成后,用dependence工具查看一下函数名是否和预期的一致。


3.调用时机。驱动安装时,会加载设备安装器,这是会调用dll的通用接口----DllMain;之后,协安装器会响应SETUPAPI!SetupDiCallClassInstaller发出的各种DI_FUNCTION功能码,进入协安装器入口。就是这里的CoInstaller函数:

DWORD CALLBACK CoInstaller(DI_FUNCTION,HDEVINFO,PSP_DEVINFO_DATA,PCOINSTALLER_CONTEXT_DATA);

这可以在协安装器中增加int 3断点来观察。首次运行devcon.exe安装SampleChar时,windbg会遇到int 3异常。

Break instruction exception - code 80000003 (first chance) ;第一次遇到int 3异常
001b:70d91a95 cc int 3
kd> .symfix C:\symbols\w7RTMx86
kd> .sympath+ C:\studio\classinstaller\objchk_win7_x86\i386
Symbol search path is: srv*;C:\studio\classinstaller\objchk_win7_x86\i386
Expanded Symbol search path is: SRV*C:\symbols\w7RTMx86*http://msdl.microsoft.com/download/symbols;c:\studio\classinstaller\objchk_win7_x86\i386
kd> .reload /user ;因为现在是内核态调试,所以要手动加载用户态调试符号
Loading User Symbols
.......................................
kd> kb ;通过函数调用栈,可以看到drvinst首先会用LdrLoadDll加载模块,然后调用dll的DllMain函数
ChildEBP RetAddr Args to Child
0065df58 70d91d86 70d90000 00000001 00000000 ConInstall!DllMain+0x5 [c:\studio\classinstaller\coninstall.c @ 152] ;调用DllMain函数
0065dfb8 77ccaf24 70d90000 00000001 00000000 ConInstall!__DllMainCRTStartup+0xe1 [d:\5359\minkernel\crts\crtw32\dllstuff\crtdll.c @ 573]
0065dfd8 77ccfd2e 70d91f06 70d90000 00000001 ntdll!LdrpCallInitRoutine+0x14
0065e0cc 77cd01db 00000000 77b5b4fe 77cb70da ntdll!LdrpRunInitializeRoutines+0x26f
0065e238 77ccf5f9 0065e298 0065e264 00000000 ntdll!LdrpLoadDll+0x4d1
0065e26c 7607b8a4 00211ebc 0065e2ac 0065e298 ntdll!LdrLoadDll+0x92
0065e2a4 767f57c9 00000000 00000000 00000001 KERNELBASE!LoadLibraryExW+0x15a
0065e928 7680e414 ffffffff 00228e10 7680e480 SETUPAPI!GetModuleEntryPoint+0x2ca
0065e9ac 767f479a 00216150 0065fbf0 0021d214 SETUPAPI!pSetupDiGetCoInstallerList+0x275
0065eebc 767f44f8 00000020 00216150 0065fbf0 SETUPAPI!_SetupDiCallClassInstaller+0x742
0065ef04 004cf951 00000020 00216150 0065fbf0 SETUPAPI!SetupDiCallClassInstaller+0x4e
0065f95c 004d1246 00000080 00216150 0065fbf0 DrvInst!InstallSelectedDeviceDriver+0xbfd
0065fba8 004d14ba 00000080 00216150 0065fbf0 DrvInst!InstallSpecificDriver+0x152
0065fc10 004cbf0b 00000002 00000080 006a22c0 DrvInst!pHandleDeviceInstall+0x11a
0065fc64 76751174 001af9cc 0065fcb0 77ccb3f5 DrvInst!HandleDeviceInstallEntry+0x2f
0065fc70 77ccb3f5 001af9cc 77b5aa76 00000000 kernel32!BaseThreadInitThunk+0xe
0065fcb0 77ccb3c8 004cbedc 001af9cc 00000000 ntdll!__RtlUserThreadStart+0x70
0065fcc8 00000000 004cbedc 001af9cc 00000000 ntdll!_RtlUserThreadStart+0x1b
kd> lm
start end module name
004a0000 004e1000 DrvInst (pdb symbols) C:\symbols\w7RTMx86\DrvInst.pdb\6373CA6671B7426686B254FE79AC602F1\DrvInst.pdb
70d90000 70d95000 ConInstall (private pdb symbols) c:\studio\classinstaller\objchk_win7_x86\i386\ConInstall.pdb

当调用DllMain后,CoInstall开始等待并响应安装管理模块的SETUPAPI!SetupDiCallClassInstaller消息,

并且由于安装管理模块会多次发出DI_FUNCTION消息,设备协安装器的安装入口会多次被调用,因此这里需要妥善处理全局变量:

kd> g
Break instruction exception - code 80000003 (first chance)
ConInstall!CoInstaller+0x26:
001b:70d91766 cc int 3
kd> kb
ChildEBP RetAddr Args to Child
0065e9ac 7680e2be 00000020 00216150 0065fbf0 ConInstall!CoInstaller+0x26 [c:\studio\classinstaller\coninstall.c @ 19] ;调用CoInstaller函数
0065eebc 767f44f8 00000020 00216150 0065fbf0 SETUPAPI!_SetupDiCallClassInstaller+0x95f
0065ef04 004cf951 00000020 00216150 0065fbf0 SETUPAPI!SetupDiCallClassInstaller+0x4e
0065f95c 004d1246 00000080 00216150 0065fbf0 DrvInst!InstallSelectedDeviceDriver+0xbfd
0065fba8 004d14ba 00000080 00216150 0065fbf0 DrvInst!InstallSpecificDriver+0x152
0065fc10 004cbf0b 00000002 00000080 006a22c0 DrvInst!pHandleDeviceInstall+0x11a
0065fc64 76751174 001af9cc 0065fcb0 77ccb3f5 DrvInst!HandleDeviceInstallEntry+0x2f
0065fc70 77ccb3f5 001af9cc 77b5aa76 00000000 kernel32!BaseThreadInitThunk+0xe
0065fcb0 77ccb3c8 004cbedc 001af9cc 00000000 ntdll!__RtlUserThreadStart+0x70
0065fcc8 00000000 004cbedc 001af9cc 00000000 ntdll!_RtlUserThreadStart+0x1b


4.被设备协安装器调用启动的可执行程序的账户。我初次调试时一直没有看到notepad程序界面,因此怀疑程序是不是错了。但CreateProcess每次都返回TRUE。这就很疑惑了,notepad去哪了?

驱动程序安装之设备协安装器_5e


任务栏上并没有notepad的踪迹,但任务管理器中的确可以看到notepad进程在运行。最重要的一点,发起它的用户是System----和service的用户一样,都是system在session 0中,所以没有界面。

标签:驱动程序,00000000,安装,DrvInst,Device,SampleChar,NT,设备
From: https://blog.51cto.com/u_13927568/5831378

相关文章

  • Wdf框架:FxDriverEntry----驱动程序的入口函数
      在前面的文章<Wdf框架中WdfDriverGlobals对象的创建>中简单的提到过WdfVersionBind函数的作用,但是没有来得及分析这个函数的调用处。今天得空,借这篇文章写下WdfVersio......
  • 搜索驱动程序分配的内存和查看KEVENT状态
    问题的提出:(类似windbg~*kb命令)的调用栈不就行了。没错,对于应用程序而言,这样做十有八九已经定位了。但是,对于驱动程序而言,它运行的上下文可能并不固定在某一进程,回溯内核......
  • 安装CNPM失败
    npmERR!codeUNABLE_TO_VERIFY_LEAF_SIGNATUREnpmERR!errnoUNABLE_TO_VERIFY_LEAF_SIGNATUREnpmERR!requesttohttps://registry.npm.taobao.org/cnpmfailed,......
  • CentOS6.x安装RabbitMQ
    一、安装步骤第一步安装erlang环境(版本20.3)第二步安装RabbitMQ(版本3.7.15)版本依赖关系:https://www.rabbitmq.com/which-erlang.htmlErlang下载:https://erl......
  • 制作initrd(6):重做Ubuntu安装盘
      接上篇 ​​制作initrd(5):解剖Ubuntu安装盘​​ 。上一篇主要提到了分解Ubuntu安装盘,这篇是解剖的反过程--合成安装盘iso,内容相对比较少。  如果仅仅把安装盘......
  • 制作initrd(5):解剖Ubuntu安装盘
      ubuntu定期更新他们的iso,iso引导系统后会有Try/InstallUbuntu两个选项。特别是选择了livecd,仅仅一张盘子就能运行一个图形化的linux,总觉得挺神奇的。在好奇心的推动......
  • 如何从 snap 包安装ONLYOFFICE桌面版编辑器v7.2
    使用桌面版​​在线编辑器​​,无需保持互联网连接状态,也可处理您计算机上的离线文件。因此,如果您愿意,可以从我们的网站下载并安装桌面版编辑器,或者将带有它们代码库的链接添......
  • 多进程(线程)访问设备的一些疑惑
       同事在看设备驱动同步时,问了我一个事:如果驱动程序创建了一个设备,在应用层是否允许多个进程同时打开这个设备;如果允许,这种方式应用层和驱动的通信方式是否会相互影响......
  • 用blkid命令解读grub.cfg文件中的块设备
      ubuntu引导配置文件grub.cfg真是越来越难看懂了:启动菜单里找不到类似root=/dev/sda这种存放根文件系统的块设备名,取而代之的是一堆让人摸不着头脑的UUID:menuentry'......
  • windbg中通过文件句柄查找设备(!handle/!fileobj/!devobj命令)
      有时,在驱动程序中会调用ZwCreateFile获得设备句柄,然后保存在设备扩展区域中供其他例程使用。由于驱动程序经常被动调用----执行的上下文可能不是同一个线程----会获得......