Tổng quan
Chào mừng đến với Phần 1 của một loạt các bài viết trên Windows Khai thác phát triển. Trong phần đầu tiên, tôi sẽ nói chỉ là vấn đề cơ bản cần thiết để hiểu được nội dung của bài viết trong tương lai, bao gồm cả một số cú pháp hội, bố trí bộ nhớ Windows, và sử dụng một trình gỡ lỗi. Đây không phải là một cuộc thảo luận toàn diện về bất kỳ chủ đề vì vậy nếu bạn không có tiếp xúc với hội, nếu bất cứ điều gì không rõ ràng sau khi bạn đọc qua bài viết đầu tiên này, tôi khuyến khích bạn hãy xem các liên kết khác nhau để các nguồn lực tôi đã cung cấp trong suốt .
Kế hoạch của tôi cho phần còn lại của loạt bài này là để đi bộ thông qua các chủ đề khai thác, từ đơn giản (trực tiếp ghi đè lên EIP) đến phức tạp hơn (unicode, thợ săn trứng, ASLR bỏ qua, đống phun, khai thác điều khiển thiết bị, vv), sử dụng khai thác thực tế để chứng minh mỗi. Tôi không thực sự có một kết thúc trong tầm nhìn, như vậy là tôi nghĩ về nhiều chủ đề, tôi sẽ tiếp tục viết bài.
Mục đích
Mục tiêu của tôi trong bộ phim này của bài viết là giới thiệu các khái niệm về việc tìm kiếm và khai thác văn bản ứng dụng Windows với hy vọng rằng các chuyên gia bảo mật và CNTT đã không có nhiều tiếp xúc với kỹ thuật cho những khái niệm này có thể mất một quan tâm đến phần mềm bảo mật và áp dụng kỹ năng của họ để làm cho phần mềm miền tư nhân và công cộng an toàn hơn. Disclaimer: Nếu bạn là một ai đó mà muốn xây dựng khai thác để tham gia vào các hoạt động bất hợp pháp hoặc vô đạo đức, xin vui lòng đi nơi khác.
Tôi cũng nên đề cập đến những bài viết không có ý định cạnh tranh với các hướng dẫn tuyệt vời khác ra khỏi đó như Corelan đội , The Grey góc , và an ninh mờ . Thay vào đó, họ có nghĩa là để bổ sung cho họ và cung cấp thêm một nguồn lực để giải thích và ví dụ - nếu bạn đang như tôi, bạn có thể không bao giờ có quá nhiều ví dụ. Tôi rất khuyến khích bạn hãy kiểm tra các trang web tuyệt vời khác.
Những gì bạn cần
Đây là những gì bạn cần nếu bạn muốn theo cùng:
- Một cài đặt Windows: Tôi có kế hoạch bắt đầu với Windows XP SP3 nhưng như tôi tiến bộ và các chủ đề khác nhau / khai thác, tôi cũng có thể sử dụng các phiên bản khác bao gồm Windows 7 và Windows Server 2003/2008.
- Một Debugger: Trên máy chủ Windows, bạn cũng sẽ cần một trình gỡ lỗi. Tôi chủ yếu sẽ được sử dụng miễn dịch Debugger mà bạn có thể tải về ở đây . Bạn cũng sẽ nhận được các plugin mona có thể tìm thấy ở đây . Tôi cũng sẽ sử dụng WinDbg cho một số ví dụ của tôi. Hướng dẫn tải về có thể được tìm thấy ở đây (di chuyển xuống trang cho các phiên bản trước của Windows).
- Một máy chủ Backtrack / Kali (tùy chọn): Tôi sử dụng một máy chủ Kali cho tất cả các kịch bản của tôi và cũng có kế hoạch sử dụng nó như là "tấn công máy" trong bất kỳ từ xa khai thác ví dụ tôi sử dụng. Tôi định sử dụng Perl và Python cho phần lớn các kịch bản của tôi, do đó bạn có thể chọn để cài đặt hoặc là môi trường ngôn ngữ trên máy chủ Windows của bạn để thay thế.
Bắt đầu với miễn dịch Debugger
Hãy bắt đầu bằng cách nhìn vào một trình gỡ lỗi vì chúng ta sẽ dành khá nhiều thời gian sử dụng một trong suốt những hướng dẫn. Tôi sẽ được chủ yếu sử dụng miễn dịch sửa lỗi bởi vì nó miễn phí và có một số bổ sung và khả năng kịch bản tùy chỉnh mà tôi dự định làm nổi bật khi chúng ta tiến bộ.
Tôi sẽ sử dụng Windows Media Player là một chương trình ví dụ để giới thiệu miễn dịch Debugger. Nếu bạn muốn theo cùng, bạn mở Windows Media Player và miễn dịch Debugger. Trong miễn dịch, nhấn File -> Đính kèm và chọn tên của ứng dụng / quá trình (trong ví dụ của tôi, wmplayer). Lưu ý: bạn cũng có thể khởi động trực tiếp từ WMP miễn dịch bằng cách nhấn vào File -> Open và chọn file thực thi.
Một khi bạn đã đưa ra một thực thi hoặc gắn liền với một quá trình trong miễn dịch, bạn nên được đưa đến xem CPU (nếu không, nhấn Alt + C), trông như thế này:
Khi bạn chạy / đính kèm vào một chương trình miễn dịch với nó bắt đầu trong trạng thái tạm dừng (xem phía góc tay phải). Để chạy chương trình bạn có thể nhấn F9 (hoặc nút play trên thanh công cụ). Để bước vào lệnh tiếp theo (nhưng tạm dừng thực hiện chương trình) nhấn F7. Bạn có thể sử dụng F7 để bước qua từng giảng dạy tại một thời điểm. Nếu bất cứ lúc nào bạn muốn khởi động lại chương trình, nhấn Ctrl + F2. Tôi sẽ không được cung cấp một hướng dẫn đầy đủ về cách sử dụng miễn dịch, nhưng tôi sẽ cố gắng đề cập đến bất kỳ phím tắt có liên quan và các phím nóng như tôi trình bày khái niệm mới trong này và các bài viết trong tương lai.
Như bạn có thể thấy, cửa sổ CPU được chia thành bốn tấm mô tả các thông tin sau:
- Hướng Dẫn CPU - hiển thị các hướng dẫn địa chỉ bộ nhớ, mã máy và lắp ráp, ý kiến bổ sung, tên chức năng và thông tin khác liên quan đến các hướng dẫn CPU
- Các Đăng ký - hiển thị các nội dung của sổ đăng ký mục đích chung, hướng con trỏ, và cờ kết hợp với tình trạng hiện tại của ứng dụng ..
- Stack - thể hiện nội dung của ngăn xếp hiện tại
- Memory Dump - thể hiện nội dung của bộ nhớ của ứng dụng
Chúng ta hãy nhìn vào mỗi một sâu hơn một chút, bắt đầu với đăng ký.
CPU Đăng ký
Sổ đăng ký CPU phục vụ khu vực lưu trữ nhỏ được sử dụng để truy cập dữ liệu một cách nhanh chóng.Trong x86 (32-bit) kiến trúc có 8 thanh ghi mục đích chung: EAX, EBX, ECX, EDX, EDI, ESI, EBP, và ESP. Họ về mặt kỹ thuật có thể được sử dụng để lưu trữ dữ liệu, mặc dù chúng đã được kiến trúc để thực hiện nhiệm vụ cụ thể, và trong nhiều trường hợp vẫn được sử dụng theo cách đó ngày hôm nay.
Dưới đây là chi tiết hơn một chút cho mỗi ...
EAX - Các Accumulator Đăng ký.
Nó được gọi là đăng ký ắc bởi vì đó là đăng ký chính được sử dụng để tính toán thông thường (như ADD và SUB). Trong khi đăng ký khác có thể được sử dụng để tính toán, EAX đã được trao cho tình trạng ưu đãi bằng cách gán cho nó hiệu quả hơn, opcodes một byte. Hiệu quả như vậy có thể là quan trọng khi nói đến văn bản khai thác shellcode cho một không gian hạn chế có sẵn đệm (thêm vào đó trong tương lai hướng dẫn). Ngoài việc sử dụng nó trong tính toán, EAX cũng được sử dụng để lưu trữ các giá trị trả về của một hàm.
Đăng ký mục đích chung này có thể được tham chiếu trong toàn bộ hoặc một phần như sau: EAX đề cập đến đăng ký 32-bit trong toàn bộ. AX đề cập đến 16 bit ít nhất là đáng kể có thể được tiếp tục chia thành AH (8 bit quan trọng nhất của AX) và AL (8 bit ít quan trọng).
Dưới đây là một hình ảnh cơ bản:
Toàn bộ này cùng một / một phần 32 -, 16 -, và 8-bit tham khảo cũng áp dụng cho ba đăng ký tiếp theo (EBX, ECX, EDX và)
EBX - Các cơ sở đăng ký.
Trong kiến trúc 32-bit, EBX không thực sự có một mục đích đặc biệt như vậy chỉ cần nghĩ về nó như một nhận tất cả để lưu trữ có sẵn. Như EAX, nó có thể được tham chiếu trong toàn bộ (EBX) hoặc một phần (BX, BH, BL).
ECX - The Counter Đăng ký.
Như tên gọi của nó, bộ đếm (hoặc tính) đăng ký thường được sử dụng như một vòng lặp và chức năng lặp lại truy cập, mặc dù nó cũng có thể được sử dụng để lưu trữ dữ liệu. Như EAX, nó có thể được tham chiếu trong toàn bộ (ECX) hoặc một phần (CX, CH, CL).
EDX - Các dữ liệu Đăng ký
Điện cơ là loại giống như một đối tác đăng ký để EAX. Nó thường được sử dụng trong các hoạt động toán học như phân chia và nhân để đối phó với tràn nơi các bit quan trọng nhất sẽ được lưu trữ trong điện cơ và ít nhất có ý nghĩa trong EAX. Nó cũng thường được sử dụng để lưu trữ các biến chức năng.Như EAX, nó có thể được tham chiếu trong toàn bộ (điện cơ) hoặc một phần (DX, DH, DL).
ESI - Nguồn Index
Các đối tác để EDI, ESI thường được sử dụng để lưu trữ các con trỏ đến một vị trí đọc. Ví dụ, nếu một chức năng được thiết kế để đọc một chuỗi, ESI sẽ giữ con trỏ đến vị trí của chuỗi.
EDI - Chỉ số Điểm đến
Mặc dù nó có thể được (và là) được sử dụng để lưu trữ dữ liệu chung, EDI được thiết kế chủ yếu để lưu trữ các con trỏ lưu trữ các chức năng, chẳng hạn như địa chỉ ghi trong một hoạt động chuỗi.
EBP - Các cơ sở Pointer
EBP được sử dụng để theo dõi các cơ sở / dưới cùng của ngăn xếp. Nó thường được sử dụng để tham khảo các biến nằm trên stack bằng cách sử dụng một bù đắp cho giá trị hiện tại của EBP, mặc dù nếu các thông số chỉ được tham chiếu bởi đăng ký, bạn có thể chọn để sử dụng cho các mục đích sử dụng EBP chung.
ESP - Các Stack Pointer
ESP được sử dụng để theo dõi trên cùng của ngăn xếp. Như các mặt hàng được chuyển đến và đi từ stack gia ESP / decrements cho phù hợp. Của tất cả các đăng ký mục đích chung, ESP là hiếm khi / không bao giờ được sử dụng cho bất cứ điều gì khác hơn đó là dự định mục đích.
Chỉ thị Pointer (EIP)
Không đăng ký mục đích chung, nhưng phù hợp để trang trải ở đây, EIP chỉ ra địa chỉ bộ nhớ của lệnh tiếp theo được thực hiện bởi CPU. Như bạn sẽ thấy trong hướng dẫn tới, kiểm soát giá trị của EIP và bạn có thể kiểm soát lưu lượng thực hiện của ứng dụng (để thực thi mã lựa chọn của bạn).
Đăng ký phân đoạn và EFLAGS đăng ký
Có hai thanh ghi thêm bạn sẽ thấy trong cửa sổ đăng ký, các bộ phận Đăng ký và EFLAGS đăng ký. Tôi sẽ không bao gồm hai chi tiết nhưng lưu ý đăng ký EFLAGS bao gồm một loạt các lá cờ đại diện cho các giá trị Boolean do tính toán và so sánh và có thể được sử dụng để xác định khi nào / nếu để nhảy có điều kiện (nhiều hơn về những sau).
Để biết thêm về các thanh ghi CPU, kiểm tra các nguồn tài nguyên:
Dump bộ nhớ
Bỏ qua một cửa sổ Dump bộ nhớ của CPU xem, điều này chỉ đơn giản là nơi bạn có thể xem nội dung của một vị trí bộ nhớ. Ví dụ, hãy nói rằng bạn muốn xem nội dung của bộ nhớ ESP, mà trong ảnh chụp màn hình sau đây được trỏ đến 0007FF0C. Nhấp chuột phải vào ESP, chọn "theo trong Dump" và cửa sổ Dump bộ nhớ sẽ hiển thị vị trí đó.
Hướng dẫn CPU
Như bạn đã biết, hầu hết các ứng dụng hiện nay được viết bằng một ngôn ngữ cấp cao (C, C + +, vv).Khi ứng dụng được biên dịch, những hướng dẫn ngôn ngữ cấp cao được dịch sang hội đã tương ứng với mã máy để giúp thêm dịch hướng dẫn vào một cái gì đó máy có thể hiểu được (mã máy). Trong trình gỡ lỗi, bạn có thể xem hướng dẫn mỗi hội (và mã máy tương ứng) được xử lý bởi CPU trong Pane CPU dẫn. Lưu ý: Đối với Windows Khai thác Series, tôi sẽ sử dụng ngôn ngữ lắp ráp Intel x86 cú pháp (http://en.wikipedia.org/wiki/X86_assembly_language # cú pháp ).
Bạn có thể bước qua lưu lượng thực hiện của một chương trình tại một thời điểm (F7) và xem kết quả của mỗi lệnh CPU. Chúng ta hãy nhìn vào tập đầu tiên của hướng dẫn Windows Media Player. Chương trình bắt đầu dừng lại. Nhấn F7 một vài lần để thực hiện những hướng dẫn đầu tiên cho đến khi chúng tôi nhận được vào thứ hai MOV DWORD PTR SS: hướng dẫn (được đánh dấu trong hình dưới đây). Bản sao lệnh MOV một mục dữ liệu từ một địa điểm khác.
Hướng dẫn này sẽ di chuyển các nội dung của EBX vào vị trí địa chỉ bộ nhớ được trỏ đến bởi EBP - 18 (nhớ với Intel x86 cú pháp đó là MOV [dst] [src]). Chú ý rằng EBP (con trỏ cơ sở stack) được trỏ đến 0007FFC0. Sử dụng Windows hoặc Mac máy tính của bạn (trong khoa học / lập trình chế độ), tính toán 0007FFC0 - 0 × 18. Kết quả sẽ 0x7FFA8, có nghĩa là nội dung của EBP sẽ được đặt vào vị trí của địa chỉ 0007FFA8. Trong thực tế, bạn không cần phải tính toán bên ngoài này của miễn dịch. Chú ý các tiểu cửa sổ ở dưới cùng của cửa sổ lệnh CPU. Nó đã cho bạn biết giá trị của EBX, cũng như giá trị của 0007FFC0 - 0 × 18 và các nội dung hiện tại của vị trí đó bộ nhớ (F4C47D04). Bạn có thể nhấp chuột phải vào các "Stack" dòng trong đó tiểu cửa sổ và chọn "theo địa chỉ trong Dump" để xác minh các nội dung của bộ nhớ vị trí.
Bây giờ nhấn F7 lần nữa để thực hiện lệnh. Chú ý 0007FFA8 vị trí bộ nhớ hiện nay có một giá trị của 00000000, vì nội dung của EBX đã được chuyển đó.
Đây chỉ là một ví dụ nhanh chóng như thế nào bạn có thể thực hiện theo các hướng dẫn thực hiện của mỗi CPU trong miễn dịch. Dưới đây là một vài hướng dẫn hội phổ biến hơn và cú pháp bạn sẽ đi qua:
- ADD / SUB op1, op2 - thêm hoặc trừ đi hai toán hạng, lưu trữ kết quả trong toán hạng đầu tiên. Đây có thể được đăng ký, vị trí bộ nhớ (giới hạn của một) hoặc hằng số. Ví dụ, ADD EAX, 10 có nghĩa là thêm 10 với giá trị của EAX và lưu trữ kết quả trong EAX
- XOR EAX, EAX - Thực hiện một 'độc quyền hoặc' của một đăng ký với chính nó đặt giá trị của nó bằng không; một cách dễ dàng thanh toán bù trừ nội dung của một đăng ký
- INC / DEC op1-tăng hoặc giảm giá trị của toán hạng của một
- CMP op1, op2 - so sánh giá trị của hai toán hạng (đăng ký / địa chỉ bộ nhớ / liên tục) và thiết lập giá trị EFLAGS thích hợp.
- Nhảy (JMP) và nhảy có điều kiện (je, jz, vv) - như tên của nó những hướng dẫn này cho phép bạn chuyển đến một vị trí khác trong bộ lưu lượng thực hiện / hướng dẫn. Hướng dẫn JMP chỉ đơn giản là nhảy đến một vị trí trong khi nhảy có điều kiện (je, jz, vv) được thực hiện chỉ khi tiêu chí nhất định được đáp ứng (bằng cách sử dụng EFLAGS đăng ký giá trị đề cập trước đó). Ví dụ, bạn có thể so sánh giá trị của hai đăng ký và chuyển đến một địa điểm nếu cả hai bằng nhau (sử dụng hướng dẫn je và không cờ (ZF) = 1).
- Khi bạn nhìn thấy một giá trị trong ngoặc như ADD DWORD PTR [X] hay MOV eax, [ebx] nó là đề cập đến giá trị được lưu trữ tại địa chỉ bộ nhớ X. Nói cách khác, EBX đề cập đến các nội dung của EBX trong khi đó [EBX] đề cập đến giá trị được lưu trữ tại địa chỉ bộ nhớ trong EBX.
- Từ khóa có liên quan kích thước: BYTE = 1 byte, 2 byte = WORD, DWORD = 4 byte.
Tôi chắc chắn không có chuyên môn, nhưng khi nói đến sự hiểu biết và cuối cùng phát triển mã khai thác của riêng bạn, bạn nên có một nắm bắt khá vững chắc của hội. Tôi sẽ thảo luận về một vài hướng dẫn hội hơn khi chúng ta tiến bộ nhưng tôi không có kế hoạch bao gồm các ngôn ngữ hội vào chiều sâu, vì vậy nếu bạn cần xem lại có một tấn các nguồn tài nguyên trực tuyến tốt bao gồm:
Nếu bạn muốn có một cuốn sách để mua, bạn có thể xem xét việc này một: Hacking: The Art of Khai thác: Nghệ thuật của khai thác mà không chỉ bao gồm các vấn đề cơ bản của hội nhưng cũng được lập thành văn bản khai thác (mặc dù chủ yếu trong môi trường Linux).
Cho loạt bài này của bài viết tôi sẽ làm hết sức mình để giải thích bất kỳ ví dụ mã tôi sử dụng vì vậy nếu bạn có ít nhất một số hiểu biết cơ bản của hội bạn nên được tốt.
Giao diện Windows Memory
Trước khi chúng ta nói về chồng, tôi muốn nói ngắn gọn về cách bố trí bộ nhớ quá trình Win32. Tôi cần nêu lên phía trước rằng đây sẽ là một giới thiệu cấp cao vô cùng và sẽ không bao gồm các khái niệm như Address Space Layout Randomization (ASLR), ảo để dịch Địa chỉ vật lý, Paging, Địa chỉ vật lý mở rộng, vv Tôi có kế hoạch để trang trải một số của các chủ đề này trong một phần sau, nhưng bây giờ tôi muốn giữ cho mọi thứ rất đơn giản.
Đầu tiên, với miễn dịch gắn liền với Windows Media Player, hãy nhìn vào bản đồ bộ nhớ bằng cách nhấn ALT + M (Hoặc bạn có thể chọn View-> nhớ hoặc nhấp vào biểu tượng 'M' trên thanh công cụ).
Bạn nên được trình bày với cái gì đó trông giống như sau (mục chính xác có thể thay đổi):
Đây là cách bố trí bộ nhớ của wmplayer.exe bao gồm cả đống, đống, mô-đun được nạp (DLL) và thực thi chính nó. Tôi sẽ giới thiệu từng mặt hàng một cách chi tiết hơn một chút bằng cách sử dụng một phiên bản hơi đơn giản của bản đồ bộ nhớ lớn được tìm thấy trên Corelan của hướng dẫn giới thiệu về Stack Dựa tràn mà tôi đã ánh xạ tới các bản đồ bộ nhớ miễn dịch của Windows Media Player.
Chúng ta hãy làm việc theo cách của chúng tôi từ dưới lên, bắt đầu với phần bộ nhớ từ 0xFFFFFFFF để 0x7FFFFFFF mà thường được gọi là "hạt nhân đất".
Hạt nhân đất
Phần này của bộ nhớ được bảo vệ bởi hệ điều hành cho thiết bị điều khiển, hệ thống bộ nhớ cache, phân trang / không paged hồ bơi, HAL, vv Không có người dùng truy cập đến phần này của bộ nhớ. Lưu ý: cho một lời giải thích thấu đáo về quản lý bộ nhớ Windows, bạn nên kiểm tra các cuốn sách của Windows Internals (hiện tại hai khối lượng).
PEB và TEB (s)
Khi bạn chạy một chương trình / ứng dụng, một thể hiện của thực thi được biết đến như là một quá trình được chạy. Mỗi quá trình cung cấp các nguồn lực cần thiết để chạy một thể hiện của chương trình đó. Mọi quá trình Windows có một quá trình điều hành (vụ Điện tử) cấu trúc chứa các thuộc tính quá trình và con trỏ đến cấu trúc dữ liệu có liên quan. Trong khi hầu hết các cấu trúc vụ Điện tử nằm trong hạt nhân Đất đai, trong Process Environment Block (PEB) nằm trong bộ nhớ người dùng có thể truy cập.Các PEB chứa các thông số chế độ người dùng khác nhau về một quá trình chạy. Bạn có thể sử dụng WinDbg để dễ dàng kiểm tra các nội dung của PEB bằng cách phát lệnh PEB!.
Như bạn có thể thấy, PEB bao gồm các thông tin như địa chỉ cơ sở của hình ảnh (thực thi), vị trí của đống, các mô-đun được nạp (DLL), và các biến môi trường (Hệ điều hành, đường dẫn có liên quan, vv).Hãy xem các ImageBaseAddress từ ảnh chụp màn hình WinDbg trên. Lưu ý các địa chỉ 01000000. Bây giờ xem lại trước sơ đồ Win32 bộ nhớ đồ và lưu ý cách này giống như là địa chỉ đầu tiên trong lời thoại miễn dịch của "Chương trình Image" khối. Bạn có thể làm tương tự cho địa chỉ đống và các file DLL liên quan.
Một lưu ý nhanh chóng về các tập tin biểu tượng ... đó là đặc biệt hữu ích để tải các tập tin biểu tượng thích hợp khi gỡ lỗi các ứng dụng Windows như họ cung cấp hữu ích, thông tin mô tả cho các chức năng, các biến, vv Bạn có thể làm như vậy trong WinDbg bằng cách vào "File -> Biểu tượng File Path ... ". Thực hiện theo các hướng dẫn tìm thấy ở đây: http://support.microsoft.com/kb/311503 . Bạn cũng có thể tải các tập tin biểu tượng trong miễn dịch bằng cách vào "Debug -> Debugging hiệu Options".
Thêm chi tiết về toàn bộ cấu trúc PEB có thể được tìm thấy ở đây .
Một chương trình, hoặc quá trình, có thể có một hoặc nhiều chủ đề mà phục vụ như là đơn vị cơ bản mà hệ điều hành phân bổ thời gian xử lý. Mỗi quá trình bắt đầu với một chủ đề duy nhất (Chủ đề chính) nhưng có thể tạo chủ đề bổ sung khi cần thiết. Tất cả các chủ đề chia sẻ không gian địa chỉ và tài nguyên hệ thống ảo cùng phân bổ cho quá trình cha mẹ. Mỗi chủ đề cũng có nguồn tài nguyên riêng của mình bao gồm cả xử lý ngoại lệ, ưu tiên, lưu trữ địa phương, vv Chỉ cần như mỗi chương trình / quá trình có một PEB, mỗi chủ đề có một chủ đề Môi trường Block (TEB). Các TEB lưu trữ thông tin bối cảnh cho bộ nạp hình ảnh và khác nhau Windows DLL, cũng như vị trí cho danh sách xử lý ngoại lệ (mà chúng tôi sẽ đề cập chi tiết trong một bài sau). Như PEB, các TEB nằm trong không gian địa chỉ tiến trình từ các thành phần chế độ người dùng yêu cầu truy cập có thể ghi.
Bạn cũng có thể xem TEB (s) sử dụng WinDbg.
Thêm chi tiết về toàn bộ cấu trúc TEB có thể được tìm thấy ở đây và biết thêm chi tiết về quy trình và chủ đề có thể được tìm thấy ở đây .
DLL
Chương trình cửa sổ tận dụng lợi thế của các thư viện mã được chia sẻ được gọi là liên kết động thư viện (DLL) cho phép tái sử dụng mã hiệu quả và cấp phát bộ nhớ. Các DLL (còn được gọi là mô-đun hoặc mô-đun thực thi) chiếm một phần của không gian bộ nhớ. Như thể hiện trong bộ nhớ đồ ảnh chụp màn hình, bạn có thể xem chúng trong miễn dịch trong giao diện bộ nhớ (Alt + M), hoặc nếu bạn chỉ muốn xem các file DLL bạn có thể chọn xem thực thi Module (Alt + E). Có những mô-đun hệ điều hành / hệ thống (ntdll, user32, vv) cũng như các module ứng dụng cụ thể và sau này là thường hữu ích trong việc tạo khai thác tràn (được nêu trong bài viết trong tương lai).
Dưới đây là một ảnh chụp màn hình của quan điểm Bộ nhớ trong miễn dịch:
Hình ảnh chương trình
Chương trình phần hình ảnh của bộ nhớ là nơi thực thi cư trú. Điều này bao gồm phần. Văn bản (có chứa các hướng dẫn mã / CPU thực thi) phần dữ liệu. (Chứa dữ liệu toàn cầu của chương trình) và phần rsrc. (Có nguồn tài nguyên không thực thi, bao gồm các biểu tượng, hình ảnh, và dây).
Ban ơn
Heap là các cấp phát động (ví dụ: malloc ()) phần bộ nhớ một chương trình sử dụng để lưu trữ các biến toàn cầu. Không giống như các ngăn xếp, phân bổ bộ nhớ heap phải được quản lý bởi các ứng dụng.Nói cách khác, bộ nhớ sẽ vẫn được giao cho đến khi nó được giải phóng bởi các chương trình hoặc chương trình chính nó chấm dứt. Bạn có thể nghĩ đống như một hồ bơi được chia sẻ bộ nhớ trong khi ngăn xếp, mà chúng tôi sẽ đề cập tới, là có tổ chức hơn và chia ngăn. Tôi sẽ không đi quá sâu hơn vào đống chỉ được nêu ra nhưng kế hoạch để trang trải nó trong một bài viết sau này tràn heap.
Stack
Không giống như đống, nơi cấp phát bộ nhớ cho các biến toàn cầu là tương đối tùy ý và bền vững, ngăn xếp được sử dụng để phân bổ lưu trữ ngắn hạn cho địa phương (chức năng / phương pháp) biến một cách trật tự và bộ nhớ được giải phóng sau đó tại chấm dứt được chức năng. Nhớ lại cách một quá trình nhất định có thể có nhiều chủ đề. Mỗi chủ đề / chức năng được phân bổ stack frame riêng của mình. Kích thước của ngăn xếp khung là cố định sau khi tạo và khung ngăn xếp được xóa khi kết thúc hàm.
PUSH và POP
Trước khi chúng tôi xem làm thế nào một chức năng được phân công một stack frame, chúng ta hãy xem nhanh một số PUSH và POP hướng dẫn đơn giản để bạn có thể xem như thế nào dữ liệu được đặt vào và lấy ra khỏi ngăn xếp. Stack là một cuối cùng trong đầu ra (LIFO) cấu trúc có nghĩa là mục cuối cùng bạn đưa vào ngăn xếp là mục đầu tiên bạn đưa ra. Bạn "đẩy" mục lên trên cùng của ngăn xếp và bạn "pop" mục tắt của đỉnh của stack. Chúng ta hãy xem này trong hành động ...
Trong hình bên dưới, bạn sẽ thấy một loạt các hướng dẫn PUSH trong cửa sổ hướng dẫn CPU (phía trên bên trái), mỗi trong số đó sẽ có một giá trị từ một trong sổ đăng ký (khung trên bên phải) và đặt giá trị trên đỉnh của stack (cửa sổ bên phải thấp hơn).
Hãy bắt đầu với các lệnh PUSH đầu tiên (PUSH ECX).
Lưu ý các giá trị của ECX cũng như địa chỉ và giá trị đỉnh của stack (dưới góc phải của màn hình trước đó). Bây giờ hướng dẫn PUSH ECX thực hiện ...
Sau khi chỉ lệnh PUSH ECX đầu tiên, giá trị từ ECX (địa chỉ 0012E6FC) đã được đẩy đến đỉnh của stack (như minh họa trong hình trên). Chú ý địa chỉ của đỉnh ngăn xếp giảm 4 byte (Từ 0012E650 để 0012E64C). Điều này cho thấy ngăn xếp phát triển lên đến các địa chỉ thấp hơn như các mặt hàng được đẩy lên nó. Cũng nhận thấy rằng ESP chỉ để trên cùng của ngăn xếp và EBP điểm các cơ sở của stack frame này. Bạn sẽ nhận thấy trong ảnh chụp màn hình đến đó EBP (con trỏ cơ sở) vẫn không đổi trong khi ESP (con trỏ ngăn xếp) thay đổi như ngăn xếp phát triển và co lại. Bây giờ, các lệnh PUSH ECX thứ hai sẽ được thực hiện ...
Một lần nữa, giá trị từ ECX (0012E6FC) đã được đẩy đến đỉnh của stack, ESP điều chỉnh giá trị của nó bằng cách thêm 4 byte, và bạn có thể thấy trong hình trên, các lệnh PUSH cuối cùng (PUSH EDI) là về để được thực hiện.
Bây giờ giá trị từ EDI (41414139) đã được đẩy đến đỉnh của stack và lệnh tiếp theo trong danh sách là về để được thực thi (một lệnh MOV) và giá trị của EDI thay đổi. Chúng ta hãy bỏ qua để hướng dẫn POP EDI để hiển thị như thế nào các mặt hàng được lấy ra khỏi ngăn xếp. Trong trường hợp này, giá trị hiện tại trên đỉnh của stack (41414139) sẽ được lấy ra khỏi và đưa vào EDI.
Như bạn có thể thấy, giá trị của EDI đã thay đổi trở lại 41414139 theo hướng dẫn POP. Bây giờ bạn có một ý tưởng về cách thao tác đống chính, chúng ta hãy xem làm thế nào các khung stack được tạo ra cho các chức năng địa phương và làm thế nào biến được đặt trên stack. Hiểu được điều này sẽ rất quan trọng khi chúng ta bước vào tràn ngăn xếp dựa trên trong phần 2 của loạt bài này.
Ngăn xếp các khung hình và chức năng
Khi một chương trình thực thi chức năng, một stack frame được tạo ra để lưu trữ các biến cục bộ của nó. Mỗi chức năng được khung stack riêng của mình, được đặt lên hàng đầu của ngăn xếp hiện tại và làm cho chồng tăng lên đến các địa chỉ thấp hơn.
Mỗi lần một stack frame được tạo ra, một loạt các hướng dẫn thực hiện để đối số chức năng lưu trữ và địa chỉ trả lại (vì vậy chương trình biết đi đâu sau khi chức năng là hơn), tiết kiệm con trỏ cơ sở của stack frame hiện tại, và không gian dự trữ bất kỳ biến chức năng địa phương. [Lưu ý: Tôi cố ý bỏ qua xử lý ngoại lệ để thảo luận cơ bản này nhưng sẽ giải quyết chúng trong một bài sau].
Chúng ta hãy nhìn vào việc tạo ra một khung ngăn xếp sử dụng một trong những chức năng đơn giản nhất tôi có thể tìm thấy ( từ Wikipedia ):
Mã này chỉ đơn giản gọi hàm foo (), đi qua nó một lệnh tham số đối số dòng duy nhất (argv [1]). Function foo () sau đó tuyên bố một c biến chiều dài 12, bảo lưu không gian cần thiết trên các ngăn xếp để giữ argv [1]. Sau đó nó gọi hàm strcpy () mà các bản sao giá trị của argv [1] vào biến c. Theo các tiểu bang bình luận, không có kiểm tra để điều này sử dụng strcpy có thể dẫn đến lỗi tràn bộ đệm, mà tôi sẽ chứng minh trong phần 2 của loạt bài này giới hạn. Bây giờ, chúng ta hãy tập trung vào cách chức năng này ảnh hưởng đến chồng.
Tôi biên dịch chương trình c này (như stack_demo.exe) sử dụng Visual Studio Command Prompt (2010) để hiển thị chính xác những gì có vẻ như là nó thực hiện trong một chương trình gỡ rối. Bạn có thể chạy một chương trình với các lệnh trực tiếp từ miễn dịch bằng cách chọn File-> Open (hoặc đơn giản nhấn F3), chọn thực thi của bạn, và nhập số dòng lệnh của bạn (s) trong lĩnh vực nhất định.
Trong ví dụ này, tôi chỉ đơn giản là sử dụng 11 A cho argv [1]. [Chúng tôi sẽ xem xét những gì xảy ra khi bạn sử dụng hơn 11 phần 2!]
Nếu bạn muốn theo cùng, có thể bạn sẽ muốn chèn một số breakpoint ở các phần liên quan của mã này.Từ địa chỉ có thể thay đổi, phương pháp tốt nhất để tìm mã chương trình có liên quan của chúng tôi là chọn View -> module thực thi (hoặc Alt + E). Sau đó, kích đúp vào các mô-đun stack_demo.exe (hoặc bất cứ điều gì bạn có tên là exe. Của bạn).
Điều này sẽ đưa bạn đến những điều sau đây:
Dòng đầu tiên bạn nhìn thấy thực sự là sự bắt đầu của foo (), nhưng chúng ta sẽ đầu tiên hãy xem main (). Tôi đã thiết lập một số breakpoint để hỗ trợ đi bộ thông qua các mã (chỉ định bởi các điểm nhấn màu xanh nhạt) và bạn có thể làm như vậy bằng cách chọn địa chỉ mong muốn và nhấn F2. Chúng ta hãy nhìn vào chính () ...
Mặc dù chính () không gì hơn là chức năng gọi foo () có một vài điều mà có xảy ra đầu tiên, như bạn sẽ thấy trong các trình gỡ lỗi. Đầu tiên, nó đẩy các nội dung của argv [1] (aaaaaaaaaaaaa) vào stack. Sau đó, khi chức năng foo () được gọi, địa chỉ trả lại được lưu vào ngăn xếp để lưu lượng thực hiện chương trình có thể tiếp tục tại vị trí thích hợp sau khi chức năng foo () kết thúc.
Hãy nhìn vào ảnh chụp màn hình miễn dịch, mà tôi đã nhận xét phù hợp - chỉ cần chú ý đến những gì trong hộp màu đỏ cho bây giờ, tôi sẽ giới thiệu một số các hướng dẫn khác trong thời gian ngắn. Bạn sẽ thấy một con trỏ đến argv [1] được đẩy vào stack ngay trước khi chức năng foo () được gọi. Sau đó hướng dẫn CALL được thực thi và địa chỉ trở lại vào lệnh tiếp theo (EIP + 4) cũng được đẩy vào stack.
Nếu bạn muốn chứng minh rằng quyết 00332FD4 chứa 0033301C đó là một con trỏ đến argv [1], tham khảo các nội dung bãi chứa của địa chỉ:
Bạn sẽ thấy nội dung viết ngược như 1C303300. Cho tôi cơ hội này để nhanh chóng bao gồm Little Endian ký hiệu. "Endian" đề cập đến thứ tự byte được lưu trữ trong bộ nhớ. Hệ thống Intel x86 dựa trên sử dụng ít ký hiệu Endian mà các cửa hàng các byte quan trọng nhất của một giá trị tại địa chỉ bộ nhớ nhỏ nhất (đó là lý do tại sao địa chỉ được lưu trữ theo thứ tự ngược). Ví dụ, tham khảo các ảnh chụp màn hình hex bãi trên - địa chỉ ở phía trên (00332FD4) là địa chỉ nhỏ nhất và ở phía dưới (00.333.034) là lớn nhất. Như vậy, các byte trong cùng bên trái (hiện đang bị chiếm đóng bởi 1C) chiếm vị trí địa chỉ nhỏ nhất và địa chỉ nhận được lớn hơn khi bạn di chuyển từ trái sang phải và trên xuống dưới. Khi bạn nhìn vào một địa chỉ như 0033301C, các byte ít nhất có ý nghĩa là byte tất cả các cách ở bên phải (1C). Để chuyển đổi nó để Little Endian ký hiệu bạn sắp xếp lại nó, một byte tại một thời gian, từ phải sang trái.Dưới đây là một hình ảnh:
Ok, do đó argv [1] và các địa chỉ trả lại hiện nay đã được đẩy lên ngăn xếp và chức năng foo () đã được gọi. Đây là một nhìn vào ngăn xếp với các phần có liên quan nhấn mạnh.
Lưu ý con trỏ đến argv [1] tại địa chỉ 0012FF74 và ngay trên nó giá trị RETURN lưu trữ. Nếu bạn xem lại ảnh chụp màn hình trước của main (), bạn sẽ nhận thấy rằng địa chỉ RETURN của 0040103F là những hướng dẫn tiếp theo sau khi CALL foo (), đó là nơi thực hiện chương trình sẽ nhận sau khi foo () kết thúc.
Bây giờ chúng ta hãy nhìn vào chức năng foo ():
Một khi chức năng foo () được gọi, điều đầu tiên mà sẽ xảy ra là cơ sở con trỏ hiện tại (EBP) sẽ được lưu vào ngăn xếp thông qua một lệnh PUSH EBP để khi chức năng chấm dứt, các cơ sở của ngăn xếp cho chính () có thể được phục hồi .
Tiếp theo, EBP được thiết lập bằng ESP (thông qua MOV EBP hướng dẫn, ESP), làm cho trên và dưới của khung ngăn xếp bằng. Từ đây, EBP sẽ vẫn không đổi (cho cuộc sống của foo chức năng) và ESP sẽ sẽ phát triển lên đến một địa chỉ thấp hơn như là dữ liệu được thêm vào ngăn xếp khung của chức năng.Dưới đây là một trước và sau khi quan điểm của các đăng ký cho thấy EBP bây giờ bằng ESP.
Tiếp theo, không gian được dành riêng cho các biến địa phương c (char c [12]) thông qua các hướng dẫn sau đây: SUB ESP, 10.
Đây là một nhìn vào ngăn xếp sau hàng loạt các hướng dẫn sau:
Chú ý trên cùng của ngăn xếp (và kết quả là ESP) đã thay đổi từ 0012FF6C để 0012FF5C.
Chúng ta hãy bỏ qua để đến các cuộc gọi của strcpy (), mà sẽ sao chép nội dung của argv [1] (aaaaaaaaaaaaa) vào không gian đã được chỉ bảo lưu trên stack cho biến c. Đây là một nhìn vào các chức năng trong trình gỡ lỗi. Tôi chỉ nhấn mạnh rằng phần thực hiện các văn bản cho chồng.
Bạn sẽ nhận thấy trong ảnh chụp màn hình sau đó nó tiếp tục lặp qua các giá trị argv [1], bằng văn bản cho không gian dành trên stack (từ trên xuống dưới của không gian dành riêng) cho đến khi tất cả các argv [1] đã được viết để ngăn xếp.
Trước khi chúng ta hãy nhìn vào những gì sẽ xảy ra với chồng khi một chức năng chấm dứt, đây là một bước theo bước trực quan để củng cố các bước thực hiện khi chức năng foo () được gọi.
Sau khi strcpy () đã hoàn thành và chức năng foo () đã sẵn sàng để chấm dứt, một số ngẫu nhiên có thể xảy ra trên stack. Chúng ta hãy nhìn vào ngăn xếp như foo () chuẩn bị chấm dứt và thực hiện chương trình được bật trở lại qua chính ().
Như bạn thấy, các chỉ dẫn đầu tiên được thực hiện là MOV ESP, EBP trong đó đặt giá trị của EBP trong ESP nên bây giờ chỉ để 0012FF6C, và hiệu quả loại bỏ biến c (aaaaaaaaaaa) từ ngăn xếp. Trên cùng của ngăn xếp bây giờ chứa EBP lưu:
Khi lệnh kế tiếp, POP EBP, được thực thi nó sẽ khôi phục lại con trỏ cơ sở ngăn xếp trước từ main () và tăng ESP 4. Con trỏ ngăn xếp tại điểm đến giá trị RETURN đặt trên stack ngay trước khi foo () được gọi. Khi hướng dẫn RETN được thực thi, nó sẽ đưa chương trình thực hiện dòng chảy trở lại các lệnh tiếp theo trong main () ngay sau khi CALL foo () hướng dẫn, như minh họa trong hình dưới đây.
Chức năng chính () sẽ thực hiện dọn dẹp riêng của mình bằng cách di chuyển con trỏ ngăn xếp xuống ngăn xếp (bằng cách tăng giá trị của mình bằng 4) và thanh toán bù trừ chồng argv [1]. Sau đó nó sẽ xóa đăng ký nó được sử dụng để lưu trữ argv [1] (EAX) thông qua một XOR, khôi phục lại EBP lưu lại, và quay trở lại địa chỉ trở lại lưu.
Đó nên là đủ của một đi bộ mặc dù hiểu làm thế nào một khung chức năng ngăn xếp được tạo / xóa và làm thế nào biến địa phương được lưu trữ trên stack. Nếu bạn muốn biết thêm ví dụ, tôi khuyến khích bạn kiểm tra một số các hướng dẫn tuyệt vời khác trên mạng (đặc biệt là những xuất bản bởi Corelan Team).
Kết luận
Đó là kết thúc của phần này đầu tiên trong dòng Windows Khai thác. Hy vọng rằng, bạn đang quen thuộc với việc sử dụng một trình gỡ lỗi, có thể nhận ra một số hướng dẫn cơ bản hội, và hiểu (ở mức cao) làm thế nào Windows quản lý bộ nhớ cũng như cách ngăn xếp hoạt động. Trong bài viết tiếp theo, chúng tôi sẽ nhận với cùng chức năng cơ bản foo () để giới thiệu các khái niệm về tràn ngăn xếp dựa trên. Sau đó tôi sẽ nhảy ngay vào viết một ví dụ thực tế khai thác tìm thấy cho một sản phẩm phần mềm dễ bị tổn thương thực sự.
Tôi hy vọng bài viết đầu tiên này đã được rõ ràng, chính xác và hữu ích. Nếu bạn có bất kỳ câu hỏi, ý kiến, chỉnh sửa, hoặc đề xuất cải tiến, xin vui lòng để lại cho tôi một số thông tin phản hồi trong phần nhận xét.
0 nhận xét:
Đăng nhận xét