vfsfitvnm / frida-il2cpp-bridge

A Frida module to dump, trace or hijack any Il2Cpp application at runtime, without needing the global-metadata.dat file.

Home Page:https://github.com/vfsfitvnm/frida-il2cpp-bridge/wiki

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

String issues

ExternalAddress4401 opened this issue · comments

I'm having an issue with strings thats much worse on iOS but is somewhat re-producable on Android.

Game: https://play.google.com/store/apps/details?id=com.spaceapegames.beatstar&hl=en_CA&gl=US

const patchFile = (path: string) => {
  const mscorlib = Il2Cpp.domain.assembly("mscorlib").image;
  const assembly = Il2Cpp.domain.assembly("Assembly-CSharp").image;
  const File = mscorlib.class("System.IO.File");
  const String = mscorlib.class("System.String");
  const bytes = File.method("ReadAllBytes").invoke(Il2Cpp.string(path));

  let strr = mscorlib
    .class("System.BitConverter")
    .method("ToString")
    .overload("System.Byte[]")
    .invoke(bytes) as Il2Cpp.String;

  strr = strr.object
    .method("Replace")
    .overload("System.String", "System.String")
    .invoke(Il2Cpp.string("-"), Il2Cpp.string("")) as Il2Cpp.String;

  strr = strr.object
    .method("Replace")
    .overload("System.String", "System.String")
    .invoke(
      Il2Cpp.string("32336631000D"),
      Il2Cpp.string("323366310009")
    ) as Il2Cpp.String;
};

Il2Cpp.perform(() => {
  const mscorlib = Il2Cpp.domain.assembly("mscorlib").image;
  const directory = "/sdcard/beatstar/songs";

  const files = mscorlib
    .class("System.IO.Directory")
    .method("GetDirectories")
    .invoke(Il2Cpp.string(directory));

  console.log("FILES", files);

  for (const file of files) {
    console.log("FILE", file);
    const path = file.toString().slice(1, -1);
    console.log("PATH", path);

    patchFile(path + "/artwork.bundle");
  }

  console.log("FILES", files);
}

Given some folders in /sdcard/beatstar/songs containing various bundle files I get various outputs.

FILES ["/sdcard/beatstar/songs/AEGLE","/sdcard/beatstar/songs/ERROR","/sdcard/beatstar/songs/song"]
FILE "/sdcard/beatstar/songs/AEGLE"
PATH /sdcard/beatstar/songs/AEGLE
FILE "/sdcard/beatstar/songs/ERROR"
PATH /sdcard/beatstar/songs/ERROR
FILE "/sdcard/beatstar/songs/song"
PATH /sdcard/beatstar/songs/song
FILES ["/sdcard/beatstar/songs/AEGLE","/sdcard/beatstar/songs/ERROR","/sdcard/beatstar/songs/song"]
FILES ["/sdcard/beatstar/songs/AEGLE","/sdcard/beatstar/songs/ERROR","/sdcard/beatstar/songs/song"]
FILE "/sdcard/beatstar/songs/AEGLE"
PATH /sdcard/beatstar/songs/AEGLE
FILE "/sdcard/beatstar/songs/ERROR"
PATH /sdcard/beatstar/songs/ERROR
FILE "/sdcard/beatstar/songs/song"
PATH /sdcard/beatstar/songs/song
FILES [null,null,null]
FILES ["/sdcard/beatstar/songs/AEGLE","/sdcard/beatstar/songs/ERROR","/sdcard/beatstar/songs/song"]
FILE "/sdcard/beatstar/songs/AEGLE"
PATH /sdcard/beatstar/songs/AEGLE
FILE "/sdcard/beatstar/songs/ERROR"
PATH /sdcard/beatstar/songs/ERROR
FILE null
PATH ul

On iOS I get various Chinese characters being printed out which I'm assuming come from broken strings.

Now I've never edited files or file but they're getting corrupted somehow from this replace calls and I'm struggling to figure out how this is happening.

I'm able to bypass it by doing the patching part on the main thread like so

      Il2Cpp.mainThread.schedule(() => {
        patchFile(path + "/artwork.bundle");
      });

but this is still bizarre.

Uhm, the fact that it works when scheduling within the main thread makes me think there's some thread-specific thing going on.

I guess this is where the breakage happens:

    let strr = mscorlib
        .class("System.BitConverter")
        .method("ToString")
        .overload("System.Byte[]")
        .invoke(bytes) as Il2Cpp.String;

perhaps it's due to a different endianness? Are you able to investigate? Can you verify the content of bytes and strr remains the same across different threads?

By the way,

// DO
const path = file.content;

// DON'T
const path = file.toString().slice(1, -1);

Did you solve this issue? Please reopen if necessary