Адреса в OllyDbg меняются при перезагрузке программы

Это мой первый пост, и я новичок в сборке и отладке, так что поддержите меня, пожалуйста.

Я пытался внедрить некоторый код (небольшой вызов MessageBoxA) в исполняемый файл Блокнота Windows 7. Однако столкнулся с проблемой адресов. Сначала я открыл исполняемый файл в OllyDbg, затем перешел к строке, содержащей ASCII-текст «notepad.pdb». Затем я помещаю под ней строку ASCII (например, «ИНЖЕКЦИОННЫЙ БЛОКНОТ»). Далее, ниже, я ввел этот ассемблерный код:

PUSH 0
PUSH address_of_ASCII_string ; In this case, 00A6B668C
PUSH address_of_ASCII_string ; In this case, 00A6B668C
PUSH 0
CALL MessageBoxA

Далее я перешел к первой строке кода в программе (просто щелкнув правой кнопкой мыши и нажав Go to Origin (или просто нажав * на цифровой клавиатуре)) Затем я заменил первую строку с инструкцией JMP на адрес первой PUSH 0 в моем введенном коде. Затем я помещаю инструкцию, которую я заменил, в конец введенного кода. После этого я помещаю инструкцию JMP в строку кода после моей инструкции JMP, которая переходит к моему внедренному коду (да, я только что описал кодовую пещеру или что-то в этом роде). Все работает нормально, когда я запускаю его. Однако когда я сохраняю измененный код в новый исполняемый файл и снова запускаю его с помощью OllyDbg, он не работает. Когда я пытаюсь сослаться на введенную строку ASCII, адрес совершенно неверен. Пример на картинках ниже:

Как видите, я запихиваю строку в стек, но когда я снова загружаю измененную программу в отладчик, адрес строки меняется, а мой код — нет. Поэтому, когда я вызываю функцию MessageBoxA, она выдает ошибку, потому что я загрузил неправильный адрес для аргументов Text и Caption. Как я могу это исправить?


person DD314    schedule 23.12.2016    source источник
comment
Ну да, вы пытаетесь использовать абсолютные адреса вместо относительных. Базовый адрес исполняемого файла рандомизируется каждый раз при запуске процесса, поэтому фиксированный адрес не будет действительным для нескольких вызовов. (Также: добро пожаловать в Stack Overflow! Спасибо за хорошо заданный и красиво представленный вопрос.)   -  person Cody Gray    schedule 23.12.2016
comment
Спасибо. Как бы я тогда использовал относительный адрес?   -  person DD314    schedule 23.12.2016
comment
Я говорю, что вы пытаетесь не вводить код, а исправлять exe. вам, конечно, нужно использовать не относительные, а абсолютные адреса - но все абсолютные адреса должны быть описаны в разделе .relocs. один из способов заставить ваш патч работать - отключить relocs на exe. для этого вам нужно установить флаг IMAGE_FILE_RELOCS_STRIPPED в IMAGE_FILE_HEADER.Characteristics - после этого exe всегда будет загружаться по постоянному адресу, а возможные хардкодные абсолютные адреса   -  person RbMm    schedule 23.12.2016
comment
Я попробовал предложение RbMm, и это сработало! Я просто открыл блокнот в CFF Explorer и перешел в раздел «Заголовок файла». Затем я отредактировал запись «Характеристики», установив флажок «Информация о перемещении удалена из файла». Я предполагаю, что это заставляет исполняемый файл использовать абсолютную адресацию вместо использования базового адреса, верно? Сломает ли эта модификация что-либо в исполняемом файле? Это не ломает блокнот, но моя цель - прикрепить некоторый код к explorer.exe. Я не знаю, сломает ли это проводник или нет. Тем не менее, это работает для блокнота. Спасибо.   -  person DD314    schedule 23.12.2016
comment
Любые другие предложения?   -  person DD314    schedule 23.12.2016
comment
@ DD314 DD314 - я предполагаю, что это заставляет исполняемый файл использовать абсолютную адресацию вместо использования базового адреса, верно? - нет. вы ошибаетесь. это отключить ASLR. exe всегда будет загружаться по собственному базовому адресу. это ничего не ломает ни в одном exe. но вы способ исправления ..   -  person RbMm    schedule 23.12.2016


Ответы (1)


Вы столкнулись с эффектами ASLR. Короче говоря, это означает, что исполняемый файл, работающий в ОС (в данном примере Windows), не будет иметь один и тот же базовый адрес при нескольких запусках.

Таким образом, есть несколько способов внедрить ваш код в другой двоичный файл, здесь я обращусь к 2, и я также догадаюсь (после прочтения комментариев), что вы пытаетесь исправить двоичный файл, который находится на диске.

  1. Исправление бинарника на диске:

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

    Допустим, у вас есть строка со смещением 0x600 от базы изображения, в случае, если исполняемый файл отображается на предпочитаемый базовый адрес (обычно 0x00400000), строка будет храниться по адресу 0x00400000. Ваш компилятор свяжет файл с адресом 0x00400000 + 0x600, поэтому 0x00400600. Что же происходит, когда исполняемый файл загружается по другому базовому адресу? В этом случае исполняемый загрузчик Windows добавит смещение базового адреса (фактически отображаемого минус предпочтительный базовый адрес) к каждой записи о перемещении (в приведенном выше примере он потребуется). Таким образом, если исполняемый файл будет загружен в 0x00500000, загрузчик добавит 0x00100000 к этой записи перемещения, ведущей к абсолютному адресу 0x00500600.

    б. Второй способ — добавить запись о перемещении в двоичный файл. Таким образом, в отличие от способа, описанного в (а), вы не повредите двоичный файл, а только добавите запись о перемещении, которая при загрузке исполняемого файла загрузчик изменит адрес на правильный (если вы добавили правильный Вход).

    в. Напишите код, независимый от позиции, и исправьте двоичный файл, используя этот код. Пример:

    sub     esp, 10*4
    mov     byte [esp], 0x68 ; 'h'
    mov     byte [esp + 1], 0x69 ; 'i'
    mov     byte [esp + 2], 0x00 ; null byte
    mov     byte [esp + 3], 0x79 ; 'y'
    mov     byte [esp + 4], 0x6f ; 'o'
    mov     byte [esp + 5], 0x75 ; 'u'
    mov     byte [esp + 6], 0x00 ; null byte
    mov     eax, esp
    push    0
    push    eax
    add     eax, 3
    push    eax
    push    0
    call    [MessageBoxA]  
    

    Этот код запишет 2 необходимые строки в стек и поместит указатели на строки в стеке, таким образом, код не нуждается в каком-либо перемещении, поскольку это часть независимого кода.

  2. Патч бинарника в памяти:

    а. Позиционно-независимый код (см. выше)

    б. Используйте VirtualAllocEx, это API после его вызова вернет адрес, по которому вы можете писать, таким образом, вы просто сохраните сопоставленный адрес в памяти и знаете, куда и как внедрить свой код.

person papadp    schedule 23.12.2016
comment
Спасибо за очень хороший ответ. Я либо собираюсь использовать вариант C, либо вариант B. Однако как мне добавить запись о перемещении в двоичный файл? Я понятия не имею, как это сделать. - person DD314; 23.12.2016
comment
Я бы не рекомендовал это, так как это не самый тривиальный способ. Короче говоря, вы найдете каталог перемещения. В каталоге перемещений вы найдете таблицы перемещений для каждого раздела / 1 КБ в исполняемом файле, вы найдете таблицу, заполненную записями, каждая запись сообщает вам смещение от начала определенного фрагмента раздела / 1 КБ и тип перемещения. Подробную информацию можно найти здесь: msdn.microsoft.com/en-us /библиотека/ms809762.aspx - person papadp; 24.12.2016