HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ПРОГРАММИРОВАНИЕ > Общие вопросы программирования
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 07.03.2024, 00:07
UnknownPerson
Новичок
Регистрация: 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++ (если таковые имеются) также приму

Заранее спасибо
 
Ответить с цитированием

  #2  
Старый 24.03.2024, 03:12
RedHolms
Постоянный
Регистрация: 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
 
Ответить с цитированием

  #3  
Старый 25.03.2024, 20:57
вайега52
Флудер
Регистрация: 19.06.2022
Сообщений: 2,997
С нами: 2055431

Репутация: 3


По умолчанию

Цитата:
Сообщение от RedHolms  

на счёт C# не знаю вообще, но на C++ ты просто буквально передаешь функцию:
если я правильно понимаю, автор темы делает экстернал чит, в таком случае, если я я верно думаю, необходимо загружать байты (в данном случае функцию) внутрь виртуальной памяти процесса
 
Ответить с цитированием

  #4  
Старый 02.04.2024, 23:19
Vintik
Познавший АНТИЧАТ
Регистрация: 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. Можешь в коде где-то в
Код:
main()
написать
[CODE]
std::cout Only Bytes») и вставить в массив. Всю неприятную работу по созданию ASM кода выполнит компилятор. Если изначальные прототипы функций (не только твоей, но и тех, что ты вызываешь внутри) верны, то краша быть не должно.

Цитата:
Сообщение от Спойлер  

Даже при краше пишет адрес краша («Exception at address ...»), так ты можешь посмотреть, где и что конкретно вызывает краш.
upd.

Чтобы получить адрес модуля
Код:
samp.dll
воспользуйся этой функцией (это можно делать как внутри твоего вызова каждый раз, так и один раз при запуске):

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


Будут еще вопросы — пиши.
 
Ответить с цитированием

  #5  
Старый 05.04.2024, 15:55
UnknownPerson
Новичок
Регистрация: 06.03.2024
Сообщений: 2
С нами: 1153155

Репутация: 3
По умолчанию

Огромное спасибо за помощь, подсказка с плюсами и CE мне очень помогла, правда, я сделал немого иначе — написал хандлер с asm кодом для вызова определенных функций, скомпилировал все в dll, инжектнул в игру и получил тело всей функции уже в виде шеллкода, ну и соответственно на шарпе я выполнил все те действия, которые описывал выше, в конечном итоге это сработало

Еще раз огромное спасибо
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.