Tutorial Calling Functions Externally - The Definitive Guide

Traxin

Global Moderator
Moderator
Dank Tier VIP
Legacy Donator
Aug 3, 2015
794
289
63
#1
Invoke/Call Functions Externally
So it seems like text tutorials are all the rage as of lately so I decided to whip one up myself.

I hope to explain, as thoroughly as I possibly can, all the techniques that I know of to invoke a function in a remote process. It’s really just two; Use hooking techniques to route execution to some sort of injected code, and then a bunch of different ways of using CreateRemoteThread. Nothing groundbreaking but it’d be nice to have the explanations and several different code examples all in one place along with the benefits of being able to change it and add to it much easier.

Disclaimer: This should end up being a rather long writeup, but I’ll try to separate things as much as possible so you can jump around and go directly to what you need.

Tools & Prerequisites
I’ll be using C++ and Visual Studio to write and compile the code, so you should probably have Visual Studio installed and have some sort of familiarity with C++. With that said, the code provided will be C++, but most of the techniques demonstrated make use of the Windows API so this stuff can be implemented in many other languages. We’ll make a little bit of use of a debugger, I use x64dbg.

So the official tool list:
  • Visual Studio
  • Debugger, i.e.: x64dbg
In visual studio the settings are somewhat important… You don’t want debug code in your executables because it’ll ironically make it hard to debug later on.

So make sure you’re ALWAYS compiling in release mode!

Prerequisites for this tut:

I think that’s it, idk. Let’s move on to some setup before the nitty gritty.

Set up
We’re going to be coding both programs, a target, and an invoker. Hopefully, through the naming we all understand what each program will be doing but for those who don’t… The target will have different functions in it, we’re going to invoke these different functions from another program, the invoker. *mindblown*

So go ahead, crank that badboy up and start two (2) instances of Visual Studio. One project we’ll name Target, the other… You guessed it! Invoker.

Next, go to Target’s project settings. Again, make sure you’re in release mode and that you’re editing the project settings for the correct configuration and platform. You’ll notice I have it set to all configurations just to be safe. Now disable optimizations, remember to hit Apply. Do the same for the Invoker.


Now that we have all that out of the way, we’ll write a few functions with different signatures. Nothing crazy.

So I broke the all the code up into two files. In Functions.h there are several functions that we will be invoking, they all have different signatures to cover different situations. In Target.cpp you’ll see a simple class with a couple of functions, I’ll also demonstrate calling member functions externally for the sake of being thorough.

Just check out the git for the target code or download it to your computer and familiarize yourself with it really quickly.

To view link: Login

To view link: Login


I believe if you clone the projects from github then the project settings should still be intact.
Not sure, but that's why I also included an image of the project settings.

Alright, now that all that is out of the way, lets get started 😉
CreateRemoteThread

I think the CreateRemoteThread (from now on CRT) method is a bit more straightforward and easier to grasp so I’ll go ahead and start with this and the 1000 ways to skin a cat.

From MSDN:

“Creates a thread that runs in the virtual address space of another process.”

To view link: Login


There are really only 3 parameters that we’ll be interested, or make use of, in for this tutorial. The process handle (hProcess), the LPTHREAD_START_ROUTINE (lpStartAddress) which is essentially a pointer to the code we want to start a thread at, and lpParameter which can be either a valid pointer to the arguments, or if the function expects a simple value, you can just shove that value right in here and it’ll work. This will be made clearer later on in the code example.

Let’s get started…

Simple Invoke
We’ll start off by calling
To view link: Login
in the target process. It’s a simple function that doesn’t take any arguments and doesn’t return anything. Calling a function like this is dead easy, you simply need to start a thread at the address of the function.

To view link: Login


It’s really that easy.

Invoke With Argument
Next, we’ll call
To view link: Login
, very similar to Function1 but this time it expects an integer as an argument. For a function like this we just have to change a parameter to the value we want to pass. The argument lpParameter expects a pointer, the function expects an integer though, so how are we gonna fix this? We’re not, we’ll tell CRT it’s a pointer and just let it pass the value to the function.

To view link: Login


And we’re done.

To be continued... Post is already too long, we're nowhere near finished lol.
 
  • Game Downloading
  • Download
Last edited:

Traxin

Global Moderator
Moderator
Dank Tier VIP
Legacy Donator
Aug 3, 2015
794
289
63
#2
Writing Arguments to Memory
Let’s look at
To view link: Login
in the Target project, it’s expecting a c-string instead of a simple integer. So hopefully we all know how c-strings work but for those who don’t…

When you feed a function a char* or a c-string, you’re essentially passing the pointer to the first character in memory. The function will then read the memory located at that address up until it hits a null terminator or some other condition is met.

So what’s the issue? Why can’t we just do this?



The problem is the string is in the Invoker’s process space, not the target's. We’re essentially passing a pointer to memory outside of the process which will cause the target to throw an Access Violation Exception.

Instead, we need to allocate some space in the target process, write the string to the space allocated, and then feed the pointer for the string (memory we allocated) to CRT.

To view link: Login


Let’s move on.

Calling Functions with Shellcode (Image Heavy...)
We'll be calling
To view link: Login
for this section, and the next.

This method is probably the one that involves the most work but it’s still very straight forward. Same thing as before, we allocate memory where we can place data we need, such as the arguments, but this time we’ll also add some shellcode to handle the process of setting up the stack, calling the function, and handle any return data if necessary.

One easy way to write your shellcode is to just write assembly in the debugger. Get the address of the allocated memory, pull it up in your debugger and just start writing your code. If you’re compiling in release mode, sometimes setting breakpoints in visual studio doesn’t work correctly, so you’ll have to get creative. You can use a printf call to print the address of the allocated memory and use a call to getch or a system(“pause”) to pause execution. Pick your poison.



Once you’ve gotten the address of the buffer in the target, navigate to that address in the debugger and start writing your code. For this example, we’ll simply be setting up the stack and registers needed to invoke a function. For example, on x64 the code may look something like this…


Now what we’re going to do is copy just the bytes, so highlight the block of code, right click, binary and copy.


You’ll end up with a string of bytes like this


Personally, I like to throw in a few new lines to it matches the instructions.


Next, I like to replace the address bytes that I mentioned before with zeros. Just so it kind of reminds me that these are the locations that need to be resolved through our code.


Simple stuff really. Next comes the hard part…. Putting in all the little commas and 0x for each byte :p
I wrote a simple program to help with this part. (I suck at naming things… Also I think there are other tools that already do this...)


So we set up our little byte array and we replace the zero’d out address placeholders with valid addresses.


So now that that’s done, we can start setting up and writing stuff to our process. We can set up a simple struct for this example to encapsulate of the data we need for our function.

C++:
struct _Args
{
    int a = 0; //arg 1
    int b = 0; //arg 2
    int c = 0; //return
};
Create an object and write the data to the process, then write the code immediately following the data (or vice versa, however you want to do it.)


Then it’s just a simple process of doing the same thing we’ve been doing. Create a thread where the code it and let it do its business. Now, some of you may be wondering “what about the return data?” Yes, you’ll notice the shellcode doesn’t do anything with the return data, but that’s not to say you can’t write code that’ll take the information out of RAX/EAX and write it to some arbitrary location for storage. Instead, for this example I’ll demonstrate the use of GetExitCodeThread to pick up the return information from the function.

Check out the finished code at:
To view link: Login


I want to make just one quick note about GetExitCodeThread. It’ll only return whatever was retuned LAST. So, let’s say you have multiple function calls in your shellcode, only the return from the last call, or whatever you want to return I guess, will be retrieved from GetExitCodeThread. I’ll demonstrate this too though, so no worries.
 
Last edited:
Likes: Rake

Traxin

Global Moderator
Moderator
Dank Tier VIP
Legacy Donator
Aug 3, 2015
794
289
63
#3
Function Mapping
This part will walk you through mapping a function from your module to the target process and doing all of the work in there. This is rather nice, because you can continue writing your code in C++ and don’t have to deal with shellcode and makes the process of dealing with return information much easier.

First things first, we need to set up a function pointer, and the function we'll be mapping to our target. We'll also create a "Marker" function right after the mapped function which will serve a kind of a bookmark that we can use to calculate the size of the mapped function (not perfect but it works, and this is why we needed to disable optimizations in the invoker as well).



Looking at MappedFunc you’ll notice we call Function4 twice. I do this to demonstrate both methods of getting return information and the behavior of each. Notice we fill the final variable in our struct, c, with the return info from the first call, and we don’t do anything with the return info of the second. You’ll see how GetExitCodeThread will only return the data from the last call, but we can still retrieve the info from the first call if we save it to some arbitrary location and then later read from it.

The next step is the same as always, allocate space, write the necessary information to the process, create your thread, yada yada yada.

To view link: Login


Calling Member Functions
If you’ve made it this far, you can probably guess what we’re going to be doing so I’ll just glare over it really quickly. We should all know by now that member functions are a tad different then regular functions. When there’s an object of whatever type of class and you invoke one of its functions, the RCX/ECX register is populated with the “this” pointer, basically the address of the object.

What’s usually done in internal cheats is you’ll either typedef a function pointer or with modern C++ the syntax is much nicer.

C++:
using _MemberFunc = void __thiscall(void* pThis);
So what we’ll do is create a struct that mimics the
To view link: Login
and encapsulates the function stuff. Hopefully you guessed correctly but we’ll be using code mapping or function mapping again to handle all of our actual function calling.


(There is a MarkerFunc2, it's just not in the screenshot.)

And the rest is pretty much the same as demonstrated in previous sections.
To view link: Login


And we're done with CRT. Let's get some hooker action going ;)

Via Hooking & Code Injection
If you are unfamiliar with the concept of hooking, now would be a good time to get acquainted. We’ll be using a simple, straight-forward, mid-function hook. Instead of using CRT to invoke the function we’re interested in calling, we’ll simply detour execution somewhere and have the program execute some code we inject. This code that we’ll be injecting will be responsible for invoking the function we’re interested in.

There are a couple of things we need to keep in mind when we’re using this technique. Since we are hooking a function while it’s executing, we need to A) we need to make sure we replicate any code we overwrite and B) make sure to save and restore the registers and flags. Failing to do either of these can cause your target to crash.

So, for x86 the process is relatively straight forward. It’s just setting up some byte/shell code and using the usual techniques of allocating memory and just placing the hook.

For x64 you just need to keep in mind that a regular 5 byte relative jmp instruction is limited to a 4GB address space so we need to allocate our memory buffer close to the location we’ll be hooking.

Depending on what architecture you're working on, you'll obviously be hooking in different locations.
On the x86 target I decided to hook just after the first call to GetAsyncKeyState. There are 5 bytes available, which is exactly what we need.


And for the x64 version I hooked after the second call to GAKS to avoid having to deal with that conditional jmp. Same result.


The rest of the process is very similar to the shellcode section of the tutorial.

To view link: Login


The only difference in the 64bit method is that we take into consideration where we're going to allocate memory. We want to use a 5 byte jmp, which means we're limited to basically 4GBs of addresses we can jump to. So instead of just initializing pMemory off the bat with VirtualAllocEx, we'll put it in a loop with a specified start address and look from there on and see if we allocate memory, which we will. This will put our injected code close enough to use a 5 byte relative jmp.

To view link: Login


Toggling this hook should result in Function1 getting spammed.

And that's it folks! That's pretty much every method I know or could think of that you can use to call/invoke a function in a remote process.

Let me know of any additions, corrections, clarifications, etc.
 
Last edited:

Rake

Wielder of Mjolnir
Administrator
Jan 21, 2014
4,721
1,435
113
USA
#6
 
Likes: Traxin
Advertise With GuidedHacking