Bắt đầu với Trình gỡ lỗi GNU trên Linux: Khóa học cấp tốc
Gỡ lỗi là một kỹ năng không thể thiếu đối với các lập trình viên và nhà nghiên cứu bảo mật. Nắm vững cách gỡ lỗi cho phép bạn hiểu tệp thực thi ở cấp độ thấp hơn và nắm bắt mọi lỗi tiềm ẩn.
Trình gỡ lỗi GNU, thường được gọi là GDB, là một tiện ích gỡ lỗi lâu dài đã được các nhà phát triển tin cậy và sử dụng theo thời gian. Trong phần này, chúng ta sẽ khám phá ứng dụng của nó trong bối cảnh hệ thống Linux.
Chuẩn bị chương trình mẫu
Để đi sâu vào các khả năng của GDB, cần phải kiểm tra nó bằng cách sử dụng một tệp thực thi có mã nguồn và biểu tượng gỡ lỗi có thể truy cập được để kiểm tra. Để làm ví dụ minh họa, chúng tôi sẽ chạy GDB trên hai chương trình riêng biệt-một ứng dụng kiểm tra khóa và một chương trình đa luồng hiển thị các thông báo trên màn hình-một chương trình được phát triển bằng C và tuân thủ bằng cách sử dụng Trình biên dịch GNU C, trong khi chương trình kia thiếu mã nguồn của nó.
Bạn có tùy chọn sử dụng bất kỳ trình biên dịch C thay thế nào, miễn là bạn không xóa siêu dữ liệu của tệp thực thi có chứa thông tin về nguồn gốc của chương trình và các sửa đổi được thực hiện trong quá trình biên dịch.
Để sử dụng GDB một cách hiệu quả, rất có thể bạn sẽ sử dụng nó trên các ứng dụng của riêng mình. Do đó, điều cần thiết là phải đảm bảo rằng các chương trình này được biên dịch bằng cờ -g
với gcc
, cho phép bao gồm các ký hiệu gỡ lỗi.
Thật vậy, khi không có biểu tượng gỡ lỗi và mã nhị phân đã được giảm thiểu đáng kể, người ta phải đi sâu vào mã đã được phổ biến của ứng dụng. Nỗ lực như vậy đòi hỏi sự hiểu biết thành thạo về hợp ngữ và sự hiểu biết phức tạp về cơ chế phân bổ bộ nhớ trong hệ điều hành Linux, cũng như việc giải thích dữ liệu được lưu trữ trong ngăn xếp và các thanh ghi.
Chạy một chương trình trong GDB
Ngoài ra, bạn cũng có thể chọn khởi chạy Trình gỡ lỗi GNU bằng cách nhập “gdb”, theo sau là các đối số dòng lệnh mong muốn, sau đó sẽ dẫn bạn đến mục nhập nhắc nhở cho tệp nhị phân đích cụ thể cần gỡ lỗi. Sau khi tải xong, bạn có thể tiến hành thực thi chương trình bằng cách nhập lệnh “run” hoặc chỉ cần sử dụng các phím tắt như “r”.
Để một chương trình hoạt động chính xác khi yêu cầu các đối số dòng lệnh, điều cần thiết là phải thêm chúng vào sau tiêu đề chương trình khi gọi. Cấu trúc ngữ pháp được Trình gỡ lỗi GNU (GDB) sử dụng để tải lên và thực thi một ứng dụng cùng với các đối số của nó có thể được tóm tắt như sau:
gdb <program>
run <args>
Hoặc:
gdb
file <program>
run <args>
Đặt điểm dừng với GDB
Điểm dừng, là sự gián đoạn có chủ ý trong luồng thực thi trong quá trình gỡ lỗi, đóng vai trò là điểm dừng được xác định trước trong mã. Bằng cách đặt các điểm đánh dấu này một cách chiến lược, các nhà phát triển có thể tạm dừng quá trình phát triển chương trình của họ tại các thời điểm cụ thể và xem xét kỹ lưỡng các tác động lên cả dữ liệu và các biến số khi mỗi giai đoạn diễn ra.
Khi sử dụng Trình gỡ lỗi GNU (GDB) để gỡ lỗi một ứng dụng phần mềm có chứa các ký hiệu gỡ lỗi, người ta có thể chọn hai phương pháp đặt điểm dừng. Chúng bao gồm việc chỉ định điểm dừng bằng cách sử dụng tiêu đề của một hàm cụ thể hoặc chỉ định điểm dừng dựa trên số dòng cụ thể trong mã. Cú pháp tương ứng như sau:
break main
break 47
Để truy cập danh sách đầy đủ các điểm ngắt hiện đang hoạt động trong phiên gỡ lỗi này, vui lòng nhập lệnh sau:
info breakpoints
Để xóa một điểm dừng cụ thể hoặc tất cả các điểm dừng hiện tại trong mã của bạn, bạn có thể sử dụng lệnh “xóa” (nếu xóa một điểm) hoặc đơn giản là “xóa” (để loại bỏ tất cả).
delete 2
delete 3-5
GDB cung cấp khả năng thiết lập các điểm dừng có điều kiện, đòi hỏi phải đáp ứng một điều kiện cụ thể để chương trình tạm dừng trong quá trình thực thi. Điều kiện này có thể liên quan đến những thay đổi về giá trị của một biến, một lệnh gọi hàm không hiệu quả hoặc bất kỳ tiêu chí nào khác mà bạn muốn. Dưới đây trình bày cú pháp được sử dụng để chỉ định các điểm dừng có điều kiện:
break <location> if n == 2
Nếu bạn muốn tiếp tục hoạt động của chương trình khi gặp điểm ngắt, vui lòng nhập lệnh “tiếp tục”.
continue
Bước qua mã
Việc kiểm tra việc thực thi các chương trình máy tính theo từng dòng là điều cần thiết để hiểu được hoạt động của chúng trên thông tin. Bằng cách duyệt qua nhiều chức năng trong phần mềm và xem xét kỹ lưỡng tình trạng của dữ liệu, người ta có thể đạt được cái nhìn sâu sắc hơn về cách hệ thống thực hiện các nguyên tắc được mã hóa trong mã nguồn của nó.
Phần mềm cho phép phân tích toàn diện các lỗi hệ thống bằng cách xác định chính xác nguồn gốc của chúng, đồng thời cung cấp khả năng kiểm tra chuyên sâu về chức năng của chương trình thông qua việc kiểm soát chính xác từng dòng mã. Quá trình thực hiện tuần tự từng dòng có thể đạt được bằng ba phương pháp riêng biệt trong công cụ gỡ lỗi được gọi là GDB.
Lệnh nói trên hướng dẫn Trình gỡ lỗi GNU (GDB) tiếp tục với các dòng tiếp theo của tệp nguồn tương ứng, từ đó cho phép truyền tải toàn diện cơ sở mã trên cơ sở riêng lẻ.
Lệnh “tiếp theo” trong REPL của Pycharm cho phép thực thi các dòng mã tiếp theo trong hàm hiện đang hoạt động, sau đó quá trình thực thi sẽ dừng lại. Không giống như lệnh “step”, hoạt động theo các lệnh hoặc câu lệnh riêng lẻ, “next” coi toàn bộ chức năng là một khối mã liên tục, do đó cho phép người dùng thực thi qua nhiều dòng mà không bị gián đoạn.
Lệnh finish
hoàn thành việc thực thi bất kỳ khối mã còn tồn đọng nào còn lại trong hàm hiện tại một cách hiệu quả, sau đó là dừng quy trình.
Kiểm tra các biến
Để phân tích sự thay đổi logic chương trình bằng cách kiểm tra các giá trị biến trong quá trình thực thi chương trình bằng GDB, người ta có thể sử dụng cú pháp sau để hiển thị giá trị hiện tại của các biến cụ thể trong môi trường gỡ lỗi:
print <variable>
Để thể hiện những sửa đổi được thực hiện đối với giá trị của một biến cụ thể tại mỗi lần lặp trong vòng lặp, người ta có thể sử dụng lệnh “hiển thị”. Cách tiếp cận như vậy có thể đặc biệt có lợi cho việc theo dõi và ghi lại tiến trình của giá trị của biến nói trên trong quá trình lặp lại của nó.
display <variable>
Đặt điểm quan sát
Điểm giám sát và điểm dừng có điều kiện có liên quan với nhau ở chỗ cả hai đều phản ứng với những thay đổi trong chương trình. Cụ thể, các điểm giám sát dùng để giám sát các sửa đổi dữ liệu xảy ra trong mã nguồn. Để minh họa, người ta có thể mong muốn phần mềm tạm dừng khi nội dung của một biến cụ thể có bất kỳ thay đổi nào. Quá trình triển khai chức năng này bằng GDB được trình bày chi tiết bên dưới:
watch <variable_name>
Gỡ lỗi theo chủ đề cụ thể với GDB
Bằng cách sử dụng trình gỡ lỗi GDB, có thể tiến hành các hoạt động gỡ lỗi trên từng luồng riêng lẻ trong các ứng dụng đa luồng. Để làm ví dụ minh họa, hãy xem xét một chương trình C ngắn gọn sử dụng nhiều luồng để tạo ra các thông báo được in.
Để có được thông tin liên quan đến các luồng đang hoạt động trong ứng dụng của bạn, hãy sử dụng lệnh “thông tin”, theo sau là một dòng trống.
info threads
Để truy cập và tương tác với một luồng cụ thể trong danh sách, người ta có thể sử dụng vị trí số hoặc chỉ mục của nó trong mảng các tùy chọn có sẵn. Điều này cho phép lựa chọn và thao tác với luồng mong muốn dựa trên mã định danh được chỉ định của nó.
thread 2
Khi chọn một luồng cụ thể, người ta có thể duyệt dần dần trình tự thực thi của nó bằng cách sử dụng các lệnh bước “bước”, “tiếp theo” và “kết thúc” như minh họa trước đó.
Gỡ lỗi từ xa với GDB
Để gỡ lỗi từ xa các ứng dụng phần mềm được lưu trữ trên thiết bị khác, người ta phải định cấu hình gdbserver trên máy tính mục tiêu. Quá trình này có thể được thực hiện bằng cách sử dụng công cụ quản lý gói được cài đặt sẵn trong hệ điều hành của bạn hoặc sử dụng bất kỳ trình quản lý gói bổ sung nào đã được cài đặt trên hệ thống của bạn.
Để cài đặt gdbserver trên hệ thống sử dụng Ubuntu hoặc Debian làm nền tảng, người ta có thể sử dụng Công cụ gói nâng cao (APT) cho mục đích này.
sudo apt install gdbserver
Khi thực hiện quá trình cài đặt, hãy điều hướng đến thư mục chứa tệp nhị phân và thực thi một lệnh cụ thể trong vị trí đó để bắt đầu vận hành chương trình gdbserver.
gdbserver <ip>:<port> <binary>
Ứng dụng “gdbserver” dự kiến sẽ hiển thị thông báo cho biết ứng dụng đã khởi động và đang tích cực lắng nghe các kết nối đến trên cổng được chỉ định. Sau đó, trên một thiết bị khác, khởi tạo một phiên bản của phần mềm “GDB” và thiết lập kết nối với máy chủ ở xa bằng cách sử dụng lệnh “đích”, sau đó là chỉ định cụ thể cho đối tượng điều tra dự định.
target remote <server_ip>:<port>
Viết tập lệnh GDB để tự động gỡ lỗi
Việc sử dụng tập lệnh GDB cho phép các nhà phát triển thực hiện lặp lại các lệnh GDB được xác định trước một cách dễ dàng. Do đó, điều này hợp lý hóa quá trình gỡ lỗi bằng cách loại bỏ nhu cầu thực hiện các tác vụ lặp đi lặp lại như đặt điểm dừng, điều hướng thực thi mã và in dữ liệu biến đổi. Bằng cách tận dụng các tập lệnh này, nhà phát triển có thể tự động hóa một loạt hành động tẻ nhạt, từ đó nâng cao năng suất của họ trong khi gỡ lỗi các phần mã cụ thể.
Đây là một ví dụ:
set logging enabled on
set logging file sample.out
break main
command 1
backtrace
print N
continue
end
quit
Trong đoạn mã được cung cấp, có hướng dẫn rằng công cụ gỡ lỗi GDB phải kích hoạt chức năng ghi nhật ký của nó và lưu trữ nhật ký kết quả trong một tệp có tên “sample.out”. Ngoài ra, một điểm gián đoạn được chỉ định trong chức năng chính của chương trình.
Để thực thi điểm dừng một, nằm ở đầu hàm’chính’, vui lòng làm theo các bước sau bằng Trình gỡ lỗi GNU (GDB): Trước tiên, hãy bắt đầu quay lại bằng cách nhập lệnh’backtrace’. Thứ hai, hiển thị giá trị của biến ‘N’ với lệnh ‘print N’. Thứ ba, tiến hành thực hiện chương trình bằng cách gõ’tiếp tục’. Trình gỡ lỗi ban đầu sẽ tiến hành dò ngược để xác định trạng thái hiện tại của luồng chương trình. Sau đó, nó sẽ thể hiện giá trị của biến’N’. Sau đó, nó sẽ tiếp tục quá trình thực hiện. Cuối cùng, khi tất cả thông tin liên quan đã được hiển thị, GDB sẽ chấm dứt hoạt động một cách nhẹ nhàng.
Để thực thi tập lệnh này, hãy sử dụng:
gdb -x <script> <binary>
Bây giờ bạn đã biết cách gỡ lỗi chương trình của mình bằng GDB!
Gỡ lỗi là một kỹ năng quan trọng và việc nắm vững cách sử dụng GDB cho mục đích gỡ lỗi sẽ nâng cao đáng kể tính linh hoạt của một nhà phát triển. Các chức năng khác nhau do GDB cung cấp như điều hướng từng bước thông qua mã, đặt điểm dừng, gỡ lỗi luồng được nhắm mục tiêu và các chức năng khác khiến nó trở thành một công cụ mạnh mẽ khi kiểm tra các tệp nhị phân trong môi trường hệ điều hành Linux.
Đối với những người muốn phân tích và khắc phục sự cố các chương trình phần mềm trong hệ điều hành Windows, việc khám phá thêm kiến thức về Windbg, một công cụ gỡ lỗi tích hợp sẵn cho Windows, có thể được coi là một lựa chọn đáng xem xét.