jeudi 13 avril 2023

C++ How to Programatically Change a Call Instruction at Runtime

Before getting into the details of the problem, I would like to disclose that this was handed to me as a research task, so it may or may not be possible. Simply, the end goal will be to have a class, that is able to call one of two functions based on a runtime condition, with minimal overhead. Our class will have two main methods:

(1) set_direction(bool) : here, we want to programatically change the call instruction in the next method. We can employ any methods to do so here, some of which I explored are binary editing, hooking, or even changing the contents of a defined executable buffer.

(2) branch() : here we will call one of two of the functions, selected by the above method. The key part is we want to do this with minimal overhead. That means, no pointer dereferencing and conditionals, just simply a CALL (or JMP) to an absolute address.

Our code will look something like this:

class BranchChanger
{
   private:
       func if_branch_func;
       func else_branch_func;
       /* possibly other stuff here as well */

   public:
       BranchChanger(func if_branch, func else_branch);
       void set_direction(bool); // change method called by 'branch' programatically
       auto branch(); // call either if_branch or else_branch directly with minimal overhead
}

Our main program should look like this:

#include <branch.h>

int add(int a, int b) { return a + b; }

int sub(int a, int b) { return a - b; }

int main() {
   BranchChanger branch = BranchChanger(&add, &sub);
   bool condition = rand() % 2; // our runtime condition
   branch.set_direction(condition);
   branch.branch(); // call either add or sub with minimal overhead
}

The problem is, what we want to happen when branch is called is this:

CALL <some_address>

But in reality, what always happens is this:

CALL QWORD PTR [<some_address>]

Due to how function pointers work, we cannot obtain the address of the function this way, because dereferencing function pointers just decay back to a pointer to the function. If we define an executable buffer with bytecode that we can edit, which we can allocate with some neat linux system calls, even this would need to be accessed through a pointer which we do not want. I have tried function hooking (including trampolines, detours ect), inline asm, indirect function compiler attributes, and even trying to stuff with symbols. However I have had no success because the branch() method will always involve some sort of indirection due to pointer dereferencing.

A really brute force idea I had would be to modify the current ELF in place, however I am not sure how feasible this is. What I wanted to do is manually copy the address of either of functions in the ELF, paste it within the body of branch, when set_direction is called. As you can see I am running out of ideas and I would appreciate some fresh eyes to look at the problem, maybe I am missing something (or maybe this is not possible at all).

Note, consider the desired syntax of the class as a placeholder, it may not be possible to actually do what we want using it, but its something we are aiming for.

All responses will be appreciated.

Aucun commentaire:

Enregistrer un commentaire