Cracker Handbook 1.0 part 216 docx

6 151 1
Cracker Handbook 1.0 part 216 docx

Đang tải... (xem toàn văn)

Thông tin tài liệu

có thể phán đoán hết được ý nghĩa của chúng, và làm sao chúng ta chọn được một phương án đúng nhất trong đó? Máy tính sẽ dùng cách thức nào để có thể hiểu được? Làm thế nào chúng ta biết được điều gì đang thực sự xảy ra ? Trong bài viết này, tôi sẽ không đi vào tìm hiểu ngữ nghĩa của data, bởi vì các cấu trúc dữ liệu là quá nhiều (như các bạn đã thấy trong ví dụ ở trên). Mỗi một định dạng file sẽ có một cấu trúc dữ liệu. Chương trình sử dụng các phần mở dụng của file (.exe, .dll v v ) như là một ám hiệu để biết cách cư xử với từng cấu trúc. Thay vào đó, tôi và các bạn sẽ tập trung vào các đoạn code thực thi, đặc biệt là các đoạn code cho x86 processor. Chúng ta sẽ bắt đầu từ binary và kết thúc với ngôn ngữ C. II. Binary to Hexadecimal Như tôi đã nói ở trên, mức biểu diễn thấp nhất của thông tin (trong một môi trường máy tính) là binary. Các đoạn mã mà máy tính có thể hiểu được được biểu diễn bằng những bit 0 và 1 dài vô tận.Điều này dẫn đến con người khó có thể hiểu được những chuỗi 0 và 1 mà họ nhìn thấy thể hiện cái gì, và điều gì sẽ xảy ra. Nếu như bạn có hứng thú trong việc tìm hiểu nguyên lý hoạt động của các mạch trong CPU, tôi gợi ý bạn nên tìm đọc các quyển sách điện tử.Còn đối với tôi, tôi không biết nhiều về chúng để có thể giải thích cho bạn một cách chi tiết về nguyên lý hoạt động (Mặc dù có một thời gian tôi đã từng làm việc với những bộ vi xử lý đơn giản). Nhằm mục đích giảng giải, binary là một định dạng khó hiểu, vì nếu số lượng các số binary là quá lớn sẽ khiến cho chúng ta khó khăn trong việc quan sát. Đó chính là lý do tại sao các bạn thấy rằng thông thường chúng ta không bao giờ chỉnh sửa bất cứ gì theo định dạng binary, mà thay vào đó chúng được chuyển sang một định dạng dễ hiểu hơn mà tôi và các bạn đều biết, đó chính là Hexadecimal.Nếu như các bạn thấy trong hệ binary chỉ có 2 số 0 và 1, hệ decimal thì có 10 số (0,1,2,3,4,5,6,7,8,9) còn hệ Hexa sẽ có 16 (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F). Bạn có thể sẽ rất ngạc nhiên là tại sao định dạng Hexa lại được chọn để biểu diễn mà không phải là hệ Decimal đã quá thân thuộc ngay từ khi lọt lòng. Câu trả lời hết sức đơn giản.Đó là bởi vì tất cả các số khi được chuyển đổi vẫn nằm dưới định dang binary.Sử dụng 4bits thì tại một thời điểm bạn có thể tạo ra chính xác 16 giá trị khác nhau từ 4 bits này, bắt đầu từ 0 cho tới 15, theo hệ Hexa thì là từ 0 cho tới F. Điều này khiến cho hệ thống xử lý một cách dễ dàng hơn đơn giản chỉ bằng thay thế 4 bits bằng một số trong hệ Hexa. Dưới đây là bảng minh họa quá trình chuyển đổi giữa các hệ, giúp các bạn phần nào hiểu thêm về những gì mà tôi đã nói : Binary Decimal Hexadecimal 0000 0 0 0001 1 1 0010 2 2 0011 3 3 0100 4 4 0101 5 5 0110 6 6 0111 7 7 1000 8 8 1001 9 9 1010 10 A 1011 11 B 1100 12 C 1101 13 D 1110 14 E 1111 15 F 10000 16 10 Như các bạn đã thấy trên bảng trên, tại giá trị Binary là 1000 thì giá trị ở hệ Hexa là (10), đó là vì con số 1 đầu tiên có thể được biểu diễn thành 0001, trong khi số 0 thứ 2 được biêu diễn bằng (0000). Do đó chúng ta có kết quả là 00010000, giá trị này rất phù hợp với hệ số Binary. III. Hexadecimal to Assembly Code Việc sử dụng kí pháp hexadecimal giúp chúng ta viết các đoạn Binary code một cách nhanh hơn, và cho phép chúng ta nhiều cái nhìn tổng quát hơn. Tuy nhiên nó vẫn không có ý nghĩa nhiều lắm cho con người bởi vì thực chất nó vẫn chỉ là những con số. Chúng ta hãy quan sát một ví dụ về đoạn code Hexa dưới đây : 83EC20535657FF158C40400033DBA39881400053 Như tôi đã nói, đây chỉ là một phương pháp biểu diễn nhanh, ngắn gọn cho các số binary.Điều đó có nghĩa là nó không cho chúng ta thấy bất kì một ý nghĩa gì cả, cũng như nhìn vào đó chúng ta chẳng hiểu nó định làm gì, nhưng cái lợi của nó là ngắn gọn hơn so với việc biểu diễn dưới dạng binary rất dài với toàn số 0 và 1. Đoạn Hexa ở trên bao gồm 40 kí tự, trong khi đó nếu chúng ta biểu diễn ở dạng binary chúng ta sẽ có được 160 (40 * 4 bits) Đoạn mã ở trên không phải là một instruction lớn (thuật ngữ “instruction” ở đây để cập tới đoạn bytes code thực sự). Trên một vài bộ vi xử lý thì mỗi một instruction sẽ có một kích thước nhất định(ví dụ : 2 bytes) vì vậy chúng ta có thể chia code thành các phần một cách dễ dàng theo kích thước để có được các câu lệnh khác nhau (Giả sử rằng bạn sẽ có được một điểm bắt đầu hợp lệ trong đoạn code). Bộ xử lý x86 ít phức tạp hơn nhiều và có các kích thước instruction khác nhau. Bây giờ bạn có thể ngạc nhiên làm thế nào chúng ta có thể luôn luôn tách được các instructions theo cách này.Ý tưởng là như sau, chúng ta lấy byte đầu tiên, nhìn vào giá trị của nó, và byte này sẽ cho bạn biết cách tiến hành như thế nào. Một vài điều có thể xảy ra như sau : _Nó có thể là một single byte instruction: ví dụ 90h là câu lệnh NOP (No Operation) và kích thước của nó chỉ là 1 byte. _Có thể câu lệnh đó chưa được hoàn chỉnh: ví dụ Các lệnh (Instructions) mà được bắt đầu bằng 0Fh , chúng ta phải cần thêm các bytes vào sau để nó tạo thành một câu lệnh có nghĩa. _Câu lệnh được định nghĩa bởi một byte độc lập, nhưng vẫn cần có tham số, ví dụ : 8Bh chuyển một thanh ghi vào trong một thanh ghi khác.Những byte mà theo sau 8Bh sẽ miêu tả nó được chuyển đến từ đâu và nó được chuyển đên đâu. _Câu lệnh chưa hoàn chỉnh và cần thêm các tham số. Bởi vì chúng ta sẽ cần phải biết đó là câu lệnh nào để mà tách ra, chúng ta sẽ kết hợp quá trình tách các câu lệnh khác nhau với việc chuyển chúng sang một định dạng mà con người có thể đọc hiểu được một cách tương đương. Ngôn ngữ mà con người có thể đọc hiểu được đó chính là “Assembly Language”, thường được viết tắt là ASM. Quá trình chúng ta chuyển dịch một chương trình từ Code thô (Raw code) sang ASM, được gọi là quá trình “Disassembling”. Việc làm này sẽ cho chúng ta khả năng để đọc hiểu ASM.Để có thể thực hiện được chúng ta cần phải có một số kinh nghiệm. Vì rằng rõ ràng không có hệ thống nào để hiều một đoạn hexadecimal code thực hiện công việc gì , đó là một công việc cực kì chán ngắt. Tuy nhiên, việc hiểu được nó làm việc thế nào là rất quan trọng.Tôi sẽ chứng minh điều này thông qua ví dụ mà các bạn đã thấy ở trên. Hãy quan sát lại đoạn Hexadecimal code : 83EC20535657FF158C40400033DBA39881400053 Chúng ta sẽ giả sử rằng byte đầu tiên chính là điểm bắt đầu hợp lệ và chúng ta sẽ bắt đầu phân tích từ đó.Đầu tiên tôi sẽ lấy byte này ra, nó là 83h , sau đó chúng ta thực hiện công việc tra cứu dựa trên một bảng và bảng này tôi để trong phần Phụ lục A1. Khi xem trong bảng này chúng ta thấy nó cần phải có thêm byte khác để mô tả nhiệm vụ của nó một cách đầy đủ nhất, và byte cần sẽ được hình thành từ một “mod R/M” byte. Để có được những gì đầy đủ về nhiệm vụ của câu lệnh chúng ta sử dụng thông tin từ byte này và tra cứu thêm bảng phụ lục thứ 2 (Phụ lục A2) để tìm kiếm thông tin thông qua “group #1”.Trong trường hợp này, byte đó chính là ECh. Một mod R/M byte bao gồm trường 3 bits sau: Bit : 7 6 5 4 3 2 1 0 Meaning : mod reg R/M Để phân tách các trường này, chúng ta quay trở lại với binary bằng cách biểu diễn lại ECh : EC = 1110 1100 = 11 101 100 Sử dụng bảng phụ lục A2, chúng ta sẽ thấy rằng những gì chúng ta biểu diễn ở trên phù hợp với giá trị xx101xxx, và đây chính là cậu lệnh SUB. Hai bit khác sẽ dùng để miêu tả toán hạng đầu tiên của câu lệnh SUB. Chúng ta lại xem tiếp trong một bảng phụ lục thứ 3 (Phụ lục A3), chúng ta tìm thấy 11 có nghĩa là chúng ta sẽ sử dụng trực tiếp một thanh ghi, và giá trị 100 ở trên chính là biểu diễn cho thanh ghi ESP. Quay trở lại bảng phụ lục A1 chúng ta thấy rằng cần phải có một toán hạng nữa để điền vào, đó chính là ‘Ib’ (Input byte). Rất dễ dàng để chúng ta thấy rằng byte tiếp theo đó chính là 20h. Ghép tất cả những gì chúng ta vừa phân tích ở trên lại với nhau ,chúng ta sẽ có được một câu lệnh ASM đầu tiên : 83EC20 SUB ESP, 20 Okie như các bạn đã thấy, khá phức tạp phải không nào. Chúng ta phải tra đi tra lại mới ra được còn máy tính thì thực hiện quá nhanh . Tiếp theo chúng ta sẽ tiếp tục quá trình phân tích với câu lệnh kế tiếp, bắt đầu tại giá trị 53h . Tra cứu trên bảng A1 nó cho chúng ta biết đây là một byte độc lập mà không có tham số : PUSH rBX (= PUSH EBX) Vậy cuối cùng chúng ta có được kết quả với 4 bytes đầu tiên được biểu diễn bằng ASM : 83EC20 SUB ESP, 20 53 PUSH EBX Như các bạn đã thấy việc làm này đã tiêu tốn của chúng ta rất nhiều thời gian phải không. Tuy nhiên chúng ta thật may mắn khi có những công cụ đã thực hiện điều này cho chúng ta (ví dụ : HIEW) : 83EC20 sub esp,020 53 push ebx 56 push esi 57 push edi FF158C404000 call d,[0040408C] 33DB xor ebx,ebx A398814000 mov [00408198],eax 53 push ebx Hoặc một cách khác cũng có thể giúp cho công việc của chúng ta đơn giản hơn đó là nhờ đến Ollydbg, chúng ta cũng có được đoạn code tương tự : Tuy nhiên nhiều khi nhìn vào chúng ta không thể hiểu ngay được ý nghĩa của chúng, vi dụ như địa chỉ ở trên tham chiếu đến hàm nào, có trỏ tới một String nào không v v Để giúp cho chúng ta các chương trình Disassemblers như IDA và W32DASM đã hỗ trợ rất nhiều. Sử dụng IDA, chúng ta sẽ có được nhiều thông tin hơn : sub esp, 20h push ebx push esi push edi call ds:GetProcessHeap xor ebx, ebx mov hHeap, eax push ebx ; lpModuleName Như bạn đã thấy, IDA đã thực hiện thật tuyệt.Nó đã nhận ra được hàm call sẽ gọi tới API nào và nó cũng hiểu được giá trị trả về từ hàm đó, đó là hàm (GetProcessHeap) và do đó nó sẽ đổi tên biến thành hHeap. Đây chỉ là minh họa nhỏ cho thấy những gì IDA có thể làm được, nhưng cũng đủ để thấy rằng nó cung cấp cho chúng ta rất nhiều thông tin hơn là những gì chúng ta quan sát trong HIEW. Điều này thật là tuyệt vời và nó giúp cho chúng ta tiết kiệm được rất nhiều thời gian hơn vào việc làm bằng tay, và bên cạnh đó nó cũng giúp cho chúng ta có một điểm bắt đầu tốt cho quá trình phân tích code về sau. . Hexadecimal 00 00 0 0 00 01 1 1 0 0 10 2 2 0 011 3 3 01 0 0 4 4 01 0 1 5 5 01 1 0 6 6 01 1 1 7 7 10 00 8 8 10 01 9 9 10 10 10 A 10 11 11 B 11 00 12 C 11 01 13 D 11 10 14 E 11 11 15 F 10 000 16 10 Như. là 10 00 thì giá trị ở hệ Hexa là ( 10 ), đó là vì con số 1 đầu tiên có thể được biểu diễn thành 00 01 , trong khi số 0 thứ 2 được biêu diễn bằng (00 00) . Do đó chúng ta có kết quả là 00 01 0 00 0, giá. chúng ta (ví dụ : HIEW) : 83EC 20 sub esp ,02 0 53 push ebx 56 push esi 57 push edi FF158C 404 000 call d, [00 404 08C] 33DB xor ebx,ebx A398 814 00 0 mov [00 40 819 8],eax 53 push ebx Hoặc một

Ngày đăng: 03/07/2014, 17:21

Tài liệu cùng người dùng

Tài liệu liên quan