119 lines
2.5 KiB
Go
119 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/mholt/archiver"
|
|
)
|
|
|
|
func crack(tid int, file []byte, fn string, passwords []string, found **string, stop *bool, total *uint64, exited *int32) {
|
|
fmt.Println("Thread", tid, ": starting with", len(passwords), "passwords...")
|
|
|
|
rar := archiver.NewRar()
|
|
rar.ContinueOnError = false
|
|
rar.ImplicitTopLevelFolder = true
|
|
rar.OverwriteExisting = true
|
|
rar.MkdirAll = false
|
|
|
|
for i := 0; i < len(passwords); i++ {
|
|
if *stop {
|
|
goto end
|
|
}
|
|
|
|
cur_pass := passwords[i]
|
|
rar.Password = cur_pass
|
|
reader := bytes.NewReader(file)
|
|
|
|
err := rar.Open(reader, 0)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = rar.Read()
|
|
if err == nil {
|
|
*found = &passwords[i]
|
|
goto end
|
|
}
|
|
|
|
rar.Close()
|
|
atomic.AddUint64(total, 1)
|
|
}
|
|
end:
|
|
fmt.Println("Thread", tid, ": stopped.")
|
|
atomic.AddInt32(exited, 1)
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) != 4 {
|
|
log.Fatal("Invalid arguments. Usage: go run crargo.go [file path] [dictionary path] [thread count]")
|
|
}
|
|
|
|
fn := os.Args[1]
|
|
dictfn := os.Args[2]
|
|
var dict []string
|
|
threads, err := strconv.Atoi(os.Args[3])
|
|
if err != nil || threads <= 0 {
|
|
log.Fatal("Invalid thread count: \"", os.Args[3], "\"")
|
|
}
|
|
|
|
fmt.Println("Cracking \"", fn, "\" with dict \"", dictfn, "\" using ", threads, " threads...")
|
|
fmt.Println("Reading archive...")
|
|
fb, err := os.ReadFile(fn)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Println("Reading dictionary...")
|
|
dictf, err := os.Open(dictfn)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
scanner := bufio.NewScanner(dictf)
|
|
for scanner.Scan() {
|
|
dict = append(dict, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Println("Processed", len(dict), "dictionary entries.")
|
|
|
|
each_thread := len(dict) / threads
|
|
|
|
var found *string = nil
|
|
var stop bool = false
|
|
var total uint64 = 0
|
|
var exited int32 = 0
|
|
for i := 0; i < threads; i++ {
|
|
go crack(i, fb, fn, dict[each_thread*i:each_thread*(i+1)], &found, &stop, &total, &exited)
|
|
}
|
|
|
|
var sec int = 0
|
|
for {
|
|
time.Sleep(1 * time.Second)
|
|
sec++
|
|
if found != nil {
|
|
fmt.Print("Found password: \"", *found, "\"\n")
|
|
stop = true
|
|
for int(atomic.LoadInt32(&exited)) < threads {
|
|
}
|
|
break
|
|
} else if int(atomic.LoadInt32(&exited)) == threads {
|
|
fmt.Println("No password found!")
|
|
break
|
|
} else {
|
|
tot := atomic.LoadUint64(&total)
|
|
fmt.Println("main: total tries: ", tot, "(", tot/uint64(sec), " req/s)")
|
|
}
|
|
}
|
|
}
|