Analyze acprotect’s use of hardware debug register lunar of arteam
Abstract
Trong thế gới “bự” này . Nó là thế giới của RCE Reverse Code Engineer, phần cứng cũng như phần mềm đều rất quan trọng. Bởi một kỹ sư nghiên cứu mã (reverse engineer) đều phải từng học qua Assembly, và học làm thế nào để debug một chương trình, họ nhanh chóng tiếp cận, đối diện với những “bức tường mạnh” chính là việc nó sử dụng phần cứng thay vì dùng phần mềm thuần túy để ngăn chặn những kỹ sư ấy. Lúc này sự hiểu biết về x86 lại trở nên rất hữu dụng, bạn có thể dùng sự hiểu biết đó để chống lại chương trình đó – và tuy nhiên chương trình đó cũng biết dùng chính những thứ bạn dùng để chống lại bạn (hi hi, câu này hay ta).
Trong bài viết này, chúng ta sẽ tìm hiểu xem ACProtect (cũng như UltraProtect) sử dụng những thanh ghi debug thuộc về phần cứng (dòng chip x86 ), dùng làm gì nhỉ? Hề hề, trình bảo vệ sử dụng chúng để giải mã chương trình được bảo vệ, đồng thời ngăn chặn việc chúng ta dùng những thanh ghi đó.
10 trang |
Chia sẻ: tlsuongmuoi | Lượt xem: 2216 | Lượt tải: 0
Bạn đang xem nội dung tài liệu Analyze acprotect’s use of hardware debug register lunar of arteam, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Analyze ACProtect’s use of HardWare Debug Register
Lunar of ARTeam
1. Abstract
Trong thế gới “bự” này …. Nó là thế giới của RCE Reverse Code Engineer, phần
cứng cũng như phần mềm đều rất quan trọng. Bởi một kỹ sư nghiên cứu mã (reverse
engineer) đều phải từng học qua Assembly, và học làm thế nào để debug một chương
trình, họ nhanh chóng tiếp cận, đối diện với những “bức tường mạnh” chính là việc nó sử
dụng phần cứng thay vì dùng phần mềm thuần túy để ngăn chặn những kỹ sư ấy. Lúc này
sự hiểu biết về x86 lại trở nên rất hữu dụng, bạn có thể dùng sự hiểu biết đó để chống lại
chương trình đó – và tuy nhiên chương trình đó cũng biết dùng chính những thứ bạn dùng
để chống lại bạn (hi hi, câu này hay ta).
Trong bài viết này, chúng ta sẽ tìm hiểu xem ACProtect (cũng như UltraProtect)
sử dụng những thanh ghi debug thuộc về phần cứng (dòng chip x86 ), dùng làm gì nhỉ?
Hề hề, trình bảo vệ sử dụng chúng để giải mã chương trình được bảo vệ, đồng thời ngăn
chặn việc chúng ta dùng những thanh ghi đó.
2. The Meat of the Matter ? (Miếng mồi ngon hay vấn nạn cần giải
quyết?)
Đầu tiên, ta sơ lược thanh ghi debug cái đã. Trong bộ xử lý Intel và cả AMD cũng vậy,
đều có khái niệm về những thanh ghi debug. Có 2 cách để ta đặt một điểm ngắt bên trong
chương trình:
- Cách đầu tiên là dùng Interrupt. Ví dụ như dùng chỉ lệnh “int 3”.
- Cách thứ 2 là đặt một điểm ngắt bằng cách sử dụng những thanh ghi debug.
Lý do chính để dùng cách này là để chống lại CRC check. Vì chỉ lệnh “int 3”
sẽ ghi đè lên mã của chương trình, còn khi dùng những thanh ghi debug sẽ
không ghi đè mã chương trình.
Các bạn có thể tìm thông tin chi tiết về các thanh ghi debug trong course Intel Manuals
Volumn 3 chapter 15. Nó sẽ nói đến các thanh ghi debug từ DR0 -> DR7. DR0 -> Dr3
được dùng để thiết lập một địa chỉ cần ngắt. Sau đó, DR7 sẽ cài đặt thêm thông tin về địa
chỉ này ( read/write hay access). Bạn nên tìm hiểu volumn nói trên để có thêm chi tiết về
vấn đề DEBUG REGISTERs.
Trong Olly, Debug Regiser brekpoints, chúng được biết đến như là “hardware
breakpoints” Những điểm ngắt phần cứng. Và bạn chỉ có thể có 4 điểm ngắt như vậy (rất
dễ giải thích vì sao).
Đối với những trình bảo vệ, để phát hiện ra các “int3”, chúng chỉ cần CRC check hoặc
kiểm tra xem có mã nhị “int3” (mã hex 0xCC) hay không. Còn đối với những ngắt phần
cứng thì các trình bảo vệ sẽ làm như thế nào đây?
Đối với ACProtect, nó sẽ dùng những thanh ghi debug để giải mã tiến trình, vì vậy trình
debugger không cách nào đặt được ngắt phần cứng. (Các bạn thử nghĩ xem vì sao nhé.)
Giờ đây, ta sẽ tìm hiểu chi tiết hơn héng.
Cài đặt trình bảo vệ ACProtect, chọn option “Use Debug Register as decode register”,
như trong hình:
Giờ đây, ta đã có một ứng dụng được bảo vệ bởi ACProtect (sử dụng debug register cho
riêng nó). Ta sẽ phân tích xem cái gì sẽ xảy ra khi Olly thiết lập ngắt phần cứng trên OEP
của chương trình (trong trường này, OEP là 0x00401750).
Load ứng dụng vào Olly, đặt ngắt phần cứng trên OEP 0x00401750, F9 .
Trên lý thuyết, Olly sẽ ngắt tại OEP:
Nhưng, ta sẽ thấy thế này hỉ:
Lưu ý thanh trạng thái của Olly:
Đó không phải là điểm ngắt mà ta đã thiết lập. Đây chính là “Hiệu Ứng” của “Use Debug
Register as decode register”. HỀ, Lúc này Hardware Breakpoints trở thành “Tài nguyên
được bảo vệ”. Nếu bạn đọc trong tài liệu của Intel, các thanh ghi DR0 -> DR3 và DR7 là
các thanh ghi đặc quyền được bảo vệ. Nếu ứng dụng có đặc quyền thấp nhất truy xuất
đến các thanh ghi thì sẽ phát sinh lỗi bảo vệ? Vậy làm thế nào mà ACProtect có thể truy
xuất thay đổi chúng? Nó có liên quan đến vấn đề Windows điều khiển các ngoại lệ
(Exceptions) như thế nào. Khi một ngoại lệ xảy ra bên trong chương trình, thì hệ thống
Windows sẽ gọi trình điều khiển ngoại lệ (exception handler) mà chương trình đã cài đặt,
và sẽ gửi dữ liệu của trình điều khiển ngoại lệ liên quan đến ngoại lệ bằng một con trỏ trỏ
đến cấu trúc ngoại lệ (exception record structure), cấu trúc này chứa đựng những giá trị
thanh ghi debug. Lúc này, chương trình có thể chỉnh sử giá trị trong thanh ghi debug; sau
đó, sẽ trã quyền điều khiển cho hệ thống window (tất nhiên là sau khi trình điều khiển
ngoại lệ hoạt động xong).
Quay trở lại một chút, ACProtect sẽ phát sinh một ngoại lệ ở vị trí đầu tiên:
(BẠn còn giữ Olly chứ. Nếu còn thì tiếp tục).
Cuộn cửa sổ window lên một chút, bạn sẽ thấy chỉ lệnh “int3”:
Không nghi ngờ gì thêm, đây chính là nơi sẽ bắt đầu xảy ra ngoại lệ, để chắc chắn, bạn
hãy restart lại Olly, đặt hardware breakpoints trên vị trí trên: 0x00407198.
Đúng thực là chương trình bị ngắt tại vị trí INT3 trên:
Lưu ý, hình trên cho ta biết trình điều khiển ngoại lệ đang ở vị trí nào, khi mà INT3 được
“bóp cò” (triggered). (Ừm, SE = Structured Exception)
Chúng ta sẽ đi đến đó hỉ:
Đây chính là đoạn mã của trình điều khiển ngoại lệ. Chúng ta cần tìm ra đoạn mã mà làm
mất giá trị trong thanh ghi debug chúng ta đã thiết lập. Chương trình chỉ có 1 ngoại lệ là
INT3. Vì thế chúng ta sẽ tìm 2 thứ:
- Loại mã ngoại lệ là cái nào.
- Nơi nào trong đoạn mã này sẽ tác động vào các thanh ghi debug.
** Vấn đề đầu tiên, Ngoại lệ nào? Nhìn vào hình trên sẽ nhận ra ngay heng. Ta nói INT3
chính là loại ngoại lệ “80000003” . Nhìn vào đoạn mã ở trên, Chỗ được khoanh vòng
màu đỏ í. Nó sẽ kiểm tra Ngoại lệ INT3 ? Nếu đúng thì không nhảy, nếu không đúng thì
jmp. Vậy, đoạn mã ngay sau nó sẽ là đoạn mã tác động đến những thanh ghi debug
Vậy, nhận xét này sẽ giúp chúng ta đến được đoạn mã cần thiết.
Những thông tin sau sẽ được đưa đến trình đềiu khiển ngọai lệ khi nó được gọi.
Cấu trúc Ngữ cảnh (CONTEXT structure) là cái ta nên chú ý.
Nhìn xuống phía dưới một chút trong cửa sổ của Olly (từ vị trí điểm bắt đầu của trình
điều khiển ngoại lệ), ta nhìn ở đây 0x004070B1, ECX sẽ lấy giá trị trong [ESP+0C], đây
là một con trỏ tới CONTEXT record (hình trên).
Tiếp theo, Chúng ta cần biết – Vị trí của những thanh ghi debug nằm trong trường
CONTEXT RECORD? Chúng ta sẽ nhìn đoạn mã mà “hit” chúng.
Giờ, ta đã có thông tin trên, và biết được ECX sẽ chứa con trỏ tới CONTEXT record,
cuộn màn hình xuống một chút trong cửa sổ diassembling trong Olly, ta thấy được vị trí
mà các thanh ghi debug đuợc truy xuất:
Ừm, lúc này DR0 bị ghi đè, rồi tới DR1, DR2, DR3; các thanh ghi này sẽ bị ghi đè vài
giá trị. Sau đó, nó sẽ ghi đè giá trị trong DR7 – cho phép hardware breakpoints “on
execution” với những địa chỉ bên trong DR0 -> DR3.
Bi giờ, chúng ta nhìn vào những địa chỉ trong DR0 -> DR3, chúng là những địa chỉ liền
kề, liên kết gần nhau. Mã ở vị trí này sẽ được thực thi nhờ vào Hardware Beakpoints.:
Khi mà những điểm ngắt này có tác dụng (come in), nó sẽ phát sinh một ngoại lệ, chương
trình buộc phải có một trình điều khiển ngoại lệ, nếu không nó sẽ crash. Bạn hãy cuộn
màn hình xuống tì vị trí 0x00407140 :
Đây là việc kiểm tra cờ “Single step flag”, là ngoại lệ bạn sẽ có khi một Hardware
Breakpoints được theo dõi, được đếm. Đây là một điều quan trọng: Hardware
Breakpoints có một tín hiệu đến Trình debugger hoặc một trình điều khiển ngoại lệ với
một “single step flag” . Cũng cùng một trình điều khiển ngoại lệ trên để điều khiển những
ngoại lệ phần cứng này. Vì thế những mã sau đây sẽ điều khiển những ngắt phần cứng
mà trình bảo vệ cài đặt:
Chúng ta nhìn vào đây hi:
Đoạn mã điều khiển các ngắt phần cứng, và các ngoại lệ phần cứng do các hardware
breakpoints có tác dụng gây nên..
Đầu tiên, nếu eax chứa giá trị từ con trỏ [EDX], thì sẽ có sự so sánh với một hằng số: 1,
sau đo là 2, và 3 . Đây là việc đếm. Đoạn mã sẽ đếm xem có bao nhiêu hardware
breakpoints vừa mới có tác dụng (come in). Mỗi lần một hardware breakpoint hoạt động
sẽ phát sinh ngoại lệ và trình điều khiển sẽ làm việc để xử lý nó:
Lần đầu, đoạn mã này sẽ thực thi:
Chúng ta biết rằng ECX chứa cấu trúc CONTEXT record, ta có được thanh ghi Edi sau
đây:
Cái hardware breakpoint thứ 2 có tác dụng, thì đoạn mã này họat động:
Và cái thứ3 có tác dụng thì mã này họat động:
Lần cuối cùng, thì sẽ thông qua cái mã nì.
Sau khi hardware breakpoint cuối cùng có tác dụng tại 0x004071A0,thì chương trình sẽ
tiếp tục ngay sau vị trí 0x004071A0:
Lưu ý rằng, trình điều khiển ngoại lệ đã ghi những giá trị cần thiết vào bên trong
ECX,EDX,EDI,DR0->DR3. Những thanh ghi này sẽ được dùng để giải mã ứng dụng.
VÀ INT3 sẽ vẫn có thể tiếp tục xảy ra cho đến khi ứng dụng được decrypt xong.
Vậy câu hỏi đặt ra là liệu những chang trai coder có cơ hội nào cho trình bảo vệ như vậy
không?
Câu trả lời là có một cách. Đó là hãy làm cái gì đó để restore giá trị bị ghi đè bởi trình
bảo vệ.
Trước tiên, ta xem xét cơ chế chuyển đổi điều khiển giũa hệ thống Windows với trình
điều khiển ngoại lệ:
Khi Windows gọi một exception handler, thì nó sẽ dùng một vài mã trong Kernel32.dll
và trong NTDLL.dll, các mã này sẽ xem xét exception, và sẽ gọi exception handler tương
ứng. Rồi exception handler trả quyền điều khiển cho Windows, rồi windows lại xem xét
mã trả về của exception handler, nếu là EXCEPTION_CONTINUE thì nó lại tiếp tục gọi
hàm ZwContinue:
Bạn nhìn vào vị trí 77F91BBC, EBX sẽ chứa giá trị trong [ESP] = con trỏ tới trường
CONTEXT record, đây là trường sẽ bị tác động bởi exception handler. Đoạn mã này
không bị trình bảo vệ can thiệp.
TỪ đây, có một ý cơ bản là chúng ta hãy hook ZwContinue, chỉnh sửa CONTEXT record
tại đây, và đặt trở lại giá trị của chúng ta muốn đặt vào các thanh ghi phần cứng. Tuy
nhiên, chúng ta nên nhớ 3 điểm này đối với trình bảo vệ:
- Phát sinh một ngoại lệ bằng INT3.
- Trong Exception Handler, nó cài đặt DR0 -> DR3.
- Khi mỗi hardware breakpoints xảy ra, thì cài đặt một phần của trình giải mã.
Do đó, nếu đơn giản chỉ là đặt vào DR0 giá trị của chúng ta sau mỗi lần ZwContinue
được gọi, thì bước đầu tiên của trình coder sẽ không bao giờ xảy ra. Vì thế chúng ta phải
đếm ngoại lệ. Nếu bạn đang dùng một trình debugger, đầu tiên hãy hook ZwContinue
nhưng sau đó bạn cũng cần làm như sau:
- Lưu giữ dấu vế của exception INT3.
- Sau khi INT3 xảy ra, bắt đầu đếm ngoại lệ single step xảy ra.
- Sau khi ngoại lệ single step thứ 2 xảy ra, thiết lập cờ ‘restore DR0 true..”
- Đoạn mã hook trong ZwContinue sẽ tìm kiếm cờ “Restore DR0 true” và nếu
TRUE thì [EBX] + 0x4 = giá trị bạn muốn cài đặt thành Hardware
Breakpoints.
- Trình debugger phải thực hiện việc này mỗi lần nó phát hiện INT3 – nó sẽ
phải bắt đầu đếm single step exceptions.
Hey, cách nay sẽ làm cho 4 thanh ghi phần cứng hoàn thành nhiệm vụ do trình bảo vệ đặt
ra, vừa theo ý muốn của ta.
Tôi không đưa ra bất kỳ một mã minh họa cho cách làm trên vì nó rất mất thời gian,
nhưng về mặt ý tưởng thì hoàn toàn chính xác.
Tạm biệt
Chúc các bạn may mắn.
Các file đính kèm theo tài liệu này:
- ACProtectDebugRegs_trans.pdf