Внедрение кода в ехе-файл в конец секции c добавлением API-функций. Часть 6

Дата публикации 5 апр 2019 | Редактировалось 17 май 2019
Общие сведения
При внедрении как внешнего кода, так и тем более дополнительных функций в этом коде, сначала необходимо выяснить размер секции кода и количество свободных в ней байт. Даже для обычных учебных программ свободного места в секции для внедрения функций может уже и не хватать.
Внедрение новых API-функций в чужой код не очень сильно отличается от внедрения команд. При внедрении API-функций необходимо не только знать количество и назначение входящих в них параметров, но и как эти параметры отображаются в окне отладчика. Для этих целей в зависимости от задачи, проще всего, написать отдельную программу с использованием необходимых API-функций. Затем откомпилировать такую программу, а потом открыть ее ехе-файл в отладчике и проанализировать их использование. После чего можно приступать и к внедрению своей программы в чужой код. В учебных целях в качестве чужой программы тоже будет применяться написанная нами программа.
При использовании отладчика x64Dbg нет необходимости вызывать, затем анализировать таблицу импорта адресов внедряемых функций, и вставлять эти адреса вместо названий функций, что сильно упрощает алгоритм внедрения.

Внедрение кода с добавлением API-функций
Предположим, что существует программа, написанная в среде masm64 с использованием команд SSE, которая вычисляет математическое уравнение. В эту программу необходимо внедрить свое сообщение функцией MessageBox без изменения функционала. Внедрение кода с изменением функционала было выполнено в предыдущей главе.
Рассмотрим основную программу (программа 5.1), в которую внедрим функцию MessageBox с соответствующим сообщением.

Программа 5.1.
Числа {a,b,c,d} заданные массивом и имеют размерность Real8. Вычислить уравнение d/b sqrt(a) + a
Код (ASM):
  1. title Рысованый А.Н.
  2. ; masm64. Числа {a,b,c,d} заданные массивом
  3. ; и имеют размерность Real8. Вычислить уравнение d/b sqrt(a) + a
  4. include win64a.inc  ;  подключаемые библиотеки
  5. .data
  6. mas1 real8 16.,2.,4.,16.  ; a, b, c, d
  7. tit1 db "masm64. Результат вычисления уравнения на SSE2",0
  8. buf1 dq ?,0  ; буфер вывода сообщения
  9. ifmt db "masm64.  Массив a, b, c, d  := 16., 2., 4., 16.",10,10,
  10. "Уравнение d/b sqrt(a) + a.  Результат: %d ",10,10,
  11. "Автор: Рысованый А.Н., каф. ВТП, фак. КИТ, НТУ ХПИ",10,
  12. 9,"Сайт:  http://blogs.kpi.kharkov.ua/v2/asm/",0
  13. .code    ; уравнение d/b sqrt(a) + a
  14. WinMain proc
  15. sub rsp,28h; cтек: 28h=32d+8; 8 - возврат
  16. mov rbp,rsp
  17. movsd xmm1,mas1[0]  ; xmm1 - a - переслать двойное слово
  18. movsd xmm2,mas1[8]  ; xmm2 - b
  19. movsd xmm3,mas1[16]  ; xmm3 - c
  20. movsd xmm4,mas1[24]  ; xmm3 - d
  21. divsd xmm4,xmm2  ; d/b
  22. sqrtsd xmm5,xmm1  ; sqrt(a)
  23. mulsd xmm4,xmm5  ; d/b x sqrt(a)
  24. addsd xmm4,xmm1  ; d/b x sqrt(a) + a
  25. cvttsd2si eax,xmm4 ;
  26. movsxd r15,eax
  27. invoke wsprintf,addr buf1,addr ifmt,r15
  28. invoke MessageBox,0,addr buf1,addr tit1,MB_ICONINFORMATION
  29. invoke RtlExitUserProcess,0
  30. WinMain endp
  31. end
Результатом выполнения программы является окно сообщения.

upload_2019-4-5_16-13-18.png


Определим объем в байтах свободного места в секции кода. Для этой цели воспользуемся программой-анализатором LotdPE. Выполним последовательность действий:
Определим объем в байтах свободного места в секции кода. Для этой цели воспользуемся программой-анализатором LotdPE. Выполним последовательность действий:
  • в программе нажать на клавишу меню PE Editor и выбрать исследуемый ехе-файл;
  • в появившемся окне нажать клавишу меню Sections;
  • выбрать секцию, где расположен текст программы (это секция text), нажать правую клавишу мышки и выбрать пункт меню hex edit section;
  • в появившемся окне memory buffer выбранная секция выделится темным цветом. В конце секции свободные ячейки будут заполнены нулями. Их необходимо просто посчитать.

upload_2019-4-5_16-14-2.png

Для подсчета количества байтов свободных ячеек памяти в секции кода необходимо из начального адреса следующей секции вычесть первую свободную ячейку после окончания кода:
600h – 477h = 188h = 393 байтов.
Для внедрения функции с ее параметрами необходимо точно знать, как эти параметры отображаются синтаксически в отладчике и применять их точно так же. В основной программе уже присутствует функция MessageBox. Поэтому, писать в качестве примера отдельную программу с этой функцией уже нет необходимости: будем использовать параметры этой функции в ехе-файле, анализировать и изменять их под собственные адреса ячеек памяти.
Открываем ехе-файл этой программы в отладчике x64Dbg. При анализе кода в отладчике x64Dbg сначала необходимо продумать свои действия: где удобнее поставить новую функцию MessageBox и в какой последовательности она должна вывести окно сообщения.
Внешний вид основной программы представлен на рис.
upload_2019-4-5_16-14-24.png

Проанализируем программу в отладчике.
В нашем самом простом случае необходимо осуществить внедрение функции с ее параметрами в существующий код. Для этого надо в программе освободить место. Внедрить новую функцию MessageBox можно в начале программы, в середине или уже в самом конце. Алгоритм внедрения при выборе любого места не поменяется. Поменяется только последовательность вывода сообщений программой.
Выбираем для внедрения кода начало программы. Первые две команды перемещать нельзя, т.к они подготавливают программу к выполнению – выравнивают стек (при использовании среды masm64 от Mikl___). Значит – меняем третью строчку. Необходимо перенести эту команду из третьей строчки на свободное место после окончания программы. Последней строкой программы является функция RtlExitUserProcess.
Затем на освободившееся место ставим команду jmp с адресом перехода на адрес расположения перенесенной команды.
После – вставляем параметры функции MessageBox и вызов (команда call) этой функции.
Последней командой после вызова функции MessageBox снова будет команда jmp, но с адресом возврата на нетронутую строчку кода после вставленной первой команды jmp в начале программы.

И так, команда jmp с адресом перехода имеет размерность 2 байта.
Перенесем третью строчку кода и тем самым освободим место под команду jmp. В третьей строчке программы находится команда, которая занимает 8 байт памяти:
00007FF7100F1007F2:0F100D F11F0000movsd xmm1,qword ptr ds:[7FF7100F3000]
Поэтому, перенесем эту команду в конец файла, а на ее место – команду jmp с адресом, который соответствует новому месту расположения после окончания программы. А оставшиеся байты заполним автоматически командами NOP.
После команды jmp вставляем функцию MessageBox, скопировав эту функцию в нашей же программе со старыми значениями параметров (теми же адресами ячеек):
Код (ASM):
  1. xor ecx,ecx
  2. lea rdx,qword ptr ds:[7FF75E51304F]
  3. lea r8,qword ptr ds:[7FF75E513020]
  4. mov r9d,40
  5. call qword ptr ds:[<&MessageBoxA>]
А позже уже заменим адреса на те, которые соответствуют новому месту расположения других параметров.
Для продолжения этой программы поставим команду возврата на не измененную строчку кода, которая расположена после вставленной в начале программы команды jmp.
Последней вставкой по свободным адресам расположим текстовую информацию для функции MessageBox. И эти адреса поставим в новой функции MessageBox.
Итак, приступаем к внедрению. Рассмотрим последовательность внедрения.
  1. Освобождаем место для команды jmp. Для этого ставим курсор мышки на строку с первой командой программы, которую будем переносить на место, которое будет располагаться после конца программы:
    Код (ASM):
    1. movsd xmm1,qword ptr ds:[7FF75E513000]
    Копируем строку кода. Для этого нажимаем правую клавишу мышки и выбираем Копировать / Дизассемблерный код.
  2. Переносим скопированную строку кода в конец кода. Для этого ставим курсор на первую позицию после самой последней команды программы. Нажимаем дважды на левую клавишу мышки и вставляем (Ctrl + V) из буфера команду
    Код (ASM):
    1. movsd xmm1,qword ptr ds:[7FF75E513000]
    upload_2019-4-5_16-15-21.png

    В этом окне показано, что скопированную команду вставлено в конец программы, но в начале кода (третья строка) эта команда еще не удалена.
    Не забываем после каждого действия сохранять внесенные изменения с заменой имени файла на другое. Для этого выбираем пиктограмму с названием Исправления, а далее новое имя и расширение ехе.
  3. Теперь необходимо заменить в начале программы команду, которую в предыдущем пункте уже переместили в конец файла, на команду jmp.
    Рис. 5.5. Окно с выделением первой команды, которую скопировали
    Для этого сначала копируем адрес перемещенной команды. Для этого ставим курсор в начало программы на команду, которую уже скопировали, но не заменили. Нажимаем правую клавишу мышки и выбираем Копировать / Адрес. После копирования адреса подводим курсор мышки в начало программы к команде, которую необходимо выделить, а затем и заменить. Дважды нажимаем на левую клавишу мышки.

    upload_2019-4-5_16-15-53.png


    В всплывающем окне пишем команду jmp, а затем Ctrl + V для вставки адреса из буфера (рис.).

    upload_2019-4-5_16-16-15.png

    А затем кнопку OK. Произошла замена команды, а лишние ячейки заполнились пустыми командами nop (рис. ).
    upload_2019-4-5_16-16-35.png
  4. Теперь вставляем параметры и вызываем саму функцию MessageBox.
    Необходимо последовательно после первой перенесенной команды вставить строки из нашей же программы:
    Код (ASM):
    1. xor ecx,ecx
    2. lea rdx, ds:[0x00007FF7100F304F]
    3. lea r8, ds:[0x00007FF7100F3020]
    4. mov r9d,40
    5. call qword ptr ds:[<&MessageBoxA>]
    Для этого ставим курсор мышки на первый параметр функции MessageBox. Это строка кода:
    Код (ASM):
    1. xor ecx,ecx
    Нажимаем правую клавишу мышки и выбираем Копировать / Дизассемблерный код, но быстрее и, как покажут дальнейшие действия, правильнее, если использовать сочетание клавиш Ctrl + C.
    Подводим курсор мышки в конец файла на свободную строку. Нажимаем дважды левую клавишу мышки и нажимаем Ctrl + V для вставки содержимого из буфера. После нажатия кнопки OK новая команда вставится на новое место (рис. ).
    upload_2019-4-5_16-16-57.png


    Таким же образом переносятся оставшиеся строки параметров функции MessageBox. А вот, чтобы скопировать команду вызова самой функции, необходимо дважды нажать на этой строке левой клавише мышки и нажать только Ctrl + C. При этом в всплывающем окне в строке отображения должно отображаться не название MessageBox, а адрес ячейки памяти, где располагается эта функция.
    После такой вставки адрес нахождения функции поменяется на название этой функции.

    Во вставленных строках параметров функции стоят старые адреса, которые необходимо заменить на новые. Но для того, чтобы не было фрагментации кода, с этими действиями необходимо пока повременить – надо еще вставить команду возврата jmp, а потом уже заменить адреса на реальные.
  5. Вставляем команду возврата в конце вставленного кода с адресом возврата на начало оставшегося кода программы.
    Для этого сначала подводим курсор к команде
    Код (ASM):
    1. movsd xmm2,qword ptr ds:[7FF60F393008]
    и копируем адрес ее расположения: Копировать / Адрес.
    После чего подводим курсор к следующей свободной в конце файла строке, нажимаем дважды левую клавишу мышки. Пишем jmp, вставляем пропуск и нажимаем комбинацию Ctrl + V (рис. ).

    upload_2019-4-5_16-17-34.png
  6. Меняем адреса параметров функции MessageBox.
    В этой функции в качестве параметров выступают текстовые строки с названиями титула упрощенного окна и строки вывода сообщения. Если указать для каждого из параметров один адрес, то эти строки будут совпадать. В регистре rdx передается сообщение, а название титула упрощенного окна – через регистр r8.
    Напишем слово «Инфицировано» и в эти регистры передадим для простоты один и тот же адрес. Скопируем адрес свободной строки и заменим эти адреса в регистрах rdx и r8. Для этого подводим курсор мышки к свободной строке, нажимаем правую клавишу и выбираем Копировать / Адрес.
    После занесения в буфер адреса последовательно вызываем строки
    Код (ASM):
    1. lea rdx,
    2. lea r8,
    и меняем из буфера адрес на адрес свободной строки, куда будем писать сообщение (рис. ).
    upload_2019-4-5_16-17-57.png
  7. Вставляем в ячейки памяти текст сообщения.
    Для этого сначала подводим курсор к любой из строк кода, где записан адрес начала сообщения. Выбираем Перейти к дампу / Константа. После чего в дампе памяти отображается содержимое этих ячеек. Подводим курсор к содержимому первого байта, нажимаем левую клавишу мышки и не отпуская ее выбираем столько ячеек, сколько букв содержится в слове Инфицировано. Нажимаем правую клавишу мышки и выбираем Двоичные операции /Редактировать. Вводим сообщение (рис. ).

    upload_2019-4-5_16-18-23.png
  8. Делаем последнее сохранение изменений с заменой имени файла на другое. Для этого выбираем пиктограмму с названием Исправления, а далее новое имя и расширение ехе.
  9. Запускаем ехе-файл. После запуска последовательно выводятся 2 сообщения (рис. ).


upload_2019-4-5_16-18-51.png upload_2019-4-5_16-18-57.png
Процесс внедрения завершен успешно.

1 12.172
Alex81524

Alex81524
New Member

Регистрация:
12 фев 2008
Публикаций:
5