C ++, Cheat Engine / OllyDBG находят базовый «статический» адрес из многоуровневых указателей - PullRequest
6 голосов
/ 18 мая 2011

Я снова вернулся, расстроен и отчаянно ищу помощь: D.

Я пытаюсь создать чит для простой программы, в основном это будет файл .dll, который изменит целое числозначение из основной программы, когда она вводится в нее с использованием ее базового адреса.Дело в том, что я не могу найти его с помощью чит-движка, потому что есть многоуровневые указатели с ОТРИЦАТЕЛЬНЫМ?Смещения.например:

//Starting pointer address
0x0033FCF0 -> 200

//Finding second level pointer using "Find out what's accessing this address" in Cheat Engine
**(mov eax,[ebp+08])** // **EAX=0x00000007** , **EPB=0x0033FCE8 => mov 00000007,[0033FCE8+08]**

2nd Level Pointer:
**(0033FCE8+18) -> 200**

Итак, я продолжаю искать следующий указатель, используя «Узнать, что ....», но при использовании T-SEARCH с адресом указателей второго уровня, и я получаю 7 - 8новые статические адреса.

Дело в том, что я не могу сказать, какой из них правильный, потому что чит-движок ОТКАЗЫВАЕТСЯ позволить мне добавить указатель, используя ОТРИЦАТЕЛЬНЫЙ?смещение.

Пример:

Base Pointer:
**mov eax,[epb-18] !!!** // Notice the **MINUS**

И вдобавок ко всему Cheat Engine отказывается принимать указатель с отрицательным смещением!

Итак, есть ли другой способ найти базовый адрес из указателей нескольких уровней?Решения OlyDBG / Idapro приветствуются.Большое спасибо, ребята!

Вот исходный код простой программы, которую я пытаюсь взломать:

#include <iostream>
#include <conio.h>
#include <windows.h>
#include <stdlib.h>

int main(){
    int hp = 100;
    while(1){
        std::cout << hp << std::endl;
        Sleep(3000);
        hp += 10;
        system("cls");
    }
    return 0;
}

Что я пытаюсь сделать, это отредактировать целое число hp с помощью этого.dll

#include <windows.h>
#define BASE    0xBASE_POINTERS_ADDRESS_WHICH_I_NEED_TO_FIND
#define OFFSET  0xTHE_OFFSET
#define VALUE   90
void MainFunction()
{
      while(1)
      {
            if (GetAsyncKeyState(VK_MENU)&0x8000 && GetAsyncKeyState('C')&0x8000) 
            MessageBox(0,L"Alt + C was pressed!",L"MessageBox! ",0);
            *(int*)((*(int*)BASE) + OFFSET) = VALUE;

            Sleep(100); //Let the program rest, otherwise it hogs cpu resources.
      }
}

BOOL WINAPI DllMain(HINSTANCE MyInstance,DWORD reason_for_call,LPVOID PointerToVoid)
{
         if (reason_for_call == DLL_PROCESS_ATTACH) CreateThread(0,0,(LPTHREAD_START_ROUTINE)&MainFunction,0,0,0);
         return true;
}

Кстати, я пытаюсь взломать HP!~ Ой, подожди, я уже это сказал, о, ну, как бы там ни было;)

Спасибо, ребята, храни вас всех!

1 Ответ

20 голосов
/ 18 мая 2011

Я думаю, вы неправильно понимаете цель Cheat Engine.

CE позволяет изменять значения, которые надежно хранятся в памяти. Например, в куче или в статических данных программы.

Например, объекты C ++ размещаются детерминированным образом и, следовательно, они никогда не перемещаются. Вот почему на них может ссылаться указатель, который остается постоянным в течение всего времени жизни объекта. Этот объект когда-то принадлежит другому. Если вы нашли указатель на объект-владелец, вы нашли то, что называется базовый указатель .

Например:

class Object
{
    bool dummy;
    int someField;
    Object* child;
};

Теперь представьте, что у вас есть вложенное дерево 3 Object. Это означает, что у вас есть корень Object (n ° 1), чей child - это другой Object (n ° 2), чей child - это другой Object (n ° 3). Представьте, что вы делаете что-то вроде этого:

int main(int argc, char** argv)
{
    Object root; // n°1
    root.child = new Object(); // n°2
    root.child->child = new Object(); // n°3

    return 0;
}

Вы заинтересованы в том, чтобы возиться со значением n ° 3 someField. Вы знаете, что адрес someField, относительно Object, равен +sizeof(bool) = 1. Так что (void*)&(object n°3) + 1 - это указатель на someField, который вы хотите.

Теперь, как найти указатель на объект № 3? Зная, что относительный адрес child равен +sizeof(bool)+sizeof(int) = 5. Мы знаем, что указатель на объект n ° 3 равен (void*)&(object n°2) + 5.

То же самое касается адреса объекта № 2, я оставлю это как упражнение.

А как насчет объекта № 1? Это не выделено в куче. Это в стеке. Дерьмо. Поэтому мы должны найти другой способ найти адрес, где хранится объект n ° 1.

Локальные переменные хранятся в стеке. В сборке они идентифицируются по их смещению относительно регистра EBP (или ESP, если функция не меняет стек). EBP - верхняя часть стека, а ESP - нижняя часть стека.

В этом примере:

function foo()
{
    int a;
    double b;
}

Когда вызывается foo, стек будет увеличен настолько, чтобы вместить a и b, то есть sizeof (int) + sizeof (double) или 12 байтов. a будет храниться в EBP - sizeof(int) = EBP - 4 (так же, как ESP + 8), а b будет храниться в EBP - sizeof(int) - sizeof(double) = EBP - 12 (так же, как ESP). Внимание! Компилятор может изменить этот порядок, поэтому порядок объявления ваших переменных не обязательно одинаков в памяти. Оптимизация также может полностью изменить это. Но давай все будем в порядке, хорошо?

Итак, вернемся к нашему основному примеру. Какие локальные переменные у нас есть? только корень. Поэтому корень будет расположен на EBP - 9 напрямую. Но это, ТОЛЬКО когда main - это функция поверх стека вызовов. Без отладчика вы не сможете этого сделать.

Предположим, что наш EBP равен 0028FF28, когда вызывается main (взято из только что скомпилированной программы на C).

корень тогда в (0x0028FF28 - 9) = 0x0028FF1F; указатель на root.child находится в (0x0028FF1F + 5) = (0x0028FF24); Следовательно, root.child расположен в * 0x0028FF24.

Указатель на root.child->child находится в (* 0x0028FF24 + 5) = (скажем, 10000) Тогда root.child->child находится на * 10000.

Наконец, root.child->child.someField находится на * 10000 + 3.

Подводя итог: вам просто нужно найти статический адрес root, чтобы найти остальные. root не находится в куче или любой другой долговременной памяти, но находится в стеке main, который длится почти всю программу, так что он почти как постоянный. CE помогает найти статический адрес путем сканирования всего пространства памяти процесса

Имея все это в виду, вы должны быть в состоянии вычислить относительный адрес hp в стеке и найти статический указатель на него (main очень, очень, очень вероятно, будет иметь статический адрес кадра каждый раз, когда вы запустить программу). Если вам нужна помощь, используйте отладчик! Я рекомендую Immunity Debugger.

...