本文主要介绍了一个c#编写的rar压缩文件密码恢复工具,该程序通过加载密码字典文件,逐个尝试密码来破解受密码保护的rar文件。
主要功能包括
1.选择rar文件和密码字典
2.显示恢复进度
3.统计尝试密码数量和速度
4.计算剩余时间
本工具采用后台线程运行密码破解过程,可以避免ui冻结,并提供取消操作功能。
效果图
程序代码
using system; using system.collections.generic; using system.componentmodel; using system.diagnostics; using system.drawing; using system.io; using system.linq; using system.security.cryptography; using system.windows.forms; using sharpcompress.archives; using sharpcompress.archives.rar; using sharpcompress.common; using sharpcompress.readers; namespace rarpasswordrecovery { public partial class mainform : form { private backgroundworker worker; private long totalpasswords; private long testedpasswords; private stopwatch stopwatch; private list<string> passwordlist; private bool passwordfound; private string foundpassword; private bool isrunning; public mainform() { initializecomponent(); initializebackgroundworker(); setupui(); } private void initializebackgroundworker() { worker = new backgroundworker { workerreportsprogress = true, workersupportscancellation = true }; worker.dowork += worker_dowork; worker.progresschanged += worker_progresschanged; worker.runworkercompleted += worker_runworkercompleted; } private void setupui() { // 设置窗体 this.text = "rar密码恢复工具"; this.size = new size(800, 500); this.minimumsize = new size(600, 400); this.backcolor = color.fromargb(45, 45, 65); this.forecolor = color.white; this.formborderstyle = formborderstyle.fixedsingle; this.startposition = formstartposition.centerscreen; // 创建控件 createcontrols(); } private void createcontrols() { // 标题标签 label titlelabel = new label { text = "rar压缩文件密码恢复", font = new font("segoe ui", 16, fontstyle.bold), autosize = true, location = new point(20, 15), forecolor = color.lightskyblue }; this.controls.add(titlelabel); // rar文件选择 label lblrarfile = new label { text = "rar文件路径:", location = new point(20, 60), autosize = true }; this.controls.add(lblrarfile); textbox txtrarfilepath = new textbox { location = new point(120, 57), size = new size(500, 25), name = "txtrarfilepath", readonly = true }; this.controls.add(txtrarfilepath); button btnbrowserar = new button { text = "浏览...", location = new point(630, 55), size = new size(80, 25), name = "btnbrowserar", backcolor = color.fromargb(70, 70, 90), forecolor = color.white, flatstyle = flatstyle.flat }; btnbrowserar.flatappearance.bordersize = 0; btnbrowserar.click += btnbrowserar_click; this.controls.add(btnbrowserar); // 字典文件选择 label lbldictionary = new label { text = "密码字典文件:", location = new point(20, 100), autosize = true }; this.controls.add(lbldictionary); textbox txtdictionarypath = new textbox { location = new point(120, 97), size = new size(500, 25), name = "txtdictionarypath", readonly = true }; this.controls.add(txtdictionarypath); button btnbrowsedict = new button { text = "浏览...", location = new point(630, 95), size = new size(80, 25), name = "btnbrowsedict", backcolor = color.fromargb(70, 70, 90), forecolor = color.white, flatstyle = flatstyle.flat }; btnbrowsedict.flatappearance.bordersize = 0; btnbrowsedict.click += btnbrowsedict_click; this.controls.add(btnbrowsedict); // 进度条 progressbar progressbar = new progressbar { location = new point(20, 150), size = new size(690, 25), name = "progressbar", style = progressbarstyle.continuous }; this.controls.add(progressbar); // 状态标签 label lblstatus = new label { location = new point(20, 185), size = new size(690, 20), name = "lblstatus", text = "就绪", textalign = contentalignment.middleleft }; this.controls.add(lblstatus); // 统计信息 label lbltotal = new label { location = new point(20, 215), size = new size(200, 20), name = "lbltotalpasswords", text = "总密码数: 0" }; this.controls.add(lbltotal); label lbltested = new label { location = new point(230, 215), size = new size(200, 20), name = "lbltested", text = "已尝试: 0" }; this.controls.add(lbltested); label lblspeed = new label { location = new point(440, 215), size = new size(200, 20), name = "lblspeed", text = "速度: 0 p/s" }; this.controls.add(lblspeed); // 时间信息 label lblelapsed = new label { location = new point(20, 245), size = new size(200, 20), name = "lblelapsed", text = "已用时间: 00:00:00" }; this.controls.add(lblelapsed); label lblremaining = new label { location = new point(230, 245), size = new size(200, 20), name = "lblremaining", text = "剩余时间: --:--:--" }; this.controls.add(lblremaining); // 当前尝试密码 label lblcurrent = new label { text = "当前尝试密码:", location = new point(20, 280), autosize = true }; this.controls.add(lblcurrent); textbox txtcurrentpassword = new textbox { location = new point(120, 277), size = new size(500, 25), name = "txtcurrentpassword", readonly = true, font = new font("consolas", 10), backcolor = color.fromargb(30, 30, 40), forecolor = color.lightgreen }; this.controls.add(txtcurrentpassword); // 按钮 button btnstart = new button { text = "开始恢复", location = new point(200, 320), size = new size(120, 35), name = "btnstart", backcolor = color.seagreen, flatstyle = flatstyle.flat, font = new font("segoe ui", 10, fontstyle.bold) }; btnstart.flatappearance.bordersize = 0; btnstart.click += btnstart_click; this.controls.add(btnstart); button btncancel = new button { text = "取消", location = new point(340, 320), size = new size(120, 35), name = "btncancel", enabled = false, backcolor = color.indianred, flatstyle = flatstyle.flat, font = new font("segoe ui", 10) }; btncancel.flatappearance.bordersize = 0; btncancel.click += btncancel_click; this.controls.add(btncancel); // 法律声明 linklabel linklegal = new linklabel { text = "使用条款和道德声明", location = new point(20, 370), autosize = true, linkcolor = color.lightskyblue, activelinkcolor = color.cyan }; linklegal.linkclicked += linklegal_linkclicked; this.controls.add(linklegal); // 状态图标 picturebox statusicon = new picturebox { location = new point(650, 320), size = new size(60, 60), sizemode = pictureboxsizemode.zoom }; // 注意:在实际项目中,您需要添加自己的图标 statusicon.backcolor = color.transparent; this.controls.add(statusicon); } private void btnbrowserar_click(object sender, eventargs e) { using (openfiledialog openfiledialog = new openfiledialog()) { openfiledialog.filter = "rar files (*.rar)|*.rar|all files (*.*)|*.*"; openfiledialog.title = "选择rar文件"; if (openfiledialog.showdialog() == dialogresult.ok) { gettextbox("txtrarfilepath").text = openfiledialog.filename; } } } private void btnbrowsedict_click(object sender, eventargs e) { using (openfiledialog openfiledialog = new openfiledialog()) { openfiledialog.filter = "text files (*.txt)|*.txt|all files (*.*)|*.*"; openfiledialog.title = "选择密码字典文件"; if (openfiledialog.showdialog() == dialogresult.ok) { gettextbox("txtdictionarypath").text = openfiledialog.filename; } } } private void btnstart_click(object sender, eventargs e) { textbox txtrarfilepath = gettextbox("txtrarfilepath"); textbox txtdictionarypath = gettextbox("txtdictionarypath"); if (string.isnullorwhitespace(txtrarfilepath.text)) { messagebox.show("请选择rar文件", "错误", messageboxbuttons.ok, messageboxicon.error); return; } if (string.isnullorwhitespace(txtdictionarypath.text)) { messagebox.show("请选择密码字典文件", "错误", messageboxbuttons.ok, messageboxicon.error); return; } if (!file.exists(txtrarfilepath.text)) { messagebox.show("选择的rar文件不存在", "错误", messageboxbuttons.ok, messageboxicon.error); return; } if (!file.exists(txtdictionarypath.text)) { messagebox.show("选择的字典文件不存在", "错误", messageboxbuttons.ok, messageboxicon.error); return; } // 重置ui passwordfound = false; foundpassword = null; testedpasswords = 0; isrunning = true; getprogressbar().value = 0; getlabel("lblstatus").text = "加载密码字典..."; getlabel("lbltested").text = "已尝试: 0"; getlabel("lblspeed").text = "速度: 0 p/s"; getlabel("lblelapsed").text = "已用时间: 00:00:00"; getlabel("lblremaining").text = "剩余时间: --:--:--"; gettextbox("txtcurrentpassword").text = ""; getbutton("btnstart").enabled = false; getbutton("btncancel").enabled = true; try { // 读取字典文件 passwordlist = file.readalllines(txtdictionarypath.text) .where(p => !string.isnullorwhitespace(p)) .distinct() .tolist(); totalpasswords = passwordlist.count; if (totalpasswords == 0) { messagebox.show("字典文件为空", "错误", messageboxbuttons.ok, messageboxicon.error); resetui(); return; } getlabel("lbltotalpasswords").text = $"总密码数: {totalpasswords:n0}"; stopwatch = stopwatch.startnew(); worker.runworkerasync(); } catch (exception ex) { messagebox.show($"读取字典文件错误: {ex.message}", "错误", messageboxbuttons.ok, messageboxicon.error); resetui(); } } private void worker_dowork(object sender, doworkeventargs e) { backgroundworker worker = sender as backgroundworker; passwordfound = false; foundpassword = null; string rarfilepath = gettextbox("txtrarfilepath").text; try { // 尝试每个密码 for (int i = 0; i < passwordlist.count; i++) { if (worker.cancellationpending) { e.cancel = true; return; } string password = passwordlist[i]; testedpasswords++; try { // 修复:使用readeroptions传递密码 var options = new readeroptions { password = password, lookforheader = true, disablecheckincomplete = true }; // 尝试打开压缩文件 using (var archive = rararchive.open(rarfilepath, options)) { // 尝试访问第一个文件 var entry = archive.entries.firstordefault(); if (entry != null) { // 尝试读取少量数据 using (var stream = entry.openentrystream()) { byte[] buffer = new byte[10]; stream.read(buffer, 0, buffer.length); // 如果成功读取数据,密码正确 passwordfound = true; foundpassword = password; return; } } } } catch (sharpcompress.common.cryptographicexception) { // 密码错误,继续尝试 } catch (invalidformatexception) { // 密码错误或文件格式问题 } catch (exception ex) { // 其他错误,记录并继续尝试 worker.reportprogress(0, $"密码 '{password}' 尝试失败: {ex.message}"); } // 每100次尝试报告一次进度 if (testedpasswords % 100 == 0) { int progress = (int)((double)testedpasswords / totalpasswords * 100); worker.reportprogress(progress, password); } } } catch (exception ex) { worker.reportprogress(0, $"错误: {ex.message}"); } } private void worker_progresschanged(object sender, progresschangedeventargs e) { if (e.userstate is string currentpassword) { gettextbox("txtcurrentpassword").text = currentpassword; } getprogressbar().value = e.progresspercentage; getlabel("lbltested").text = $"已尝试: {testedpasswords:n0} / {totalpasswords:n0}"; // 计算速度 double seconds = stopwatch.elapsed.totalseconds; double passwordspersecond = seconds > 0 ? testedpasswords / seconds : 0; getlabel("lblspeed").text = $"速度: {passwordspersecond:n1} p/s"; // 计算剩余时间 if (passwordspersecond > 0) { long remaining = totalpasswords - testedpasswords; timespan remainingtime = timespan.fromseconds(remaining / passwordspersecond); getlabel("lblremaining").text = $"剩余时间: {remainingtime:hh\\:mm\\:ss}"; } getlabel("lblelapsed").text = $"已用时间: {stopwatch.elapsed:hh\\:mm\\:ss}"; getlabel("lblstatus").text = "正在尝试恢复密码..."; } private void worker_runworkercompleted(object sender, runworkercompletedeventargs e) { stopwatch.stop(); isrunning = false; if (e.cancelled) { getlabel("lblstatus").text = "操作已取消"; } else if (e.error != null) { getlabel("lblstatus").text = $"错误: {e.error.message}"; } else if (passwordfound) { getlabel("lblstatus").text = "密码已找到!"; gettextbox("txtcurrentpassword").text = foundpassword; gettextbox("txtcurrentpassword").forecolor = color.lime; messagebox.show($"密码已找到: {foundpassword}", "成功", messageboxbuttons.ok, messageboxicon.information); } else { getlabel("lblstatus").text = "在字典中未找到密码"; gettextbox("txtcurrentpassword").text = "未找到匹配的密码"; } getbutton("btnstart").enabled = true; getbutton("btncancel").enabled = false; } private void btncancel_click(object sender, eventargs e) { if (worker.isbusy) { worker.cancelasync(); getbutton("btncancel").enabled = false; getlabel("lblstatus").text = "正在取消操作..."; } } private void linklegal_linkclicked(object sender, linklabellinkclickedeventargs e) { messagebox.show("本工具仅供教育目的使用\n\n" + "仅限您合法拥有的文件使用\n\n" + "未经授权访问他人文件是违法行为\n\n" + "使用本工具即表示您同意承担所有责任", "法律和道德声明", messageboxbuttons.ok, messageboxicon.information); } private void resetui() { getbutton("btnstart").enabled = true; getbutton("btncancel").enabled = false; } // helper methods to get controls by name private textbox gettextbox(string name) => this.controls.find(name, true).firstordefault() as textbox; private label getlabel(string name) => this.controls.find(name, true).firstordefault() as label; private button getbutton(string name) => this.controls.find(name, true).firstordefault() as button; private progressbar getprogressbar() => this.controls.find("progressbar", true).firstordefault() as progressbar; } }
以上就是基于c#实现rar文件密码破解工具的详细内容,更多关于c#破解rar文件密码的资料请关注代码网其它相关文章!
发表评论