Сейчас на форуме: asfa, Rio, _MBK_, Adler (+6 невидимых)

 eXeL@B —› Вопросы новичков —› Поиск вызова библиотечной функции в двоичном коде
Посл.ответ Сообщение

Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 17:23
· Личное сообщение · #1

Здравствуйте. Имеется задача прочитать ЕХЕ-шник и начти в нем вызовы библиотечных функций (например, scrcopy).
Дизассемблеры типа IDA спокойно разпознают вызовы бибилиотечных функций, но я так и не понял, как они это делают.
С помощью гугла отрыл, что IDA использует технологию FLIRT (http://www.idapro.ru/description/flirt/). Но как искать в файле по сигнатуре, если самого кода функции там не нету, не понял..
Похоже, нужно использовать таблицу импорта, искать импортируемые dll-ки и их функции и использовать примерно такой алгоритм:
1. Смотрим в таблицу импорта и сопоставляем адрес вызова с функцией
2. Ищем в ЕХЕ-шнике в разделе кода call <адрес нужной функции>
Но вот вопрос, существует ли возможность определить адреса вызова футкций до загрузки программы в память? Напримет, в случае непривязанного импорта, если я все правильно понял, адреса импортируемых функций записывваются в время загрузки программы.. но тогда как можно заранее определить, какие инструкции искать?

Вот, например, как выглядит код вызова функции strcpy в дизассемблере:
Code:
  1. strcpy(s2, s1);
  2. 003B378A 8D 45 D8             lea         eax,[ebp-28h]  
  3. 003B378D 50                   push        eax  
  4. 003B378E 8B 4D CC             mov         ecx,dword ptr [ebp-34h]  
  5. 003B3791 51                   push        ecx  
  6. 003B3792 E8 49 DA FF FF       call        @ILT+475(_strcpy) (3B11E0h) 
  7. ...
  8. @ILT+475(_strcpy):
  9. 003B11E0 E9 0D 02 00 00       jmp         strcpy (3B13F2h)  
  10. ...
  11. strcpy:
  12. 003B13F2 FF 25 DC 82 3B 00    jmp         dword ptr [__imp__strcpy (3B82DCh)]


Получается, что все вызовы strcpy перенаправляются на метку "@ILT+475(_strcpy)", а оттуда уже на метку "strcpy".

По идее, получается, что в программе мне нужно искать все команды "call @ILT+475(_strcpy)". Но как узнать, что я должен искать именно такую команду, ведь в таблице импорта нет никакой информации об этой метке. Я там нашел только RVA строк, которые хранят названия функций. Скрин с таблицей приаттачил..

ed84_07.05.2013_EXELAB.rU.tgz - import table.png



Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 07 мая 2013 18:11
· Личное сообщение · #2

Берешь из таблицы импорта имя функции, GetProcAddress(LoadLibrary(..),..) получаешь адрес функции. Вызывается оно обычно call [strcpy] либо call m1/m1: jmp [strcpy]

А то что ида нашла в коде - это рантайм библиотека, которая может реализовать тот же strcpy сама или дергнуть для этого API



Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 18:52
· Личное сообщение · #3

Спасибо за ответ! Но ведь после вызова GetProcAddress(LoadLibrary(..),..), я получу виртуальный адрес функции в адресном пространстве программы, которая сканирует ЕХЕ-шник. Этот адрес, по идее, никак не связан с теми адресами, что зашиты в самом ЕХЕ файле. Если так, то как можно будет сравнивать эти адреса?



Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 07 мая 2013 19:16
· Личное сообщение · #4

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



Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 19:46
· Личное сообщение · #5

Извините, наверно, не очень понятно пишу... Задача такая: программа на вход получает ЕХЕ-шник и должна определить, в каких местах вызввалась определенная библиотченая функция (например, scrcopy).

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




Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 07 мая 2013 19:46
· Личное сообщение · #6

Veliant пишет:
Не понятно что вы хотите.

Похоже, что в секции кода нужно найти все вызовы API или CRT. Так для этого смотрим таблицу перекрёстных ссылок. Или цель написать свой дизассемблер?

-----
Следуй за белым кроликом




Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 20:07
· Личное сообщение · #7

Да, цель именно та )) Дизассемблер не пишу, но нужно "научить" свою прогу разпознавать эти вызовы автоматически )



Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 07 мая 2013 20:28 · Поправил: Veliant
· Личное сообщение · #8

без дизассемблера плохо будет. совсем топорный способ - искать байты FF25 или FF15 в секции кода, и сравнивать следующий dword указывает на адрес из IAT(а не на саму api) или нет.

| Сообщение посчитали полезным: Alex071

Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 20:39 · Поправил: Alex071
· Личное сообщение · #9

Я, честно говоря, как раз вынашивал этот топорный метод ))

Но ведь пока программа не загружена в память, IAT не заполнена, там находятся только имена импортируемых функций (это я из --> Таблица импорта PE файла <-- вычитал). Тогда как вести сравнение?




Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 07 мая 2013 20:56
· Личное сообщение · #10

Alex071 пишет:
там находятся только имена импортируемых функций

По именам и вести. Только что-то мне подсказывает, это это очередной велосипед и ваши 'реальные' задачи решаются иными, гораздо легчеми путями.

-----
Следуй за белым кроликом


| Сообщение посчитали полезным: Alex071


Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 07 мая 2013 21:19 · Поправил: -=AkaBOSS=-
· Личное сообщение · #11

Alex071 пишет:
Но ведь пока программа не загружена в память, IAT не заполнена, там находятся только имена импортируемых функций

а каким образом пользовательский код вдруг получит управление в тот момент, когда IAT не заполнена?

если цель - чисто статический анализ, тогда либо читаем/анализируем модули, прописанные в таблице импорта, либо просто запоминаем диапазон адресов, где находится IAT и, при обращении к ним, подставляем соответствующее имя функции.



Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 21:44 · Поправил: Alex071
· Личное сообщение · #12

Получается, код
Code:
  1. FF 25 DC 82 3B 00    jmp         dword ptr [__imp__strcpy (3B82DCh)]

уже заранее есть в ЕХЕ-файле?
Попробовал поискать "FF 25 DC 82 3B 00" в Hex-редакторе, но без успеха..

Или же в ЕХЕ-шнике есть код типа "дальний переход на адрес, что записан в IDT", но в "FF 25 DC 82 3B 00" он превращается уже после загрузки программы в память?


Например, если строка в IAT имеет такой вид:

pFile | Data | Value

000060DC | 0001873E | 063B strcpy


То какой должна быть строка поиска? FF 25...

Извините за глупые вопросы, мне очень стыдно ))




Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 07 мая 2013 21:52 · Поправил: -=AkaBOSS=-
· Личное сообщение · #13

Alex071 пишет:
Получается, код
Code:
1. FF 25 DC 82 3B 00 jmp dword ptr [__imp__strcpy (3B82DCh)]
уже заранее есть в ЕХЕ-файле?


советую перечитать доку по секции импорта PE-файла
если функция принадлежит к секции импорта, то там есть только
где-то:
Code:
  1.   сall strcpy


переходники_сгенеренные_компилятором:
Code:
  1.  jmp [strcpy]


и, наконец, в директории импорта:
Code:
  1. strcpy dd rva _strcpy
  2. <....>
  3. _strcpy db 0, 0, "strcpy", 0


rva _strcpy - относительное смещение на имя импортируемой функции
загрузчик, при загрузке модуля, заменяет его на реальный адрес функции в адресном пространстве процесса

/ADD:
но! переходников может и не быть:
Code:
  1. mov eax, offset
  2. call d,[eax]


или, например:

Code:
  1. mov eax, [offset]
  2. call eax


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

| Сообщение посчитали полезным: Alex071

Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 22:09 · Поправил: Alex071
· Личное сообщение · #14

Черт, спасибо огроменное, я, кажется, все понял )) Т.е. мне нужно искать в секции кода "jmp [rva _strcpy]" ?
//ADD:
Следить за RVA функции это всмысле проверять, где в секции кода есть поаледовательность байт равная RVA в таблице импорта?




Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 07 мая 2013 22:20
· Личное сообщение · #15

Alex071 пишет:
я, кажется, все понял

и
Alex071 пишет:
Т.е. мне нужно искать в секции кода "jmp [rva _strcpy]" ?


можно сделать вывод что ничего не поняли)



Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 07 мая 2013 22:31 · Поправил: Alex071
· Личное сообщение · #16

черт) Вот мое понимание, поправьте пожалуйста, что не так:
1.В IAT до загрузки программы хранятся RVA строк, содержащих имена импортируемых функций.
2.Далее загрузчик подменяет эти RVA на адреса точек входа в функции.
3.В ЕХЕ-шнике уже есть код, который берет адрес, записанный в IAT и делает jmp на этот адрес (если есть переходник)

Поэтому задача в простейшем случае сводится к нахождению кода из пункта 3




Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 07 мая 2013 22:44
· Личное сообщение · #17

Alex071 пишет:
3.В ЕХЕ-шнике уже есть код, который берет адрес, записанный в IAT и делает jmp на этот адрес (если есть переходник)


обращения к записи в IAT будут по-любому, иначе в ней бы не было смысла
но! опять подчёркиваю - адрес записи в таблице импорта может помещаться в регистр или переменную перед использованием, поэтому искать нужно константу (ImageBase+rva ImportedFunc)

ТС, перед поиском решения, не помешало бы изложить суть задачи - возможно, метод решения окажется проще...



Ранг: 0.6 (гость)
Активность: 0=0
Статус: Участник

Создано: 08 мая 2013 14:22 · Поправил: Alex071
· Личное сообщение · #18

Сэнкью всем вэри-вэри мач! Теперь все осозналось и получилось )) Наверно, уже нет смысла запаривать народ сутью своей (довольно глупой ) задачи. Еще раз спасибо!


 eXeL@B —› Вопросы новичков —› Поиск вызова библиотечной функции в двоичном коде
Эта тема закрыта. Ответы больше не принимаются.
   Для печати Для печати