├── README.md ├── LICENSE └── Chrome Password Recovery.go /README.md: -------------------------------------------------------------------------------- 1 | # Chrome-Password-Recovery 2 | A Simple Go program for Windows that will recover Google Chrome Logins... Made for Windows but you might be able to edit it to work with any system. You may need to edit the path to the Login Data file, Though it should work fine in most cases. 3 | 4 | DOES NOT EXPORT OUT OF FILE, LISTS ALL LOGINS IN CONSOLE ONLY. 5 | 6 | # Features 7 | * Gives URL, USERNAME and Decrypted PASSWORD 8 | 9 | # Compiling 10 | Import needed packages. (gcc is needed!) 11 | go build Chrome Password Recovery.go 12 | 13 | # Packages Used 14 | * github.com/mattn/go-sqlite3 15 | 16 | # Other 17 | Go is a amazing and powerful programming language. If you already haven't, check it out; https://golang.org/ 18 | 19 | # Donations 20 | 21 |

Please Donate To Bitcoin Address: 1AEbR1utjaYu3SGtBKZCLJMRR5RS7Bp7eE

22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Adam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chrome Password Recovery.go: -------------------------------------------------------------------------------- 1 | //Chrome Password Recovery project main.go 2 | //Recover Websites, Username and Passwords from Google Chromes Login Data file. 3 | 4 | //Windows Only 5 | 6 | //SQLLite3 - github.com/mattn/go-sqlite3 7 | //Using Crypt32.dll (win32crypt) for decryption 8 | 9 | //C:\Users\{USERNAME}\AppData\Local\Google\Chrome\User Data\Default 10 | 11 | package main 12 | 13 | import ( 14 | "database/sql" 15 | "fmt" 16 | "io" 17 | "log" 18 | "os" 19 | "syscall" 20 | "unsafe" 21 | "strings" 22 | "encoding/json" 23 | "io/ioutil" 24 | "encoding/base64" 25 | "crypto/aes" 26 | "crypto/cipher" 27 | _ "github.com/mattn/go-sqlite3" 28 | ) 29 | 30 | var ( 31 | dllcrypt32 = syscall.NewLazyDLL("Crypt32.dll") 32 | dllkernel32 = syscall.NewLazyDLL("Kernel32.dll") 33 | 34 | procDecryptData = dllcrypt32.NewProc("CryptUnprotectData") 35 | procLocalFree = dllkernel32.NewProc("LocalFree") 36 | 37 | dataPath string = os.Getenv("USERPROFILE") + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data" 38 | localStatePath string = os.Getenv("USERPROFILE") + "\\AppData\\Local\\Google\\Chrome\\User Data\\Local State" 39 | masterKey []byte 40 | ) 41 | 42 | type DATA_BLOB struct { 43 | cbData uint32 44 | pbData *byte 45 | } 46 | 47 | func NewBlob(d []byte) *DATA_BLOB { 48 | if len(d) == 0 { 49 | return &DATA_BLOB{} 50 | } 51 | return &DATA_BLOB{ 52 | pbData: &d[0], 53 | cbData: uint32(len(d)), 54 | } 55 | } 56 | 57 | func (b *DATA_BLOB) ToByteArray() []byte { 58 | d := make([]byte, b.cbData) 59 | copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:]) 60 | return d 61 | } 62 | 63 | func Decrypt(data []byte) ([]byte, error) { 64 | var outblob DATA_BLOB 65 | r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outblob))) 66 | if r == 0 { 67 | return nil, err 68 | } 69 | defer procLocalFree.Call(uintptr(unsafe.Pointer(outblob.pbData))) 70 | return outblob.ToByteArray(), nil 71 | } 72 | 73 | func copyFileToDirectory(pathSourceFile string, pathDestFile string) error { 74 | sourceFile, err := os.Open(pathSourceFile) 75 | if err != nil { 76 | return err 77 | } 78 | defer sourceFile.Close() 79 | 80 | destFile, err := os.Create(pathDestFile) 81 | if err != nil { 82 | return err 83 | } 84 | defer destFile.Close() 85 | 86 | _, err = io.Copy(destFile, sourceFile) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | err = destFile.Sync() 92 | if err != nil { 93 | return err 94 | } 95 | 96 | sourceFileInfo, err := sourceFile.Stat() 97 | if err != nil { 98 | return err 99 | } 100 | 101 | destFileInfo, err := destFile.Stat() 102 | if err != nil { 103 | return err 104 | } 105 | 106 | if sourceFileInfo.Size() == destFileInfo.Size() { 107 | } else { 108 | return err 109 | } 110 | return nil 111 | } 112 | 113 | func checkFileExist(filePath string) bool { 114 | if _, err := os.Stat(filePath); os.IsNotExist(err) { 115 | return false 116 | } else { 117 | return true 118 | } 119 | } 120 | 121 | 122 | func getMasterKey() ([]byte,error){ 123 | 124 | var masterKey []byte 125 | 126 | // Get the master key 127 | // The master key is the key with which chrome encode the passwords but it has some suffixes and we need to work on it 128 | jsonFile, err := os.Open(localStatePath) // The rough key is stored in the Local State File which is a json file 129 | if err != nil { 130 | return masterKey,err 131 | } 132 | 133 | defer jsonFile.Close() 134 | 135 | byteValue, err := ioutil.ReadAll(jsonFile) 136 | if err != nil { 137 | return masterKey,err 138 | } 139 | var result map[string]interface{} 140 | json.Unmarshal([]byte(byteValue), &result) 141 | roughKey := result["os_crypt"].(map[string]interface{})["encrypted_key"].(string) // Found parsing the json in it 142 | decodedKey, err := base64.StdEncoding.DecodeString(roughKey)// It's stored in Base64 so.. Let's decode it 143 | stringKey := string(decodedKey) 144 | stringKey = strings.Trim(stringKey, "DPAPI") // The key is encrypted using the windows DPAPI method and signed with it. the key looks like "DPAPI05546sdf879z456..." Let's Remove DPAPI. 145 | 146 | masterKey,err = Decrypt([]byte(stringKey)) // Decrypt the key using the dllcrypt32 dll. 147 | if err != nil{ 148 | return masterKey,err 149 | } 150 | 151 | return masterKey,nil 152 | 153 | } 154 | 155 | func main() { 156 | //Check for Login Data file 157 | if !checkFileExist(dataPath) { 158 | os.Exit(0) 159 | } 160 | 161 | 162 | //Copy Login Data file to temp location 163 | err := copyFileToDirectory(dataPath, os.Getenv("APPDATA")+"\\tempfile.dat") 164 | if err != nil { 165 | log.Fatal(err) 166 | } 167 | 168 | 169 | //Open Database 170 | db, err := sql.Open("sqlite3", os.Getenv("APPDATA")+"\\tempfile.dat") 171 | if err != nil { 172 | log.Fatal(err) 173 | } 174 | defer db.Close() 175 | 176 | //Select Rows to get data from 177 | rows, err := db.Query("select origin_url, username_value, password_value from logins") 178 | if err != nil { 179 | log.Fatal(err) 180 | } 181 | defer rows.Close() 182 | 183 | for rows.Next() { 184 | var URL string 185 | var USERNAME string 186 | var PASSWORD string 187 | 188 | err = rows.Scan(&URL, &USERNAME, &PASSWORD) 189 | if err != nil { 190 | log.Fatal(err) 191 | } 192 | //Decrypt Passwords 193 | if strings.HasPrefix(PASSWORD, "v10"){ // Means it's chrome 80 or higher 194 | PASSWORD = strings.Trim(PASSWORD, "v10") 195 | 196 | //fmt.Println("Chrome Version is 80 or higher, switching to the AES 256 decrypt.") 197 | if string(masterKey) != ""{ 198 | ciphertext := []byte(PASSWORD) 199 | c, err := aes.NewCipher(masterKey) 200 | if err != nil { 201 | 202 | fmt.Println(err) 203 | } 204 | gcm, err := cipher.NewGCM(c) 205 | if err != nil { 206 | fmt.Println(err) 207 | } 208 | nonceSize := gcm.NonceSize() 209 | if len(ciphertext) < nonceSize { 210 | fmt.Println(err) 211 | } 212 | 213 | nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] 214 | plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) 215 | if err != nil { 216 | fmt.Println(err) 217 | } 218 | if string(plaintext) != ""{ 219 | fmt.Println(URL," | ", USERNAME," | ", string(plaintext)) 220 | //fmt.Println(URL," | ", USERNAME," | ", "**DEMO**") 221 | 222 | } 223 | }else{ // It the masterkey hasn't been requested yet, then gets it. 224 | mkey,err := getMasterKey() 225 | if err != nil{ 226 | fmt.Println(err) 227 | } 228 | masterKey = mkey 229 | } 230 | }else{ //Means it's chrome v. < 80 231 | pass, err := Decrypt([]byte(PASSWORD)) 232 | if err != nil { 233 | log.Fatal(err) 234 | } 235 | 236 | if URL != "" && URL != "" && string(pass) != "" { 237 | fmt.Println(URL, USERNAME, string(pass)) 238 | } 239 | } 240 | 241 | 242 | //Check if no value, if none skip 243 | 244 | } 245 | err = rows.Err() 246 | if err != nil { 247 | log.Fatal(err) 248 | } 249 | 250 | } 251 | --------------------------------------------------------------------------------