"От зелёного к красному" поиск адреса функции по имени

Тема в разделе "WASM.BEGINNERS", создана пользователем amvoz, 26 окт 2009.

  1. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Друзья!
    Кто-нибудь искал из вас?
    Вот в этой статье
    http://www.wasm.ru/article.php?article=green2red02

    Сказано, как это сделать. Вот алгоритм

    * 1) Найти индекс в массиве имен AddressOfNames, соответствующий нужному имени.
    * 2) Использовать этот индекс как индекс в массиве AddressOfNameOrdinalsи получить значение в массиве.
    * 3) Вычесть из полученного значения OrdinalBase.
    * 4) Использовать полученный индекс, чтобы получить RVAфункции в массиве AddressOfFuncions

    Это неправильный какой-то алгоритм. Если кто-о из вас спотыкался уже об него, скажите, пожалуйста, каким он должен быть.

    А если кто всерьёз заинтересуется, я укажу, в чём он конкретно неправильный. Чтобы зря время не отнимать. Кто знает, может его неправильность очевидна всем, кроме меня?..
    P. S. Речь идёт о таблице экспорта, я работаю с kernel32.dll
     
  2. intel_x128

    intel_x128 New Member

    Публикаций:
    0
    Регистрация:
    17 май 2009
    Сообщения:
    345
    Указывай "в чем неправильный"
     
  3. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    А вот в чём.
    Возьмём, к примеру, функцию AddAtomA. RVA её точки входа равно 0X392a3 (Сомнению не подлежит, я писал код в отладчике call 7c8392a3 и мне прописывалось, что это прыжок на AddAtomA)

    А теперь попробуем найти вручную RVA её точки входа.
    Для начала- вот НЕОБХОДИМЫЕ значения структуры IMAGE_EXPORT_DIRECTORY для вышеупомянутого модуля
    Если будете сверяться-чтобы вы эти адреса не искали.

    Export== 7c80262c
    Base== 1
    AddressOfFunctions== 7c802654
    AddressOfNames== 7c803528
    AddressOfNameOrdinals== 7c8043fc

    1) Идём по адресу AddressOfNames== 7c803528, это массив указателей на имена функций.
    Находим указатель на имя AddAtomA, это имя расположено по адресу 7с804b82, нашли указатель на него, он имеет
    в массиве AddressOfNames индекс 1

    2)Теперь используем этот индекс как индекс в массиве AddressOfNameOrdinals== 7c8043fc, получаем значение 1

    3) Отнимаем из полученного значения OrdinalBase. То есть базовый ординал Base== 1. Получаем 0

    4) Теперь идём в массив AddressOfFunctions== 7c802654 и ищем там нулевой элемент. Получаем RVA= 0xA634
    А должно быть 0X392a3

    К слову сказать, это RVA==0X392a3 в массиве AddressOfFunctions под номером один, а не ноль.
    Помогите, кто может!
     
  4. intel_x128

    intel_x128 New Member

    Публикаций:
    0
    Регистрация:
    17 май 2009
    Сообщения:
    345
    Не отнимай базу ординала

    Смотри статью "Вирусология - программирование на уровне ринг3"

    Там "правильный алгос"
     
  5. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    отнимать Base не стоит.
     
  6. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Да не то, что Base отнимать не надо- этого мало...
    Нужно именно такой алогоритм использовать!
    http://www.wasm.ru/article.php?article=vgw04

    Нужно именно находить ординал в табице ординалов- его значение может быть каким угодно!
    Ничего не пойму... Что за недосмотр-то автора такой такой?
    Как бы то ни было- спасибо откликнувшимся.
     
  7. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Кстати, в той статье тоже ошибка небольшая

    "Адрес API-функции: (Ординал функции*4)+VA таблицы адресов+база KERNEL32"

    Неправильно. Базу Kernel32.dll прибавлять не надо, ибо она УЖЕ входит в VA таблицы адресов таблицы адресов
    (Действительно, VA таблицы адресов== RVA таблицы адресов+ база KERNEL32)
     
  8. JCronuz

    JCronuz New Member

    Публикаций:
    0
    Регистрация:
    26 сен 2007
    Сообщения:
    1.240
    Адрес:
    Russia
    Напиши свою версию статей по вирусологии и попробуй не допусти ошибок
     
  9. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Это, конечно, невозможно.
    Но уж больно они того... Крупные...
    Там ниже функция идёт для работы с таблицей экспорта, так она тоже того... То есть она вообще того я бы сказал.
    Я её переделал.
    Я бы вообще автору написал, но куда?
    Я тыкаю в ссылки, а они отправляют меня на этот форум.
    Товарищи модераторы, скажите автору, там есть что исправлять и здорово есть, пусть со мной свяжется, я функцию для работы с таблицей экспорта ему дам. Пусть исправит.

    Да, а некоторым штатским, которые только и ждут, чтобы сделать замечание подобно предыдущему, хочу заметить: не хуже твоего понимаю масштабы трудов и усилий, затраченных на эти статьи. А, может и получше, ибо я разобрался во всех представленных кодах, и маленько приблизился к пониманию цены, которую авторы заплатили за их написание, а ты не знаю.

    Но ошибки есть и нормальные такие ошибки. Их надо исправлять. И указывать на них (да, указывать). А не выделываться тут "напиши" да "не допусти".
     
  10. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    amvoz
    Ну... вообще-то она там далеко не одна. Одна только первая синяя табличка чего стоит. Временной штам занимает 4 байта, а никак не два. Зато вместо этого Minor Version вдруг стала 4-байтовой вместо двух. Ordinal Base так вообще пропущен. В результате общий размер указан тоже на четыре байта меньше реального.
    Короче, читать надо статьи, но головой тоже думать. Есть большое желание отметиться, отпишитесь в комментариях к статье. И читайте официальные доки.
     
  11. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    Врядли он жив

    Насчет функции, то может ошибку специально допустили чтобы люди не копипастили
    Код (Text):
    1. VOID *
    2. PeMaGetFunctionAddress(
    3.     IN  PVOID   pFileBase,
    4.     IN  UINT32  FnHash
    5.     )
    6. {
    7.     PIMAGE_EXPORT_DIRECTORY pExport     = NULL;
    8.     ULONG                   i           = 0;
    9.     UINT32                  Hash        = 0;
    10.     CHAR*                   pName       = NULL;
    11.     PVOID                   pAddress    = NULL;
    12.     UINT16                  Ordinal     = 0;
    13.  
    14.     do
    15.     {
    16.         pExport = (PIMAGE_EXPORT_DIRECTORY)
    17.         PeDereferenceDirectory(
    18.             pFileBase,
    19.             IMAGE_DIRECTORY_ENTRY_EXPORT
    20.             );
    21.  
    22.         if(pExport == NULL)
    23.         {
    24.             break;
    25.         }
    26.  
    27.         for(i = 0; i < (ULONG)Export->NumberOfNames; i++)
    28.         {
    29.             pName = (CHAR* )VA(FileBase,((PCHAR *)VA(pFileBase, pExport->AddressOfNames))[i]);
    30.             Ordinal = ((UINT16* )VA(pFileBase, pExport->AddressOfNameOrdinals))[i];
    31.             pAddress = (PVOID)VA(pFileBase,((UINT32 *)VA(pFileBase, pExport->AddressOfFunctions))[Ordinal]);
    32.             Hash = HashCRC32(pName, CrtAnsiStrLen(pName));
    33.             if(Hash == FnHash)
    34.             {
    35.                 break;
    36.             }
    37.             else
    38.             {
    39.                 pAddress = NULL;
    40.             }
    41.         }
    42.     }while(0);
    43.  
    44.     return pAddress;
    45. }
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Кстати, о птичках. Глянул сейчас в официальный pecoff_v8. И вот что обнаружил:
    Собственно подчёркнута дезинформация. Да и код в конце также неверен, т.к. базу вычитать не нужно.
     
  13. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Я утрусь.
    Просто я не уверен в своих силах.
    Вижу ошибку и не пойму- то ли автор ошибается, то ли я?
    Вот и спрашиваю.

    А в комментах что толку спрашивать-то?
     
  14. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    просто коряво написано.
    Base отнимается только от ординалов при импорте.
    То есть если мы хотим получить функций с ординалом Ord, то предварительно нужно отнять Base.
    При этом OrdinalTable содержит уже подкорректированные ординалы.
     
  15. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    картинки взяты из питрековской статьи. остальное, судя по всему, перевод сперва на асм, а потом на ру. весьма солидный труд для одного человека

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

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    n0name
    Ну я бы согласился с "коряво написано". Типа в ordinal table на самом деле не хранятся ordinals, а только 16-bit indexes и т.п. Но против псевдокода-то что сказать... Там явно указано: вычитать ordinal base из числа, полученного из ordinal table. Врут и не краснеют.
     
  17. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    А я не пойму, чё администрация форума статьи-то не поправит?
    Могу сюда выложить функцию вывода таблицы экспорта. Только надо, чтобы она не затерялась, а туда её впихнуть. В статью. А ту убрать.
     
  18. yurza

    yurza New Member

    Публикаций:
    0
    Регистрация:
    5 мар 2008
    Сообщения:
    69
    Вот мой разбор Export по тойже статье не помню тоже вроде что то переделывал
    Код (Text):
    1. DWORD RVA_EXPORT=pImOpHe->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    2. if (RVA_EXPORT!=0){
    3. Memo1->Lines->Add("-========Export=======-");
    4. PIMAGE_SECTION_HEADER Sec_for_export=RvaToSection(&(pInth->FileHeader),RVA_EXPORT);
    5.  
    6. PIMAGE_EXPORT_DIRECTORY ExpTable1=(PIMAGE_EXPORT_DIRECTORY)((DWORD)pExe+(RVA_EXPORT-(Sec_for_export->VirtualAddress-Sec_for_export->PointerToRawData)));
    7. DWORD* a=(DWORD*)((DWORD)pExe+Sec_for_export->PointerToRawData);
    8. DWORD* AddressOfFunctions2=(DWORD*)(ExpTable1->AddressOfFunctions-Sec_for_export->VirtualAddress);
    9. AddressOfFunctions2=(DWORD*)((DWORD)a+(DWORD)AddressOfFunctions2);
    10. DWORD* AddressOfNames=(DWORD*)(ExpTable1->AddressOfNames-Sec_for_export->VirtualAddress);
    11. AddressOfNames=(DWORD*)((DWORD)a+(DWORD)AddressOfNames);
    12. WORD* AddressOfNameOrdinals=(WORD*)(ExpTable1->AddressOfNameOrdinals-Sec_for_export->VirtualAddress);
    13. AddressOfNameOrdinals=(WORD*)((DWORD)a+(DWORD)AddressOfNameOrdinals);
    14. PCHAR Name="MessageBoxA";
    15. PVOID addres=NULL;
    16. for (DWORD i=0;i<ExpTable1->NumberOfNames;i++){
    17.      char* name=(char*)((DWORD)pExe+(DWORD)(AddressOfNames[i]-(Sec_for_export->VirtualAddress-Sec_for_export->PointerToRawData)));
    18.      DWORD *offset=(DWORD*)((AddressOfFunctions2[i]-(Sec_for_export->VirtualAddress-Sec_for_export->PointerToRawData)));
    19.      if(!strcmp(name,Name)){
    20.         addres=(PVOID)(pImOpHe->ImageBase+AddressOfFunctions2[i]);
    21.         }
    22.       sprintf(buffer,"NAMES of function - %s RVA - %X  Ofset - %X ",name,AddressOfFunctions2[i],offset);
    23.      Memo1->Lines->Add(buffer);
    24.     }
     
  19. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Код (Text):
    1. #include <windows.h>
    2. #include <stdio.h>
    3. #define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew))
    4.  
    5. void PrintExportTable(long hMap){
    6.     PIMAGE_NT_HEADERS pPE=(PIMAGE_NT_HEADERS)NTSIGNATURE(hMap);
    7.     short NumberOfSection=pPE->FileHeader.NumberOfSections;
    8.     DWORD ExportRVA=pPE->OptionalHeader.DataDirectory[0].VirtualAddress;
    9.     long BaseAdress= (long)pPE->OptionalHeader.ImageBase;
    10.     printf("ExportRVA=   %x\n", ExportRVA);
    11.  
    12.    
    13.  
    14.     PIMAGE_EXPORT_DIRECTORY Export=(PIMAGE_EXPORT_DIRECTORY)((long)ExportRVA+ BaseAdress);
    15.     printf("\n\n\nPIMAGE_EXPORT_DIRECTORY=   %x\n", Export);
    16.     printf("Characteristics=  %x\n", Export->Base);
    17.     printf("TimeDateStamp=  %x\n", Export->TimeDateStamp);
    18.     printf("MajorVersion=  %x\n", Export->MajorVersion);
    19.     printf("MinorVersion=  %x\n", Export->MinorVersion);
    20.     printf("Name=  %x\n", (long)Export->Name+ BaseAdress);
    21.     printf("Base= %d\n",Export->Base);
    22.     printf("NumberOfFunctions=  %d\n",Export->NumberOfFunctions);
    23.     printf("NumberOfNames= %d\n", Export->NumberOfNames);
    24.  
    25.     DWORD* AddressOfFunctions= (DWORD*)((long)Export-> AddressOfFunctions +BaseAdress);
    26.     printf("AddressOfFunctions=  %x\n", AddressOfFunctions);
    27.  
    28. [b] DWORD* AddressOfNames=(DWORD*)((long)Export->AddressOfNames+BaseAdress);    
    29.     printf("AddressOfNames=  %x\n", (long) AddressOfNames);
    30.  
    31.     WORD* AddressOfNameOrdinals= (WORD*) ((long)Export->AddressOfNameOrdinals +BaseAdress);
    32.     printf("AddressOfNameOrdinals=  %x\n\n\n", (long) AddressOfNameOrdinals);
    33.  
    34.  
    35.  
    36.  
    37.     WORD index;
    38.     printf("%4s      %-40s       %s\n-------------------------------------"\
    39.            "----------------------------------\n","Ordinal","NameOfFunctions",
    40.            "EntryPoint");
    41.     for (unsigned int i=0;i<Export->NumberOfFunctions;i++)  {
    42.         index=0xFFFF;
    43.         for (unsigned int j=0;j<Export->NumberOfNames;j++){
    44.             if (AddressOfNameOrdinals[j]== i){
    45.              index=j;
    46.              break;
    47.             }
    48.         }
    49.         if ((AddressOfFunctions[i]>=
    50.              pPE->OptionalHeader.DataDirectory[0].VirtualAddress)&&
    51.              (AddressOfFunctions[i]<=
    52.              pPE->OptionalHeader.DataDirectory[0].VirtualAddress+ pPE-> OptionalHeader.DataDirectory[0].Size)) {        {
    53.             if (index!=0xFFFF) {
    54.              printf("%4d         |%-40s       |Forw->%x\n",
    55.               i, BaseAdress+ AddressOfNames[index], AddressOfFunctions[index]);
    56.             }  
    57.             else {
    58.              printf("%4d         |%-40s       |Forw->%x\n",
    59.              i, "OrdinalOnly", AddressOfFunctions[i]); }
    60.             }
    61.         }
    62.         else {
    63.          if (index!=0xFFFF){
    64.           printf("%4d         |%-40s       |%X\n",
    65.           i, BaseAdress+ AddressOfNames[index], AddressOfFunctions[index]);
    66.          }  
    67.          else {
    68.           printf("%4d         |%-40s       |%X\n",
    69.           i, "OrdinalOnly",AddressOfFunctions[i]);
    70.    
    71.          }
    72.         }
    73.     }
    74. }
    А вот мой.
    Там главное файловое смещение не задействовать.
    И то: загружается файл в оперативную память- зачем оно нам нужно? Тем более, что автор в начале статьи сказал- не будем возиться с файловым смещением.
    Без него гораздо всё проще.
     
  20. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    2 примера того, как не надо писать программы.