 |

07.03.2024, 00:07
|
|
Новичок
Регистрация: 06.03.2024
Сообщений: 2
С нами:
1153155
Репутация:
3
|
|
Привет! Не буду тянуть кота за хвост и перейду сразу к сути
В samp.dll имеется функция, которая создает клиентские команды (адрес функции — 0x69000). Выглядит функция так:
AddCommand:
Код:
void
__thiscall CInput
::
AddCommand
(
CInput
*
this
,
const
char
*
szName
,
void
(
__cdecl
*
handler
)
(
const
char
*
)
)
Соответственно функция принимает название команды и хандлер для обработки этой команды, который принимает введенные игроком параметры и исполняет какой-либо код
Я вызываю эту функцию удаленно через CreateRemoteThread и прочие приблуды, функция вызывается и выполняется, команда создается, с этим никаких проблем нет, но есть проблема с хандлером, который нужно засунуть в качестве второго аргумента функции
Прошерстив интернет я выяснил, что засунуть хандлер в принципе возможно, но как это сделать и возможно ли это вообще в сампе — непонятно
В качестве хандела я пытаюсь засунуть шеллкод:
shellcode:
Код:
byte
[
]
asmBytes
=
new
byte
[
]
{
0x55
,
// push ebp
0x89
,
0xE5
,
// mov ebp, esp
0x89
,
0xEC
,
// mov esp, ebp
0x5D
,
// pop ebp
0xC3
// ret
}
;
Затем я выделяю память для этого кода и записываю его в процесс, а также получаю адрес выделенной области, который передаю как хандлер:
Запись в процесс:
Код:
memoryAddress
=
VirtualAllocEx
(
handle
,
IntPtr
.
Zero
,
asmBytes
.
Length
,
0x1000
,
0x40
)
;
WriteMemoryBytes
(
memoryAddress
,
asmBytes
)
;
Код успешно регистрирует клиентскую команду и при использовании ее в игре краша нет, но и хандлер ничего не выполняет, а служит обычной "заглушкой"
Мне нужно, чтобы хандлер вызывал функцию AddEntry (0x67460) в случае, если игрок не ввел ни одного параметра в команде, и функцию SendCommand (0x69190) (отправляет сразу команду в чат), если пользователь ввел какие-то параметры в команде
Функция AddEntry:
Код:
void
__thiscall CInput
::
AddCommand
(
CInput
*
this
,
const
char
*
szName
,
void
(
__cdecl
*
handler
)
(
const
char
*
)
)
Я пробовал вызвать AddEntry следующим образом:
C#:
Код:
byte
[
]
asmBytes
=
new
byte
[
]
{
0x55
,
// push ebp
0x89
,
0xE5
,
// mov ebp, esp
0x89
,
0xEC
,
// mov esp, ebp
0x68
,
0x00
,
0x00
,
0x00
,
0x00
,
// push CChatAddress (сюда вписывается samp.dll + 0x26E8C8)
0x6A
,
0x08
,
// push 0x8
0x68
,
0x74
,
0x65
,
0x78
,
0x74
,
// push "text"
0x68
,
0x00
,
0x00
,
0x00
,
0x00
,
// push 0x0 (empty string for szPrefix)
0x68
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
// push 0xFFFFFF (textColor)
0x68
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
// push 0xFFFFFF (prefixColor)
0xB9
,
0x00
,
0x00
,
0x00
,
0x00
,
// mov ecx, AddEntryFunctionAddress (сюда вписывается samp.dll + 0x67460)
0xFF
,
0xD1
,
// call ecx
0x5D
,
// pop ebp
0xC3
// ret
}
;
Но игра вызывает краш после ввода команды и попытки выполнить этот код. Хочу также подметить, что в ассемблере я не силен от слова совсем
Из всего вышенаписанного вытекает вопрос: реально ли вообще реализовать вызов функции AddCommand подобным образом и если да, то мне нужен пример того, как это можно правильно сделать с краткими объяснениями (ну или если есть желание, то с подробными, было бы вообще круто)
Все вышепоказанное я делал на C#, но примеры на C++ (если таковые имеются) также приму
Заранее спасибо 
|
|
|

24.03.2024, 03:12
|
|
Постоянный
Регистрация: 04.06.2020
Сообщений: 620
С нами:
3127813
Репутация:
133
|
|
на счёт C# не знаю вообще, но на C++ ты просто буквально передаешь функцию:
C++:
Код:
void
handler
(
const
char
*
arg
)
{
/// ....
}
void
reg
(
)
{
CInput
::
AddCommand
(
"mycmf"
,
handler
)
;
}
Я бы советовал поискать в интернете, возможно ли передать C#-пную функцию как аргумент C-шной (100% функция должна быть статической)
И еще, не балуйся с потоками, так как самп не thread-safe
|
|
|

25.03.2024, 20:57
|
|
Флудер
Регистрация: 19.06.2022
Сообщений: 2,997
С нами:
2055431
Репутация:
3
|
|
Сообщение от RedHolms
на счёт C# не знаю вообще, но на C++ ты просто буквально передаешь функцию:
если я правильно понимаю, автор темы делает экстернал чит, в таком случае, если я я верно думаю, необходимо загружать байты (в данном случае функцию) внутрь виртуальной памяти процесса
|
|
|

02.04.2024, 23:19
|
|
Познавший АНТИЧАТ
Регистрация: 18.08.2017
Сообщений: 1,568
С нами:
4598023
Репутация:
183
|
|
Да, привет!
Ты всё понял верно, шаги у тебя правильные.
На самом деле, нужно понять на каком моменте что-то ломается.
Сообщение от UnknownPerson
Код успешно регистрирует клиентскую команду и при использовании ее в игре краша нет, но и хандлер ничего не выполняет, а служит обычной "заглушкой"
Шаг первый. Нужно проверить, работает ли твоя заглушка. В консоль твоей программы выпиши адрес области, которая выделяется VirtualAllocEx (эта же функция и возвращает этот адрес). После инъекции, уже при работе программы, открываешь Cheat Engine (CE), дальше Memory Viewer, дальше Ctrl + G и вставляй этот адрес. У тебя должна открыться твоя же функция (те байты, которые ты написал). Выбираешь любой из них (любую строку) и нажимаешь F5 (либо ПКМ и «Break and trace instructions»). А теперь попробуй ввести в чат команду, которую ты зарегистрировал. CE должен будет остановить твою игру, а в меню Memory Viewer появится активная кнопка «Продолжить» (как при паузе). Если так, то это оно! Значит игра проходит через твою заглушку.
Сообщение от UnknownPerson
Но игра вызывает краш после ввода команды и попытки выполнить этот код. Хочу также подметить, что в ассемблере я не силен от слова совсем
Шаг второй. Я думаю, что в ASM коде мало кто силён. Если шаг первый успешно выполнен, то единственная задача — правильно написать функцию, не сломав при этом значения регистров и программный стек. Прототип твоей функции следующий:
C++:
Код:
void
__cdecl
handler
(
const
char
*
)
;
И никто не мешает тебе в отдельной программе (не основной!) написать на C++ ту функцию, которая тебе нужна:
C++:
Код:
// создаёшь прототипы своих функций (я не знаю какие аргументы там)
typedef
void
(
__thiscall
*
AddEntry
)
(
int
,
int
,
const
char
*
,
int
,
int
,
int
)
;
int
SampDll
;
// получаешь адрес модуля samp.dll
void
__cdecl
handler
(
const
char
*
arg
)
{
if
(
strlen
(
arg
)
==
0
)
reinterpret_cast
(
SampDll
+
0x67460
)
(
SampDll
+
0x26E8C8
,
8
,
"text"
,
0x0
,
0xFFFFFF
,
0xFFFFFF
)
;
.
.
.
}
А дальше компилируешь это всё дело в x32. Можешь в коде где-то в
написать
[CODE]
std::cout Only Bytes») и вставить в массив. Всю неприятную работу по созданию ASM кода выполнит компилятор. Если изначальные прототипы функци й (не только твоей, но и тех, что ты вызываешь внутри) верны, то краша быть не должно.
Сообщение от Спойлер
Даже при краше пишет адрес краша («Exception at address ...»), так ты можешь посмотреть, где и что конкретно вызывает краш.
upd.
Чтобы получить адрес модуля
воспользуйся этой функцией (это можно делать как внутри твоего вызова каждый раз, так и один раз при запуске):
C++:
Код:
DWORD
GetProcId
(
const
char
*
procname
)
{
PROCESSENTRY32 pe
;
HANDLE hSnap
;
pe
.
dwSize
=
sizeof
(
PROCESSENTRY32
)
;
hSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPPROCESS
,
NULL
)
;
if
(
Process32First
(
hSnap
,
&
pe
)
)
{
do
{
if
(
strcmp
(
pe
.
szExeFile
,
procname
)
==
0
)
break
;
}
while
(
Process32Next
(
hSnap
,
&
pe
)
)
;
}
return
pe
.
th32ProcessID
;
}
HMODULE
GetModuleHandleExtern
(
const
char
*
szModuleName
,
DWORD dwProcessId
)
{
if
(
!
szModuleName
||
!
dwProcessId
)
{
return
NULL
;
}
HANDLE hSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPMODULE
,
dwProcessId
)
;
if
(
hSnap
==
INVALID_HANDLE_VALUE
)
{
return
NULL
;
}
MODULEENTRY32 me
;
me
.
dwSize
=
sizeof
(
MODULEENTRY32
)
;
if
(
Module32First
(
hSnap
,
&
me
)
)
{
while
(
Module32Next
(
hSnap
,
&
me
)
)
{
if
(
!
strcmp
(
me
.
szModule
,
szModuleName
)
)
{
CloseHandle
(
hSnap
)
;
return
me
.
hModule
;
}
}
}
CloseHandle
(
hSnap
)
;
return
NULL
;
}
Использование:
Код:
HMODULE SampDll
=
GetModuleHandleExtern
(
"samp.dll"
,
GetProcId
(
"gta_sa.exe"
)
)
;
// HMODULE — это обычный указатель, который занимает 4 байта в x32. Поэтому можешь использовать C-cast: (unsigned int)SampDll
Будут еще вопросы — пиши.
|
|
|

05.04.2024, 15:55
|
|
Новичок
Регистрация: 06.03.2024
Сообщений: 2
С нами:
1153155
Репутация:
3
|
|
Огромное спасибо за помощь, подсказка с плюсами и CE мне очень помогла, правда, я сделал немого иначе — написал хандлер с asm кодом для вызова определенных функций, скомпилировал все в dll, инжектнул в игру и получил тело всей функции уже в виде шеллкода, ну и соответственно на шарпе я выполнил все те действия, которые описывал выше, в конечном итоге это сработало
Еще раз огромное спасибо
|
|
|
|
 |
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|