2011-01-31 18 views
7

Nếu bạn có một bộ mã Delphi sạch và tất cả các chuỗi được tạo bằng TThread, bạn có thể đặt điểm ngắt trong phương thức khởi tạo (TThread.Create) và tìm ra ai đã tạo chủ đề của bạn. Bạn thậm chí có thể cố gắng đặt tên cho tất cả các chủ đề của mình bằng cách sử dụng tính năng được tích hợp trong đối tượng Delphi TThread cho phép bạn đặt tên gỡ lỗi cho mỗi chuỗi. Tuy nhiên, làm thế nào để bạn xác định các chuỗi phụ liên tục, khó tìm, vẫn còn ẩn danh (không có tên gỡ lỗi) và xuất hiện, ví dụ, trong thời gian khởi tạo mô-đun, khi ứng dụng bắt đầu. Quay lại đầu trang Tôi có thể thực hiện một bước thông qua việc khởi tạo mô-đun, nhưng tôi không thể xác định tất cả các mô-đun nguồn (giả sử, 900+ phần khởi tạo mô-đun được thực hiện) có khả năng tạo chủ đề và tôi đã không tìm ra cách thêm một thông báo gỡ lỗi (sử dụng các thuộc tính breakpoint và các thông báo) sẽ đổ từng tên đơn vị trong khi nó khởi tạo. Việc sử dụng sáng tạo các điểm ngắt được thiết lập trong System.pas, với các thông điệp ghi nhật ký cho phép tôi thực hiện một số việc khi gỡ lỗi các ứng dụng đơn giản, nhưng ứng dụng càng phức tạp, tôi càng cảm thấy bị mù bởi các chủ đề, cả hai đều được tạo ra ở giữa của một ứng dụng chạy, và những ứng dụng được tạo tại thời điểm mô đun-init (đó là trước khi bạn bước vào dòng đầu tiên của mã trong dự án dpr của bạn).Làm thế nào bạn có thể tìm ra ai tạo ra tất cả các chủ đề của bạn trong một chương trình delphi?

Tôi muốn biết bạn có thể tìm thấy những kỹ thuật nâng cao nào để xác định và tìm ra ai đã tạo một chuỗi cụ thể. Nếu chúng ta đang sử dụng một trình gỡ lỗi như GDB thay vì một trình gỡ rối như hạt nhân trình gỡ lỗi delphi (Turbo Debugger?) Được tích hợp vào IDE delphi, tôi nghĩ chúng ta có thể thiết lập một điểm ngắt trên một hàm api của cửa sổ như BeginThread. Nhưng tôi không nghĩ rằng tôi có thể làm điều đó ở Delphi.

Cập nhật: Tôi không biết bạn có thể đặt điểm ngắt trong phần triển khai của windows.pas cho các dll cửa sổ bên ngoài như kernel32.dll.

Cập nhật 2: Có vẻ như câu trả lời của David H là ý tưởng tốt nhất để sử dụng chung. Tôi cũng đang tìm kiếm một thư viện mã trợ giúp nhỏ mà tôi đang viết ngay bây giờ để duy trì một từ điển các id luồng đã được nhìn thấy trước đó, và gán một số tên gỡ lỗi cho các chủ đề không được đặt tên khác, dựa trên thời gian tạo của chúng. chúng tôi đã gọi ngay trước khi chúng tôi nhận thấy chuỗi mới tồn tại). Tôi nghĩ rằng điều này sẽ giúp tôi thu hẹp 40 chủ đề được đánh số để tất cả chúng được đặt tên, mặc dù một số chúng được tạo trong các tệp C/C++ bên ngoài hoặc bằng các quy trình COM.

+0

Để biết thông tin, kernel32 không phải là một phần của hạt nhân. Tôi biết điều này là khó hiểu. Hạt nhân Windows nằm trong ntoskrnl.exe. kernel32 là một DLL chế độ người dùng, mặc dù tôi chắc chắn nó chuyển công việc sang chế độ hạt nhân cho nhiều chức năng của nó. Bạn chắc chắn không thể gỡ lỗi mã chế độ hạt nhân với trình gỡ lỗi Delphi –

+0

Tôi thực sự biết rằng một nơi nào đó ở phía sau đầu của tôi. Nhưng để được ít cẩu thả tôi đã sửa chữa Cập nhật của tôi. –

+0

Tôi nhận thấy một chuỗi được tạo bởi một số cuộc gọi COM CoInitializeSecurity. Tôi hơi ngạc nhiên bởi điều đó. –

Trả lời

9

Tôi có thể xem xét sử dụng các công cụ như Process ExplorermadExcept, nhưng có rất nhiều công cụ xung quanh có thể hữu ích.

Tôi không tin rằng Delphi sử dụng Turbo Debugger. Delphi là gì hoàn toàn có khả năng thiết lập các điểm phá vỡ trên các điểm nhập kernel32 như CreateThread.

Tôi sẽ chạy với Debug DCUs được bật và đặt điểm ngắt khi triển khai CreateThread trong Windows.pas. Một khi bạn phá vỡ có chuyển sang cửa sổ CPU và bước vào thói quen. Bạn sẽ thấy hướng dẫn JMP DWORD PTR [address]. Bước qua này và hey mau, bây giờ bạn đang gỡ lỗi trong kernel32. Bạn có thể đặt điểm ngắt tại đây.

Bây giờ nếu bạn đặt lại ứng dụng và bắt đầu gỡ lỗi lần nữa, bạn sẽ ngắt tất cả các cuộc gọi đến kernel32.CreateThread bắt nguồn từ quá trình của bạn. Kiểm tra ngăn xếp cuộc gọi sẽ cho bạn biết cách bạn đến đó. Nó trông giống như sau:

enter image description here

Cuối cùng, tôi không chắc chắn lý do tại sao bạn đang gặp rắc rối bởi ứng dụng của bạn tạo ra chủ đề. Hầu hết các ứng dụng có kích thước phù hợp tạo nhiều chủ đề - điều đó hoàn toàn bình thường để làm như vậy. Bạn đang gặp phải vấn đề gì?

+0

Cool. tôi không có ý tưởng bạn có thể làm điều đó! –

+0

+1. Thủ thuật rất hay. –

+0

@Mason Cảm ơn. Tôi nghĩ mọi người đều biết điều này! Delphi debugger chắc chắn là tốt hơn mỗi bản phát hành. –

6

... Tôi nghĩ chúng tôi có thể đặt điểm ngắt trên chức năng api của cửa sổ như BeginThread. Nhưng tôi không nghĩ rằng tôi có thể làm điều đó ở Delphi.

Chắc chắn bạn có thể.

  • Bật dự án, tùy chọn, trình biên dịch Delphi, biên dịch, gỡ lỗi, sử dụng gỡ lỗi .dcus. (Đó là cách để tìm thấy nó trong Delphi XE, vị trí chính xác có thể khác nhau trong các phiên bản Delphi khác nhau).

  • Biên dịch lại.

  • Mở đơn vị Hệ thống và đặt điểm ngắt trên Kết quả: = CreateThread ... trong hàm BeginThread.

  • Chạy chương trình và chờ cho đến khi điểm ngắt được kích hoạt.

  • Cửa sổ CPU mở (Xem, Gỡ lỗi Windows, Cửa sổ CPU, Toàn bộ CPU).

cửa sổ CPU sẽ hiển thị một cái gì đó như thế này:

System.pas.16559: Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P, 
00406A97 8B4508   mov eax,[ebp+$08] 
00406A9A 50    push eax 
00406A9B 8B450C   mov eax,[ebp+$0c] 
00406A9E 50    push eax 
00406A9F 53    push ebx 
00406AA0 B81C6A4000  mov eax,$00406a1c 
00406AA5 50    push eax 
00406AA6 8B45F8   mov eax,[ebp-$08] 
00406AA9 50    push eax 
00406AAA 8B45FC   mov eax,[ebp-$04] 
00406AAD 50    push eax 
00406AAE E855BBFFFF  call CreateThread 
00406AB3 8BF0    mov esi,eax 
  • Bấm vào cửa sổ CPU trên dòng 'gọi CreateThread'.

  • Nhấn F4.

  • Nhấn F7.

Bạn sẽ được bố trí trong bảng công văn:

CreateThread: 
00402608 FF2594AA4F00  jmp dword ptr [$004faa94] 
0040260E 8BC0    mov eax,eax 
  • Nhấn F5 để đặt breakpoint ở đây.

  • Chạy lại chương trình (Ctrl-F2, F9).

Điểm ngắt sẽ được kích hoạt mỗi khi tạo chuỗi. Breakpoint sẽ xuất hiện để xảy ra trong WindowsAPIs.INC tại

function CreateThread(SecurityAttributes: Pointer; StackSize: LongWord; 
        ThreadFunc: TThreadFunc; Parameter: Pointer; 
        CreationFlags: LongWord; var ThreadId: LongWord): Integer; stdcall; 
    external kernel name 'CreateThread'; 

(ít nhất là trong Delphi XE).

Bạn may vẫn bỏ lỡ một số cuộc gọi tạo chủ đề. Tôi không biết nếu phương pháp này sẽ bắt chủ đề được tạo ra bởi Direct X, ví dụ.

+0

chỉ nhận các cuộc gọi đến CreateThread có nguồn gốc từ Delphi. Tôi muốn đi sâu hơn một cấp và đặt điểm ngắt trong kernel32 - sau đó bạn có thể nắm bắt các cuộc gọi từ các nguồn khác - ví dụ: Thư viện Win32/COM. Đó là những gì tôi đã cố gắng thể hiện trong câu trả lời của tôi, mặc dù bạn đã đi vào chi tiết hơn rất nhiều mà tôi đã làm! –

+0

Chà. Điều đó thậm chí còn chi tiết hơn. Yêu các chi tiết. –

+0

mà không bắt một số trong những người được tạo ra bởi (tôi nghĩ) DevExpress, và tôi nghi ngờ nó bỏ lỡ tất cả những người tạo ra thông qua COM. Nhưng nó bắt tất cả mọi thứ có sử dụng mã Delphi để tạo ra chúng, vì vậy bạn có được tất cả mọi thứ bạn có thể làm bất cứ điều gì hữu ích với. –

1

Thực ra BeginThread là một hàm trong System.pas, mặc dù là một hàm "riêng" (không có khai báo hàm trong phần giao diện). Vì vậy, bằng cách sử dụng debug của dcu bạn chỉ có thể thiết lập một breakpoint trong hàm BeginThread và kiểm tra stack trace từ đó.

Một tùy chọn khác là móc hàm BeginThread sử dụng madCodeHook hoặc KBSM (IIRC).Bên trong hàm hooking, bạn có thể sử dụng một cái gì đó như:

UseOurStuff := Assigned(Parameter) and IsInstanceOfType(Parameter, TThread); 
    if Assigned(Parameter) then 
    if UseOurStuff then 
     ThreadClassName := Instance.ClassName 
    else 
     ThreadClassName := 'Non-object Parameter thread' 
    else 
    ThreadClassName := 'NIL Parameter thread'; 

để bạn có thể ghi lại tất cả các chuỗi được tạo, bất kể chúng đến từ đâu. Những người duy nhất bạn đang bỏ lỡ là các chủ đề được tạo ra bằng cách gọi trực tiếp API Windows CreateThread. Nhưng bạn có thể sử dụng cùng một kỹ thuật hooking để có được bàn tay của bạn trên những cuộc gọi.

Cập nhật

Oh, IsInstanceOfType là một trong những chức năng thư viện của chúng tôi nhưng nó về cơ bản có một con trỏ không định kiểu và kiểm tra xem nếu nó tham chiếu một đối tượng của nhóm nhất định.

+0

Không cần phải móc, chỉ cần thiết lập một điểm ngắt trong kernel32! –

+0

Hooking có thể hữu ích, nhưng trong trường hợp của tôi, câu trả lời của David đơn giản hơn. –

+0

@David: nếu bạn chỉ muốn làm điều đó một lần, tôi đồng ý. Nếu bạn quan tâm đến việc tạo thread/hủy diệt như là một vấn đề của khóa học (đăng nhập/trực tiếp moinitoring của một ứng dụng), bạn cần móc. @ Warren có lẽ chỉ cần nó một lần, nhưng khi bạn thêm hoặc chuyển đổi các thành phần, có mã hooking tại chỗ, có thể dễ dàng hơn rất nhiều nếu bạn kết hợp đó với một số đăng nhập. –

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