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

В массив byte записать DWORD


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

Здравствуйте! Потихоньку пишу и оптимизирую трейнер и возник вопрос:

1) Корректно ли писать так:

DWORD jmpAddress = 0;
byte *bytes = new byte[20];
jmpAddress = allocAddress - (baseAddress + offsetAddress[0]) - 5; 
...
memcpy((void*)&(*(bytes+1)), &jmpAddress, 4);

2) Я сократил количество кода заменив memcpy на такое выражение

Цитата

(DWORD&)((*(bytes + 1))) = allocAddress - (baseAddress + offsetAddress[0]) - 5;

Как с точки зрения "Чистого кода" можно так делать?

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

Не очень понимаю, зачем массив байт делать указателем - он типа и так указатель уже. Я обычно просто 0-й байт присваивал опкоду jmp\call, а остальные 4 (8) - нужному адресу. И все.

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

void *DetourFunc(BYTE *src, const BYTE *dst, const int len)
{
	BYTE *jmp = (BYTE*)malloc(len + 5); // Выделяем памяти в длину кода len + 5 байт на прыжок
	DWORD dwback; // Переменная для сохранения флагов защиты
	VirtualProtect(src, len, PAGE_READWRITE, &dwback); // Ставим защиту нужного участка кода в RW
	memcpy(jmp, src, len);	jmp += len; // Копируем код в выделенную память + занимаем место под прыжок
	jmp[0] = 0xE9; // 0-й байт - опкод JMP
	*(DWORD*)(jmp + 1) = (DWORD)(src + len - jmp) - 5; // Записываем в выделенную память код (с 1-го байта, учитывая занятые под прыжок и адрес 5 байт)
	src[0] = 0xE9;
	*(DWORD*)(src + 1) = (DWORD)(dst - src) - 5;
	VirtualProtect(src, len, dwback, &dwback);
	return (jmp - len);
}

 

 

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

Цитата

Не очень понимаю, зачем массив байт делать указателем

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

byte *bytes = new byte[20];

а вот так 

byte *bytes = new byte[jmpBackAddressSize[0]];

если делать не указателем, то так нельзя сделать:

byte bytes[jmpBackAddressSize[0]];

 

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

В общем, как видишь, в моем примере принцип копирования примерно тот же, так что он явно имеет право на жизнь. Каноничнее, конечно, воспользоваться memcpy, но у нее есть два недостатка - она медленная и она медленная. С другой стороны, обычно подобные операции проводятся один раз в рамках игровой сессии, так что можно и подзабить. В-третьих, маньяков вроде меня, считающих байты кода и такты процессора - крайне мало, так что я бы советовал лишний раз не заморачиваться. Плюс в таком подходе один (помимо скорости) - резко возрастает понимание того, что делаешь.

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

keng

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

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

@helldrg это ручное создание хуков, аля Microsoft Detours. Имеем на входе два адреса - адрес исходной функции и адрес конечной (хука). Выделяем 5 байт. Копируем начало функции из исходной в выделенные 5 байт. Дальше в 0-й байт выделенной памяти записываем опкод JMP. После этого рассчитываем, на сколько байт нам нужно прыгнуть, а в начало исходной функции записываем такой же массив вида "JMP *выделенные_5_байт*". Итого:

 

Было:

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

void Blah() {
    ololo; // Какой-то код
    return;
}

 

 

Стало:

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

void Hook() { // Наш хук
    ololo; // Сохраненный код, который мы затерли прыжком сюда
    jmp *ret_from_hook* // Выход на место сразу после перехода на хук в Blah()
}

void Blah() {
    jmp Hook // Переход на хук
    *ret_from_hook* // Blah + 5 байт, сюда вернемся
    return;
}

 

Типа того. Нужно просто несколько раз в отладчике посмотреть, чтобы понять, как это работает. Отладчик - твой друг! Я сам дня 2-3 ломал голову, когда писал это все. :)

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

keng

Я попытался осмыслить, но, надо в отладчик лезть) Сегодня уж попытаюсь доделать трейнер на с++ и winapi, выложу, и почитаю про с++ и xaml, что бы сделать трейнер в стиле metro и баи) А завтра уже попробую в DetourFunc вникнуть

А пока у меня такое представление: для всего этого нужно:
1) адрес, где будет производится переход на нужный нам код (baseAddress + offsetAddress) адрес модуля и смещения в нем
2) размер кода перехода jmpSrcAddressSize - в него входит 5 байт для перехода и нопы, в случае необходимости
3) размер кода для которого мы выделили память jmpDestAddressSize туда входит код и 5 байт для перехода

4) массив байт с кодом который мы записываем  new byte[jmpDestAddressSize] там находится код вместе с переходом

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

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

bytes[0] = '\xe9';
(DWORD&)((*(bytes + 1))) = allocAddress - (baseAddress + offsetAddress[0]) - 5;
bytes[5] = '\x90';
bytes[6] = '\x90';
 bytes[7] = '\x90';
bytes[8] = '\x90';
bytes[9] = '\x90';
bytes[10] = '\x90';
if (Process.WriteMemory(baseAddress + offsetAddress[0], (LPVOID)bytes, jmpSrcAddressSize[0]) == FALSE)
                        wsprintf(buffer, "Ошибка!");

 

и надо рассчитать адрес возвращения

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

jmpAddress = (baseAddress + offsetAddress[0]) - allocAddress - 10 + jmpSrcAddressSize[0];
                    memcpy((void*)bAddres, &jmpAddress, 4);
                    bytes[0] = '\x83';    bytes[1] = '\x7f';    bytes[2] = '\x08';    bytes[3] = '\x02';
                    bytes[4] = '\x0f';    bytes[5] = '\x84';    bytes[6] = bAddres[0];    bytes[7] = bAddres[1];    bytes[8] = bAddres[2];    bytes[9] = bAddres[3];
                    jmpAddress = (baseAddress + offsetAddress[0]) - allocAddress - jmpDestkAddressSize[0] + jmpSrcAddressSize[0];
                    memcpy((void*)bAddres, &jmpAddress, 4);
                    bytes[10] = '\x89';    bytes[11] = '\x47';    bytes[12] = '\x04';
                    bytes[13] = '\xc7';    bytes[14] = '\x44';    bytes[15] = '\x24';    bytes[16] = '\x74';    bytes[17] = '\xff';    bytes[18] = '\xff';    bytes[19] = '\xff';    bytes[20] = '\xff';
                    bytes[21] = '\xe9';    bytes[22] = bAddres[0];    bytes[23] = bAddres[1];    bytes[24] = bAddres[2];    bytes[25] = bAddres[3];
                    if (Process.WriteMemory(allocAddress, (LPVOID)bytes, jmpDestkAddressSize[0]) == FALSE)
                        wsprintf(buffer, "Ошибка!");

 

в первой строчке минус 10, потому что в коде находится 2 джампа,1 проверочный, если требования не выполняются то раньше возвращаемся в программу

И вот это все применить к DetourFunc, меня просто в ужас бросает, надеюсь отладчик поможет =)

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

Учти, что мой код - в dll, так что я нахожусь в одном адресном пространстве с игрой. Следовательно, мне нужно просто рассчитать два смещения - туда и обратно. И все. Извне делать такие штуки тоже можно, но на пару действий больше понадобится.

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

я бы сделал примерно так

static BYTE bytes[] = {0xE8,0x00,0x00,0x00,0x00,0x90};
DWORD temp = baseAddress-offsetAddress-5;
memcpy(&bytes[1],&temp ,sizeof temp );

компиль всеравно memcpy заменит на 1-2 инстр.

 

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

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

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

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