Как я могу найти последовательности байтов в памяти на коробке Windows XP / 7? - PullRequest
2 голосов
/ 25 апреля 2011

Проблема: я работаю над проектом для школы (мой выбор), который представляет собой загрузчик программ / инжектор DLL, идея которого я изначально нашел здесь , модифицированный в соответствии с моими потребностями и преобразованный ASM-части DLL для расширенного ASM, который будет компилироваться с GCC вместо Visual Studio. Вместо того, чтобы печатать счет пинбола в окне консоли, я загружаю написанную мной программу, которая принимает данные от пользователя и записывает их в файл. Загрузчик внедряет DLL с функцией, которая перенаправляет ввод пользователя, ранее предназначенный для файла, в ящик сообщений и записывает мою собственную строку в файл.

Это работает на моей машине, однако у меня есть опасения по поводу переключения платформы, потому что мой профессор должен скомпилировать работу на своей машине, поэтому вполне возможно, что адрес 0x004014A6, который в настоящее время содержит инструкцию для CALL <some address>, который записывает эту строку в файл (фактический код: ofile << user_input;) не будет содержать ничего похожего на то, что скомпилировано на другом компьютере, но все равно будет вызывать эту функцию, которая записывает строку в файл .

То, что я хочу сделать, это динамически определять, каким будет этот адрес, в отличие от жесткого кодирования адреса. Я думаю, что я могу сделать это, используя GetProcAddress для функции, которая вызывается для получения адреса, затем создать массив для хранения байтов, представляющих CALL <that function>, и искать побайтно в памяти где-то там, где я ожидаю найти этот вызов сделать, взять адрес и работать оттуда.

Хотя я точно не знаю, как это сделать.

ОСНОВНОЙ ВОПРОС: Как я могу отсканировать диапазон адресов памяти и сравнить содержимое с элементами массива?

Другими словами, я хочу включить в мою DLL функцию, которая читает байты по произвольному адресу в памяти и сравнивает его с ожидаемой последовательностью. Как я могу просто произвольно прочитать содержимое адресов памяти в определенном процессе?

Подозрения: мне нужно знать начальный и конечный адреса, где происходит выполнение исходной программы. Как я могу получить диапазон между начальным и конечным адресами? (Это похоже на настоящее препятствие. Остальное я, вероятно, могу получить, зная только, как получить начальный и конечный адреса процессов.)

Ответы [ 2 ]

0 голосов
/ 20 августа 2013

Если вы используете Python, возможно, ptrace может помочь.Он кросс-платформенный и может быть установлен из пипса.Вот фрагмент кода для Unix, который я взял здесь: http://sixserv.org/2010/07/26/memory-debugging-or-a-universal-game-trainer-with-python-and-ptrace/

def search_memory_locations(pid, max_memory, search_value):
    child_pid = os.fork()
    if child_pid == 0: # search within forked process:
        locations = list()
        prev_locations = read_locations()

        dbg = PtraceDebugger()
        process = dbg.addProcess(pid, False)
        memory_mappings = readProcessMappings(process)

        print "\x1B[?25l", # deactivate cursor (^_^)
        for memory_mapping in memory_mappings:
            # only search in read/writable memory areas within range...
            if "rw" in memory_mapping.permissions and memory_mapping.end <= max_memory:
                for loc in range(memory_mapping.start, memory_mapping.end):
                    value = process.readBytes(loc, 1)
                    if value[0] == search_value:
                        print "search memory area[0x%08X-0x%08X] address[0x%08X] value[0x%02X (%03d)]   \r" % (memory_mapping.start, memory_mapping.end, loc, ord(value), ord(value)),

                        if prev_locations and len(prev_locations) > 0 and not loc in prev_locations:
                            continue # skip prev not found locations

                        locations.append(loc)
        print "\x1B[?25h", # activate cursor
        dbg.quit()
        write_locations(locations)
        sys.exit()

    return child_pid # don't really need this

Если вы используете C / C ++, вот функция, специфичная для Windows, которую я использовал ранее из ITH (http://code.google.com/p/interactive-text-hooker/):

DWORD SearchPattern(DWORD base, DWORD base_length, LPVOID search, DWORD search_length) //KMP
{
    __asm
    {
        mov eax,search_length
alloc:
        push 0
        sub eax,1
        jnz alloc

        mov edi,search
        mov edx,search_length 
        mov ecx,1
        xor esi,esi
build_table:
        mov al,byte ptr [edi+esi]
        cmp al,byte ptr [edi+ecx]
        sete al
        test esi,esi
        jz pre
        test al,al
        jnz pre
        mov esi,[esp+esi*4-4]
        jmp build_table
pre:
        test al,al
        jz write_table
        inc esi
write_table:
        mov [esp+ecx*4],esi

        inc ecx
        cmp ecx,edx
        jb build_table

        mov esi,base
        xor edx,edx
        mov ecx,edx
matcher:
        mov al,byte ptr [edi+ecx]
        cmp al,byte ptr [esi+edx]
        sete al
        test ecx,ecx
        jz match
        test al,al
        jnz match
        mov ecx, [esp+ecx*4-4]
        jmp matcher
match:
        test al,al
        jz pre2
        inc ecx
        cmp ecx,search_length
        je finish
pre2:
        inc edx
        cmp edx,base_length //search_length
        jb matcher
        mov edx,search_length
        dec edx
finish:
        mov ecx,search_length
        sub edx,ecx
        lea eax,[edx+1]
        lea ecx,[ecx*4]
        add esp,ecx
    }
}
0 голосов
/ 30 апреля 2011

Если версия программы, на которую вы нацелены, скоро не изменится, вы можете использовать VA (виртуальный адрес) = RVA (относительный виртуальный адрес) + модуль Базовый адрес загрузки (который можно получить с помощью GetModuleHandle), чтобы получитьадрес, который не подведет в разных системах.Если версия меняется, то вы смотрите на сканер подписиОднако они не являются надежными, так как шаблоны, которые вы сканируете, могут радикально меняться от одной сборки к другой.Любой необходимый диапазон данных может быть получен из PE целевого приложения, который затем может быть использован для временного применения привилегий чтения к разделу .code, что позволяет вам эффективно проходить через него (не так эффективно было использовать * 1003).*).Вот небольшая библиотека sigscanner, далее внизу также ссылка на источник для простого сканера sig: http://www.blizzhackers.cc/viewtopic.php?f=182&t=478228&sid=55fc9a949aa0beb2ca2fb09e933210de

...