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

Trace losing calls

ExternalAddress4401 opened this issue · comments

Forgive me if I'm simply misunderstanding something but I feel as if something weird is going on here.

Given the following trace call:

Il2Cpp.perform(() => {
  Il2Cpp.trace(true)
    .assemblies(Il2Cpp.domain.assembly("mscorlib"))
    .filterMethods((method) => method.name.toLowerCase().includes("directory"))
    .verbose()
    .and()
    .attach();
});

I get a large output. As an example:

il2cpp:
0x01e14870 ┌─System.IO.MonoIO::get_DirectorySeparatorChar()
0x01e14870 └─System.IO.MonoIO::get_DirectorySeparatorChar = 47

il2cpp:
0x01e14874 ┌─System.IO.MonoIO::get_AltDirectorySeparatorChar()
0x01e14874 └─System.IO.MonoIO::get_AltDirectorySeparatorChar = 47

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 47)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = true

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 115)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 101)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 121)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

il2cpp:
0x01e1065c ┌─System.IO.Path::GetDirectoryName(path = "/storage/emulated/0/Android/data/ai.nreal.fridalauncher/files/Library")
0x01e0b81c │ ┌─System.IO.Path::IsDirectorySeparator(c = 47)
0x01e0b81c │ └─System.IO.Path::IsDirectorySeparator = true
0x01e1065c └─System.IO.Path::GetDirectoryName = "/storage/emulated/0/Android/data/ai.nreal.fridalauncher/files"

il2cpp:
0x01e1579c ┌─System.IO.Path::GetDirectoryName(path = *)
0x01e1065c │ ┌─System.IO.Path::GetDirectoryName(path = "*")
0x01e1065c │ └─System.IO.Path::GetDirectoryName = ""
0x01e1579c └─System.IO.Path::GetDirectoryName =

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 100)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 102)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

il2cpp:
0x01e1065c ┌─System.IO.Path::GetDirectoryName(path = "/data/user/0/ai.nreal.fridalauncher/cache/CASESENSITIVETEST678936aa02a54a2184d6cd37c66cdb5f")
0x01e0b81c │ ┌─System.IO.Path::IsDirectorySeparator(c = 47)
0x01e0b81c │ └─System.IO.Path::IsDirectorySeparator = true
0x01e1065c └─System.IO.Path::GetDirectoryName = "/data/user/0/ai.nreal.fridalauncher/cache"

... etc as I don't want to copy paste the entire thing.

I've found that the call I'm looking for isn't here so I've expanded the search to all assemblies as so:

Il2Cpp.perform(() => {
  Il2Cpp.trace(true)
    .assemblies(...Il2Cpp.domain.assemblies) //do all the assemblies!
    .filterMethods((method) => method.name.toLowerCase().includes("directory"))
    .verbose()
    .and()
    .attach();
});

This now prints out

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 47)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = true

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 115)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

il2cpp:
0x01e0b81c ┌─System.IO.Path::IsDirectorySeparator(c = 112)
0x01e0b81c └─System.IO.Path::IsDirectorySeparator = false

Uhh, where did everything else go...?

Uhm, yeah. What's the application?

Uhm, yeah. What's the application?

Yeah so this is the launcher for the Xreal Beam I'm attempting to boot and examine on a phone. It doesn't run correctly by default as it expects to be run as a system app so I use the script below to bypass the startup checks that aren't required to function.

It's also not available on the play store or anything so I've uploaded the APK: https://mega.nz/file/wecihZ4S#c3UznU1VNIpisuIgLHo4WLPXYvrEbIK-Iiaf-Tg91hE

Java.perform(function () {
  console.log("Running");
  try {
    var telephonyManager = Java.use("android.telephony.TelephonyManager");
    var build = Java.use("android.os.Build");
    var systemProperties = Java.use("android.os.SystemProperties");
    var buildProperties = Java.use("android.os.Build");

    //-----------------------------------------------
    buildProperties.MODEL.value = "payload";
    buildProperties.DEVICE.value = "payload";
    buildProperties.BOARD.value = "payload";
    buildProperties.PRODUCT.value = "payload";
    buildProperties.HARDWARE.value = "payload";
    buildProperties.FINGERPRINT.value = "payload";
    buildProperties.MANUFACTURER.value = "payload";
    buildProperties.BOOTLOADER.value = "payload";
    buildProperties.BRAND.value = "payload";
    buildProperties.HOST.value = "payload";
    buildProperties.ID.value = "payload";
    buildProperties.DISPLAY.value = "payload";
    buildProperties.TAGS.value = "payload";
    buildProperties.SERIAL.value = "payload";
    buildProperties.TYPE.value = "payload";
    buildProperties.USER.value = "payload";
    buildProperties.UNKNOWN.value = "payload";

    //-----------------------------------------------

    var payl0ad = "payload";

    console.log("Payload: " + payl0ad);

    systemProperties.get.overload("java.lang.String").implementation =
      function (key) {
        console.log(
          "[+] Get system properties called using key: " +
            key +
            ", returning " +
            payl0ad
        );
        return payl0ad;
      };

    build.getSerial.implementation = function () {
      return payl0ad;
    };

    telephonyManager.getLine1Number.overloads[0].implementation = function () {
      return payl0ad;
    };

    telephonyManager.getSubscriberId.overload().implementation = function () {
      console.log("[i] Application asks for device IMSI, returning:" + payl0ad);
      return payl0ad;
    };
    telephonyManager.getSubscriberId.overload("int").implementation =
      function () {
        console.log(
          "[i] Application asks for device IMSI, returning " + payl0ad
        );
        return payl0ad;
      };

    telephonyManager.getDeviceId.overloads[0].implementation = function () {
      console.log("[i] Application asks for device IMEI, returning" + payl0ad);
      return payl0ad;
    };
    telephonyManager.getDeviceId.overloads[1].implementation = function (slot) {
      console.log("[i] Application asks for device IMEI, returning:" + payl0ad);
      return payl0ad;
    };

    telephonyManager.getImei.overloads[0].implementation = function () {
      console.log(
        "[i] Application asks for device IMEI, returning :" + payl0ad
      );
      return payl0ad;
    };
    telephonyManager.getImei.overloads[1].implementation = function (slot) {
      console.log(
        "[i] Application asks for device IMEI, returning: " + payl0ad
      );
      return payl0ad;
    };

    telephonyManager.getSimOperator.overload().implementation = function () {
      console.log("[+] getSimOperator call detected, returning:" + payl0ad);
      return payl0ad;
    };
    telephonyManager.getSimOperator.overload("int").implementation = function (
      sm
    ) {
      console.log("[+] getSimOperator call detected, returning:" + payl0ad);
      return payl0ad;
    };
  } catch (error) {
    console.log(error);
  }
});

This APK also doesn't seem to play well with injecting while it's running. Make sure to include the -f ai.nreal.evalauncher flag to get it to boot. (there's a small chance I renamed this particular one to ai.nreal.fridalauncher as I'm trying to duplicate it to run alongside the original)

Thanks, unfortunately I do not have a arm64 device with me, so...

You could edit the source code here

and log this.#targets ...

Also, did you upgrade to 0.9.0?

Thanks, unfortunately I do not have a arm64 device with me, so...

You could edit the source code here

and log this.#targets ...
Also, did you upgrade to 0.9.0?

Freshly installed everything yesterday so I assume npm i frida-il2cpp-bridge would've given me 0.9.0 yes.

I'll get an update on what logs out later and check my version.

So I am indeed on 0.9.0 and the output for this.#targets looks correct.

System.Void DirectoryCreate(System.String path); // 0x00af2a48,System.Boolean DirectoryExists(System.String path); // 0x00af2bf8,System.Void DirectoryCreate(System.String path);,System.Boolean DirectoryExists(System.String path);,static System.String GetDirectoryEntryFullPath(Interop.Sys.DirectoryEntry& dirent, System.String currentPath); // 0x01495f30,static System.String GetTimeZoneDirectory(); // 0x014959e8,static System.String GetTimeZoneDirectoryUnity(); // 0x0149e4e4,static System.String get_CurrentDirectory(); // 0x01610610,static System.Boolean IsDirectorySeparator(System.Char c); // 0x01905750,static System.Boolean EndsInDirectorySeparator(System.ReadOnlySpan<System.Char> path); // 0x019057b8,static System.Boolean StartsWithDirectorySeparator(System.ReadOnlySpan<System.Char> path); // 0x01905840,static System.String TrimEndingDirectorySeparator(System.String path); // 0x019058bc,static System.ReadOnlySpan<System.Char> TrimEndingDirectorySeparator(System.ReadOnlySpan<System.Char> path); // 0x01905a78,static System.IO.DirectoryInfo CreateDirectory(System.String path); // 0x0190d8b0,static System.String InternalGetDirectoryRoot(System.String path); // 0x0190e810,static System.String GetCurrentDirectory(); // 0x0190e8c8,static System.String InsecureGetCurrentDirectory(); // 0x0190e8d0,System.String get_DirectoryName(); // 0x01911fe8,System.IO.DirectoryInfo get_Directory(); // 0x01912044,System.Boolean get_InitiallyDirectory(); // 0x019120d0,System.Void set_InitiallyDirectory(System.Boolean value); // 0x019120d8,static System.Void CreateDirectory(System.String fullPath); // 0x0190da00,static System.Void RemoveDirectory(System.String fullPath, System.Boolean recursive); // 0x0190f034,static System.Void RemoveDirectoryInternal(System.IO.DirectoryInfo directory, System.Boolean recursive, System.Boolean throwOnTopLevelDirectoryNotFound); // 0x01912bc0,static System.Boolean DirectoryExists(System.ReadOnlySpan<System.Char> fullPath); // 0x0190e1a4,static System.Boolean DirectoryExists(System.ReadOnlySpan<System.Char> fullPath, Interop.ErrorInfo& errorInfo); // 0x01912bb4,static System.Boolean ShouldIgnoreDirectory(System.String name); // 0x01913250,static System.String GetCurrentDirectory(System.IO.MonoIOError& error); // 0x01e26ce0,static System.Char get_DirectorySeparatorChar(); // 0x01e26e44,static System.Char get_AltDirectorySeparatorChar(); // 0x01e26e48,static System.String GetDirectoryName(System.String path); // 0x01e22c30,static System.ReadOnlySpan<System.Char> GetDirectoryName(System.ReadOnlySpan<System.Char> path); // 0x01e27d70,static System.Boolean IsDirectorySeparator(System.Char c); // 0x01e1ddf0,System.ReadOnlySpan<System.Char> get_Directory(); // 0x01e2c08c,System.Void set_Directory(System.ReadOnlySpan<System.Char> value); // 0x01e2c09c,System.ReadOnlySpan<System.Char> get_RootDirectory(); // 0x01e2c0a8,System.Void set_RootDirectory(System.ReadOnlySpan<System.Char> value); // 0x01e2c0b8,System.ReadOnlySpan<System.Char> get_OriginalRootDirectory(); // 0x01e2c0c4,System.Void set_OriginalRootDirectory(System.ReadOnlySpan<System.Char> value); // 0x01e2c0d4,System.Boolean get_IsDirectory(); // 0x01e2c128,System.IO.DirectoryInfo <DirectoryInfos>b__7_0(System.IO.Enumeration.FileSystemEntry& entry); // 0x01e2dd20,System.Boolean <DirectoryInfos>b__1(System.IO.Enumeration.FileSystemEntry& entry); // 0x01e2df4c,static System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo> DirectoryInfos(System.String directory, System.String expression, System.IO.EnumerationOptions options); // 0x01e2d6f0,static System.Boolean IsDirectoryNotFound(Interop.ErrorInfo info);,System.IntPtr CreateDirectoryHandle(System.String path, System.Boolean ignoreNotFound);,System.Void CloseDirectoryHandle();,System.Boolean DequeueNextDirectory();,System.Void OnDirectoryFinished(System.ReadOnlySpan<System.Char> directory);,System.Void DirectoryFinished();,static System.Boolean DirectoryExists(System.String path); // 0x01fb7290,static System.Int32 GetDirectoryIndex(System.String path); // 0x01fb8d18,static System.Boolean DirectoryExists(System.String path); // 0x01fb728c,static System.Boolean IsDirectorySeparator(System.Char c); // 0x02583c2c,static System.String FixTrailingDirectorySeparators(System.String path); // 0x02583c48,static System.Void ReadEndOfCentralDirectory(System.IO.Stream stream, System.IO.BinaryReader reader, System.Int64& expectedNumberOfEntries, System.Int64& centralDirectoryStart); // 0x0258ad14,static System.Void SetSourceAssetBundleDirectory(System.String relativePath); // 0x0258c6e4,static System.Void CreateDirectoryIfNotExists(System.String filePath); // 0x00bf64fc,System.IO.FileSystemWatcher WatchUpgradeCacheDirectory(); // 0x014ba2f4,static System.String get_UpgradeCacheDirectory(); // 0x014bcaf8,System.String get_WorkingDirectory(); // 0x00a80148,System.String GetLoginDirectory(System.String str); // 0x00b3b2f4,System.Net.Configuration.SmtpSpecifiedPickupDirectoryElement get_SpecifiedPickupDirectory(); // 0x0216b924,System.String get_PickupDirectoryLocation(); // 0x0216bdbc,System.Void set_PickupDirectoryLocation(System.String value); // 0x0216bdf4,static NRKernal.NativeResult NRTrackableImageDatabaseLoadDirectory(System.UInt64 session_handle, System.UInt64 trackable_image_database_handle, System.String trackable_image_database_directory); // 0x01141970,static System.Boolean ZipDirectory(System.String _path, System.String _parentRelPath, ICSharpCode.SharpZipLib.Zip.ZipOutputStream _zipOutputStream, NRKernal.ZipUtility.ZipCallback _zipCallback); // 0x00c634d4,System.Boolean get_IsDirectory(); // 0x015fd8e4,System.Void WriteZip64EndOfCentralDirectory(System.Int64 noOfEntries, System.Int64 sizeEntries, System.Int64 centralDirOffset); // 0x015ff4c8,System.Void WriteEndOfCentralDirectory(System.Int64 noOfEntries, System.Int64 sizeEntries, System.Int64 startOfCentralDirectory, System.Byte[] comment); // 0x015ff6a0

I'm wondering if maybe it could be time related? I don't think so because it prints the first 2 function calls fine but I've noticed it takes a lot longer to print this.#targets with the entire assemblies list vs a single assembly.

Uhm yeah, it might be time related. I guess you are spawning the game? Does it lag?

If so, you can try scheduling the callback within the main thread:

Il2Cpp.perform(() => {
    Il2Cpp.trace(true) // ...
}, "main");

I'll come back to this eventually but I've got my hands full with other stuff right now.