Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dlopen hook failed in nexus6p with Android8.0 #448

Open
YaphetsH opened this issue Mar 14, 2018 · 20 comments
Open

dlopen hook failed in nexus6p with Android8.0 #448

YaphetsH opened this issue Mar 14, 2018 · 20 comments

Comments

@YaphetsH
Copy link

YaphetsH commented Mar 14, 2018

hook code:
Interceptor.attach(Module.findExportByName(null, 'dlopen'), {
onEnter: function (args) {
this.path = Memory.readUtf8String(args[0]);
console.log(this.path);
},
onLeave: function (retval) {
if(!retval.isNull() && this.path.indexOf('libnative-lib.so')!== -1 && !didHookApis) {
didHookApis = true;
console.log("File loaded hooking");
hooknative2();
// ...
}
}
});

And here is some error logs:
E/HAL: load: module=/vendor/lib64/hw/gralloc.msm8994.so
dlopen failed: library "/vendor/lib64/hw/gralloc.msm8994.so" needed or dlopened by "(unknown)" is not accessible for the namespace "(anonymous)"

What's the problem?

@awakened1712
Copy link

I faced the same issue. In fact, I tested with Android 7.0 and 7.1 on the Nexus 6P too. I got the same error.

@YaphetsH
Copy link
Author

YaphetsH commented Mar 17, 2018

@awakened1712 Now I change my nexus6p system from 8.1 to 6.0,and it works,I think something different about dlopen since Android 7.0 .
this maybe help you something.
And by the way,do you know how to modify native method retval in onLeave callback when return type is String?

@awakened1712
Copy link

I don't remember exactly. I think the below should work

var newStr = 'abcd';
Memory.writeUtf8String(retval, newStr);

@YaphetsH
Copy link
Author

@awakened1712 I try it and get this error
{'type': 'error', 'description': 'Error: access violation accessing 0x10001d', 'stack': 'Error: access violation accessing 0x10001d\n at script1.js:25', 'fileName': 'script1.js', 'lineNumber': 25, 'columnNumber': 1}
And I use Memory.project api to make target memory readable&writable,like this:

onLeave: function (retval) {
        Memory.protect(retval, 4,rw-');
	var newretval ='1234'
	Memory.writeUtf8String(retval,newretval);
 }

but it doesn't work,do you have this problem and how to deal with?

@awakened1712
Copy link

0x10001d does not seem to be a valid address to me. That's why you had access violation.

@YaphetsH
Copy link
Author

@awakened1712 so you don't have this error in your nexus6p?Maybe I have some code error.

@awakened1712
Copy link

I did not try to check the retval. Let me check again tomorrow.

@YaphetsH
Copy link
Author

YaphetsH commented Mar 18, 2018

@awakened1712 thanks

@YaphetsH
Copy link
Author

@awakened1712 Did you find something about it?

@madushan1000
Copy link

AFAIK, in Android 7, Google introduced "namespaces" for dlopen, you can't load any dynamic library outside the app namespace or it will fault. Frida itself get around this using a neat trick, take a look at the android injection code for a reference, maybe you can adopt that to your hooking logic.
Sorry I can't link to the code, I'm on my phone :/

@SheilaLundin
Copy link

@YaphetsH Have you solved this problem?

@flynnch
Copy link

flynnch commented Aug 20, 2018

same problem

@awakened1712
Copy link

awakened1712 commented Aug 20, 2018

@YaphetsH I gave up on dlopen hook. Instead, I hooked its Java wrapper, System.loadLibrary, as below:

Java.perform(function() {
    const System = Java.use('java.lang.System');
    const Runtime = Java.use('java.lang.Runtime');
    const VMStack = Java.use('dalvik.system.VMStack');

    System.loadLibrary.implementation = function(library) {
        try {
            console.log('System.loadLibrary("' + library + '")');
            const loaded = Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), library);
            return loaded;
        } catch(ex) {
            console.log(ex);
        }
    };
    
    System.load.implementation = function(library) {
        try {
            console.log('System.load("' + library + '")');
            const loaded = Runtime.getRuntime().load0(VMStack.getCallingClassLoader(), library);
            return loaded;
        } catch(ex) {
            console.log(ex);
        }
    };
});

@daviyang35
Copy link

This code will log correctly and will not cause the program to crash abnormally.

    var dlopen = new NativeFunction(Module.findExportByName(null, 'dlopen'), 'pointer', ['pointer', 'int']);
    Interceptor.replace(dlopen, new NativeCallback(function(path, mode) {
    	console.log("dlopen(" + "path=\"" + Memory.readUtf8String(path) + "\"" + ", mode=" + mode + ")");
        var name = Memory.readUtf8String(path);
        if (name !== null && name.indexOf('msm8994') !== -1) {
        	console.log("[*] found msm8994");
            return dlopen(path, mode);
        }
        return dlopen(path, mode);
    }, 'pointer', ['pointer', 'int']));

@chenbinhi
Copy link

AFAIK, in Android 7, Google introduced "namespaces" for dlopen, you can't load any dynamic library outside the app namespace or it will fault. Frida itself get around this using a neat trick, take a look at the android injection code for a reference, maybe you can adopt that to your hooking logic.
Sorry I can't link to the code, I'm on my phone :/

can you post this link? thanks

@enovella
Copy link

@iddoeldor
Copy link

Java.use('java.lang.Runtime')

for api < 23

    Java.use('java.lang.System').load.implementation = function (lib) {
		console.log(lib);
		return Java.use('java.lang.Runtime').getRuntime().load(lib, Java.use('dalvik.system.VMStack').getCallingClassLoader());
    };

This was referenced Sep 27, 2019
@n3tman
Copy link

n3tman commented Feb 7, 2020

I know this is an old one, but in my use case I had to combine the two solutions above.
dlopen caused an app crash in Android 7 (x86 emulator) and loadLibrary didn't work in Android 5:

undefined not callable property loadLibrary0

Also, load didn't get called at all in Android 5. This might be because of specific app's implementation of dynamic library loading.

Anyway, here's the combined solution. Removed try/catch for simplicity.

Java.perform(function () {
    const System = Java.use('java.lang.System');
    const Runtime = Java.use('java.lang.Runtime');
    const VMStack = Java.use('dalvik.system.VMStack');
    const sdkValue = Java.use('android.os.Build$VERSION').SDK_INT.value;

    if (sdkValue < 24) {
        Interceptor.attach(Module.findExportByName(null, 'dlopen'), {
            onEnter: function (args) {
                this.path = Memory.readUtf8String(args[0]);
                console.log('[*] dlopen called with: ' + this.path);
            },
            onLeave: function () {
                console.log('[*] dlopen finished with: ' + this.path);
            }
        });
    } else {
        System.loadLibrary.implementation = function (library) {
            console.log('[*] loadLibrary called with: ' + library);

            const loaded = Runtime.getRuntime().loadLibrary0(
                VMStack.getCallingClassLoader(), library
            );

            console.log('[*] loadLibrary finished with: ' + library);

            return loaded;
        };
    }
});

Note that there are two pairs of console.log commands. Replace them with your custom code depending on when you want the hook to execute (before or after a library is loaded).

Maybe sdk < 24 should be sdk < 23, but I didn't have a chance to test on Android 6, so I assumed dlopen should work there too.

@promeG
Copy link

promeG commented Apr 5, 2020

Try this code which I have tested on Android 7.1.

function intercept_dlopen(address) {
    try {
        Interceptor.attach(address, {
            onEnter: function(args) {
                this.lib = Memory.readUtf8String(args[0]);
	        console.log("dlopen called with: " + this.lib);
            },
            onLeave: function(ignored) {}
        });
    } catch (e) {
        console.error(e);
    }
}
 
function find_dlopen_symbol() {
	var dlopenSymbol;
	symbols.forEach(function(symbol){
		if (symbol.name == '__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv') {
			 dlopenSymbol = symbol;			 
		 } else if (symbol.name == '__dl__Z9do_dlopenPKciPK17android_dlextinfoPv') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl__ZL10dlopen_extPKciPK17android_dlextinfoPv') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl__Z20__android_dlopen_extPKciPK17android_dlextinfoPKv') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl___loader_android_dlopen_ext') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl__Z9do_dlopenPKciPK17android_dlextinfo') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl__Z8__dlopenPKciPKv') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl___loader_dlopen') {
			 dlopenSymbol = symbol;
		 } else if (symbol.name == '__dl_dlopen') {
			 dlopenSymbol = symbol;
		 }
		 
	});
	return dlopenSymbol;
}

var dlopenSymbol = find_dlopen_symbol();
console.log("hook   " + dlopenSymbol.name + "   " + dlopenSymbol.address);
intercept_dlopen(dlopenSymbol.address);

@brunoaduarte
Copy link

brunoaduarte commented May 13, 2024

@YaphetsH I gave up on dlopen hook. Instead, I hooked its Java wrapper, System.loadLibrary, as below:

Java.perform(function() {
    const System = Java.use('java.lang.System');
    const Runtime = Java.use('java.lang.Runtime');
    const VMStack = Java.use('dalvik.system.VMStack');

    System.loadLibrary.implementation = function(library) {
        try {
            console.log('System.loadLibrary("' + library + '")');
            const loaded = Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), library);
            return loaded;
        } catch(ex) {
            console.log(ex);
        }
    };
    
    System.load.implementation = function(library) {
        try {
            console.log('System.load("' + library + '")');
            const loaded = Runtime.getRuntime().load0(VMStack.getCallingClassLoader(), library);
            return loaded;
        } catch(ex) {
            console.log(ex);
        }
    };
});

Not a very good generic solution nowadays, because on apps that use "SuperPack" it will only log the loading of the superpack lib.

15:34:08 [com.app.util.Log.i]     applibloader/system-load-library-with-install start, loading: superpack

System.loadLibrary("superpack")

15:34:08 [com.app.util.Log.d]     applibloader/system-load-library-with-install loaded: superpack
15:34:08 [com.app.util.Log.i]     applibloader/system-load-library-with-install end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests