0

I'm attempting to learn reversing techniques using IDA on an exe built with VC/MFC, and could use a little initial help learning some patterns for simplifying the decompiled code.

IDA found approximately 30K subroutines in my exe, and they make heavy use of the CString class, so that seems like a good place to start. I've read a lot of IDA tutorials and articles, but haven't found anything that covers this specifically.

Here's a relatively simple example, unmodified by me:

void __cdecl sub_428258(int a1, int a2, int a3)
{
  int v3; // esi
  int v4; // eax
  int v5; // eax
  char v6; // [esp+10h] [ebp-10h]
  int v7; // [esp+1Ch] [ebp-4h]

  v7 = 0;
  v3 = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::ReverseFind(&a1, 92);// Find '\'
  if ( v3 < 0
    && (v3 = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::ReverseFind(&a1, 47), v3 < 0) )// Find '/'
  {
    ATL::CSimpleStringT<wchar_t,1>::Empty(a2);
    ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::operator=(a3, &a1);// Return empty string in a3
  }
  else
  {
    v4 = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Left(&a1, &v6, v3);
    LOBYTE(v7) = 1;
    ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::operator=(a2, v4);
    LOBYTE(v7) = 0;
    ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v6);
    v5 = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Right(
           &a1,
           &v6,
           *(_DWORD *)(a1 - 12) - v3 - 1);
    LOBYTE(v7) = 2;
    ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::operator=(a3, v5);
    LOBYTE(v7) = 0;
    ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v6);
  }
  v7 = -1;
  ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&a1);
}

Because IDA was able to use the MFC PDB file and RTTI, the logic is pretty easy to follow in this case. It seems to be doing something like splitting the first CString param on '\' or '/', and returning the split strings in the second and third CString params, i.e.:

void Split(CString source, CString &left, CString &right);

Questions:

  1. Is this likely a class member function, and if so, how do you know?
  2. Why is V7 being set before each call to the CString functions?
  3. What is "*(_DWORD *)(a1 - 12) - v3 - 1" doing?
  4. Is there a way to tell IDA to just use "CString" instead of the fully expanded type?
  5. Can I define a CString struct to help simplify the code?

My guess is that it is a member function, and that the answers to #2 and #3 have to do with the class definition, but I'm just not sure. An example of the simplified code would really help.

2
  • It might be helpful to know that a CString is a struct with a single pointer in it (it points to the string directly, but in front of it there is extra data). The decompiler doesn’t deal with this nicely at all. Defining the struct can be done but you won’t get much better output other than better CString in front of the casts.
    – mrexodia
    Apr 13 '18 at 10:48
  • Oh and I think V7 is used for exception handling (detection of which state the program is in). I’ll write a full answer later.
    – mrexodia
    Apr 13 '18 at 10:49
1
  1. to know that, it's better to look at assembler, not pseudocode. If there's an argument passed to sub_428258 through ECX, most likely yes, this should be a method of some class.
  2. maybe error code, which should be returned by the function. I.e. current function definition might be wrong. Can't tell without seeing the assembler.
  3. seems like it's accessing to some member of the class, pointer to which is stored in a1, so I suppose it's something in ATLString.
  4. if I understand it correct, those long names - are imported functions, so IDA just demangles and shows the names as is. You may only rename them manually.
  5. Yes, it would help you with 3.
1
  • Thanks Anton. I have learned a lot more in the 2 days since posting the question, and your answers confirm what I've learned so far. #2 is still a mystery to me, so thanks for the error code suggestion. Will check it out. Apr 5 '18 at 15:44
1

What is "*(_DWORD *)(a1 - 12) - v3 - 1" doing?

this is probably undocumented or poorly documented i don't know

these are from memory of my fiddling with this Cstring (be aware for misinterpretation from my part too )

it is trying to return you the substring after *\*

the Cstring when initialized is normally a part of a bigger structure or class or whatever its terminology is you can use windbg to follow on any generic Cstring Constructor

0:000> ?? &s
class ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > * 0x0016fb2c
   +0x000 m_pszData        : 0x00584630  "C:\Program Files\Microsoft Visual Studio\2017\Community\Common7\Tools"

0:000> $$ your a1 is == 0x584630 
0:000> $$ your (a1-12) is == (0x584630 - 0n12) = 0x584624 
0:000> $$ it is accessing the length of cstring->m_pszData because it is a part of bigger structure 

0:000> dt -r cstr!ATL::CNilStringData (0x584630-10)
   +0x000 pStringMgr       : 0x56dc1578 ATL::IAtlStringMgr
      +0x000 __VFN_table : 0x567a3458 
   +0x004 nDataLength      : 0n69
   +0x008 nAllocLength     : 0n69
   +0x00c nRefs            : 0n1
   +0x010 achNil           : [2]  "C:"

0:000> $$ CNilStringData is also a part of bigger struct/class but not relevent to present discussion

0:000> ??  (wchar_t *)(( cstr!ATL::CNilStringData *) @@(0x584630-10))->achNil
wchar_t * 0x00584630
 "C:\Program Files\Microsoft Visual Studio\2017\Community\Common7\Tools"

0:000> ??  (wchar_t *)(( cstr!ATL::CNilStringData *) @@(poi(s)-10))->achNil
wchar_t * 0x00584630
 "C:\Program Files\Microsoft Visual Studio\2017\Community\Common7\Tools"
0:000> $$ so *(dword *) (a1-12) is accessing the nDataLength

you can test with some code like this

int main()
{
    CString s(_T("C:\\Program Files\\Microsoft Visual Studio\\2017\\Community\\Common7\\Tools"));
    CString t(_T("C:\\Program Files"));
    CString u(_T("C:\\Program Files\\Microsoft Visual Studio"));
    CString v(_T("C:\\Program Files\\Microsoft Visual Studio\\2017"));
    CString w(_T("C:\\Program Files\\Microsoft Visual Studio\\2017\\Community"));
    CString x(_T("C:\\Program Files\\Microsoft Visual Studio\\2017\\Community\\Common7"));
    int found;
    CString temp[6] = { s,t,u,v,w,x };
    for (int i = 0; i < 6; i++) {
        printf("%x\n", wcslen(temp[i].GetBuffer()));
        if ((found = temp[i].ReverseFind(_T('\\'))) != -1) {
            printf("%S\n", (LPCWSTR)temp[i].Mid(found));
            printf("%S\n", (LPCWSTR)temp[i].Right(found));
        }
    }

    return 0;
}

compiled and executed you would get

45
\Tools
gram Files\Microsoft Visual Studio\2017\Community\Common7\Tools
10
\Program Files
es
28
\Microsoft Visual Studio
ft Visual Studio
2d
\2017
ogram Files\Microsoft Visual Studio\2017
37
\Community
 Files\Microsoft Visual Studio\2017\Community
3f
\Common7
am Files\Microsoft Visual Studio\2017\Community\Common7
Press any key to continue . . .

put the compiled exe in windbg and give it a stir

0:000> .for(r $t0=0; @$t0<6; r $t0 = @$t0+1) { dx  wcslen(temp[@$t0].m_pszData)}
wcslen(temp[@$t0].m_pszData) : 0x45
wcslen(temp[@$t0].m_pszData) : 0x10
wcslen(temp[@$t0].m_pszData) : 0x28
wcslen(temp[@$t0].m_pszData) : 0x2d
wcslen(temp[@$t0].m_pszData) : 0x37
wcslen(temp[@$t0].m_pszData) : 0x3f
0:000> .for(r $t0=0; @$t0<6; r $t0 = @$t0+1) {dt cstr!ATL::CNilStringData nDataLength @@C++(*(int *)(&temp[@$t0]) - 0x10)}
   +0x004 nDataLength : 0x45
   +0x004 nDataLength : 0x10
   +0x004 nDataLength : 0x28
   +0x004 nDataLength : 0x2d
   +0x004 nDataLength : 0x37
   +0x004 nDataLength : 0x3f
0:000> .for(r $t0=0; @$t0<6; r $t0 = @$t0+1) {.printf "%mu\n" , @@c++((wchar_t *) temp[@$t0].m_pszData)}
C:\Program Files\Microsoft Visual Studio\2017\Community\Common7\Tools
C:\Program Files
C:\Program Files\Microsoft Visual Studio
C:\Program Files\Microsoft Visual Studio\2017
C:\Program Files\Microsoft Visual Studio\2017\Community
C:\Program Files\Microsoft Visual Studio\2017\Community\Common7

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.