frida-java-bridge icon indicating copy to clipboard operation
frida-java-bridge copied to clipboard

android: alternative offset to ExceptionClear in libart (https://github.com/frida/frida/issues/2958)(https://github.com/frida/frida-java-bridge/issues/336)

Open matbrik opened this issue 1 year ago • 15 comments

In the latest libart versions (35xxxxxxx) the offset in the vtable of venv for ExceptionClear is not valid anymore. I added a check through an heuristic to detect if the found function is the correct one or if the new offset is needed.

The commit is only for arm64, a fix for other architectures may be needed.

Tested on libart:

350820380 350820960 350820860

matbrik avatar Sep 24 '24 13:09 matbrik

On Android 14, libart 350820960 the error goes away when starting the server but when trying to run an app with frida attached, the phone soft-reboots after a few seconds. (The app did actually spawn).

Were you able to spawn and attach with this PR?

nilathedragon avatar Sep 24 '24 15:09 nilathedragon

On Android 14, libart 350820960 the error goes away when starting the server but when trying to run an app with frida attached, the phone soft-reboots after a few seconds. (The app did actually spawn).

Were you able to spawn and attach with this PR?

I tried only with frida-inject and I was working fine. With frida-server there is a problem with a function (RunFlip) that changed signature from art::Thread::RunFlipFunction(art::Thread*,bool) to art::Thread::RunFlipFunction(art::Thread*)

In this commit android: handle change of signature of runFlip:

  • I changed the getExportByName which throws an exception with findExportByName
  • noticing that in devices using ConcurrentCopying with the recent versions of libart I had stability problems similar to https://github.com/frida/frida-java-bridge/pull/326 I extended the hook of runFlip to a generic case and removed the MayUseCollector check

matbrik avatar Sep 25 '24 10:09 matbrik

It is confirmed that this patch works on com.android.art@350820860 - Android 13.

thinhbuzz avatar Sep 30 '24 11:09 thinhbuzz

@matbrik It has issues on older devices or those without com.android.art for example as shown below. image

image

thinhbuzz avatar Oct 01 '24 14:10 thinhbuzz

@matbrik It has issues on older devices or those without com.android.art for example as shown below. image

can you provide more details and logs on the error?

matbrik avatar Oct 02 '24 07:10 matbrik

@matbrik It has issues on older devices or those without com.android.art for example as shown below. image

can you provide more details and logs on the error?

This is sample information, you can run it and try. If you need more information, give me your Discord or Telegram, we can discuss further. eg error:

{
    "type": "error",
    "description": "Error: access violation accessing 0x7cff553fd0",
    "stack": "Error: access violation accessing 0x7cff553fd0\n    at Ln (frida/node_modules/frida-java-bridge/lib/android.js:1617:1)\n    at kt (frida/node_modules/frida-java-bridge/lib/android.js:582:1)\n    at frida/node_modules/frida-java-bridge/lib/memoize.js:4:1\n    at vt (frida/node_modules/frida-java-bridge/lib/android.js:577:1)\n    at frida/node_modules/frida-java-bridge/lib/class-model.js:112:1\n    at Function.build (frida/node_modules/frida-java-bridge/lib/class-model.js:7:1)\n    at k._make (frida/node_modules/frida-java-bridge/lib/class-factory.js:168:1)\n    at k.use (frida/node_modules/frida-java-bridge/lib/class-factory.js:62:1)\n    at frida/node_modules/frida-java-bridge/index.js:224:1\n    at c.perform (frida/node_modules/frida-java-bridge/lib/vm.js:12:1)",
    "fileName": "frida/node_modules/frida-java-bridge/lib/android.js",
    "lineNumber": 1617,
    "columnNumber": 1
}

eg code:

import Wrapper = Java.Wrapper;

Java.perform(() => {
  try {
    const application = Java.use('android.app.ActivityThread').currentApplication() as (Wrapper | null);
    if (!application) {
      console.log('initBroadcastReceiver !application');
      return;
    }
    const ctx = application.getApplicationContext();
    console.log(ctx);
  } catch (e) {
    //===
    console.error('initBroadcastReceiver error', e);
    //===
  }
})

thinhbuzz avatar Oct 02 '24 11:10 thinhbuzz

I don't have a similar device available. you could comment out this whole if statement here if it is not working you can add logs to narrow the bug sadly the stacktrace you linked does not match the correct lines of frida-java-bridge

matbrik avatar Oct 02 '24 12:10 matbrik

I don't have a similar device available. you could comment out this whole if statement here if it is not working you can add logs to narrow the bug sadly the stacktrace you linked does not match the correct lines of frida-java-bridge

If you comment out that conditional statement, it will work like it did before.

if it is not working you can add logs to narrow the bug sadly the stacktrace you linked does not match the correct lines of frida-java-bridge

It seems that when building, Frida will minify the JavaScript code, leading to stack traces no longer matching those in this library. Can you guide me on how to set up to add logging?

By the way, this is the command I use to build. ./configure --host=android-arm64 && make

thinhbuzz avatar Oct 02 '24 14:10 thinhbuzz

If you comment out that conditional statement, it will work like it did before.

so it does work correctly on your Android 10?

Can you guide me on how to set up to add logging? just add several console.log("") in the android.js to track down the point in the code that causes crash

check also this comment from frida/frida there is a variation of this pull request with a different heuristic https://github.com/frida/frida/issues/2958#issuecomment-2388822794

matbrik avatar Oct 02 '24 15:10 matbrik

so it does work correctly on your Android 10?

Yes, it works just like before.

check also this comment from frida/frida there is a variation of this pull request with a different heuristic

I will try and report back the results.

thinhbuzz avatar Oct 02 '24 15:10 thinhbuzz

check also this comment from frida/frida there is a variation of this pull request with a different heuristic

I will try and report back the results.

@matbrik After applying the patch to frida-java-bridge, I still encountered a similar error in the makeArtThreadStateTransitionImpl function. Commenting it out made everything work again.

Additionally, when I applied the patch to the frida-core/lib/payload/cloak.vala file, I couldn't build successfully.

thinhbuzz avatar Oct 02 '24 17:10 thinhbuzz

@matbrik @thinhbuzz On my S21 Ultra running Android 14 and this latest Google Play update, this PR fixes the error but the actual function passed to Java.perform never gets called. Are you not seeing this problem on your device?

It works fine on an old Android 11 Pixel 2.

radubogdan2k avatar Oct 06 '24 11:10 radubogdan2k

@matbrik @thinhbuzz On my S21 Ultra running Android 14 and this latest Google Play update, this PR fixes the error but the actual function passed to Java.perform never gets called. Are you not seeing this problem on your device?

It works fine on an old Android 11 Pixel 2.

@radubogdan2k I have someone else reporting me the same problem on the same device. Sometimes the hooks are not triggered but there is not any error reported.

Maybe @oleavr can share some wisdom on the cause and how to fix it

matbrik avatar Oct 07 '24 09:10 matbrik

@matbrik @thinhbuzz On my S21 Ultra running Android 14 and this latest Google Play update, this PR fixes the error but the actual function passed to Java.perform never gets called. Are you not seeing this problem on your device? It works fine on an old Android 11 Pixel 2.

@radubogdan2k I have someone else reporting me the same problem on the same device. Sometimes the hooks are not triggered but there is not any error reported.

Maybe @oleavr can share some wisdom on the cause and how to fix it

Yes, that's exactly the behavior I'm seeing also. Hopefully Ole will be able to help.

radubogdan2k avatar Oct 07 '24 10:10 radubogdan2k

@matbrik @thinhbuzz On my S21 Ultra running Android 14 and this latest Google Play update, this PR fixes the error but the actual function passed to Java.perform never gets called. Are you not seeing this problem on your device? It works fine on an old Android 11 Pixel 2.

@radubogdan2k I have someone else reporting me the same problem on the same device. Sometimes the hooks are not triggered but there is not any error reported. Maybe @oleavr can share some wisdom on the cause and how to fix it

Yes, that's exactly the behavior I'm seeing also. Hopefully Ole will be able to help.

Yeah, I have confirmed that some classes and methods are not hooked in a commercial app that I cannot reveal the name of. (Frida 16.5.6 modified)

As of now, I have to remove the com.google.android.art package, and there seems to be no other countermeasure at the moment.

pig837 avatar Oct 24 '24 07:10 pig837

Fix only for arm64 Due to libart being stripped we missed DoCall hooks and NterpEntrypoints. It is also missing the ensurePluginLoaded used in Java.choose, I found the function in memory but on a device it caused a massive slowdown of the app and I decided to keep it commented out

matbrik avatar Oct 29 '24 14:10 matbrik

@matbrik @thinhbuzz On my S21 Ultra running Android 14 and this latest Google Play update, this PR fixes the error but the actual function passed to Java.perform never gets called. Are you not seeing this problem on your device? It works fine on an old Android 11 Pixel 2.

@radubogdan2k I have someone else reporting me the same problem on the same device. Sometimes the hooks are not triggered but there is not any error reported. Maybe @oleavr can share some wisdom on the cause and how to fix it

Yes, that's exactly the behavior I'm seeing also. Hopefully Ole will be able to help.

Yeah, I have confirmed that some classes and methods are not hooked in a commercial app that I cannot reveal the name of. (Frida 16.5.6 modified)

As of now, I have to remove the com.google.android.art package, and there seems to be no other countermeasure at the moment.

Fixed, @matbrik Thx. (Google Play System Update 2024.10, com.android.art@351011240)

pig837 avatar Oct 30 '24 00:10 pig837

@matbrik I got a new error on Samsung Galaxy Note 9 (SM-N960F/DS) - android 10 device

{
    "type": "error",
    "description": "Error: invalid decimal string",
    "stack": "Error: invalid decimal string\n    at qe (frida/node_modules/frida-java-bridge/lib/android.js:274:1)\n    at ze (frida/node_modules/frida-java-bridge/lib/android.js:207:1)\n    at Fe (frida/node_modules/frida-java-bridge/lib/android.js:16:1)\n    at _tryInitialize (frida/node_modules/frida-java-bridge/index.js:29:1)\n    at new _ (frida/node_modules/frida-java-bridge/index.js:21:1)\n    at Object.4../lib/android (frida/node_modules/frida-java-bridge/index.js:332:1)\n    at o (frida/node_modules/browser-pack/_prelude.js:1:1)\n    at frida/node_modules/browser-pack/_prelude.js:1:1\n    at Object.22.frida-java-bridge (frida/runtime/java.js:1:1)\n    at o (frida/node_modules/browser-pack/_prelude.js:1:1)",
    "fileName": "frida/node_modules/frida-java-bridge/lib/android.js",
    "lineNumber": 274,
    "columnNumber": 1
}

thinhbuzz avatar Oct 30 '24 01:10 thinhbuzz

@matbrik I got a new error on Samsung Galaxy Note 9 (SM-N960F/DS) - android 10 device

{
    "type": "error",
    "description": "Error: invalid decimal string",
    "stack": "Error: invalid decimal string\n    at qe (frida/node_modules/frida-java-bridge/lib/android.js:274:1)\n    at ze (frida/node_modules/frida-java-bridge/lib/android.js:207:1)\n    at Fe (frida/node_modules/frida-java-bridge/lib/android.js:16:1)\n    at _tryInitialize (frida/node_modules/frida-java-bridge/index.js:29:1)\n    at new _ (frida/node_modules/frida-java-bridge/index.js:21:1)\n    at Object.4../lib/android (frida/node_modules/frida-java-bridge/index.js:332:1)\n    at o (frida/node_modules/browser-pack/_prelude.js:1:1)\n    at frida/node_modules/browser-pack/_prelude.js:1:1\n    at Object.22.frida-java-bridge (frida/runtime/java.js:1:1)\n    at o (frida/node_modules/browser-pack/_prelude.js:1:1)",
    "fileName": "frida/node_modules/frida-java-bridge/lib/android.js",
    "lineNumber": 274,
    "columnNumber": 1
}

@thinhbuzz can you share your gadget so I can check where it crashes? and tell me the version of libart installed?

matbrik avatar Oct 30 '24 08:10 matbrik

@thinhbuzz can you share your gadget so I can check where it crashes? and tell me the version of libart installed?

~~i use frida-inject and not frida gadget. for art info you can see in my comment above.~~ latest commit works fine

thinhbuzz avatar Oct 30 '24 08:10 thinhbuzz

@matbrik

I share the current status of this issue (Contributed by @hackcatml)

  • Comment: https://github.com/frida/frida/issues/2958#issuecomment-2488844579

  • Code: https://gist.github.com/hackcatml/e4ad5a73f08758332da9d347b11aac0e

pig837 avatar Nov 22 '24 05:11 pig837

Thanks a lot for this amazing contribution, and apologies for the delay. I've been in a very deep iOS rabbit-hole, and had to hold off on reviewing non-trivial PRs in the meantime.

I've started working on polishing this PR in fix/art-compat, incorporating the improvements by @hackcatml on top of it. The first pass of refactoring is now working on arm64, but 32-bit ARM is still work in progress.

oleavr avatar Dec 12 '24 23:12 oleavr

Hi @oleavr thanks for the help and sorry for my horrible code :) . Here there are some suggestion and fixes to problems I encountered: at https://github.com/frida/frida-java-bridge/blob/653246ec88ac7d85dd96fd8b2bee1fe91e0b79e2/lib/android.js#L691 isApiLevel34OrApexEquivalent is not working in libart 35 because the symbol we are looking for is present in libart 34 but not in libart 35 which is stripped of a lot of symbols, in my code https://github.com/frida/frida-java-bridge/commit/807c7f00689e4e506aa8711684e6ba431f719c66#diff-127e99379196fef4dc63a69846f5adbcf81a12eb24557f9b1850b85a9f4f78dfR727 I also looked for the new signature of the RunFlip available from libart 35

for the support to arm I had ready a couple of functions for finding the DoCall function

function findDoCalls32 () {

  const pattern ='2d e9 f0 4f 03 af ?? b0 c0 ef 50 00';
  const module = Process.findModuleByName('libart.so');
  const ranges = module.enumerateRanges('r-x');
  return ranges.map((range) => {
    const base = range.base;
    const size = range.size;
    const result = Memory.scanSync(base, size, pattern);
    if (result.length > 0) return result;
    return null;
  }).filter(element => element !== null).flat();
  const patternResults = findPatternInModule(pattern, 'libart.so');
  return patternResults
}

and for the ExecuteNterpImpl

function findExecuteNterpImpl32 () {
  const pattern = '02 CA 4D E2 00 C0 9C E5  F0 4F 2D E9 10 8A 2D ED 10 B0 90 E5 01 00 1B E3';
  const module = Process.findModuleByName('libart.so');
  const ranges = module.enumerateRanges('r-x');
  return ranges.map((range) => {
    const base = range.base;
    const size = range.size;
    const result = Memory.scanSync(base, size, pattern);
    if (result.length > 0) return result;
    return null;
  }).filter(element => element !== null).flat();
  const patternResults = findPatternInModule(pattern, 'libart.so');
  return patternResults
}

matbrik avatar Dec 13 '24 08:12 matbrik

Superseded by 33307d4d5f074094b802dbbe2adfe7ab4e909470. Thanks!

oleavr avatar Jan 08 '25 10:01 oleavr