Archive for April, 2016


Viết linh tinh ……too_sad

Cơ bản, nhiều người có cùng suy nghĩ chung là không sử dụng IDA trong việc unpack file và theo tôi quan điểm này không có gì sai, vì như đã biết việc unpack thường sử dụng các trình debugger như OllyDBG/Immunity kết hợp với các công cụ fix PE file (LordPE; ImpREC, Scylla…). Tuy nhiên, trong bài viết này chúng ta sẽ thử dùng IDA để unpack một unpackme đơn giản, không sử dụng các biện pháp bảo vệ cao cấp, mục đích chủ yếu là để biết được cách thức thực hiện như thế nào với IDA.

Công cụ sử dụng:

  • DIE v1.01 (Detect It Easy)
  • IDA 6.8
  • Peditor v1.7 (yoda&M.o.D)
  • Scylla v0.9.8

Tải Unpackme tại: https://www.hex-rays.com/products/ida/support/tutorials/unpack_pe/test00.exe

Trước tiên, dùng DIE để kiểm tra sơ bộ unpackme:

2016-04-16_16-15-00

Fig.1

File được pack bằng MEW(SE v1.0), đoán là bản Standard Edition. Gồm 2 sections, section đầu có tên là MEW và section thứ hai có tên rất loằng ngoằng:

2016-04-16_16-18-47

Fig.2

Thông tin về các hàm APIs được unpackme sử dụng:

2016-04-16_16-20-04

Fig.3

OK thông tin cơ bản đã có. Tiếp theo mở IDA và load unpackme:

2016-04-16_16-05-50

Fig.4

Giữ nguyên các tùy chọn mặc định tại phần Options, nhấn OK để tiếp tục, ta nhận được thông báo sau:

2016-04-16_16-11-15

Fig.5

Thông báo này cho biết, section có ký tự loằng ngoằng bên dưới section MEW đã bị cắt bỏ các offsets và IDA sẽ chỉ đọc 0x7A1 bytes. Bỏ qua cảnh báo này, nhấn OK để tiếp tục, một thông báo nữa xuất hiện cho biết import của file đã bị hủy, điều này có nghĩa là khả năng lớn là file đã bị pack hoặc đã bị chỉnh sửa khiến cho việc phân tích trở nên khó khăn:

2016-04-16_16-25-47

Fig.6

Nhấn OK, để tiếp tục, IDA sẽ dừng lại tại đây:

2016-04-16_16-32-25

Fig.7

Quan sát tại màn hình IDA, lúc này ta thấy trước các byte đều xuất hiện cụm “dd” hay “db”. Điều này có nghĩa là IDA không nhận diện được code nên nó diễn giải dữ liệu dưới dạng dword (dd), word(dw), byte(db). IDA cho phép chúng ta thay đổi kiểu dữ liệu bằng cách nhấn phím tắt D:

2016-04-16_16-50-10

Fig.8

Để cấu hình các kiểu dữ liệu chọn Options > Setup data types… hoặc nhấn Alt+D:

2016-04-16_16-52-43

Fig.9

Đây là các thiết lập mặc định của IDA để chuyển đổi giữa các kiểu byte, word và dword khi nhấn D, tuy nhiên ta cũng có thể cấu hình thêm các loại dữ liệu khác nếu cần thiết. Trong trường hợp này của unpackme, ta cần không thực hiện việc thay đổi kiểu dữ liệu nữa mà thực hiện chuyển đổi các dữ liệu này sang các lệnh assembly. Để thực hiện việc chuyển đổi này, IDA hỗ trợ phím tắt C hoặc vào Edit > Code:

2016-04-16_17-11-40

Fig.10

Kết quả có được như sau:

2016-04-16_17-13-25

Fig.11

Ta thấy rằng, dữ liệu đã được chuyển thành một lệnh nhảy tới địa chỉ thuộc section đầu tiên, bắt đầu từ 400000 và kết thúc tại 401000. Vì IDA đã không nhận diện được code chuẩn ngay từ đầu nên lệnh nhảy này cũng không cho ta nhiều thông tin, chọn địa chỉ 400158 và nhấn Enter để follow cũng không tới được địa chỉ đó. Nếu như chúng ta sử dụng trình debugger như OllyDBG thì hoàn toàn có thể tới được địa chỉ trên:

2016-04-16_17-28-16

Fig.12

Tuy nhiên, mục tiêu của bài viết là sử dụng IDA để thực hiện nên ta sẽ làm theo cách khác. Ta sẽ thay đổi cách load file với tùy chọn Manual load như đã thấy trong phần Options của IDA. Mở lại unpackme, lựa chọn như hình minh họa:

2016-04-16_17-35-49

Fig.13

Tùy chọn Manual load cho phép ta quyết định sections nào sẽ được load vào IDA thay vì để IDA tự động load toàn bộ, việc bỏ tùy chọn Create imports segment sẽ loại bỏ cảnh báo của IDA về việc IAT bị hủy. Sau khi cấu hình như trên, nhấn OK để tiếp tục:

2016-04-16_17-42-20

Fig.14

IDA yêu cầu nhập địa chỉ của ImageBase. Ta giữ nguyên không thay đổi, nhấn OK để tiếp tục, IDA sẽ yêu cầu xác nhận việc nạp các sections và file header:

2016-04-16_17-44-24

Fig.15

2016-04-16_17-44-24

Fig.16

2016-04-16_17-46-15

Fig.17

Nhấn Yes để xác nhận, sau khi IDA load xong, nhấn C để chuyển dữ liệu sang code:

2016-04-16_17-54-27

Fig.18

Như đã thấy trên hình, địa chỉ 400158 đã được IDA nhận dạng là một location cụ thể, nhấn đúp chuột vào địa chỉ này ta tới vùng code bắt đầu tại địa chỉ đó:

2016-04-16_17-57-47

Fig.19

Tại đây được IDA nhận là Header code, nhấn P để tạo function hoặc chọn Edit > Functions > Create function…

2016-04-16_20-06-06

Fig.20

Nhấn space bar để chuyển sang Graphic mode. Quan sát tại màn hình Graphic ta thấy có rất nhiều lệnh call và lệnh nhảy, các lệnh call đều liên quan đến thanh ghi ebx. Thanh ghi ebx được khởi tạo bởi hai lệnh mov esi, 40601Ch & mov ebx, esi:

2016-04-16_20-19-37

Fig.21

Quan sát giá trị tại 0x40601C xem có thông tin gì:

2016-04-16_20-23-40

Fig.22

Nhấn D để chuyển đổi kiểu dữ liệu về giá trị dword:

2016-04-16_20-25-34

Fig.23

Chuyển tới địa chỉ 0x400130, quan sát tại đây có thể thấy rằng vùng code thể hiện thông tin của các sections tương ứng với thông tin mà ta thấy được khi xem bằng DIE:

2016-04-16_20-36-44

Fig.24

Tên của section thứ nhất (“MEW”) thì rõ ràng rồi, nhưng tên của section thứ hai thì nhìn rối rắm và dường như nó đã được encrypt hoặc có thể chứa thông tin gì đó. Chọn tên section này và thử nhấn C để chuyển sang mã lệnh, ta thấy có lệnh được ẩn trong chuỗi tên:

2016-04-16_20-46-51

Fig.25

Ta thấy có hai lệnh nhảy tới hai địa chỉ là 400108+7 và 400108+4, các địa chỉ này đều nằm giữa chuỗi tên của section thứ nhất, để có thông tin cụ thể về các địa chỉ này ta cần phải undefine vùng địa chỉ chứa tên của section thứ nhất. Chọn địa chỉ 0x400108 và nhấn phím U:

2016-04-16_21-05-16

Fig.26

Sau khi undefine, ta thấy tên của section thứ nhất chính xác chỉ từ 0x400108 đến 0x40010B, còn các vùng từ 0x40010C tới 0x40010F là vùng dữ liệu được IDA đánh dấu là unk (unknown). Để chỉnh sửa lại cho chính xác, nhấn C để chuyển đổi vùng đó thành code:

2016-04-16_21-19-48

Fig.27

Sau khi chuyển đổi thành công thì đoạn code tại 0x400130 cũng thay đổi theo:

2016-04-16_21-23-31

Fig.28

Thông tin thu được khá hữu ích rồi, tuy nhiên để tiếp tục ta phải sử dụng tới việc debug. Lựa chọn trình debugger như hình:

2016-04-16_21-32-57

Fig.29

Quay lại lệnh nhảy tới sub_400158, nhấn F2 để đặt một breakpoint:

2016-04-16_21-34-46

Fig.30

Sau khi đặt bp xong, nhấn F9 để run unpackme, ta sẽ dừng lại tại bp:

2016-04-16_21-40-13

Fig.31

Nhấn F7 để trace tới sub_400158:

2016-04-16_21-41-43

Fig.32

2016-04-16_21-43-10

Fig.33

Tại màn hình debug của IDA, nhấn Shift+F7 để mở cửa sổ Segments. Quan sát tại cửa sổ này ta thấy thông tin về các sections của file. Thông thường, dưới thông tin về PE header sẽ là section .text (ở đây có thể là section MEW(đã bị packer đổi tên)):

2016-04-16_22-01-59

Fig.34

Theo thông tin cửa sổ Segments cung cấp thì section MEW bắt đầu từ 0x401000 và kết thúc tại 0x406000, vậy size của section này là 0x5000. Tiếp theo, mở cửa sổ Breakpoint lists (Ctrl+Alt+B) để thiết lập một bp tương tự như ta đặt memory bp trong OllyDBG. Tại cửa sổ Breakpoints, nhấn Ins để thiết lập thêm một bp như sau:

2016-04-17_1-24-04

Fig.35

Với thông tin như trên, ta sẽ thiết lập một bp tại section đầu tiên (thường là section chứa OEP), nơi mà code sẽ được ghi vào để xem code được decompress tại section đó như thế nào. Ở đây ta chọn section MEW tại 0x401000 và kích thước là 0x5000 để yêu cầu dừng lại khi đạt tới kích thước đã thiết lập. Sau khi đặt xong, nhấn F9 để thực thi:

2016-04-16_22-28-09

Fig.36

Sau khi dừng lại tại bp, ta thấy code đã được decompress xong. Bước tiếp theo ta sẽ tiến hành dump toàn bộ file. Dựa trên thông tin từ màn hình Segments cung cấp, ta sẽ dump file bắt đầu từ 0x400000 tới 0x407004. Để dump được ta sử dụng idc script sau:

static main()
{
auto fp, ea;
fp = fopen("test00_dump.bin", "wb");
for ( ea=0x400000; ea < 0x407004; ea++ )
  fputc(Byte(ea), fp);
}

Tại IDA, nhấn Shift+F2 để mở cửa sổ thực thi script, copy&paste đoạn script trên vào, sau đó nhấn Run để thực hiện:

2016-04-17_1-36-22

Fig.37

Kết quả, ta có file được dump ra là test00_dump.bin nằm cùng thư mục của unpackme:

2016-04-17_1-40-01

Fig.38

Sử dụng PEditor để mở file vừa được dump:

2016-04-17_1-42-02

Fig.39

Nhấn sections để xem thông tin về các section, chuột phải tại section MEW và chọn:

2016-04-17_1-44-59

Fig.40

Sau khi dump xong, đổi .bin thành .exe:

2016-04-17_1-48-53

Fig.41

Bước cuối cùng của quá trình unpack chính là fix IAT. Mở Scylla và chọn process test00.exe. Chỉnh lại OEP thành 0x401000, sau đó nhấn IAT Autosearch:

2016-04-17_1-53-28

Fig.42

OK Scylla đã tìm thấy thông tin của IAT, tiếp theo nhấn Get Imports để nhận các APIs:

2016-04-17_1-56-59

Fig.43

Tìm thấy 19 hàm APIs mà unpackme sử dụng, không có invalid. Nhấn Fix Dump để thực hiện fix cho file test00_dump.exe:

IDA_19funcs

Fig.44

OK, vậy là quá trình rebuild thành công, Scylla tạo ra file mới là test00_dump_SCY.exe. Chạy file đã fix kết quả như sau:

2016-04-17_2-02-57

Fig.45

Vậy là quá trình unpack đã thành công!!

2016-04-21_18-33-26