typedef struct _monoString {
void *klass;
void *monitor;
int length;
char chars[1];
int getLength() {
return length;
}
char *getChars() {
return chars;
}
} monoString;
monoString *(*String_CreateString)(void *_this, const char *str, int startIndex, int length);
void (*get_StringInstance);
#include <codecvt>
#include <locale>
std::string FromUTF16(monoString* str) {
std::u16string u16(reinterpret_cast<const char16_t*>(str->chars));
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
}
bool isGetNickname;
monoString* (*get_Nickname)(void *instance);
void (*old_Update)(void *instance);
void Update(void *instance) {
if (instance != NULL) {
if (isGetNickname) {
LOGI("Nickname: %s", FromUTF16(get_Nickname(instance)).c_str());
}
}
return old_Update(instance);
}
bool isSetNickname;
const char *Nickname;
monoString* (*old_getNickname)(void* instance);
monoString* getNickname(void* instance) {
if (instance != NULL && isSetNickname) {
return String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname));
}
return old_getNickname(instance);
}
#if defined(__aarch64__) //To compile this code for arm64 lib only. Do not worry about greyed out highlighting code, it still works
A64HookFunction((void*)getAbsoluteAddress(targetLibName, 0xFFC538), (void*)Update, (void**)&old_Update);
A64HookFunction((void*)getAbsoluteAddress(targetLibName, 0x233574C), (void*)getNickname, (void**)&old_getNickname);
String_CreateString = (monoString *(*)(void *, const char *, int startIndex, int length))getAbsoluteAddress(targetLibName, 0x2066CB0);
get_StringInstance = (void (*))getAbsoluteAddress(targetLibName, 0x2066CB0);
get_Nickname = (monoString* (*)(void *))getAbsoluteAddress(targetLibName, 0x233574C);
const char *features[] = {
OBFUSCATE("30_CollapseAdd_Toggle_Get Nickname"),
OBFUSCATE("37_CollapseAdd_InputText_Nickname"),
OBFUSCATE("38_CollapseAdd_Toggle_Set Nickname"),
};
switch (featNum) {
case 30:
isGetNickname = boolean;
break;
case 37:
Nickname = env->GetStringUTFChars(str, 0);
break;
case 38:
isSetNickname = boolean;
break;
}
This is either an unsuitable method, or try to hook in the Update() method.Here's the code:
C++:typedef struct _monoString { void *klass; void *monitor; int length; char chars[1]; int getLength() { return length; } char *getChars() { return chars; } } monoString; monoString *(*String_CreateString)(void *_this, const char *str, int startIndex, int length); void (*get_StringInstance); #include <codecvt> #include <locale> std::string FromUTF16(monoString* str) { std::u16string u16(reinterpret_cast<const char16_t*>(str->chars)); return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16); } bool isGetNickname; monoString* (*get_Nickname)(void *instance); void (*old_Update)(void *instance); void Update(void *instance) { if (instance != NULL) { if (isGetNickname) { LOGI("Nickname: %s", FromUTF16(get_Nickname(instance)).c_str()); } } return old_Update(instance); } bool isSetNickname; const char *Nickname; monoString* (*old_getNickname)(void* instance); monoString* getNickname(void* instance) { if (instance != NULL && isSetNickname) { return String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname)); } return old_getNickname(instance); } #if defined(__aarch64__) //To compile this code for arm64 lib only. Do not worry about greyed out highlighting code, it still works A64HookFunction((void*)getAbsoluteAddress(targetLibName, 0xFFC538), (void*)Update, (void**)&old_Update); A64HookFunction((void*)getAbsoluteAddress(targetLibName, 0x233574C), (void*)getNickname, (void**)&old_getNickname); String_CreateString = (monoString *(*)(void *, const char *, int startIndex, int length))getAbsoluteAddress(targetLibName, 0x2066CB0); get_StringInstance = (void (*))getAbsoluteAddress(targetLibName, 0x2066CB0); get_Nickname = (monoString* (*)(void *))getAbsoluteAddress(targetLibName, 0x233574C); const char *features[] = { OBFUSCATE("30_CollapseAdd_Toggle_Get Nickname"), OBFUSCATE("37_CollapseAdd_InputText_Nickname"), OBFUSCATE("38_CollapseAdd_Toggle_Set Nickname"), }; switch (featNum) { case 30: isGetNickname = boolean; break; case 37: Nickname = env->GetStringUTFChars(str, 0); break; case 38: isSetNickname = boolean; break; }
The code i gave is not the full code (to avoid confusion).This is either an unsuitable method, or try to hook in the Update() method.
Already tried everything that's related (method, variables, etc).You could try playerName in networkingpeer and photonnetwork
Already tried everything that's related (method, variables, etc).This is either an unsuitable method, or try to hook in the Update() method.
instance != NULL
in your getNickName hook and try again.monoString* getNickname(void* instance) {
if (isSetNickname) {
return String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname));
}
return old_getNickname(instance);
}
this pointer
is set to NULL by default, but your code is checking if instance != NULL, your hook probably works fine, but the mod conditions is always skipped over due to this.I'll try it, but i also have hookedRemoveinstance != NULL
in your getNickName hook and try again.
C++:monoString* getNickname(void* instance) { if (isSetNickname) { return String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname)); } return old_getNickname(instance); }
get_NickName in PhotonNetwork is public static string get_NickName() { }, get_NickName is static, static methods dont have a class instance the il2cpp documentation states thethis pointer
is set to NULL by default, but your code is checking if instance != NULL, your hook probably works fine, but the mod conditions is always skipped over due to this.
if (instance != nullptr)
If you just scroll up a bit u will see:Removeinstance != NULL
in your getNickName hook and try again.
C++:monoString* getNickname(void* instance) { if (isSetNickname) { return String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname)); } return old_getNickname(instance); }
get_NickName in PhotonNetwork is public static string get_NickName() { }, get_NickName is static, static methods dont have a class instance the il2cpp documentation states thethis pointer
is set to NULL by default, but your code is checking if instance != NULL, your hook probably works fine, but the mod conditions is always skipped over due to this.
oh and also the getNickname works because i already used LOGI to check the value.
if (isSetNickname) {
LOGI("get_NickName hook!");
std::string result = String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname));
LOGI("New name is: %s", result);
return result;
}
Why in ur opinion it has to be different if its static?
I've encounter a few cases where the instance is nullptr, especially when im hooking a constructor (.ctor)To be honest, in the 6 years I was modding and staff on android sites, I never ever checked if instance is null or not when il2cpp became a thing, I'm assuming it was done like that in some modding template and now everyone copy pastes that into their code without knowing why, to me honestly its unnecessary unless you understand what its for and have a specific reason to need to check if the this pointer is valid.
Yeah, that is what I was trying to get at, the fact that it can depend on the current situation rather than just checking if its NULL everywhere beacuse: "Thats how the template did it", especially since for static methods like I mentioned here, il2cpp devs state themselves its default value is NULL, which means instance != NULL can actually work against you.I've encounter a few cases where the instance is nullptr, especially when im hooking a constructor (.ctor)
There's also a case where the instance is random number and not a pointer to Il2CppObject
Im sure the people that make the template encounter this issue and add a check, and like you said people just copy pasting stuff without even knowing what they do
Thanks for the information! the time when i made the get_Nickname hook was when i was learning about string hooking and instance pointers i think, so i didnt really consider it as a possibility. I will try nonetheless.your get_NickName LOGI is in your update() hook.... update is not a static method, so of course that's going to work, also why are you logging get_NickName in update() but modifying it in the get_NickName method?
it would be much easier and more consistent to check all this in your actual get_NickName hook:
This way if you see logs you know its getting to that code, if you don't even see logs then you know something is wrong such as: instance is null.C++:if (isSetNickname) { LOGI("get_NickName hook!"); std::string result = String_CreateString(get_StringInstance, Nickname, 0, (int)strlen(Nickname)); LOGI("New name is: %s", result); return result; }
Again, thanks for the information!This isn't my opinion this is from reading info from the Unity developers themselves, they themself have stated that the this pointer in static methods is set to NULL by default since the this pointer (or instance) is a pointer to the instance of the object but static methods don't have an instance so Unity devs decided to set it to NULL by default.
Also, you aren't even using the instance parameter in your get_NickName hook so you shouldn't even need to check for or care what the this pointer is set to.
To be honest, in the 6 years I was modding and staff on android sites, I never ever checked if instance is null or not when il2cpp became a thing, I'm assuming it was done like that in some modding template and now everyone copy pastes that into their code without knowing why, to me honestly its unnecessary unless you understand what its for and have a specific reason to need to check if the this pointer is valid.
Okay, after thinking about it for a while it makes sense that u can return the new string, because the method isn't a void (method that doesn't return a value) which in this case it can return strings.Thanks for the information! the time when i made the get_Nickname hook was when i was learning about string hooking and instance pointers i think, so i didnt really consider it as a possibility. I will try nonetheless.
Again, thanks for the information!
About the instance parameter thingy, i used it to return the original method of get_NickName (if u are not talking about the NickName hook part).
I don't have much information about instance but i think instance is the memory address of the class? (correct me if im wrong)
but then there is using another update method from another class and passing its instance to a method of another class to hook it like my update method.
I take this back, im stupid to realize lol thats its the same thing but now the name is printed out too inside the get_Nickname hookOkay, after thinking about it for a while it makes sense that u can return the new string, because the method isn't a void (method that doesn't return a value) which in this case it can return strings.
For the most part yes, the "this pointer", will be the memory address to an instance of the class rather than the memory address of "the" class.I don't have much information about instance but i think instance is the memory address of the class? (correct me if im wrong)
void* instance
parameter will be the memory address of the enemy being processed in the current context.We use cookies to personalize content and ads, to provide social media features and to analyse our traffic. We also share necessary information with our advertising and analytics partners to optimize your experience on our site.
Learn more about cookies
We use cookies to personalize content and ads, to provide social media features and to analyse our traffic. We also share necessary information with our advertising and analytics partners to optimize your experience on our site.
Learn more about cookies