Comments: /* MSNMessenger password is encrypted by DPAPI and saved in the Registry * This program demonstrates the decoding process * tombkeeper [0x40] nsfocus [0x2e] com * tombkeeper [0x40] xfocus [0x2e] net * 2004.08.11 */# include <Windows. h> # pragma comment (lib, "Advap/* MSNMessenger password is saved in the registry after being encrypted by DPAPI
* This program demonstrates the decoding process.
* Tombkeeper [0x40] nsfocus [0x2e] com
* Tombkeeper [0x40] xfocus [0x2e] net
* 2004.08.11
*/# Include <Windows. h> # pragma comment (lib, "Advapi32.lib ")
# Define FCHK (a) if (! (A) {printf (# a "failed \ n"); return 0 ;}
Typedef struct _ CRYPTOAPI_BLOB {
DWORD cbData;
BYTE * pbData;
} DATA_BLOB;
Typedef struct _ CRYPTPROTECT_PROMPTSTRUCT {
DWORD cbSize;
DWORD dwPromptFlags;
HWND hwndApp;
LPCWSTR szPrompt;
} CRYPTPROTECT_PROMPTSTRUCT, * PCRYPTPROTECT_PROMPTSTRUCT;
Typedef BOOL (WINAPI * PCryptUnprotectData )(
DATA_BLOB * pDataIn,
LPWSTR * ppszDataDescr,
DATA_BLOB * pOptionalEntropy,
PVOID pvReserved,
CRYPTPROTECT_PROMPTSTRUCT * pPromptStruct,
DWORD dwFlags,
DATA_BLOB * pDataOut
);
PCryptUnprotectData CryptUnprotectData = NULL; int main (void)
{
Int ret;
HMODULE hNtdll;
HKEY hKey;
DWORD dwType;
Char Data [0x100] = {0 };
DWORD dwSize;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
Ret = RegOpenKeyEx
(
HKEY_CURRENT_USER,
"Software \ Microsoft \ MSNMessenger ",
0,
KEY_READ,
& HKey
);
If (ret! = ERROR_SUCCESS) return 1;
Ret = RegQueryValueEx
(
HKey,
"Password. NET Messenger Service ",
NULL,
& DwType,
Data,
& DwSize
);
If (ret! = ERROR_SUCCESS) return 1;
FCHK (hNtdll = LoadLibrary ("Crypt32.dll "))! = NULL );
FCHK (CryptUnprotectData = (PCryptUnprotectData)
GetProcAddress (hNtdll, "CryptUnprotectData "))! = NULL );
DataIn. pbData = Data 2; // password ciphertext starting from second
DataIn. cbData = dwSize-2;
CryptUnprotectData
(
& DataIn,
NULL,
NULL,
NULL,
NULL,
1,
& DataOut
);
Base64_decode (DataOut. pbData, Data, strlen (DataOut. pbData ));
Printf ("MSN Password: % s \ n", Data );
Return 0;
}
// Copied from GNU libc-libc/resolv/base64.c
Int base64_decode (char const * src, char * target, size_t targsize)
{
Static const char Base64 [] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /";
Static const char Pad64 = ';
Int tarindex, state, ch;
Char * pos;
State = 0;
Tarindex = 0;
While (ch = * src )! = '\ 0 ')
{
If (isspace (ch)/* Skip whitespace anywhere .*/
Continue;
If (ch = Pad64)
Break;
Pos = strchr (Base64, ch );
If (pos = 0)/* A non-base64 character .*/
Return (-1 );
Switch (state)
{
Case 0:
If (target)
{
If (size_t) tarindex> = targsize)
Return (-1 );
Target [tarindex] = (pos-Base64) <2;
}
State = 1;
Break;
Case 1:
If (target)
{
If (size_t) tarindex 1> = targsize)
Return (-1 );
Target [tarindex] | = (pos-Base64)> 4;
Target [tarindex 1] = (pos-Base64) & 0x0f) <4;
}
Tarindex;
State = 2;
Break;
Case 2:
If (target)
{
If (size_t) tarindex 1> = targsize)
Return (-1 );
Target [tarindex] | = (pos-Base64)> 2;
Target [tarindex 1] = (pos-Base64) & 0x03) <6;
}
Tarindex;
State = 3;
Break;
Case 3:
If (target)
{
If (size_t) tarindex> = targsize)
Return (-1 );
Target [tarindex] | = (pos-Base64 );
}
Tarindex;
State = 0;
Break;
Default:
Abort ();
}
}
/*
* We are done decoding Base-64 chars. Let's see if we ended
* On a byte boundary, and/or with erroneous trailing characters.
*/
If (ch = Pad64)
{/* We got a pad char .*/
Ch = * src;/* Skip it, get next .*/
Switch (state)
{
Case 0:/* Invalid = in first position */
Case 1:/* Invalid = in second position */
Return (-1 );
Case 2:/* Valid, means one byte of info */
/* Skip any number of spaces .*/
For (void) NULL; ch! = '\ 0'; ch = * src)
If (! Isspace (ch ))
Break;
/* Make sure there is another trailing = sign .*/
If (ch! = Pad64)
Return (-1 );
Ch = * src;/* Skip the = */
/* Fall through to "single trailing =" case .*/
/* FALLTHROUGH */
Case 3:/* Valid, means two bytes of info */
/*
* We know this char is an =. Is there anything
* Whitespace after it?
*/
For (void) NULL; ch! = '\ 0'; ch = * src)
If (! Isspace (ch ))
Return (-1 );
/*
* Now make sure for cases 2 and 3 that the "extra"
* Bits that slopped past the last full byte were
* Zeros. If we don't check them, they become
* Subliminal channel.
*/
If (target & target [tarindex]! = 0)
Return (-1 );
}
}
Else
{
/*
* We ended by seeing the end of the string. Make sure we
* Have no partial bytes lying around.
*/
If (state! = 0)
Return (-1 );
}
Return (tarindex );
}