Skip to content

Instantly share code, notes, and snippets.

@c0d3x27
Created June 21, 2023 09:25
Show Gist options
  • Save c0d3x27/4f479938828125cfab89bba67ddf6148 to your computer and use it in GitHub Desktop.
Save c0d3x27/4f479938828125cfab89bba67ddf6148 to your computer and use it in GitHub Desktop.
keepass
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace keepass_password_dumper
{
internal static class Program
{
private const string AllowedChars = "^[\x20-\x7E]+$";
private const int BufferSize = 524288;
private static void Main(string[] args)
{
var passwordChar = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "*" : "●";
if (args.Length < 1)
{
Console.WriteLine("Please specify a file path as an argument.");
return;
}
var filePath = args[0];
if (!File.Exists(filePath))
{
Console.WriteLine("File not found.");
return;
}
var pwdListPath = args.Length >= 2 ? args[1] : string.Empty;
var candidates = new Dictionary<int, HashSet<string>>();
var currentStrLen = 0;
var debugStr = string.Empty;
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var buffer = new byte[BufferSize];
int bytesRead;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
for (var i = 0; i < bytesRead - 1; i++)
{
if (buffer[i] == 0xCF && buffer[i + 1] == 0x25)
{
currentStrLen++;
i++;
debugStr += passwordChar;
}
else
{
if (currentStrLen == 0) continue;
currentStrLen++;
var character = new[] { buffer[i], buffer[i + 1] };
var strChar = System.Text.Encoding.Unicode.GetString(character);
var isValid = Regex.IsMatch(strChar, AllowedChars);
if (isValid)
{
if (!candidates.ContainsKey(currentStrLen))
{
candidates.Add(currentStrLen, new HashSet<string> { strChar });
}
else
{
if (!candidates[currentStrLen].Contains(strChar))
candidates[currentStrLen].Add(strChar);
}
debugStr += strChar;
Console.WriteLine($"Found: {debugStr}");
}
currentStrLen = 0;
debugStr = string.Empty;
}
}
}
Console.WriteLine("\nPassword candidates (character positions):");
Console.WriteLine($"Unknown characters are displayed as \"{passwordChar}\"");
Console.WriteLine($"1.:\t{passwordChar}");
var combined = passwordChar;
var count = 2;
foreach (var (key, value) in candidates.OrderBy(x => x.Key))
{
while (key > count)
{
Console.WriteLine($"{count}.:\t{passwordChar}");
combined += passwordChar;
count++;
}
Console.Write($"{key}.:\t");
if (value.Count != 1)
combined += "{";
foreach (var c in value)
{
Console.Write($"{c}, ");
combined += c;
if (value.Count != 1)
combined += ", ";
}
if (value.Count != 1)
combined = combined[..^2] + "}";
Console.WriteLine();
count++;
}
Console.WriteLine($"Combined: {combined}");
if (pwdListPath == string.Empty)
return;
var pwdList = new List<string>();
generatePwdList(candidates, pwdList, passwordChar);
File.WriteAllLines(pwdListPath, pwdList);
Console.WriteLine($"{pwdList.Count} possible passwords saved in {pwdListPath}. Unknown characters indicated as {passwordChar}");
}
private static void generatePwdList(
Dictionary<int, HashSet<string>> candidates,
List<string> pwdList,
string unknownChar,
string pwd = "",
int prevKey = 0)
{
foreach (var kvp in candidates)
{
while (kvp.Key != prevKey + 1)
{
pwd += unknownChar;
prevKey++;
}
prevKey = kvp.Key;
if (kvp.Value.Count == 1)
{
pwd += kvp.Value.First();
continue;
}
foreach (var val in kvp.Value)
{
generatePwdList(
candidates.Where(x => x.Key >= kvp.Key + 1).ToDictionary(d => d.Key, d => d.Value),
pwdList,
unknownChar,
pwd + val,
prevKey);
}
return;
}
pwdList.Add(pwd);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment