After loading the Windows PE executable into Ghidra SRE, some functions imported from MFC90U.DLL Ghidra does not detect:

                DAT_00aea270                   FUN_004ae180:004ae1ee, 
                                               FUN_0067a2f0:0067a332, [more]
        00aea270 af            ??         AFh     XREF[892]:
        00aea271 09            ??         09h
        00aea272 00            ??         00h
        00aea273 80            ??         80h

I exactly know that this is a function of CStringT :: Find. Similarly, the CStringT :: Replace function is undefined by Ghidra, too.

If I force the bytes at address 0x00AEA270 to be the type of pointer, then I hover the cursor over the DAT_800009af variable and Ghidra complains "Address: ram: 800009af, Address not in memory":

                PTR_DAT_00aea270               FUN_004ae180:004ae1ee, 
                                               FUN_0067a2f0:0067a332, [more]
        00aea270 af 09 00 80   addr       DAT_800009af     XREF[892]:
                                               |Address: ram: 800009af|
                                               |Address not in memory |

At the same time, other functions from the same MFC90U.DLL are detected correctly:

             *                POINTER to EXTERNAL FUNCTION                *
             CStringT<wchar    EAX:4          <RETURN>
             CStringT<wchar    ECX:4 (auto)   this
             CStringT<wchar    Stack[0x4]:4   param_1
                811  Ordinal_811  <<not bound>>
                PTR_operator=_00aea26c         FUN_004cdbe0:004ce2e5,
                                               FUN_00911be0:00914605, [more]
        00aea26c 2b 03 00 80   addr       MFC90U.DLL::ATL::CStringT<wchar_t,class_StrTra   XREF[4517]:

             *                POINTER to EXTERNAL FUNCTION                *
                 int __thiscall ShowWindow(CWnd * this, int param_1)
             int               EAX:4          <RETURN>
             CWnd *            ECX:4 (auto)   this
             int               Stack[0x4]:4   param_1
                 6604  Ordinal_6604  <<not bound>>
                 PTR_ShowWindow_00aea278                         ShowWindow:00947004  
        00aea278 cc 19 00 80    addr       MFC90U.DLL::CWnd::ShowWindow                     XREF[1]:

Moreover, the address of functions that Ghidra does not detect (0x800009af which is CStringT::Find and 0x80001723 which is CStringT::Replace) are located between the addresses 0x8000032b and 0x800019cc, i.e. between the addresses of those functions that Ghidra SRE detects. That is, these addresses cannot be "Address not in memory" by any means!

As a result, in the listing window:

    006c88a2 68 8c 98           PUSH       u_</HeaderData>_00b6988c
             b6 00
    006c88a7 8d 8d 34           LEA        ECX=>local_26d0,[EBP + 0xffffd934]
             d9 ff ff
                              -> DAT_800009af
    006c88ad ff 15 70           CALL       dword ptr [PTR_DAT_00aea270]
             a2 ae 00
    006c88b3 85 c0              TEST       EAX,EAX
    006c88b5 7c 13              JL         LAB_006c88ca

and in the decompiler window:

    iVar4 = (*(code *)&DAT_800009af)(L"</HeaderData>",0);
    if (-1 < iVar4) {

I only see unknown calls from indirect unknown addresses.

But IDA Pro correctly detects the same imports. Here is the import window with the same imports from IDA Pro:

.idata:00AEA26C ; public: class ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>> & __thiscall ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>>::operator=(class ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>> const &)
.idata:00AEA26C                 extrn ??4?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QAEAAV01@ABV01@@Z:dword
.idata:00AEA26C                                         ; CODE XREF: sub_4016D0+15E↑p
.idata:00AEA26C                                         ; sub_402E30+30↑p ...
.idata:00AEA270 ; public: int __thiscall ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>>::Find(wchar_t const *, int)const
.idata:00AEA270                 extrn ?Find@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QBEHPB_WH@Z:dword
.idata:00AEA270                                         ; CODE XREF: sub_401680+1A↑p
.idata:00AEA270                                         ; sub_403210+8B↑p ...
.idata:00AEA274 ; public: int __thiscall ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>>::Replace(wchar_t const *, wchar_t const *)
.idata:00AEA274                 extrn ?Replace@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QAEHPB_W0@Z:dword
.idata:00AEA274                                         ; CODE XREF: sub_4011C0+269↑p
.idata:00AEA274                                         ; sub_41A3F0+D7↑p ...
.idata:00AEA278 ; __declspec(dllimport) public: int __thiscall CWnd::ShowWindow(int)
.idata:00AEA278                 extrn __imp_?ShowWindow@CWnd@@QAEHH@Z:dword
.idata:00AEA278                                         ; DATA XREF: CWnd::ShowWindow(int)↑r

Here is the IDA Pro listing window showing the same place inside the executable:

.text:006C88A2                 push    offset aHeaderdata ; "</HeaderData>"
.text:006C88A7                 lea     ecx, [ebp+var_26CC]
.text:006C88AD                 call    ds:?Find@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QBEHPB_WH@Z ; ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Find(wchar_t const *,int)
.text:006C88B3                 test    eax, eax
.text:006C88B5                 jl      short loc_6C88CA

and the Hex-Rays decompiler window with the call to this function is also in the same place inside the executable:

    v18 = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Find(&v39, L"</HeaderData>", 0);
    if ( v18 >= 0 )

However, I prefer the result of the Ghidra decompiler some more than the Hex-Rays decompiler does, and therefore I would like to use Ghidra at least for this particular executable file.

How could I achieve correct importing with Ghidra? What should I do to fix it? How could I tell Ghidra that these are normal imported functions located at normal addresses inside the executable process?

Yes, there is the description of both CStringT::Find and CStringT::Replace inside the file ~/ghidra_9.1.2_PUBLIC/Ghidra/Features/Base/data/symbols/win32/mfc90u.exports:


<EXPORT ORDINAL="2479" NAME="?Find@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QBEHPB_WH@Z" PURGE="-1" COMMENT="" />


So Ghidra SRE knows about of these functions are exist and how to correctly name them, but for some reason does not detect and define them properly as imported from MFC90U.DLL. Why?

I run Ghidra 9.1.2 public release Feb-12-2020 1149 EST and IDA Pro version 7.1.180227.

  • 1
    Ghidra 9.1.2 can have a hard time with PDB's. Did you load in a PDB for this DLL? – cc2021 Apr 12 at 14:13
  • Nope. There was a bug inside Ghidra code so I had to use an external script to achieve this behavior. – Perikl Femidi Apr 12 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.