Archive for September 11, 2008


Sử dụng IceSword để Remove Rootkits

Tác giả : Mahesh Satyanarayana (swatkat)

Ngày công bố : May 21, 2006

Chỉnh sửa : Larry Stevenson (Prince_Serendip).

Lược dịch : kienmanowar

Trước tiên download phiên bản English của IceSword tại : http://202.38.64.10/~jfpan/download/IceSword120_en.zip

Giới thiệu :

Trong bài viết này tác giả sử dụng một công cụ rất nổi tiếng đó là HxDef (hay còn gọi là Hacker Defender) để che dấu tất cả các files, folders, các registries entry và thậm chí cả các processes có liên quan tới chương trình Sandboxie. Sau khi thực hiện công việc này, tác giả đã sử dụng công cụ IceSword để phân tích. Phần tiếp theo của bài viết này sẽ là các bước hướng dẫn cụ thể quá trình loại bỏ rootkits ra khỏi hệ thống.
Chú ý : Ở đây chương trình SandBoxie không phải là Malware. Thực chất, nó là một công cụ khá hữu ích để phòng chống malware trong đó có cả rootkits.

Các bước thực hiện :

Bước 1 : Chạy IceSword. Bên tab Functions chọn “Processes” để kiểm tra các processes đang chạy trên máy, tìm kiếm xem có những processes nào bị nghi ngờ , đánh dấu màu đỏ bởi IceSword. Những processes bị đánh dấu màu đỏ được liệt kê ra này là những hidden processes .

Hình minh họa dưới đây cho ta thấy có 2 processes ẩn đó là hxdef100.exe và control.exe :

Photo Sharing and Video Hosting at Photobucket

Bước 2 : Tại tab Functions chọn tiếp “Win32 Services” và tìm kiếm danh sách những mục bị đánh dấu màu đỏ trong danh sách các services trên máy.

Xem hình minh họa bên dưới ta thấy có một Hidden Serivce là HxDef :

Photo Sharing and Video Hosting at Photobucket

Bước 3 : Tiếp theo, chọn “SSDT” và kiểm tra các entry bị đánh dấu màu đỏ. Nếu thấy có bất kì dấu hiệu nào, chú ý đến tên file và tên các folder. Các rootkits hoạt động ở Kernel level chỉnh sửa các SDT entries để hook các hàm APIs natively.

Hình minh họa dưới đây chỉ cho ta thấy kernel level API hooking bới SandBoxie driver:
Photo Sharing and Video Hosting at Photobucket

Bước 4 : Bây giờ chúng ta sẽ tiến hành loại bỏ rootkit ra khỏi hệ thống. Chọn “Processes” , sau đó chuột phải lên các processes bị đánh dấu màu đỏ và chọn “Terminate Process”. Khi bạn thực hiện công việc này IceSword sẽ tiêu diệt các rooted processes.

Xem hình minh họa dưới đây :

Photo Sharing and Video Hosting at Photobucket

Bước 5 : Nhấn chọn “Win32 Services”. Do các rooted processes đã hoàn toàn bị terminated, các rootkit service cũng sẽ hoàn toàn tự động bị stop. Do đó tại thời điểm này service sẽ không còn hidden nữa cho nên nó cũng không còn bị đánh dấu màu đỏ như hình bên trên. Do ta đã lưu lại tên của service tại bước 2, do đó việc tìm kiếm lại nó hoàn toàn dễ dàng. Bây giờ chọn nó , chuột phải và chọn “Disabled” để hoàn toàn disable service này.

Xem hình minh họa dưới đây :

Photo Sharing and Video Hosting at Photobucket

Bước 6 : Tiếp theo chúng ta phải xóa các root files. Nhấn chọn “File”, nó sẽ hiển thị giao diện giống như khi ta làm việc với Windows Explorer. Tìm đến folder nơi có chứa rootkit và xóa chúng.

Xem hình minh họa :

Photo Sharing and Video Hosting at Photobucket
Photo Sharing and Video Hosting at Photobucket

Bước 7 : *Not recommended for novice users*

Các file mà được che dấu bởi rootkit thông thường sẽ tạo và lưu vết trong Registry để tự nó được load lên mỗi khi Windows loads. Để kiểm tra có những startup entries cho bất kì các rooted files nào (thậm chí đã được deleted trong các bước trước), nhấn chọn “Startup”. Nếu như tìm thấy có các startup entries liên quan thì sử dụng công cụ có sẵn của IceSword để remove nó. Chọn “Registry” để vào registry editor tương tự như chúng ta gõ Regedit.exe. Tiếp theo tìm đến các key/value , chọn và xóa chúng.

Hình minh họa dưới đây sẽ cho ta thấy các bước thực hiện :

Photo Sharing and Video Hosting at Photobucket

Photo Sharing and Video Hosting at Photobucket

Bước 8 : Khởi động lại máy, vào File > Reboot and Monitor

Khởi động lại hệ thống sử dụng IceSword :
Photo Sharing and Video Hosting at Photobucket

Bước 9 : Sau khi khởi động lại, chạy lại IceSword một lần nữa và kiếm tra lại như các bước đã thực hiện ở trên.

Xem hình minh họa dưới đây :
Photo Sharing and Video Hosting at Photobucket

Photo Sharing and Video Hosting at Photobucket


Trên REA lão RCA có code một cái crackme nhỏ và ra đề như sau :

+ Crackme level 1.1 by Rongchaua.
– Level : Very very easy.
– Aim :
. Thực tập cách set breakpoint.
. Thực tập patch.
. Mã Ascii.

Rảnh rỗi ngồi phân tích thử xem thế nào!

Dùng PeID check thử, hú hồn may quá lão Rồng nhà ta không pack, thoát khỏi bước đầu tiên. Đọc Rulz và run thử Crackme thì thấy nút Checkit bị Disable mất tiêu. Soi lại list các hàm API thường dùng cho Window thì thấy có em EnableWindow (đây mới chỉ là nghi thôi)

The EnableWindow function enables or disables mouse and keyboard input to the specified window or control. When input is disabled, the window does not receive input such as mouse clicks and key presses. When input is enabled, the window receives all input.

BOOL EnableWindow(
HWND hWnd, // handle to window
BOOL bEnable // flag for enabling or disabling input
);

Parameters
hWnd
Identifies the window to be enabled or disabled.
bEnable
Specifies whether to enable or disable the window. If this parameter is TRUE, the window is enabled. If the parameter is FALSE, the window is disabled.

Okie đã có thông tin cho sol đầu tiên “Patch to enable the button”, load crackme vào trong Olly. Tại Olly , chuột phải và chọn Search all intermodular calls, ta sẽ thấy được một list các danh sách API mà lão Rồng dùng :

Found intermodular calls
Address Disassembly Destination
00401000 Cr PUSH 0 (Initial CPU selection)
004010FE CALL user32.CreateDialogParamA
00401035 CALL user32.DialogBoxParamA
0040107D CALL user32.EnableWindow
0040108C CALL user32.EnableWindow
004011D5 CALL user32.EnableWindow
004011EF CALL user32.EnableWindow
00401113 CALL user32.EndDialog
00401125 CALL user32.EndDialog
0040123C CALL user32.EndDialog
0040103B CALL kernel32.ExitProcess
0040106C CALL user32.GetDlgItem
004011C8 CALL user32.GetDlgItem
004011E2 CALL user32.GetDlgItem
004010BA CALL user32.GetDlgItemTextA
004010D1 CALL user32.GetDlgItemTextA
00401002 CALL kernel32.GetModuleHandleA
00401017 CALL user32.LoadIconA
0040118C CALL kernel32.lstrcatA
004011A3 CALL kernel32.lstrcmpA
0040115F CALL kernel32.lstrlenA
004011BB CALL user32.MessageBoxA
00401205 CALL user32.MessageBoxA
00401140 CALL ntdll.RtlZeroMemory
0040114F CALL ntdll.RtlZeroMemory
0040105F CALL user32.SendMessageA
0040122A CALL user32.SendMessageA
0040117A CALL user32.wsprintfA

_Ái chà có tới 4 hàm EnableWindow lận, vậy là không còn nghi ngờ gì nữa rồi.Chuột phải vào 1 hàm EnableWindow bất kì và chọn Set BP on every call to EnableWindow. Kết thúc quá trình Set BP, bây h nhấn F9 để Run cracke. Bụp, Olly đã break tại 1 hàm EnableWindow và đây chính là hàm cần Patch. Lý do tại sao tôi khẳng định được là vì khi form crackme của lão Rồng được load lên thì hàm EnableWindow sẽ được load theo để Disable cái nút nhấn Checkit :

00401087 |> \6A 00 PUSH 0 ; /Enable = FALSE <== Patch here
00401089 |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; |hWnd
0040108C |. E8 D3010000 CALL ; \EnableWindow <== Break here

_Dịch lên 1 chút ta thấy PUSH 0, và thấy Olly comment bên cạnh. Do đó ta sẽ patch lại thành PUSH 1 . (0 và 1 ở đây thực chất là các cờ dùng cho việc set disable hoặc enable)

_Patch xong save lại và Run .. Done nút Checkit đã được Enable lên. Vậy là đã giải quyết được bài tập thứ nhât!

_Tiếp theo là đến bài tập tìm Real Serial. Như trong danh sách các APIs mà lão Rồng dùng ở trên, chúng ta để ý thấy có hàm GetDlgItemTextA. Check lại info về hàm này :

The GetDlgItemText function retrieves the title or text associated with a control in a dialog box.
UINT GetDlgItemText(
HWND hDlg, // handle of dialog box
int nIDDlgItem, // identifier of control
LPTSTR lpString, // address of buffer for text
int nMaxCount // maximum size of string
);

_Okie vậy là ta set 1 BP tại GetDlgItemTextA. Sau đó nhấn F9 để run Crackme và nhập thông tin về UserName và Fake Serial vào. Cuối cùng nhấn CheckIt, ta sẽ break tại đây trong Olly :

004010A8 |. 68 00010000 PUSH 100 ; /Count = 100 (256.)
004010AD |. 68 68304000 PUSH CrackMe.00403068 ; |Buffer = CrackMe.00403068
004010B2 |. 68 EC030000 PUSH 3EC ; |ControlID = 3EC (1004.)
004010B7 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004010BA |. E8 B7010000 CALL ; \GetDlgItemTextA <== Break here

Tại cửa sổ Stack :

0012FB1C 000C019E |hWnd = 000C019E ('CrackMe Level 1.1 by Rongchaua',class='#32770')
0012FB20 000003EC |ControlID = 3EC (1004.)
0012FB24 00403068 |Buffer = CrackMe.00403068
0012FB28 00000100 \Count = 100 (256.)

_UserName nhập vào của chúng ta sẽ được lưu tại Buffer trên. F8 để trace qua hàm , tại cửa sổ Dump ta có :

00403068  6B 69 65 6E 6D 61 6E 6F 77 61 72 00 00 00 00 00  kienmanowar.....

_Tương tự với hàm tiếp theo ta cũng có được kết quả FakeSerial được lưu vào một Buffer khác :

00403368  31 31 31 31 31 39 38 32 00 00 00 00 00 00 00 00  11111982........

_Sau khi Trace xong ta tới đây :


004010D6 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; /Arg1
004010D9 |. E8 52000000 CALL CrackMe.00401130 ; \CrackMe.00401130 <== Trace Into

_ Trace Into vào hàm Call ở trên, ta sẽ tới quá trình tính toán sinh ra Real Serial.

00401130 /$ 55 PUSH EBP
00401131 |. 8BEC MOV EBP,ESP
00401133 |. 83C4 F8 ADD ESP,-8
00401136 |. 68 00010000 PUSH 100 ; /Length = 100 (256.)
0040113B |. 68 68314000 PUSH CrackMe.00403168 ; |Destination = CrackMe.00403168
00401140 |. E8 55010000 CALL ; \RtlZeroMemory
00401145 |. 68 00010000 PUSH 100 ; /Length = 100 (256.)
0040114A |. 68 68324000 PUSH CrackMe.00403268 ; |Destination = CrackMe.00403268
0040114F |. E8 46010000 CALL ; \RtlZeroMemory
00401154 |. BE 68324000 MOV ESI,CrackMe.00403268 ; ASCII "6b"
00401159 |. BF 68304000 MOV EDI,CrackMe.00403068 ; <== FU
0040115E |. 57 PUSH EDI ; /String => "kienmanowar"
0040115F |. E8 48010000 CALL ; \lstrlenA
00401164 |. 8BD8 MOV EBX,EAX ; <== Len = Length(User Name)
00401166 |. 33C0 XOR EAX,EAX ; <== i == 0
00401168 |> 50 /PUSH EAX ; <== i
00401169 |. 53 |PUSH EBX ; <== Len
0040116A |. 57 |PUSH EDI ; <== FU
0040116B |. 0FBE0C38 |MOVSX ECX,BYTE PTR DS:[EAX+EDI] ; <== Temp = FU [i]
0040116F |. 51 |PUSH ECX ; /<%x>
00401170 |. 68 59304000 |PUSH CrackMe.00403059 ; |Format = "%x"
00401175 |. 68 68314000 |PUSH CrackMe.00403168 ; |s = CrackMe.00403168
0040117A |. E8 D3000000 |CALL ; \wsprintfA
0040117F |. 83C4 0C |ADD ESP,0C
00401182 |. 68 68314000 |PUSH CrackMe.00403168 ; /StringToAdd = "69"
00401187 |. 68 68324000 |PUSH CrackMe.00403268 ; |ConcatString = "6b"
0040118C |. E8 0F010000 |CALL ; \lstrcatA
00401191 |. 5F |POP EDI
00401192 |. 5B |POP EBX
00401193 |. 58 |POP EAX
00401194 |. 40 |INC EAX ; <== i++
00401195 |. 3BC3 |CMP EAX,EBX ; <== While i < Len
00401197 |.^ 7C CF \JL SHORT CrackMe.00401168 ; <== Continue
00401199 |. 68 68334000 PUSH CrackMe.00403368 ; /String2 = "11111982"
0040119E |. 68 68324000 PUSH CrackMe.00403268 ; |String1 = "6b"
004011A3 |. E8 FE000000 CALL ; \lstrcmpA
004011A8 |. 0BC0 OR EAX,EAX
004011AA |. 75 4A JNZ SHORT CrackMe.004011F6
004011AC |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004011AE |. 68 00304000 PUSH CrackMe.00403000 ; |Title = "Reverse Engineering Association"
004011B3 |. 68 20304000 PUSH CrackMe.00403020 ; |Text = "Congratulation! You've done with it"
004011B8 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
004011BB |. E8 C2000000 CALL ; \MessageBoxA
004011C0 |. 68 EC030000 PUSH 3EC ; /ControlID = 3EC (1004.)
004011C5 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011C8 |. E8 A3000000 CALL ; \GetDlgItem
004011CD |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
004011D0 |. 6A 00 PUSH 0 ; /Enable = FALSE
004011D2 |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; |hWnd
004011D5 |. E8 8A000000 CALL ; \EnableWindow
004011DA |. 68 ED030000 PUSH 3ED ; /ControlID = 3ED (1005.)
004011DF |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011E2 |. E8 89000000 CALL ; \GetDlgItem
004011E7 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
004011EA |. 6A 00 PUSH 0 ; /Enable = FALSE
004011EC |. FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; |hWnd
004011EF |. E8 70000000 CALL ; \EnableWindow
004011F4 |. EB 14 JMP SHORT CrackMe.0040120A
004011F6 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004011F8 |. 68 00304000 PUSH CrackMe.00403000 ; |Title = "Reverse Engineering Association"
004011FD |. 68 44304000 PUSH CrackMe.00403044 ; |Text = "No,no! Try it again!"
00401202 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
00401205 |. E8 78000000 CALL ; \MessageBoxA
0040120A |> C9 LEAVE
0040120B \. C2 0400 RETN 4

_ Tóm tắt đoạn code này như sau :
Đây là một vòng lặp dùng để chuyển từng kí tự trong chuỗi user name mà chúng ta nhập vào sang dạng mã Hexa của kí tự đó ( ví dụ : k — 0x6b). Sau quá trình trace khỏi vòng lặp ta được kết quả như sau :

EAX 0000000B <== length(FU)
ECX 77E74BAE kernel32.77E74BAE
EDX 00000003
EBX 0000000B
ESP 0012FB18
EBP 0012FB20
ESI 00403268 ASCII "6b69656e6d616e6f776172" <== after converted
EDI 00403068 ASCII "kienmanowar" <== String to convert

_Chuỗi sau khi tính toán sẽ được đem đi so sành với Serial mà chúng ta nhập vào. Đúng thì Ok, còn sai thì đi bụi

00401199 |. 68 68334000 PUSH CrackMe.00403368 ; /String2 = "11111982"
0040119E |. 68 68324000 PUSH CrackMe.00403268 ; |String1 = "6b69656e6d616e6f776172"
004011A3 |. E8 FE000000 CALL ; \<== Compare two Strings

Kết quả cuối cùng :

User Name : kienmanowar
Serial    : 6b69656e6d616e6f776172

Phần tiếp theo là dùng IDA+HexRays :

Cái tên HexRays sau khi xuất hiện trên site của lão Ilfak Guilfanov (http://www.hexblog.com/) đã làm cho giới RE kinh thiên động địa mặc dù lúc đó nó mới chỉ là trong ý tưởng.Đến sau này khi lão release sản phầm và public trên một site khác (http://www.hex-rays.com/) càng làm cho “giang hồ” thèm muốn. Nhưng cái giá mà lão đưa ra để có được HexRays thì quá chua chát : “A single user license of the Hex-Rays Decompiler is 2299USD (1500EUR)”. Với số tiến như thế này thì có mà thách đố, chắc đi cày đến hết đời mới mua nổi em nó về dùng. Cũng có một số team có ý định và đã bỏ tiền ra mua HexRays về sử dụng…. nhưng rồi đến một ngày, một ngày mà cả giới RE phải online để download hàng. Đó chỉnh là hôm YAG Team public hexrays cho bà con download….. Hơ hơ nhưng mà tool xịn có trong tay rồi, giờ dùng sao ta ? Không lẽ down về để đó ngó chơi…… hơn 2 ngàn $ chứ có ít đâu . Hôm nay tập dùng HexRays bèn lấy em crackme của lão Rồng ra vọc thử .. Thấy đại ca Còm dùng HexRays hay quá nên ráng đua đòi ..nhưng cũng chỉ dừng ở mức cưỡi ngựa xem hoa chứ chưa dám chạy trước . Và đây là kết quả cuối cùng sau một hồi ngồi phân tích bằng IDA + HexRays :

int __stdcall DialogFunc(HWND a1, UINT a2, WPARAM a3, LPARAM a4)
{
HWND v5; // eax@2
HWND hWnd; // [sp+0h] [bp-4h]@2

switch ( a2 )
{
case 0x110u:
SendMessageA(a1, 0x80u, 1u, lParam);
v5 = GetDlgItem(a1, 1006);
hWnd = v5;
if ( v5 )
EnableWindow(hWnd, FALSE); // disable checkit button
else
EnableWindow(hWnd, TRUE);
break;
case 0x111u:
switch ( a3 )
{
case 0x3EEu:
GetDlgItemTextA(a1, 1004, szName, 256);
GetDlgItemTextA(a1, 1005, szSerial, 256);
convert_szName_to_hex(a1);
break;
case 0x3F0u:
CreateDialogParamA(hInstance, (LPCSTR)0x3F1, a1, sub_40120E, 0);
break;
case 0x3EFu:
EndDialog(a1, 0);
break;
}
break;
case 0x10u:
EndDialog(a1, 0);
break;
}
return 0;
}

void __stdcall convert_szName_to_hex(HWND hDlg)
{
int i; // eax@1
int iLen; // ebx@1
int iIndex; // ST14_4@2
HWND v4; // eax@4
HWND v5; // eax@4

RtlZeroMemory(szBuf, 256); // Set a block of memory with 0's.
RtlZeroMemory(szHex, 256);
iLen = lstrlenA(szName);
i = 0;
do
{
iIndex = i;
wsprintfA(szBuf, "%x", szName[i]); // convert szName[i] to Hexa and store in a szBuf
lstrcatA(szHex, szBuf); // append szBuf to szHex
i = iIndex + 1;
}
while ( iIndex + 1 < iLen );
if ( lstrcmpA(szHex, szSerial) ) // compare szHex with szSerial
{
MessageBoxA(hDlg, "No,no! Try it again!", "Reverse Engineering Association", 0);
}
else
{
MessageBoxA(hDlg, "Congratulation! You've done with it", "Reverse Engineering Association", 0);
v4 = GetDlgItem(hDlg, 1004);
EnableWindow(v4, 0);
v5 = GetDlgItem(hDlg, 1005);
EnableWindow(v5, 0);
}
}