为什么带有CryptUnprotectData的RAD Studio CreateBlobStream会返回额外的字符?

时间:2017-10-18 20:34:00

标签: c++ winapi c++builder

我正在编写一个从Chrome中提取密码的恢复应用。它有一个GUI,所以我使用了他们的SQLite包装器,它使用了SQLConnection和SQLQuery。这是我的代码片段:

//Create our blob stream
TStream *Stream2 = SQLQuery1->CreateBlobStream(SQLQuery1->FieldByName("password_value"), bmRead);
//Get our blob size
int size = Stream2->Size;
//Create our buffer
char* pbDataInput = new char[size+1];
//Adding null terminator to buffer
memset(pbDataInput, 0x00, sizeof(char)*(size+1));
//Write to our buffer
Stream2->ReadBuffer(pbDataInput, size);
DWORD cbDataInput = size;

DataOut.pbData = pbDataInput;
DataOut.cbData = cbDataInput;

LPWSTR pDescrOut = NULL;
//Decrypt password
CryptUnprotectData( &DataOut,
        &pDescrOut,
        NULL,
        NULL,
        NULL,
        0,
        &DataVerify);

//Output password
UnicodeString password = (UnicodeString)(char*)DataVerify.pbData;
passwordgrid->Cells[2][i] = password;

输出数据看起来很好,除了它的行为好像我的null终止符出了问题。以下是每行的输出结果:

Output Data With Extra Chars at end of Password

我已阅读

CryptUnprotectData的Windows文档:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa382377.aspx

CreateBlobStream的Embarcadero文档:

http://docwiki.embarcadero.com/Libraries/en/Data.DB.TDataSet.CreateBlobStream

memset的:

http://www.cplusplus.com/reference/cstring/memset/

1 个答案:

答案 0 :(得分:1)

您的阅读和解密呼叫仅在原始字节上运行,它们对字符串一无所知,也不关心它们。您要添加到pbDataInput的空终止符永远不会被使用,因此请删除它:

//Get our blob size
int size = Stream2->Size;
//Create our buffer
char* pbDataInput = new char[size];
//Write to our buffer
Stream2->ReadBuffer(pbDataInput, size);
DWORD cbDataInput = size;
...
delete[] pbDataInput;
delete Stream2;

现在,在将pbData分配给password时,您将pbData转换为char*,因此UnicodeString构造函数将数据解释为以null结尾ANSI字符串并使用系统默认的ANSI代码页将其转换为UTF-16,这可能是非ASCII字符的有损转换。那是你真正想要的吗?

如果是这样,并且如果解密的数据实际上不是以null结尾,则必须指定UnicodeString构造函数的字符数:

UnicodeString password( (char*)DataVerify.pbData, DataVerify.cbData );

另一方面,如果解密输出已经是UTF-16,则需要将pbData转换为wchar_t*而不是:

UnicodeString password = (wchar_t*)DataVerify.pbData;

或者,如果没有以空值终止:

UnicodeString password( (wchar_t*)DataVerify.pbData, DataVerify.cbData / sizeof(wchar_t) );