Перейти к содержанию

C# преобразование команд asm в байты


Рекомендуемые сообщения

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

Дело вот в чем, есть команда

CALL gta-vc.exe +  AE8F0            ||              call 004AE8F0                ||             E8 DD E8 0D 00

Взаимосвязь между командой и байтами я не вижу, как ни крути... Как понял E8 - равносильно команде call,

тогда как упаковать мой адрес в эти байты?

 

 

Вот мой кодец  

Скрытый текст

            int iProcessId = 1480;
            Process proc = Process.GetProcessById(iProcessId);

            IntPtr hHandle = OpenProcess(ProcessAccessFlags.All, false, iProcessId);
            int ptr_base = (int)proc.MainModule.BaseAddress;

            byte[] asm = new byte[] {
            0x68, 0xB1, 0x00, 0x00, 0x00 , //          - push 000000B1 { 177 }
            0xE8, 0xE6, 0xE8, 0x5D, 0xFF,  //          - call gta-vc.exe+AE8F0
            0x59,                          //          - pop ecx
            0xC3                           //          - ret 
};

нашел базовый адрес модуля игры (если ошибаюсь, поправьте) 

Собственно, как записать адрес я затрудняюсь.... 
Подскажите пожалуйста, на сколько мне подсказали, то что я ищу: 

ptr_base + 0xAE8F0  + 5 //Как это можно записать в код? 

Действительно ли нужен отступ именно на 5? Как преобразовать это в байты?

 

 

Ссылка на комментарий
Поделиться на другие сайты

Может проще будет написать дллку на C++ добавить функцию как экспортируемую, и запускать из под C# после импорта? Просто .Net по своей природе не предназначен использовать asm, так что это то ещё извращение.

 

5 часов назад, Trix сказал:

0xE8, 0xE6, 0xE8, 0x5D, 0xFF

 

А вот это уже хрень какая-то, выходит ты вызываешь ff5de8eb по твоим опкодам, а должен вызывать вроде как физический адрес и программа сама рассчитает положение функции(вроде так называется, если нет прошу поправить, чтобы не создавать путницы), т.е тут должно быть:

 

byte[] asm = new byte[] {
            0x68, 0xB1, 0x00, 0x00, 0x00 , //          - push 000000B1 { 177 }
            0xE8, 0xDD, 0xE8, 0x0D, 0x00,  //          - call gta-vc.exe+AE8F0
            0x59,                          //          - pop ecx
            0xC3                           //          - ret 

 

А так все верно и мне кажется должно заработать, если у тебя дллка и она инжектируется в процесс, иначе ты будешь вызывать по этим опкодам функцию внутри своей программы и тогда возможен краш.

 

Но это не точно, т.к не писал на C# и не знаю всех тонкостей.

Изменено пользователем partoftheworlD
Ссылка на комментарий
Поделиться на другие сайты

Ну чувак... блин. Че за фигня?

На C++ это выглядело бы примерно так:

BYTE call[] = { 0xE8, 0x00, 0x00, 0x00, 0x00,   /* call relative address */
                0xC3 };                         /* ret */

// VirtualAllocEx 
LPVOID pAlloc = VirtualAlloc( NULL, sizeof( call ), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );

if( pAlloc != NULL )
{
	// Патчим наш адрес
	*(DWORD*)( call + 1 ) = (DWORD) foo - ( (DWORD) pAlloc + 5 );

	// Тут заменить на WriteProcessMemory
	memcpy( pAlloc, call, sizeof( call ) );

	CreateThread( NULL, NULL, (LPTHREAD_START_ROUTINE) pAlloc, NULL, NULL, NULL );

	VirtualFree( pAlloc, NULL, MEM_RELEASE );
}

В моем случае foo это просто тестовая функция. Код проверил, все работает. Удачи.

Изменено пользователем uhx
Ссылка на комментарий
Поделиться на другие сайты

13 минуты назад, uhx сказал:

В моем случае foo это просто тестовая функция. Код проверил, все работает. Удачи.

:offtopic:

Почему бы не сделать так? Или твой вариант не использует инжект и проделывает все это как внешний чит?

 

typedef void(*Spawner)(dword);

auto *AnyFunction = reinterpret_cast<Spawner>(address);

void main()
{
	AnyFunction(A2);
}

BOOL APIENTRY DllMain(HMODULE hmodule, DWORD reason, LPVOID lpReserved)
{
	switch (reason)
	{
	case DLL_PROCESS_ATTACH:
		CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(main), hmodule, 0, 0);
		break;
....

 

Изменено пользователем partoftheworlD
Ссылка на комментарий
Поделиться на другие сайты

15 минут назад, partoftheworlD сказал:

Почему бы не сделать так? Или твой вариант не использует инжект и проделывает все это как внешний чит?

Дык этот чувак пишет на шарпе, и у него там "как внешний чит".

Он вообще из этой темы пришел:

Поэтому я по его подобию сделал, как у него там примерно. Так то ясен фиг проще дллку закинуть и через нее вызывать, чем внедрять опкоды и выполнять их через CreateRemoteThread

Изменено пользователем uhx
Ссылка на комментарий
Поделиться на другие сайты

Одно дело - смотреть опкоды в дизассемблере, другое - в отладчике, когда он уже загружен в память. Во втором случае все переходы и смещения уже пересчитаны относительно базового адреса, по которому загрузился исполняемый модуль. В первом - нет. Итого:

 

gta-vc.exe +  AE8F0 - тот адрес, что тебе показывает отладчик.

004AE8F0 - куда будем прыгнем по факту. Тут 400000 - базовый адрес.

E8 DD E8 0D 00 - опкоды из отладчика. E8 - это call, причем относительный, значит прыгать мы будем на 000DE8DD байт вперед (вниз по коду).

 

В общем, посмотри, по какому адресу загрузился gta-vc.exe. Скорее всего, если из этого адреса вычесть 000DE8DD, то получится 000F0E8A.

Ссылка на комментарий
Поделиться на другие сайты

2 часа назад, keng сказал:

Одно дело - смотреть опкоды в дизассемблере, другое - в отладчике, когда он уже загружен в память. Во втором случае все переходы и смещения уже пересчитаны относительно базового адреса, по которому загрузился исполняемый модуль. В первом - нет. Итого:

 

gta-vc.exe +  AE8F0 - тот адрес, что тебе показывает отладчик.

004AE8F0 - куда будем прыгнем по факту. Тут 400000 - базовый адрес.

E8 DD E8 0D 00 - опкоды из отладчика. E8 - это call, причем относительный, значит прыгать мы будем на 000DE8DD байт вперед (вниз по коду).

 

В общем, посмотри, по какому адресу загрузился gta-vc.exe. Скорее всего, если из этого адреса вычесть 000DE8DD, то получится 000F0E8A.

Окей, Кенг, я примерно понял, поковыерялся, дошло что это действительно относительный адрес.. 

Правда, как его вычислить ух, это непонятно 

 У меня есть следующие значения 

Смещение на функцию, Базовый адрес, Адрес инъекции, как мне с этим всем можно узнать последующие байты после call?

Ссылка на комментарий
Поделиться на другие сайты

Окей, нашлось решение, всем спасибо за участие, если кому-то остался актуален этот вопрос, то вот решение 

jmp - E8, а адрес вычисляется по следующей инструкции:

Нужный адрес(в моем случае gta-vc.exe+AE8F0  - адрес инъекции, куда поместили байты -  5 (место на jmp(1байт) + адрес(4байта))

 

В принципе, пришел к выводу, что как команда call, так и jmp относительна)) 

Всем еще раз спасибо ^_^

Ссылка на комментарий
Поделиться на другие сайты

15 minutes ago, Trix said:

Окей, нашлось решение, всем спасибо за участие, если кому-то остался актуален этот вопрос, то вот решение 

jmp - E8, а адрес вычисляется по следующей инструкции:

Нужный адрес(в моем случае gta-vc.exe+AE8F0  - адрес инъекции, куда поместили байты -  5 (место на jmp(1байт) + адрес(4байта))

 

В принципе, пришел к выводу, что как команда call, так и jmp относительна)) 

Всем еще раз спасибо ^_^

call - это push + jmp в одном флаконе. На стеке сохраняется адрес возврата.

Ссылка на комментарий
Поделиться на другие сайты

22 часа назад, Trix сказал:

Окей, нашлось решение, всем спасибо за участие, если кому-то остался актуален этот вопрос, то вот решение 

jmp - E8, а адрес вычисляется по следующей инструкции:

Нужный адрес(в моем случае gta-vc.exe+AE8F0  - адрес инъекции, куда поместили байты -  5 (место на jmp(1байт) + адрес(4байта))

 

В принципе, пришел к выводу, что как команда call, так и jmp относительна)) 

Всем еще раз спасибо ^_^

Так я тебе про это две темы затирал)

 

В 05.05.2017 в 03:40, uhx сказал:

На C++ это выглядело бы примерно так:


BYTE call[] = { 0xE8, 0x00, 0x00, 0x00, 0x00,   /* call relative address */
                0xC3 };                         /* ret */

// VirtualAllocEx 
LPVOID pAlloc = VirtualAlloc( NULL, sizeof( call ), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );

if( pAlloc != NULL )
{
	// Патчим наш адрес
	*(DWORD*)( call + 1 ) = (DWORD) foo - ( (DWORD) pAlloc + 5 );

	// Тут заменить на WriteProcessMemory
	memcpy( pAlloc, call, sizeof( call ) );

	CreateThread( NULL, NULL, (LPTHREAD_START_ROUTINE) pAlloc, NULL, NULL, NULL );

	VirtualFree( pAlloc, NULL, MEM_RELEASE );
}

В моем случае foo это просто тестовая функция. Код проверил, все работает. Удачи.

А это тебе не помогло? Хоть и на плюсах, но принцип тот же. Формула для расчета адреса ведь есть. Я думал после этого хоть понятно станет...

Ссылка на комментарий
Поделиться на другие сайты

В 06.05.2017 в 13:35, uhx сказал:

Так я тебе про это две темы затирал)

 

А это тебе не помогло? Хоть и на плюсах, но принцип тот же. Формула для расчета адреса ведь есть. Я думал после этого хоть понятно станет...

Ну, видишь, я отличаюсь интеллектом. В плане доходит оч. долго:wacko:

Первым делом обратил внимание на ассемблерную команду, а потом на байт-код, поэтому и сбился, но зато запомнится 

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.