基于USBDeview的自制USB设备监管系统实现(3)——USB S/N Checker

10 篇文章 0 订阅

在本系列文章的第一章已经说明了USB S/N Checker程序的作用,本章将详细说明这个程序的编制思路,并附完整的源代码。

由于历史原因,USB S/N Checker在实现时被命名为usbdevicelogger(以下简称UDL)。

UDL用C/C++语言写成,其main函数如下:

int main(int argc, char* argv[])
{
   loadConfig(__configFilename, &config);

   /* 获取USB设备插入时间和主机名 */
   time_t currTime = time(NULL);
   struct tm *plugTime = localtime(&currTime);
   DWORD hostNameLength = sizeof(computerName) / sizeof(TCHAR);   // windows platform only
   GetComputerName((LPTSTR)computerName, &hostNameLength);        // windows platform only

   int serialNumberCount = loadSerialNumber(config.serialNumberFilename);
   char *currSerialNumber = argv[idx_serialNumber];
   bool found = checkSerialNumber(currSerialNumber, serialNumberCount);
   if (!found)
   {  // the serial number of the plugging device is illegal.
#ifdef __STOP_DEVICE__
      // stop the illegal USB device.
      sprintf(sysCmd, "usbdeview /stop_by_serial %s", currSerialNumber);
      system(sysCmd);
#endif // __STOP_DEVICE__
      // call webservice of NTMS to record the illegal action.
      notifyToNtms(plugTime, computerName, argc, argv);
   }
   saveDeviceInfo(plugTime, computerName, argc, argv, found);

   return found ? SUCCESS : ERROR_SN_ILLEGAL;
}

main函数揭示了UDL的大体运行流程:

  1. 首先获取当前时间,由于UDL是在插入U盘时被usbdeview激活,因此可以认为UDL启动运行的时间就是U盘插入的时间;
  2. 随后调用Win32 API中的GetComputerName函数获取当前主机名,这是需要被记入日志的重要元素;
  3. 从磁盘文件(默认为legal_sn.txt)中加载合法的U盘序列号清单,这个序列号清单文件是文本文件,每个序列号占用一行;
  4. 从命令行参数中获取当前插入的USB设备的序列号,调用自定义函数checkSerialNumber检查本次插入的USB设备的序列号是否在合法序列号清单中;
  5. 如果在合法序列号清单中未找到当前序列号,则使用/stop_by_serial命令调用usbdeview程序禁用这个USB设备,并通知USB Management System(本文命名为NTMS);
  6. 将本次USB设备插入事件记录到本地日志中;
  7. 结束。

main函数的第一条语句是调用loadConfig来装载UDL配置文件udl.ini,这个文件样式如下:

deviceLog=C:\Windows\usbdevice.log
agentName=ntmsAgent.exe
serialNumber=.\legal_sn.txt
debugLog=.\debug.log
baseUrl="http://ntms.company.com/ntms/illegalusb"

这个文件指定了UDL的运行时属性,每个参数占用一行,采用“key=value”的样式。注意:key和value之间用“=”字符分隔,'='字符前后不能有空格。key不区分大小写。value中的URL、文件路径最好用半角双引号包围起来。配置文件属性说明如下:

  • deviceLog属性指定了日志文件的文件名(完整绝对路径);
  • agentName属性指定了NTMS服务代理程序,UDL通过这个代理程序向NTMS发送消息;
  • serialNumber属性指定了UDL需要依据的合法序列号文件,可以是相对路径或绝对路径;
  • debugLog属性指定了UDL调试信息记录在哪个文件里;
  • baseUrl属性指定了URL可以通过浏览器向NTMS传递USB插入信息的URL(UDL可以通过条件编译被编译成绕过NTMS Agent直接调用浏览器向NTMS发送数据的模式)。

下面对UDL的部分函数做个说明。

  • checkSerialNumber函数
bool checkSerialNumber(char currSerialNumber[], int rangeCount)
{
   bool found = false;
   for(int index = 0; index < rangeCount; index ++)
   {
      if (strlen(currSerialNumber) == 0)     // for the device that has not serial number.
      {
         found = true;
         break;
      }
      int result = strcmp(currSerialNumber, legalSerianNumber[index]);
      if (result == 0)
      {
         found = true;
         break;
      }
   }
   return found;
}

注意里面有一段

      if (strlen(currSerialNumber) == 0)     // for the device that has not serial number.
      {
         found = true;
         break;
      }

这是判断当前插入的USB设备的序列号是否为空,若为空,则表示这个设备不是U盘,一般是USB key、USB键鼠之类的,这样的设备可以认为是合法设备,不用管它。

  • notifyToNtms函数
void notifyToNtms(struct tm *plugTime, char hostName[], int argc, char *argv[])
{  // Call NTMS agent to transfer the detail of USB device to NTMS.
   int errorCode = 0;
   char *dateTimeStr = dateTime2String(plugTime);
   sprintf(sysCmd, "%s \"%s\" \"%s\"", config.ntmsAgent, dateTimeStr, hostName);
   for(int argIndex = 1; argIndex < argc; argIndex ++)
   {
      strcat(sysCmd, " \"");
      strcat(sysCmd, argv[argIndex]);
      strcat(sysCmd, "\"");
   }
   free(dateTimeStr);
#ifdef __DEBUG_LOG__
   logDebug(plugTime, sysCmd);
#endif // __DEBUG_LOG__
#ifdef __INVOKE_NTMSAGENT__
   errorCode = system(sysCmd);
   if (errorCode == -1)
   {
      char errMsg[128];
      sprintf(errMsg, "system() error code: %d\n", errno);
      logDebug(plugTime, errMsg);
   }
#endif // __INVOKE_NTMSAGENT__

   return;
}

notifyToNtms函数会合成一个调用ntmsAgent代理程序的命令行,存入sysCmd字符数组中。完成命令行构造之后,notifyToNtms函数调用system(sysCmd)来执行通知NTMS的动作。

最后,列出UDL的完整源代码如下:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#ifdef __cplusplus
#include <string>

using namespace std;
#endif // __cplusplus

/**
   关于条件编译宏定义的说明:
   __cplusplus__              编译器内置宏。当使用C++编译器以C++方式编译此文件时,该宏被编译器定义。
   __STOP_DEVICE__            若定义了此宏,则插入非法USB设备时,usbdevicelogger会停用(断开)该设备,在usbdeview
                              中将看不到此设备。当插入的设备为USB存储设备时,其对应的盘符会消失。UDL正式部署前,
                              应该启用该宏定义,并重新编译UDL后部署。
   __SAVE_XML__               若定义了此宏,则插入USB设备时,usbdevicelogger会调用usbdeview将当前接入到计算机中的
                              所有USB设备详情保存到usbdevice.xml文件中。如果不需要调用usbdeview保存USB设备记录,则
                              无需启用该宏定义。
   __USE_WEBSERVICE__         若定义了此宏,则插入非法USB设备时,usbdevicelogger会调用NTMS agent将非法设备信息通过
                              WS接口传递给NTMS;否则,将调用系统默认浏览器,以URL方式传递给NTMS。
   __INVOKE_NTMSAGENT__       若定义了此宏,则会将非法插入设备的信息传递给NTMS,传递方法由__USE_WEBSERVICE__宏定义
                              决定。UDL正式部署前,应启用该宏定义,并重新编译UDL后部署。
   __HIDE_WINDOW__            若定义了此宏,则usbdevicelogger的窗口不会闪现。
   __DEBUG_LOG__              若定义了此宏,则usbdevicelogger运行时会生成调试日志,保存在debug.log文件中。当发现UDL
                              运行异常时,可启用该宏定义,并重新编译UDL后部署。
*/
#define __STOP_DEVICE__
// #define __SAVE_XML__
#define __USE_WEBSERVICE__
#define __INVOKE_NTMSAGENT__
#define __USE_CONFIG_FILE__
// #define __HIDE_WINDOW__
#define __DEBUG_LOG__

/** 以下是常数宏定义 */
#define __LEGAL_SN_COUNT__ 1024
#define __SN_LENGTH__ 64
#define __CMDLINE_LENGTH__ 16384
#define __MAX_URL_LENGTH__ 16384

const int SUCCESS = 0;
const int ERROR_SN_ILLEGAL = 1;

const char __configFilename[] = "udl.ini";
const char __deviceLogKey[] = "DEVICELOG";
const char __agentNameKey[] = "AGENTNAME";
const char __debugLogKey[] = "DEBUGLOG";
const char __baseUrlKey[] = "BASEURL";
const char __serialNumberKey[] = "SERIALNUMBER";

const char splitChar = '|';
const char urlParamNames[][32] =
{
   "plugTime",
   "hostName",
   "deviceDescr",
   "serialNumber",
   "deviceType",
   "serviceName",
   "deviceClass",
   "deviceMfg",
   "driverFile",
   "driverVersion",
   "firmwareVersion",
   "productName",
   "vendorName",
   "legalFlag"
};

typedef struct __tagConfig
{
   char logFilename[MAX_PATH + 1];
   char ntmsAgent[MAX_PATH + 1];
   char serialNumberFilename[MAX_PATH + 1];
   char debugLogFilename[MAX_PATH + 1];
   char baseUrl[__MAX_URL_LENGTH__ + 1];
} Config;

/*
char logFilename[MAX_PATH + 1] = "C:\\Windows\\usbdevice.log";
char ntmsAgent[MAX_PATH + 1] = "ntmsagent";
char serialNumberFilename[MAX_PATH + 1] = "legal_sn.txt";
char debugLogFilename[MAX_PATH + 1] = "debug.log";
char baseUrl[__MAX_URL_LENGTH__ + 1] = "http://ntms.803.sast.casc/ntms/illegalusb";
*/
Config config =
{
   "C:\\Windows\\usbdevice.log",
   ".\\ntmsagent",
   ".\\legal_sn.txt",
   ".\\debug.log",
   "http://ntms.803.sast.casc/ntms/illegalusb"
};

char legalSerianNumber[__LEGAL_SN_COUNT__][__SN_LENGTH__ + 1];  // 可以存放__LEGAL_COUNT__个合法序列号,每个序列号256个字节。
char computerName[MAX_COMPUTERNAME_LENGTH + 1];
char sysCmd[__CMDLINE_LENGTH__ + 1];
char ntmsUrl[__MAX_URL_LENGTH__ + 1];

typedef enum __tagDeviceParamsIndex   // 用于指示命令行参数中设备参数信息所在的位置索引。
{
   idx_deviceDescr = 1,
   idx_serialNumber = 2,
   idx_deviceType = 3,
   idx_serviceName = 4,
   idx_deviceClass = 5,
   idx_deviceMfg = 6,
   idx_driverFile = 7,
   idx_driverVersion = 8,
   idx_firmwareVersion = 9,
   idx_productName = 10,
   idx_vendorName = 11
} DeviceParamsIndex;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

WINBASEAPI HWND WINAPI GetConsoleWindow();

int loadConfig(const char configFile[], Config *config);
void saveDeviceInfo(struct tm *plugTime, char hostName[], int argc, char* argv[], bool legal);    // 保存当前插入的USB设备的详细信息到文件中。
int loadSerialNumber(const char fileName[]);    // 读入合法的USB设备序列号,返回值为读入的序列号个数。
bool checkSerialNumber(char currSerialNumber[], int rangeCount);     // 检查插入的USB设备序列号是否合法。合法则返回true,非法则返回false。
void notifyToNtms(struct tm *plugTime, char hostName[], int argc, char *argv[]);   // 将非法USB插入记录提交给NTMS。
void composeUrl(struct tm *plugTime, char hostName[], int argc, char *argv[], char url[]);
char *dateTime2String(struct tm *dateTime);

int replaceSpace(char src[], char dest[]);
void strupr(char str[]);

void logDebug(struct tm *plugTime, char logStr[]);

#ifdef __cplusplus
}
#endif // __cplusplus

int main(int argc, char* argv[])
{
#ifdef __HIDE_WINDOW__
   HWND consoleWindowHandle = GetConsoleWindow();
   ShowWindow(consoleWindowHandle, SW_HIDE);
#endif // __HIDE_WINDOW__

   loadConfig(__configFilename, &config);

   /* 获取USB设备插入时间和主机名 */
   time_t currTime = time(NULL);
   struct tm *plugTime = localtime(&currTime);
   DWORD hostNameLength = sizeof(computerName) / sizeof(TCHAR);   // windows platform only
   GetComputerName((LPTSTR)computerName, &hostNameLength);        // windows platform only

   int serialNumberCount = loadSerialNumber(config.serialNumberFilename);
   char *currSerialNumber = argv[idx_serialNumber];
   bool found = checkSerialNumber(currSerialNumber, serialNumberCount);
   if (!found)
   {  // the serial number of the plugging device is illegal.
#ifdef __STOP_DEVICE__
      // stop the illegal USB device.
      sprintf(sysCmd, "usbdeview /stop_by_serial %s", currSerialNumber);
      system(sysCmd);
#endif // __STOP_DEVICE__
      // call webservice of NTMS to record the illegal action.
      notifyToNtms(plugTime, computerName, argc, argv);
   }
   saveDeviceInfo(plugTime, computerName, argc, argv, found);

   return found ? SUCCESS : ERROR_SN_ILLEGAL;
}

int loadConfig(const char configFile[], Config *config)
{
   int loadCode = 0;
#ifdef __USE_CONFIG_FILE__
   const char splitter = '=';

   char *valuePtr;
   char key[32];
   char buffer[__MAX_URL_LENGTH__ + 1];
   FILE *cfgFp = fopen(configFile, "r");
   if (cfgFp != NULL)
   {
      loadCode = 0;
      do {
         fscanf(cfgFp, "%s", buffer);
         valuePtr = strchr(buffer, splitter);
         if (valuePtr == NULL)
         {
            loadCode = -2;
            break;
         }
         *valuePtr = '\0';
         valuePtr ++;
         // strncpy(key, buffer, strlen(buffer) - strlen(valuePtr) + 1);
         strcpy(key, buffer);
         strupr(key);
         if (!strcmp(key, __deviceLogKey))
         {
            strcpy(config->logFilename, valuePtr);
         }
         else if (!strcmp(key, __agentNameKey))
         {
            strcpy(config->ntmsAgent, valuePtr);
         }
         else if (!strcmp(key, __serialNumberKey))
         {
            strcpy(config->serialNumberFilename, valuePtr);
         }
         else if (!strcmp(key, __baseUrlKey))
         {
            strcpy(config->baseUrl, valuePtr);
         }
         else if (!strcmp(key, __debugLogKey))
         {
            strcpy(config->debugLogFilename, valuePtr);
         }
         else
         {
            loadCode = -2;
            break;
         }
      } while(!feof(cfgFp));
      fclose(cfgFp);
   }
   else
   {
      loadCode = -1;
   }
#endif // __USE_CONFIG_FILE__

   return loadCode;
}

void saveDeviceInfo(struct tm *plugTime, char hostName[], int argc, char* argv[], bool legal)
{
   FILE *ofp = fopen(config.logFilename, "a+");

   // record the date-time the USB device was plugged..
   fprintf(ofp, "%04d-%02d-%02d %02d:%02d:%02d",
           plugTime->tm_year + 1900, plugTime->tm_mon + 1, plugTime->tm_mday,
           plugTime->tm_hour, plugTime->tm_min, plugTime->tm_sec);
   // record the computer name.
   fprintf(ofp, "%c%s", splitChar, hostName);
   // record the detail of the plugged USB device.
   for(int argIdx = 1; argIdx < argc; argIdx ++)
   {
      fprintf(ofp, "%c%s", splitChar, argv[argIdx]);
   }
   fprintf(ofp, "%c%c", splitChar, legal ? 'Y' : 'N');
   fprintf(ofp, "\n");

   fclose(ofp);
#ifdef __SAVE_XML__
   system("usbdeview /sxml usbdevice.xml");     // optional //
#endif // __SAVE_XML__
}

int loadSerialNumber(const char fileName[])
{
   int count = 0;
   FILE *ifp = fopen(fileName, "r");
   if (ifp != NULL)
   {
      do {
         fscanf(ifp, "%s", legalSerianNumber[count]);
         count ++;
      } while(!feof(ifp));
      fclose(ifp);
   }

   return count;
}

bool checkSerialNumber(char currSerialNumber[], int rangeCount)
{
   bool found = false;
   for(int index = 0; index < rangeCount; index ++)
   {
      if (strlen(currSerialNumber) == 0)     // for the device that has not serial number.
      {
         found = true;
         break;
      }
      int result = strcmp(currSerialNumber, legalSerianNumber[index]);
      if (result == 0)
      {
         found = true;
         break;
      }
   }
   return found;
}

void notifyToNtms(struct tm *plugTime, char hostName[], int argc, char *argv[])
{  // Call NTMS agent to transfer the detail of USB device to NTMS.
   int errorCode = 0;
   char *dateTimeStr = dateTime2String(plugTime);
   sprintf(sysCmd, "%s \"%s\" \"%s\"", config.ntmsAgent, dateTimeStr, hostName);
   for(int argIndex = 1; argIndex < argc; argIndex ++)
   {
      strcat(sysCmd, " \"");
      strcat(sysCmd, argv[argIndex]);
      strcat(sysCmd, "\"");
   }
   free(dateTimeStr);
#ifdef __DEBUG_LOG__
   logDebug(plugTime, sysCmd);
#endif // __DEBUG_LOG__
#ifdef __INVOKE_NTMSAGENT__
   errorCode = system(sysCmd);
   if (errorCode == -1)
   {
      char errMsg[128];
      sprintf(errMsg, "system() error code: %d\n", errno);
      logDebug(plugTime, errMsg);
   }
#endif // __INVOKE_NTMSAGENT__

   return;
}

void logDebug(struct tm *plugTime, char logStr[])
{
   FILE *logFp = fopen(config.debugLogFilename, "a");
   char *dtStr = dateTime2String(plugTime);
   fprintf(logFp, "%s%c%s\n", dtStr, splitChar, logStr);
   free(dtStr);
   fclose(logFp);
   // system("pause");
}

char *dateTime2String(struct tm *dateTime)
{
   char *dateTimeString = (char *)malloc(64);
   if (dateTime != NULL)
   {  // if convert success, the memory space of dateTimeString will not be freed.
      sprintf(dateTimeString, "%04d-%02d-%02d %02d:%02d:%02d",
              dateTime->tm_year + 1900, dateTime->tm_mon + 1, dateTime->tm_mday,
              dateTime->tm_hour, dateTime->tm_min, dateTime->tm_sec);
   }
   else
   {
      free(dateTimeString);
      dateTimeString = NULL;
   }
   return dateTimeString;
}

void strupr(char str[])
{
   int length = strlen(str);
   for(int index = 0; index < length; index ++)
   {
      if ((str[index] >= 'a') && (str[index] <= 'z'))
      {
         str[index] -= 0x20;
      }
   }
}

以上代码用Code::Blocks + MinGW 5.10编译通过,并已经过简单测试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
近年来,随着移动设备的普及,许多用户习惯了使用USB设备传输数据。然而,在这个过程中,系统会在设备上留下未被删除的痕迹和垃圾文件,这些可能会造成信息泄露,或者占用存储空间。因此,我们需要一款高效的工具来深度清理USB设备使用痕迹。 目前市场上有许多USB设备管理软件,如USBDeview、Device Cleanup Tool、USB Oblivion等,但是在Windows系统中自带的磁盘清理工具Disk Cleanup也可以协助清理USB设备痕迹。以下是使用Disk Cleanup清理USB设备痕迹的具体步骤: 1. 将USB设备连接到电脑上,并等待电脑自动识别设备; 2. 打开“计算机”,右键选择连接的USB设备,点击“属性”; 3. 在“属性”窗口中,点击“磁盘清理”选项; 4. 系统会自动扫描USB设备中的垃圾文件,并列出详细清理项目; 5. 勾选需要清理的垃圾文件选项,然后点击“确定”按钮,系统会自动清理选中的垃圾文件。 需要注意的是,使用Disk Cleanup清理USB设备痕迹时,请选择删除“临时文件”,“缩略图”,“下载文件”等不必要的文件,不要删除USB设备中真正需要的文件。此外,清理USB设备时可能需要较长时间,耐心等待系统清理完成即可。 总的来说,无论是使用Disk Cleanup,还是其他USB设备管理软件,深度清理USB设备使用痕迹是保证数据安全和存储空间清理的重要措施之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值