0

Here are some chunks:

  v13 = cocos2d::FileUtils::getInstance(v9);
  (*(void (__fastcall **)(char *))(*(_DWORD *)v13 + 64))(&v46);

  v19 = cocos2d::FileUtils::getInstance(fileHandle);
  v21 = *(void (__fastcall **)(char *, int, unsigned __int8 *))(*(_DWORD *)v19 + 28);
  v21(&v44, v20, &v42);

  v23 = cocos2d::FileUtils::getInstance(v22),
  v24 = (cocos2d::FileUtils *)(*(int (**)(void))(*(_DWORD *)v23 + 152))(),

cocos2d is an open source project, and I have downloaded it, but I have no idea how to determine what the order of the methods are. So, how do I identify what method 28, 64, or 152 really is? (Dead-listings only, can't execute the code to find the answer).

2
  • This looks more like a decompilation, but that's besides the point. Is this snippet from the library/dll itself or from a program written using the library? Aug 12, 2021 at 6:13
  • The above is a Hex Rays "Pseudo-C" decompilation of some code from an .SO that has statically linked against the Cocos2D library. I've picked up a little more information about it. This is the method used to call virtual C++ methods. But the question still remains. How do I work out WHICH virtual C++ method these refer to.
    – FrankRizzo
    Aug 13, 2021 at 13:56

2 Answers 2

1

I presume the binary is fully optimized and stripped of debug info
My answer pertains to a windows binary (ex getinst.exe) but the generic concept applies to elf (ex foo.so )

some base presumptions about cocos2d from google are

  1. appears to be 32 bit only
  2. FileUtils appears to be a singleton implementation judging by the use of getInstance() and google

FileUtils* s_sharedFileUtils
staticprotected
The singleton pointer of FileUtils.

shown below is a bare minimum proof of concept singleton c++ code

:\>type getinst.cpp
#include <iostream>
using namespace std;
class Singleton
{
        static Singleton *instance;
        Singleton() {}
public:
        static Singleton *getInstance()
        {
                if (!instance)
                        instance = new Singleton;
                return instance;
        }
        virtual void funcone() { cout << "funcone\n"; }
        virtual void functwo() { cout << "functwo\n"; }
        virtual void functre() { cout << "functre\n"; }
        virtual void funcfor() { cout << "funcfor\n"; }
};
Singleton *Singleton::instance = nullptr;
int main()
{
        Singleton *s = s->getInstance();
        s->funcone();
        s->functwo();
        s->functre();
        s->funcfor();
        return 0;
}

compilation and linking with vs2017 as 32bit (x86) Full Optimization and nodebuginfo

:\>type complink.bat
cl /W4 /analyze:autolog- /EHsc /Ox /nologo getinst.cpp /link /release

contents of Directory pre and post compilation and execution of compiled binary

:\>ls -lg
total 5
-rw-r--r-- 1 197121  69 Aug 15 09:43 complink.bat
-rw-r--r-- 1 197121 603 Aug 15 09:24 getinst.cpp

:\>complink.bat

:\>cl /W4 /analyze:autolog- /EHsc /Ox /nologo getinst.cpp /link /release
getinst.cpp

:\>ls -lg
total 261
-rw-r--r-- 1 197121     69 Aug 15 09:43 complink.bat
-rw-r--r-- 1 197121    603 Aug 15 09:24 getinst.cpp
-rwxr-xr-x 1 197121 183808 Aug 15 09:49 getinst.exe
-rw-r--r-- 1 197121  76677 Aug 15 09:49 getinst.obj

:\>getinst.exe
funcone
functwo
functre
funcfor

lets dig into disassembly / find The RTTI / rename / etc

using a hex editor search for pattern ".?A"
I am using xxd a Commandline hex dumper

also I am providing a partial name .?AVSing to illustrate the point
but on an unknown binary you maybe forced to analyze all the results of .?A

:\>xxd -g 4 getinst.exe |grep -B 1 -i ".?AVSing"
0002a8e0: 676f7279 40737464 40400000 8cf44100  gory@std@@....A.
0002a8f0: 00000000 2e3f4156 53696e67 6c65746f  .....?AVSingleto

the Address of Partial Mangled class name Starts at 0x2a8f8
( &StartofPattern + 4) == ( 0x2a8f4 + 4 ) == Singleton@@

:\>xxd -s 0x2a8f8 -l 16 getinst.exe
0002a8f8: 5369 6e67 6c65 746f 6e40 4000 8cf4 4100  Singleton@@...A. 

Prepend ??_7 and Append 6B@ to this partial Mangled name
pass the conacatenated string to undname.exe or c++filt or demangler.com to get a Demangled or undecorated Name

:\>undname ??_7Singleton@@6B@
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "??_7Singleton@@6B@"
is :- "const Singleton::`vftable'" 

This Class name is part of a Structure Called _TypeDescriptor https://www.geoffchappell.com/studies/msvc/language/predefined/

typedef struct _TypeDescriptor
{
    const void *pVFTable;
    void *spare;
    char name []; <<<<<<<<<<<<<<
} _TypeDescriptor;

which is a member of another structure

typedef const struct _s__RTTICompleteObjectLocator {
    unsigned long signature;
    unsigned long offset;
    unsigned long cdOffset;
    _TypeDescriptor *pTypeDescriptor; <<<<<<<<<<
    __RTTIClassHierarchyDescriptor *pClassDescriptor;
} __RTTICompleteObjectLocator;

find the cross references to these two structures
if the offset member is == 0 (SINGLE INHERITANCE)
the vtable follows the __RTTICompleteObjectLocator with methods

from the dump above

 _TypeDescriptor.name       = 0x2a8f4
 _TypeDescriptor.spare      = 0x2a8f0
  _TypeDescriptor.pVFTable  = (FO) 0x2a8ec -> 0x42baec (VA)
  FO = FileOffset ,VA = VirtualAddress
  VA == python -c "print(hex(0x2a8ec-0x29e00+0x42b000))" 

find xref to 0x42baec There Are 2 xrefs

  :\>xxd -g4 getinst.exe | grep ecba4200
00027e90: 00000000 00000000 ecba4200 a08c4200  ..........B...B.
00027eb0: b88c4200 00000000 ecba4200 00000000  ..B.......B.....

From First Cross Reference

__RTTICompleteObjectLocator->pTypeDescriptor    = 0x27e98
__RTTICompleteObjectLocator.cdOffset            = 0x27e94
__RTTICompleteObjectLocator.offset              = 0x27e90
__RTTICompleteObjectLocator.signature           = 0x27e8c

find cross reference to VA of 0x27e8c

dumpbin /SECTION:.rdata getinst.exe

SECTION HEADER #2
  .rdata name
    EA7E virtual size
   1C000 virtual address (0041C000 to 0042AA7D)
    EC00 size of raw data
   1B200 file pointer to raw data (0001B200 to 00029DFF)


python -c "print(hex(0x27e8c-0x1b200+0x41c000))"
0x428c8c

:\>xxd -g4 getinst.exe | grep 8c8c4200
0001b470: 66626974 20736574 00000000 8c8c4200  fbit set......B.

the methods follow 0x1b47c at 0x1b480

:\>xxd -g 4 -s 0x1b480 -l 64  getinst.exe
0001b480: 50204000 90204000 70204000 30204000  P @.. @.p @.0 @.
0001b490: 66756e63 6f6e650a 00000000 66756e63  funcone.....func
0001b4a0: 74776f0a 00000000 66756e63 7472650a  two.....functre.
0001b4b0: 00000000 66756e63 666f720a 00000000  ....funcfor.....

4 methods

0x402050 
0x402090
0x402070
0x402030

disasm of the methods

:\>dumpbin /disasm /range:0x402030,0x4020b0 getinst.exe

  00402030: 68 B4 C2 41 00     push        41C2B4h == 0x1b4b4 == funcfor
  00402035: 68 48 BE 42 00     push        42BE48h
  0040203A: E8 E1 F0 FF FF     call        00401120
  0040203F: 83 C4 08           add         esp,8
  00402042: C3                 ret
  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  00402050: 68 90 C2 41 00     push        41C290h  
  :\>python -c "print(hex(0x1b490-0x1b200+0x41c000))"
    0x41c290  
   :\>dumpbin /rawdata /range:0x41c290,0x41c29f getinst.exe
  0041C290: 66 75 6E 63 6F 6E 65 0A 00 00 00 00 66 75 6E 63  funcone.....func
  
  00402055: 68 48 BE 42 00     push        42BE48h
  0040205A: E8 C1 F0 FF FF     call        00401120
  0040205F: 83 C4 08           add         esp,8
  00402062: C3                 ret
  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  00402070: 68 A8 C2 41 00     push        41C2A8h == 0x1b4a8 == functre
  00402075: 68 48 BE 42 00     push        42BE48h
  0040207A: E8 A1 F0 FF FF     call        00401120
  0040207F: 83 C4 08           add         esp,8
  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  00402090: 68 9C C2 41 00     push        41C29Ch == 0x1b492 == functwo
  00402095: 68 48 BE 42 00     push        42BE48h
  0040209A: E8 81 F0 FF FF     call        00401120
  0040209F: 83 C4 08           add         esp,8
  004020A2: C3                 ret
  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

the 4 methods retrieved without symbol information using basic tools and manual fishing.

hope you can apply this to your cocos2d

1
  • This is BY FAR the most incredible answer I've ever seen here. The amount of work required is STAGGERING! The ONLY thing that makes it less than 100% ideal for my question is that my instance is in a Linux .SO compiled for ARM. :-\
    – FrankRizzo
    Aug 17, 2021 at 1:06
0

If you are using IDA Pro, there are plugins to reconstruct the RTTI (runtime type identification) of the classes you are interested in. Take a look at medigate. There are other similar plugins as well which you can find on the web.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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