特色

CommMonitor串口监控10 .0

2018-01-15

CommMonitor  串行端口监视精灵是用于RS232 / RS422 / RS485端口监控的专业强大的系统实用程序软件。CommMonitor监视显示,记录和分析系统中的所有串行端口活动。这是追踪应用程序或驱动程序开发,串行设备测试和优化等过程中可能出现的问题的理想方法。还提供过滤、搜索、数据导出和强大的数据拦截功能,可以将指定端口的数据流、控制流信息拦截并保存下来,供分析之用。如察看端口状态的变化(波特率、数据位、校验位、停止位),拦截上行、下行的数据,处理速度快,拦截效率高,并可以以十六进制、ASCII字符形式显示,全面支持Unicode   。

新增支持Socket TCP/UDP网络转发功能。

支持Windows系统版本:WinXP、Win2003、WinVista、Win7、Win2008、Win8、Win2012、Win2016、Win10,32/64位系统,驱动程序已签名,完全支持64位Windows系统。

语言支持:简体中文、繁体中文、英文三种语言。

CommMonitor 10

10.0更新日志:
—————————————
1、内核驱动升级,添加支持网络功能;
2、内核驱动增加监控日志毫秒级时间显示;
3、内核驱动增加支持大量数据缓存;
4、内核驱动增加动态加密,以保证数据传输的安全性;
5、CommMonitor主程序升级 ,支持监控TCP/UDP Socket远程服务器上的串口;
6、增加CommMonitorSvr服务启动监控,提供TCP/UDP 网络服务;
7、解决正在使用中的串口绑定失败问题,需要CommMonitorSvr服务启动;
8、SDK OCX增加监控日志驱动序号、进程名、及远程进程名;
9、SDK OCX增加TCP/UDP网络连接功能;
10、SDK OCX增加网络调用API、网络事件。

 

SDK DEMO 安装包里面已包含 :  DelphiXE7、 VS2012(C#,VC,VB.net) ActiveX  OCX调用示例。

CommMonitor 10.0下载地址:镜像下载1    镜像下载2​   非凡下载   华军下载

CEIWEI USBMonitor USB监控SDK OCX下载

CEIWEI USBMonitorX USB监控SDK 

版本:v2.3 Build:19053

USBMonitorX USB监控SDK,能够嵌入到你的App程序中,从而在你的App中实现USB端口协议分析、调试USB设备的协议信息,并可以拦截、记录USB程序操作USB设备In、Out数据包, 可以主动给USB端口发送你指定的数据包,从而改变端口协议调试输出。支持监控分析USB票据打印机、USB条码贴纸打印机、USB转串口等常见的USB设备。

关于HID,MTP等USB设备协议分析,请联系 CEIWEI。

支持Windows系统版本: WinXP、Win2003、WinVista、Win7、Win2008、Win8、Win2012、Win2016、Win10,32/64位系统。

以管理员权运行Regsvr32  全路径\USBMonitorX.dll

备注:Demo试用版, 会随机将URB数据前5字节替换成*****

下载SDK:http://www.ceiwei.com/mt/download/showdownload.php?lang=cn&id=3

CEIWEI USBMonitor SDK DEMO
CEIWEI USBMonitor SDK DEMO

SDK  OCX API接口C#语法说明

1.MonitorInit

功能: 初始化监控实例

参数: cKey String类型, 调用 Key, 对正式版有效

参数: cLicense String类型, 授权License, 对正式版有效

返回: Boolean类型,成功=True,失败=False

bool MonitorInit(string cKey, string cLicense);

2.DeviceIcons

功能: 获取TreeView控件Icons句柄,此Icons是系统设备信息IconIndex

参数: hTreeView  uint类型, 调用者传入TreeView.Handle句柄

返回: unint类型, 成功=Icons HWND,失败=0

uint DeviceIcons(uint hTreeView);

3. GetDeviceList

功能: 获取监控设备列表, 只有调用了此API事件OnAddDevice才能执行,具体参照OnAddDevice事件

参数: 无

返回: unint类型, 成功=设备数量>0,失败=0

uint GetDeviceList();

4. DeviceChild

功能: 用于判断设备所在的Parent节点

参数: cInstanceId String 类型,设备的Parent节点

参数:  cChildInstanceId String 类型,设备的Child节点

返回: Boolean类型, 成功=True表示是父子关系,失败=False

bool DeviceChild(string cInstanceId,  string cChildInstanceId);

5. MonitorDevice

功能: 设置设备监控状态

参数: deviceID uint类型,传入设备的Device ID

参数:  active  Boolean 类型, 传入设备的状态, True=表示开启监控, False=表示停止监控

返回: Boolean类型, 成功=True表示传入的状态值成功,失败=False

bool MonitorDevice(uint deviceID, bool active);

6. WriteData

功能: 主动向设备写入数据

参数: deviceID uint类型,传入设备的Device ID

参数: lpData Untype 类型,传入要写入的数据缓冲区

参数: dwSize int类型,传入数据缓冲区的长度

返回: boolean类型, 成功=True表示传入的状态值成功,失败=False

备注: 调用此功能function设备必须处于Open状态(也就是设备已经和应用层App在通信,建立了数据通道),否则调用是会阻塞进程;

bool WriteData(uint deviceID, object lpData, int dwSize);

7. LastError

功能: 获取最后出错的ErrorCode

参数: 无

返回: int类型, Error = 0 无错误, 大于0对应的Windows API Error Code

int LastError();

8. UrbFuncName

功能: 获取UrbFuncCode 的常量名称

参数: funcCode  uint类型,传入Urb FuncCode

返回: string类型,  UrbFuncCode 的常量名称

string UrbFuncName(uint funcCode);

9. InstallDrvier

功能: 安装驱动

参数: handle uint类型,传入调用者窗口句柄

返回: boolean类型, 成功=True,失败=True;

备注: 失败请调用LassError() 获取最后错误信息

bool InstallDrvier(uint handle);

10. UninstallDrvier

功能: 卸载驱动

参数: handle uint类型,传入调用者窗口句柄

返回: boolean类型, 成功=True,失败=True;

备注: 失败请调用LassError() 获取最后错误信息

bool UninstallDriver (uint handle);

11. ABout

功能: 显示关于对话框

参数: 无

返回: 弹出窗口

void About();

12. OnAddDevice 事件

功能: 配合GetDeviceList 添加系统设备

参数: uint deviceID, 设备ID

参数: bool enabled,设备监控开启状态, true=已开启,false=未开启

参数: int imageIndex, 设备所处系统 Icons的索引号

参数: string friendlyName, 设备显示名称

参数: string deviceName,  设备PDO名称

参数: string cInstanceId,设备实例 ID

Public OnAddDevice(uint deviceID, bool enabled, int imageIndex, string friendlyName, string deviceName, string cInstanceId);

13. OnUrb 事件

功能: 监控所有URB\PNP数据事件

参数: uint deviceID, 设备ID

参数: uint processID, 监控所在进程PID

参数: string funcCode, URB, PNP功能名

参数: string times,  监控时间戳

参数: string inOut,  数据方向, IN, OUT, PNP IRP

参数: int size, 数据大小

参数: object data, 数据缓冲区指针

public OnUrb(uint deviceID, uint processID, string funcCode, string times, string inOut, int size, object data);

下载SDK:http://www.ceiwei.com/mt/download/showdownload.php?lang=cn&id=3

CEIWEI USBMonitor USB监控精灵V2.3

 

CEIWEI USBMonitor监控精灵

是一款监控USB端口协议分析软件,用于监控和分析USB设备的活动,可以拦截、记录电脑和软件程序操作USB设备In、Out数据包。支持监控分析USB票据打印机、USB条码贴纸打印机、USB转串口等;使用USBMonitor能够有效提高工程师测试和优化USB与应用程序通信工作的效率。

支持Windows系统版本: WinXP、Win2003、WinVista、Win7、Win2008、Win8、Win2012、Win2016、Win10,32/64位系统。

支持语言:简体中文、繁体中文、英语三种语言。

 

CEIWEI USBMonitor

 

本地下载: CEIWEI USBMonitor2.3

Delphi 读取注册表REG_MULTI_SZ类型,注意事项

注意Delphi版本,网络上的代码大多是Delphi7基于Ansi编码格式读取,默认的PChar是AnsiChar,不是WideChar,这样的代码是不能用在Delphi XE或以后的Delphi 版本;

//通用兼容Delphi7,推荐
function ReadMultiSZ(const ValueName: string; TS: TStrings): Boolean;
function WriteMultiSZ(const ValueName: string; TS: TStrings): Boolean;

 

//————————————————————————————

unit uRegMutilSZ;

interface

 

uses
Windows, SysUtils, Classes, Registry;

type
{$IF CompilerVersion >= 22} //Delphi XE或以上
TChars = System.TArray<Char>;
{$ELSE}
TChars = array of Char;
TBytes = array of Byte;
{$ENDIF}

TRegistryMultiSZ = class(TRegistry)
private
function QueryMultiSZValue(ValueName: AnsiString; var aBytes: TBytes): DWORD; overload;
function QueryMultiSZValue(ValueName: WideString; var aBytes: TBytes): DWORD; overload;
function QueryMultiSZ(ValueName: string; var aBuffer: TChars): DWORD;
public
procedure ReadStrings(const ValueName: AnsiString; TS: TStrings); overload;
procedure ReadStrings(const ValueName: WideString; TS: TStrings); overload;
procedure WriteStrings(const ValueName: AnsiString; TS: TStrings); overload;
procedure WriteStrings(const ValueName: WideString; TS: TStrings); overload;
//通用兼容Delphi7
function ReadMultiSZ(const ValueName: string; TS: TStrings): Boolean;
function WriteMultiSZ(const ValueName: string; TS: TStrings): Boolean;
end;

 

 

implementation

 

{ TRegistryMultiSZ }

function TRegistryMultiSZ.QueryMultiSZValue(ValueName: AnsiString; var aBytes: TBytes): DWORD;
var
Error: Integer;
valueType: DWORD;
begin
Error := RegQueryValueExA (CurrentKey, PAnsiChar (valueName), nil, @valueType, nil, @Result);
if Error = ERROR_SUCCESS then
begin
if valueType = REG_MULTI_SZ then
begin
SetLength(aBytes, Result);
Error := RegQueryValueExA (CurrentKey, PAnsiChar(valueName), nil, nil, PBYTE(aBytes), @Result);
if Error <> ERROR_SUCCESS then
Windows.OutputDebugStringA(PAnsiChar(Format(‘QueryMultiSZValueA.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;
end
else
Windows.OutputDebugStringA(PAnsiChar(Format(‘QueryMultiSZValueA.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;

function TRegistryMultiSZ.QueryMultiSZ(ValueName: string; var aBuffer: TChars): DWORD;
var
Error: Integer;
valueType: DWORD;
begin
Error := RegQueryValueEx(CurrentKey, PChar(ValueName), nil, @valueType, nil, @Result);
if Error = ERROR_SUCCESS then
begin
if valueType = REG_MULTI_SZ then
begin
SetLength(aBuffer, Result div SizeOf(Char));
Error := RegQueryValueEx(CurrentKey, PChar(ValueName), nil, nil, PBYTE(@aBuffer[0]), @Result);
if Error <> ERROR_SUCCESS then
Windows.OutputDebugString(PChar(Format(‘QueryMultiSZ.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;
end
else
Windows.OutputDebugString(PChar(Format(‘QueryMultiSZ.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;

function TRegistryMultiSZ.QueryMultiSZValue(ValueName: WideString;
var aBytes: TBytes): DWORD;
var
Error: Integer;
valueType: DWORD;
begin
Error := RegQueryValueExW (CurrentKey, PWideChar(ValueName), nil, @valueType, nil, @Result);
if Error = ERROR_SUCCESS then
begin
if valueType = REG_MULTI_SZ then
begin
SetLength(aBytes, Result);
Error := RegQueryValueExW (CurrentKey, PWideChar(ValueName), nil, nil, PBYTE(aBytes), @Result);
if Error <> ERROR_SUCCESS then
Windows.OutputDebugString(PChar(Format(‘QueryMultiSZValueW.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;
end
else
Windows.OutputDebugString(PChar(Format(‘QueryMultiSZValueW.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;

procedure TRegistryMultiSZ.ReadStrings(const ValueName: WideString;
TS: TStrings);
var
I: Integer;
valueLen : DWORD;
S, aLine: WideString;
aTemp, aBytes: TBytes;
begin
TS.Clear;
valueLen := QueryMultiSZValue(ValueName, aBytes);
aLine := ”;
if valueLen > 0 then
begin
SetLength(S, valueLen div SizeOf(Char));
System.Move(aBytes[0], S[1], valueLen);
end;
for I := 1 to (valueLen div SizeOf(Char)) do
begin
if S[I] = #0 then //以0结束的字符串数组,最后,还要一个0结束数组, 双字节的话是0000
begin
if aLine <> ” then TS.Add(aLine);
aLine := ”;
end
else
aLine := aLine+WideChar(S[I]);
end;
end;

 

procedure TRegistryMultiSZ.ReadStrings(const ValueName: AnsiString; TS: TStrings);
var
I: Integer;
valueLen : DWORD;
aLine: AnsiString;
aBytes: TBytes;
begin
TS.Clear;
valueLen := QueryMultiSZValue(ValueName, aBytes);
aLine := ”;
if valueLen > 0 then
for I := Low(aBytes) to valueLen-1 do
begin
if aBytes[I] = 0 then //以0结束的字符串数组,最后,还要一个0结束数组, 双字节的话是0000
begin
if aLine <> ” then TS.Add(aLine);
aLine := ”;
end
else
aLine := aLine+AnsiChar(aBytes[I]);
end;
end;

procedure TRegistryMultiSZ.WriteStrings(const ValueName: AnsiString; TS: TStrings);
var
I, Error: Integer;
aLineCount, aTotalCount: Integer;
aBytes, aTemp: TBytes;
aLine: string;
begin
//如果是XE或以上版本 TS是Unicode 需转换成Ansi 字符串

aTotalCount := 0;
for I := 0 to TS.Count – 1 do
begin
aLine := TS[I];
if aLine = ” then System.Continue; //REG_MULTI_SZ 类型的数据不能包含空字符串。注册表编辑器将删除找到得空字符串。

{$IF CompilerVersion >= 22}
aTemp := TEncoding.ANSI.GetBytes(aLine); //XE 以上
{$ELSE}
SetLength(aTemp, Length(aLine)); //兼容Delphi7
System.Move(aLine[1], aTemp[0], Length(aLine));
{$ENDIF}

aLineCount := Length(aTemp)+1;

Inc(aTotalCount, aLineCount);
SetLength(aBytes, aTotalCount);
System.Move(aTemp[0], aBytes[aTotalCount-aLineCount], aLineCount-1);
aBytes[aTotalCount-1] := 0; //0结束
end;

 

Inc(aTotalCount);
SetLength(aBytes, aTotalCount);
aBytes[aTotalCount-1] := 0; //最后一个数组0结束

Error := RegSetValueExA (CurrentKey, PAnsiChar(valueName), 0, REG_MULTI_SZ, @aBytes[0], aTotalCount);
if Error <> ERROR_SUCCESS then
Windows.OutputDebugString(PChar(Format(‘WriteStringsA.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;

procedure TRegistryMultiSZ.WriteStrings(const ValueName: WideString;
TS: TStrings);
var
I, Error: Integer;
aLineCount, aTotalCount: Integer;
aBytes, aTemp: TBytes;
aLine: WideString;
begin
//如果是XE或以上版本 TS是Unicode 需转换成Ansi 字符串

aTotalCount := 0;
for I := 0 to TS.Count – 1 do
begin
aLine := TS[I];
if aLine = ” then System.Continue; //REG_MULTI_SZ 类型的数据不能包含空字符串。注册表编辑器将删除找到得空字符串。

{$IF CompilerVersion >= 22}
aTemp := TEncoding.Unicode.GetBytes(aLine); //XE 以上
{$ELSE}
SetLength(aTemp, Length(aLine) * SizeOf(WideChar)); //兼容Delphi7
System.Move(aLine[1], aTemp[0], Length(aLine)* SizeOf(WideChar));
{$ENDIF}

aLineCount := Length(aTemp)+2;

Inc(aTotalCount, aLineCount);
SetLength(aBytes, aTotalCount);
System.Move(aTemp[0], aBytes[aTotalCount-aLineCount], aLineCount-2);
aBytes[aTotalCount-2] := 0; //0结束
aBytes[aTotalCount-1] := 0;
end;

 

Inc(aTotalCount, 2);
SetLength(aBytes, aTotalCount);
aBytes[aTotalCount-2] := 0;
aBytes[aTotalCount-1] := 0; //最后一个数组0结束

Error := RegSetValueExW(CurrentKey, PWideChar(valueName), 0, REG_MULTI_SZ, @aBytes[0], aTotalCount);
if Error <> ERROR_SUCCESS then
Windows.OutputDebugString(PChar(Format(‘WriteStringsW.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;

 

function TRegistryMultiSZ.ReadMultiSZ(const ValueName: string;
TS: TStrings): Boolean;
var
cbBufferSize, I: integer;
aBuffer: TChars;
aLine: string;
begin
//通用兼容Delphi7
TS.Clear;
cbBufferSize := QueryMultiSZ(ValueName, aBuffer);
if cbBufferSize > 0 then
for I := 0 to (cbBufferSize div SizeOf(Char))-1 do
begin
if aBuffer[I] = #0 then //以0结束的字符串数组,最后,还要一个0结束数组, 双字节的话是0000
begin
if aLine <> ” then TS.Add(aLine);
aLine := ”;
end
else
aLine := aLine+aBuffer[I];
end;

Result := TS.Count > 0;
end;

 

function TRegistryMultiSZ.WriteMultiSZ(const ValueName: string; TS: TStrings): Boolean;
var
I, Error: Integer;
aLineCount, aTotalCount: Integer;
aLine: string;
begin
//通用兼容Delphi7
aLine := ”;
for I := 0 to TS.Count – 1 do
begin
aLine := aLine+TS[I] + #0;
end;
aLine := aLine + #0;

Error := RegSetValueEx(CurrentKey, PChar(ValueName), 0, REG_MULTI_SZ,
PChar(aLine), Length(aLine)*Sizeof(Char));

Result := Error = ERROR_SUCCESS;
if not Result then
Windows.OutputDebugString(PChar(Format(‘WriteMultiSZ.error=%d, %s’, [Error, SysUtils.SysErrorMessage(Error)])));
end;

 

end.

//——————————————————————

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
TForm1 = class(TForm)
btn1: TButton;
btn2: TButton;
mmo1: TMemo;
btn3: TButton;
btn4: TButton;
btn5: TButton;
btn6: TButton;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure btn3Click(Sender: TObject);
procedure btn4Click(Sender: TObject);
procedure btn6Click(Sender: TObject);
procedure btn5Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses
uRegMutilSZ;

{$R *.dfm}

 

// Ansi的部份
procedure TForm1.Btn1Click(Sender: TObject);
var
reg: TRegistryMultiSZ;
begin
reg := TRegistryMultiSZ.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKey(‘SOFTWARE\Microsoft\Active Setup\InstallInfo’, False) then
reg.ReadStrings(AnsiString(‘UpperFilters’), mmo1.Lines);
finally
reg.Free;
end;
end;

// Ansi的部份
procedure TForm1.Btn2Click(Sender: TObject);
var
reg: TRegistryMultiSZ;
begin
reg := TRegistryMultiSZ.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKey(‘SOFTWARE\Microsoft\Active Setup\InstallInfo’, False) then
reg.WriteStrings(AnsiString(‘UpperFilters’), mmo1.Lines);
finally
reg.Free;
end;
end;

// WideString的部份
procedure TForm1.Btn3Click(Sender: TObject);
var
reg: TRegistryMultiSZ;
begin
reg := TRegistryMultiSZ.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKey(‘SOFTWARE\Microsoft\Active Setup\InstallInfo’, False) then
reg.ReadStrings( WideString(‘UpperFilters’), mmo1.Lines);
finally
reg.Free;
end;
end;

// WideString的部份
procedure TForm1.Btn4Click(Sender: TObject);
var
reg: TRegistryMultiSZ;
begin
reg := TRegistryMultiSZ.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKey(‘SOFTWARE\Microsoft\Active Setup\InstallInfo’, False) then
reg.WriteStrings( WideString(‘UpperFilters’), mmo1.Lines);
finally
reg.Free;
end;
end;

 

// general的部份
procedure TForm1.Btn5Click(Sender: TObject);
var
reg: TRegistryMultiSZ;
begin
reg := TRegistryMultiSZ.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKey(‘SOFTWARE\Microsoft\Active Setup\InstallInfo’, False) then
reg.ReadMultiSZ(‘UpperFilters’, mmo1.Lines);
finally
reg.Free;
end;
end;

// general的部份
procedure TForm1.Btn6Click(Sender: TObject);
var
reg: TRegistryMultiSZ;
begin
reg := TRegistryMultiSZ.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKey(‘SOFTWARE\Microsoft\Active Setup\InstallInfo’, False) then
reg.WriteMultiSZ( ‘UpperFilters’, mmo1.Lines);
finally
reg.Free;
end;
end;

 

procedure TForm1.FormCreate(Sender: TObject);
begin
self.mmo1.Clear;
end;

end.

加载驱动ERROR: 127 找不到指定的程序

加载驱动一些Bug:

一、ErrorCode: 2, Msg: 系统找不到指定的文件。

1、此处不是真的找不到指定的文件,而是同名path驱动文件已经有一个实例,所以提示此错误, 要么改path, 要么改文件名称,这样才能共存多个不同的实例(不同的符号链接名), 要检查DriverUnload 是否删除符号连接,清理完成了不

2、还有就是驱动没有启动,也就是没有安装成工,导致CreateFile()时的驱动符号链接无效。

二、ErrorCode: 193, Msg: %1 不是有效的 Win32 应用程序。

这是因为32位使用了64位驱动

三、ErrorCode: 127, Msg: 找不到指定的程序

这是因为驱动编译时使用Win7编译环境,如果在XP环境下使用导致有些内核API无效,也就是有些NT6.0才支持的API,在XP环境下是无法调用的。

 

CommTone串口调试精灵 v7.0

 Version: 7.0(19021)   2019-04-18

 

CommTone串口调试精灵

    是一款功能强大的串行端口通信调试软件,内嵌超过100种标准的CRC校验功能,并支校验结果高低位字节前导转换;支持批量协议调试,并支持文件、16进制、UNICODE字符串发送和显示;支持无限循环发送、和次数循环发送数据;支持高精度的发送时间延时。使用CommTone能够有效提高工程师调试设备串口通信的工作效率。

支持Windows系统版本: WinXP、Win2003、WinVista、Win7、Win2008、Win8、Win2012、Win2016、Win10,32/64位系统。

支持语言:简体中文、繁体中文、英文三种语言。

 

AAA.png

CommTone串口调试精灵软件的优势

  1.  CommTone启动秒开!不带任何插件,不需要安装任何第三方依赖库;
  2.   简单调试的灵活性!强大的CRC校验功能,免除工程师额外计算CRC冗余校验;
  3. 批量调试的专业性!批量调试能够专业的定义设备串口通信协议包,设置批量调试项目协议按定义的流程调试,并能保存成项目工程文件,可以循环调试或按次数循环调试;
  4. 强大的数据缓存功能!数据列表技持100万级数据量缓存显示,支持数据输出TXT、CSV、HTML。

CommTone串口调试精灵软件适合用户
1、设备软件硬件工程师,软件测试人员;
2、通信息软件工程师、通信测试人员。

下载: 本地下载    非凡下载

CommCheckSum 校验工具

 

CommCheckSum校验工具是一款通用的循环冗余校验码CRC(Cyclic Redundancy Check)、MD5、SHA1、SHA2、SHA3、HAVAL、SHAKE、TIGER、BLAKE、RIPEMD、GOST等算法Hash校验的专业工具软件。

CRC校验支持:CRC3、CRC4、CRC5、CRC6、CRC7、CRC8、CRC11、CRC12、CRC13、CRC14、CRC15、CRC16、CRC17、CRC21、CRC24、 CRC30、CRC31、CRC32、CRC40、CRC64、CRC82、Adler32全面的105种CRC算法,支持显示标准的多项式、初始值、数据反转以及结果异或值。支持Windows资源管理器外壳扩展,方便快捷的调用显示文件的CRC/Hash信息。

支持计算的数据:16进制HEX、字符串、文件,字符串支持ANSI、UTF8、Unicode、Unicode BigEndian编码方式。

支持Windows系统版本: WinXP、Win2003、WinVista、Win7、Win2008、Win8、Win2012、Win2016、Win10,32/64位系统。

支持语言:简体中文、繁体中文、英文三种语言。

 

image.png

下载:  本地下载

Driver 加载步骤

Driver 加载步骤

转载 2016年06月30日 10:50:02
http://blog.csdn.net/wzsy/article/details/51788483

1)当硬件连接到PC或从PC移除时,在硬件上会有信号跳变,BUS Driver会检测到器件的插入和移除,比如DVI的hotplug,再比如USB1.1的1.5K上拉。BUS Driver将调用IOInvalidateDevcieRelations,PNP Manager将知道BUS上的Device关系有所改变。

 

2)为了获得新的Device关系,PNP Manager将调用IRP_MN_QUERY_DEVICE_RELATIONS。BUS Driver将会回应其BUS关系(目录)。

 

3)一旦得知Device之间的关系,PNP Manager就能容易地确定哪些器件没有被初始化。IRP_MN_QUERY_ID将被发出来获得Device ID。

 

4) 一旦获得这些详细信息后,PNP Manager就能确定转载那一类driver了。于是利用INF文件来安装Driver

 

5) 接下来进入标准DriverEntry流程来初始化Driver,同时系统调用AddDevice来添加器件。

 

6) Device添加完毕后,PNP Manger通过发出IRP_MN_QUERY_RESOURCE_REQUIREMENTS。这个IRP让BUS DRIVER来描述各种资源请求,包括中断,IO端口地址,IO MEMORY地址,DMA通道等等。

 

7) PNP Manger针对BUS DRIVER描述的资源请求将资源分配给Driver,配置好Driver后,发出IRP_MN_START_DEVICE,接收到IRP后,Driver配置和连接一些内核资源,然后等待着被使用。

 

后面Driver的工作,与System的交互,靠IRP来进行。而user mode与Driver交互也是通过WINAPI->System->Driver;Driver->System->WINAPI来进行。

 

当一个WDM总线驱动程序为响应IRP_MN_QUERY_DEVICE_RELATIONS而列出新设备时,如果类型是BusRelations,它将创建一个物理设备对象(PDO)。

下列规则决定了一个总线驱动程序是调用IoCreateDevice还是调用IoCreateDeviceSecure来创建一个设备对象:

l         如果设备可以在原始模式(raw mode)下使用,那么必须调用IoCreateDeviceSecure。

l         如果设备不能在原是模式下使用,那么总线驱动程序既可以调用IoCreateDevice,也可以调用IoCreateDeviceSecure。当对于总线上的设备的默认系统安全性足够的时候可以调用IoCreateDevice;调用IoCreateDeviceSecure可以指定更严格的安全描述符。

 

 

1、I/O管理器(根总线)为总线生成并维护PDO,总线驱动为插入的设备生成并维护PDO(即下层设备驱动为上层设备生成并维护PDO);驱动程序中的AddDevice例程接受的参数PhysicalDeviceObject就是下层设备为其生成的PDO, AddDevice例程Create的只能是该设备的FDO。

2、总线驱动发现新设备插入后,通过调用IoInvalidateDeviceRelations告诉PnP管理器BusRelations改变(注意:IoInvalidateDeviceRelations中传入的DeviceObject是总线的PDO);PnP管理器发送IRP_MN_QUERY_DEVICE_RELATIONS查询BusRelations,此时总线设备的FDO为新设备生成PDO,并报告。

BTW:TOASTER总线驱动是在发现新设备插入后就生成子PDO,然后通知PnP管理器;然后PnP管理器进行查询。这与DDK中说明不一致,可能无关紧要??

3、当UnPlug动作发生时,如同Plug动作发生,总线驱动(其FDO) 通过调用IoInvalidateDeviceRelations告诉I/O管理器BusRelations改变(注意:IoInvalidateDeviceRelations中传入的DeviceObject是总线的PDO,不是此时UnPlug的设备PDO)

4、当设备发生Eject动作时,总线驱动(其FDO) 通过调用IoRequestDeviceEject告诉I/O管理器,此时IoRequestDeviceEject的参数PhysicalDeviceObject是该设备的PDO。

5、总线驱动程序需要处理两类PnP事件,一类发给总线FDO的PnP事件,一类是总线驱动为插入的设备生成的PDO的PnP事件。对于发给总线FDO的PnP事件,一般都需要继续下传,而对于发给为插入的设备生成的PDO的PnP事件则IoCompleteRequest。

6、每一个设备都有一个设备堆栈,在该设备堆栈里,代表该设备的PDO永远都处于最底层。总线的PDO与在总线上的设备PDO没有层次关系。但是总线驱动程序负责生成其发现的设备的PDO,设备提供商提供的驱动程序主要是该设备的FDO,FDO进行数据传输/功能作业时一般不需要与代表设备的PDO进行交互。

7、FiDO都是相对FDO而言,Upper FiDO表明该FiDO在设备堆栈中处于FDO的上面,Lower FiDO表明该FiDO在设备堆栈中处于FDO的下面;但所有的一切都处于PDO的上面。

8、PnP管理器不保证设备堆栈中的驱动加载顺序,但是它保证了调用AddDevice的顺序来确保Stack的正确。

9、如果设备处于Raw状态,则它的设备堆栈里只有PDO与总线驱动生成的FiDO

win7 x64部署和串口调试虚拟驱动toaster

http://bbs.csdn.net/topics/390728347
就是把kmdf\inc中public.h中的GUID_DEVINTERFACE_BUSENUM_TOASTER的GUID用GUID_DEVINTERFACE_TOASTER进行了替换,然后就正常了。
http://blog.csdn.net/lixiangminghate/article/details/51378483
    WDK7600自带的toaster驱动是个很好的学习驱动的案例,从总线驱动到App层,Class-install/Co-install都有涉及。本文主要涉及驱动部署和调试。
1.先说说调试的准备工作。一般调试驱动都是在虚拟机中进行的,这里也不例外,用windbg+vmware双击联调。通常开发阶段,Wdm驱动以inf形式安装并加载,加载后依次执行DriverEntry,AddDevice并响应IRP_MJ_PNP&IRP_MN_START事件。安装的同时,pnp管理器会复制文件及改写注册表,待下次重启,驱动在系统重启阶段会加载运行驱动。因此,在DriverEntry时加入断点尤为重要,要不然将错过这些函数的调试时机。在x86时代,加入口断点无非是代码中插入 asm int 3.但是,这么美好的时代已经过去了,x64驱动不支持嵌入汇编。取而代之,必须通过编写一个asm文件,在源码中以调用外部函数的形式,共5步来实现。1.1第一步实现int 3的汇编代码形如:

  1. .code
  2. asm_int3 proc
  3. int 3
  4.     ret
  5. asm_int3 endp
  6. end

1.2将这段代码保存为softbp.asm。然后用wdk自带的ml64编译,注意仅编译生成obj文件:

  1. ml64 /c softbp.asm

1.3接着是在C文件中调用这个函数,如在wdm/bus/busenum.c的DriverEntry处加入断点

  1. extern void asm_int3(); //<————-外部函数声明
  2. NTSTATUS
  3. DriverEntry (
  4.     __in  PDRIVER_OBJECT  DriverObject,
  5.     __in  PUNICODE_STRING RegistryPath
  6.     )
  7. /*++
  8. Routine Description:
  9.     Initialize the driver dispatch table.
  10. Arguments:
  11.     DriverObject – pointer to the driver object
  12.     RegistryPath – pointer to a unicode string representing the path,
  13.                    to driver-specific key in the registry.
  14. Return Value:
  15.   NT Status Code
  16. –*/
  17. {
  18.     asm_int3(); //<————–外部函数调用
  19.     Bus_KdPrint_Def (BUS_DBG_SS_TRACE, (“Driver Entry \n”));
  20. //
  21. // Save the RegistryPath for WMI.

1.4修改sources文件,添加对softbp.obj的链接:原本sources文件中TARGETLIBS的值为

  1. TARGETLIBS=  $(DDK_LIB_PATH)\wdmsec.lib \
  2.              $(DDK_LIB_PATH)\ntstrsafe.lib

修改为:

  1. TARGETLIBS=  $(DDK_LIB_PATH)\wdmsec.lib \
  2.              $(DDK_LIB_PATH)\ntstrsafe.lib \
  3.              softbp.obj

1.5运行build -ceZ编译链接整个toaster工程。2.得到驱动文件后就是部署阶段。win7 x64的部署也是够磨人的:bcdedit增加启动项(再次怀念xp的好,修改boot.ini就够了),禁用驱动签名,最后安装驱动。以下的步骤都在虚拟机中进行

2.1增加启动项:

2.1.1 以administrator权限下进入cmd,运行bcdedit命令设置端口COM1为调试端口, baudrate为115200(我已将虚拟机的打印机移除,打印机可耻的占用着COM1,并将串口的名字改为COM1)

  1. bcdedit /dbgsettings serial baudrate:115200 debugport:1

2.1.2 复制一个开机选项, 以进入OS的debug模式

  1. bcdedit /copy {current} /d DebugEnty

2.1.3 接着增加一个新的选项到引导菜单

  1. bcdedit /displayorder {current} {6426f429-17fc-11e6-bf64-ad656b9740aa}

{6426f429-17fc-11e6-bf64-ad656b9740aa}是2.1.2运行结束后生成的id值2.1.4 激活前面生成的debug项

  1. bcdedit /debug {6426f429-17fc-11e6-bf64-ad656b9740aa} on

最后上一张效果图,然后重启机器准备调试:

3.windbg链接。

开始串口连接前,要设置调试符号和windbg启动参数,我直接写了个脚本setenv.bat完成这两步,以后双击运行即可:

  1. ;set _NT_SYMBOL_PATH=SRV*C:\sym;用于设置调试符号的路径
  2. set _NT_SYMBOL_PATH=SRV*C:\sym;
  3. ;我的winbdg装在下列位置,后面的参数是串口调试参数
  4. “D:\WinDDK\7600.16385.1\Debuggers\windbg.exe” -b -k com:pipe,port=\\.\pipe\com_1,baud=115200,pipe

系统重启后双击setenv.bat,在虚拟机中选择DebugEntry 按F8进入高级启动项,然后选择Disable Driver Signature Enforcement

(注,在等待虚拟机启动期间,经常出现windbg闪退,这时再双击setenv.bat即可。)

4.部署toaster

进入win7后,在控制面板中没有硬件向导的一席之地!需要通过在开始菜单-运行中输入hdwwiz.exe来打开。真是何其不易。ms出于安全目的,希望我们通过driver store安装受信得驱动,倒给开发驱动的找了一堆破事。安装toaster的步骤不再叙述,参照wdk中xp下安装方式在hdwwiz.exe中设置即可。

安装的末尾,也就是进入DriverEntry,由于我们在代码中设置了int3断点,因此windbg会获得执行权。这时可以追加并验证toaster的调试符号,因为此时驱动已经加载到内存中,因此设置断点不会报类似code not set之类的错误,而且符号也能正确加载。

  1. 追加toaster调试符号
  2. kd> .sympath+ C:\toaster\wdm\bus\objchk_win7_amd64\amd64
  3. Symbol search path is: SRV*C:\sym;C:\toaster\wdm\bus\objchk_win7_amd64\amd64
  4. 检验符号是否加载
  5. kd> lm m busenum*
  6. start             end                 module name
  7. fffff880`0392e000 fffff880`0393e000   busenum    (private pdb symbols)  c:\toaster\wdm\bus\objchk_win7_amd64\amd64\BusEnum.pdb
  8. 验证符号是否和sys版本一致
  9. kd> !itoldyouso busenum c:\toaster\wdm\bus\objchk_win7_amd64\amd64\busenum.sys
  10. busenum.sys
  11.     Timestamp: 57333596
  12.   SizeOfImage: 10000
  13.           pdb: c:\toaster\wdm\bus\objchk_win7_amd64\amd64\BusEnum.pdb
  14.       pdb sig: A8748D1B-8C93-4855-BBC7-4D773CADC3B0
  15.           age: 1
  16. Loaded pdb is c:\toaster\wdm\bus\objchk_win7_amd64\amd64\BusEnum.pdb
  17. BusEnum.pdb
  18.       pdb sig: A8748D1B-8C93-4855-BBC7-4D773CADC3B0
  19.           age: 1
  20. MATCH: BusEnum.pdb and busenum.sys
  21. 验证当前执行的位置是不是在busenum中
  22. kd> ln $ip
  23. (fffff880`039301a0)   busenum!asm_int3   |  (fffff880`039301c0)   busenum!__security_check_cookie
  24. Exact matches:

待一切验证完毕,就可以在AddDevice 等函数入口下断点。等下次系统在启动阶段时,会在这些断点处停下。如果想多次进入DriverEntry/AddDevice函数,可以在设备管理器中找到toaster设备,然后右键disable/enable设备,就能多次进入这些函数

版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 本文已收录于以下专栏:
  • win内核

DDK样例toaster分析(2)

转载:http://blog.csdn.net/lixiangminghate/article/details/51705710

前一篇 DDK样例toaster分析(1) 主要讨论了toaster样例中的busenum总线驱动。本篇将讨论从总线驱动过渡到功能驱动,也就是toaster.sys。

成功安装busenum.sys后,运行toaster/exe/enum目录下的enum程序模拟一个toaster设备插入:

[cpp] view plain copy

  1. enum -p 1

前面busenum.sys!Bus_AddDevice创建Fdo的同时还为Fdo创建一个接口:

[cpp] view plain copy

  1. status = IoRegisterDeviceInterface (
  2.                 PhysicalDeviceObject,
  3.                 (LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER,
  4.                 NULL,
  5.                 &deviceData->InterfaceName);
  6. DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_TOASTER,
  7.         0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);
  8. //  {D35F7840-6A0C-11d2-B841-00C04FAD5171}

enum.exe通过SetupDi函数打开并通过ioctl访问这个接口:

[cpp] view plain copy

  1. hardwareDeviceInfo=SetupDiGetClassDevs(GUID_DEVINTERFACE_BUSENUM_TOASTER,…);
  2. SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,…,&deviceInterfaceData);
  3. file = CreateFile ( deviceInterfaceDetailData->DevicePath,…);

调用Ioctl后,最终进入到Bus_Ioctl中,因为是插入设备,所以最终会调用Bus_PlugInDevice

[cpp] view plain copy

  1. NTSTATUS
  2. Bus_PlugInDevice (
  3.     PBUSENUM_PLUGIN_HARDWARE    PlugIn,
  4.     ULONG                       PlugInSize,
  5.     PFDO_DEVICE_DATA            FdoData
  6.     )

先看下FdoData中的内容,确定enum打开的是busenum.sys创建的Fdo:

[cpp] view plain copy

  1. kd> dd FdoData l1
  2. 0x81ec60e8
  3. kd> dt _FDO_DEVICE_DATA 81ec60e8
  4. busenum!_FDO_DEVICE_DATA
  5.     +0x01c UnderlyingPDO    : 0x823e73d0 _DEVICE_OBJECT
  6. kd> !devobj 0x823e73d0
  7. Device object (823e73d0) is for:
  8.  00000034 \Driver\PnpManager DriverObject 823eb2b0
  9. Current Irp 00000000 RefCount 1 Type 00000004 Flags 00001040
  10. Dacl e1594174 DevExt 823e7488 DevObjExt 823e7490 DevNode 823e7288
  11. ExtensionFlags (0000000000)
  12. AttachedDevice (Upper) 81ec6030 \Driver\busenum
  13. Device queue is not busy.

FdoData用UnderlyingPDO指出了堆叠在设备下面的设备。从windbg的输出看出,UnderlyingPDO就是busenum.sys所依赖的pnpmanager设备对象。

M$的帮助文档将busenum.sys!Bus_AddDevice创建的设备描述为Fdo,而将Bus_PlugInDevice创建的设备描述为Pdo。这是因为在Bus_PlugInDevice中创建出来的devobj代表了busenum总线对象,作为toaster.sys创建的设备对象的堆叠基石。另外也可以从windbg的输出看到,busenum新创建的设备对象并没有attach到任何已有设备对象上:
1).调用Bus_PlugInDevice!IoCreateDeviceSecure前,属于busenum.sys驱动对象的设备对象:

[cpp] view plain copy

  1. kd> !drvobj busenum
  2. Driver object (81dfdda0) is for:
  3.  \Driver\busenum
  4. Driver Extension List: (id , addr)
  5. Device Object list:
  6. 81ec6030 <—是attach在\Driver\PnpManager上的Fdo对象,上一张图中有描述
[cpp] view plain copy

  1. kd> !devstack 81ec6030
  2.   !DevObj   !DrvObj            !DevExt   ObjectName
  3. > 81ec6030  \Driver\busenum    81ec60e8
  4.   823e73d0  \Driver\PnpManager 823e7488  00000034
  5. !DevNode 823e7288 :
  6.   DeviceInst is “Root\UNKNOWN\0000”
  7.   ServiceName is “busenum”

上图中,busenum.sys只有一个设备对象
2).调用IoCreateDeviceSecure后,busenum.sys会新增一个设备对象:

[cpp] view plain copy

  1. kd> !drvobj busenum
  2. Driver object (81dfdda0) is for:
  3.  \Driver\busenum
  4. Driver Extension List: (id , addr)
  5. Device Object list:
  6. 82062408<—新加的设备对象  81ec6030 <—原有的设备对象
  7. kd> !devobj 82062408
  8. Device object (82062408) is for:
  9.  0000008a \Driver\busenum DriverObject 81dfdda0
  10. Current Irp 00000000 RefCount 0 Type 0000002a Flags 000000c0
  11. Dacl e23ad84c DevExt 820624c0 DevObjExt 820624f8
  12. ExtensionFlags (0000000000)
  13. Device queue is not busy.

从windbg输出可以看到,这个新的设备对象下面并没有attach其他设备对象

之后,busenum为这个新创建的设备对象创建HardwareID(总线设备的职责不就是为新加入的设备分配设备ID吗?)

[cpp] view plain copy

  1. pdoData->HardwareIDs =
  2.             ExAllocatePoolWithTag (NonPagedPool, length, BUSENUM_POOL_TAG);
  3. RtlCopyMemory (pdoData->HardwareIDs, PlugIn->HardwareIDs, length);
  4. 后分配busenum pdo的HardwardID
  5. kd> dd pdoData l1
  6. b21fdbec  820624c0
  7. kd> dt _PDO_DEVICE_DATA  820624c0
  8. busenum!_PDO_DEVICE_DATA
  9.     +0x020 HardwareIDs      : 0x8213aa50  -> 0x7b
  10. kd> du 0x8213aa50 <——注意,这是busenum.sys为pdo对象设置的硬件id,之后要按这个id匹配功能驱动
  11. 8213aa50  “{B85B7C50-6A01-11d2-B841-00C04FA”
  12. 8213aa90  “D5171}\MsToaster”

最后,Bus_PlugInDevice通过IoInvalidateDeviceRelations,通知pnp管理器:有新的设备加入设备树,pnp管理器要更新设备树关系(说人话,就是为新设备加载匹配的驱动)

由于系统中并没有安装这个Pdo的驱动,因此会跳出搜索驱动的对话框,这里选择手动安装,选择toaster/inf/sample.inf文件。至于为什么要选这个文件,因为sample.inf文件的硬件兼容列表里表示支持这个设备:

[cpp] view plain copy

  1. [Manufacturer]
  2. %StdMfg%=Standard
  3. [Standard]
  4. ; DisplayName               Section           DeviceId
  5. ; ———–               ——-           ——–
  6. %ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster <—硬件兼容列表

这个列表中的内容完全匹配新创建设备对象的HardwareID,因此系统加载sample.inf中指定的sys文件,并创建对应的服务,最后把执行权限交给toaster.sys:

[cpp] view plain copy

  1. [Version]
  2. Signature=“$WINDOWS NT$”
  3. Class=TOASTER
  4. ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171}
  5. Provider=%MSFT%
  6. DriverVer=09/21/2006,6.0.5736.1
  7. CatalogFile=toaster.cat
  8. [Toaster_Device.NT]
  9. CopyFiles=Toaster_Device.NT.Copy
  10. [Toaster_Device.NT.Copy]
  11. toaster.sys

驱动安装后,设备管理器里多出一个toaster设备,查看Driver Detail可以看到驱动文件的信息:


扯点题外话,可以通过Update Driver替换新的inf文件,比如选择toasterf.inf(含设备过滤驱动的toaster.sys),并指定sys文件路径后,再查看Driver Detail可以看到功能驱动和过滤驱动:(tmd公司要做驱动测试,测试老问我加载过滤驱动后,怎么在设备管理器里看到!还一定要在设备管理器里看到,注册表里不算,我折腾很久才发现这个!!)

当然这种更新操作要底层设备支持disable/enable,像磁盘设备的,不支持disable/enable操作就不能这样更新驱动(这要感谢同事周AM的解释)
好好,扯远了,回到正题,执行权从busenum.sys过渡到toaster.sys。当然了进入toaster.sys后还会调用toaster的AddDevice函数ToasterAddDevice,因此要在这个函数上下断:

[cpp] view plain copy

  1. DriverEntry
  2. kd> !drvobj 8216db10
  3. Driver object (8216db10) is for:
  4.  \Driver\toaster
  5. Driver Extension List: (id , addr)
  6. Device Object list:
[cpp] view plain copy

  1. kd> bp toaster!ToasterAddDevice;g
  2. kd> dd DriverObject l1
  3. f8aed9e8  8216db10
  4. kd> !drvobj 8216db10
  5. Driver object (8216db10) is for:
  6.  \Driver\toaster
  7. Driver Extension List: (id , addr)
  8. Device Object list:

刚进入ToasterAddDevice时,驱动对象下还没有设备对象。顺带看下ToasterAddDevice的接口

[cpp] view plain copy

  1. NTSTATUS
  2. ToasterAddDevice(
  3.     __in PDRIVER_OBJECT DriverObject,
  4.     __in PDEVICE_OBJECT PhysicalDeviceObject
  5.     )

DriverObject不用说肯定是toaster.sys的,PhysicalDeviceObject,则是前面busenum创建的pdo了(由于刚才更新驱动时停用启用过设备,设备对象跟上文不能连续了,不过还是能通过!drvobj !devstack来观察结果):

[cpp] view plain copy

  1. kd> dd PhysicalDeviceObject l1 ;<—PhysicalDeviceObject的值
  2. f8ae99ec  82062408
  3. kd> !devstack 82062408  ;<—通过设备堆栈证明这个是前面busenum创建的Pdo
  4.   !DevObj   !DrvObj            !DevExt   ObjectName
  5. > 82062408  \Driver\busenum    820624c0  0000008a ;<—这个设备对象下面并没有attach其他设备,跟上文的结论一下,因此可以认为是Pdo
  6. !DevNode 82266878 :
  7.   DeviceInst is “{B85B7C50-6A01-11d2-B841-00C04FAD5171}\MsToaster\1&1aafb3d5&0&01”
  8.   ServiceName is “toaster”
  9. kd> !drvobj busenum  ;<—当然,有人不信,那只能列出busenum驱动对象下的设备对象
  10. Driver object (81dfdda0) is for:
  11.  \Driver\busenum
  12. Driver Extension List: (id , addr)
  13. Device Object list:
  14. 82062408  81ec6030  <—这个驱动对像目前只有2个设备对象,为了证明82062408对象是Pdo,只要证明81ec6030  是Fdo就行了,剩下的靠排除法就能证明
[cpp] view plain copy

  1. kd> !devstack 81ec6030 ;<—81ec6030的设备栈显示,这个就是Fdo,attach在pnpmanager设备对象上
  2. !DevObj !DrvObj !DevExt ObjectName
  3. > 81ec6030 \Driver\busenum 81ec60e8 823e73d0 \Driver\PnpManager 823e7488 00000034!DevNode 823e7288 : DeviceInst is “Root\UNKNOWN\0000” ServiceName is “busenum”

 


之后,Toaster.sys调用IoCreateDevice创建功能驱动(注意是toaster.sys的Fdo不是busenum.sys的Fdo),把这个Fdo堆叠到busenum.sys的Pdo上:

[html] view plain copy

  1. status = IoCreateDevice (DriverObject,
  2.                              sizeof (FDO_DATA),
  3.                              NULL,
  4.                              FILE_DEVICE_UNKNOWN,
  5.                              FILE_DEVICE_SECURE_OPEN,
  6.                              FALSE,
  7.                              &deviceObject);
  8. fdoData->NextLowerDriver = IoAttachDeviceToDeviceStack (deviceObject,
  9.                                                        PhysicalDeviceObject);

这样就完成了从busenum到toaster的过渡。

DDK样例toaster分析(1)

转载:http://blog.csdn.net/lixiangminghate/article/details/51700357

 

 

msddk样例中toaster是一个比较完整和值得学习的pnp驱动,包括了一个完整的设备栈(含总线驱动/功能驱动,以及设备栈中各层过滤驱动)和驱动安装程序(含驱动安装包/类安装程序/协安装程序)。本篇记录在xp下调试busenum驱动入口(关于环境的搭建网上一搜一大把,这里就省了,当然也可以参考这篇:win7 x64部署和串口调试虚拟驱动toaster)。

通过添加硬件的方式安装busenum.sys后,会依次进入busenum.c!DriverEntry和pnp.c!Bus_AddDevice。AddDevice是本篇的重点,因此进入DriverEntry后在这个函数上下一个断点:

[cpp] view plain copy

  1. kd> lmvm busenum //查看驱动和调试符号加载是否正确
  2. start    end        module name
  3. b20e9000 b20f2b80   busenum    (private pdb symbols)  d:\winddk\7600.16385.1\src\general\toaster\wdm\bus\objchk_wxp_x86\i386\BusEnum.pdb
  4.     Loaded symbol image file: busenum.sys
  5. kd> !itoldyouso busenum
  6. busenum.sys
  7.     Timestamp: 57639546
  8.   SizeOfImage: 9B80
  9.           pdb: d:\winddk\7600.16385.1\src\general\toaster\wdm\bus\objchk_wxp_x86\i386\BusEnum.pdb
  10.       pdb sig: A0EB3691-6995-416E-9BF4-C25A160C9318
  11.           age: 1
  12. Loaded pdb is d:\winddk\7600.16385.1\src\general\toaster\wdm\bus\objchk_wxp_x86\i386\BusEnum.pdb
  13. BusEnum.pdb
  14.       pdb sig: A0EB3691-6995-416E-9BF4-C25A160C9318
  15.           age: 1
  16. MATCH: BusEnum.pdb and busenum.sys

确定sys文件加载正确后,查找函数并下断点,然后继续运行:

[cpp] view plain copy

  1. kd> x busenum!Bus_AddDevice
  2. b20eca60 busenum!Bus_AddDevice (struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *)
  3. kd> bp busenum!Bus_AddDevice
  4. kd> bl
  5.  1 e b20eca60     0001 (0001) busenum!Bus_AddDevice

当windbg进入Bus_AddDevice遇到断点时,函数有两个参数:PDRIVER_OBJECT DriverObject和PDEVICE_OBJECT PhysicalDeviceObject。DriverObject很好理解,就是busenum.sys,有windbg为证:

[cpp] view plain copy

  1. kd> dd DriverObject l1
  2. f8ae99e8  8227a3b8
  3. kd> !drvobj 8227a3b8
  4. Driver object (8227a3b8) is for:
  5.  \Driver\busenum

PhysicalDeviceObject是什么 呢?如果是pnp设备驱动,那很简单,这就是底层总线驱动对应的设备。但busenum本身是总线驱动,谁提供底层设备?答案是pnp管理器

[cpp] view plain copy

  1. kd> dd PhysicalDeviceObject l1
  2. f8ae99ec  81f41030
  3. kd> !devobj 81f41030 —> 这个设备是pnp创建的设备
  4. Device object (81f41030) is for:
  5.  00000082 \Driver\PnpManager DriverObject 823eb2b0 —> windbg指出,创建设备对象的驱动对象
  6. kd> !drvobj 823eb2b0
  7. Driver object (823eb2b0) is for:
  8.  \Driver\PnpManager  —>驱动对象
  9. Driver Extension List: (id , addr)
  10. 该驱动对象的设备对象
  11. Device Object list:
  12. 81f41030  823e73d0  823e7610  823e7850

原来,pnp管理器为了维护一颗设备树,在加载总线驱动前会为总线设备创建一个pnpmanage设备对象,作为设备栈的栈底对象,让总线设备attach上去。在busenum.sys代码中也有这种设备栈的上下体现:

[cpp] view plain copy

  1. NTSTATUS
  2. Bus_AddDevice(
  3.     __in PDRIVER_OBJECT DriverObject,
  4.     __in PDEVICE_OBJECT PhysicalDeviceObject
  5.     )
  6. {
  7.     status = IoCreateDevice (
  8.                     DriverObject,…,&deviceObject);
  9.     deviceData->UnderlyingPDO = PhysicalDeviceObject;
  10.     deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack (
  11.                                     deviceObject,
  12.                                     PhysicalDeviceObject);
  13. }

首先代码创建busenum.sys的设备对象,然后attach到pnpmanager设备对象上。难怪toaster的帮助文档中注释这个对象为Fdo,而把Bus_AddDevice的第二个参数认为是Pdo。

来看下创建设备后设备栈情况:

[cpp] view plain copy

  1. kd> !drvobj 8227a3b8
  2. Driver object (8227a3b8) is for:
  3.  \Driver\busenum
  4. Driver Extension List: (id , addr)
  5. ;相比刚进入DriverEntry时,现在busenum驱动对象下已经有一个设备对象了,这个就是调用IoCreateDevice时创建的
  6. Device Object list:
  7. 81f2a930

[cpp] view plain copy

  1. kd> dd deviceObject l1
  2. f8ae99dc  81f2a930 ;设备对象的地址
  3. kd> !devobj 81f2a930 ;验证一下设备对象的属主
  4. Device object (81f2a930) is for:
  5.   \Driver\busenum DriverObject 8227a3b8
  6. Current Irp 00000000 RefCount 0 Type 0000002a Flags 00000088
  7. DevExt 81f2a9e8 DevObjExt 81f2aa90
  8. ExtensionFlags (0000000000)
  9. Device queue is not busy.

[cpp] view plain copy

  1. kd> !devstack 81f2a930 ;81f2a930就是前面IoCreateDevice创建的设备对象
  2.   !DevObj   !DrvObj            !DevExt   ObjectName
  3.  > 81f2a930  \Driver\busenum    81f2a9e8
  4.   81f41030  \Driver\PnpManager 00000000  00000082
  5.   !DevNode 81f2a008 :
  6.   DeviceInst is “ROOT\UNKNOWN\0000” ;设备实例
  7.   ServiceName is “busenum”          ;设备对应的服务名

至此busenum的设备栈已经成形了,可以创建Fdo了。

在结束本文前,还有一些琐碎的东西需要记录。就是busenum.inf中DDinstall section

安装busenum驱动后,打开设备管理器,在system devices下可以看到设备对象。

如图所示,设备出现在system devices下,设备实例是ROOT\Unknow\0000。问题来了,为什么会这样?

首先,设备管理器是以类设备为视图,不同的设备类归入不同的类下(物以类聚)。因此出现在system devices下一定是刻意设定,那么这由谁来设定?当然是inf文件了,在version节中指定:下面的内容摘自bus.inf

[cpp] view plain copy

  1. [Version]
  2. Signature=“$WINDOWS NT$”
  3. Class=System ;指明busenum属于system类
  4. ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} ;类的guid
  5. Provider=%MSFT%
  6. DriverVer=09/21/2006,6.0.5736.1
  7. CatalogFile=toaster.cat

其次,硬件ID,由inf文件DDinstall节指定,msdn文档上一般将DDinstall节认为是从Manufacturer开始:

[cpp] view plain copy

  1. [Manufacturer]
  2. %StdMfg%=Standard
  3. [Standard]
  4. ; These are the toaster bus pnp ids
  5. %ToasterBus.DeviceDesc%=ToasterBus_Device, root\busenum ;root\busenum指定了设备的HardwareID

有了这两项,在结合驱动在注册表下的路径可以找到相应的信息:

先确定设备的总线关系,inf文件中已经指出了busenum属于root总线,它在注册表中的路径为:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root

设备实例ROOT\Unknow\0000表明,busenum在root总线的Unknow\0000下,在这个项中可以找到驱动的service和class信息:

1)通过ROOT\Unknow\0000索引驱动的service为busenum

在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{SerivceName}下可以找到各种驱动注册的服务相关的注册表值:

对于busenum驱动ServiceName是busenum

ImagePath是驱动程序被安装的路径,这些信息在Inf文件中都有对应内容,

[cpp] view plain copy

  1. [ToasterBus_Device.NT.Services] ;这个节是服务安装节
  2. AddService = busenum,%SPSVCINST_ASSOCSERVICE%, busenum_Service_Inst

[cpp] view plain copy

  1. ;AddService对应驱动在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\下创建的服务名
  2. {4D36E97D-E325-11CE-BFC1-08002BE10318}
  3. ; ————– busenum driver install sections
  4. [busenum_Service_Inst]
  5. DisplayName    = %busenum.SVCDESC% ;<span style=“font-family: Arial, Helvetica, sans-serif;”>busenum.SVCDESC</span><span style=“font-family: Arial, Helvetica, sans-serif;”>=busenum.SVCDESC = “Toaster Bus Enumerator”对应注册表项DisplayName和在设备管理器上显示的名字</span>
  6. ServiceType    = 1               ; SERVICE_KERNEL_DRIVER
  7. StartType      = 3               ; SERVICE_DEMAND_START <span style=“font-family: Arial, Helvetica, sans-serif;”>;对应注册表的Start</span>
  8. ErrorControl   = 1               ; SERVICE_ERROR_NORMAL
  9. ServiceBinary  = %12%\busenum.sys                       ;对应注册表中ImagePath
  10. LoadOrderGroup = Extended Base

2)通过ROOT\Unknow\0000索引驱动的class信息

在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{ClassGuid}
对于busenum驱动ClassGuid是{4D36E97D-E325-11CE-BFC1-08002BE10318},挨个找过去可以找到busenum注册表项:

这里InfPath名为oem12.inf,是因为系统把所有inf文件拷到系统路径后(c:\windows\inf),统一命名为oemxx.inf形式。而InfSection应该对应了设备的DDInstall节,这个节可能是当系统重启时需要加载设备时到对应的oemxx.inf中寻找DDInstall进行驱动安装的依据

CommMonitor FAQ问题解答?

1、启动监控时弹出:创建远程调用过程失败? 或是  拒绝访问?

此问题是安全卫士拦截了驱动加载,关闭安全卫士如QQ,360,2345等卫士,或是将CommMonitor添加到卫士的白名单里面去。

2、Windows无法验证此文件的数字签名?

此问题存在于Windows 10 家庭中文版,X64位系统导致无法启动监控,此Windows10版本需更新最新的Update。

注册CommMonitor—财务招领

兹有以下注册用户,支付后没有联系,请尽快联系CEIWEI,收取注册授文件。

 

类  型:注册 CommMonitor 64位
时  间:2017-12-26  20:23:15
转账单号:10000503012017122603103*****02
交易单号:100005030117122602320200031053****0659


类  型:注册 CommMonitor 32位
时  间:2017-12-18  08:43:14
转账单号:100005030120171218121011*****62
交易单号:10000503011712180232020001211011******659


 

类  型:注册 CommMonitor 32位
时  间:2017-11-09 13:43:15
转账单号:1000050301171109031025018***2
交易单号:1000050301171109023202000031025018****59

CEIWEI Serial port monitor 10.0

CEIWEI Serial port monitor 10.0   Serial port monitoring wizard is used for RS232 / RS422 / RS485 port monitoring professional powerful system utility software. CommMonitor monitors all serial port activity in the display, log, and analysis system. This is the ideal way to track problems that may occur in applications or driver development, serial device testing, and optimization. Also provides filtering, search, data export and powerful data interception function, you can specify the port data flow, control flow information to intercept and save down for analysis purposes. Such as the port state changes (baud rate, data bits, parity bit, stop bit), blocking the uplink and downlink data, processing speed, high interception efficiency, and can be hexadecimal, ASCII characters, Full support for Unicode.

Support Net socket TCP/UDP data trans.

Support windows: WinXP, Win2003, Win7, Win2008, Win8, Win2012, Win2016, Win10, 32/64-bit system, the driver has signed, fully support 64-bit Windows system.

Language support: Simplified Chinese, Traditional Chinese, English three languages.

SDK DEMO :  DelphiXE7、 VS2008/VS2012(C#,VC,VB.net) ActiveX  OCX。

10.0 update log:
————-
1, kernel driver upgrade, add support for network functions;
2, kernel driver monitoring log millisecond time display;
3, kernel driver to increase support for large amounts of data cache;
4, kernel driver increase of dynamic encryption, in order to ensure data transmission security;
5, CommMonitor main program upgrade, support for monitoring the serial port on the remote server;
6, increase CommMonitorSvr service to start monitoring, provide network services;
7, support for monitoring the use of the serial port, you need CommMonitorSvr service start;
8, SDK OCX increase monitoring log drive serial number, process name, and remote process name;
9, SDK OCX increase TCP / UDP network connectivity;
10, SDK OCX increase network call API, network events.

CommMonitor 10.0 download: 镜像下载1    镜像下载2

CommMonitor10.0 EXE 版本 注册流程

注册声明:

CommMonitor 8.0 已注册专业版用户可以免费升级为 CommMonitor 10.0 专业版,  从2018-01-15 起,不再受理CommMonitor 8.0专业版注册。

 

 

CommMonitor10.0 EXE 版本 注册流程:

点击【未注册用户】,弹出注册支付窗口->>扫描二维码微信或支付宝,完成支付->>点击【查看注册license】->>找到安装目录下的request.license文件->>发给QQ:348677065,获取专业版授权文件,获取到专业版授权文件后- >>复制到安装目录(即CommMonitor10相同目录),重新启动CommMonitor10即可。

 

 

CommMonitor10.0 EXE/SDK OCX版本区别

注册声明:

CommMonitor 8.0 已注册专业版用户可以免费升级为 CommMonitor 10.0 专业版,  从2018-01-15 起,不再受理CommMonitor 8.0专业版注册。

淘宝购买地址:  https://item.taobao.com/item.htm?id=565814765243

CommMonitor EXE  10.0版本 日期:2018-01-15
序号 功能说明 标准版 专业版 备注
1 监控串口读写数据
2 监控串口控制码协议
3 监控所有COM端口类型
4 同时监控多个串口
5 64位系统驱动签名
6 监控正在使用中的串口 需要网络服务程序支持
7 远程网络监控串口(TCP/UDP) 需要网络服务程序支持
8 复制监控数据(本地监控)
9 复制监控数据(远程网络监控)
10 保存监控数据日志(本地监控)
11 保存监控数据日志(远程网络监控)
购买价格: 免费 118(包3台电脑注册) 单位:RMB

SDK OCX版本

1、专业版: 有64位驱动签名,支持串口CTRL码分析、同时监控多个串口, 支持服务启动,解决绑定使用中的串口失败问题,适合32/64位系统使用;
2、企业版: 有64位驱动签名,支持串口CTRL码分析、同时多个串口监控,支持服务启动,解决绑定使用中的串口失败问题;支持监控串口数据网络转发功能,可将监控串口数据转发到Socket(TCP/UDP)网络上去,你的客户端可以是windows/Linux,只要有网络就可以了;适合32/64位系统使用;
3、源码版:定制Sys驱动+SDK OCX源代码。

购买SDK/OCX咨询QQ:348677065

CommMonitor SDK/OCX 10.0版本 日期:2018-01-15
序号 功能说明 专业版 企业版 备注
1 监控串口读写数据
2 监控串口控制码协议
3 所有COM端口类型
4 同时监控多个串口
5 64位系统驱动签名
6 监控正在使用中的串口 需要服务程序支持
7 远程网络监控串口(TCP/UDP) 需要服务程序支持

 

CommMonitor8.0测试

1、WinXP X86测试200万次IRP读写:

2、WinServer 2003  X64测试110万次IRP读写:

3、WinVista X64测试500万次IRP读写: 

4、Win7 X64测试325万次IRP读写:

win7 x64位,325万次读写

5、Win8 X64测试170万次IRP读写:

Win8 x64 170万次
Win8 x64 170万次

6、Win2008 X64测试660万次IRP读写:

Win Server 2008 660次

7、Win2012 X64测试100万次IRP读写:

Win server 2012 100万次

8、Win2016 X64测试276万次IRP读写:

Win server 2016 276 万次

9、Win10 X64测试610万次IRP读写:

Win10 610万次

10、Win7 X86 测试1500 万次IRP读写:

Win7 X86 测试1500 万次
Win7 X86 测试1500 万次