2012-04-19 49 views
5

Hôm nay tôi quyết định dịch ngược chương trình "Hello world" đơn giản được viết bằng hình ảnh C++, sử dụng IDA Pro.Kỹ thuật đảo ngược C++

Với kiến ​​thức trước đây của tôi, tôi chắc chắn tôi sẽ không tìm thấy lệnh gọi printf ngay tại điểm vào thực thi và tôi đã đúng. Tôi tìm thấy rất nhiều mã không được viết bởi tôi và được trình biên dịch thêm vào trong quá trình biên dịch.

Tôi muốn hiểu rõ hơn về mã nào được thêm vào trong quá trình biên dịch. Nó làm gì? Có bất kỳ "thủ thuật" nào để nhanh chóng tìm "chính" và bỏ qua tất cả các mã không cần thiết được tạo ra bằng cách tháo gỡ không?

Điều tốt nhất tôi có thể tìm được trong bài viết này: http://www.codeproject.com/Articles/4210/C-Reverse-Disassembly, nói thứ tự thực hiện của một thực thi biên soạn sử dụng Visual C++ như sau:

  1. CrtlStartUp

  2. chính

  3. CrtlCleanUp

Tôi có thể lấy câu trả lời chi tiết hơn không?

+5

Trình biên dịch và nền tảng cụ thể. Tôi nghi ngờ bạn sẽ nhận được câu trả lời chính xác mà bạn muốn. – Matt

+1

Tôi khuyên bạn nên [bài đăng này] (http://stackoverflow.com/a/9952374/176769) làm lộ trình cho bất kỳ người kỹ sư đảo ngược-guru-wannabe nào. – karlphillip

+1

Tôi không có kinh nghiệm trong kỹ thuật đảo ngược, nhưng bạn không thể chỉ cần thiết lập một điểm ngắt trình gỡ lỗi ở đầu của chính để có được địa chỉ tương đối? Hoặc, cách khác, tìm kiếm chính trong một kết xuất đối tượng của tập tin thực thi? – bjhend

Trả lời

4

Có nhiều thứ khác nhau được yêu cầu theo tiêu chuẩn C++ mà bạn có thể gặp phải.

Quan trọng nhất là cần có mã xử lý bất kỳ số liệu thống kê nào trong đơn vị dịch chính trước khi gọi chính và chức năng sau lá chính xử lý sự hủy diệt của chúng. Ngoài ra, tiêu chuẩn yêu cầu một hàm atexit cho phép bạn đăng ký các hàm bổ sung được gọi sau khi trả về chính.

Vì vậy, ở mức tối thiểu, mã khởi động cần có khả năng tạo cấu trúc dữ liệu này của các hàm sẽ được gọi khi trả về từ chính. Đây là một cấu trúc dữ liệu động bởi vì nó cần được thêm vào thời gian chạy bởi chương trình, và thứ tự các cuộc gọi ngược lại với việc đăng ký (vì vậy thông thường bạn muốn có một cấu trúc dữ liệu bổ sung cho nơi bạn đi bộ một cách dễ dàng).

Nhưng ngoài ra, tiêu chuẩn yêu cầu rằng các số liệu thống kê trong các đơn vị dịch thuật khác được tạo trước khi thực hiện bất kỳ chức năng nào trong đơn vị dịch đó. Thông thường, các trình biên dịch sẽ đơn giản sắp xếp mọi thứ trong trình liên kết để mọi thứ được gọi trước chính, nhưng điều đó không bắt buộc. Những trình biên dịch đó làm những việc khác nhau, sau đó cần phải cung cấp các thói quen khởi tạo trong các mã đơn vị dịch thuật khác được liên kết mà sẽ được gọi vào cuộc gọi hàm đầu tiên.

Đây chỉ là một chút công việc nếu bạn sử dụng bất kỳ thư viện chuẩn nào. Hãy nhớ rằng, std :: cout là một đối tượng tĩnh (static lifetime, không liên kết tĩnh - confusingly overloaded alert alert). Vì vậy, điều đó có nghĩa là xây dựng thông tin liên lạc đến giao diện điều khiển của bạn, sẽ có bất kỳ API nào cần thiết bởi nền tảng của bạn được gọi. Có nhiều đối tượng như vậy trong tiêu chuẩn.

Và sau đó, có thể có nội dung cụ thể cho nền tảng và/hoặc trình biên dịch của bạn chuẩn bị quy trình theo cách hữu ích hoặc phân tích biến môi trường hoặc tải thư viện động/thư viện "chuẩn" hoặc nội dung tương tự.

Thông thường, lối ra chỉ là đi bộ danh sách đó và bằng cách nào đó cung cấp giá trị trả về chính cho môi trường, vì hầu hết các hệ điều hành hiện đại đều tự dọn dẹp, nhưng có thể có thêm hệ thống cụ thể.

2

Trình biên dịch ngày nay tạo ra các tệp thi hành lớn, vì vậy ngay cả khi bạn sẽ tìm thấy điểm vào, bạn sẽ mất một thời gian để hiểu và đi đến phần bạn thực sự cần.

Trong trường hợp của bạn với ứng dụng hello world, bạn có thể sử dụng IDA tìm điểm vào trong hộp thoại danh sách hàm (Tôi không nhớ tên chính xác). Nhưng một lần nữa tôi không khuyên bạn nên cách tiếp cận này, trừ khi ứng dụng là rất nhỏ.

Phương pháp Tôi đang sử dụng tôi gọi là "xuống để tiếp cận từ trên" (c)

Tôi sẽ bắt đầu từ việc phân tích hành vi hiện tại của ứng dụng mà không cần đến bất kỳ công cụ. Đó là bước rất quan trọng sẽ tiết kiệm rất nhiều thời gian vì bạn sẽ biết bạn đang tìm kiếm điều gì và khi nào điều đó xảy ra. Sau đó xác định "điểm yếu" như chuỗi, giá trị không đổi mà bạn có thể tìm thấy bằng công cụ phân tích tĩnh (IDA).

Bước tiếp theo là để tháo gỡ ứng dụng và tìm kiếm những "điểm yếu" (chuỗi mô-đun trong IDA) sau đó tìm tài liệu tham khảo đối với họ từ những gì các chức năng họ đã sử dụng (bạn có thể sử dụng chế độ phân cấp đồ họa trong phiên bản IDA mới)

Nếu bạn vẫn không thể nhận được nó hoạt động như thế nào hoặc mã này được gọi từ nhiều nơi bạn không biết bạn cần gì. Bạn có thể bắt đầu với phân tích thời gian chạy và sử dụng trình gỡ lỗi (softice? :)) như ollydbg. Điều này sẽ hiển thị cho bạn những thứ không hiển thị với phân tích tĩnh như hàm ảo/con trỏ hàm chẳng hạn: gọi EAX.

Sau đó, bạn chỉ cần xử lý từng bước cho đến khi bạn nhận được những gì bạn cần.

Các vấn đề liên quan