Analiza aplikacji ConEmu z użyciem disassemblera IDA.

Po ostatnim wpisie dotyczącym wykorzystania IDR do zmodyfikowania aplikacji napisanej w Delphi, tym razem postanowiłem pokazać jak szybko możemy udoskonalić aplikację ConEmu z wykorzystaniem disassemblera IDA w celu przeanalizowania jej składników, również w postaci 64 bitowej.Analizowanym programem tym razem będzie ConEmu napisany w C++. Program ten pozwala nam na korzystanie z aplikacji konsolowych lub samej konsoli pod cmd.exe na pełnym ekranie (co jest normalnie niemożliwe w systemach od Visty wzwyż), posiada on również wiele dodatkowych opcji i możliwości. ConEmu można pobrać stąd. Oczywiście są dostępny jest jego kod źródłowy, ale my chcemy dokonać tylko drobnej modyfikacji, a poza tym możemy bardzo słabo znać C++ (jak ja :)) i nie posiadać w danej chwili żadnych zainstalowanych środowisk do kompilacji źródeł. Do analizy wykorzystamy znany za pewne wielu z Was dissasmebler IDA autorstwa firmy Hex-Rays. Niestety musicie sobie go sami wygooglować. Możecie się też wspomóc wersją free.

Cel modyfikacji.

Po pobraniu archiwum *.7z i jego rozpakowaniu do jakiegoś katalogu, uruchommy jeden z głównych plików wykonywalnych. Ja pomimo iż posiadam zainstalowany system Windows 7 w wersji 64 bitowej, uruchomię conemu.exe i teraz proponuję go od razu ustawić. Najwygodniej do ekranu ustawień jeżeli mamy konsolę ustawioną na pełen ekran (a ja tak preferuję ze względu na słabszy wzrok i wygodę czytania tekstów wyświetlanych przez inne aplikacje uruchomione pod ConEmu) dostaniemy się dzięki kombinacji klawiszy Lewy Klawisz Windows + Alt + P. Ja preferuję takie ustawienia jakie są zawarte w umieszczonym poniżej pliku, który został wyeksportowany z Rejestru Windows. Wystarczy go pobrać stąd w postaci archiwum ZIP, a następnie rozpakować i wypakowany plik *.reg importować dwuklikiem z pod Eksploratora Windows lub z pod Total Commandera naciskając po jego wybraniu kursorami klawisz Enter. Potwierdzając operację klikając na „Tak”. Należy tego dokonać najlepiej przy zamkniętym ConEmu. Ustawienia jakie przygotowałem mogą wymagać jedynie zmiany wartości „size” oraz „width” w zakładce „Main” w polu „Font”. W moim przypadku prawidłowe wyświetlanie osiągnąłem ustawiając te wartości odpowiednio na 33 oraz 18. Program prezentuje się tak jak na ekranie poniżej, po uruchomieniu przez conemu.exe i chęci jego natychmiastowego zamknięcia poleceniem konsolowym „exit”. Jak widzimy ukazuje się komunikat żądający potwierdzenia zamknięcia okna konsoli (mimo wyłączenia wszelkich dostępnych do ustawienia potwierdzeń w preferencjach aplikacji).

Jest to dość irytujące, bo komunikat występuje oczywiście również w przypadku otwieranych innych aplikacji. A ConEmu możemy używać z File Managerem FAR lub używanym w poprzednim wpisie hex edytorze HIEW. Ja osobiście używam właśnie FAR’a skojarzonego z Total Commanderem do poglądu i edycji plików, a wiadomo że czasem podejrzymy jakiś plik na mniej niż 10 sekund, więc będziemy zmuszeni do oglądania tego komunikatu i naciskania dodatkowych klawiszy aby zamknąć ConEmu. Spróbujmy więc się pozbyć tej niedogodności.

Analiza miejsca koniecznego do modyfikacji.

Pod Total Commanderem w katalogu, do którego rozpakowaliśmy ConEmu naciśnijmy kombinację klawiszy Alt+F7 i jako szukaną sekwencję wpiszmy * (gwiazdkę), a jako szukany tekst: „Root process was alive” (oczywiście bez cudzysłowów) i naciśnijmy Enter. Nie znalazło nic. Spróbujmy więc to samo poszukać, ale dodatkowo zaznaczmy checkbox „Unicode”. Udało się. Tekst znajduje się w bibliotekach dll o nazwach: conemucd.dll i conemucd64.dll w podkatalogu CONEMU. Sprawdźmy trochę lamerskim, ale za to pewnym sposobem na stwierdzenie, z której dllki korzysta proces conemu.exe w trakcie uruchomienia go bez parametrów (czyli wywołania cmd.exe) uruchamiając HIEW i ładując najpierw conemucd.dll, naciskamy F3 (w widokach „Decode” lub „Hex”, na które możemy przełączyć się naciskając klawisz F4 lub Enter). Edycja jest możliwa. Otwórzmy teraz conemucd64.dll i naciśnijmy F3, otrzymujemy komunikat błędu o treści „Sharing violation”. Ok, czyli jeżeli proces jest 64 bitowy (a takowym jest cmd.exe w wersji 64 bitowej Windows 7) to conemu.exe mimo wszystko korzysta z conemucd64.dll. Pora na przeanalizowanie tej biblioteki w 64 bitowej wersji IDA. Przejdźmy do katalogu, do którego rozpakowaliśmy disassembler IDA i uruchommy idaq64.exe, następnie zamknijmy okienko informacyjne kliknięciem na „OK”, a później w kolejnym oknie kliknijmy na przycisk „Go” i przeciągnijmy na pole „Drag a file here to disassemble it.” plik conemucd64.dll. W nowym oknie potwierdzamy ustawienia klikając na „OK”. Jeśli pokaże się nam informacja o wykryciu debug informations, potwierdźmy że chcemy je wczytać. I teraz jeżeli załadował nam się plik w widoku tak zwanych grafów, to z menu „Options” wybierzmy polecenie „General” i w nowym oknie na zakładce „Graph” odznaczmy checkbox „Use graph view by default”. Widok grafów często się przydaje, ale w tym wypadku wygodniej będzie posłużyć się jednak widokiem kodu czyli „Disassembly”. Najszybciej przełączymy się na niego z okna „Quick view”, które wywołamy naciskając kombinację klawiszy Ctrl+1. Teraz będąc w widoku „Disassembly” naciskamy kombinację klawiszy Alt+T i w oknie „Text search” odznaczmy „Case sensitive” (oczywiście jeśli jest zaznaczone) i upewnijmy się, że zaznaczony jest checkbox „Find all occurences”, a „Direction” ustawione jest na „Search Down”. Wpiszmy tekst: „root process was” (bez cudzysłowów oczywiście) i naciśnijmy klawisz enter. Wybierzmy pierwszą pozycję, która znajduje się na liście wyników wyszukiwania. Naszym oczom powinien ukazać się taki fragment kodu jak na zrzucie ekranu poniżej.

Przyjrzyjmy się temu kodowi, przewijając go również nieco na dół.

.text:0000000054612BB0 loc_54612BB0: ; CODE XREF: ConsoleMain2+145Ej
.text:0000000054612BB0 cmp cs:dword_5465F2D4, 1
.text:0000000054612BB7 jnz short loc_54612C06
.text:0000000054612BB9 cmp cs:dword_5465F2D0, 0
.text:0000000054612BC0 jz short loc_54612BF7
.text:0000000054612BC2 cmp cs:dword_5465F2C4, 1
.text:0000000054612BC9 jz short loc_54612BF7
.text:0000000054612BCB mov r8d, cs:ExitCode
.text:0000000054612BD2 lea rdx, aConemucRootPro ; "\n\nConEmuC: Root process was alive less "...
.text:0000000054612BD9 lea rcx, word_5465F440 ; LPWSTR
.text:0000000054612BE0 call cs:wsprintfW
.text:0000000054612BE6 lea rdx, word_5465F440
.text:0000000054612BED mov [rsp+18C8h+lpBuffer], rdx
.text:0000000054612BF5 jmp short loc_54612C06
.text:0000000054612BF7 ; ---------------------------------------------------------------------------
.text:0000000054612BF7
.text:0000000054612BF7 loc_54612BF7: ; CODE XREF: ConsoleMain2+14B0j
.text:0000000054612BF7 ; ConsoleMain2+14B9j
.text:0000000054612BF7 lea rax, aPressEnterOr_0 ; "\n\nPress Enter or Esc to close console.."...
.text:0000000054612BFE mov [rsp+18C8h+lpBuffer], rax
.text:0000000054612C06
.text:0000000054612C06 loc_54612C06: ; CODE XREF: ConsoleMain2+149Ej
.text:0000000054612C06 ; ConsoleMain2+14A7j ...
.text:0000000054612C06 cmp [rsp+18C8h+lpBuffer], 0
.text:0000000054612C0F jnz short loc_54612C20
.text:0000000054612C11 lea rax, aPressEnterOr_1 ; "\n\nPress Enter or Esc to close console, "...
.text:0000000054612C18 mov [rsp+18C8h+lpBuffer], rax
.text:0000000054612C20
.text:0000000054612C20 loc_54612C20: ; CODE XREF: ConsoleMain2+14FFj
.text:0000000054612C20 mov cs:dword_5465F2B8, 1
.text:0000000054612C2A mov eax, 0Dh
.text:0000000054612C2F mov word ptr [rsp+18C8h+var_98], ax
.text:0000000054612C37 mov eax, 1Bh
.text:0000000054612C3C mov word ptr [rsp+18C8h+var_98+2], ax
.text:0000000054612C44 xor eax, eax
.text:0000000054612C46 mov word ptr [rsp+18C8h+var_98+4], ax
.text:0000000054612C4E mov r9d, [rsp+18C8h+var_90] ; int
.text:0000000054612C56 mov r8d, 1 ; int
.text:0000000054612C5C mov rdx, [rsp+18C8h+lpBuffer] ; lpBuffer
.text:0000000054612C64 lea rcx, [rsp+18C8h+var_98] ; __int64
.text:0000000054612C6C call sub_54616F50
.text:0000000054612C71 cmp [rsp+18C8h+var_174C], 72h
.text:0000000054612C79 jnz short loc_54612CAB
.text:0000000054612C7B mov rax, cs:qword_5465F328
.text:0000000054612C82 mov eax, [rax+958h]
.text:0000000054612C88 mov [rsp+18C8h+var_84], eax
.text:0000000054612C8F cmp [rsp+18C8h+var_84], 1
.text:0000000054612C97 jg short loc_54612CA6
.text:0000000054612C99 mov rax, cs:qword_5465F328
.text:0000000054612CA0 cmp dword ptr [rax+70h], 0
.text:0000000054612CA4 jz short loc_54612CAB
.text:0000000054612CA6
.text:0000000054612CA6 loc_54612CA6: ; CODE XREF: ConsoleMain2+1587j
.text:0000000054612CA6 jmp loc_54612771
.text:0000000054612CAB ; ---------------------------------------------------------------------------
.text:0000000054612CAB
.text:0000000054612CAB loc_54612CAB: ; CODE XREF: ConsoleMain2+12EEj
.text:0000000054612CAB ; ConsoleMain2+1346j ...
.text:0000000054612CAB cmp cs:hEvent, 0
.text:0000000054612CB3 jz short loc_54612CD9
.text:0000000054612CB5 cmp cs:dword_5465F294, 0
.text:0000000054612CBC jnz short loc_54612CD4
.text:0000000054612CBE mov ecx, cs:dword_5465F2A0
.text:0000000054612CC4 mov eax, cs:dword_5465F2A4
.text:0000000054612CCA lea eax, [rcx+rax+0Bh]
.text:0000000054612CCE mov cs:dword_5465F294, eax
.text:0000000054612CD4
.text:0000000054612CD4 loc_54612CD4: ; CODE XREF: ConsoleMain2+15ACj
.text:0000000054612CD4 call sub_546172F0
.text:0000000054612CD9
.text:0000000054612CD9 loc_54612CD9: ; CODE XREF: ConsoleMain2+15A3j
.text:0000000054612CD9 cmp cs:qword_5465F2A8, 0
.text:0000000054612CE1 jz short loc_54612CF0
.text:0000000054612CE3 mov rcx, cs:qword_5465F2A8 ; hEvent
.text:0000000054612CEA call cs:SetEvent
.text:0000000054612CF0
.text:0000000054612CF0 loc_54612CF0: ; CODE XREF: ConsoleMain2+15D1j
.text:0000000054612CF0 mov dword ptr [rsp+18C8h+var_18A8], 0
.text:0000000054612CF8 xor r9d, r9d
.text:0000000054612CFB xor r8d, r8d
.text:0000000054612CFE xor edx, edx
.text:0000000054612D00 lea rcx, aFinalizing_3 ; "Finalizing.3"
.text:0000000054612D07 call sub_54611000
.text:0000000054612D0C cmp cs:dword_5465F2FC, 1
.text:0000000054612D13 jnz loc_54612DC4
.text:0000000054612D19 mov dl, 1
.text:0000000054612D1B mov ecx, [rsp+18C8h+var_174C]
.text:0000000054612D22 call sub_54623C10
.text:0000000054612D27 mov rax, cs:qword_5465F328
.text:0000000054612D2E cmp qword ptr [rax+80h], 0
.text:0000000054612D36 jz short loc_54612D79
.text:0000000054612D38 mov rax, cs:qword_5465F328
.text:0000000054612D3F mov rax, [rax+80h]
.text:0000000054612D46 mov [rsp+18C8h+var_80], rax
.text:0000000054612D4E mov rax, cs:qword_5465F328
.text:0000000054612D55 mov qword ptr [rax+80h], 0
.text:0000000054612D60 cmp [rsp+18C8h+var_80], 0FFFFFFFFFFFFFFFFh
.text:0000000054612D69 jz short loc_54612D79
.text:0000000054612D6B mov rcx, [rsp+18C8h+var_80] ; hObject
.text:0000000054612D73 call cs:CloseHandle

Pod jego koniec widzimy ciekawie wyglądający string „Finalizing.3” oraz funkcję CloseHandle. Znaczy, ze są tutaj zawarte jakieś operacje finalizujące działanie. Możemy teraz klikać dwukrotnie myszką na etykiety „CODE XREF: ConsoleMain2+……” aby przenosić się do miejsc, z których pochodzą skoki do tych miejsc. Jednak najwygodniej będzie zrobić tak. Spójrzmy na ten fragment kodu:

.text:0000000054612CAB loc_54612CAB: ; CODE XREF: ConsoleMain2+12EEj
.text:0000000054612CAB ; ConsoleMain2+1346j ...
.text:0000000054612CAB cmp cs:hEvent, 0
.text:0000000054612CB3 jz short loc_54612CD9
.text:0000000054612CB5 cmp cs:dword_5465F294, 0
.text:0000000054612CBC jnz short loc_54612CD4
.text:0000000054612CBE mov ecx, cs:dword_5465F2A0
.text:0000000054612CC4 mov eax, cs:dword_5465F2A4
.text:0000000054612CCA lea eax, [rcx+rax+0Bh]
.text:0000000054612CCE mov cs:dword_5465F294, eax

Kliknijmy prawym przyciskiem myszki na  „CODE XREF: ConsoleMain2+12EE” obok ” loc_54612CAB” i z menu, które się ukazało wybierzmy polecenie „Jump to cross reference” lub naciśnijmy kombinację klawiszy Ctrl+X. W nowym oknie, które się ukaże wybierzmy pierwszą znalezioną pozycję

text:00000000546129DB mov dword ptr [rsp+18C8h+var_18A8], 0
.text:00000000546129E3 xor r9d, r9d
.text:00000000546129E6 xor r8d, r8d
.text:00000000546129E9 xor edx, edx
.text:00000000546129EB lea rcx, aFinalizing_2 ; "Finalizing.2"
.text:00000000546129F2 call sub_54611000
.text:00000000546129F7 cmp cs:dword_5465F2B4, 0
.text:00000000546129FE jnz loc_54612CAB
.text:0000000054612A04 cmp [rsp+18C8h+var_174C], 0
.text:0000000054612A0C jz short loc_54612A4F
.text:0000000054612A0E cmp [rsp+18C8h+var_174C], 79h
.text:0000000054612A16 jz short loc_54612A4F
.text:0000000054612A18 cmp [rsp+18C8h+var_174C], 7Eh
.text:0000000054612A20 jz short loc_54612A4F
.text:0000000054612A22 cmp [rsp+18C8h+var_174C], 8Dh
.text:0000000054612A2D jz short loc_54612A4F
.text:0000000054612A2F cmp [rsp+18C8h+var_174C], 8Eh
.text:0000000054612A3A jz short loc_54612A4F
.text:0000000054612A3C cmp cs:dword_5465F2FC, 1
.text:0000000054612A43 jz short loc_54612A5C
.text:0000000054612A45 cmp [rsp+18C8h+var_174C], 69h
.text:0000000054612A4D jnz short loc_54612A5C

Znowu interesujący string  „Finalizing.2” sugerujący, że w tym miejscu następuje zakończenie. Po nim następuje wiele innych skoków  prowadzących do miejsc w kodzie, gdzie wypisywany jest komunikat. Spróbujmy tak zmienić kod aby skok warunkowy jnz (jump if not zero) mógł skoczyć od razu do kodu, który bezpośrednio poprzedza wywołanie CloseHandle, co spowoduje, że komunikat oraz konieczność naciskania klawisza Enter po mniej niż 10 sekundach od uruchomienia ConEmu nie będą nam więcej utrudniać korzystania z programu.

Finałowe patchowanie.
Skopiujmy sobie adres skoku pomijając nazwę sekcji (text) oraz zera wiodące czyli: 546129FE. Następnie przed dokonaniem zmian dla pewności wykonaj kopię zapasową pliku który chcesz modyfikować czyli conemucd64.dll, proponuje skopiować go pod Total Commanderem do nazwy na przykład conemucd64.dl kombinacją Shift+F5. Teraz uruchommy HIEW i załadujmy plik conemucd64.dll. W widoku Decode naciskamy F5, wpisujemy kropkę (ponieważ mamy skoczyć do adresu wirtualnego, a nie offsetu) i wklejamy kombinacją klawiszy Shift+Insert wartość: 546129FE. Teraz można by było najprościej nacisnąć klawisz F2 i w widoku edycji kodu zamienić jnz na jmp. Jednak po takiej zmianie nieco za bardzo mieszamy w kodzie, zmieniając poniższe skoki. Jest to mało profesjonalne i mało eleganckie. Fakt, że do poniższym instrukcji żaden skok już nie nastąpi co widać pod dissaseblerem IDA, ale postarajmy się zrobić ładny patch. Widać przed zapisem zmian, że instrukcja skoku jmp w tym przypadku ma 5 bajtów, a nie sześć i zaczyna się od bajtu E9. Możemy więc zmianę rozwiązać w ten sposób, że naciskamy klawisz F3 w linii  546129FE i wpisujemy 90 czyli opcode instrukcji nop (no operation), a po niej E9 i zmiany zatwierdzamy klawiszem F9. Możemy również zamienić w linijce powyższej porównanie instrukcją cmp z liczbą 0 zamienić na 1. Jednak może zajść sytuacja gdzie rejestr ten będzie wynosił jednak 0 i skok się nie wykona. Dlatego najbezpieczniej będzie zmienić dwa pierwsze bajty pod adresem 546129FE na 90 i E9. Po dokonaniu zmiana i zapisaniu ich klawiszem F9 powinno to wyglądać tak jak poniżej.

Zamykamy HIEW i uruchamiamy conemu.exe, piszemy w konsoli polecenie „exit” i Voilà. Konsola zamyka się bez zbędnych komunikatów oraz naciskania klawiszy. Pozostała nam jeszcze zmiana  zachowania ConEmu w przypadku programów 32 bitowych.

W tym celu uruchamiamy dissasembler IDA w wersji 32 bitowej (plik idag.exe) i ładujemy analogicznie bibliotekę conemucd.dll. Możemy teraz analizować ją analogicznie jak jej wersję 64 bitową, ale aby przyśpieszyć sobie pracę naciśnijmy w widoku Disassembly kobinację klawiszy i wyszukajmy znany nam wcześniej string  „Finalizing.2”. IDA przenosi nas do takiego fragmentu kodu:

.text:546125BC mov ecx, offset aFinalizing_2 ; "Finalizing.2"
.text:546125C1 call sub_54611030
.text:546125C6 cmp dword_5464EE8C, 0
.text:546125CD jnz loc_54612842
.text:546125D3 cmp [ebp+var_118], 0
.text:546125DA jz short loc_54612618
.text:546125DC cmp [ebp+var_118], 79h
.text:546125E3 jz short loc_54612618
.text:546125E5 cmp [ebp+var_118], 7Eh
.text:546125EC jz short loc_54612618
.text:546125EE cmp [ebp+var_118], 8Dh
.text:546125F8 jz short loc_54612618
.text:546125FA cmp [ebp+var_118], 8Eh
.text:54612604 jz short loc_54612618
.text:54612606 cmp dword_5464EED0, 1
.text:5461260D jz short loc_54612625
.text:5461260F cmp [ebp+var_118], 69h
.text:54612616 jnz short loc_54612625.

Jak widzimy analogiczny skok dla wersji 32 bitowej biblioteki dll znajduje się pod adresem:  546125CD. Wiadomo teraz co należy zrobić 🙂 Wykonujemy kopię zapasową pliku conemucd.dll i uruchamiamy HIEW ładując conemucd.dll. Naciskamy F5, wpisujemy kropkę i wklejamy kombinacją Shift+Insert adres: 546125CD. Wciskamy w widoku Decode klawisz F3 i wpisujemy 90 E9, nacisjamy F9 i zamykamy HIEW klawiszem Escape lub F10. Zróbmy teraz test z aplikacją 32 bitową. Uruchommy conemu.exe, najlepiej z pod Total Commandera wpisując polecenie:

conemu.exe /cmd "C:\PROGRAMY\HIEW\hiew32.exe"

U Ciebie ścieżka do HIEW może być oczywiście inna. Natychmiast po otwarciu naciśnij klawisz Escape. ConEmu zamyka się bez zbędnego czekania. Czyli nasz cel osiągnięty. Możesz posiadając kopię zapasowe obu dllek, stworzyć posiłkując się na przykład patcherem dUP2 o którym pisałem w poprzednim moim wpisie stworzyć modyfikację w postaci patchera w pliku exe.

I to tyle w tym wpisie. Mam nadzieję, że czegoś się nauczyłeś. Na koniec dodam tylko, że tutaj również cel, który analizowaliśmy jest aplikacją darmową, a ponieważ i tak ma dostępne źródła, autor nie pakował jej plików ani nie zabezpieczył przed analizą żadnymi dodatkowymi narzędziami, także analizowanie i modyfikacja nie było żadnym, wielkim wyczynem, i proponowany sposób „zahacza” o podstawy reverse engineeringu 🙂

Comments (0)

› No comments yet.

Dodaj komentarz

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Pingbacks (0)

› No pingbacks yet.