Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Поиск в памяти процесса


Автор: Townsmen 8.6.2012, 09:51
Доброго времени суток!
Есть такое консольное приложение, оно ищет в процессе int и в результате выдает адреса найденных совпадений:
Код

#include <Windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <iostream>
#include <vector>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
using namespace std;//использование пространства имён std
#define PROGRAMM_NAME "Калькулятор Плюс"
vector<LPVOID> myvector; //вектор для хранения в нем адресов
//получаем базовый адресс процесса
LPVOID GetBaseAddress(HANDLE hProcess)
{
    MODULEINFO mInfo;//структура с информацией о процессе
    //получаем базовый адрес процесса
    if (GetModuleInformation(hProcess, NULL, &mInfo, sizeof(mInfo)))
        return mInfo.EntryPoint;
    else
        return NULL;
}
//получить размер используемой памяти приложения(в байтах)
DWORD GetMemorySize(HANDLE hProc)
{
    //структура с информацией о процессе
    PROCESS_MEMORY_COUNTERS pmcInfo;
    //получаем информацию о процессе
    if (GetProcessMemoryInfo(hProc, &pmcInfo, sizeof(pmcInfo)))
        return (DWORD)pmcInfo.WorkingSetSize;
    else
        return 0;
}
//функция поиска в массиве считаных байт
int mem_sub(void * src, size_t src_sz, void * dst, size_t dst_sz, LPBYTE adres)
{
    LPVOID lpadr;
    for (size_t i = 0; i < src_sz - dst_sz + 1; i++)
    {
        if (!memcmp((char *)src + i, dst, dst_sz))
        {
            lpadr = (LPVOID)adres;
            myvector.push_back (lpadr);//записываем адрес найденого совпадения
        }
        adres++;
    }
    
   return 0;
}

int main()
{
    setlocale(LC_ALL, "Russian");//устанавливаем русский язык для вывода
    HWND hWnd = FindWindow(NULL, TEXT(PROGRAMM_NAME));//ищем окно
    if (!hWnd)
    {
        MessageBoxA(0,"No work process","Fail",0);
        ExitProcess(0);
    } else {
    //получаем ID процесса
    DWORD dwPID;
    GetWindowThreadProcessId(hWnd, &dwPID);
    if (!dwPID)
    {
        MessageBoxA(0,"No give ID","Fail",0);
    }
    HANDLE hProcess;
    MEMORY_BASIC_INFORMATION mbi;//--Выделения фрагмента памяти
    SYSTEM_INFO msi;// Содержит сведения о диапазоне страниц в виртуальном адресном пространстве нашего процесса.
    ZeroMemory(&mbi, sizeof(mbi));//затирка содержимого памяти.
    GetSystemInfo(&msi);//Получаем системную информацию 
    hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwPID);
    if (!hProcess)
    {
       MessageBoxA(0,"OpenProcess!!!","Fail",0);
       ExitProcess(0);
    }
    cout << "Ищем в программе: "<< PROGRAMM_NAME <<"\n";
    //получаем размер занимаемой памяти
    DWORD dwMemSize = GetMemorySize(hProcess);
    LPVOID dwStart = GetBaseAddress(hProcess);//стартовый адрес в поиске
    DWORD start = (DWORD)dwStart;//стартовый адрес в поиске
    const int rSize = 128;//размер считываемых байт
    byte lpData[rSize];//массив для хранения считанных байт
    SIZE_T lpRead = 0;//размер прочитанных байт
    int value;//искаемое число
    cout << "Введите число для поиска: ";
    cin >> value;

    for(LPBYTE lpAddress = (LPBYTE)msi.lpMinimumApplicationAddress;
        lpAddress <= (LPBYTE)msi.lpMaximumApplicationAddress;
        lpAddress += mbi.RegionSize){ //идем по регионам памяти
            if(VirtualQueryEx(hProcess, lpAddress, &mbi, sizeof(mbi))){//Узнаем о текущем регионе памяти.
                if((mbi.Protect & PAGE_READWRITE) || (mbi.Protect & PAGE_WRITECOPY)){// Если он доступен для записи, работаем с ним.
                    if(mbi.RegionSize>= rSize) {//проверяем что бы регион не был меньше 128
                        for(unsigned int t=0; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128
                            if (ReadProcessMemory(hProcess, (LPBYTE)lpAddress, &lpData, rSize, &lpRead)){ //считываем по 128
                                int pos = mem_sub(lpData, sizeof(lpData), &value, sizeof(value),lpAddress);//исчем в считанои массиве
                                lpAddress+=0x00000080; //переходим на 128 адресов    
                        }}}}}}
    CloseHandle(hProcess);
    if((int) myvector.size() > 0) {
        cout << "\nНайдено " << (int) myvector.size() << " чисел.\n";
        cout << "Адреса: \n";
        for (unsigned int i=0; i<myvector.size(); i++) {
            cout <<"0x"<< myvector[i] << "\n";
        }
    } else {
        cout << "Ничего не найдено!";
    }
    MessageBoxA(0,"Search complete!","Complete",0);
    return 0;
    }
}
 
Но при тестировании приложения, оно выдает немного разное количество найденных чисел чем ArtMoney. Например: я ищу в программе "Калькулятор плюс" число 45, в результате ArtMoney нашло 7 адресов с числом 45, а єта программа 12 с числом 45.
Почему такие результаты? мне кажется программа проверяет больше диапазонов адресов чем ArtMoney, или у меня неправильный алгоритм прохождения по диапазонам или неправильно использую VirtualQueryEx

Автор: feodorv 8.6.2012, 10:15
Цитата(Townsmen @  8.6.2012,  10:51 Найти цитируемый пост)
в результате ArtMoney нашло 7 адресов с числом 45, а єта программа 12 с числом 45.

Можно попросить список найденных адресов (как программой, так и артмани)?

Автор: Townsmen 8.6.2012, 22:38
Цитата(feodorv @  8.6.2012,  10:15 Найти цитируемый пост)
Можно попросить список найденных адресов (как программой, так и артмани)?

я проверял адреса, приложение нашло все те самые что артмани и еще 5 адресов. Все зависит от числа которое ищем, в одних случаях все адреса одинаковые. В конце поиска программы выводятся все адреса найденные в консоль.  

Автор: feodorv 8.6.2012, 22:52
Я не просто так спрашиваю. Я хочу убедиться, что адреса выровнены или не выровнены по 4-х байтной границе.

Повторяю просьбу:
Цитата(feodorv @  8.6.2012,  11:15 Найти цитируемый пост)
Можно попросить список найденных адресов (как программой, так и артмани)? 


Автор: Townsmen 8.6.2012, 23:01
Цитата(feodorv @  8.6.2012,  22:52 Найти цитируемый пост)
Я хочу убедиться, что адреса выровнены или не выровнены по 4-х байтной границе.

как это выровнены? незнаю...

Автор: feodorv 9.6.2012, 00:07
Просто показать списки можно?
А то у меня начинает складываться такое чувство, что я Вас прошу выдать военную тайну.... smile 

Автор: Townsmen 9.6.2012, 00:12
можно, просто я неправильно понял что с меня требуется... Сейчас скриншоты сделаю или текстом написать?

Добавлено через 6 минут и 59 секунд
user posted image

Автор: feodorv 9.6.2012, 02:54
Спасибо, так пойдёт!
Увы, на вид всё выравнено (addr % 4 даёт 0). То есть, действительно, находит больше. Было бы неплохо, если бы Вы вывели на печать значение mbi.Type для каждого найденного адреса, возможно, определилась бы какая-нибудь закономерность....

Цитата(Townsmen @  8.6.2012,  10:51 Найти цитируемый пост)
                if((mbi.Protect & PAGE_READWRITE) || (mbi.Protect & PAGE_WRITECOPY)){// Если он доступен для записи, работаем с ним.

Мне кажется, это имеет смысл проверять, если mbi.State есть MEM_COMMIT.

Автор: GremlinProg 9.6.2012, 06:55
Цитата(Townsmen @  8.6.2012,  11:51 Найти цитируемый пост)
искаемое число

 smile 

Цитата(Townsmen @  9.6.2012,  02:12 Найти цитируемый пост)
Сейчас скриншоты сделаю

а как так получилось, что одно из попаданий лежит в обеих программах в соседних 4-байтовых ячейках:
Цитата

3A00C0
3A00C4

версии программы совпадают?
Цитата(Townsmen @  8.6.2012,  11:51 Найти цитируемый пост)
Почему такие результаты? мне кажется программа проверяет больше диапазонов адресов чем ArtMoney

если проверять все адреса процесса, тогда надо сделать исключение по крайней мере для служебных диапазонов: секции и заголовки PE, в них-то искать ничего не надо

я так думаю )

Добавлено через 1 минуту и 34 секунды
Цитата(GremlinProg @  9.6.2012,  08:55 Найти цитируемый пост)
секции и заголовки PE

вернее, конечно не сами секции, а заголовки этих секций

Автор: Townsmen 9.6.2012, 09:55
Цитата(GremlinProg @  9.6.2012,  06:55 Найти цитируемый пост)
а как так получилось, что одно из попаданий лежит в обеих программах в соседних 4-байтовых ячейках:

я даже сам незнаю почему так получилось
Цитата

003А00С4   -это 5-й адресс в ArtMoney
003А00С0   - а это 5-й в проге

Если допустить что произошла ошибка в нумерации адресов, то дальше все адреса должны не совпадать, а они совпадают. Получается только 1 адрес не на своем месте чего то. 
 
Цитата(feodorv @  9.6.2012,  02:54 Найти цитируемый пост)
Мне кажется, это имеет смысл проверять, если mbi.State есть MEM_COMMIT

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

Автор: Townsmen 10.6.2012, 00:52
Сделал еще вывод mbi.State и mbi.Type но никакой закономерности не вижу, только что mbi.State для всех адресов неизменная. Последний адрес в артмани вообще не совпал smile у меня уже подкралась мысль, может это артмани некорректно работает( все может быть) версия 7.28
user posted image

Автор: volatile 10.6.2012, 01:39
Цитата(Townsmen @  10.6.2012,  00:52 Найти цитируемый пост)
может это артмани некорректно работает

Ха, ха, может быть конечно...
Но прежде чем искать соломинку в "чужом глазу", неплохо бы убрать "брёвна" из "своего глаза"
Цитата(Townsmen @  8.6.2012,  09:51 Найти цитируемый пост)
                        for(unsigned int t=0; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128

Простой пример, допустим RegionSize = 256, цикл запишется так:
for(t=0; t <= (256/128); ...)
т.е
for(t=0; t <= 2); ...)
т.е
цикл будет отработан 3 раза
3*128=384 (напомню, это при размере 256).

Выход за пределы, как минимум.

Это только самое первое "бревно", валяющеея на поверхности.
 smile 

Автор: Townsmen 10.6.2012, 07:55
Цитата(volatile @  10.6.2012,  01:39 Найти цитируемый пост)
Это только самое первое "бревно", валяющеея на поверхности.

Уже исправил, что еще не так?
Саме больше на мой взгляд ошибок в этом участке кода:
Код

for(LPBYTE lpAddress = (LPBYTE)msi.lpMinimumApplicationAddress;
        lpAddress <= (LPBYTE)msi.lpMaximumApplicationAddress;
        lpAddress += mbi.RegionSize){ //идем по регионам памяти
            if(VirtualQueryEx(hProcess, lpAddress, &mbi, sizeof(mbi))){//Узнаем о текущем регионе памяти.
                if((mbi.Protect & PAGE_READWRITE) || (mbi.Protect & PAGE_WRITECOPY)){// Если он доступен для записи, работаем с ним.
                    if(mbi.RegionSize>= rSize) {//проверяем что бы регион не был меньше 128
                        for(unsigned int t=1; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128
                            if (ReadProcessMemory(hProcess, (LPBYTE)lpAddress, &lpData, rSize, &lpRead)){ //считываем по 128
                                int pos = mem_sub(lpData, sizeof(lpData), &value, sizeof(value),lpAddress);//исчем в считанои массиве
                                lpAddress+=0x00000080; //переходим на 128 адресов    
                        }}}}}}

Автор: volatile 10.6.2012, 08:57
Цитата(Townsmen @  10.6.2012,  07:55 Найти цитируемый пост)
Саме больше на мой взгляд ошибок в этом участке кода:

Новички почему-то любят писать сложные конструкции, наверно думают что так поступают крутые программеры.
Так вот, крутые программеры, такие невменяемые конструкции не пишут.
Я например, в силу своей природной тупости, не могу охватить весь этот участок мысленным взором.

Цитата(Townsmen @  10.6.2012,  07:55 Найти цитируемый пост)
for(LPBYTE lpAddress = (LPBYTE)msi.lpMinimumApplicationAddress;
        lpAddress <= (LPBYTE)msi.lpMaximumApplicationAddress;
        lpAddress += mbi.RegionSize){ //идем по регионам памяти
            if(VirtualQueryEx(hProcess, lpAddress, &mbi, sizeof(mbi))){//Узнаем о текущем регионе памяти.
                if((mbi.Protect & PAGE_READWRITE) || (mbi.Protect & PAGE_WRITECOPY)){// Если он доступен для записи, работаем с ним.
                    if(mbi.RegionSize>= rSize) {//проверяем что бы регион не был меньше 128
                        for(unsigned int t=1; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128
                            if (ReadProcessMemory(hProcess, (LPBYTE)lpAddress, &lpData, rSize, &lpRead)){ //считываем по 128
                                int pos = mem_sub(lpData, sizeof(lpData), &value, sizeof(value),lpAddress);//исчем в считанои массиве
                                lpAddress+=0x00000080; //переходим на 128 адресов    
                        }}}}}}


Зачем переменная цикла прибавляется два раза, в разных местах?
Вы как автор программы, можете объясить?

Автор: Townsmen 10.6.2012, 13:11
Эту часть кода я взял с http://habrahabr.ru/post/93437/. Но он там был нерабочий и мне пришлось немного его самому переделывать (получается цикл в цикле). Если честно я немного удивлен как этот код работает, он наверное пропускает некоторые участки памяти, но то что нужно найти он находит smile. Я нигде не могу найти рабочий алгоритм прохождения по всем адресам (с правом записи), а написать самому что-то не получается. несколько раз пробовал но программа очень долго работает и неправильные результаты выдает. Структура процесса имеет начальный адрес, конечный адрес, регионы адресов размером 128, 256, 512, 1024 ... и незнаю еще какие там бывают. наверное 32 и 64 байта тоже есть регионы. а между регионами участков с адресами нету?

Автор: volatile 10.6.2012, 17:56
К слову, еще баг, если например будем искать строку, и граница 128 байтного блока (кстати, почему именно 128?) придется на эту строку, то он ее не найдет.
Цитата(Townsmen @  10.6.2012,  13:11 Найти цитируемый пост)
но то что нужно найти он находит 

Ну а в чем тогда проблема-то, если все так замечателно? smile 

Цитата(Townsmen @  10.6.2012,  13:11 Найти цитируемый пост)
 Я нигде не могу найти рабочий алгоритм прохождения по всем адресам (с правом записи

Цитата(Townsmen @  10.6.2012,  07:55 Найти цитируемый пост)
(mbi.Protect & PAGE_WRITECOPY)){

Кстати попробуйте убрать эту часть, PAGE_WRITECOPY - это не право записи. Имхо, это копирование блока, и запись в этот откопированный блок, то есть запись в копию, которая не при делах.

Во внутреннем цикле введите еще одну переменную
LPBYTE temp_adr = lpAddress, (или какое вам нравиться, имя)
перед этой строкой: 
Цитата(volatile @  10.6.2012,  08:57 Найти цитируемый пост)
for(unsigned int t=1; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128

И ниже все lpAddress, замените на эту переменную.
Потому-что нельзя менять переменную цикла, в двух местах.

Автор: Dem_max 11.6.2012, 04:48
посмотри еще тут
http://forum.tuts4you.com/topic/16209-how-to-search-bytes-in-process/#entry81108

Автор: xvr 11.6.2012, 10:34
Еще замечание - все адреса, где ваша программа расходится во мнениях с артмани принадлежат области данных исследуемой программы (скорее всего стеку и/или куче). А содержимое таких областей имеет тенденцию меняться со временем. Попробуйте запустить артмани и вашу программу 2 раза (по очереди)

Автор: Townsmen 11.6.2012, 10:56
Цитата(volatile @  10.6.2012,  17:56 Найти цитируемый пост)
К слову, еще баг, если например будем искать строку, и граница 128 байтного блока (кстати, почему именно 128?) придется на эту строку, то он ее не найдет.

для строки 128 байт массив 100% не годится, там лутше сразу регионом считывать.
Цитата(volatile @  10.6.2012,  17:56 Найти цитируемый пост)
Во внутреннем цикле введите еще одну переменную
LPBYTE temp_adr = lpAddress, (или какое вам нравиться, имя)
перед этой строкой: 
Цитата(volatile @  10.6.2012,  08:57 Найти цитируемый пост)
for(unsigned int t=1; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128

И ниже все lpAddress, замените на эту переменную.
Потому-что нельзя менять переменную цикла, в двух местах.

Вы читаете мои мысли, после того как Вы написали что lpAddress прибавляю в 2 раза в цикле, то я потом немного помозговал и переделал:
Код

LPBYTE subAddress;
for(LPBYTE lpAddress = (LPBYTE)msi.lpMinimumApplicationAddress;
        lpAddress <= (LPBYTE)msi.lpMaximumApplicationAddress;
        lpAddress += mbi.RegionSize){ //идем по регионам памяти
            if(VirtualQueryEx(hProcess, lpAddress, &mbi, sizeof(mbi))){//Узнаем о текущем регионе памяти.
                if((mbi.Protect & PAGE_READWRITE) || (mbi.Protect & PAGE_WRITECOPY)){// Если он доступен для записи, работаем с ним.
                    if(mbi.RegionSize>= rSize) {//проверяем что бы регион не был меньше 128
                        subAddress = lpAddress;
                        for(unsigned int t=1; t <= (mbi.RegionSize/rSize); t++){//делим регион на части по 128
                            if (ReadProcessMemory(hProcess, subAddress, &lpData, rSize, &lpRead)){ //считываем по 128
                                int pos = mem_sub(lpData, sizeof(lpData), &value, sizeof(value),subAddress);//исчем в считанои массиве
                                subAddress+=0x00000080; //переходим на 128 адресов
                            }}}}}}

и еще уберу (mbi.Protect & PAGE_WRITECOPY)


Dem_max, спасибо за ссылку нужно будет разобраться в немного в коде

Автор: Townsmen 11.6.2012, 11:47
Сделал изменения и программа уже более точно начала искать, уже ближе к адресам артмани. Наверное нужно переделать что бы она считывала весь регион сразу и проверяла. Смотрел http://forum.tuts4you.com/topic/16209-how-to-search-bytes-in-process/#entry81108
Вижу здесь записывают сразу регион:
Код

 char* szMemDump = (char*)malloc(mbi.RegionSize+1);

А это для поиска строки может пойдет, но для поиска чисел некоректно:
Код

if( (mbi.Protect != PAGE_NOACCESS) && (mbi.State == MEM_COMMIT) )

Автор: 500mhz 11.6.2012, 12:40
Что то вы в дебри полезли, напомню (из умной книжки)

Цитата

В настоящее время системные DLL занимают адреса в памяти от 0x70000000 до 0x78000000


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)