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

feat: "native" calls #2

Closed
ndrewh opened this issue May 7, 2024 · 2 comments
Closed

feat: "native" calls #2

ndrewh opened this issue May 7, 2024 · 2 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@ndrewh
Copy link
Owner

ndrewh commented May 7, 2024

I think in theory you can just cast an int to a function pointer using ctypes.cast and call it, but I'm not sure. It would be cool to make it easier to do make these calls e.g:

e = ELF(...)
crc32_result = p.call[e.symbols["crc32"]](0, b"AAAA", 4)

It would also be nice to do this with some guardrails. For example:

  • Catching segfaults that occur during these calls, and report them as Python exceptions
  • Instrument memory accesses during these calls so that they can be (optionally) rolled back (?)

These guardrails would be quite complicated to implement, so some analysis of use-cases is warranted...

@ndrewh ndrewh added the enhancement New feature or request label May 7, 2024
@ndrewh
Copy link
Owner Author

ndrewh commented Jul 9, 2024

I've realized there's a decent chance directly calling into the executable won't work as intended, depending on how much indirection is imposed by dynamorio in the first place. I don't think dynamorio actually ever jumps directly to app code; it always translates blocks and then jumps to the translation in the code cache. Depending on whether it also translates certain data accesses, we might not find the library in the state we intended.

Instead, I think it would be useful to have a primitive to "run code from X to Y safely". This has several applications, including making it easier to implement a call primitive. The basic flow needs to look something like this:

  1. Assert that the application is stopped (e.g. after a run_until. note: being in a hook does not qualify)
  2. Save the current mcontext (so we can restore it upon return from the call)
  3. Set up the new mcontext for the call (e.g. put args in registers), update rip
  4. p.run_until(end_addr)
  5. Restore mcontext

@ndrewh ndrewh modified the milestone: 0.3 Jul 9, 2024
@ndrewh
Copy link
Owner Author

ndrewh commented Jul 24, 2024

I've updated the previous comment now that run_until is implemented.

I think all we need to implement this is a push/pop operation for register state. We can leave the notion of "safety" or "rollback" to another issue (#31).

@ndrewh ndrewh added this to the 0.4 milestone Jul 24, 2024
@ndrewh ndrewh changed the title feat: native calls feat: "native" calls Jul 24, 2024
@ndrewh ndrewh self-assigned this Aug 3, 2024
@ndrewh ndrewh closed this as completed in d558622 Aug 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant