Closed rhyek closed 1 month ago
Ok, I just went through https://github.com/sensepost/objection/wiki/Early-Instrumentation and it all seems simple enough, but my patched application is not starting in a paused state. Am i missing something? A missing option, perhaps?
I did have to patch the apk with these options: objection patchapk --source test.apk --skip-resources --pause
to avoid some errors I was getting. Might this be why my patched version of the apk is starting up without waiting for my REPL session?
I am using objection 1.8.4, apktool 2.4.1, openjdk 1.8.0_242
Ok, I went ahead and just edited the Smali code myself, built the apk, signed it and everything works as expected. Feel free to close the issue, but objection
did not work for me in this regard.
Hey! So the early instrumentation in objection is at fault here, and not the way you had to patch the agent in. Launching objection and then running the import
command means that app would have been resumed already so that objections own agent logic can be run before your script comes along. From the early instrumentation article, really whats happening behind the scenes is a crappy race condition to just run some agent logic before others.
There is actually a PR to improve this here which still needs to be properly tested.
I am considering adding another change to mimic the frida
command-line tool's behaviour that would allow importing your script, then manually resuming when you are ready before the rest of the agent logic comes along.
ok, seems good. what's odd to me is from the docs I had understood that running a patched apk would have it be in a paused state immediately giving me all the time in a world to run the explore command and only then resume. that is not happening at all. the app starts up normally. is this what you're talking about as well? you're saying the race condition is what's preventing the app from pausing?
When you patch an app, the launchable activity gets a loadLibrary
call (unless you specify another class to target) in its constructor. After you install the patched app on your device and tap to launch it, as soon as the launchable activities constructor is run, the Frida gadget loads, affectively pausing further execution. This is the paused state that is referred to in the docs where the Frida Gadget is waiting for a client to connect and tell it to resume. The moment you connect objection, it will inject its own agent and resume the application to interact with it.
This "connect -> resume" is the part that needs improvement, which is tricky at the moment as some of the REPL is populated from responses received from the agent and needs some refactoring.
Hope that helps!
ok, then what I am saying is my patched apk is not opening in a paused state.
Gotcha. So I think there could be a few reasons and it would definitely need some debugging. I would consider:
patchapk
command?The original apk is not mine, but what I can tell you is the code is obfuscated.
Patching should be ok even if the app is obfuscated. Last thing I can suggest is to try patch the class defined in the app manifests app:name
key in the application
tag with --target-class
flag.
I'm currently struggling with nearly the same problem. I want to patch the same method as rhyek. I'm doing this on a rooted phone and after many hours of trying different things I think this should be the correct approach:
objection --gadget "com.car2go" -N -h 192.168.178.24 explore --startup-script start.js
So this should start the app with frida and then automatically load my script at startup through objection.
However it gives me this error:
Using networked device @`192.168.178.24:27042`
Agent injected and responds ok!
Importing and running startup script at: <_io.TextIOWrapper name='start.js' mode='r' encoding='cp1252'>
Traceback (most recent call last):
File "c:\python37-32\lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "c:\python37-32\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Python37-32\Scripts\objection.exe\__main__.py", line 7, in <module>
File "c:\python37-32\lib\site-packages\click\core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "c:\python37-32\lib\site-packages\click\core.py", line 782, in main
rv = self.invoke(ctx)
File "c:\python37-32\lib\site-packages\click\core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "c:\python37-32\lib\site-packages\click\core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "c:\python37-32\lib\site-packages\click\core.py", line 610, in invoke
return callback(*args, **kwargs)
File "c:\python37-32\lib\site-packages\objection\console\cli.py", line 149, in explore
response = agent.single(startup_script.read())
File "c:\python37-32\lib\site-packages\objection\utils\agent.py", line 249, in single
self.device.resume(self.spawned_pid)
File "c:\python37-32\lib\site-packages\frida\core.py", line 26, in wrapper
return f(*args, **kwargs)
File "c:\python37-32\lib\site-packages\frida\core.py", line 148, in resume
self._impl.resume(self._pid_of(target))
frida.InvalidArgumentError: invalid PID
Asking jobs to stop...
Unloading objection agent...
I'm not sure if this fault is Frida or Objection. The same command does work if the app was already launched before. I assume the early execution is problematic.
I'm not sure if this fault is Frida or Objection.
This looks like objections fault for not getting the right PID to resume the app when you provide a startup script. Maybe this is the culprit. I am not sure and will have to debug that as well.
I'm not sure if this fault is Frida or Objection.
This looks like objections fault for not getting the right PID to resume the app when you provide a startup script. Maybe this is the culprit. I am not sure and will have to debug that as well.
Here is the log with --debug
[debug] Injecting agent...
Using networked device @`192.168.178.24:27042`
[debug] Attempting to attach to process: `com.car2go`
[debug] Unable to find process: `com.car2go`, attempting spawn
[debug] PID `24764` spawned, attaching...
[debug] Resuming PID `24764`
Agent injected and responds ok!
Importing and running startup script at: <_io.TextIOWrapper name='start.js' mode='r' encoding='cp1252'>
[debug] Resuming PID `24764`
Maybe resuming twice is the bug? The process is resumed after attaching and once more after the startup script has been loaded.
Maybe resuming twice is the bug? The process is resumed after attaching and once more after the startup script has been loaded.
Ah that may very well be it. Try and comment out the block I quoted maybe and see if that helps? If you are unsure how to get a dev environment up, this may help.
Keep in mind the original context of this ticket though. Early instrumentation needs some love.
I added self.resumed = True
after this line
But now I get another error:
Importing and running startup script at: <_io.TextIOWrapper name='sharenowHooks.js' mode='r' encoding='cp1252'>
[]
Traceback (most recent call last):
File "c:\python37-32\lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "c:\python37-32\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Python37-32\Scripts\objection.exe\__main__.py", line 7, in <module>
File "c:\python37-32\lib\site-packages\click\core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "c:\python37-32\lib\site-packages\click\core.py", line 782, in main
rv = self.invoke(ctx)
File "c:\python37-32\lib\site-packages\click\core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "c:\python37-32\lib\site-packages\click\core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "c:\python37-32\lib\site-packages\click\core.py", line 610, in invoke
return callback(*args, **kwargs)
File "c:\python37-32\lib\site-packages\objection\console\cli.py", line 156, in explore
device_info = get_device_info()
File "c:\python37-32\lib\site-packages\objection\commands\device.py", line 41, in get_device_info
package_info = api.env_android()
File "c:\python37-32\lib\site-packages\frida\core.py", line 401, in method
return script._rpc_request('call', js_name, args, **kwargs)
File "c:\python37-32\lib\site-packages\frida\core.py", line 26, in wrapper
return f(*args, **kwargs)
File "c:\python37-32\lib\site-packages\frida\core.py", line 333, in _rpc_request
raise result[2]
frida.InvalidOperationError: script is destroyed
Asking jobs to stop...
Unloading objection agent...
[debug] Calling unload()
Unable to run cleanups: script is destroyed
So, when will this love happen you are speaking of? :D
I have been having the same problem. I'm using the same script as @rhyek where I change the CertificatePinner.Builder.add function on startup. My application is obfuscated and using Jadx I found that the function is called a in class m.h$a. My code is:
console.log("Waiting for Java..");
while(!Java.available) {
console.log("Java not available yet");
}
console.log("Java available..");
Java.perform(function(){
console.log("Entered perform..");
var Pinner = Java.use("m.h$a");
console.log(Pinner);
console.log(Pinner.a.overload('java.lang.String', '[Ljava.lang.String;'));
Pinner.a.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(a, b)
{
console.log("Disabling pin for " + a);
return this;
}
console.log('Done');
});
Then I run the following command:
objection --gadget XXX explore --startup-script hook.js
with the following output:
Using USB device `Android Emulator 5554`
Agent injected and responds ok!
Importing and running startup script at: <_io.TextIOWrapper name='hook.js' mode='r' encoding='cp1252'>
Waiting for Java..
Java available..
Entered perform..
<class: m.h$a>
function e() { [ecmascript code] }
Done
Traceback (most recent call last):
File "C:\Users\Kasper\AppData\Local\Programs\Python\Python38-32\Scripts\objection-script.py", line 11, in <module>
load_entry_point('objection==1.9.6', 'console_scripts', 'objection')()
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\click\core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\click\core.py", line 782, in main
rv = self.invoke(ctx)
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\click\core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\click\core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\click\core.py", line 610, in invoke
return callback(*args, **kwargs)
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\objection\console\cli.py", line 149, in explore
response = agent.single(startup_script.read())
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\objection\utils\agent.py", line 249, in single
self.device.resume(self.spawned_pid)
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\frida\core.py", line 26, in wrapper
return f(*args, **kwargs)
File "c:\users\kasper\appdata\local\programs\python\python38-32\lib\site-packages\frida\core.py", line 148, in resume
self._impl.resume(self._pid_of(target))
frida.InvalidArgumentError: invalid PID
Asking jobs to stop...
Unloading objection agent...
The app also starts, but certificate pinning is still enabled. From the output I can see that the script works as expected, since the correct class and function are found. But the console.log() inside of the overwritten function is never fired. So I assume that the function has already been called before the script was injected, and making it useless. Is there anyway to get this script running before the app creates it's CertificatePinner instance?
The article from NVISO states that doing import hook.js
when objection is already running should work, but as @rhyek said, that doesn't make sense to me because the app should already instantiated it when it's up and running. I'm sure it does work and the function is overwritten, but it should happen before the app starts.
I'm not sure about the invalid PID error, but the script doesn't work when I fire it directly with Frida:
frida -U -f XXX -l hook.js --no-pause
This starts the app and immediately crashes it. What is strange though, is that I get output from the first two console.log()'s, but but not from the console.log()'s inside of the Java.perform(). Am I missing something? I'm quite new to this.
Regarding the hook, hooking post instantiation is usualy ok. It's tricky in that you are hooking an add
method which probably only happens once, hence the need for early instrumentation. I'd suggest you hunt for the actual verification logic so that you can hook at any time. As for the hook itself, the return this
means this function itself is being returned, instead of the return value the function called is expecting which is why your hook is probably not working. For example, here we return an empty ArrayList
which is the expected return type.
Regarding the PID error, this is probably a bug in the current early instrumentation logic when using a script. I am expecting an import hook.js
to work just fine if you hunt down the verification logic, assuming your hook is correct. If your hook is not firing using the default frida
tools, it will most certainly fail in objection as well.
The best early instrumentation implementation is going to be using the frida
command line and a valid hook for now.
For anyone that encounters this, I found a workaround that might sound obvious but took me a long while to figure out. Just use Frida natively to run your early instrumentation script, then attach to the process with Objection after that. This requires two terminal windows, or starting frida as a background job.
# After running the below line, you can interact with the application using Objection
# if you use its PID as the Gadget ID.
frida -U -f $targetapp -l ./frida_okhttp_pinner_bypass.js --no-pause
# -- In a separate terminal window
# Get PID of app while its running and instrumented with the above Frida script
frida-ps -Ua
# Attach to the target app with Objection
objection -g 11987 explore
For anyone that encounters this, I found a workaround that might sound obvious but took me a long while to figure out. Just use Frida natively to run your early instrumentation script, then attach to the process with Objection after that. This requires two terminal windows, or starting frida as a background job.
# After running the below line, you can interact with the application using Objection # if you use its PID as the Gadget ID. frida -U -f $targetapp -l ./frida_okhttp_pinner_bypass.js --no-pause # -- In a separate terminal window # Get PID of app while its running and instrumented with the above Frida script frida-ps -Ua # Attach to the target app with Objection objection -g 11987 explore
To be honest, I have given up objection, and then found that objection is not irreplaceable, and only using Frida scripts gave me more freedom.
Well IDK if i was right or wrong, you can load your app by running objection -g
For anyone that encounters this, I found a workaround that might sound obvious but took me a long while to figure out. Just use Frida natively to run your early instrumentation script, then attach to the process with Objection after that. This requires two terminal windows, or starting frida as a background job.
# After running the below line, you can interact with the application using Objection # if you use its PID as the Gadget ID. frida -U -f $targetapp -l ./frida_okhttp_pinner_bypass.js --no-pause # -- In a separate terminal window # Get PID of app while its running and instrumented with the above Frida script frida-ps -Ua # Attach to the target app with Objection objection -g 11987 explore
It's really helped.
But how can I find frida_okhttp_pinner_bypass.js, who can share
For anyone that encounters this, I found a workaround that might sound obvious but took me a long while to figure out. Just use Frida natively to run your early instrumentation script, then attach to the process with Objection after that. This requires two terminal windows, or starting frida as a background job.
# After running the below line, you can interact with the application using Objection # if you use its PID as the Gadget ID. frida -U -f $targetapp -l ./frida_okhttp_pinner_bypass.js --no-pause # -- In a separate terminal window # Get PID of app while its running and instrumented with the above Frida script frida-ps -Ua # Attach to the target app with Objection objection -g 11987 explore
It's not beautiful and not a good way, but it works.
For anyone that encounters this, I found a workaround that might sound obvious but took me a long while to figure out. Just use Frida natively to run your early instrumentation script, then attach to the process with Objection after that. This requires two terminal windows, or starting frida as a background job.
# After running the below line, you can interact with the application using Objection # if you use its PID as the Gadget ID. frida -U -f $targetapp -l ./frida_okhttp_pinner_bypass.js --no-pause # -- In a separate terminal window # Get PID of app while its running and instrumented with the above Frida script frida-ps -Ua # Attach to the target app with Objection objection -g 11987 explore
It's not beautiful and not a good way, but it works.
Don't use --no-pause
, please enter the command resume
to resume the process.
$ objection version
objection: 1.11.0
$ objection -s -n $target_package start -S $your_srcipt.js
... (run) on (Android: 9) [usb] # resume
... (run) on (Android: 9) [usb] #
Closing issue as stale, feel free to reopen.
Following this guide on disabling ssl pinning on obfuscated apps and this guide on working with jobs, I'm trying to understand the steps to get the following script working:
That script basically intercepts the
CertificatePinner.Builder.add()
method so that no hostname and pins are added at all, but i believe that is something that is run at application start-up. My workflow is currently this:1) install objection patched apk (com.test.app) to emulator 2) open app in emulator 3) create hook.js script with above code 3) in my terminal run
objection --gadget com.test.app explore
4) in REPL, runimport hook.js
This doesn't do anything and it makes sense to me since the
CertificatePinner.Builder.add()
would have already been called before I import my script.What do i need to change here? Ideally there would be a way to schedule my script to be run on application start up somehow. Thanks.