19 November 2013

Śliskie kody w asemblerze

Od jakiegoś czasu testuję możliwości OllyDbg 2.01. Nigdy nie wykorzystywałem tego debuggera w pracy - ale od wielu lat projekt się rozwija i może być podstawowym narzędziem pracy dla analityków - nie tylko początkujących. Chciałem sprawdzić jak poradzi sobie z jedną z najstarszych sztuczek crackerów - śliskie kody. Jest to metoda ukrywania opkodów instrukcji procesora, w parametrach instrukcji asemblera. Implementacja takich kodów w MASM32 nie jest specjalnie trudna, ale wymaga wielu testów przed publikacją programu - ich zastosowanie, może prowadzić do groźnych błędów czasu wykonania. Metoda utrudnia analizę kodu wykonywalnego, dlatego jest wykorzystywana przez blackHat's do ukrywania szkodników lub do ochrony własności intelektualnych przez producentów softu. Tak czy inaczej analityk musi umieć rozpoznać taki kod. Nie jest to trudne bo debuggery zaczynają zachowywać się dziwnie - kod w oknie się śliska - dosłownie. Najgorsze jest to, że dopiero śledzenie instrukcji ujawnia prawdę o programie. Poniżej prezentuję przykład wykorzystujący śliskie kody w asemblerze.
  .486
  .model flat, stdcall
  option casemap :none
 
include         \masm32\include\windows.inc
include         \masm32\include\kernel32.inc
include         \masm32\include\user32.inc
includelib      \masm32\lib\user32.lib
includelib      \masm32\lib\kernel32.lib

  .data
    MsgCaption    db "www.FiveWithFour.blogspot.com",0
    MsgBoxText    db "Dummy Codes Example",0

  .code
start:
        invoke MessageBox, NULL, addr MsgBoxText, addr MsgCaption, MB_OK
@Code:  add eax, 009Eb336Ah  
        mov esi, 012345678h
        jmp @Code+1
        invoke MessageBox, NULL, addr MsgBoxText, addr MsgCaption, MB_OK  
        invoke ExitProcess, NULL
end start 

Czytając źródło stwierdzamy, że program wyrzuci po kolei dwa jednakowe okna typu MB_OK z informacją. Ale rezultat jest taki:


Pierwsze okno jest to MB_OK (wywołane w kodzie), ale drugie z takim samym wywołaniem jest kombinacją MB_ICONWARNING i MB_YESNOCANCEL - pomimo braku odpowiednich parametrów w źródle. Kod został wykonany w inny sposób i aby zobaczyć jak, należy użyć disassembler'a np. OllyDbg, który raczej średnio poradził sobie z dekompilacją, a debugger pozostawia wiele do życzenia - przynajmniej z "fabrycznymi" ustawieniami. IDA 6.3 Demo poprawnie przetłumaczyła binarkę na kod asemblera, a debugger wykrył modyfikację kodu w trakcie wykonania. Wykorzystałem standardowy build.bat z MASM32 - dla chcących sprawdzić jak to właściwie działa. Wnioskiem jest to, że darmowa IDA (okrojone funkcje) poradziła sobie lepiej z nietypowym kodem niż OllyDbg.
Poniżej zrzuty z IDA - pierwszy disasemblowany plik - poprawnie jak w źródle, drugi to faktycznie wykonywane instrukcje przez procesor - mov esi, 012345678h w źródle to dodatkowy kod - wszystko dla zmylenia wroga ;-)
Kod przed wykonaniem:

Kod po wykonaniu:


Drugi screen wyraźnie jest nieczytelny nawet w IDA. Taka metoda ochrony kodu przed analizą może być utrudnieniem ale też prowokuje analityków. Kod wygląda na niszczycielski i pozbawiony sensu ale nie zostanie wykonany - dlatego śliskie kody mogą mylić ale nie są trudne do opanowania - ich pojawienie się może świadczyć o ukrytych możliwościach procedur. O wiele trudniejszy w analizie jest nawet prosty kod napisany w odpowiednim języku wysokiego poziomu i skompilowany jednym z wszystkorobiących kompilatorów.