Skip to content

Commit 2d8fd5d

Browse files
committed
Refactoring code to be lazy with error checkign and begin to support taking in salt,guid,path from command line instead of using hardcoded values.
1 parent 3967818 commit 2d8fd5d

1 file changed

Lines changed: 66 additions & 87 deletions

File tree

UserPreferencesExplorer/UserPreferencesExplorer.cpp

Lines changed: 66 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
#include <string>
33
#include <fstream>
44
#include <iostream>
5-
#include <openssl/evp.h>
65
#include <Windows.h>
76

7+
#include <openssl/evp.h>
8+
#include <boost/algorithm/hex.hpp>
9+
810
#pragma comment(lib, "libeay32")
911

1012
/// <summary>
@@ -14,23 +16,20 @@
1416
/// <returns>Container of sequential bytes or empty container on error.</returns>
1517
std::vector<uint8_t> ReadAllBytes(const std::string &path)
1618
{
17-
try
19+
std::ifstream inStream(path, std::ios::binary | std::ios::ate);
20+
auto fileSize = static_cast<size_t>(inStream.tellg());
21+
if (fileSize == 0)
1822
{
19-
std::ifstream inStream(path, std::ios::binary | std::ios::ate);
20-
auto fileSize = static_cast<size_t>(inStream.tellg());
21-
auto fileBytes = std::vector<uint8_t>(fileSize);
23+
throw std::exception("File is empty");
24+
}
2225

23-
inStream.seekg(0, std::ios::beg);
24-
inStream.read(reinterpret_cast<char *>(&fileBytes[0]), fileSize);
25-
inStream.close();
26+
auto fileBytes = std::vector<uint8_t>(fileSize);
2627

27-
return fileBytes;
28-
}
29-
catch (const std::exception& ex)
30-
{
31-
std::cerr << "Failed to read file '" << path << "' - " << ex.what() << std::endl;
32-
return std::vector<uint8_t>();
33-
}
28+
inStream.seekg(0, std::ios::beg);
29+
inStream.read(reinterpret_cast<char *>(&fileBytes[0]), fileSize);
30+
inStream.close();
31+
32+
return fileBytes;
3433
}
3534

3635
/// <summary>
@@ -42,55 +41,40 @@ std::vector<uint8_t> ReadAllBytes(const std::string &path)
4241
/// <param name="initialization_vector">Initialization vector used for decryption.</param>
4342
/// <param name="out_plaintext">[out] Decrypted bytes.</param>
4443
/// <returns>True on success.</returns>
45-
bool Decrypt(
44+
std::vector<uint8_t> Decrypt(
4645
const std::vector<uint8_t> &cipherText,
4746
const std::vector<uint8_t> &key,
48-
const std::vector<uint8_t> &initialization_vector,
49-
std::vector<uint8_t> &out_plaintext)
47+
const std::vector<uint8_t> &initialization_vector)
5048
{
51-
out_plaintext.resize(cipherText.size());
52-
int plaintext_length = 0;
53-
49+
auto out_plaintext = std::vector<uint8_t>(cipherText.size());
50+
auto plaintext_length = 0;
5451
auto cipher = EVP_aes_256_cbc();
5552
auto ctx = EVP_CIPHER_CTX_new();
5653

5754
EVP_CIPHER_CTX_init(ctx);
5855

59-
auto is_successful = EVP_DecryptInit_ex(ctx, cipher, nullptr, &key[0], &initialization_vector[0]);
60-
if (is_successful == false)
56+
if (!EVP_DecryptInit_ex(ctx, cipher, nullptr, &key[0], &initialization_vector[0]))
6157
{
62-
std::cerr << "EVP_DecryptInit_ex - FAILED" << std::endl;
6358
EVP_CIPHER_CTX_free(ctx);
64-
return false;
59+
throw std::exception("EVP_DecryptInit_ex - FAILED");
6560
}
6661

67-
is_successful = EVP_DecryptUpdate(
68-
ctx,
69-
&out_plaintext[0],
70-
&plaintext_length,
71-
&cipherText[0],
72-
static_cast<int>(cipherText.size())
73-
);
74-
75-
if (is_successful == false)
62+
if(!EVP_DecryptUpdate(ctx, &out_plaintext[0], &plaintext_length, &cipherText[0], static_cast<int>(cipherText.size())))
7663
{
77-
std::cerr << "EVP_DecryptUpdate - FAILED" << std::endl;
7864
EVP_CIPHER_CTX_free(ctx);
79-
return false;
65+
throw std::exception("EVP_DecryptUpdate - FAILED");
8066
}
8167

8268
auto additional_length = 0;
83-
is_successful = EVP_DecryptFinal_ex(ctx, &out_plaintext[plaintext_length], &additional_length);
84-
if (is_successful == false)
69+
if (!EVP_DecryptFinal_ex(ctx, &out_plaintext[plaintext_length], &additional_length))
8570
{
86-
std::cerr << "EVP_DecryptFinal_ex - FAILED" << std::endl;
8771
EVP_CIPHER_CTX_free(ctx);
88-
return false;
72+
throw std::exception("EVP_DecryptFinal_ex - FAILED");
8973
}
9074

9175
out_plaintext.resize(plaintext_length + additional_length);
9276
EVP_CIPHER_CTX_free(ctx);
93-
return true;
77+
return out_plaintext;
9478
}
9579

9680
/// <summary>
@@ -101,7 +85,7 @@ bool Decrypt(
10185
/// <param name="out_key">[out] Generated key.</param>
10286
/// <param name="out_initialization_vector">[out] Generated initialization vector.</param>
10387
/// <returns>True on success.</returns>
104-
bool GetKeys(
88+
void GetKeys(
10589
const std::vector<uint8_t> &salt,
10690
const std::vector<uint8_t> &source_bytes,
10791
std::vector<uint8_t> &out_key,
@@ -115,7 +99,7 @@ bool GetKeys(
11599
out_key.resize(cipher->key_len);
116100
out_initialization_vector.resize(cipher->iv_len);
117101

118-
auto result = EVP_BytesToKey(
102+
auto derived_key_length = EVP_BytesToKey(
119103
cipher,
120104
md,
121105
&salt[0],
@@ -125,7 +109,11 @@ bool GetKeys(
125109
&out_key[0],
126110
&out_initialization_vector[0]
127111
);
128-
return result > 0;
112+
113+
if (derived_key_length == 0)
114+
{
115+
throw std::exception("EVP_BytesToKey - Failed to generate key");
116+
}
129117
}
130118

131119
/// <summary>
@@ -165,26 +153,23 @@ std::string GetMachineGuid()
165153
if (result != ERROR_SUCCESS)
166154
{
167155
RegCloseKey(key_handle);
168-
std::cerr << "RegOpenKeyEx - FAILED" << std::endl;
169-
return "";
156+
throw std::exception("RegOpenKeyEx - FAILED");
170157
}
171158

172159
DWORD buff_size = 0;
173160
result = RegQueryValueExA(key_handle, kMachineGuidName.c_str(), nullptr, nullptr, nullptr, &buff_size);
174161
if (result != ERROR_SUCCESS)
175162
{
176163
RegCloseKey(key_handle);
177-
std::cerr << "RegQueryValueEx - FAILED" << std::endl;
178-
return "";
164+
throw std::exception("RegQueryValueEx - FAILED");
179165
}
180166

181167
auto machine_guid = std::vector<uint8_t>(buff_size);
182168
result = RegQueryValueExA(key_handle, kMachineGuidName.c_str(), nullptr, nullptr, &machine_guid[0], &buff_size);
183169
if (result != ERROR_SUCCESS)
184170
{
185171
RegCloseKey(key_handle);
186-
std::cerr << "RegQueryValueEx - FAILED" << std::endl;
187-
return "";
172+
throw std::exception("RegQueryValueEx - FAILED");
188173
}
189174

190175
RegCloseKey(key_handle);
@@ -215,56 +200,50 @@ std::string GetPathToUserPreferencesBag()
215200
return local_app_data_path + kDefaultUserPreferencesPath;
216201
}
217202

218-
int main(int argc, char* argv[])
219-
{
220-
// The salt is hardcoded
221-
static const std::vector<uint8_t> kSalt {
222-
0x6E, 0x3F, 0x03, 0x29, 0x49, 0x63, 0x7D, 0x2E
223-
};
224203

225-
auto machine_guid = GetMachineGuid();
226-
if (machine_guid.empty())
227-
{
228-
std::cerr << "Failed to get MachineGuid" << std::endl;
229-
return 0;
230-
}
204+
/// <summary>
205+
/// Decrypts the specified encrypted user preferences file
206+
/// </summary>
207+
/// <param name="file_path">Path to the encrypted UserPreferences.bag</param>
208+
/// <param name="machine_guid">Machine GUID used to encrypt the UserPreferences.bag</param>
209+
/// <param name="salt_string">Salt used to encrypt UserPreferences.bag</param>
210+
/// <returns>Decrypted user preferences</returns>
211+
std::string DecryptUserPreferences(const std::string& file_path, const std::string& machine_guid, const std::string& salt_string)
212+
{
213+
std::vector<uint8_t> salt_bytes;
214+
boost::algorithm::unhex(salt_string.begin(), salt_string.end(), std::back_inserter(salt_bytes));
231215

232216
auto machine_guid_bytes = std::vector<uint8_t>(machine_guid.begin(), machine_guid.end() - 1);
233217
auto mangled_data = MangleData(machine_guid_bytes);
234218

235219
std::vector<uint8_t> key;
236220
std::vector<uint8_t> initialization_vector;
237-
if (!GetKeys(kSalt, mangled_data, key, initialization_vector))
238-
{
239-
std::cerr << "Failed to generate keys" << std::endl;
240-
return EXIT_FAILURE;
241-
}
221+
GetKeys(salt_bytes, mangled_data, key, initialization_vector);
242222

243-
std::string path_to_decrypt;
244-
if (argc == 2)
245-
{
246-
path_to_decrypt = std::string(argv[1]);
247-
}
248-
else
249-
{
250-
path_to_decrypt = GetPathToUserPreferencesBag();
251-
}
223+
auto cipher_text = ReadAllBytes(file_path);
224+
auto plaintext = Decrypt(cipher_text, key, initialization_vector);
225+
226+
return std::string(plaintext.begin(), plaintext.end());
227+
}
252228

253-
auto cipher_text = ReadAllBytes(path_to_decrypt);
254-
if (cipher_text.empty())
229+
int main(int argc, char* argv[])
230+
{
231+
static const auto kSalt = std::string("6E3F032949637D2E");
232+
233+
try
255234
{
256-
std::cerr << "ReadAllBytes - FAILED" << std::endl;
257-
return EXIT_FAILURE;
258-
}
235+
auto user_preferences_path = GetPathToUserPreferencesBag();
236+
auto machine_guid = GetMachineGuid();
237+
auto salt = kSalt;
259238

260-
auto plaintext = std::vector<uint8_t>(cipher_text.size());
261-
if (!Decrypt(cipher_text, key, initialization_vector, plaintext))
239+
auto decrypted_preferences = DecryptUserPreferences(user_preferences_path, machine_guid, salt);
240+
std::cout << decrypted_preferences << std::endl;
241+
}
242+
catch (const std::exception& ex)
262243
{
263-
std::cerr << "Decrypt - FAILED" << std::endl;
244+
std::cerr << "Failed to decrypt user preferences: " << ex.what() << std::endl;
264245
return EXIT_FAILURE;
265246
}
266-
267-
std::cout << &plaintext[0] << std::endl;
268-
247+
269248
return EXIT_SUCCESS;
270249
}

0 commit comments

Comments
 (0)