diff --git a/GUI.png b/GUI.png new file mode 100644 index 0000000..ac2e8f7 Binary files /dev/null and b/GUI.png differ diff --git a/Makefile b/Makefile index 3b3602d..4b4d41d 100644 --- a/Makefile +++ b/Makefile @@ -5,13 +5,18 @@ win64: GOOS=windows GOARCH=amd64 go build -tags windows -o thanos_decrypt_64.exe linux: - go build + GOOS=linux GOARCH=amd64 go build win32GUI: - GOOS=windows GOARCH=386 go build -tags windows,gui -ldflags="-H windowsgui -w -s" -o thanos_decrypt_32.exe + set GOARCH=386 + go build -tags windows,gui -ldflags="-H windowsgui -w -s" -o thanos_decrypt_32_GUI.exe win64GUI: - GOOS=windows GOARCH=amd64 go build -tags windows,gui -ldflags="-H windowsgui -w -s" -o thanos_decrypt_64.exe + set GOARCH=amd64 + go build -tags windows,gui -ldflags="-H windowsgui -w -s" -o thanos_decrypt_64_GUI.exe -all: win32 win64 linux win32GUI win64GUI +cross_linux: win32 win64 linux + +gui: win32GUI win64GUI +all: win32 win64 linux win32GUI win64GUI diff --git a/README.md b/README.md index 0e646c2..9aa79bc 100644 --- a/README.md +++ b/README.md @@ -102,11 +102,27 @@ The output should like this. Since we match the file with magic number, it might 2795306... ``` +### GUI +We provide a GUI version for windows users. All features is supported in the GUI version. If you know nothing about programming, please follow the steps below to decrypt your files: + +1. Choose a file to decrypt. +2. Choose the output file name. +3. Select "Use thread" and fill in 16. (Threads usually make the decryption routine faster, but it actually depends on amount of your cpu cores) +4. Select "Search extension" and fill in your file type. (For instance, PNG) +5. Click decrypt. +6. There is a counter, which shows the current guessing tickcount. +7. The decrypting result will show in the text block below. (There may be multiple possible key, so the decryption routine will continue to decrypt even find a possible key. You can terminate it at any time.) +8. Since the tickcounts (seeds) used to encrypt are near, you can try to record the seed above and select "Start tickcount" with value `seed-10000` next time. It may be faster. + +![GUI](/GUI.jpg?raw=true) + ## Build ```bash make win32 # windows 32 bits make win64 # windows 64 bits make linux # linux +make win32GUI # windows 32 bits GUI (built on windows) +make win64GUI # windows 64 bits GUI (build on windows) ``` ## Supported File Format diff --git a/go.mod b/go.mod index b63bbc2..43cdc87 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,10 @@ module thanos_decrypt go 1.15 require ( + github.com/akavel/rsrc v0.10.2 // indirect github.com/h2non/filetype v1.1.1 + github.com/lxn/walk v0.0.0-20210112085537-c389da54e794 // indirect + github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect + gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect ) diff --git a/go.sum b/go.sum index f703ce0..03fa37e 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,19 @@ +github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw= +github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/lxn/walk v0.0.0-20210112085537-c389da54e794 h1:NVRJ0Uy0SOFcXSKLsS65OmI1sgCCfiDUPj+cwnH7GZw= +github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= diff --git a/main.go b/main.go index 7f572c7..303793b 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,56 @@ +// +build !gui + +/* +MIT License + +Copyright (c) 2021 CyCraft Technology + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + package main import( "flag" + "log" + "fmt" + "strings" + "strconv" ) +var ctrLogger *log.Logger + +type ctrWritter struct{ + lastVal *int +} + +func (w ctrWritter) Write(p []byte) (n int, err error) { + strp := strings.TrimRight(string(p), "\n\r") + strp = strings.TrimLeft(strp, "\n\r") + stri, _ := strconv.Atoi(strp) + if stri / 1000 != *w.lastVal { + *w.lastVal = stri / 1000 + fmt.Printf("\r%d000...", stri/1000) + } + return len(p), nil +} + func main(){ inputFile := flag.String("i", "", "Input encrypted file.") outputFile := flag.String("o", "", "Output decrypted file.") @@ -17,6 +64,13 @@ func main(){ bytesFormat := flag.String("b", "", "Custom search with byte value. (i.e. \\xde\\xad\\xbe\\xef -> deadbeef)\nPlease use ?? to match any byte (i.e. de??beef)") flag.Parse() + ctrLogger = log.New(ctrWritter{new(int)}, "", 0) + + defer func(){ + // abandon panic to prevent process exit + recover() + }() + thanosDecrypt(decOption{ inputFile: *inputFile, outputFile: *outputFile, diff --git a/main.manifest b/main.manifest new file mode 100644 index 0000000..d36b771 --- /dev/null +++ b/main.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + PerMonitorV2, PerMonitor + True + + + diff --git a/main.syso b/main.syso new file mode 100644 index 0000000..b066647 Binary files /dev/null and b/main.syso differ diff --git a/main_gui.go b/main_gui.go index 35a9087..f0abfa4 100644 --- a/main_gui.go +++ b/main_gui.go @@ -30,12 +30,14 @@ import( "log" "time" "math" + "strings" + "strconv" "github.com/lxn/walk" . "github.com/lxn/walk/declarative" ) - +var ctrLogger *log.Logger type logWritter struct { results *walk.TextEdit @@ -46,11 +48,28 @@ func (w logWritter) Write(p []byte) (n int, err error) { return len(p), nil } +type ctrWritter struct { + ctrText *walk.TextLabel + lastVal *int +} + +func (w ctrWritter) Write(p []byte) (n int, err error) { + strp := strings.TrimLeft(string(p), "\r") + strp = strings.TrimRight(strp, "\n") + intp, err := strconv.Atoi(strp) + if (intp / 1000) != *w.lastVal { + *w.lastVal = intp / 1000 + w.ctrText.SetText(strconv.Itoa(intp/1000) + "000...") + } + return len(p), nil +} + type mainWindow struct { *walk.MainWindow inputFile *walk.LineEdit outputFile *walk.LineEdit results *walk.TextEdit + counter *walk.TextLabel // tickcount useCurTick *walk.CheckBox startTick *walk.CheckBox @@ -111,7 +130,13 @@ func (mw *mainWindow) selectStartTick(){ func (mw *mainWindow) decrypt(){ mw.opt.inputFile = mw.inputFile.Text() + if mw.opt.inputFile == "Input file" { + mw.opt.inputFile = "" + } mw.opt.outputFile = mw.outputFile.Text() + if mw.opt.outputFile == "Output file" { + mw.opt.outputFile = "" + } if mw.startTick.CheckState() == walk.CheckChecked { mw.opt.startTick = int(mw.startTickNum.Value()) } @@ -137,7 +162,13 @@ func (mw *mainWindow) decrypt(){ mw.opt.bytesFormat = mw.searchBytes.Text() } - go thanosDecrypt(mw.opt) + go func(){ + defer func(){ + // abandon panic to prevent process exit + recover() + }() + thanosDecrypt(mw.opt) + }() } @@ -157,8 +188,9 @@ func main(){ // log to results (set after run) go func(){ - time.Sleep(time.Second) + time.Sleep(3 * time.Second) log.SetOutput(logWritter{mw.results}) + ctrLogger = log.New(ctrWritter{mw.counter, new(int)}, "", 0) }() // mainWindow @@ -346,14 +378,25 @@ func main(){ }, }, // Decrypt - PushButton{ - Text: "Decrypt", - OnClicked: mw.decrypt, + Composite{ + Layout: HBox{}, + Children: []Widget{ + PushButton{ + Text: "Decrypt", + OnClicked: mw.decrypt, + }, + TextLabel{ + AssignTo: &mw.counter, + }, + }, }, // result TextEdit{ AssignTo: &mw.results, ReadOnly: true, + HScroll: true, + VScroll: true, + MinSize: Size{Height: 200}, }, }, }.Run()); err != nil { diff --git a/thanos_decrypt.go b/thanos_decrypt.go index b99de37..931e61a 100644 --- a/thanos_decrypt.go +++ b/thanos_decrypt.go @@ -75,7 +75,7 @@ func writeFile(data []byte, path string, seed int32, key string) error { func decRoutine(jobs chan int32, result chan bool, file []byte, output string, exam *examine.TypeExam) { plain := make([]byte, len(file)) for seed := range jobs { - fmt.Printf("\r%d", seed) + go ctrLogger.Printf("\r%d", seed) key := genKey(seed) salsa20.XORKeyStream(plain, file, []byte{1, 2, 3, 4, 5, 6, 7, 8}, &key) if exam.Match(plain) { @@ -92,13 +92,13 @@ func decRoutine(jobs chan int32, result chan bool, file []byte, output string, e func thanosDecrypt(opt decOption){ if opt.inputFile == "" || opt.outputFile == "" { - log.Fatal("Please provide input file path and output file path") + log.Panic("Please provide input file path and output file path") } if opt.key != "" { // decrypt file with the key file, err := ioutil.ReadFile(opt.inputFile) if err != nil { - log.Fatal(err) + log.Panic(err) } plain := make([]byte, len(file)) var key_b [32]byte @@ -106,24 +106,24 @@ func thanosDecrypt(opt decOption){ salsa20.XORKeyStream(plain, file, []byte{1, 2, 3, 4, 5, 6, 7, 8}, &key_b) err = ioutil.WriteFile(opt.outputFile, plain, 0644) if err != nil { - log.Fatal(err) + log.Panic(err) } } else { // guess key if opt.threadCount <= 0 { - log.Fatal("Please provide a positive integer.") + log.Panic("Please provide a positive integer.") } else if opt.format == "" && opt.customSearch == "" && opt.bytesFormat == "" { - log.Fatal("Please provide a possible file extension or custom search string.") + log.Panic("Please provide a possible file extension or custom search string.") } else if opt.customSearch == "" && opt.bytesFormat == "" && !filetype.IsSupported(opt.format) { - log.Fatal("Unsupported format. Please provide a custom search regular expression with -s.") + log.Panic("Unsupported format. Please provide a custom search regular expression with -s.") } else if len(opt.bytesFormat) % 2 == 1 { - log.Fatal("Lemgth of bytes format should be a multiple of 2.") + log.Panic("Lemgth of bytes format should be a multiple of 2.") } if opt.startTick < 0 { opt.startTick = - opt.startTick } if opt.startTick > math.MaxInt32 { - log.Fatal("Tick count should between -2147483648 and 2147483648.") + log.Panic("Tick count should between -2147483648 and 2147483648.") } if opt.useCurTick { @@ -136,7 +136,7 @@ func thanosDecrypt(opt decOption){ // Read input file file, err := ioutil.ReadFile(opt.inputFile) if err != nil { - log.Fatal(err) + log.Panic(err) } // start worker