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

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

Добрый день. 

Вот в этой теме мне ответил Keng по поводу инъекции кода, а точнее её переноса на с++.

Вот цитатка:

0. Получаем все нужные права через OpenProcess и VirtualProtectEx.

1. Выделяем себе кусок памяти в адресном пространстве игры через VirtualAllocEx.

2. Через WriteProcessMemory записываем в него код инъекции (в 16-ричной системе счисления. На конце - jmp. Все ассемблерные команды - в опкодах, т.е. как бы после компиляции).

3. Берем адрес для инъекции. Берем место, куда записали код. Нам нужно сделать относительный прыжок, верно? Отнимаем один адрес из другого. Все время путаю, какой откуда, но это можно проверить в отладчике. 

4. Разворачиваем задом наперед этот адрес (в 16-ричном представлении!), сохраняем куда-нибудь.

5. Берем адрес, куда записали код инъекции + длину инъекции в байтах + 4. Отнимаем этот адрес из адреса для инъекции + еще пять байт. Потому что сначала мы прыгаем из игры в наш код, а потом из нашего кода обратно в игровой. +5, чтобы не прыгнуть на то место, с которого прыгали изначально - прыгать нужно _после_ этого места.

6. Записываем через тот же WriteProcessMemory адрес в конец кода инъекции (чтобы было jmp + адрес).

7. Записываем в место инъеции "jmp + смещение для кода инъекции + nop".

8. Готово!

 

0. Ok...

1. Oook...

Я не совсем понимаю, что делает VirtualAllocEx. Он берет процесс, переходит по адресу, задает размер, выделяет память...

Но как узнать адрес выделенной памяти?

Я пытался провести "опыты" на notepad.exe (я криминален), взял произвольный адрес, и алокнул 16 байт. 

Знаете? Ничего не произошло с этим адресом (тот, который я взял). Я наблюдал через СЕ за этим регионом.

Может быть алокнулось где-то еще, но где?

2. Ooook...

 

 

Через WriteProcessMemory записываем в него код инъекции (в 16-ричной системе счисления. На конце - jmp. Все ассемблерные команды - в опкодах, т.е. как бы после компиляции).

Ooook, записываем... В кого в него? В адрес выделеной памяти? Ладно, а как в него записать что-то? Всмысле, асемблерные инструкции через WPM, как занести? На конце jmp чтобы вернуться на оригинальный адресс+5 (это затерли мы под прыжок).

3. Ладненько

 

 

3. Берем адрес для инъекции. Берем место, куда записали код. Нам нужно сделать относительный прыжок, верно? Отнимаем один адрес из другого. Все время путаю, какой откуда, но это можно проверить в отладчике. 

Берем адресс для инъекции? Т.е. исходный адрес? Ок, взяли. Алоченая память? Взяли. Какой относительный прыжок?

Что из чего отнимаем? И самое главное: зачем?

4. Поехали

 

 

4. Разворачиваем задом наперед этот адрес (в 16-ричном представлении!), сохраняем куда-нибудь.

Разворачиваем? Это как? Было 0x123456 а станет 0x654321 ? 

5. Стартуем

 

 

5. Берем адрес, куда записали код инъекции + длину инъекции в байтах + 4. Отнимаем этот адрес из адреса для инъекции + еще пять байт. Потому что сначала мы прыгаем из игры в наш код, а потом из нашего кода обратно в игровой. +5, чтобы не прыгнуть на то место, с которого прыгали изначально - прыгать нужно _после_ этого места.

Алокнутый адрес? Взяли. + что? Длинну инъекции? Тоесть... Ах, ну да. Насколько жирная наша инъекция. Только тут нюансик: общий жир выделенной памяти или жир только наших инструкций? Если жир наших инструкций, то как их определить? (всмысле, сколько байт мы занимаем)? +4. Зачем отнимать? Смысл? 

6. Ok

 

 

6. Записываем через тот же WriteProcessMemory адрес в конец кода инъекции (чтобы было jmp + адрес).

Тут вопросов нет. Как я понял, мы записываем прыжок на оригинальный адрес + 5 (последствия прыжка), чтобы оригинальный игровой код выполнялся как ни в чем не бывало.

7. Ok

 

 

7. Записываем в место инъеции "jmp + смещение для кода инъекции + nop".

Вот тут не понятно. Зачем записывать это? "в место инъекции" тоесть в алокнутую память? 

8. Единственный, пожалуй, шаг - по которому нет вопросов :D

 

P.s. пытаюсь писать код сам и сам же понимать его смысл. Выходит пока что на 20-30% ))

void Memoria(char Process[], int addr) //просто не знаю пока что передавать{	DWORD oldProtect = 0; 	DWORD pID = GetProcessByName(Process); //получаем процесс из шапке	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID); //открываем	VirtualProtectEx(hProc, (LPVOID)addr, (size_t)size, PAGE_EXECUTE_READWRITE, &oldProtect); //снимаем защиту	....... //do somethink	CloseHandle(hProc); //закрываем хендл}
void Memoria(char Process[], int addr) //просто не знаю пока что передавать{	DWORD oldProtect = 0; 	DWORD pID = GetProcessByName(Process); //получаем процесс из шапке	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID); //открываем	VirtualProtectEx(hProc, (LPVOID)addr, (size_t)size, PAGE_EXECUTE_READWRITE, &oldProtect); //снимаем защиту        VirtualAllocEx(hProc, (LPVOID)addr, (size_t)size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);	....... //do somethink	CloseHandle(hProc); //закрываем хендл} 
Изменено пользователем RockHamer
Ссылка на комментарий
Поделиться на другие сайты

VirtualAllocEx возвращает адрес выделенной памяти. Тебе нужно присвоить его какой-нибудь переменной

Да, в адрес выделенной памяти записать. Записать опкоды, как выше писал кенг.

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

VirtualAllocEx возвращает адрес выделенной памяти. Тебе нужно присвоить его какой-нибудь переменной

Угу... Значит, вот так?

DWORD NewMemka = VirtualAllocEx(hProc, (LPVOID)addr, (size_t)size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

Тут всё правильно?

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

Чего ж ты до этого момента терпел с вопросами, если не понял, как оно работает? Давай на примере посмотрим. Есть у тебя вот такой участок игрового кода:

 

0x100: nop

0x101: nop

0x102: nop

0x103: nop

0x104: nop

 

1 инструкция nop = опкод 0x90 = 1 байт памяти. Итого 5 байт. Нам нужно сделать так, чтобы игра, дойдя до адреса 0x100, выполнила наш код, длина которого больше 5 байт, а затем вернулась обратно. Как это сделать? Прежде всего, нужно куда-то записать код, который наш, чтобы игра могла его выполнить. Для этого нужно выделить участок памяти. Допустим, что длина нашего кода будет 10 байт. Дальше я буду писать в псевдокоде:

 

allocated_mem = VIrtualAllocEx(10)

 

После выполнения видим, что allocated_mem присвоилось значение 0x110. Это для примера. Итого получаем:

 

0x100: nop

0x101: nop

0x102: nop

0x103: nop

0x104: nop

...

0x110: <- отсюда лежит 10 байт выделенной нам памяти, в которую мы можем писать

0x111

0x112

0x113

0x114

0x115

0x116

0x117

0x118

0x119

 

Так, память выделили, теперь нужно научить игру переходить на нужный нам адрес. Для этого нам понадобится команда безусловного перехода - jmp. Она прыгает на относительный адрес, а не на абсолютный. Показываю, опять же, на примере:

 

0x10: my_code

...

0x15: jmp my_code

 

Вместо "my_code" по адресу 0x15 подставится -5. То есть на пять байт выше относительно текущего адреса (15-5 = 10). Прыжки вниз по коду - то есть вперед - прибавляют нужное смещение от текущего адреса. Смотрим еще раз на код игры и выделенную память. Код игры - 0x100, выделенная память - 0x110. То есть нам нужно прыгнуть ниже по коду, а значит вместо игрового кода по адресу 0x100 записать:

 

0x100: jmp 10

 

То есть на 0x110, на 10 байт вперед. Итого управление передастся на наш код, но нам нужно будет вернуться обратно. Чтобы вернуться обратно, нам понадобится еще один jmp и адрес, куда прыгать. Опкод команды jmp занимает 1 байт, адрес - 4 байта, итого 5. Так что для нашего кода нам остается 5 байт, ибо всего у нас их 10. То есть в выделенной памяти по адресу 0x115 нам нужно записать "jmp адрес", где адресом будет игровой код, откуда мы прыгнули, +5 байт. Почему +5? Вот почему:

 

Игровой код:

0x100: jmp 10

0x105: ...

 

jmp 10 занимает 5 байт. Нам нужно продолжить выполнение с команды, идущей сразу после нее, то есть 0x105. Если прыгнем опять на 0x100 - получится, что прыгнули снова на jmp 10, в итоге получится рекурсия и игра зависнет. В общем, нам нужно сделать jmp с адреса 0x115 наверх, на 0x105. Итого:

 

0x115: jmp -10

 

У нас есть адрес игрового кода (game_addr), адрес, куда нужно прыгнуть (game_addr + 5), адрес нашей выделенной памяти (allocated_mem), ее размер (10 байт) и адрес, откуда прыгать (allocated_mem + 10 - 5). Считаем, получается, что адрес, куда нужно прыгнуть, это 0x105, адрес, откуда прыгать - 0x110+10 - 5 = 0x115, вычитаем, получаем 110 - 115 = -10. Что дает нам:

 

0x100: jmp 0x110
0x105: <- сюда прыгнем обратно
...
0x110: <- сюда прыгнем из игрового кода
0x111:
0x112:
0x113:
0x114:
0x115: jmp 0x105 <- отсюда прыгнем обратно
 
И вот, у нас остается еще целых 5 байт для кода, который выполнит игра вместо своего оригинального. Берем WriteProcessMemory и записываем 5 байт по адресу нашей выделенной памяти, то есть 0x110.
 
Как вернуть все на место? Скажем, когда человек нажал кнопку, чтобы функцию трейнера отключить. У нас есть адрес игрового кода, адрес нашей выделенной памяти, и оригинальный игровой код, который мы заблаговременно сохранили перед его изменением. Алгоритм простой:
 
0. По адресу 0x100 (игрового кода) используя WriteProcessMemory записываем оригинальный игровой код.
1. Очищаем выделенную нами память через VirtualFreeEx. 
 
Вот как-то так и работает инъекция кода в Cheat Engine. Единственное, каждый вызов WriteProcessMemory лучше оборачивать в Virtual(Un)ProtectEx.

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

Чего ж ты до этого момента терпел с вопросами, если не понял, как оно работает?

Главное - дотерпеть))) 

А если серьезно - просто или времени не было... Или ноута нормального. Впринципе, сейчас тоже ноута нормального нет... И монитора... Но, думаю, смогу что-нибудь сделать на своём старом ноуте. Дал процессу студии высший приоритет, она шустрей стала. Начал разбираться в твоих инструкциях. И вот немножко призадумался)

Спасибо, постараюсь вникнуть )

 

Единственное, каждый вызов WriteProcessMemory лучше оборачивать в Virtual(Un)ProtectEx.

Это всмысле:

VirtualProtectEx(PAGE_EXECUTE_READWRITE)WriteProcessMemoryVirtualProtectEx(oldProtect) ?

Вот так?

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

Ага. Можешь посмотреть примеры использования этой функции в интернете. А если MSVS медленно работает - поставь себе mingw и не заморачивайся.
Ссылка на комментарий
Поделиться на другие сайты

Ага. Можешь посмотреть примеры использования этой функции в интернете. А если MSVS медленно работает - поставь себе mingw и не заморачивайся.
Тут даже не в этом деле) Ноут не тянет даж видео на ютубе) А что такое Mingw?
Ссылка на комментарий
Поделиться на другие сайты

MinGW - это портированный набор компиляторов GCC под Windows.

 

PS: Первым делом лучше смотреть все незнакомые слова в гугле.

Уже посмотрел, скачал... Но там только инсталятор. Никак не могу запустить саму программу, а не инсталятор.

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

Оно работает из командной строки, нужно папку c:\mingw\bin\ положить в переменную PATH, а потом просто набираешь в командной строке "g++ main.cpp -o my_cool_hack.exe", находясь в папке с исходным кодом. MSVS для маломощных компьютеров мало подходит, т.к. жрет много ресурсов и заметно тормозит, если их нет.
Ссылка на комментарий
Поделиться на другие сайты

Оно работает из командной строки, нужно папку c:\mingw\bin\ положить в переменную PATH, а потом просто набираешь в командной строке "g++ main.cpp -o my_cool_hack.exe", находясь в папке с исходным кодом. MSVS для маломощных компьютеров мало подходит, т.к. жрет много ресурсов и заметно тормозит, если их нет.

Ok, как это сделать?) Я про переменную PATH. 

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

Ok, как это сделать?) Я про переменную PATH.

Для Windows 7 и выше:

Пуск -> Правая кнопка мыши на "Компьютер" -> "Свойства", в открывшемся окне (слева) - Дополнительные параметры системы. В открывшемся окне ("Свойства системы"), на вкладке "Дополнительно" - кнопка "Переменные среды" (в самом низу).

В "Системных переменных" (область снизу), есть ключ "Path". Кажется, это имел в виду keng, если я не ошибаюсь.

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

Совершенно верно. Вариант для командной строки:

setx path "%path%;c:\mingw\bin\"

 

setx - изменяет переменную окружения, %path% возвращает текущее значение переменной path, ; - разделитель. Получается так:

 

path = path + ";c:\mingw\bin"

 

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

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

Совершенно верно. Вариант для командной строки:

setx path "%path%;c:\mingw\bin\"

 

setx - изменяет переменную окружения, %path% возвращает текущее значение переменной path, ; - разделитель. Получается так:

 

path = path + ";c:\mingw\bin"

 

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

Яяяясно... И что я сделал? Взломал пентагон?

znD0DGs.png

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

Вторую команду вводить в консоль было не нужно, я просто показал в псевдокоде, что делает первая. Если перезапустить консоль и ввести "path" еще раз - что она выдаст?
Ссылка на комментарий
Поделиться на другие сайты

Вас куда-то понесло уже не туда. Тема топика внедрение кода в другой процесс посредством C++/WinAPI, а вы здесь уже пошли компиляторы перебирать.

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

Вторую команду вводить в консоль было не нужно, я просто показал в псевдокоде, что делает первая. Если перезапустить консоль и ввести "path" еще раз - что она выдаст?

Если ещё раз её ввести, то выдает тоже самое, что и на первом скриншоте вверху. Много много букв, где описываются всяческие пути.

 

Вас куда-то понесло уже не туда. Тема топика внедрение кода в другой процесс посредством C++/WinAPI, а вы здесь уже пошли компиляторы перебирать.

Дык ведь попутная же тема, не?

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

Если ещё раз её ввести, то выдает тоже самое, что и на первом скриншоте вверху. Много много букв, где описываются всяческие пути.

 

Дык ведь попутная же тема, не?

Компилятор и реализация алгоритма - не имеют ничего общего.

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

Вопросик небольшой... Выделенная память что-то не выделяется. 

Т.е. я сделал всё как нужно, но почему-то адрес выделенной памяти не печатается в консоли. Может краска закончилась?

QQ3x3kL.png

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

Зачем ты это сделал, непонятно.

При выделении памяти порядок другой

На кодкейвы нужно так писать

VirtualAlloxEx(адрес не указываешь, пусть сам ищет подходящее место для выделения памяти)VirtualProtectEx(адрес, который вернула предыдущая функция) - и даже это, в принципе, необязательно, так как ты нужные права сразу ставишь в выделялке.WriteProcessMemory(и снова адрес, который вернула выделялка памяти)

А для затирания оригинальных инструкций прыжком на кейв уже надо

VPExWPMVPEx(oldprotect)

Как-то так.

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

Зачем ты это сделал, непонятно.

При выделении памяти порядок другой

На кодкейвы нужно так писать

VirtualAlloxEx(адрес не указываешь, пусть сам ищет подходящее место для выделения памяти)VirtualProtectEx(адрес, который вернула предыдущая функция) - и даже это, в принципе, необязательно, так как ты нужные права сразу ставишь в выделялке.WriteProcessMemory(и снова адрес, который вернула выделялка памяти)

А для затирания оригинальных инструкций прыжком на кейв уже надо

VPExWPMVPEx(oldprotect)

Как-то так.

Олрайд, бат хау кен ай ду зис? 

LPVOID NewMem = VirtualAllocEx(hProc, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

Вот туточки он просит адрес. Что сделать? Я знаю только NULL, что значит - "пусто". Или нужно как-то по другому это реализовать?

 

И еще вопросик, когда буду VirtualFreeEx делать, то какоой тип памяти брать? MEM_DECOMIT или MEM_RELEASE?

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

 

Вот туточки он просит адрес. Что сделать? Я знаю только NULL, что значит - "пусто". Или нужно как-то по другому это реализовать?

 

Его и ставь

 

И еще вопросик, когда буду VirtualFreeEx делать, то какоой тип памяти брать? MEM_DECOMIT или MEM_RELEASE?

 

 

Первый. А можешь и оба )

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

Его и ставь

 

 

Первый. А можешь и оба )

Я когда RELEASE поставил - вообще ничего не произошло. Поставил DECOMIT - все байты и вся память стрелась)))

Еще, что удивило - я ставлю в алоке - 32 байта алокнуть, а он алокает вот так: сначала 0x320000 потом 0x330000. По 10.000 алокает)

Т.е. ему как бы вообще пофигу, что я напишу. Он сам решает сколько алокать) Он как быть "Fuck the system" :D

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

Цитирую MSDN:

 

"The pointer that specifies a desired starting address for the region of pages that you want to allocate."

 

Это - про второй аргумент VirtualAllocEx. Если надо выделить память в конкретной области - даем адрес этой области. Аргумент не обязательный.

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

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

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

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