Как я могу запустить код операции ASM в строковой переменной или преобразовать его в байты? - PullRequest
4 голосов
/ 29 февраля 2020

У меня есть этот фрагмент кода asm в строковом атрибуте :

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

, прежде чем попасть в то, чего я пытаюсь достичь, сначала я изменю клиента. dll + ... в его окончательный адрес, конечно.

Теперь то, что я сейчас пытаюсь достичь, это либо:

  • Конвертировать этот фрагмент кода asm в эквивалентных байтах , чтобы я мог записать эти байты в память после их изменения с помощью winapi ..

  • Или как-то записать содержимое строки в выделенной памяти, что кажется невозможным без преобразования его в байты .. idk

Я не знаю, возможно ли это или нет, но у меня тоже есть эта идея :

  • создайте dll в c ++, которая будет иметь функцию, которая может быть импортирована из моего c# приложения
  • , используя любые возможные способы достижения моей цели, передав асм код операции и выделенный адрес памяти в качестве параметров (не эксперт C ++), но я знаю, что встроенный asm возможен в c ++.

Имейте в виду, что код ASM, приведенный в этом посте, просто для демонстрации того, что я пытаюсь сделать, на самом деле он сильно изменится, надеюсь, вы получите идея.

Ответы [ 3 ]

2 голосов
/ 03 марта 2020

Используйте Keystone C# bindings , чтобы преобразовать вашу сборку в байты. Он очень прост в использовании, вы даете ему строку, и он дает вам массив байтов, которые представляют код сборки, который вы дали для ввода:

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);
}

Чтобы преобразовать скрипт Cheat Engine Code Injection в C# код, вы хотите сделать внешний обход. Используйте VirtualAllocateEx(), чтобы освободить место в целевом процессе, запишите свой код оболочки, который вы создали с помощью KeyStone, в память, используя WriteProcessMemory, затем выполните обход, чтобы обойти поток выполнения с введенным вами шелл-кодом.

Вам понадобится разрешить относительные переходы и все относительные адреса вручную в функции обхода.

В качестве альтернативы вы можете использовать CreateRemoteThread() для выполнения кода в целевом процессе в новом потоке, а не через обход, в зависимости от того, что вы хотите сделать .

1 голос
/ 01 марта 2020

Это далеко от вашей полной проблемы (C# ...), но это может дать вам некоторые подсказки.

Этот пример сделан в C с g cc на Linux - 64; вам, возможно, придется адаптировать его на вашей платформе.

Первым шагом было написать функцию с некоторой встроенной сборкой (синтаксис gnu-asm), чтобы увидеть, как она выглядит с objdump (на самом деле он никогда не вызывается) .
Здесь был найден трюк для перехода к постоянному адресу: { ссылка }

После этого мы должны создать исполняемый сегмент памяти и заполните его байтами, вдохновленными предыдущей функцией (благодаря objdump).
Если единственное, что можно изменить, это адрес, то мы просто перезаписываем этот адрес в предыдущем коде.
В этом примере адрес другой функции используется для этой цели.

Тогда этот исполняемый сегмент памяти можно рассматривать как функцию (гуд ... надеюсь), и мы используем его через указатель на функцию.
И, похоже, работа!

Единственная проблема, которую я вижу, это инструкция movb $0xff,0xa(%ecx,%ebx,4), которая делает что-то плохое, потому что я не знаю точно, что должны содержать регистры.
Я решил замените эту инструкцию на шесть nop, чтобы занять то же место и сохранить этот пример аналогичным исходной задаче.
(я полагаю, что в контексте вашей проблемы эти регистры будут иметь соответствующее значение).

/**
  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;
}
1 голос
/ 01 марта 2020

Если вы используете c#, я предлагаю вам использовать обертки для записи памяти процесса и импортировать необходимые библиотеки и т. Д. c, получать необработанные байты ваших кодов операций asm и манипулировать ими по своему усмотрению

если вы используете c ++, вы можете просто использовать функции без необходимости извлекать обертки и т.д .; большинство функций есть в C ++ libs

, если вы ищете что-то вроде читерного кодового движка (Aob инъекция с помощью прыжка и возврата), вы можете потратить некоторое время на изучение кое-чего о манипулировании памятью / распределении памяти / как В общем, работа asm, после этого вы можете просто без проблем связываться с памятью

также для внутренних библиотек, использующих c ++, вам нужно использовать необработанные байты, если я правильно помню, они удалили функциональность asm для кодовых кодов и тому подобного из Visual Studio 2010 и ограничил его только корпоративной версией или чем-то

также, если вы думаете об использовании этого кода операции как jmp client.dll+3A8D96, что было бы очень плохой идеей, если вы знаете asm, если его прыжок в ближнем бою не большое дело, но эти смещения могут время от времени меняться

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

это всего лишь пример того, как я использую байты для своих кодов, на youtube есть несколько хороших руководств, вы должны их проверить

...