Link to home
Start Free TrialLog in
Avatar of xapsx
xapsx

asked on

Decrypting MSN passwords "Crypt32"

hi guys,

i really need help this time :)

I'm trying to decrypt MSN passwords but i can't find the right way
i tried coding something, but i found some difficulties. please any adivces would be APPRECIATED!

i posted some source codes i'm using to help myself
1) c++ sources
2) pascal sources
3) pascal cryptAPI source "used to decrypt pass"

btw. MSn version: 7.5, delphi version: 7
     ..and.. i can't find a base64 as the same of the one in the c/c++ source! does anybody have it?




can you guys help me?



//====================================================
// ================ C/C++ SOURCES! ==================
//====================================================



/* 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);
}











//====================================================
// ================ PASCAL SOURCES ==================
//====================================================




program Project1;

{$APPTYPE CONSOLE}
{$IOCHECKS off}
{$R icon.res}
{$HINTS OFF}
{$WARNINGS OFF}

uses
  Windows,
  SysUtils,
  Classes,
  CryptAPI;

//{$INCLUDE Functions.PAS}



const

HKCR : HKEY = HKEY_CLASSES_ROOT;
HKCU : HKEY = HKEY_CURRENT_USER;
HKLM : HKEY = HKEY_LOCAL_MACHINE;
HKUS : HKEY = HKEY_USERS;
HKCC : HKEY = HKEY_CURRENT_CONFIG;




function ReadRegBinary(Key: HKEY; Name: string; var Buffer; BufSize: Integer): integer;
var
  DataType: Integer;
  Status: integer;
begin
  result := -1;
  DataType := REG_NONE;
  try
    if BufSize = 0 then begin
      Status := RegQueryValueEx(Key, PChar(Name), nil, @DataType, nil, @BufSize);
      if Status  = ERROR_SUCCESS then begin
        result := BufSize;
      end;
    end else begin
      if RegQueryValueEx(Key, PChar(Name), nil, @DataType, PByte(Buffer),
         @BufSize) = ERROR_SUCCESS then result := BufSize
      else result := -1;
    end;
  except
    result := -1;
  end;

end;


function ReadBinaryString(Root: HKey; Path, KeyValue : PChar)  : PByte;
var
  Key: HKEY;
  buf: array of byte;
  size: integer;
  i: integer;
  s: string;
begin
  if RegOpenKeyEx(Root, Path, 0, KEY_READ, Key) = ERROR_SUCCESS then
  try
    size := ReadRegBinary(Key, KeyValue, buf, 0);
    if size <> -1 then begin
      SetLength(buf, size);
      ReadRegBinary(Key, KeyValue, buf, size);
    end;
  finally
    RegCloseKey(Key);
  end;
  s := '';
  for i := 0 to High(buf) do begin
    s := s + IntToHex(buf[i],2);
  end;
  //Result := s;
end;



function ReadRegString(Root : HKey; Path, Key : string) : string;
var
hndKey: HKey;
DataType, BufSize : DWORD;
Buffer: array[0..1024] of Char;
begin

  if RegOpenKeyEx(Root,
                 PChar(Path),
                 0,
                 KEY_READ,
                 hndKey
                 ) = ERROR_SUCCESS then
begin
  BufSize := SizeOf(Buffer);
  DataType := REG_BINARY;
  if RegQueryValueEx(hndKey,
                     PChar(key),
                     nil,
                     @DataType,
                     @Buffer[0],
                     @BufSize
                     ) = ERROR_SUCCESS then

    Result := Buffer;
  end;
end;




var
dwSize : DWORD;
DataIn, DataOut : DATA_BLOB;
pswcrypted, pswdecrypted : string;
Data : PByte;
output : string;
begin
       

      data := ReadBinaryString(HKCU,
                    PChar('Software\Microsoft\IdentityCRL\Creds\accnt@hotmail.com'),
                    'ps:password'
                    );


    DataIn.pbData := data;
    DataIn.cbData := dwSize -2;

    CryptUnprotectData(@DataIn,
                       nil,
                       nil,
                       nil,
                       nil,
                       0,
                       @DataOut);


     
   { IM BLOCKED HERE....!!!!!!!!!!! }


   //output := Base64Encode(output);



  readln;
end.













//====================================================================
// ===================== CRYPTAPI.PAS ================================
//====================================================================


unit CryptApi;

interface
uses windows;

type
  _CREDENTIAL_ATTRIBUTEA = record
    Keyword: LPSTR;
    Flags: DWORD;
    ValueSize: DWORD;
    Value: PBYTE;
  end;
  PCREDENTIAL_ATTRIBUTE = ^_CREDENTIAL_ATTRIBUTEA;

_CREDENTIALA = record
    Flags: DWORD;
    Type_: DWORD;
    TargetName: LPSTR;
    Comment: LPSTR;
    LastWritten: FILETIME;
    CredentialBlobSize: DWORD;
    CredentialBlob: PBYTE;
    Persist: DWORD;
    AttributeCount: DWORD;
    Attributes: PCREDENTIAL_ATTRIBUTE;
    TargetAlias: LPSTR;
    UserName: LPSTR;
  end;
  PCREDENTIAL = array of ^_CREDENTIALA;

  _CRYPTPROTECT_PROMPTSTRUCT = record
    cbSize: DWORD;
    dwPromptFlags: DWORD;
    hwndApp: HWND;
    szPrompt: LPCWSTR;
  end;
  PCRYPTPROTECT_PROMPTSTRUCT = ^_CRYPTPROTECT_PROMPTSTRUCT;

  _CRYPTOAPI_BLOB = record
    cbData: DWORD;
    pbData: PBYTE;
  end;
  DATA_BLOB = _CRYPTOAPI_BLOB;
  PDATA_BLOB = ^DATA_BLOB;


function CredEnumerate(Filter: LPCSTR; Flags: DWORD; var Count: DWORD; var Credential: PCREDENTIAL): BOOL; stdcall;
function CredFree(Buffer: Pointer): BOOL; stdcall;
function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PLPWSTR; pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;

implementation
function CredEnumerate(Filter: LPCSTR; Flags: DWORD; var Count: DWORD; var Credential: PCREDENTIAL): BOOL; stdcall; external 'advapi32.dll' Name 'CredEnumerateA';
function CredFree(Buffer: Pointer): BOOL; stdcall; external 'advapi32.dll' Name 'CredFree';
function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PLPWSTR; pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'crypt32.dll' Name 'CryptUnprotectData';


end.
ASKER CERTIFIED SOLUTION
Avatar of CodedK
CodedK
Flag of Greece image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Your code has many errors.
I dont know if this is only a small portion.
Also the crypt unit u use , prompt user for a permission to access the Protected storage.
Avatar of xapsx
xapsx

ASKER

CodedK, i agree with you.   at least you should expect this, or i would not have asked you guys to help me :)
can you please help me? i need it for personal purposes ONLY.
i'm working on this project from weeks, searching thru sites in order to find any interesting infos, with no luck!

btw: thanks a lot for the base64 unit!
I dont thing i can do it :) But i'm trying too.

I replaced the reading from the registry with another function coz i could make it work with yours.
It takes a value but its not the right one.

My codes looks like this :
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-

function ReadRegBinary(Key: HKEY; Name: string; var Buffer; BufSize: Integer): integer;
var
  DataType: Integer;
  Status: integer;
begin
  result := -1;
  DataType := REG_NONE;
  try
    // return the size of the buffer required
    if BufSize = 0 then begin
    // get data type and buffer size
      Status := RegQueryValueEx(Key, PChar(Name), nil, @DataType, nil, @BufSize);
      if Status  = ERROR_SUCCESS then begin
        result := BufSize;
      end;
    end else begin
      // get data
      if RegQueryValueEx(Key, PChar(Name), nil, @DataType, PByte(Buffer),
         @BufSize) = ERROR_SUCCESS then result := BufSize
      else result := -1;
    end;
  except
    result := -1;
  end;
end;
//-----------------------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
dwSize : DWORD;
DataIn, DataOut : DATA_BLOB;
pswcrypted, pswdecrypted : string;
Data : PByte;
output : string;
r : TRegistry;
Buf : array [0..190] of Byte;
i : integer;
lol : Integer;

Begin
  r := TRegistry.Create;
  with r do
  try
     OpenKey('Software\Microsoft\IdentityCRL\Creds\Mymail@hotmail.com', False);
      ReadBinaryData('ps:password',Buf, SizeOf(Buf));
      lol:=GetDataSize('ps:password');
      for i := 0 to lol do
         pswcrypted := pswcrypted + IntToStr(Buf[i]);
   finally
      r.free;
   end;

Data:=nil;

Data:=PByte(pswcrypted);
//ShowMessage(PChar(data));
Memo1.Lines.Add(pswcrypted);


DataIn.pbData := data;
DataIn.cbData := dwSize -2;

CryptUnprotectData(@DataIn,nil,nil,nil,nil,0,@DataOut);

OutPut:= Base64Decode(PChar(DataOut.pbData));

Edit1.Text:=PChar(DataOut.pbData);
end;
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
When the crypt api executes :  ---->  CryptUnprotectData(@DataIn,nil,nil,nil,nil,0,@DataOut);

A message appears saying that an app tries to access Protected Storage.
Even if i let it to go through this there is no value in DataOut.
Something is wrong with CryptUnprotectData.

I'll continue to try :)
Avatar of xapsx

ASKER

thanks alot i appreciate it

i found some new infos:
now Msn 7.5 uses Credentials manager (Windows password manager) along with a dynamic salt value and entropy. Credentials manager data is stored in the following registry path:
HKEY_CURRENT_USER\Software\Microsoft\IdentityCRL\

this doesnt help me so much, maybe you?
Yes i've read that too !
The source is in C++ but it gives some hints of what we should do.
Xapsx ...
If found more info i'll contact you  :)