Показано с 1 по 3 из 3
  1. #1
    Юзер Аватар для Evangard
    Регистрация
    12.01.2007
    Сообщений
    3
    Сказал(а) спасибо
    0
    Поблагодарили 0 раз(а) в 0 сообщениях

    По умолчанию Сканер памяти

    Предмет повествования состоит в изучении принципов сканирования виртуальной памяти процессов (этим занимаются такие программы как ArtMoney и др.), создании и реализации алгоритма целочисленного "универсального обманщика игр".

    Задача:
    Найти адрес переменной в адресном пространстве целевого процесса.
    Ограничения: Для простоты рассматриваются целочисленные переменные размером dword, поиск проводится по младшему байту.

    Идея:
    Организация поиска в страницах памяти, доступных для чтения и записи, целевого процесса начиная с адреса 010000h по 7FFF0000h [1]. Для получения информации о страницах памяти внешнего процесса естественно использовать VirtualQueryEx. Для чтения памяти - ReadProcessMemory.
    Поиск адресов происходит многопроходным образом, причем начальный этап отличается от остальных: сначала необходимо сохранить адреса всех байтов, имеющих заданное значение, далее сужать поиск по сохраненным адресам при изменении значения искомой переменной.
    Алгоритм верхнего уровня детализации для первого прохода выглядит так:
    1. Получить описание страницы памяти чужого процесса;
    2. ЕСЛИ страница принадлежит диапазону поиска то п. 3 ИНАЧЕ выход;
    3. ЕСЛИ страница не доступна для чтения и записи ТО п. 5;
    4. сохранить в список все адреса переменных, значения которых равны заданному;
    5. Перейти к следующей странице и п. 1;
    6. Алгоритм последующих проходов:
    7. Прочитать значение переменной по адресу из списка (в памяти исследуемого процесса);
    8. ЕСЛИ значение равно заданному ТО п. 4;
    9. Удалить адрес из списка;
    10. ЕСЛИ список не закончился ТО Перейти к адресу следующей переменной и п. 1;


    Алгоритм
    Общий алгоритм программы состоит из нескольких частей:
    Организация списка адресов.
    Так как заранее неизвестно количество найденных переменных при первом проходе (в дальнейшем оно будет уменьшаться), логично зарезервировать некоторый объем памяти, скажем 4*VARMAX, где VARMAX - это наибольшее возможное количество найденных переменных. Это число, на практике, небесконечно и определяется, с одной стороны, временем максимально долгого возможного поиска, а с другой, - достаточностью объема для проведения поиска. В среднем хватает 10*1024*1024 переменных. Причем, следует отметить, что при начальном поиске переменных со значением 0, велика вероятность нехватки указанного объема, по нескольким причинам, в том числе и из-за чтения зарезервированных областей (еще не используемых процессом), которые возвращают 0. Множитель 4 введен исходя из размера хранимого адреса переменной равного dword. Легко видеть что нет необходимости передавать всю зарезервированную память адресов сразу (это можно сделать при первом обращении к ней), т.о. можно считать подготовку списка адресов переменных завершенной:
    ;резервирование с передачей физической памяти при обращении.
    invoke VirtualAlloc,0,BSIZE,MEM_RESERVE+MEM_COMMIT,PAGE_R EADWRITE

    ;ЕСЛИ не удалось выделить память, ТО выход
    ;(далее для краткости обработка ошибок опускается)
    test eax,eax
    jz NotEnoughMem

    ;ИНАЧЕ сохранение адреса начала блока памяти.
    mov [addrbuffer],eax
    Примечание: здесь и далее программный код приводится в соответствии с синтаксисом flat assembler (fasm)[2].
    Получение Handle процесса для чтения, записи.
    Предлагается следующий путь: Сначала получим Handle окна необходимого процесса, затем получим идентификатор процесса создавшего окно, затем "откроем" процесс для проведения операций с памятью.
    ;ebx содержит адрес названия необходимого окна.
    invoke FindWindow,0,ebx

    ;создать в стеке переменную, и передать ее адрес из esp в параметры
    push eax
    ;для получения идентификатора процесса
    invoke GetWindowThreadProcessId,eax,esp
    pop eax ;вынуть из стека результат.

    ;получить Handle процесса для операций с памятью
    invoke OpenProcess,PROCESS_QUERY_INFORMATION+PROCESS_VM_O PERATION+PROCESS_VM_READ+PROCESS_VM_WRITE,0,eax
    mov [hProcess],eax ;сохранить Handle открытого процесса.
    Организация считывания целевых (RW) страниц.
    Итак, по порядку: получаем адрес начала и размер текушей страницы памяти, проверяем права доступа на чтение и запись. Создаем блок памяти требуемого размера в текущем адресном пространстве (для копирования), читаем блок из исследуемого процесса в созданный блок. После отработки поиска байтов освобождаем уже не нужный блок.
    ;Сначала [fmbi.BaseAddress] = начальному адресу 10000h,
    ;а [fmbi.RegionSize] = 0, BaseAddress+RegionSize = адресу первого блока
    getblock:
    ;в дальнейшем BaseAddress+RegionSize = адресу следующего блока
    mov eax,[fmbi.BaseAddress]
    add eax,[fmbi.RegionSize]

    mov [address],eax
    ;прочитать состояние блока
    invoke VirtualQueryEx,[hProcess],[address],fmbi,MBIsz
    cmp [fmbi.Protect],PAGE_READWRITE ;проверить доступ
    jne getblock ;ЕСЛИ нет возможности чтения и записи, ТО перейти к новому блоку

    ;создать блок нужного размера блока
    invoke VirtualAlloc,0,[fmbi.RegionSize],MEM_COMMIT,PAGE_READWRITE
    mov [buffer],eax

    ;скопировать в него память исследуемого процесса
    invoke ReadProcessMemory,[hProcess],[fmbi.BaseAddress],eax,[fmbi.RegionSize],BytesRead

    ;... осушествить поиск и сохранение адресов

    ;освободить блок
    invoke VirtualFree,[buffer],0,MEM_RELEASE
    Сохранение адресов искомых переменных.
    Запустить сканирование до совпадения байта или конца строки, получить адрес совпадающего байта в пространстве искомого процесса (учитывая то, что поиск ведется в созданном блоке текущего процесса), сохранить адрес в списке.
    ;вход:
    ; ecx = edx = количеству прочитанных байт
    ; esi содержит адрес блока (в текущем адресном пространстве)
    ; edi - адрес списка
    ; ebx - адрес начала блока в адресном пространстве исследумого процесса

    lfind:
    xchg edi,esi
    repne scasb ;поиск до совпадения al с байтом из строки edi
    xchg edi,esi

    jne getblock;ЕСЛИ ничего не найдено ТО к следующему блоку

    ;Адрес = Адрес начала блока в исследуемом процессе + смещение в текущем
    ;Смещение в текущем = количество прочитанных байт edx - оставшиеся байты ecx
    neg ecx ;изменить знак
    lea eax,[edx+ecx] ;получить смещение
    dec eax ;учесть что считаем с 0, а не с 1
    add eax,ebx ;добавить [fmbi.BaseAddress]
    stosd ;сохранить адрес в список адресов

    neg ecx ;проверить последний ли это байт
    jz getblock ;ЕСЛИ да ТО перейти к следующему блоку
    jmp lfind ;ИНАЧЕ проболжать поиск в текущем блоке
    Примечание: В [3] использование префиксов описано с ошибками.
    Определение действительных адресов искомых переменных (дальнейший поиск).
    Получить адрес из списка, прочитать память процесса, сравнить прочитанное значение с заданым, если 1= то удалить адрес.
    Последний раз редактировалось IMPERIAL; 16.03.2009 в 17:22.
    Оставь надежду
    Всяк сюда попавший

  2. #2
    Юзер
    Регистрация
    01.05.2007
    Сообщений
    4
    Сказал(а) спасибо
    0
    Поблагодарили 0 раз(а) в 0 сообщениях

    По умолчанию

    это писал не ты.

  3. #3
    Юзер
    Регистрация
    31.12.2006
    Сообщений
    11
    Сказал(а) спасибо
    0
    Поблагодарили 0 раз(а) в 0 сообщениях

    Angry

    Ага, скопировал статью с васма и хочет чтоб похвалили



Социальные закладки

Социальные закладки

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •