qq闪照恢复--go
闪照缓存目录:
文件管理/Android/data/com.tencent.mobileqq/xxx/Cache_xxxxxxxxx_fp
code
爆破DES 8字节密钥,每字节仅需考虑9种字符("02468@BDF"),9**8=43046721 种可能
// reference: https://keuin.cc/blog/cracking-encrypted-qq-flash-photos
//
// https://github.com/keuin/mobileqq-flash-photo-cracker
package main
import (
"bufio"
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/md5"
"flag"
"fmt"
"io"
"os"
"time"
)
const (
keychars string = "02468@BDF"
KEYSPACE_SIZE int = 43046721 //9**8
)
var (
jpg_magic = []byte{0xff, 0xd8, 0xff}
// png_magic = []byte{0x89, 0x50, 0x4e, 0x47}
fp_magic = []byte{0x45, 0x4E, 0x43, 0x52, 0x59, 0x50, 0x54, 0x3A} //ENCRYPT:
bruteThreads int
outPath string
fpPath string
isFindKey bool = false
done chan int
)
func checkPad(block *cipher.Block, lastData []byte) (bool, []byte) {
buf := make([]byte, 8)
(*block).Decrypt(buf, lastData[:8])
var pad_size = buf[7]
if pad_size > 8 {
return false, nil
}
for i := byte(8 - pad_size); i < pad_size; i++ {
if buf[i] != pad_size {
return false, nil
}
}
return true, buf[:8-pad_size]
}
func testDec(key, encData []byte) bool {
block, err := des.NewCipher(key)
if err != nil {
return false
}
headerData := make([]byte, 8)
block.Decrypt(headerData, encData[:8])
// if bytes.Equal(headerData[:4], png_magic) || bytes.Equal(headerData[:3], jpg_magic) {
if bytes.Equal(headerData[:3], jpg_magic) {
fmt.Printf("[+]DES key:%s <---dec---> magic:%s\n", key, headerData)
isPad, lastpart := checkPad(&block, encData[len(encData)-8:])
if !isPad {
fmt.Println("[!]DES key Incorrect!")
return false
}
if isFindKey {
return false
}
isFindKey = true
// fmt.Printf("[*]DES key:%s\n", key)
buf := make([]byte, len(encData)-16)
bs := block.BlockSize()
dst := buf
data := encData[8 : len(encData)-8]
for len(data) > 0 {
block.Decrypt(dst, data[:bs])
data = data[bs:]
dst = dst[bs:]
}
x := append(headerData, buf...)
x = append(x, lastpart...)
writeData(outPath, x)
fmt.Printf("[*]key:%s<--------->md5:%X\n", key, md5.Sum(x))
fmt.Println("[*]save to:", outPath)
return true
}
return false
}
func worker(a, b int, encData []byte) {
var (
isFind bool
// k []byte
)
start := time.Now()
for i := a; i < b; i++ {
if isFindKey {
break
}
// isFind, k = testDec([]byte(Keys[i]))
isFind = testDec(genKey(i), encData)
if isFind {
isFindKey = true
fmt.Printf("[+]genKey(%v)\n", i)
// fmt.Println("[-]find key:", hex.EncodeToString(k))
break
}
}
elapsed := time.Since(start)
fmt.Printf("[-][%v-%v] time:%v\n", a, b, elapsed)
done <- 1
}
// #define FILL_KEY(buf, key, i) \
// do { ((buf)[7-(i)] = keychars[(key)%9u]); (key) /= 9u; } while(0)
func genKey(a int) []byte {
var s [8]byte
for i := 0; i < 8; i++ {
s[7-i] = keychars[a%9]
a /= 9
}
return s[:]
}
func writeData(fpath string, data []byte) {
fi, err := os.Create(fpath)
if err != nil {
fmt.Println(err)
return
}
defer fi.Close()
_, err = fi.Write(data)
if err != nil {
fmt.Println(err)
return
}
}
func readData(fpath string) []byte {
fi, err := os.Open(fpath)
if err != nil {
fmt.Println(err)
return nil
}
defer fi.Close()
r := bufio.NewReader(fi)
tmp := make([]byte, 8)
n, err := r.Read(tmp)
if err != nil && err != io.EOF && n != 8 {
fmt.Println(err)
return nil
}
if !bytes.Equal(tmp, fp_magic) {
return nil
}
var chunks []byte
buf := make([]byte, 4096)
for {
n, err := r.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
chunks = append(chunks, buf[:n]...)
}
return chunks
}
func doRun() {
done = make(chan int, bruteThreads)
range_size := int(KEYSPACE_SIZE / bruteThreads)
encData := readData(fpPath)
if encData == nil {
return
}
for i := 0; i < bruteThreads-1; i++ {
go worker(range_size*i, range_size*i+range_size, encData)
}
go worker(range_size*(bruteThreads-1), KEYSPACE_SIZE, encData)
//wait
for i := 0; i < cap(done); i++ {
<-done
}
fmt.Println("end")
}
func init() {
flag.StringVar(&outPath, "out", "", "(op)-->out path")
flag.StringVar(&fpPath, "in", "", "[must]-->in path")
flag.IntVar(&bruteThreads, "threads", 10, "(op)-->brute threads(Goroutine)")
flag.Parse()
if fpPath == "" {
flag.Usage()
os.Exit(-1)
}
if outPath == "" {
outPath = fpPath + "_dec.png"
}
}
func main() {
doRun()
}
log
main.exe -in pic.xb -out out.png -threads 40
[+]DES key:2B0F2880 <---dec---> magic:���� �Ex
[-][31208872-32285040] time:20.0654193s
[-][40894384-41970552] time:20.0654193s
[-][3228504-4304672] time:20.0947397s
[-][19371024-20447192] time:20.0684109s
[-][16142520-17218688] time:20.0684109s
[-][0-1076168] time:20.0947397s
[-][29056536-30132704] time:20.0670064s
[-][4304672-5380840] time:20.0953299s
[-][35513544-36589712] time:20.0670064s
[-][5380840-6457008] time:20.0947397s
[-][8609344-9685512] time:20.0953299s
[-][2152336-3228504] time:20.0953299s
[-][9685512-10761680] time:20.0947397s
[-][1076168-2152336] time:20.0953299s
[-][21523360-22599528] time:20.0680023s
[-][36589712-37665880] time:20.0670064s
[-][18294856-19371024] time:20.0690011s
[-][34437376-35513544] time:20.0680023s
[-][39818216-40894384] time:20.0670064s
[-][25828032-26904200] time:20.0883133s
[-][32285040-33361208] time:20.0654193s
[-][22599528-23675696] time:20.0685076s
[-][12914016-13990184] time:20.0726921s
[-][30132704-31208872] time:20.0675117s
[-][13990184-15066352] time:20.0715966s
[-][20447192-21523360] time:20.0695064s
[-][17218688-18294856] time:20.0695064s
[-][23675696-24751864] time:20.0685076s
[-][6457008-7533176] time:20.0958352s
[-][11837848-12914016] time:20.0715966s
[-][27980368-29056536] time:20.0685076s
[-][37665880-38742048] time:20.0685076s
[-][33361208-34437376] time:20.0685076s
[-][15066352-16142520] time:20.0695064s
[-][41970552-43046721] time:20.0953316s
[-][38742048-39818216] time:20.0664162s
[-][24751864-25828032] time:20.0685076s
[-][26904200-27980368] time:20.0685076s
[-][10761680-11837848] time:20.0958352s
[*]key:2B0F2880<--------->md5:
[*]save to: out.png
[+]genKey(8025192)
[-][7533176-8609344] time:20.1167501s
end