Phần 1 của 3
Nếu bạn nghiêm túc với kỹ thuật đảo ngược - hãy quên các trình đào tạo và động cơ gian lận.
Kỹ sư đảo ngược giỏi trước tiên nên biết hệ điều hành, các chức năng API cốt lõi, cấu trúc chung của chương trình (vòng lặp chạy là gì, cấu trúc cửa sổ, quy trình xử lý sự kiện), định dạng tệp (PE). Tác phẩm kinh điển "Lập trình Windows" của Petzold có thể giúp ích (www.amazon.com/exec/obidos/ISBN=157231995X) cũng như MSDN trực tuyến.
Trước tiên, bạn nên nghĩ về nơi có thể gọi quy trình khởi tạo bãi mìn. Tôi đã nghĩ đến những điều sau:
- Khi bạn khởi chạy trò chơi
- Khi bạn nhấp vào khuôn mặt hạnh phúc
- Khi bạn nhấp vào Trò chơi-> Mới hoặc nhấn F2
- Khi bạn thay đổi mức độ khó
Tôi quyết định kiểm tra lệnh tăng tốc F2.
Để tìm mã xử lý bộ tăng tốc, bạn phải tìm quy trình xử lý thông báo cửa sổ (WndProc). Nó có thể được truy tìm bằng các cuộc gọi CreateWindowEx và RegisterClass.
Đọc:
Mở cửa sổ IDA, Imports, tìm "CreateWindow *", chuyển đến nó và sử dụng lệnh "Jump xref to operand (X)" để xem nó được gọi ở đâu. Chỉ nên có một cuộc gọi.
Bây giờ, hãy tìm ở trên cho hàm RegisterClass và nó là tham số WndClass.lpfnWndProc. Tôi đã đặt tên cho hàm mainWndProc trong trường hợp của mình.
.text:0100225D mov [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264 mov [ebp+WndClass.cbClsExtra], edi
.text:01002267 mov [ebp+WndClass.cbWndExtra], edi
.text:0100226A mov [ebp+WndClass.hInstance], ecx
.text:0100226D mov [ebp+WndClass.hIcon], eax
.text:01002292 call ds:RegisterClassW
Nhấn Enter trên tên hàm (sử dụng 'N' để đổi tên nó thành tên khác tốt hơn)
Bây giờ hãy xem
.text:01001BCF mov edx, [ebp+Msg]
Đây là id thông báo, trong trường hợp nhấn nút F2 phải chứa giá trị WM_COMMAND. Bạn phải tìm nó ở đâu so với 111h. Nó có thể được thực hiện bằng cách truy tìm edx trong IDA hoặc bằng cách thiết lập điểm ngắt có điều kiện trong WinDbg và nhấn F2 trong trò chơi.
Dù bằng cách nào cũng dẫn đến một cái gì đó như
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Nhấp chuột phải vào 111h và sử dụng "Hằng số ký hiệu" -> "Sử dụng hằng số ký hiệu tiêu chuẩn", gõ WM_ và Enter. Bây giờ bạn nên có
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
Đây là một cách dễ dàng để tìm ra các giá trị id tin nhắn.
Để hiểu cách xử lý máy gia tốc, hãy kiểm tra:
Có khá nhiều văn bản cho một câu trả lời duy nhất. Nếu bạn quan tâm, tôi có thể viết một vài bài viết khác. Bãi mìn ngắn câu chuyện dài được lưu trữ dưới dạng một mảng byte [24x36], 0x0F cho biết byte đó không được sử dụng (chơi trường nhỏ hơn), 0x10 - trường trống, 0x80 - của tôi.
Phần 2 của 3
Ok, hãy tiếp tục với nút F2.
Theo Sử dụng bộ tăng tốc bàn phím khi nhấn nút F2, chức năng wndProc
... nhận được thông báo WM_COMMAND hoặc WM_SYSCOMMAND. Từ bậc thấp của tham số wParam chứa mã định danh của bộ gia tốc.
Ok, chúng tôi đã tìm thấy nơi WM_COMMAND được xử lý, nhưng làm thế nào để xác định giá trị tham số wParam tương ứng? Đây là lúc Resource hacker vào cuộc. Nuôi nó bằng nhị phân và nó hiển thị cho bạn mọi thứ. Giống như bảng gia tốc cho tôi.
văn bản thay thế http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Bạn có thể thấy ở đây, nút F2 đó tương ứng với 510 trong wParam.
Bây giờ chúng ta hãy quay lại mã, xử lý WM_COMMAND. Nó so sánh wParam với các hằng số khác nhau.
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 210h
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 1FEh
.text:01001DD8 jz loc_1001EC8
Sử dụng menu ngữ cảnh hoặc phím tắt 'H' để hiển thị các giá trị thập phân và bạn có thể thấy bước nhảy của chúng tôi
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 528
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 510
.text:01001DD8 jz loc_1001EC8 ; here is our jump
Nó dẫn đến đoạn mã gọi một số proc và thoát khỏi wndProc.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
Đó có phải là chức năng bắt đầu trò chơi mới không? Tìm hiểu điều đó trong phần cuối cùng! Giữ nguyên.
Phần 3 của 3
Chúng ta hãy xem phần đầu tiên của hàm đó
.text:0100367A sub_100367A proc near ; CODE XREF: sub_100140C+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, dword_10056AC
.text:0100367F mov ecx, uValue
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, dword_1005334
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, dword_1005338
.text:0100369E jnz short loc_10036A4
Có hai giá trị (dword_10056AC, uValue) được đọc vào thanh ghi eax và ecx và được so sánh với hai giá trị khác (dword_1005164, dword_1005338).
Hãy xem các giá trị thực tế bằng WinDBG ('bp 01003696'; on break 'p eax; p ecx') - đối với tôi chúng giống như kích thước bãi mìn. Chơi với kích thước bãi mìn tùy chỉnh cho thấy rằng cặp thứ nhất là thứ nguyên mới và thứ hai - thứ nguyên hiện tại. Hãy đặt tên mới.
.text:0100367A startNewGame proc near ; CODE XREF: handleButtonPress+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, newMineFieldWidth
.text:0100367F mov ecx, newMineFieldHeight
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, currentMineFieldWidth
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, currentMineFieldHeight
.text:0100369E jnz short loc_10036A4
Một chút sau các giá trị mới sẽ ghi đè lên chương trình con hiện tại và chương trình con được gọi là
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
Và khi tôi nhìn thấy nó
.text:01002ED5 sub_1002ED5 proc near ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5 ; sub_100367A+38p
.text:01002ED5 mov eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA: ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA dec eax
.text:01002EDB mov byte ptr dword_1005340[eax], 0Fh
.text:01002EE2 jnz short loc_1002EDA
Tôi hoàn toàn chắc chắn rằng tôi đã tìm thấy mảng bãi mìn. Nguyên nhân do chu kỳ chiếm mảng độ dài 360h byte (dword_1005340) với 0xF.
Tại sao 360h = 864? Có một số gợi ý bên dưới rằng hàng có 32 byte và 864 có thể được chia cho 32, vì vậy mảng có thể chứa 27 * 32 ô (mặc dù giao diện người dùng cho phép trường tối đa 24 * 30, có một phần đệm byte xung quanh mảng cho đường viền).
Mã sau tạo đường viền trên và dưới của bãi mìn (byte 0x10). Tôi hy vọng bạn có thể thấy sự lặp lại vòng lặp trong mớ hỗn độn đó;) Tôi đã phải sử dụng giấy và bút
.text:01002EE4 mov ecx, currentMineFieldWidth
.text:01002EEA mov edx, currentMineFieldHeight
.text:01002EF0 lea eax, [ecx+2]
.text:01002EF3 test eax, eax
.text:01002EF5 push esi
.text:01002EF6 jz short loc_1002F11 ;
.text:01002EF6
.text:01002EF8 mov esi, edx
.text:01002EFA shl esi, 5
.text:01002EFD lea esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03
.text:01002F03 loc_1002F03: ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03 dec eax
.text:01002F04 mov byte ptr MineField?[eax], 10h ; top border
.text:01002F0B mov byte ptr [esi+eax], 10h ; bottom border
.text:01002F0F jnz short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11: ; CODE XREF: sub_1002ED5+21j
.text:01002F11 lea esi, [edx+2]
.text:01002F14 test esi, esi
.text:01002F16 jz short loc_1002F39
Và phần còn lại của chương trình con vẽ các đường viền trái và phải
.text:01002F18 mov eax, esi
.text:01002F1A shl eax, 5
.text:01002F1D lea edx, MineField?[eax]
.text:01002F23 lea eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A: ; CODE XREF: sub_1002ED5+62j
.text:01002F2A sub edx, 20h
.text:01002F2D sub eax, 20h
.text:01002F30 dec esi
.text:01002F31 mov byte ptr [edx], 10h
.text:01002F34 mov byte ptr [eax], 10h
.text:01002F37 jnz short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39: ; CODE XREF: sub_1002ED5+41j
.text:01002F39 pop esi
.text:01002F3A retn
Việc sử dụng thông minh các lệnh WinDBG có thể cung cấp cho bạn kết xuất bãi mìn thú vị (kích thước tùy chỉnh 9x9). Kiểm tra các đường biên giới!
0:000> db /c 20 01005340 L360
01005340 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005360 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005380 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053a0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053c0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053e0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005400 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005420 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005440 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005460 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005480 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054a0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054c0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054e0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
Rất tiếc, có vẻ như tôi sẽ cần một bài đăng khác để đóng chủ đề