-
Постов
1 635 -
Зарегистрирован
-
Посещение
-
Победитель дней
55
Тип контента
Профили
Форумы
Загрузки
Блоги
Весь контент keng
-
/*----------------------------------------------------------------------------*/ Привет! Сравнивает, равны ли BASETEX и (DWORD)BTEX. Первое - элемент массива (как видно выше - вектора, но сути это не меняет) BASETEX по индексу i, второе - значение переменной BTEX, приведённое к типу DWORD, так как элементы BASETEX тоже имеют тип DWORD. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Потому что в ней нет особого смысла. У меня самого таких коллекция - это мало что меняет, а объяснить свою позицию и\или точку зрения можно и на абстрактных примерах, безо всякой конкретики. Достаточно того, что в шапке темы написано. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Привет! Можно ещё посмотреть вот [этот] мой пост. Возможно, чем-то поможет. Особого значения при этом не имеет, через какой именно регистр и каким именно образом проходят данные. Обычно в таких ситуациях нужно смотреть выше по коду, как формируются операнды нужной команды (в твоём случае - что попадает в ESI и XMM0 перед выполнением самой команды MOVSS). /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ В том-то вся и проблема, что это совсем другое, нежели взлом игр. Да, тоже участвуют отладчик и дизассемблер, но на этом сходство фактически заканчивается. Другая сама идеология процесса. Я могу попробовать объяснить краткую суть процесса. Возможно, показать пару примеров. Но явно не на этом форуме, а по почте. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Привет! Я не думаю, что тут кто-то за такую работу возьмётся, так как тематика форума иная, но не мог бы ты скинуть мне собранную программу на почту? 00 keng @ gmail com . /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ На странице восстановления пароля не показывается капча - только грустное сообщение о том, что надо бы пройти антиспам-квест. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Привет! Советую почитать вот [этот] пост, там даже картинки есть. /*----------------------------------------------------------------------------*/
-
/*---------------------------------------------------------------------------*/ Я, может, не совсем правильно понял, но какую сигнатуру ты имеешь ввиду? Ту, что используется для функции aob_scan()? Дык она тебе не нужна толком, ты же и так знаешь адрес функции. Давай я ещё раз приведу описание твоей задачи: "Есть функция которая меняет значение, я поставил хук на эту функцию и получаю готовое значение, но как мне узнать через какую функцию это значение создается? Так же мне известно что функция которая создает это значение срабатывает при определенном действии в игре." У тебя есть адрес некоторой функции, которая изменяет значение адреса A. Тебе хочется узнать, "через какую функцию это значение создаётся". Следовательно, самый первый шаг - посмотреть функцию, которая это значение меняет, а точнее - весь код, который идёт выше от инструкции, меняющей адрес. Брейкпоинт на запись, а затем смотрим выше, как меняются регистры. Следующий шаг - брейкпоинт на чтение этого же адреса - там наверняка найдётся не один вызов, в том числе и функции, которая твоё значение "создаёт". На самом деле, со словом "создаёт" тоже стоит кое-что уточнить - под созданием можно понимать как объявление функции, так и создание объекта, так и присвоение переменной какого-то значения. Не думай пока про хуки или что-то ещё, для начала нужно разобраться с кодом и понять, что дальше делать. На данный момент тебе нужно просто найти код, меняющий адрес памяти, который ты уже знаешь, в каком-то другом месте. Поставь брейкпоинт на этот адрес памяти и смотри, что будет в том или ином случае. /*---------------------------------------------------------------------------*/
-
/*---------------------------------------------------------------------------*/ Интересных ты профессионалов поспрашивал! Олли - хороший отладчик, Ида - отличный (если не лучший) дизассемблер + неплохой отладчик. Это, собственно, просто инструменты. Первым находишь, куда копать (адрес функции), вторым - копаешь (разбираешься, как функция работает). Это можно делать час, три, пару дней, неделю или месяцы. Я когда-то давно, ради спортивного интереса, снимал с одной игры защиту под именем StarForce - потратил месяц чистого времени - т.е. месяц только лишь сидения в отладчике\дизассемблере, не говоря о пробах, раздумьях и записях. Очень долго, очень муторно, очень медленно и крайне малоэффективно - пытаться понять по дизассемблерному листингу логику работы высокоуровневой программы, будь то современная игра или что-то другое. Так что запасись терпением и для начала сядь и представь, абстрактно, как можно реализовать задуманное и с чего бы начать. 95% времени - это отладка кода, оставшиеся 5% - поиск адреса или указателя в CE. /*---------------------------------------------------------------------------*/
-
/*---------------------------------------------------------------------------*/ В CE 6.4 появилась крутяцкая штука под названием Ultimap, которая как раз для этого и предназначена. Единственная трудность - для неё нужен полностью рабочий DBVM (ядерный отладчик, идущий в комплекте с CE), который работает только под Intel. PS: На 8.1 x64 у меня его завести так и не удалось - на семёрке работает. /*---------------------------------------------------------------------------*/
-
/*---------------------------------------------------------------------------*/ Дело не в навыках программирования или владения английским языком. Штука в том, что сообщения, написанные неграмотно и впопыхах, тяжело читать и воспринимать визуально. Грамотно написанное сообщение быстро читается и легко понимается, а если оно большого объёма, то и ориентироваться в нём тоже можно достаточно быстро. Если же вместо связного текста написана каша без знаков препинания и вообще намёков на оформление - то дольше времени потратится на прочтение, перечитывание и попытки осознать, чего же хотел автор, чем на, собственно, решение его вопроса. Главное понимать, что форум - это не чат, некуда тут торопиться. Сообщения, как и темы, никуда не денутся, так что можно сидеть и составлять хоть полчаса, хоть час - всё равно ведь прочитают. /*---------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Ещё как принимает, но для него команды нужны специальные. Это один из регистров SSE - штуки-расширения процессора, которая позволяет работать со 128-битными числами. Это расширение часто используется в играх, где чего-нибудь много, например стратегиях - там много юнитов. Подробнее можно вот [тут] почитать. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Дык можно и в него писать, я не спорю. Только нельзя писать, куда попало. Надо или найти блок байт, который не используется (В отладчике Cheat Engine меню Tools - Scan for code caves), или же выделить через VirtualAllocEx, для неё нужно указать флажки, размер блока и pID процесса, который можно получить, например, через OpenProcess (пример моего кода): GetMemoryForCave proc bsize:dword LOCAL phndl:dword invoke OpenProcess,PROCESS_ALL_ACCESS,NULL,pid .if eax != 0 mov phndl,eax invoke VirtualAllocEx,phndl,NULL,bsize,MEM_COMMIT,PAGE_EXECUTE_READWRITE push eax invoke CloseHandle,phndl pop eax .endif ret GetMemoryForCave endp Как переворачивать адрес? Ну, это массив. Руками! WriteBuffer proc t:dword,f:dword,b:dword,s:dword push eax push ebx mov ebx, mov dword ptr [ebx],0E8h mov eax,t sub eax,f sub eax,5 mov byte ptr [ebx+1],al mov byte ptr [ebx+2],ah shr eax,16 mov byte ptr [ebx+3],al mov byte ptr [ebx+4],ah mov eax,s sub eax,5 cmp eax,0 je $+10 mov byte ptr [ebx+5],090h inc ebx dec eax jne $-11 pop ebx pop eax ret WriteBuffer endp /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Верно, обращение по амперсанду выдаёт адрес переменной в памяти, обращение по имени - значение переменной. Точно так же, если к тебе пришёл адрес переменной, а ты хочешь получить значение из этого адреса - делаешь звёздочку: int foo = 0; // Объявляем переменную типа int с именем foo int* pFoo = &foo; // Объявляем указатель на int с именем pFoo, кладём в него // указатель на foo int bar = *pFoo; // Объявляем переменную типа int с именем bar и кладём в него //значение указателя pFoo В результате bar будет равно 0, то есть изначальному значению foo. То же самое, что и: int foo = 0; int bar = foo; Приведу ещё раз ассемблерную вставку из своего примера: __asm { push eax mov eax,[foo] inc eax mov [foo],eax pop eax } 0. Сохраняем регистр EAX в стек - мало ли, что там было до нашей функции. Вдруг важное?1. Кладём в EAX значение (не адрес!) переменной foo2. Увеличиваем eax на 13. Кладём в переменную foo новое значение То же самое, что и: foo++;или:foo += 1;или:foo = foo + 1; Дальше мы сообщаем в консоль значение foo и адрес foo в памяти. Если посмотреть этот код в отладчике, то увидим мы нечто такое: CPU DisasmAddress Hex dump Command 00023C0F |. 50 |PUSH EAX00023C10 |. A1 5C810200 |MOV EAX,DWORD PTR DS:[foo]00023C15 |. 40 |INC EAX00023C16 |. A3 5C810200 |MOV DWORD PTR DS:[foo],EAX00023C1B |. 58 |POP EAX Наша задача - как-то впихнуть в это место код, который скопирует EAX в какую-нибудь переменную, т.е. в какой-то другой адрес памяти. Вроде этого: CPU DisasmAddress Hex dump Command 00023C0F |. 50 |PUSH EAX00023C10 |. A1 5C810200 |MOV EAX,DWORD PTR DS:[foo]00023C15 |. 40 |INC EAX00023C16 |. A3 5C810200 |MOV DWORD PTR DS:[foo],EAX MOV [0x1234567],EAX00023C1B |. 58 |POP EAX Но просто так взять и записать кусок кода посреди программы мы не можем. Почему? Потому что компилятор - умный. И при компиляции весь код, переводя его в машинные инструкции (колоночка hex dump) кладёт их поближе друг к другу, но что самое важное - все переходы по коду (jmp, je, jne и так далее) осуществляются относительно текущего адреса. Следовательно, если порядок байт нарушить, впихнув лишних, то переходы, которые раньше ссылались на правильно заданные при компиляции места, начнут ссылаться в какую-нибудь далёкую страну, например SEG_FAULT. Приятный момент тут в том, что после компиляции в исполняемый файл код всегда будет лежать по одним и тем же адресам, т.е. адрес инструкции "MOV DWORD PTR DS:[foo],EAX" как был равен 0x00023C16, так там и останется. Нужно как-то впихнуть сюда ещё 5 байт (столько команда MOV и занимает вместе соперандами). Текущий код нельзя расширить, но можно поменять. Тут-то нам напомощь и спешит команда JMP. Стираем текущую команду MOV, вместо неё пихаем JMPна другой адрес, а там делаем так: MOV DWORD PTR DS:[foo],EAXMOV [0x1234567],EAXRET В итоге оригинальный код начинает выглядеть так: CPU DisasmAddress Hex dump Command 00023C0F |. 50 |PUSH EAX00023C10 |. A1 5C810200 |MOV EAX,DWORD PTR DS:[foo]00023C15 |. 40 |INC EAX00023C16 |. A3 5C810200 |JMP 0x123456700023C1B |. 58 |POP EAX Как такое сделать? Вот пример:
-
/*---------------------------------------------------------------------------*/ [GetModuleHandle], но её нужно вызывать из адресного пространства процесса. Вернёт адрес, по которому загружен тот или ной исполняемый модуль. А дальше считаешь: hDll + 0x12345678 = адрес нужного участка кода. Я ещё раз советую сначала попробовать обойтись без использования указателей там, где это возможно. Указатели на память - не самая надёжная штука. /*---------------------------------------------------------------------------*/
-
/*---------------------------------------------------------------------------*/ Причин может быть довольно много, но мне в голову приходит только одна - code shifting. Это ситуация, когда часть игрового кода подгружается игрой динамически, а хранится при этом в DLL. В этом случае надо получить адрес DLL, затем от него взять смещение до нужного адреса, будь то код или память. Попробуй сначала сделать инъекцию кода, чтобы не использовать указатели, если не сработает - можно начинать думать о чём-то более сложном. /*---------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Не забываем, само собой, но я не уверен, что ART вот так из коробки взял и стал позволять лезть в чужое адресное пространство. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Можно, конечно, написать про использование inline-ассемблера. А-ля: DWORD GetMyData() { DWORD result = 0; __asm mov result,ecx return result; } Но, я так понимаю, тебе надо сделать именно инжект кода. Регистры меняются не "каждый байт", а тогда, когда их меняют, за исключением всяких там esp и прочих ebp. Скажем, ecx не поменяется, пока его не поменяют. Алгоритм такой, я думаю: 0. Выделить где-нибудь 4 байта под переменную, хранящую значение. 1. Заменить нужный кусок кода инструкцией вида "JMP 0x01234567", где 0x01234567 - адрес процедуры вроде GetMyData выше. Как заменить? JMP в опкодах - 0xE9, дальше нужно посмотреть, какой адрес больше - процедуры GetMyData или куска кода, который меняем. Из большего вычитаем меньшее (хотя вроде можно и наоборот), так как прыжки на адрес всегда делаются относительно текущей позиции - типа на 100 байт вперёд или на 100 байт назад. 2. В процедуре делаем это самое "mov result,ecx" и выходим. 3. Используем полученный result. В принципе, malloc(), virtualprotectex(), memcpy(), readprocessmemory() - вот и всё необходимое, помимо получения pID процесса (но тут уже варианты на твой вкус). PS: Таки getthreadcontext() будет всё равно попроще, я думаю. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Далвик не даст на чужое адресное пространство посмотреть без рут-прав. /*----------------------------------------------------------------------------*/
-
/*----------------------------------------------------------------------------*/ Дополню предыдущий пост и порекомендую сперва проверить, не нули ли в координатах, а только потом пытаться их куда-то записывать. Неосторожность чревата вылетами из игры. /*----------------------------------------------------------------------------*/
-
/*---------------------------------------------------------------------------*/ Могу предположить, что "непонятный мусор", судя по открытому окну Cheat Engine, является типом float, так что его ещё надо из DWORD сконвертировать: float f_coord_X = (float)coord_X; /*---------------------------------------------------------------------------*/