Using CreateRemoteThread we can call a specific kind of function of another process. It has to be application-defined and of type LPTHREAD_START_ROUTINE.
If no such function does exist in the target process you have to inject your own and that's where I need your help.
Using VirtualAllocEx and WriteProcessMemory I would like to inject such a function as byte code. So I'd like to know, what such a function looks like in raw assembly.

  • This should help, create the project in an IDE and observe it in a debugger. – Dominik Antal Dec 15 '14 at 1:17

This question is a little too broad to answer without more information but I'll cover some general points about what I think you're looking for. I'm also going to assume x86 calling convention on Windows for simplicity's sake.

The only thing that really determines what a function "looks like" in assembly is its calling convention, but there's no restriction (particularly writing raw byte code) about what a function can do. In the case of using CreateRemoteThread the only restriction is that you don't corrupt the stack (which could crash the target process)

So for example, I could write a function in assembly that looks like this:


And it would be 100% valid. But as far as more complicated functionality let's look at the MSDN for CreateRemoteThread:

LPTHREAD_START_ROUTINE is a #define to the following function definition:

  _In_  LPVOID lpParameter

Where WINAPI is another #define to the stdcall calling convention. You can check the wiki for it here but the important part (if you're writing raw assembly") is that for WINAPI/stdcall functions the callee function cleans up the stack, which means the function that you write which runs in the remote process will have to cleanup its parameter(s). This is done with the ret N set of instructions. For example, if you have:

WINAPI foo(int x)

Then the foo will have to clean up one parameter on the stack, so the assembly for this function will end with a ret 4 instruction, because there was one parameter which means 4 bytes need to be cleaned up on the stack.

Similarly, if you had:

WINAPI bar(int x, int y)

Then the assembly will end with a ret 8 instruction, because there are 2 parameters = 8 bytes now. It's also important to note that if I had something like:

WINAPI foobar(char x, char y, int z)

It will still end in a ret 0C. Even though the char params only have one byte of data the stack will still be aligned in 4 byte increments.

Going back to the API for CreateRemoteThread you can see that one of the paremeters is

LPVOID lpParameter

Which is the pointer that gets passed a parameter to your remote function. This means that in your "remote" function you'd have to clean up one parameter on the stack using a ret 4 instruction. If you perform some tricks you can write your WINAPI function in C code, have the compiler compile it for you (makes it easier to code and you don't have to worry about cleanup yourself), and find the function at run time to copy it off.

| improve this answer | |
  • Thank you, this was very helpful. So, am I correct, that the function may look like this? pastebin.com/rz4cep7f Also, can you give me an advice on were to learn the basics about raw assembly? It seems to be quite different from inline assembly and the assembly returned by assembly.ynh.io – Forivin Dec 15 '14 at 16:49
  • I'm also wondering if I need a near or far return. x86.renejeschke.de/html/file_module_x86_id_280.html – Forivin Dec 15 '14 at 18:49
  • Near return. Far returns are only used to switch between segments, which in modern OS isn't something you (usually) have to worry about in userspace. Also, in your assembly you're popping the parameter to ECX, which means when you do the RET 4 at the end you will had incremented the stack by one DWORD too many. Instead of a pop you would want to do something like mov ecx,[esp] – Fewmitz Dec 15 '14 at 19:42
  • As far as learning Assembly, the best source is really going to be stepping through functions in a debugger. The more you see how contructs, the stack, etc are laid out when you write code an functions the more obvious it will become. The link you put in your comment is in AT&T format which is different than what you have in the pastebin. Both formats result in the same execution but they're displayed differently. If you attach Windbg and debug your assembly that way it will be in Intel format which may clear up some confusion – Fewmitz Dec 15 '14 at 19:44
  • Though it might also be helpful to check out a book like Practical Malware Analysis; by reverse engineering some stuff you'll get used to looking at assembly and therefore have a better understanding of what it should look like if you write it – Fewmitz Dec 15 '14 at 19:50

Not the answer you're looking for? Browse other questions tagged or ask your own question.