Vì sao khi cố xâm nhập vào kernel NT 3.1 thì máy 486DX4 của tôi lại khởi động lại?
(retrocomputing.stackexchange.com)- Trên Windows NT 3.1, khi dùng
i386kdđể break-in bằng Ctrl-C, hệ thống 486DX4 đích sẽ khởi động lại thay vì hiện dấu nhắckd>, và nguyên nhân là do vấn đề tương thích enhanced 486 KiSaveProcessorControlStatevàKiRestoreProcessorControlStatetrong NTOSKRNL.EXE dùng so sánh word khi kiểm tra loại CPU, nên nhận nhầm 486 có hỗ trợ CPUID là Pentium trở lênCpuTypevàCpuIDtrong KPRCB bị đọc cùng lúc, khiến số model của 486 hỗ trợ CPUID bị diễn giải lớn hơn 256, và kết quả là phát sinh truy cập vào thanh ghi CR4 vốn không tồn tại trên 486- Trên 486DX-33 nguyên bản và Am486DX4-NV8T write-through không có SMM, kernel debugging hoạt động bình thường, nên vấn đề được thu hẹp vào enhanced 486 có cung cấp lệnh CPUID
- Có thể sửa cả NT 3.1 Advanced Server nguyên bản và NT 3.1 SP3 bằng cách vá hai vị trí
cmp ds:word_FFDFF138, 5trong NTOSKRNL.EXE thành byte compare
Môi trường tái hiện và triệu chứng
- Đã cài Windows NT 3.1 lên Compaq ProSignia 3080 rồi thử kernel debugging
- Hệ thống này thực tế từng chạy Windows NT 3.1, và có vẻ là một trong những máy mà Windows NT nhắm tới rõ ràng
- RAM được nâng lên 128MB, và CPU Intel 486DX-33 dạng socket được thay bằng AMD enhanced 486DX4-SV8B
- CPU này hỗ trợ write-back cache và SMM, được gắn vào socket adapter điện áp
- Việc xử lý hỗ trợ 486DX4 trong BIOS được để lại sau, còn CPU được đặt jumper ở hệ số nhân 2x
- Với chipset không hỗ trợ L1 write-back mà đặt 2x, kỳ vọng là tương thích phần mềm với Intel 80486DX2-66
- Intel 80486DX2-66 là một tùy chọn được hỗ trợ trên hệ thống này
- Bản thân việc cài Windows NT 3.1 hoàn tất bình thường
- Đĩa CD Windows NT 3.1 có kèm đầy đủ symbol debug nên đã thử kernel debugging
- Mục đích là điều tra vì sao NetDDE ghi lỗi vào event log
- Cũng có vấn đề hệ thống bị crash với một số card Ethernet EISA nhất định, và vẫn còn khả năng lỗi phần cứng
- Phải dùng
i386kdđi kèm Windows NT 3.1 thay vìkdhayntkdtừ bộ công cụ phát triển Windows 10 mới hơn thì cấu hình kernel debugging mới khớp - Khi thử break-in bằng Ctrl-C trong
i386kd, máy đích khởi động lại thay vì đưa ra dấu nhắckd>
Những khả năng đã được loại trừ
- Bộ nhớ đã được xác nhận là bình thường
- Không phải do hỏng file hệ thống
- Không có watchdog phần cứng nào được bật để khởi động lại máy khi kernel dừng vì debugging
- USB-serial adapter phía máy host giao tiếp bình thường
- Thiết bị này có vẻ là PL2301 giả, nhưng không phải do gửi nhầm lệnh debugger thành lệnh “reboot system”
- Giao thức KD thực sự có lệnh reboot system
- Cũng không liên quan đến tùy chọn quản trị từ xa hay cảnh báo của mainboard
Nguyên nhân thực sự: enhanced 486 không tương thích với kernel NT 3.1
- Kernel Windows NT 3.1 không tương thích với bộ xử lý enhanced 486
- Cụ thể hơn, vấn đề xảy ra trên các CPU 486 có cung cấp lệnh
CPUID - Kernel debugging hoạt động bình thường trên các CPU sau
- 486DX-33 gốc ban đầu
- Am486DX4-NV8T write-through dùng core non-enhanced đời cũ, không có SMM
- Nếu chỉ muốn thử kernel debugging trên NT 3.1 thì nên dùng CPU vốn tương thích mặc định với Windows NT 3.1
- Nếu muốn sửa chính NT, cần vá lỗi nhận diện loại CPU trong NTOSKRNL.EXE
Đường đi mã kernel nơi lỗi phát sinh
- Nguyên nhân trực tiếp của sự không tương thích là lỗi trong
KiSaveProcessorControlState- Hàm đối ứng
KiRestoreProcessorControlStatecũng có lỗi tương tự
- Hàm đối ứng
KiSaveProcessorControlStateđược gọi ở ba vị trí trong NTOSKRNL.EXE- Khi một exception được phản ánh tới kernel debugger qua
KdpTrap- Với break-in Ctrl-C, một breakpoint exception xảy ra trong chức năng polling break-in bên trong timer tick interrupt
- Khi
KeBugCheckExđược gọi, tức là tình huống “màn hình xanh” - Khi
KiSaveProcessorStateđược gọi- Nếu phân tích control flow của NTOSKRNL.EXE bằng IDA là đầy đủ, hàm này không được export và cũng không được gọi ở đâu trong nội bộ NTOSKRNL, nên trên thực tế có vẻ không xảy ra
- Khi một exception được phản ánh tới kernel debugger qua
KiSaveProcessorControlStatelưu trạng thái điều khiển bộ xử lý vào cấu trúcCONTEXTmở rộng- Lưu CR0, CR2, CR3
- Trên Pentium trở lên thì lưu cả CR4
- Lưu các thanh ghi debug DR0~DR3, DR6, DR7
- Cả các thiết lập protected mode toàn cục như địa chỉ GDT, địa chỉ IDT, TSS selector đang hoạt động, và LDT selector
Lỗi diễn giải các trường KPRCB
- Việc xác định loại bộ xử lý dùng các giá trị trong KPRCB
- KPRCB là một phần của KPCR
- KPRCB của bộ xử lý khởi động hoặc hệ thống đơn xử lý nằm tại địa chỉ ảo
FFDFF120, và địa chỉ này được hardcode trong phương thức đó
- Theo tổng hợp của Geoff Chappell, các trường KPRCB liên quan trong NT 3.1 là:
+018 CHAR CpuType+019 CHAR CpuID+01A UShort CpuStep
- Các trường này được khởi tạo trong
KiSetProcessorType- Trên bộ xử lý 486, byte ở offset 18 được đặt thành 4
- Bộ xử lý Pentium được đặt thành 5
- Pentium Pro và Pentium II/III được đặt thành 6
- Byte ở offset 19 là cờ boolean cho biết bộ xử lý có hỗ trợ CPUID và hoạt động “hợp lý” hay không
- Lệnh so sánh gây vấn đề đọc word ở địa chỉ
FFDFF138thay vì byteFFDFF138là vị trí cách điểm bắt đầu KPRCB 18h byte- Vì vậy không chỉ
CpuTypemà cả byte kế tiếp làCpuIDcũng bị diễn giải chung như một phần của số model
- Các bộ xử lý hỗ trợ CPUID bị coi là có số model lớn hơn thực tế 256
- 80-4-86 có hỗ trợ CPUID bị Windows NT 3.1 coi như 80-260-86
- 260 lớn hơn rất nhiều so với mốc Pentium là 5, nên kernel kết luận rằng CPU đó phải có CR4
- Enhanced 486 không có CR4, vì vậy đường break-in phát sinh lỗi
Cách vá
- Sau khi xác nhận lỗi, cách sửa khá đơn giản
- Trong NTOSKRNL.EXE, lệnh
cmp ds:word_FFDFF138, 5chỉ xuất hiện đúng hai lầnKiSaveProcessorControlStateKiRestoreProcessorControlState
- Cả hai vị trí đều phải đổi word compare thành byte compare
- Dùng hex editor để vá chuỗi byte sau ở cả hai chỗ
- Cũ:
66 83 3D 38 F1 DF FF 05 - Mới:
90 80 3D 38 F1 DF FF 05
- Cũ:
- Bản sửa này áp dụng được cho cả NTOSKRNL.EXE của bản phân phối NT 3.1 Advanced Server nguyên bản và NT 3.1 SP3
1 bình luận
Các ý kiến trên Hacker News
Trước đây tôi từng làm một công cụ kiểm tra cổng để xem dịch vụ còn sống không, và chỉ bằng cách mở vài cổng TCP trên các máy, tôi đã làm chết một nửa công ty
Đó là một thời kỳ thật vô lý
Chúng ta đã đi được một chặng đường rất xa
https://en.wikipedia.org/wiki/Ping_of_death
Một số máy còn có lỗ hổng SMB không được vá trong nhiều năm. Đó đã là thời có Metasploit, nên chỉ với vài lệnh là có thể tiêm VNC vào hầu hết các máy Windows trong mạng nội bộ. Ngày nay, ít nhất tốc độ vá lỗi đã nhanh hơn rất nhiều
À, cái hang thỏ của retro computing. Nó được tách biệt một cách vô hại khỏi các hệ quả trong thế giới thực, nhưng vẫn cực kỳ thỏa mãn
Đúng là một cái bẫy mật cho dân geek. Cuối cùng tôi vẫn bấm nút mở rộng “xem thêm 6 bình luận”
Có lẽ hôm nay tôi vẫn làm được chút việc
Nhưng 486 ư? Nó gợi lại quá nhiều ký ức về màn hình xanh và những lần chờ đợi vô tận vì máy không gánh nổi bộ nhớ nên phải swap ra đĩa. Có vẻ với tôi vẫn còn quá sớm
Câu “giải pháp thì hiển nhiên” thật sự rất đúng
Có lẽ là cứ đọc disassembly của mã trap cho đến khi phát hiện ra vấn đề. Tôi không nghĩ khi đó có thể dùng QEMU hay phương tiện debug nào khác
Nhất định phải đọc cả cách làm bị chôn trong phần bình luận bị ẩn ở cuối
Nó không phải là ẩn bình luận có ít phiếu nhất, cũng không phải ẩn theo mới nhất hay cũ nhất. Nó có cảm giác ngẫu nhiên và không cần thiết
Nếu vấn đề là không gian, tôi nghĩ nên dùng phân trang thay vì ẩn đi
Những thứ như adapter slotket từng được dùng để tương thích trên các bo mạch Abit, Asus cũ, và có lẽ cả MSI, thật sự có khả năng ép xung
Mấu chốt là tốc độ RAM là bao nhiêu và bo mạch chủ chịu được xung đến mức nào ở thiết lập hệ số nhân. Đó là thời kỳ ép xung tương đối sơ khai, thời của Celeron và Pentium II
Có lúc vì lý do tương thích, tôi cắm một con Celeron 600 vào adapter, rồi lại cắm vào adapter Slot II sang Socket 370, chạy ổn ở 1.2GHz với cấu hình kiểu [1]. Thậm chí hình như tôi còn đẩy lên 1.4GHz trên Windows ME, và cuối cùng đã đốt cháy con CPU đó
[1]http://krick.3feetunder.com/370mod/
Câu trả lời cho câu hỏi đó thật sự xuất sắc
Chủ đề hay, câu trả lời cũng rất hay
Thật tuyệt khi người đặt câu hỏi tự đăng cả câu trả lời
Tôi thích những thứ như thế này. Rất vui khi mọi người quan tâm đến retro computing
Việc ghi chép lại cả những vấn đề và giải pháp như thế này cho tất cả mọi người là một điều tốt
Tôi biết cái CPUID này là một ý tưởng tệ mà
Vì sao timestamp của câu hỏi và câu trả lời lại giống nhau?
Có lẽ họ cho rằng đăng thông tin này theo dạng hỏi đáp trên SO sẽ tồn tại lâu hơn một bài blog mà không ai tìm thấy
Có tệ không khi tôi biết nó là gì mà không cần mở ra?
Thôi được rồi, tôi phải đi hét với bọn trẻ thời nay rằng hãy ra khỏi bãi cỏ nhà tôi đây
Thứ có thể dựa vào chỉ là sự lanh trí, và nếu cần thì vài cao thủ có thể gọi bằng điện thoại cố định. Không có một Internet tuyệt vời đầy những câu trả lời hữu ích ở mức độ rất khác nhau như bây giờ