Windows Live Mailのメールサーバ設定からパスワードを読み出す

概要

 タイトル通りです。経緯としては、前任者が使っていた古いパソコン(Windows8)のメール設定にYahooメールのアカウントがあったのですが、パスワードが分からず、新しいパソコンに移行するのに支障が出たため、なんとかしようとした件となります。

 Windows Live Mailに設定したメールアカウントのパスワードがわからなくなった方(いるのか?)は参考にしてください。

対応

 メールソフトはWindows Live Mailだったのですが、すでにサポートが切れており、アカウント設定(パスワード)を他のソフトや新しいPCに移行する手段がありませんでした。(メールの本文等は移行できましたが。)

 で、以下のサイトを参考に、レジストリと設定ファイルにあるバイナリ値からパスワードを復元するプログラムを書いて、パスワードを出力させて解決しました。

 ちなみに、パスワードを入力したWindows Live Mailが動いているパソコンで実行しないとパスワードは復元できません。

 

 How to Recover Saved Email Passwords in Windows Live Mail | XenArmor

 

 [Win32] Encryption via Data Protection API (DPAPI) | すなのかたまり

 

プログラム

// ConsoleApplication1.cpp : このファイルには 'main' 関数が含まれています。プログラム実行の開始と終了がそこで行われます。
//

// https://xenarmor.com/how-to-recover-saved-email-passwords-in-windows-live-mail/
// https://msmania.wordpress.com/2011/11/06/win32-encryption-via-data-protection-api-dpapi-2/

#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <Wincrypt.h>

#pragma comment(lib, "Crypt32.lib")

// salt binary from ...
// HKEY_CURRENT_USER\Software\Microsoft\Windows Live Mail
const char salttxt[] = "f34d312fb8(略)025a5e";

// password binary from ...
// 
// [Windows Vista/7/8/10]
// C:\Users\[user_name]\AppData\Local\Microsoft\Windows Live Mail\[random_name].oeaccount
//
// [Windows XP / 2003]
// C:\Documents and Settings\[user_name]\Local Settings\Application Data\Microsoft\Windows Live Mail\[random_name].oeaccount
const char   pwtxt[] = "01000000d08c9ddf0115d1118c7a00c0"
"4fc297eb01000000fad5a274e0ea6540"
(略)
"e8dac16eaf88";

const char BIN[] = "0123456789abcdef";

int BinValue(char ch)
{
	int index;
	for (index = 0; index < sizeof(BIN); index++) {
		if (ch == BIN[index]) {
			return index;
		}
	}
	return -1;
}

int Text2Bin(const char* textData, int textLen, char* binArea, int length)
{
	int textIndex;
	int binIndex;
	char binChar;

	for (textIndex = 0, binIndex = 0; textIndex < textLen; textIndex++) {
		binChar = tolower(textData[textIndex]);
		int ret = BinValue(binChar);
		if (ret == -1) {
			break;
		}
		if (textIndex % 2 == 0) {
			binArea[binIndex] = 0xFF & (ret << 4);
		}
		else {
			binArea[binIndex] = binArea[binIndex] | (0x0F & ret);
			binIndex++;
		}
	}
	return binIndex;
}

void DecryptPassword(char* byteSalt, int dwSaltDataSize, char* passData, int passLen, char* strPassword, int length)
{
	DATA_BLOB DataPassword;
	DATA_BLOB DataOutput;
	DATA_BLOB OptionalEntropy;

	OptionalEntropy.pbData = (BYTE*)byteSalt;
	OptionalEntropy.cbData = dwSaltDataSize;

	DataPassword.cbData = passLen;
	DataPassword.pbData = (BYTE*)passData;

	if (CryptUnprotectData(&DataPassword, NULL, &OptionalEntropy, 0, 0, 0, &DataOutput) == FALSE)
	{
		// パスワードを生成したPCで実行しないと、0x8009000bのエラーになる
		printf("CryptUnprotectData failed with error 0x%.8x", GetLastError());
		return;
	}

	DataOutput.pbData[DataOutput.cbData] = 0;

	//convert password to ascii
	WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)DataOutput.pbData, DataOutput.cbData / 2, strPassword, length, NULL, NULL);

	printf("Decrypted Password is %s\n", strPassword);

	LocalFree(DataOutput.pbData);

}

int main()
{
	std::cout << "--- start\n";

	char saltBuf[256];
	int saltLen = Text2Bin(salttxt, (int)sizeof(salttxt), saltBuf, (int)sizeof(saltBuf));
	char pwBuf[256];
	int pwLen = Text2Bin(pwtxt, (int)sizeof(pwtxt), pwBuf, (int)sizeof(pwBuf));
	char strPassword[256];
	DecryptPassword(saltBuf, saltLen, pwBuf, pwLen, strPassword, (int)sizeof(strPassword));

    std::cout << "--- end\n";
}

開発環境

 Visual Studio 2022 (無料でダウンロードできるやつ)

 (別のパソコン(Windows11)でビルドして、対象PC(Windows8)で実行。)

 

雑感

 10年以上振りにVisual Studio使いました。今はタダでダウンロードできるんですねぇ。最初、Debugビルドのものを持って行って、いろいろ足りないと怒られて少し悩みました。そういえばReleaseビルドなるものがあったなと思い出して、それを持って行ったら動きました。

 バイナリ値をコードに直打ちしていますが、レジストリなりファイルから読み込めるのでその気になれば汎用的なものは作れると思います。(もうやらないと思うので、私は作りませんが。)