18/09/2018, 13:55

Tổng quan về Pack và Unpack (phần 1)

Packer là một kiểu chương trình nén hoặc che dấu file thực thi (executable file). Các chương trình này ra đời bắt nguồn từ mục đích giảm kích thước của file, làm cho việc tải file nhanh hơn. Rất nhiều các coder hay các hãng phần mềm sử dụng Packer nhằm mục đích khiến cracker/reverser khó khăn ...

 Packer là một kiểu chương trình nén hoặc che dấu file thực thi (executable file). Các chương trình này ra đời bắt nguồn từ mục đích giảm kích thước của file, làm cho việc tải file nhanh hơn.

Rất nhiều các coder hay các hãng phần mềm sử dụng Packer nhằm mục đích khiến cracker/reverser khó khăn và tốn thời gian hơn trong việc bẻ khỏa hoặc đảo ngược phần mềm của họ. Đối với những kẻ chuyên phát tán các phần mềm độc hại (malicious software) thì Packer còn có tác dụng giúp kéo dài thời gian tồn tại của phần mềm càng lâu bị phát hiện càng tốt.

Cụ thể khi sử dụng, Packer nén, mã hóa, lưu hoặc dấu code gốc của chương trình, tự động bổ sung một hoặc nhiều section, sau đó sẽ thêm đoạn code Unpacking Stub và chuyển hướng Entry Point (EP) tới vùng code này. Bình thường một file không đóng gói (Nonpacked) sẽ được tải bởi OS. Với file đã đóng gói thì Unpacking Stub sẽ được tải bởi OS, sau đó chương trình gốc sẽ tải Unpacking Stub. Lúc này code EP của file thực thi sẽ trỏ tới Unpacking Stub thay vì trỏ vào mã gốc. Để hiểu được các phần trên thì các bạn cần hiểu cấu trúc PE file và cách thực thi của nó. Bạn có thể xem bài viết Tìm hiểu cấu trúc PE file.

Cấu trúc đầy đủ của một PE file như sau:

anh1

Trong môi trường DOS, chương trình sẽ kiểm tra DOS header và nếu hợp lệ sẽ thực thi DOS Stub. Còn bình thường file của chúng ta hay chạy trên Windows thì 2 trường này có thể bỏ qua. Trường này là một cấu trúc có 19 thành phần.

Cuối trường DOS header sẽ có một thành phần là: e_lfanew sẽ chứa offset của PE header so với vị trí  đầu file. Chương trình sẽ thực thi đến PE header. Tiếp đến là đọc Section Table để xem trong chương trình có những section nào. Sau đó chương trình sẽ nhảy đến từng section và thực thi. Entry Point thường nằm ở các section đầu nếu file chưa bị đóng gói.

2. Nguyên lí hoạt động của Packer

Cấu trúc của file PE ban đầu sẽ có dạng như sau:

packer-1

File này sẽ bị nén và mã hóa rồi được thêm vào một hay nhiều section do packer tự tạo ra.

Capture

Khi chạy file thì chương trình sẽ được thực thi như sau:

packer-3

Tiếp theo chương trình sẽ thực thi PE header:

packer-4

packer-5

packer-6

Sau khi nhảy đến Entry Point của section UMPACKER thì toàn bộ giá trị của các thanh ghi sẽ được lưu lại nhờ lệnh PUSHAD. Sau đó Import Table sẽ được tính toán lại. Trong một file bị pack, Import Table sẽ bị thay đổi và các dữ liệu sẽ bị mã hóa.

Tiếp theo chương trình sẽ khôi phục lại giá trị các thanh ghi đã được lưu trong Stack bằng lệnh POPAD. Cuối cùng chương trình sẽ nhảy đến Origin EntryPoint và thực thi như file lúc chưa bị đóng gói.

3.Nguyên lí Unpack

Đầu tiên ta phải nhận biết được xem một file có bị đóng gói hay không bằng cách dùng các công cụ như PEiD :

packer-7

Ở đây mình dùng file UnPackMe_ASPack2.12 làm đối tượng để test thử. File trên đã bị đóng gói bằng ASPack. Thông thường, các bước cơ bản để thực hiện unpack như sau:

packer-8

  1. Tìm OEP (Origin Entry Point): Orginal entry point là nơi mà chương trình gốc thực sự bắt đầu thực thi. Ta sẽ dùng một số công cụ debug file như OllyDbg và IDA để tìm lại OEP.
  1. Kết xuất file (Dump): Sau khi nhảy đến OEP ta sẽ tiến hành dump file. Mục đích của việc này là fix lại các section và import table như file ban đầu trước khi bị đóng gói. Sử dụng Plugin OllyDumpEx để dump file.

packer-9

  1. Sửa lại IAT (Repair Import Address Table): Sử dụng công cụ ImportREC.

packer-10

  1. Kiểm tra file xem còn các cơ chế Anti hoặc ngăn chặn việc thực thi hay không rồi tiến hành chỉnh sửa. Đảm bảo file sau unpack thực thi bình thường (Phần này sẽ được giới thiệu trong các phần sau).

Trên đây là tổng quan về pack và unpack. Phần tiếp theo mình sẽ demo với các bạn một số ví dụ cơ bản.

0