GDI resource leaks или как перехватить функции у MFC42.dll

Тема в разделе "WASM.WIN32", создана пользователем klizardin, 4 июл 2006.

  1. klizardin

    klizardin New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2006
    Сообщения:
    1
    Изначальная проблема: Есть модуль достаточно большой чтобы в нем было тяжело отслеживать GDI лики на глаз. Т.е. необходимо хотябы средство для опеределения есть ли лики или их нет, есть ли нюансы с GDI ресурсами. Причем, и что то вроде

    Код (Text):
    1. {
    2. CPen ppen,*poldpen;
    3. ppen.CreatePen(...);
    4. poldpen = pDC->SelectObject(&ppen);
    5. poldpen->DeleteObject();
    6. }
    7. // ну и далее deselect ppen-а не производиться. Хотя он удаляется так как вызывается деструктор CPen-а.
    Этот нюанс BoundsChecker правда достаточно старый не отловил.

    Начал писать сам с помощью перехвата API функций, но обнаружилось, что во всех описанных методах, не учитывается, что ".idata" может и не быть(в частности такое и наблюдается в MFC42.dll. Почему нужно перехватывать функции не только в главном модуле, но и в этой дллке? Т.к. большинство не inline GDI функций вызываются через нее).

    Вопрос: Как перехватывать API функции у модулей без ".idata"
    а также вопрос.
    есть ли уже написанные freeware утилиты для контроля утечек www.deleaker.com не подходит т.к. проект написан не под VC7.0 а еще под VC5.0 ;(

    Код (Text):
    1. bool CThunk::install(LPBYTE _pimage,IMAGE_IMPORT_DESCRIPTOR* _iid)
    2. {
    3.     m_pRVAThunk = NULL;
    4.     VERIFY_EXIT1(NULL!=m_szModule && NULL!=m_szFuncName,false);
    5.     VERIFY_EXIT1(NULL!=m_func && NULL==m_oldfunc,false);
    6.     VERIFY_EXIT1(NULL!=_pimage && NULL !=_iid,false);
    7.  
    8.     m_oldfunc = GetProcAddress(GetModuleHandle(m_szModule),m_szFuncName);
    9.     if(!m_oldfunc) return false; //can`t get module fucntion address
    10.     for(;_iid->Name;_iid++){if(_stricmp((char*)_pimage + _iid->Name,m_szModule)) break;}
    11.     if(!_iid->Name) return false; //no mudule
    12.  
    13.     //IMAGE_THUNK_DATA* pOrigThunk = (IMAGE_THUNK_DATA*)(_pimage + (DWORD)_iid->OriginalFirstThunk);
    14.     IMAGE_THUNK_DATA* pRealThunk = (IMAGE_THUNK_DATA*)(_pimage + (DWORD)_iid->FirstThunk);
    15.     for(;*(LPDWORD)pRealThunk;pRealThunk++)
    16.     {
    17.         if(pRealThunk->u1.Function!=m_oldfunc) continue;
    18.         //intercept fucntion address;
    19.         DWORD buf = (DWORD)m_func;
    20.         DWORD op=0;
    21.         VirtualProtect((LPVOID)pRealThunk,4,PAGE_READWRITE,&op);
    22.         DWORD written = 0;
    23.         WriteProcessMemory(GetCurrentProcess(),(LPVOID)pRealThunk,(LPVOID)&buf,4,&written);
    24.         VirtualProtect((LPVOID)pRealThunk,4,op,&op);
    25.         if(4!=written) return false;
    26.         m_pRVAThunk = pRealThunk;
    27.         return true;
    28.     }
    29.     return false;//can`t find fucntion in import list
    30. }
    31. /*
    32.    Передается имя модуля в которов будет осуществляться перехват и массив функций для перехвата
    33. */
    34. bool CCounter::install(LPCTSTR _szModule,CThunk* _pthunk)
    35. {
    36.     m_log.Empty();
    37.     m_log.Format(_T("Install API intercepter module for %s\n")
    38.         ,_szModule?_szModule:_T("NULL"));
    39.     int i;
    40.     for(i=0;i<m_thunkvec.size();i++)m_thunkvec[i] = NULL;
    41.     VERIFY_EXIT1(_pthunk!=NULL,false);
    42.     LPBYTE pimage = (LPBYTE)::GetModuleHandle(_szModule);
    43.     if(!pimage) return false;
    44.     IMAGE_DOS_HEADER *idh;
    45.     IMAGE_OPTIONAL_HEADER *ioh;
    46.     IMAGE_SECTION_HEADER *ish;
    47.     IMAGE_IMPORT_DESCRIPTOR *iid;
    48.     idh = (IMAGE_DOS_HEADER*)pimage;
    49.     ioh = (IMAGE_OPTIONAL_HEADER*)(pimage + idh->e_lfanew
    50.                                  + 4 + sizeof(IMAGE_FILE_HEADER));
    51.     ish = (IMAGE_SECTION_HEADER*)((BYTE*)ioh + sizeof(IMAGE_OPTIONAL_HEADER));
    52.     if(idh->e_magic!=0x5A4D) return false;
    53.     for(i=0; i<16; i++) {if(_stricmp((char*)((ish+i)->Name) , ".idata") == 0) break;}
    54.     if(i==16) return false;
    55. /*!!!!Вот здесь код кончает работу для MFC42.dll, потому как нет ".idata" !!!!*/
    56.     iid = (IMAGE_IMPORT_DESCRIPTOR*)(pimage + (ish +i)->VirtualAddress);
    57.     for(;*_pthunk;_pthunk++)
    58.     {
    59.         CThunk* pthunk = new CThunk;
    60.         *pthunk = *_pthunk;
    61.         if(!pthunk->install(pimage,iid))
    62.         {
    63.             delete pthunk;
    64.             continue;
    65.         }
    66.         installed(_szModule,*pthunk);
    67.     }
    68.     m_binitialized = true;
    69.     m_module = _szModule;
    70.     return true;
    71. }
     
  2. reverser

    reverser New Member

    Публикаций:
    0
    Регистрация:
    27 янв 2004
    Сообщения:
    615
    http://msdn.microsoft.com/msdnmag/issues/03/01/GDILeaks/
     
  3. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    DevPartner вроде неплохо отлавливает учетки и ошибки. Правда, немало и ложных срабатываний.

    А MFC::CPen в деструкторе не удаляет объект или мне показалось? WTL и то умнее..