Iil2cpp codegen add handles
The call to il2cpp_codegen_add handles any operator overloading of + in the expression a + b.
IL2CPP_RUNTIME_CLASS_INIT ensures that a class (Console in this case) has executed its static constructor before being used,
for example in Console.WriteLine. At the top of the function, we find a boolean check which IL2CPP generates for every static method,
again used to ensure that the proper initialization is done before execution proceeds.
So, why does any of this matter?
Obviously if you are reverse-engineering a game,
you won’t have the Unity project so you won’t be able to look at the generated C++.
But it’s important to remember that even if by some dark magic you achieve a perfect
decompilation of the target binary into C++, what you will end up with is very different
to the original C# source code. Whereas our idealized C++ version using printf disassembles like this on x64:
; int __cdecl main(int argc, const char **argv, const char **envp)
main proc near
sub rsp, 28h
mov edx, 3
lea rcx, _Format ; "Hello world: %d\n"
call printf
xor eax, eax
add rsp, 28h
retn
main endp
The IL2CPP version, on the other hand, looks like this:
; void __fastcall Program_Main_m2325437134(Il2CppObject *__this, StringU5BU5D_t1642385972 *___args0, MethodInfo *method)
Program_Main_m2325437134 proc near
push rbx
sub rsp, 20h
cmp cs:s_Il2CppMethodInitialized_8016, 0
jnz short loc_14038BFF1
mov ecx, cs:?Program_Main_m2325437134_MetadataUsageId@@3IB
call ?InitializeMethodMetadata@MetadataCache@vm@il2cpp@@SAXI@Z
mov cs:s_Il2CppMethodInitialized_8016, 1
loc_14038BFF1:
mov rcx, cs:?Int32_t2071877448_il2cpp_TypeInfo_var@@3PEAUIl2CppClass@@EA
lea rdx, [rsp+48h]
mov dword ptr [rsp+48h], 3
call ?Box@Object@vm@il2cpp@@SAPEAUIl2CppObject@@PEAUIl2CppClass@@PEAX@Z
mov rcx, cs:?Console_t2311202731_il2cpp_TypeInfo_var@@3PEAUIl2CppClass@@EA
mov rbx, rax
test byte ptr [rcx+10Ah], 1
jz short loc_14038C02B
cmp dword ptr [rcx+0BCh], 0
jnz short loc_14038C02B
call ?ClassInit@Runtime@vm@il2cpp@@SAXPEAUIl2CppClass@@@Z
loc_14038C02B:
mov rdx, cs:?_stringLiteral3443654334@@3PEAUString_t2029220233@@EA
xor r9d, r9d
mov r8, rbx
xor ecx, ecx
call Console_WriteLine_m3776981455
add rsp, 20h
pop rbx
retn
Program_Main_m2325437134 endp
and that disassembly is with the symbols included, which you initially won’t have.
Therefore, in order to be able to understand the disassembly of a method in an IL2CPP application,
we really have to understand all of the key data structures and internal API calls that IL2CPP provides and manages,
so we can cut through all of the boilerplate and drill down into the actual functionality of the application.
To this end, it can be very useful to compile small snippets of C# with IL2CPP and investigate what comes out
(cryptographers will recognize this as a sort of known plaintext attack).