【问题标题】:Heap corruption while working with two LPTSTRs使用两个 LPTSTR 时堆损坏
【发布时间】:2015-04-03 12:53:35
【问题描述】:

我一直在使用从过滤器驱动程序接收消息的应用程序。该驱动程序运行良好,但我的内存管理有问题,可能与 LPTSTRs user & domain 有关。

在调试时,我收到有关堆损坏的消息,它们通常指向两个 free 或第二个 LookupAccountSid 调用。我在这里做错了什么?

#include "stdafx.h"
#include "myapp-service.h"
#include <Windows.h>
#include <fltUser.h>
#include <string>
#include <sddl.h>

BOOL
getUser(
_In_ WCHAR* sidstr,
_Inout_ LPTSTR* AcctName,
_Inout_ LPTSTR* DomainName
)
{
    PSID sid;
    DWORD dwAcctName = 1;
    DWORD dwDomainName = 1;
    SID_NAME_USE eUse = SidTypeUnknown;
    bool success;

    if (!ConvertStringSidToSidW(sidstr, &sid))
    {
        printf_s("ConvertStringSidToSid failed with 0x%08x\n", GetLastError);
        return false;
    }

    // Lookup!
    LookupAccountSid(
        NULL,
        sid,
        *AcctName,
        (LPDWORD)&dwAcctName,
        *DomainName,
        (LPDWORD)&dwDomainName,
        &eUse);

    *AcctName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwAcctName);
    *DomainName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwDomainName);

    success = LookupAccountSid(
        NULL,
        sid,
        *AcctName,
        (LPDWORD)&dwAcctName,
        *DomainName,
        (LPDWORD)&dwDomainName,
        &eUse);

    if (success) {
        _tprintf(TEXT("Username %s@%s\n"), *AcctName, *DomainName);
    }
    else {
        printf_s("LookupAccountSid failed with 0x%08x\n", GetLastError);
        return false;
    }

    return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT status;
    HANDLE port;
    myapp_USER_MESSAGE msg;

    //
    //  Open a communication channel to the filter
    //

    printf("myapp-service: Connecting to the filter ...\n");

    status = FilterConnectCommunicationPort(myappPortName,
        0,
        NULL,
        0,
        NULL,
        &port);

    if (IS_ERROR(status)) {

        printf("ERROR: Connecting to filter port: 0x%08x\n", status);
        return 2;
    }

    //
    // Fetch messages & handle them
    //

    while (TRUE) {
        status = FilterGetMessage(port,
            &msg.MessageHeader,
            sizeof(msg),
            NULL
            );

        if (status == S_OK) {
            // Got a message successfully!

            // The problem is most likely with these two
            LPTSTR user = NULL;
            LPTSTR domain = NULL;

            if (getUser(msg.Message.Sid, &user, &domain)) {
                _tprintf(TEXT("Username %s@%s accessed %ls at %ls\n"), user, domain, &msg.Message.FileName, &msg.Message.TimeStamp);
            }
            else {
                printf("Unable to get user data!");
            };

            if (user) {
                GlobalFree(user);
            }
            if (domain) {
                GlobalFree(domain);
            }

        }
        else {
            printf("ERROR: GetMessage: 0x%08x\n", status);
        }

        printf("\n\n");
    }

    // 
    // Close the communication channel to the filter
    //

    printf("myapp-service: Closing connection ...\n");

    CloseHandle(&port);

    return 0;
}

【问题讨论】:

    标签: c++ winapi


    【解决方案1】:

    LookupAccountSid 的参数cchNamecchReferenceDomainNamecch 为前缀(即字符数)。您在分配内存时必须考虑到这一点,因为GlobalAlloc 占用字节数

    *AcctName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwAcctName * sizeof(TCHAR));
    *DomainName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwDomainName * sizeof(TCHAR));
    

    您还应该在第一次调用之前将大小参数初始化为零:

    DWORD dwAcctName = 0x0;
    DWORD dwDomainName = 0x0;
    

    文档中对此进行了概述:

    如果函数因缓冲区太小或如果 cchName 为零而失败,则 cchName 将接收所需的缓冲区大小,包括终止空字符。


    顺便说一句:你的两个printf_s 调用都将打印GetLastError地址,而不是它的返回值。您必须添加括号 (GetLastError()) 才能调用函数。

    【讨论】:

      【解决方案2】:
      *AcctName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwAcctName*sizeof(TCHAR));
      *DomainName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwDomainName*sizeof(TCHAR));
      

      因为 LookupAccountSid 以 TCHAR 形式返回大小,而不是以字节为单位

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-22
        • 2014-03-31
        • 1970-01-01
        • 2011-12-03
        • 1970-01-01
        • 1970-01-01
        • 2010-11-15
        • 1970-01-01
        相关资源
        最近更新 更多