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

Pause/Resume when a hook is reached #544

Open
cryptax opened this issue May 16, 2022 · 8 comments
Open

Pause/Resume when a hook is reached #544

cryptax opened this issue May 16, 2022 · 8 comments

Comments

@cryptax
Copy link

cryptax commented May 16, 2022

It would be convenient to pause when a given hook is reached, so that we can for instance retrieve file from the file system at this exact moment.
For example, if I wish to unpack a sample, I can add a hook onto DexClassLoader constructor. When the constructor is reached, if it pauses, I can go and inspect the device, download the DEX. Then, I can resume execution.
Currently, pause/resume is not possible, thus, in many cases, I see that DexClassLoader is reached, would love to grab the file, but by the time I do, File.delete() has been called and I am too late.

For example this is what I have:

objection --gadget com.qfoqzju.yrcapztuywyu explore --startup-command 'android hooking watch class_method dalvik.system.DexClassLoader.$init --dump-args --dump-return'
(agent) Attempting to watch class dalvik.system.DexClassLoader and method $init.
(agent) Hooking dalvik.system.DexClassLoader.$init(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader)
(agent) Registering job 484905. Type: watch-method for: dalvik.system.DexClassLoader.$init
...
(agent) [025432] Called dalvik.system.DexClassLoader.DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader)
(agent) [025432] Arguments dalvik.system.DexClassLoader.DexClassLoader(:/data/user/0/com.qfoqzju.yrcapztuywyu/app_files/zczvob.jar, /data/user/0/com.qfoqzju.yrcapztuywyu/app_files, (none), dalvik.system.PathClassLoader[DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.qfoqzju.yrcapztuywyu-Kepiuxeda7PSWVYTzj0XYg==/base.apk"],nativeLibraryDirectories=[/data/app/com.qfoqzju.yrcapztuywyu-Kepiuxeda7PSWVYTzj0XYg==/lib/x86, /system/lib]]])

Describe the solution you'd like

objection --gadget com.qfoqzju.yrcapztuywyu explore --startup-command 'android hooking pause class_method dalvik.system.DexClassLoader.$init --dump-args --dump-return' would be lovely.

Note the keyword pause.
Then, when it is paused, I could issue a resume to continue when I am ready.

Describe alternatives you've considered

I considered hooking File.delete and modifying it's return value, but that doesn't work, because there is no meant return value for that. I'd need to make File.delete do nothing.

I also considered writing a Frida hook. But the point of easy hooking with objection is not to have to do that :)

@CDuPlooy
Copy link
Contributor

CDuPlooy commented May 16, 2022

I don't think it'd be trivial to add something like that. If instead what your after is a way to pull dex files loaded by dalvik.system.DexClassLoader and store them on your testing machine, that could be do-able.

Maybe something like android hooking dexloader enable --dump-dir /tmp ?

@leonjza
Copy link
Member

leonjza commented May 16, 2022

Thinking about this problem today, I was getting stuck on how we would manage to pause everything when an application is running. I don't know the answer that.

However, (ignoring the potentially catastrophic side effects this might have depending on what you are hooking) we could block in a function's onEnter() (and probably onLeave() too) with something like this:

var op = recv('input', function(value) {
    // do work with value.payload
});
op.wait();

Maybe this warrants a new flag in the hooking commands to patch in such a blocking revc(), even if just to allow for a user to press enter to something to continue?

@CDuPlooy
Copy link
Contributor

@leonjza you mentioned the catastrophic side effects, what I've seen when trying to instrument RASP solutions is that the application will crash if something like that is blocking for longer than some amount of time, granted that was only one case.

My other concern is that it's misleading to say the application has been paused when in reality only that one specific thread is blocking.

That said, I do know the above happens to work in some cases (enough that I've used it often outside of objection).

@leonjza
Copy link
Member

leonjza commented May 16, 2022

My other concern is that it's misleading to say the application has been paused when in reality only that one specific thread is blocking.

Yeah we can just call it a thread block or something more appropriate, with a warning saying the app is probably going to crash. If it does not, buy a lotto ticket! :P

@CDuPlooy
Copy link
Contributor

http://www.giovanni-rocca.com/how-i-turn-frick-into-a-real-frida-based-debugger/

I looked into breakpoints a while ago and came across this excellent blog post. There a way to handle process level exceptions (I've got an example somewhere else) that may also be useful. TLDR of what I'm thinking:

  • Create a breakpoint using the above
  • When it's triggered, suspend the process tree of the app
  • Return some context to the objection repl
  • Once resume is picked, resume all threads

I think the hardest parts of this would be around ensuring this works on as many android devices as possible. I recall having some trouble with the whole suspending a thread thing.

@cryptax
Copy link
Author

cryptax commented May 17, 2022

I don't think it'd be trivial to add something like that. If instead what your after is a way to pull dex files loaded by dalvik.system.DexClassLoader and store them on your testing machine, that could be do-able.

Maybe something like android hooking dexloader enable --dump-dir /tmp ?

Yes, that would work for me, but it's less generic than having a way to issue kind of a breakpoint.

  • note DEX files can also be loaded with PathClassLoader, or InMemoryDexClassLoader.

@cryptax
Copy link
Author

cryptax commented May 17, 2022

@leonjza you mentioned the catastrophic side effects

Yes, I am aware this can cause serious issues, depending where you pause. But it's a hacker tool. So, if you play nuts, bad things occur ;P

Yeah we can just call it a thread block or something more appropriate

Would be fine.

Other options - instead of pausing -

  • Allow input/output arguments to be dumped in files instead of just printing them. That would solve my problem. But we have to find a way to specify the dump file.
  • Allow to hook a given method with a Frida hook. I'm not sure this is such a good solution, because one of the points of objection is having not to write Frida hooks...
  • Slightly different than pause, put a sleep before the hooked method is actually called. I'll dump quickly during that time frame. It's less convenient, but do-able.

@CDuPlooy
Copy link
Contributor

CDuPlooy commented Oct 27, 2022

wow, this year has gone by quickly.

I've literally spent a hot minute thinking about this, so @leonjza, in line with what you were proposing, how about editing the watch command to add another option --break which will set a "BrEaKpOiNt" haha

We could then add something similar to the jobs interface, where for each unique function call, an entry is created and you have to explicitly resume it. This could work using the messaging API combination of send and recv. Something like

ios hooking watch NSData --dump-args --break

Once the method is invoked we can output something like:

$CLASS & $METHOD has been triggered, blocking until .... (I'll think of some better wording)

Then users can do breakpoints list coupled with breakpoints continue $BP

EDIT: It probably also makes sense to have a continue all option

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

No branches or pull requests

3 participants