edx Опубликовано 14 апреля, 2020 Поделиться Опубликовано 14 апреля, 2020 (изменено) Всем здравствуйте. Пишу бота с интерфейсом, застопорился на вызове функций из внедренной в процесс DLL-ки. Некоторую информацию можно получить удаленно через ReadProcessMemory по адресам и оффсетам, да. Но чтобы получать класс User к примеру, который имеет динамический адрес надо внутри процесса вызвать API функцию. И вот вопрос: каким способом это сделать из интерфейса? Кусочек кода: void memRead(HANDLE hProc, DWORD address, LPVOID buffer) { DWORD oldProtect = 0; VirtualProtectEx(hProc, (LPVOID)address, sizeof(buffer), PAGE_READWRITE, &oldProtect); ReadProcessMemory(hProc, (LPVOID)address, buffer, sizeof(buffer), 0); VirtualProtectEx(hProc, (LPVOID)address, sizeof(buffer), oldProtect, &oldProtect); } typedef int(__thiscall* f_GetUser)(int this_UNetworkHandler, int id); f_GetUser call_GetUser = reinterpret_cast<f_GetUser>(0x203D9150); int GetMyUserClass() { HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID); DWORD UNetworkHandler_this; int my_id; memRead(hProc, 0x20522A6C, &UNetworkHandler_this); memRead(hProc, 0x2077ED7C, &my_id); return call_GetUser(UNetworkHandler_this, my_id); //call_GetUser Возвращает адрес класса User CloseHandle(hProc); } ID и адрес класса UNetworkHandler получаются корректно, но функция не вызывается. Не пинайте меня, я еще многого не знаю..:) Изнутри процесса все окей, функция работает. Можно конечно постоянно юзать ее из DLL, но тогда я не знаю как правильно организовать обмен информацией между DLL и exe-шником. Через пайп как-то геморно.. Как вызвать функцию удаленно? Изменено 14 апреля, 2020 пользователем edx Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 14 апреля, 2020 Поделиться Опубликовано 14 апреля, 2020 Ну, собственно, именнованный пайп - самое оно. Или можно сокетом воспользоваться, с ним меньше геморроя. Ссылка на комментарий Поделиться на другие сайты Поделиться
edx Опубликовано 14 апреля, 2020 Автор Поделиться Опубликовано 14 апреля, 2020 (изменено) 44 минуты назад, Xipho сказал: Ну, собственно, именнованный пайп - самое оно. Или можно сокетом воспользоваться, с ним меньше геморроя. В общем, мне нужно как-то закостылить организовать (к примеру) вызов функции MoveToLocation, отправляя при этом в DLL координаты куда нужно бежать и BOOL параметр для активации функции. При этом, DLL должна непрерывно передавать параметры в GUI. Я немного не понимаю как использовать для этого пайп канал. Чтобы отправить команду в DLL из GUI мне приходится отстыковывать один пайп и пристыковывать другой.. Можно общаться одним пайпом как-то не перекрывая записанные данные? Я не нашел толковых примеров в гугле.. Нигде блин. Фрагмент кода GUI: Спойлер // По нажатию кнопки в GUI происходит инжект DLL в процесс, устанавливается флаг для работы BackgroundWorker и запускается сам воркер ... ... private: System::Void btnInject_Click(System::Object^ sender, System::EventArgs^ e) { if (InjectDLL()) { tolog("DLL successfuly injected"); } else { tolog("ERROR: DLL Injection was failed!"); } statusBufferWorker = TRUE; bufferWorker->RunWorkerAsync(); } ... ... // Воркер коннектится к DLL, и с установленной периодичностью получает стркутуру из DLL в которой записана инфа о персонаже и выводит данные в GUI. private: System::Void bufferWorker_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) { Sleep(500); if (!hPipeData1) { hPipeData1 = CreateFile("\\\\.\\pipe\\PipeData1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hPipeData1) tolog("Connection with injected DLL was opened!"); } else tolog("ERROR: Connection with injected DLL is closed!"); while (statusBufferWorker) { ReadFile(hPipeData1, &buf, sizeof(buf), &cbRead, NULL); //if (buf.messages.msg.length() > 0) { tolog(sts(buf.messages.msg)); } float cp_percent = buf.me.curCP / (buf.me.maxCP / 100.0); float hp_percent = buf.me.curHP / (buf.me.maxHP / 100.0); float mp_percent = buf.me.curMP / (buf.me.maxMP / 100.0); userCpBar->Size = System::Drawing::Size(cp_percent, 13); userHpBar->Size = System::Drawing::Size(hp_percent, 13); userMpBar->Size = System::Drawing::Size(mp_percent, 13); userCpLabel->Text = its(buf.me.curCP) + "/" + its(buf.me.maxCP); userHpLabel->Text = its(buf.me.curHP) + "/" + its(buf.me.maxHP); userMpLabel->Text = its(buf.me.curMP) + "/" + its(buf.me.maxMP); userIdField->Text = its(buf.me.ptrClass); Sleep(100); } } ... ... // При нажатии кнопки для выгрузки DLL из процесса запускается другой воркер, устанавливается флаг для остановки первого воркера, отсоединяется пайп по которому шли данные, открывается новый пайп, посылает команду в DLL на выгрузку, а там DLL отрабатывает все для выгрузки себя из процесса. private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) { statusBufferWorker = FALSE; DisconnectNamedPipe(hPipeData1); CloseHandle(hPipeData1); hPipeData1 = 0; BOOL dllStatus = FALSE; hPipeDllStatus = CreateNamedPipeA("\\\\.\\pipe\\PipeDllStatus", PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 5000, NULL); BOOL fConnected = ConnectNamedPipe(hPipeDllStatus, NULL); BOOL msg = WriteFile(hPipeDllStatus, &dllStatus, sizeof(dllStatus), &cbWritten, NULL); if (msg) tolog("DLL successfuly unloaded!"); DisconnectNamedPipe(hPipeDllStatus); CloseHandle(hPipeDllStatus); hPipeDllStatus = 0; } Фрагмент кода DLL: Спойлер ... ... // Создаем канал для передачи данных. При успехе возвращается HANDLE канала. hPipeData1 = CreateNamedPipeA("\\\\.\\pipe\\PipeData1", PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 5000, NULL); // Переходим в режим ожидания подключения клиента к каналу fConnected = ConnectNamedPipe(hPipeData1, NULL); // Пишем сообщение в структуру для GUI if (fConnected) { strcpy(buf.messages.msg , "FROM DLL: Connect with DLL successful!"); } // Действия выполняемые DLL-кой в цикле for (;; Sleep(100)) { // Проверяем запущен ли процесс GUI, если нет, то выгружаем DLL if (!CheckLoadedGUI()) { DisconnectAll(); break; } // Если есть соединение с таким именем ожидающее подключения, цепляем его, чекаем сообщение на выгрузку if (WaitNamedPipeA("\\\\.\\pipe\\PipeDllStatus", 5000)) { hPipeDllStatus = CreateFile("\\\\.\\pipe\\PipeDllStatus", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); BOOL dllStatus; ReadFile(hPipeDllStatus, &dllStatus, sizeof(dllStatus), &cbRead, NULL); if (dllStatus == FALSE) { DisconnectAll(); break; } } // Пишем данные о персонаже в структуру и отправляем её UpdateMyUserStruct(); WriteFile(hPipeData1, &buf, sizeof(buf), &cbWritten, NULL); ... ... Читал еще про FileMapping, выглядит очень удобно, но пока не понимаю как побайтно организовать несколько переменных, чтобы они корректно считывались? Как правильно отобразить несколько переменных в память? Не до конца понимаю смысл параметров dwFileOffsetHigh и dwFileOffsetLow. MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap, LPVOID lpBaseAddress); Изменено 14 апреля, 2020 пользователем edx Ссылка на комментарий Поделиться на другие сайты Поделиться
edx Опубликовано 14 апреля, 2020 Автор Поделиться Опубликовано 14 апреля, 2020 (изменено) UPD: Хм, в принципе, как вариант создать пару-тройку MappedFile, записать в них нужные переменные (а лучше структуру) для работы и использовать.. Но это же костыль и нерациональное использование ресурсов?) Изменено 14 апреля, 2020 пользователем edx Ссылка на комментарий Поделиться на другие сайты Поделиться
mrPTyshnik Опубликовано 14 апреля, 2020 Поделиться Опубликовано 14 апреля, 2020 (изменено) но лучше конечно использовать инжектируемую библиотеку в процесс. По поводу передачи данных - обычный FileMapping 1) Создаешь FileMapping в основном приложении 2) При инжекте, инжектируемая dll открывает этот FileMapping 3) Читаешь/пишешь в цикле, тут главное согласовать структуры данных, например: typedef struct MyRedneckProtocol { BYTE ControlCode; Vector3 Coord1; Vector3 Coord2; int resultCode; } эта структуру одинакова в dll и в основном приложении. Метод грубый и лучше бы конечно использовать пайп. Изменено 14 апреля, 2020 пользователем mrPTyshnik Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 14 апреля, 2020 Поделиться Опубликовано 14 апреля, 2020 Еще вариант - собрать длл-ку с одной пошаренной секцией (shared sections). Но это больше геморроя. Имхо, самый наименее геморройный вариант - общение через сокет. Чуть более геморройный - именованный пайп, я помню, у меня тоже с ним были проблемы как-то. Замапленные файлы использовать - то еще "удовольствие", потому что нужно согласовывать их запись/чтение. Ссылка на комментарий Поделиться на другие сайты Поделиться
edx Опубликовано 14 апреля, 2020 Автор Поделиться Опубликовано 14 апреля, 2020 (изменено) 1 час назад, Xipho сказал: Еще вариант - собрать длл-ку с одной пошаренной секцией (shared sections). Но это больше геморроя. Имхо, самый наименее геморройный вариант - общение через сокет. Чуть более геморройный - именованный пайп, я помню, у меня тоже с ним были проблемы как-то. Замапленные файлы использовать - то еще "удовольствие", потому что нужно согласовывать их запись/чтение. О, а можно немного подробнее про согласование? Я допустим сейчас сделал структуру общую, разметил её одинаково в обоих файлах, замапил. Вроде всё работает неплохо. Нужно не допустить одновременной записи и чтения одной и той же переменной? Я где-то читал про Event'ы, но так и не понял как они работают (пока что). Это из той оперы? upd: Или Вы имеете в виду очередность записи/чтения чтобы буфер не перекрывался разными переменными? Изменено 14 апреля, 2020 пользователем edx Ссылка на комментарий Поделиться на другие сайты Поделиться
edx Опубликовано 14 апреля, 2020 Автор Поделиться Опубликовано 14 апреля, 2020 2 часа назад, mrPTyshnik сказал: но лучше конечно использовать инжектируемую библиотеку в процесс. По поводу передачи данных - обычный FileMapping 1) Создаешь FileMapping в основном приложении 2) При инжекте, инжектируемая dll открывает этот FileMapping 3) Читаешь/пишешь в цикле, тут главное согласовать структуры данных, например: typedef struct MyRedneckProtocol { BYTE ControlCode; Vector3 Coord1; Vector3 Coord2; int resultCode; } эта структуру одинакова в dll и в основном приложении. Метод грубый и лучше бы конечно использовать пайп. А что обычно используют в таких случаях? В расчет беру частое обращение на запись/чтение. Принципиально ли использовать что-то конкретное? Быстродействие пайпа и маппинга здесь роли не играет как я понимаю из-за маленького объема данных? Ссылка на комментарий Поделиться на другие сайты Поделиться
imaginary Опубликовано 14 апреля, 2020 Поделиться Опубликовано 14 апреля, 2020 1 час назад, edx сказал: А что обычно используют в таких случаях? Я например, когда так делала, у меня было общение через ReadProcessMemory / WriteProcessMemory, А сначала, соединение устанавливалось через PostThreadMessage. А ещё я пробовала через системные объекты, которые можно создавать сколько угодно, единственная проблема, у них может быть только 2 состояние, true или false, и если передавать через них, то как в азбуке Морзе, прямо по битам, 101010 ? Ссылка на комментарий Поделиться на другие сайты Поделиться
edx Опубликовано 15 апреля, 2020 Автор Поделиться Опубликовано 15 апреля, 2020 (изменено) Я не понимаю, не могу вызвать функции даже изнутри процесса. Клиент почему-то просто вырубается и все. Объявляю вроде правильно, вызываю тоже. typedef int(__thiscall* f_NextCreature)(int this_UNetworkHandler, float Radius, int PrevID); f_NextCreature call_GetNextCreature = reinterpret_cast<f_NextCreature>(0x203D7F30); float Radius = 100.0; int pClassUser = call_GetNextCreature(pUNetworkHandler, Radius, PrevID)); И все, при таком вот вызове клиент закрывается. Работает только одна функция GetUser.. Вот код из IDA 7: .text:203D7F30 ; Exported entry 5758. ?GetNextCreature@UNetworkHandler@@UAEPAUUser@@MH@Z .text:203D7F30 .text:203D7F30 ; =============== S U B R O U T I N E ======================================= .text:203D7F30 .text:203D7F30 .text:203D7F30 ; struct User *__thiscall UNetworkHandler::GetNextCreature(UNetworkHandler *__hidden this, float, int) .text:203D7F30 public ?GetNextCreature@UNetworkHandler@@UAEPAUUser@@MH@Z .text:203D7F30 ?GetNextCreature@UNetworkHandler@@UAEPAUUser@@MH@Z proc near .text:203D7F30 ; DATA XREF: .text:20522E68↓o .text:203D7F30 .text:203D7F30 var_8 = dword ptr -8 .text:203D7F30 arg_0 = dword ptr 4 .text:203D7F30 arg_4 = dword ptr 8 .text:203D7F30 .text:203D7F30 mov edx, [esp+arg_4] Чего я не так делаю? Изменено 15 апреля, 2020 пользователем edx Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 15 апреля, 2020 Поделиться Опубликовано 15 апреля, 2020 20 часов назад, edx сказал: Нужно не допустить одновременной записи и чтения одной и той же переменной? Именно так. Открывать файл эксклюзивно при чтении и записи. Можно мьютексом это сделать, мьютексы глобально можно юзать. Ссылка на комментарий Поделиться на другие сайты Поделиться
mrPTyshnik Опубликовано 25 апреля, 2020 Поделиться Опубликовано 25 апреля, 2020 (изменено) В 15.04.2020 в 16:36, edx сказал: Чего я не так делаю? 1) найди код в игре который вызывает эту функцию и хорошенько присмотрись 2) через asm вставки(если работаешь на x32) ИЛИ через отдельный *.asm файл(если в x64) повтори один в один вызов этой функции из своей DLL Параметры функции могут передаваться через стек, а могут через регистры. Возможно ты что-то упускаешь + Еще вариант: Поставь бряк на эту функцию и посмотри как туда передаются параметры с реальными данными когда сама игра вызывает эту функцию Изменено 25 апреля, 2020 пользователем mrPTyshnik Ссылка на комментарий Поделиться на другие сайты Поделиться
edx Опубликовано 27 апреля, 2020 Автор Поделиться Опубликовано 27 апреля, 2020 В 25.04.2020 в 22:22, mrPTyshnik сказал: 1) найди код в игре который вызывает эту функцию и хорошенько присмотрись 2) через asm вставки(если работаешь на x32) ИЛИ через отдельный *.asm файл(если в x64) повтори один в один вызов этой функции из своей DLL Параметры функции могут передаваться через стек, а могут через регистры. Возможно ты что-то упускаешь + Еще вариант: Поставь бряк на эту функцию и посмотри как туда передаются параметры с реальными данными когда сама игра вызывает эту функцию Спасибо, уже разобрался. Похукал немного функции, посмотрел что за параметры идут через стек и т.п. Теперь вопрос, как скрыть загруженную в процесс dll от сканера памяти) И как сделать беспалевный вызов API клиента. Есть какой-то способ заставить античит думать что эта DLL принадлежит клиенту и клиент сам использует свой API? Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 28 апреля, 2020 Поделиться Опубликовано 28 апреля, 2020 19 часов назад, edx сказал: как скрыть загруженную в процесс dll от сканера памяти Manual Map тебе в помощь. Ссылка на комментарий Поделиться на другие сайты Поделиться
AlisaCodeDragon Опубликовано 28 апреля, 2020 Поделиться Опубликовано 28 апреля, 2020 В 14.04.2020 в 09:58, edx сказал: как правильно организовать обмен информацией между DLL и exe-шником. Через пайп как-то геморно.. Как вызвать функцию удаленно? Ребята пишут свою dll с перехватом нативных функций как мы все знаем u пакет - unreal scripts u пакет содержит нативные функции Когда я собирала компилятор эффектов то пришлось заново делать Core.u + Engine.u там встречались следующие классы HUD + CANVAS они содержаться в Engine.u canvas отрисовка на экране hud имеет отношение к интерфейсу можно взять и посмотреть скажем исходный код rguard защиты она старенькая но код там полезен для изучения. и вывод на экран и многое другое там все присутствует Спойлер 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения