-
Notifications
You must be signed in to change notification settings - Fork 6
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
Proposal: Copy and Micropatch based target #24
Comments
@calebh Thanks for bringing this idea up! This does indeed look like a very clever way to do instruction-level patching using C code. I agree using I think a good way to implement this is to add an optional argument p = Patcherex("some_binary", target_opts={"compiler": "clang19"}) # clang 19 component to be implemented
c_code = """
if(rcx >= r8){
rdi = rsi * rdx;
}
"""
p.patches.append(InsertInstructionPatch(0xdeadbeef, c_code, language="C")) Let me know if you have a better idea on how to integrate it into patcherex2 :) |
An initial implementation for x64 optionally using preserve_none is now working in our fork. See the example here: https://github.com/draperlaboratory/Patcherex2/blob/main/examples/insert_instruction_patch_c/patch.py Here is the general strategy that I have implemented: For the most part the logic is the same as an assembly InsertInstructionPatch, except that we compile C instead of assembly. The inserted code consists of the compiled C code concatenated with the moved instructions. This is followed by a jump back to just after the insertion point. The There are changes in a few different places:
The user can also use subregisters by passing them as appropriate to
However you cannot use both What remains to be done:
Primary files changed:
Here is the current generated C for the example program (the user never sees this):
|
@calebh Thanks for the great work on this so far! The overall code looks pretty good to me. A few thoughts:
Let me know if there's anything you need from me to help wrap this up. Once you feel it's ready, please go ahead and open a PR against the main branch. I'll do a thorough code review and testing pass, and then we can get it merged. Thanks again for driving this forward! |
The fork is currently in good shape, nearly ready to merge back into the main repo. Most of the remaining tasks revolve around different architectures. What's left to do:
I do not currently have access to any systems that are not x64. Do you have any system for testing non x64 architectures? |
@calebh Thank you for your efforts to make this happen! |
Implemented in #31 |
My coworker, Phil Zucker, came up with a new clever method of creating micropatches using an ordinary C compiler. The strategy is called "copy and micropatch" and operates similarly to copy and patch JITs. The strategy is based around abuse of the calling convention to force values into certain registers.
The easiest way to illustrate the concept is with an example (taken from Phil's blog):
The calling convention for this snippet ensures that the
PATCHCODE
receives certain registers as inputs, and theCALLBACK
at the end ensures that the variables are placed into the correct registers once the function terminates.The code is passed through an ordinary C compiler, and the body of
PATCHCODE
is extracted and inserted somewhere where there is space. This process requires tail-call optimization turned on, which turns the call toCALLBACK
into a jump. Through the use of a linker script we could set the CALLBACK symbol to be placed at the detour return point.With the
__attribute__((preserve_none))
tag built into the latest version of Clang, we can get control over many registers (at least on x64). Note that thepreserve_none
is brand new, I don't think it has landed into any release versions of Clang yet. As an alternative topreserve_none
, we could add shims to push/pop registers to ensure the data gets to the right place.For more info, see Phil's blog here: https://www.philipzucker.com/permutation_compile/
I'm willing to put the time into developing this target for integration into patcherex2. Is there anything that we need to know before forking and getting started? Using the version of Clang with support for
preserve_none
would be highly desirable.See also:
preserve_none
calling convention on AArch64 targets llvm/llvm-project#87423The text was updated successfully, but these errors were encountered: