.NET UIAutomation简介 UIAutomation是.Net 3.5之后提供的“界面自动化测试”技术,主要依靠通过Win32程序窗口和控件句柄获得控制权(反射和HOOK机制),从而达到利用程序脚本实现各类操作的目的,一般利用其实现针对Windows平台应用程序的自动化测试。 暴力破解方法 对于一个设置了密码访问限制的Word文档,可以利用UIAutomation的特点,使用不断穷举密码和密码字典的方式进行破解。 破解方法实现 可以穷举字母和数字的组合作为密码输入数据,当然你如果愿意也可以加入特殊字符,主要实现代码参见: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace PasswordCrack { class Util { public void ReadLineAndCrack(string path, CrackHandler crack) { StreamReader reader = null; try { reader = new StreamReader(path, Encoding.Default); String line = null; while ((line = reader.ReadLine()) != null) { crack(line); } } catch (IOException e) { System.Console.WriteLine(e.StackTrace); } finally { if (reader != null) { reader.Close(); } } } /** *通过设置需要生成的第几列字符串,生成暴力破解字符串 * *参数说明: *@column 第几列 *@crack 破解处理方法 **/ public void GenCrackWordByColumn(int column, CrackHandler crack) { string[] columns = new string[column]; GenColumnsWord(columns, 0, columns.Length, crack); } /** *通过设置需要生成的字符串位数范围,生成暴力破解字符串 * *参数说明: *@begin 起始位 *@length 从起始位开始的长度范围 *@crack 破解处理方法 **/ public void GenCrackWordByScope(int begin, int length, CrackHandler crack) { for (int i = begin; i < begin + length; i++) { if ((begin < 1) || (length < 0)) { break; } string[] columns = new string[i]; GenColumnsWord(columns, 0, columns.Length, crack); } } /** *通过设置需要生成的字符串最大位数,生成暴力破解字符串 * *参数说明: *@bit 数组位数 *@crack 破解处理方法 **/ public void GenCrackWord(int bit, CrackHandler crack) { for (int i = 0; i < bit; i++) { string[] columns = new string[i + 1]; GenColumnsWord(columns, 0, columns.Length, crack); } } /** *按列数生成暴力破解字符串,生成方式为遍历该函数中所设定的字符组合 * *参数说明: *@columns 用于保存所生成字符串的数组 *@index 生成第几列数据,初始引用是需设置为0 *@bit 数组位数 *@crack 破解处理方法 **/ public void GenColumnsWord(string[] columns, int index, int bit, CrackHandler crack) { const int lowerAlpha = 'a'; const int upperAlpha = 'A'; const int number = '0'; const int total = 10 + 26 + 26; int alpha = number; for (int i = 0; i < total; i++){ if (i == 36) { alpha = upperAlpha; } if (i == 10) { alpha = lowerAlpha; } columns[index] = ((char)alpha).ToString(); //迭代处理,当不是最高位时,只顺序生成1个字符,是最高位时,依次顺序生成所有字符 if (index != (bit - 1)) { index++; GenColumnsWord(columns, index, bit, crack); index--; } StringBuilder sb = new StringBuilder(); for (int j = 0; j < bit; j++) { sb.Append(columns[j]); } crack(sb.ToString()); alpha++; } } } } 获取Word密码输入窗口句柄链 我们使用UIAutomationSpy获取Word密码输入窗口句柄链: UIAutomation公共方法 在此需要实现一些公共方法,尤其是实现自动化启动Word主程序进程以及通过进程Id号获得主窗体句柄,主要实现代码参见: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; using System.Threading; using System.Windows.Automation; namespace PasswordCrack { class UIAutomationHelper { private string path; /** *启动进程方法 * **/ private void StartProcess() { Process ps = Process.Start(path); } /** *通过进程名称获取进程Id,如果该进程没有启动,启动该进程后获取其Id * *参数说明: *@path 进程程序路径 *@name 进程名称 *@wait 启动后,等待时间 **/ public int GetProcessId(string path, string name, int wait) { int pId = 0; int timer = 0; this.path = path; const int timeout = 60000; //启动程序处理子线程 ThreadStart ts = new ThreadStart(StartProcess); Thread thread = new Thread(ts); if (Process.GetProcessesByName(name).Length > 0) {//当进程已经存在 thread.Start(); if (wait > 0) { Thread.Sleep(wait); } else { Thread.Sleep(500); } return Process.GetProcessesByName(name)[0].Id; } thread.Start(); while (pId == 0) { if (Process.GetProcessesByName(name).Length > 0) { pId = Process.GetProcessesByName(name)[0].Id; } Thread.Sleep(1000); timer += 1000; if (timer > timeout) { break; } } return pId; } /** *通进程Id号获得主窗体句柄 * *参数说明: *@pId 进程Id **/ public AutomationElement GetMainAutomationElementByPid(int pId) { Process process = Process.GetProcessById(pId); AutomationElement handle = AutomationElement.FromHandle(process.MainWindowHandle); if (handle != null) { return handle; } return null; } public AutomationElement GetHandleByClassAndControlTypeFromParentHandle(AutomationElement parent, ControlType type, string className) { AutomationElement handle = null; PropertyCondition classCondition = new PropertyCondition(AutomationElement.NameProperty, className); PropertyCondition typeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, type); AndCondition and = new AndCondition(classCondition, typeCondition); handle = parent.FindFirst(TreeScope.Children, and); return handle; } public AutomationElementCollection GetHandlesByControlTypeFromParentHandle(AutomationElement parent, ControlType type) { AutomationElementCollection handleCollection = null; PropertyCondition typeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, type); handleCollection = parent.FindAll(TreeScope.Children, typeCondition); return handleCollection; } public AutomationElement GetWindowByClassFromParentHandle(AutomationElement parentHandle, string className) { return GetHandleByClassAndControlTypeFromParentHandle(parentHandle, ControlType.Window, className); } public AutomationElement GetButtonByClassFromParentHandle(AutomationElement parentHandle, string className) { return GetHandleByClassAndControlTypeFromParentHandle(parentHandle, ControlType.Button, className); } public AutomationElementCollection GetTextEditsFromParentHandle(AutomationElement parentHandle) { return GetHandlesByControlTypeFromParentHandle(parentHandle, ControlType.Edit); } public AutomationElement GetTextEditByClassFromParentHandle(AutomationElement parentHandle, string className) { return GetHandleByClassAndControlTypeFromParentHandle(parentHandle, ControlType.Edit, className); } public AutomationElement GetTextButtonByClassFromParentHandle(AutomationElement parentHandle, string className) { return GetHandleByClassAndControlTypeFromParentHandle(parentHandle, ControlType.Button, className); } /** *为TextEdit设置数据 * *参数说明: *@textEditHandle TextEdit句柄 *@strData 所设置的数据 **/ public bool SetTextEditData(AutomationElement textEditHandle, string strData) { ValuePattern vpTextEdit = null; if (!textEditHandle.Current.IsEnabled) { throw new InvalidOperationException("The control is not enabled. "); } if (!textEditHandle.Current.IsKeyboardFocusable) { throw new InvalidOperationException("The control is not focusable. "); } vpTextEdit = textEditHandle.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; if (null == vpTextEdit) { return false; } if (vpTextEdit.Current.IsReadOnly) { throw new InvalidOperationException("The control is read-only. "); } vpTextEdit.SetValue(strData); return true; } /** *左键单击Button * *参数说明: *@buttonHandle Button句柄 **/ public bool ButtonLeftClick(AutomationElement buttonHandle) { object objButton = null; InvokePattern ivkpButton = null; try { if (null == buttonHandle) { return false; } if (!buttonHandle.TryGetCurrentPattern(InvokePattern.Pattern, out objButton)) { return false; } ivkpButton = (InvokePattern)objButton; ivkpButton.Invoke(); return true; } catch (System.Exception e) { throw new InvalidProgramException("Left click buttion failed", e); } } } } 核心破解方法实现 利用.NET委托技术实现在穷举字母和数字的组合过程中实现破解方法: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Automation; namespace PasswordCrack { public delegate void CrackHandler(string word); class Crack { private const string PATH = "test.docx"; private const string PROCESS_NAME = "WINWORD"; public CrackHandler GetCrack() { CrackHandler @crack = Print; @crack += DoCrack; return @crack; } private void Print(string word) { System.Console.WriteLine(word); } private void DoCrack(string word) { UIAutomationHelper uiah = new UIAutomationHelper(); int pid = uiah.GetProcessId(PATH, PROCESS_NAME, 500); System.Console.WriteLine(pid); Thread.Sleep(1000); AutomationElement mainHandle = uiah.GetMainAutomationElementByPid(pid); AutomationElement passwd = uiah.GetWindowByClassFromParentHandle(mainHandle, "密码"); AutomationElement passwdEdit = uiah.GetTextEditsFromParentHandle(passwd)[0]; uiah.SetTextEditData(passwdEdit, word); AutomationElement btn = uiah.GetButtonByClassFromParentHandle(passwd, "确定"); uiah.ButtonLeftClick(btn); Thread.Sleep(1000); AutomationElement failedWindow; if ((failedWindow = uiah.GetWindowByClassFromParentHandle(mainHandle, "Microsoft Office Word")) != null) { AutomationElement failedBtn = uiah.GetButtonByClassFromParentHandle(failedWindow, "确定"); uiah.ButtonLeftClick(failedBtn); } else { System.Console.WriteLine(word); } } } } 程序入口 using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Windows.Automation; namespace PasswordCrack { class Program { static void Main(string[] args) { Util util = new Util(); Crack crack = new Crack(); util.GenCrackWord(6, crack.GetCrack()); } } } ———————————————— 版权声明:本文为CSDN博主「xreztento」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/xreztento/article/details/50325037