android: alternative offset to ExceptionClear in libart (https://github.com/frida/frida/issues/2958)(https://github.com/frida/frida-java-bridge/issues/336)
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
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?
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
It is confirmed that this patch works on com.android.art@350820860 - Android 13.
@matbrik It has issues on older devices or those without com.android.art for example as shown below.
@matbrik It has issues on older devices or those without
com.android.artfor example as shown below.
can you provide more details and logs on the error?
@matbrik It has issues on older devices or those without
com.android.artfor example as shown below.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);
//===
}
})
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
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
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
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.
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.
@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.
@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 @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.
@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.
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 @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)
@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
}
@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?
@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
@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
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.
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
}
Superseded by 33307d4d5f074094b802dbbe2adfe7ab4e909470. Thanks!
