How can i run ASM opcode in a string variable Or convert it to bytes?

Viewed 1078

i have this piece of asm code in a string attribute:

mov [ecx+ebx*4+10],ff
jmp client.dll+3A8D96

before getting into what i'm trying to achieve, first i will change client.dll+... into it's final address of course.

Now what i'm currently trying to achieve is either:

  • Convert that piece of asm code into it's equivalent bytes so i can write back these bytes into memory after changing them using winapi ..

  • Or somehow write that string's content in an allocated memory , which kind of seems impossible without converting it to bytes .. idk

I dont know if possible or not but i also have got this idea:

  • make a dll in c++ that will have a function that can be imported from my c# app
  • make use of any posible ways to achieve my goal by passing the asm opcode and allocated memory adress as Parameters (not a c++ expert) but i know that inline asm is possible in c++ .

Keep in mind that the ASM code given in this post is just to demonstrate what i'm trying do, it will be actually changing a lot, i hope you get the idea.

3 Answers

Use Keystone's C# bindings to convert your assembly into bytes. It's very easy to use, you give it a string and it gives you an array of bytes that represent the assembly code you gave for input:

using Keystone;

using (Engine keystone = new Engine(Architecture.X86, Mode.X32) { ThrowOnError = true })
{
    ulong address = 0;

    keystone.ResolveSymbol += (string s, ref ulong w) =>
    {
        if (s == "_j1")
        {
            w = 0x1234abcd;
            return true;
        }

        return false;
    };

    EncodedData enc = keystone.Assemble("xor eax, eax; jmp _j1", address);

    enc.Buffer.ShouldBe(new byte[] { 0x00 });
    enc.Address.ShouldBe(address);
    enc.StatementCount.ShouldBe(3);
}

To convert a Cheat Engine Code Injection script to a C# code, you want to do external detouring. Use VirtualAllocateEx() to get space in the target process, write your shell code you created with KeyStone into memory using WriteProcessMemory, then perform your detour to detour execution flow to your shellcode you injected.

You will need to resolve relative jumps and all relative addresses manually in your detour function.

Alternatively you can use CreateRemoteThread() to execute code in the target process in a new thread rather than via a detour, depending what you want to do.

If you are using c# i suggest u use wrappers for Write process memory and Import the necessary dlls and etc and get raw bytes of your asm opcodes and manipulate them to your own accord

if you are using c++ you can just use the functions without needing to fetch the wrappers and etc; most of the functions are there in C++ libs

if you looking for something like cheat engine codecave (aob injection with a jump and jumpback) id consider u invest some time for learning somethings about memory manipulating / allocating memory / how asm work in general, after that u can just mess with memory at ease

also for internal dlls using c++ you need to use raw bytes, if i recall correctly they removed the asm functionality for codecaves and such from visual studio 2010 and restricted it only to enterprise version or something

also if you thinking about using this opcode as it is jmp client.dll+3A8D96 that would be a really bad idea if u know asm, if its a near jump its not a big deal but these offsets could change from time to time

"\xFE\xC8\x5B\x23\xC1"

this is just an example how i use bytes for my codes, there are some good tutorials on youtube you should check them out

This is far from your full problem (C#...) but it could give you some clues.

This example is done in C with gcc on Linux-64; you may have to adapt it on your platform.

The first step was to write a function with some inline assembly (gnu-asm syntax) in order to see how it looks with objdump (it is never called actually).
The trick to jump to a constant address was found here: https://stackoverflow.com/a/53876008/11527076

After that we have to create an executable memory segment and fill it with bytes inspired from the previous function (thanks to objdump).
If the only thing that may be changed is the address, then we just overwrite this address in the previous code.
In this example, the address of another function is used for this purpose.

Then this executable memory segment can be considered as a function (hum... hopefully) and we use it through a function pointer.
And it seems to work!

The only problem I can see is the instruction movb $0xff,0xa(%ecx,%ebx,4) which does something bad because I don't know exactly what the registers should contain.
I decided to replace this instruction by six nop to occupy the same place and keep this example similar to the original problem.
(I suppose that in the context of your problem these registers will have a relevant value).

/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#undef __STRICT_ANSI__ // for MAP_ANONYMOUS
#include <sys/mman.h>

#include <stdio.h>
#include <string.h>
#include <stddef.h>

void
target_function(void)
{
  printf("~~~~ %s ~~~~\n", __func__);
}

void
inline_asm_example(void)
{
  __asm__ __volatile__(
    "\tnop\n"
    "\tmovb   $0xff,0xa(%ecx,%ebx,4)\n"
    "\tjmpq   *0x0(%rip)\n"
    ".quad 0xAA00BB11CC22DD33\n");
  // the jump relative to rip is inspired from
  // https://stackoverflow.com/a/53876008/11527076
}

int
main(void)
{
  // create an executable page
  void *page=mmap(NULL, 6+6+8,
                  PROT_READ|PROT_WRITE|PROT_EXEC,
                  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  if(page==MAP_FAILED)
  {
    fprintf(stderr, "cannot allocate memory page\n");
    return 1;
  }

  // initialise code pattern
  //   objdump --disassemble=inline_asm_example prog
  char *code_pattern=(char *)page;
#if 0 // this instruction causes something wrong
  memcpy(code_pattern+0,
    "\x67\xc6\x44\x99\x0a\xff", 6); // movb   $0xff, 10(%ecx,%ebx,4)
#else // use some useless instructions instead
  memcpy(code_pattern+0,
    "\x90\x90\x90\x90\x90\x90", 6); // 6x nop
#endif
  memcpy(code_pattern+6,
    "\xff\x25\x00\x00\x00\x00", 6); // jmpq   *0x0(%rip)

  // insert into the pattern the address we want to jump to
  ptrdiff_t target_address=(ptrdiff_t)target_function;
  memcpy(code_pattern+6+6, &target_address, sizeof(target_address));

  // consider the code pattern as a function
  void (*fnct_ptr)(void)=NULL;
  memcpy(&fnct_ptr, &code_pattern, sizeof(code_pattern));

  // here we go
  printf("about to do something I will probably regret...\n");
  fnct_ptr();
  printf("ah? it was not so painful after all!\n");

  // let's forget everything about that
  munmap(code_pattern, 6+6+8);
  return 0;
}
Related