Chapter 2.4: Comparing Against Android
Android GD is special for one important reason - it has symbols! What this means is that every function name is present in the code, just like Cocos2d on Windows - and not only their names, but their parameter types aswell! And because GD is a cross-compiled game from a single codebase, this means that we can compare against Android GD to aid reverse engineering other platforms.
Android GD’s binary is called libcocos2dcpp.so - it contains GD, Cocos2d, and all other dependencies in a single package. However, getting your hands into it is not as easy as Windows, since you need to extract it from the APK - ask some other modder for their copy of it 😉
⚠️ ARMv8 support in Ghidra broke in version 11, so you’d preferably get the ARMv7 version.
Once you have acquired the Android binary, import it to Ghidra the same way you imported Windows, except make sure to disable the Non returning functions: discovered option for Analysis.


So, let’s verify the REing we did in the last chapter!
Open up the class list on Android and look up LevelSettingsLayer:

Whoa, that’s a lot of functions… thanks, symbols! The first function we found in the last chapter was the constructor, so let’s navigate straight to it!
Well, hm. There doesn’t seem to be any function named LevelSettingsLayer here? The destructors are there but no constructor? Suspicious… let’s open up create instead to see what’s up:

Ah, so that’s what happened - the constructor got inlined. This means that its code was inserted to its call sites and the function definition itself got removed.
Well, if we look at the end of the create function, we can see the call to init is there:

Let’s follow the call and compare this to the LevelSettingsLayer::init we found on Windows:

(Left is Android, right is Windows)
Hmm, alright, both have the call to FLAlertLayer::init at the start. And both make calls to CCObject::retain, CCDirector::sharedDirector, and the CCRect constructor at similar times… Oh, and there’s a string literal! Both have a call to CCLabelBMFont::create with the same parameters. String literals are a really good way to compare functions, so this confirms it - we definitely found the real LevelSettingsLayer::init on Windows.
So, let’s copy the signature from Android to Windows:

Note that the Android function signatures aren’t perfect - they don’t have parameter names, and more crucially they don’t have a return type. You may notice that Ghidra has inferred the type of LevelSettingsLayer::init to be a void, however we know better than Ghidra that init functions don’t return void! Manually fixing the return type makes Ghidra add the missing return false:

So let’s get back to adding the correct parameter types on Windows. The first one is a LevelSettingsObject*, so let’s add it-

Oh, Ghidra has no clue what a LevelSettingsObject is. Well, we could manually define the type using the Data Type Manager, but it’s better to let Ghidra make the definition for us by finding some LevelSettingsObject member function and typing it as __thiscall:

(LevelSettingsObject::init was found using the same method as the previous chapters, however replicating it is left as an exercise for the reader!)
Repeat the same for LevelEditorLayer, and now Ghidra lets us use them as parameter types:

⚠️ The reason the calling convention of
LevelSettingsLayer::initis__thiscallwill be explained in a later chapter - not all functions have the same calling convention!
And there we go - we can now be pretty much certain that we have found the correct LevelSettingsLayer::init, and that our signature is right!