Получение базы kernel32.dll [Asm]

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by isqad88, 20 Jan 2010.

  1. isqad88

    isqad88 New Member

    Joined:
    16 Dec 2009
    Messages:
    14
    Likes Received:
    0
    Reputations:
    0
    Вот решил провести эксперимент и написал (не без помощи сайтов) прогу (masm32), которая определяет адрес базы kernel32.dll:
    Code:
    .386
    option casemap:none
    .model flat, stdcall
    ;----------------------------include---------------------
    includelib \masm32\lib\kernel32.lib
    include \masm32\include\kernel32.inc
    ;--------------------------------------------------------
    
    .data
        db 0
    
    .code
        start:
            mov esi, [esp]
            call GetBase; после вызова в eax база kernel32.dll
            invoke ExitProcess, 0
    
    ;#####################################GetBase###############################
    ;
    ;                 Получение базы kernel32.dll
    ;
    ;###########################################################################
    GetBase:
       
    	push esi;сохраняем все регистры, которые используются
    	push ecx
    
    	pushf;сохраняем регистр флагов
    	and esi,0FFFF0000H;гранулярность выделения памяти
    	mov ecx,6;счетчик страниц
    
    _@1:            ;проверка очередной страницы
    	  
            cmp word ptr [esi], "ZM"
            jz WeGotBase
    _@2:
            sub esi, 10000h
            loop _@1
    WeFailed:
            mov eax, 00000000h ;база не найдена
            jmp EndGetBase
    WeGotBase:
        xchg eax, esi
            
    
    EndGetBase:	
    	popf;восстанавливаем значения флагов
    	pop ecx
    	pop esi;восстанавливаем значения регистров
    	ret
    
    ;#########################################################################
    ;Конец процедуры GetBase
    ;#########################################################################
    end start
    
    
    В Windows XP SP3 я получил адрес базы 7C800000h в Windows 7 77140000h
     
  2. Hiro Protagonist

    Joined:
    26 Aug 2009
    Messages:
    132
    Likes Received:
    24
    Reputations:
    -2
    cmp word ptr [esi], "ZM"
    jz WeGotBase

    после этого чекай на PE. А вообще байан редкостный. Тем более для dll не подходит.
     
  3. isqad88

    isqad88 New Member

    Joined:
    16 Dec 2009
    Messages:
    14
    Likes Received:
    0
    Reputations:
    0
    cmp word ptr [esi], "ZM" - разве это не есть проверка на PE
     
  4. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    спрашивается а нафига её искать методом поиска?
    Если же можно тупо взять из PEB
    Вариант с подмененным и неправильным PEB'ом можно расценивать как манию приследывания и последюю стадию шизофрении. Так что лучше юзать через PEB
    Под 2k, XP, 2k3 ты получишь адрес kernel32.dll а под w7 - адрес KERNELBASE
    KERNELBASE - это считай жалкий аналог kernel32.dll
    Но есть хитрость. В них в обоих есть функции GetProcAddress и LoadLibraryExA
    через который можно загрузить любую либу (хотябы туже kernel32 для w7)
    Для всякого малвара своего юзаю примерно такую схему:

    Code:
    __declspec(naked) HMODULE GetKernel32(void)
    {
    	__asm 
    	{
    		push    esi
    		xor     eax,eax
    		mov     eax,fs:[0x30]
    		js      find_kernel_9x
    		mov     eax,[eax+0x0c]
    		mov     esi,[eax+0x1c]
    		lodsd
    		mov     eax,[eax+0x8]
    		jmp     find_kernel_end
    find_kernel_9x:
    		mov		eax,[eax+0x34]
    		lea		eax,[eax+0x7c]
    		mov		eax,[eax+0x3c]
    find_kernel_end:
    		pop     esi
    		ret
    	}
    }
    
    KERNELBASE = GetKernel32();
    *(void* *)&_LoadLibraryExA = HideGetProcAddress(KERNELBASE, "LoadLibraryExA");
    *(void* *)&_GetProcAddress = HideGetProcAddress(KERNELBASE, "GetProcAddress");
    
    if (!_LoadLibraryExA || !_GetProcAddress) return 0;
    
    kernel32_dll = _LoadLibraryExA("kernel32.dll", 0, 0);
    итд итп.
    
    HideGetProcAddress - самописная функция поиска адреса функции (когдато выкладывал тут её)
    И пашет идеально на всей линейке NT начиная от 2k

    Другое дело в ядре искать адрес загрузки ядра, Там это уже нужно осуществлять перебор.
    Вот пример
    Code:
     mov esi, dword ptr ds:[0ffdff038h]; адрес обработчика для IDLE
     lodsd
     cdq 
     lodsd
    base_loop: 
     dec eax 
     cmp dword ptr [eax], 00905a4dh ; сигнатура для файла ядра MZ+P+0x00
     jnz base_loop  
     mov lib, eax
    
    Но этот код очень удобно юзать под ядром. Вернее под ядром его тока и можно заюзать )
     
  5. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    >>>> cmp word ptr [esi], "ZM" - разве это не есть проверка на PE
    это проверка на дос заголовок. В досовских exe файлах и в старом LE нету PE заголовка )
    Проверка на PE делается так
    1) находится ImageBase и проверяется сигнатура MZ
    2) ImageBase + 0x3С - по этому офсету хранится DWORD указывающий смещение (относительно ImageBase) на PE заголовок
    3) ImageBase + офсет на PE и по этому адресу проверяется двойное слово
    на сигнатуру 'P' 'E' 0x00 0x00
     
  6. Hiro Protagonist

    Joined:
    26 Aug 2009
    Messages:
    132
    Likes Received:
    24
    Reputations:
    -2
    2slesh
    жесть, зачем это делать ассемблерной вставкой? али влом структуры описывать и пользоваться макросами для LIST_ENTRY?
     
  7. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    по старинке юзаю из шелкодов )
    Но вообще некоторые операции без асм вставки будут некрасиво выглядеть. Допустим та же mov eax,fs:[0x30], которую придется заменить на соотвествующую апишку
     
  8. Hiro Protagonist

    Joined:
    26 Aug 2009
    Messages:
    132
    Likes Received:
    24
    Reputations:
    -2
    дык понятно, я это тоже вставкой делаю. Но доступ то к полям пеба )))
     
  9. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    Code:
    mov     esi,[eax+0x1c]
    lodsd
    mov     eax,[eax+0x8]
    
    зачем тут еsi?)

    А ещё сравнил бы на всякий случай имя библиотеки
     
  10. Hiro Protagonist

    Joined:
    26 Aug 2009
    Messages:
    132
    Likes Received:
    24
    Reputations:
    -2
    2desTiny
    как зачем, а указать lodsd откуда грузить значение? Мы ж обращаемся ко второму LDR_MODULE_ENTRY в цепочке.
    а проверять не нужно, там постоянно ntdll->kernel32->[user32]->...
     
    #10 Hiro Protagonist, 21 Jan 2010
    Last edited: 21 Jan 2010
  11. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    mov esi,[eax+0x1c]
    lodsd

    ~

    mov eax, [eax+0x1c]
    mov eax, [eax]

    и нафиг не нужны эти первый пуш и последний поп

    >> там постоянно
    никто ничего не обещает. Вот если ты так уверен в порядке - ну-ка сходу скажи, где в цепочке будет kernelbase.dll?
     
  12. isqad88

    isqad88 New Member

    Joined:
    16 Dec 2009
    Messages:
    14
    Likes Received:
    0
    Reputations:
    0
    как получать API? Сколько кода просмотрел нигде не нашел рабочего
     
  13. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    почитай например http://www.phrack.com/issues.html?issue=62&id=7
     
  14. Adio

    Adio Elder - Старейшина

    Joined:
    23 May 2005
    Messages:
    1,646
    Likes Received:
    148
    Reputations:
    18
    Таких пару статей прочитьтать и на дурку )))
     
  15. Hiro Protagonist

    Joined:
    26 Aug 2009
    Messages:
    132
    Likes Received:
    24
    Reputations:
    -2
    2desTiny
    а зачем мне kernelbase.dll?
    главное я чотко уверен, что под всей линейкой ntdll->kernel32. Остальное в принципе не интересно ) в данном случае. Поэтому проверять не надо.
     
  16. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    >>главное я чотко уверен
    А вот семёрке плевать на твою уверенность.
     
  17. Hiro Protagonist

    Joined:
    26 Aug 2009
    Messages:
    132
    Likes Received:
    24
    Reputations:
    -2
    ладно, пойду семерку ставить на виртуалку и смотреть )
     
  18. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Для самоуверенных читать мой пост где я кинул кусок кода и там описал что и как.
    И То что нужно искать там LoadLibraryExA/W потому что других подобных нету.
    Это пришлось сделать именно из-за W7 потому как именно kernelbase там получалась а не kernel32.
     
  19. isqad88

    isqad88 New Member

    Joined:
    16 Dec 2009
    Messages:
    14
    Likes Received:
    0
    Reputations:
    0
    Верно ли написан код получения GetProcAddress ? Вроде все как в туториале
    Code:
    .386
    .model flat, stdcall
    option casemap:none
    
    includelib \masm32\lib\kernel32.lib
    
    ExitProcess PROTO : DWORD
    .data
    	db 0
    	ProcAd db "GetProcAddress",0h
    	Counter db 0h
    	OrdinalTableVA db 0h
    	AddressTableVA db 0h
    	Kernel db 0h
    .code
    	
    	
    start:
    	;считаем дельта смещение
    	call VirDelta
    	VirDelta:
    		sub dword ptr [esp], offset VirDelta
    		push dword ptr [esp]
    		;jmp ReadSEH
    	
    		; Читаем SEH
    ReadSEH:
        xor    edx, edx              ; edx = 0
        assume fs:flat
        mov    eax, fs:[edx]         ; читаем элемент SEH
        dec    edx                   ; edx = 0FFFFFFFFh
    
    ; Ищем элемент со значением 0FFFFFFFFh
    SearchKernel32:
        cmp    [eax], edx            ; сравниваем очередной с 0FFFFFFFFh
        je     CheckKernel32         ; прыгаем, если нашли
        mov    eax, [eax]            ; получаем следующее значение
        jmp    SearchKernel32        ; если не нашли - ищем дальше
    
    ; Определяем адрес Kernel32
    CheckKernel32:
        mov    eax, [eax + 4]        ; получаем адрес ГДЕ-ТО в 
                                     ; kernel32.dll
        xor    ax, ax                ; выравниваем полученный адрес
    
    ; Ищем сигнатуру MZ
    SearchKernelMZ:          
        cmp word ptr [eax], 5A4Dh    ; сверяем сигнатуру MZ
        je  CheckKernelMZ            ; сигнатура верна, переходим на 
                                     ; проверку сигнатуры PE
        sub eax, 10000h              ; если не равна MZ, то ищем дальше
        jmp SearchKernelMZ
    
    ; Проверяем сигнатуру PE
    CheckKernelMZ:	
        mov  edx, [eax + 3Ch]        ; переходим на PE-заголовок
        cmp  word ptr [eax + edx], 4550h ; сверяем сигнатуру
        jne  _Exit                   ; неверная сигнатура, поэтому 
                                     ; выходим
    	call GetAPI
    	
    _Exit:
    		invoke ExitProcess, 0h
    	
    ;поиск адреса GetProcessAddress
    GetAPI:
    mov edx, offset Kernel
    mov [edx], eax
    mov esi, offset ProcAd
    mov edx, esi
    @_1:
    	cmp byte ptr [esi], 0; конец строки?
    	jz @_2
    	inc esi
    	jmp @_1
    @_2:
    	inc esi
    	sub esi, edx
    	mov ecx, esi
    ;;теперь в ecx и esi находится размер имени функции GetProcessAddress (12h символов)
    
    
    mov ebx, eax
    xor eax, eax
    mov esi, ebx
    add esi, 3Ch ;заголовок PE
    lodsw
    add eax, ebx
    mov esi, [eax + 78h] ;RVA таблицы экспортов
    add esi, ebx ;указатель на RVA таблицы адресов
    add esi, 1ch
    
    lodsd ;eax = RVA таблицы адресов
    add eax, ebx ;eax VA таблицы адресов
    mov edx, offset AddressTableVA
    mov[edx], eax
    ;push eax ;сохраняем
    
    lodsd ;eax = RVA таблицы указателей на имена
    add eax, ebx ; eax = VA таблицы указателей на имена
    
    push eax ;сохраняем
    
    lodsd ;eax = RVA таблицы ординалов
    add eax, ebx
    mov edx, offset OrdinalTableVA
    mov [edx], eax
    ;push eax
    pop esi
    @_3: push esi ;сохраняем VA таблицы указателей на имена
    	lodsd
    	add eax, ebx
    	mov esi, eax
    	mov edi, offset ProcAd
    	push ecx
    	cld
    	repe cmpsb
    	pop ecx
    	jz @_4
    	pop esi
    	add esi, 4
    	mov edx, [offset Counter]
    	inc edx
    	push ecx
    	mov ecx, offset Counter
    	mov [ecx], edx
    	pop ecx
    	jmp @_3
    	@_4:
    	pop esi
    	mov edx, offset Counter
    	mov eax, [edx]
    	shl eax, 1
    	mov edx, offset OrdinalTableVA
    	add eax, [edx]
    	shl eax, 2
    	mov edx, offset AddressTableVA
    	add eax, [edx]
    	mov edx, offset Kernel
    	add eax, [edx]
    	ret
    	
    
    
    
    	
    		
    
    end start
    
    по идее в EAX должен остаться адрес этой функции...Сильно не ругайте за корявый код я только начал учить асму