演示从注册表中还原MSNMessenger口令

/* MSNMessenger的口令是经过DPAPI加密后保存在注册表中的
     * 这个程序演示解码过程
     * 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; //口令密文从第二位开始
     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 but
     * 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 a
     * 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);
     }