我有一个密码过滤器dll,至少现在只需要在成功更改用户帐户密码时将用户名和密码写入日志。我正在接触一些有关c字符串的古老问题。
我感兴趣的两个变量是PUNICODE_STRING类型(它只是一个* UNICODE_STRING)。当然,我在网上搜索这个数据类型,这个数据让我来到这里:http://msdn.microsoft.com/en-us/library/windows/desktop/aa380518(v=vs.85).aspx
提供该信息我知道我可以访问这种动物的长度,并且它有一个指向宽字符串的指针。真棒。这是提取我需要的内容的大量知识(所以我想)。
这是我的dll代码(dllmain.cpp)
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#define LOGFILE "c:\\PasswordFilter.txt"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void WriteToLog (const wchar_t* UserName, const wchar_t* NewPassword)
{
#ifdef LOGFILE
FILE* log = fopen(LOGFILE, "a");
if(NULL == log)
{
return;
}
fwprintf(log,L"%s password was successfully reset to %s\r\n",UserName,NewPassword);
fclose(log);
#endif
return;
}
LPWSTR __stdcall ConvertWideChar(PUNICODE_STRING input)
{
wchar_t* wszString = new wchar_t[input->Length + 1];
memset(wszString, 0, sizeof(wchar_t) * (input->Length + 1));
wcsncpy(wszString,input->Buffer,input->Length);
#ifdef LOGFILE
FILE* log = fopen(LOGFILE, "a");
if(NULL != log)
{
fwprintf(log,L"value of wszString: %s\r\n",wszString);
fclose(log);
}
#endif
return wszString;
}
BOOLEAN __stdcall InitializeChangeNotify(void)
{
return TRUE;
}
NTSTATUS __stdcall PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING NewPassword
)
{
LPWSTR ConvertedUserName = ConvertWideChar(UserName);
LPWSTR ConvertedNewPassword = ConvertWideChar(NewPassword);
WriteToLog(ConvertedUserName,ConvertedNewPassword);
return 0;
}
BOOLEAN __stdcall PasswordFilter(
PUNICODE_STRING AccountName,
PUNICODE_STRING FullName,
PUNICODE_STRING Password,
BOOLEAN SetOperation
)
{
return TRUE;
}
以下是头文件(stdafx.h)的内容
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#include <NTSecAPI.h>
// TODO: reference additional headers your program requires here
我自然担心的是保持准确性。这就是我的痛苦开始的地方。我们有一个wchar_t告诉我,这可能是UTF16格式的unicode(就像所有其他基于Windows的字符串一样)。上面的代码将PUNICODE_STRING的缓冲区复制到以零结尾的wchar_t(因为缓冲区不保证自己为零终止),然后尝试将该字符串输出到日志文件。
我首先尝试使用WideCharToMultiByte作为将缓冲区复制到字符串的方法,但这似乎永远不会起作用。结果将每次都为null。这也遇到了将unicode值转换为更简单格式的问题,这种格式存在数据丢失的风险。所以我现在决定使用我现在拥有的东西,但是记录的值在它们后面有?和其他垃圾,这可能是一个unicode问题。
如果可能,我真的希望保留此数据结构的unicode编码类型。我该怎么办并将我的值打印到日志中?
答案 0 :(得分:3)
您没有正确使用UNICODE_STRING::Length
字段。它以字节表示,而不是以字符表示。所以你没有正确分配+填充空终止缓冲区。您也在泄漏您分配的缓冲区。
根本不需要分配缓冲区。您可以将原始Buffer
和Length
值直接传递给fwprintf
,不需要空终结符:
NTSTATUS __stdcall PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING NewPassword
)
{
#ifdef LOGFILE
FILE* log = fopen(LOGFILE, "a");
if (NULL != log)
{
fwprintf(log, L"%.*s password was successfully reset to %.*s\r\n",
UserName->Length / sizeof(WCHAR), UserName->Buffer,
NewPassword->Length / sizeof(WCHAR), NewPassword->Buffer);
fclose(log);
}
#endif
return 0;
}
如果您确实需要添加空终止符,请使用std::wstring
而不是手动分配+复制:
#include <string>
NTSTATUS __stdcall PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING NewPassword
)
{
#ifdef LOGFILE
FILE* log = fopen(LOGFILE, "a");
if (NULL != log)
{
fwprintf(log, L"%.s password was successfully reset to %.s\r\n",
std::wstring(UserName->Buffer, UserName->Length / sizeof(WCHAR)).c_str(),
std::wstring(NewPassword->Buffer, NewPassword->Length / sizeof(WCHAR)).c_str());
fclose(log);
}
#endif
return 0;
}
答案 1 :(得分:0)
您实际上可以使用修饰符%wZ和printf打印UNICODE_STRING结构。无需任何花哨的缓冲区翻译或担心空终止符。
UNICODE_STRING someStr;
RtlInitUnicodeString(&someStr, L"Hello");
printf("String: %wZ\n", &someStr);
FINI。