Показать сообщение отдельно

Hash Importer
  #6  
Старый 04.01.2007, 10:09
hidden
Постоянный
Регистрация: 23.04.2006
Сообщений: 622
Провел на форуме:
5887054

Репутация: 1292


По умолчанию Hash Importer

Алгоритм: Hash Importer
Синтаксис: fasm
Описание: Импортирует функции из модулей по ихним хэшам или номерам, при первом варианте они хешируются без учёта регистра макроинструкцией iprc, абсолютная вероятность неповторимости хэша сохраняется, только при условии, что длина имени не превышает 6 символов, не включает цифр и не зависит от регистра, тем не менее, количество вариантов настолько велико, что вероятность того что в одном модуле будут две функции одной и той-же длины и с одной и той-же хешью стремится к 0. Во время импортирования вычисляется дельта функций относительно мест, куда они будут сохранены, и сохраняются в виде относительных переходов(инструкция E9), также сохраняются и нэнделы проанализированных модулей. Всё это сохранённое добро доступно по указанным ссылкам. Установка флага AntiDebug включает проверку, если первая инструкция в импортированной функции mov edi, edi знацит пропустить эту инструкцию, что очень запутывает отладчик.
Комментарий: Макроинструкция istr содержит имена библиотек, её можно вынести в ReadOnly секцию. Да и готовые функции ProcIdByHash, ProcAddrById и BaseByAddr тоже иногда бывают полезны.
Змечания: В примере используется не invoke, a stdcall, т.к. invoke proc компилируется как call dword[proc] (вызов функции, адрес которой записан в переменной proc), а stdcall как call proc (вызов инструкции, по адресу proc), что позволяет использовать этот алгоритм в базонезависимых программах, так как call proc - relative call(Относительный вызов). Если используется подгрузка дополнительных модулей, то должна присутствовать функция LoadLibraryA, она может импортироваться из первого модуля(до подгрузки остальных) или же создана статически. Также можно создать функцию ImportErrProc, программа будет попадать на неё, при вызове функции которой не нашел импортер.
Результат работы:
Код:
до:
LoadLibraryA db         $0C                     ; Длина LoadLibraryA
             dd         $9224447C               ; Хэшь LoadLibraryA
             db         $FF                     ; Команда загрузить модуль
user         dd         $004010FC               ; Адрес строки user.str содержащий имя модуля
             db         $0B                     ; Длина MessageBoxA
MessageBoxA  dd         $1E1EC3BC               ; Хэшь MessageBoxA
             db         $FE                     ; Конец структуры
user.str     db         'user32',0

после:
LoadLibraryA jmp        kernel.LoadLibraryA     ; E9 860C407C
             db         $FF                     ; Команда загрузить модуль
user         dd         user32.77D40000         ; 0000D477 - База user32
MessageBoxA  jmp        user32.MessageBoxA      ; E9 EFF39777
             db         $FE                     ; Конец структуры
user.str     db         'user32',0
Пример вызова:
Код:
format PE GUI 4.0
entry start

AntiDebug equ

include 'win32a.inc'
include 'utils.inc'

myi:
  iprc LoadLibraryA, 'LoadLibraryA'
  imod user, 'user32'
  iprc MessageBoxA, 'MessageBoxA'
  endi
  istr user

tit     db 'Message',0;
txt     db 'Example of Hash importer',0

start:
        stdcall BaseByAddr, [esp+4] ; or stdcall GetKernel without parametrs
        stdcall importer, eax, myi
        stdcall MessageBoxA, 0, txt, tit, 0
        ret
Код:
macro iprc [proc, name]
 { forward
    if used proc | proc eq LoadLibraryA
     if name eqtype ''
      local ch
      local hash
      local length
      virtual at 0
       db name
       length = $
       hash = 0
       repeat length
        load ch byte from length-%
        hash = ((hash shl 5) or (hash shr (32 - 5))) and $FFFFFFFF ; hash = hash rol 5
        hash = hash xor (ch and 11111b)
       end repeat
      end virtual
      virtual at $
       proc dd ?
      end virtual
      db length ; Length, if $ff then load lib, if $fe then end, if $fd then by id
      dd hash
     else
      db $fd
      dd name+1
     end if
    end if }

macro imod [module, str]
 { forward
    db $fe
    module dd module#.str - $
    module#.text equ str }

macro istr [module]
 { forward
    module#.str db module#.text, 0 }

macro endi ierrproc
 { db $ff }

struct IED
 Characteristics        dd ? ;This field appears to be unused and is always set to 0.
 TimeDateStamp          dd ? ;The time/date stamp indicating when this file was created.
 Version                dd ? ;These fields appear to be unused and are set to 0.
 Name                   dd ? ;The RVA of an ASCIIZ string with the name of this DLL.
 Base                   dd ? ;The starting ordinal number for exported functions. For example, if the file exports functions with ordinal values of 10, 11, and 12, this field contains 10. To obtain the exported ordinal for a function, you need to add this value to the appropriate element of the AddressOfNameOrdinals array.
 NumberOfFunctions      dd ? ;The number of elements in the AddressOfFunctions array. This value is also the number of functions exported by this module. Theoretically, this value could be different than the NumberOfNames field (next), but actually they're always the same.
 NumberOfNames          dd ? ;The number of elements in the AddressOfNames array. This value seems always to be identical to the NumberOfFunctions field, and so is the number of exported functions.
 AddressOfFunctions     dd ? ;This field is an RVA and points to an array of function addresses. The function addresses are the entry points (RVAs) for each exported function in this module.
 AddressOfNames         dd ? ;This field is an RVA and points to an array of string pointers. The strings are the names of the exported functions in this module.
 AddressOfNameOrdinals  dd ? ;This field is an RVA and points to an array of WORDs. The WORDs are the export ordinals of all the exported functions in this module. However, don't forget to add in the starting ordinal number specified in the Base field.
ends

proc ProcIdByHash, base, hash, len:byte
        xchg    edi, [base]
        push    ebx ecx edx esi

        mov     ebx, [edi+$3C] ; OffSet to PE Header
        mov     ebx, [edi+ebx+$78] ; Offset to Export section

        push    ebx
        mov     ecx, [edi+ebx+IED.NumberOfNames] ; NumberOfFunctions - Stupid MSDN writers, who have trying to import from ws2_32 that understend
        mov     ebx, [edi+ebx+IED.AddressOfNames]
        add     ebx, edi

  .next:mov     esi, [ebx+ecx*4-4]
        add     esi, edi
        mov     edx, [hash]
        movzx   eax, [len]
        cmp     byte[esi+eax], 0
        jne     .wrng
  @@:   lodsb
        or      al, al
        jz      @f
        and     al, 11111b
        xor     dl, al
        ror     edx, 5
        jmp     @b
  @@:   or      edx, edx
        jz      .ret ; @f
  .wrng:loop    .next
        xor     eax, eax
        jmp     .end
  .ret: pop     ebx
        mov     eax, [edi+ebx+IED.AddressOfNameOrdinals]
        add     eax, edi
        movzx   eax, word[eax+ecx*2-2]
        add     eax, [edi+ebx+IED.Base]

  .end: pop     esi edx ecx ebx
        mov     edi, [base]
        ret
endp

proc ProcAddrById, base, id
        xchg    edi, [base]
        xchg    ebx, [id]

        mov     eax, [edi+$3C] ; OffSet to PE Header
        mov     eax, [edi+eax+$78] ; Offset to Export section
        sub     ebx, [edi+eax+IED.Base]
        mov     eax, [edi+eax+IED.AddressOfFunctions]

        add     eax, edi

        mov     eax, [eax+ebx*4]
        add     eax, edi

        mov     ebx, [id]
        mov     edi, [base]
        ret
endp

proc GetKernel
        xor     eax, eax
        mov     eax, [fs:eax+30h]
        test    eax, eax
        js      ngk
        mov     eax, [eax+0Ch]
        mov     esi, [eax+1Ch]
        lodsd
        mov     eax, [eax+8]
        jmp     egk
ngk:    mov     eax, [eax+34h]
        add     eax, 7Ch
        mov     eax, [eax+3Ch]
egk:    ret
endp

proc BaseByAddr, addr
        mov     eax, [addr]

        xor     ax, ax
  @@:   cmp     word[eax], 'MZ'
        jz      @f
        sub     eax, $10000
        jmp     @b
  @@:   ret
endp

proc importer, kernel, imports
        xchg    esi, [imports]
        xchg    edi, [kernel]

        ;stdcall BaseByAddr, edi
        ;mov     edi, eax

  .loop:lodsb
        cmp     al, $fd
        ja      .more
        je      .byid
        mov     ah, al

        or      edi, edi
        jz      .xxx

        stdcall ProcIdByHash, edi, [esi], [esi-1]

        or      eax, eax
        if      defined ImportErrProc
         jnz      @f
         lea     eax, [esi-ImportErrProc]
         mov     eax, errfunc
         lodsd
         jmp     .stor
  @@:   else
         jz     .stor
         display 'ImportErrProc is undefined',13,10
        end     if

  .gbi: stdcall ProcAddrById, edi, eax

  .stor:if      AntiDebug eq
         cmp     word[eax], $FF8B
         jnz     @f
         add     eax, 2
  @@:   end     if
         sub     eax, 4

  @@:   sub     eax, esi
        mov     byte[esi-1], $E9
        mov     dword[esi], eax
  .xxx: lodsd
        jmp     .loop

  .byid:mov     eax, [esi]
        jmp     .gbi

  .more:cmp     al, $ff
        je      .endi
        lodsd

        if      defined LoadLibraryA
         lea     eax, [eax+esi-4]
         stdcall LoadLibraryA, eax
         mov     edi, eax
         mov     [esi-4], eax
        else
         display 'LoadLibraryA is undefined',13,10
        end     if

        jmp     .loop

  .endi:mov     edi, [kernel]
        mov     esi, [imports]
        ret
endp
Особые извращенцы над компилятором(шутка), могут воспользоваться таким способом импортирования функций, как приведён ниже. В некоторых случаях очень удобно, потому что, находит почти любую функцию которая может понадобится, хотя придётся немного(на моём примерно 0,9 seconds) подождать. Он не включает неиспользуемые функции, но он не проверяет, используется ли модуль, так что все модули включать не стоит, а-то он их все загрузит.
Код:
myi:
  include '\imp\kernel32.inc'
  include '\imp\ntdll.inc'
  include '\imp\advapi32.inc'
  include '\imp\comdlg32.inc'
  include '\imp\gdi32.inc'
  include '\imp\ole32.inc'
  include '\imp\oleaut32.inc'
  include '\imp\shell32.inc'
  include '\imp\shlwapi.inc'
  include '\imp\user32.inc'
  endi
  istr ntdll, advapi, comdlg, gdi, ole, oleaut, shell, shlwapi, user
А также все эти файлы, с выдранными функциями из данных модулей WindowsXP ниже в архиве, мучийте свой компилятор на здоровье

Updates:
- Добавлена относительность имён загружаемых библиотек
- возможность импорта по ордилалу
- исправле недочёт(по вине этих грёбаных писателей MSDN) с возможным не совпадением количества функций с количеством их имён.
Вложения
Тип файла: zip imp.zip (48.9 Кб, 17 просмотров)

Последний раз редактировалось hidden; 21.01.2007 в 19:31..
 
Ответить с цитированием