简介
RAR Cracker是用GO编写的命令行工具,有助于破解受密码保护的RAR档案。它提供了两种工作模式:字典模式和蛮力模式。字典模式试图通过使用包含可能密码列表的字典文件来破解存档。蛮力模式基于用户定义的标准生成密码的所有可能组合。本文提供了对代码及其功能的深入说明。
代码解释
代码分为几个功能和一个主要功能。让我们深入了解代码的每个部分以了解其目的和功能。
-
crackRar
函数:- 此功能以RAR文件名和密码生成器频道为输入。
- 它试图通过使用提供的密码执行
unrar
命令来提取RAR存档。 - 如果提取成功(无错误),它将与密码一起打印提取的文件消息和返回。
- 如果密码生成器频道已经用尽(不再尝试密码),它将打印一条“对不起”消息,表明无法找到密码。
-
fromDictionary
函数:- 此功能将字典文件名作为输入并返回密码生成器频道。
- 它打开字典文件并读取每一行,通过密码生成器频道发送密码。
- 阅读所有行后,它关闭了通道并返回。
-
main
函数:- 它是程序的入口点。
- 该程序首先打印欢迎消息并提示用户获取RAR文件名。
- 然后,它使用
fileExists
函数验证了提供的文件名的存在。 - 接下来,该程序要求用户选择一个工作模式:字典或蛮力。
- 根据所选模式,它提示了其他输入,例如字典文件名或蛮力模式的标准(包括字母,符号,数字,数字,空格,最小和最大长度)。
- 最后,它通过使用提供的文件名和密码生成器调用
crackRar
函数来启动开裂过程。
-
fileExists
函数:- 它将文件名作为输入,并通过使用
os.Stat
函数检查文件是否存在。 - 它返回一个布尔值,指示文件是否存在。
- 它将文件名作为输入,并通过使用
-
brute
函数:- 此功能将起始长度,最大长度和各种布尔标志作为输入。
- 它生成密码生成器频道并返回。
- 该功能根据提供的标准(字母,数字,符号,空格)构建一个字符集。
- 它根据字符集的长度和基础计算最大组合数。
- 它通过生成密码并通过密码生成器频道发送它们来迭代所有可能的组合。
- 一旦生成了所有组合,它就会关闭通道并返回。
-
pow
功能:- 此功能需要两个整数A和B,并计算出A^b的指控。
- 它返回了指数的结果。
代码
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"strings"
)
func crackRar(rarFilename string, pwdGenerator <-chan string) {
for pwd := range pwdGenerator {
cmd := exec.Command("unrar", "x", "-p"+pwd, rarFilename)
err := cmd.Run()
if err == nil {
fmt.Println("File extracted")
fmt.Printf("The password is %s\n", pwd)
return
}
}
fmt.Println("Sorry, cannot find the password")
}
func fromDictionary(dicName string) <-chan string {
pwdGenerator := make(chan string)
go func() {
file, err := os.Open(dicName)
if err != nil {
fmt.Println("Error opening dictionary file:", err)
close(pwdGenerator)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
pwdGenerator <- scanner.Text()
}
close(pwdGenerator)
}()
return pwdGenerator
}
func main() {
fmt.Println("----------------------------------------------------")
fmt.Println(" RAR Cracker")
fmt.Println(" by @AYOUB")
fmt.Println("----------------------------------------------------")
reader := bufio.NewReader(os.Stdin)
fmt.Print("Please enter the filename: ")
filename, _ := reader.ReadString('\n')
filename = strings.TrimSpace(filename)
for !fileExists(filename) {
fmt.Print("No such file, please enter a valid filename: ")
filename, _ = reader.ReadString('\n')
filename = strings.TrimSpace(filename)
}
var mode string
for mode != "dictionary" && mode != "brute" {
fmt.Print("Please select a working mode [dictionary/brute]: ")
mode, _ = reader.ReadString('\n')
mode = strings.TrimSpace(mode)
}
var pwdGen <-chan string
if mode == "dictionary" {
fmt.Print("Please enter the filename of the dictionary: ")
dicName, _ := reader.ReadString('\n')
dicName = strings.TrimSpace(dicName)
for !fileExists(dicName) {
fmt.Print("No such file, please enter a valid filename: ")
dicName, _ = reader.ReadString('\n')
dicName = strings.TrimSpace(dicName)
}
pwdGen = fromDictionary(dicName)
}
if mode == "brute" {
var letters, symbols, numbers, spaces bool
fmt.Print("Include letters? [yes/no] (default yes) ")
includeLetters, _ := reader.ReadString('\n')
letters = strings.TrimSpace(includeLetters) != "no"
fmt.Print("Include symbols? [yes/no] (default yes) ")
includeSymbols, _ := reader.ReadString('\n')
symbols = strings.TrimSpace(includeSymbols) != "no"
fmt.Print("Include numbers? [yes/no] (default yes) ")
includeNumbers, _ := reader.ReadString('\n')
numbers = strings.TrimSpace(includeNumbers) != "no"
fmt.Print("Include spaces? [yes/no] (default no) ")
includeSpaces, _ := reader.ReadString('\n')
spaces = strings.TrimSpace(includeSpaces) == "yes"
fmt.Print("Min length: ")
var startLength int
fmt.Scanf("%d\n", &startLength)
fmt.Print("Max length: ")
var length int
fmt.Scanf("%d\n", &length)
pwdGen = brute(startLength, length, letters, numbers, symbols, spaces)
}
fmt.Println("Start cracking")
fmt.Println("This may take some time, please wait...")
crackRar(filename, pwdGen)
}
func fileExists(filename string) bool {
_, err := os.Stat(filename)
return err == nil
}
func brute(startLength, length int, letters, numbers, symbols, spaces bool) <-chan string {
pwdGenerator := make(chan string)
go func() {
charset := ""
if letters {
charset += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
if numbers {
charset += "0123456789"
}
if symbols {
charset += "!@#$%^&*()-_=+[]{}|;:',.<>/?`~"
}
if spaces {
charset += " "
}
base := len(charset)
maxCombinations := pow(base, length)
for i := 0; i < maxCombinations; i++ {
password := ""
n := i
for j := 0; j < length; j++ {
password = string(charset[n%base]) + password
n /= base
}
pwdGenerator <- password
if len(password) < length {
break
}
}
close(pwdGenerator)
}()
return pwdGenerator
}
func pow(a, b int) int {
result := 1
for i := 0; i < b; i++ {
result *= a
}
return result
}
该代码有几个限制:
-
有限的密码破解技术:该代码仅提供两种密码破解技术:字典模式和蛮力模式。它不包含更先进的技术,例如哈希破裂算法(例如MD5,SHA1)或彩虹桌查找。这些技术通常在破解密码方面更有效。
-
依赖外部工具:代码依赖于
unrar
命令行工具来提取RAR档案。该依赖关系假定该工具是在执行代码的系统上安装和访问的。如果unrar
工具不可用,则代码无法正常运行。 -
没有并行化:代码顺序执行密码破解过程,一次尝试一个密码。这种方法可能很慢,尤其是对于更长的密码长度或大词典。引入并行化技术(例如,在GO中使用goroutines)可以显着提高开裂过程的速度。
-
有限的错误处理:该代码缺乏全面的错误处理。例如,如果在提取过程中或读取字典文件时发生错误,则代码只会打印错误消息并继续执行。优雅地处理此类错误,为用户提供更好的反馈并通过文件I/O或命令执行处理潜在问题将更加健壮。
-
在蛮力模式下缺乏用户反馈:在蛮力模式下,通过编程生成密码,用户就剩余的进度或估计的时间没有任何反馈。添加某种形式的进度指示或状态更新将增强用户体验并更好地了解开裂过程。
-
有限的密码复杂性配置:虽然代码允许用户指定字母,数字,符号和空格的包含,但它并未提供对密码复杂性的更细粒度的控制。例如,它不允许用户定义特定的字符集或执行密码策略(例如,大写字母的最低要求,小写字母,特殊字符)。
-
不支持现代RAR加密:该代码假定使用传统的基于密码的加密对RAR档案进行加密。它不支持使用更高级加密方法的破解RAR档案,例如强对称加密或公开密码。
-
安全性和合法性关注:重要的是要注意,在没有适当授权的情况下使用此代码破解密码是非法和不道德的。尊重隐私并遵守适用的法律法规至关重要。该守则应用于教育目的或适当的法律授权。
这些限制突出了可以增强代码以提高功能,性能和安全性的领域。
结论:
提供的代码演示了GO中实现的基本RAR饼干。它提供了两种模式:字典和蛮力。字典模式使用包含潜在密码列表的文件,而蛮力模式基于用户定义的标准生成所有可能的组合。该代码展示了用于密码生成的通道,使用os/exec
的命令执行以及使用os
软件包的文件操作。通过了解此代码,您可以深入了解密码破解机制的工作方式以及如何在GO中实施它们。