Экспорт из PE & ядро

Тема в разделе "WASM.NT.KERNEL", создана пользователем haxorart, 13 апр 2010.

  1. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Здравствуйте.
    Цель:
    Надоело каждый раз зашивать номера системных серверов драйверы или использовать ненадежные методы их поиска. Поэтому необходимо создать парсер таблиц экспорта PE файлов. Затем распарсить ntdll.dll и ntoskernel.dll. И далее с помощью дизассемблера или поиска по сигнатурам(на основе алгоритма Пратта-Кнута-Морриса) вытаскивать смещения, адреса функций, либо ещё какие-нибудь константы. (Возможно есть более простое решение?)
    Задачи:
    1)Весь функционал нужно реализовать в ядре. Для тестирования начал делать в юзер моде вот что получилось вначале:
    Код (Text):
    1. [...]
    2. HANDLE p=GetModuleHandle("ntdll.dll");
    3. IMAGE_DOS_HEADER* idh=(PIMAGE_DOS_HEADER)p;
    4. IMAGE_NT_HEADERS* inth=(PIMAGE_NT_HEADERS)((DWORD)p+idh->e_lfanew);
    5. IMAGE_EXPORT_DIRECTORY* ied=(PIMAGE_EXPORT_DIRECTORY)((DWORD)p+inth->OptionalHeader.DataDirectory[0].VirtualAddress);
    6. DWORD num=ied->NumberOfNames;
    7. PCHAR* name = (PCHAR*)((DWORD)p+ied->AddressOfNames);
    8. PDWORD func  = (PDWORD)((DWORD)p+ied->AddressOfFunctions);
    9. PWORD ordinal = (PWORD)((DWORD)p+ied->AddressOfNameOrdinals);
    10. for(int i=0;i<num;i++)
    11. [...]
    Сверился с PEiD вроде все результаты совпадают. Но потом я вручную слодил базу и RVA полученную прогой и сравнил с GetProcAddress. Результаты разошлись. Почему?

    Далее хотел передавать информацию в драйвер ну и т.д. Но если похукать хотя бы GetModuleHandle метод можно легко обломать. Поэтому решил парсить файл на диске. Обратил внимание, что в интернете все делают как я в 1 случае и почему то никто не парсил с диска. Попробовал:

    Код (Text):
    1. [...]
    2. FILE* f=fopen(Edit1->Text.c_str(),"rb");
    3. fseek(f,0,SEEK_END);
    4. DWORD fs=ftell(f);
    5. fseek(f,0,SEEK_SET);
    6.  
    7. IMAGE_DOS_HEADER idh;
    8. GetDosHeader(f,&idh);
    9. IMAGE_NT_HEADERS inth;
    10. GetNtHeader(f,idh.e_lfanew,&inth);
    11.  
    12.  
    13. fseek(f,inth.OptionalHeader.DataDirectory[0].VirtualAddress,SEEK_SET);
    14. IMAGE_EXPORT_DIRECTORY ied;
    15. fread(&ied,sizeof(ied),1,f);
    16. //здесь уже начинается неправильно. Правильно ли я понял что RVA(для файла, а не для памяти) это просто смещение от начала файла? Если да, то в чём ошибка?
    17. [...]
    В чём я ошибаюсь? Возможно пошёл не по тому пути? Может для ядра существуют более лёгкие пути решения проблемы. В общем хотелось бы услышать мнения кто как решал данную проблему... Вариант, например с MmGetSystemRoutineAddress не подойдет, т.к. нужно именно распарсить файл с диска(так получается более защищенный от хуков код, или я ошибаюсь?), ну и естественно в ядре.
     
  2. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    haxorart
    Код (Text):
    1. GET_CURRENT_GRAPH_ENTRY macro
    2.     Call _$_GetCallbackReference
    3. endm
    4.  
    5. SEH_Prolog proc C
    6.     pop ecx
    7.     push ebp
    8.     push eax
    9.     Call SEH_GetRef
    10.     push eax
    11.     assume fs:nothing
    12.     push dword ptr fs:[TEB.Tib.ExceptionList]
    13.     mov dword ptr fs:[TEB.Tib.ExceptionList],esp
    14.     jmp ecx
    15. SEH_Prolog endp
    16.  
    17. ; o Не восстанавливаются Ebx, Esi и Edi.
    18. ;
    19. SEH_Epilog proc C
    20.     pop ecx
    21.     pop dword ptr fs:[TEB.Tib.ExceptionList]
    22.     lea esp,[esp + 3*4]
    23.     jmp ecx
    24. SEH_Epilog endp
    25.  
    26. SEH_GetRef proc C
    27.     GET_CURRENT_GRAPH_ENTRY
    28.     mov eax,dword ptr [esp + 4]
    29.     mov esp,dword ptr [esp + 2*4]   ; (esp) -> ExceptionList
    30.     mov eax,EXCEPTION_RECORD.ExceptionCode[eax]
    31.     mov ebp,dword ptr [esp + 3*4]
    32.     jmp dword ptr [esp + 2*4]
    33. SEH_GetRef endp
    34.  
    35. _$_GetCallbackReference::
    36.     pop eax
    37.     ret
    38.  
    39. ; +
    40. ;Проверяет валидность заголовка модуля.
    41. ;
    42. LdrImageNtHeader proc ImageBase:PVOID, ImageHeader:PIMAGE_NT_HEADERS
    43.     mov edx,ImageBase
    44.     mov eax,STATUS_INVALID_IMAGE_FORMAT
    45.     assume edx:PIMAGE_DOS_HEADER
    46.     cmp [edx].e_magic,'ZM'
    47.     jne @f
    48.     add edx,[edx].e_lfanew
    49.     assume edx:PIMAGE_NT_HEADERS
    50.     cmp [edx].Signature,'EP'
    51.     jne @f
    52.     cmp [edx].FileHeader.SizeOfOptionalHeader,sizeof(IMAGE_OPTIONAL_HEADER32)
    53.     jne @f
    54.     cmp [edx].FileHeader.Machine,IMAGE_FILE_MACHINE_I386   
    55.     jne @f
    56.     test [edx].FileHeader.Characteristics,IMAGE_FILE_32BIT_MACHINE
    57.     je @f
    58.     mov ecx,ImageHeader
    59.     xor eax,eax
    60.     mov dword ptr [ecx],edx
    61. @@:
    62.     ret
    63. LdrImageNtHeader endp
    64.  
    65. ; +
    66. ;
    67. CompareAsciizString proc uses ebx String1:PSTR, String2:PSTR
    68.     mov ecx,String1
    69.     mov edx,String2
    70.     xor ebx,ebx
    71. @@:
    72.     mov al,byte ptr [ecx + ebx]
    73.     cmp byte ptr [edx + ebx],al
    74.     jne @f
    75.     inc ebx
    76.     test al,al
    77.     jne @b
    78. @@:
    79.     ret
    80. CompareAsciizString endp
    81.  
    82. ; +
    83. ; Поиск функции по имени/хэшу в экспорте.
    84. ;
    85. LdrImageQueryEntryFromCrc32 proc uses ebx esi edi ImageBase:PVOID, Crc32OrFunctionName:DWORD, pRtlComputeCrc32:PVOID, PartialCrc:ULONG, Function:PVOID
    86. Local ExportDirectory:PIMAGE_EXPORT_DIRECTORY
    87. Local ImageHeader:PIMAGE_NT_HEADERS
    88. Local NumberOfNames:ULONG
    89.     Call SEH_Epilog_Reference
    90.     Call SEH_Prolog
    91.     mov eax,fs:[TEB.Peb]
    92.     mov ebx,ImageBase
    93.     mov eax,PEB.Ldr[eax]
    94.     test ebx,ebx
    95.     mov eax,PEB_LDR_DATA.InLoadOrderModuleList.Flink[eax]
    96.     .if Zero?
    97.     mov eax,LDR_DATA_TABLE_ENTRY.InLoadOrderModuleList.Flink[eax]
    98.     mov ebx,LDR_DATA_TABLE_ENTRY.DllBase[eax]   ; ntdll.dll
    99.     .endif
    100.     invoke LdrImageNtHeader, Ebx, addr ImageHeader
    101.     test eax,eax
    102.     mov edx,ImageHeader
    103.     jnz Exit
    104.     assume edx:PIMAGE_NT_HEADERS
    105.     mov eax,[edx].OptionalHeader.DataDirectory.VirtualAddress
    106.     test eax,eax
    107.     jz ErrImage
    108.     add eax,ebx
    109.     assume eax:PIMAGE_EXPORT_DIRECTORY 
    110.     mov ExportDirectory,eax
    111.     mov esi,[eax].AddressOfNames   
    112.     test esi,esi
    113.     jz ErrTable
    114.     mov eax,[eax].NumberOfNames
    115.     test eax,eax
    116.     jz ErrTable
    117.     mov NumberOfNames,eax
    118.     add esi,ebx
    119.     xor edi,edi
    120.     cld
    121. Next:  
    122.     mov eax,dword ptr [esi]
    123.     add eax,ebx
    124.     .if pRtlComputeCrc32 != NULL
    125.     push edi
    126.     mov edi,eax
    127.     mov ecx,MAX_PATH
    128.     mov edx,edi
    129.     xor eax,eax
    130.     repne scasb
    131.     not ecx
    132.     pop edi
    133.     add ecx,MAX_PATH
    134.     push ecx
    135.     push edx
    136.     push PartialCrc
    137.     Call pRtlComputeCrc32
    138.     cmp Crc32OrFunctionName,eax
    139.     .else
    140.     invoke CompareAsciizString, Crc32OrFunctionName, Eax
    141.     .endif
    142.     jnz @f
    143.     mov ecx,ExportDirectory    
    144.     assume ecx:PIMAGE_EXPORT_DIRECTORY
    145.     mov eax,[ecx].AddressOfNameOrdinals
    146.     add eax,ebx
    147.     movzx edi,word ptr [2*edi+eax]
    148.     .if edi
    149.       .if edi >= [ecx]._Base
    150.       sub edi,[ecx]._Base
    151.       .endif
    152.     inc edi
    153.     .endif
    154.     mov esi,[ecx].AddressOfFunctions
    155.     add esi,ebx
    156.     mov ecx,dword ptr [4*edi + esi]
    157.     test ecx,ecx
    158.     mov edx,Function
    159.     jz ErrImage
    160.     add ecx,ebx
    161.     xor eax,eax
    162.     mov dword ptr [edx],ecx
    163.     jmp Exit
    164. @@:
    165.     add esi,4
    166.     inc edi
    167.     dec NumberOfNames
    168.     jnz Next
    169.     mov eax,STATUS_PROCEDURE_NOT_FOUND
    170.     jmp Exit
    171. SEH_Epilog_Reference:
    172.     GET_CURRENT_GRAPH_ENTRY
    173. Exit:
    174.     Call SEH_Epilog
    175.     ret
    176. ErrImage:
    177.     mov eax,STATUS_INVALID_IMAGE_FORMAT
    178.     jmp Exit
    179. ErrTable:
    180.     mov eax,STATUS_BAD_FUNCTION_TABLE
    181.     jmp Exit
    182. LdrImageQueryEntryFromCrc32 endp
    Далее мапите с диска ядро, либо нтдлл, в случае если нужно ID-сервисов находить и извлекаете их из стабов.
    Для этого есть универсальный двиг, создаётся граф и далее парсится и разбирается вашими калбэками. Это позволяет писать минимум кода для поиска какихто функций/переменных лежащих глубоко в недрах кода.
    Также иногда инфа извлекается из релоков, в загруженном ядре секция с ними выгружена, поэтому также нужно мапить с диска.
     
  3. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Забыл, тот код юзермодный, вот ядерный:
    Код (Text):
    1. ImageQueryEntryFromName proc uses ebx esi edi ImageBase:PVOID, FunctionName:PCHAR, RvaOrAddress:BOOLEAN, Function:PULONG
    2. Local ExportDirectory:PIMAGE_EXPORT_DIRECTORY, ImageHeader:PIMAGE_NT_HEADERS
    3. Local NumberOfNames:ULONG
    4.     mov ebx,ImageBase
    5.     invoke LdrImageNtHeader, Ebx, addr ImageHeader
    6.     test eax,eax
    7.     mov edx,ImageHeader
    8.     jnz err_image_
    9.     assume edx:PIMAGE_NT_HEADERS
    10.     mov eax,[edx].OptionalHeader.DataDirectory.VirtualAddress
    11.     test eax,eax
    12.     jz err_image_  
    13.     add eax,ebx
    14.     assume eax:PIMAGE_EXPORT_DIRECTORY 
    15.     mov ExportDirectory,eax
    16.     mov esi,[eax].AddressOfNames   
    17.     test esi,esi
    18.     jz err_table_  
    19.     mov eax,[eax].NumberOfNames
    20.     test eax,eax
    21.     jz err_table_
    22.     mov NumberOfNames,eax
    23.     add esi,ebx
    24.     xor edi,edi
    25. loop_: 
    26.     mov eax,dword ptr [esi]
    27.     add eax,ebx
    28.     invoke CompareAsciizString, FunctionName, Eax
    29.     .if Eax
    30.     mov ecx,ExportDirectory    
    31.     assume ecx:PIMAGE_EXPORT_DIRECTORY
    32.     mov eax,[ecx].AddressOfNameOrdinals
    33.     add eax,ebx
    34.     movzx edi,word ptr [2*edi+eax]
    35.     .if edi
    36.       .if edi >= [ecx]._Base
    37.       sub edi,[ecx]._Base
    38.       .endif
    39.     inc edi
    40.     .endif
    41.     mov esi,[ecx].AddressOfFunctions
    42.     add esi,ebx
    43.     mov eax,dword ptr [4*edi + esi]
    44.     test eax,eax
    45.     mov ebx,Function
    46.     jz err_image_
    47.       .if RvaOrAddress == TRUE
    48.       add eax,ImageBase
    49.       .endif
    50.     mov dword ptr [ebx],eax
    51.     xor eax,eax
    52.     .else
    53.     add esi,4
    54.     inc edi
    55.     dec NumberOfNames
    56.     jnz loop_
    57.     mov eax,STATUS_PROCEDURE_NOT_FOUND
    58.     .endif
    59. exit_:
    60.     ret
    61. err_image_:
    62.     mov eax,STATUS_INVALID_IMAGE_FORMAT
    63.     jmp exit_
    64. err_table_:
    65.     mov eax,STATUS_BAD_FUNCTION_TABLE
    66.     jmp exit_
    67. ImageQueryEntryFromName endp
     
  4. ohne

    ohne New Member

    Публикаций:
    0
    Регистрация:
    28 фев 2009
    Сообщения:
    431
  5. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    http://eretik.omegahg.com/art/02.html
    http://rsdn.ru/forum/asm/3725528.1.aspx
     
  6. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Читать нада в таком порядке, видно брехню про продуманный дизайн)
     
  7. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    А взглянуть на него можно?
     
  8. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Да и ещё основной вопрос остаётся открытым: почему возникают различия при парсинге файла на диске и загруженного(к примеру с помощью LoadLibrary\GetModuleHandle)? Как это исправить?
     
  9. slesh

    slesh New Member

    Публикаций:
    0
    Регистрация:
    6 фев 2009
    Сообщения:
    214
    грузишь файл в память, с обработкой всех секций. Это не сложно. Затем вот тебе код.
    Ему даешь имя апишки и ImageBase загруженного файла и она возвращает адрес её.
    Только обрати внимание на код:
    if ((ULONG)AddressTable < 0x80000000 && AddressTable->Name[0])
    тут я проверял что импорт идет не по имени а по ординалу. В ядре с этим могут быть проблемы из-за адреса.

    Код (Text):
    1. typedef struct _IMPORT_TABLE
    2. {
    3.     ULONG LookUp;
    4.     ULONG TimeStamp;
    5.     ULONG ForwardChain;
    6.     ULONG NameRVA;
    7.     ULONG AddresTableRVA;
    8. } IMPORT_TABLE, *PIMPORT_TABLE;
    9.  
    10. #pragma pack(1)
    11.  
    12.  
    13. typedef struct _ADDRESS_TABLE
    14. {
    15.     USHORT Hint;
    16.     char Name[];
    17. } ADDRESS_TABLE, *PADDRESS_TABLE;
    18.  
    19. #pragma pack()
    20.  
    21. ULONG FindImportAddrByApiNameInModule(char * name, ULONG filebase)
    22. {
    23.     ULONG PE;
    24.     PIMPORT_TABLE ImportTable;
    25.     PADDRESS_TABLE AddressTable;
    26.     ULONG IAT_Index;
    27.     ULONG RVA;
    28.     ULONG ret = 0;
    29.  
    30.  
    31.     PE = *(ULONG*)(filebase + 0x3C) + filebase;
    32.     if (*(ULONG*)(PE + 0x80))
    33.     {
    34.         ImportTable = (PIMPORT_TABLE)(*(ULONG*)(PE + 0x80) + filebase);
    35.    
    36.         while (ImportTable->NameRVA)
    37.         {
    38.             if (ImportTable->LookUp)
    39.             {
    40.                 RVA = ImportTable->LookUp + filebase;
    41.             }
    42.             else
    43.             {
    44.                 RVA = ImportTable->AddresTableRVA + filebase;
    45.             }
    46.            
    47.             IAT_Index = 0;
    48.            
    49.             while (*(ULONG*)RVA)
    50.             {
    51.                 AddressTable = (PADDRESS_TABLE)(*(ULONG*)RVA + filebase);
    52.            
    53.        
    54.                 if ((ULONG)AddressTable < 0x80000000 && AddressTable->Name[0])
    55.                 {
    56.                     if (!strcmp(name, AddressTable->Name))
    57.                     {
    58.                         if (ImportTable->AddresTableRVA)
    59.                         {
    60.                             ret = ImportTable->AddresTableRVA + filebase + IAT_Index;
    61.                         }
    62.                         else
    63.                         {
    64.                             ret = RVA;
    65.                         }
    66.                         return ret;
    67.                
    68.                     }
    69.                
    70.                 }
    71.                        
    72.        
    73.                 RVA += 4;
    74.                 IAT_Index += 4;
    75.             }
    76.            
    77.             ImportTable = (PIMPORT_TABLE)((ULONG)ImportTable+sizeof(IMPORT_TABLE));
    78.         }
    79.  
    80.     }
    81.    
    82.     return ret;
    83. }
     
  10. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Всем спасибо за помощь.
     
  11. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    haxorart
    Разумеется, он паблик, хотя там немного кривой(дизасм не полноценный), тут лежит аттач http://wasm.ru/forum/viewtopic.php?id=34151&p=1
    В нём собственно двиг есть, один момент - там юзермодный менеджер памяти. Удалите его и перелинкуйте.
     
  12. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Возник такой очень странный вопрос(в документации ответа не нашел): Обязательно ли таблицы с именами упорядочены по имени или это произошло в тех 2х длл, которые я разбирал? Обязательно ли адреса функций упорядочены?
     
  13. 0x6b65

    0x6b65 Забанен

    Публикаций:
    0
    Регистрация:
    8 окт 2009
    Сообщения:
    92
    Для ntoskrnl.exe и HAL.DLL - да (см. сорцы WRK: реализация MmGetSystemRoutineAddress(), MiFindExportedRoutineByName()), за остальное точно сказать не могу
     
  14. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Я смотрел kernel32.dll ntdll.dll ntoskrnl.exe там так + ещё пару PE. За это компилятор отвечает или стандарт есть?
     
  15. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Потому что есть FileAlignment, а есть и SectionAlignment.
    Научиться читать доку.
    Упомянутая MiFindExportedRoutineByName и аналог в юзере рассчитывают на это и используют binary search.
    Нет.
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    J0E
    Это аналогично как распространённый среди пишущих на дельфе код kernel32!GetProcAddress(kernel32!"GetGetProcAddress"), или типо того.
     
  17. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Поясни, какое отношение дельфе и kernel32!GetProcAddress(kernel32!"GetGetProcAddress") имеют к ядру?

    Если не понято про MiFindExportedRoutineByName, попробую по другому: реализация гарантирует, что линкер Майкрософт должен упорядочить импорт по алфавиту (написали же: см. исходник).
     
  18. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Ссылку в студию, где в доках написанно, что линкер обязан упорядочивать имена. +Учесть тот факт, что пост 0x6b65 был посде моего вопроса.
     
  19. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    haxorart
    Во-первых, этот комментарий относился к различиям образа в памяти и на диске.
    Во-вторых, страница 51:
    "Name pointer table | An array of pointers to the public export names, sorted in ascending order".
     
  20. haxorart

    haxorart New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    123
    Вопросов больше не имею, спасибо.