首页
社区
课程
招聘
[翻译]Inline Hook IoGetDeviceObjectPointer Routine
2008-10-3 10:08 6084

[翻译]Inline Hook IoGetDeviceObjectPointer Routine

2008-10-3 10:08
6084
代码作者我不记得是谁了,其实我也是在Debugman上随便Download 的code,来读并且学习的,相信会有人认出来的。菜菜的我,还不会写Inline Hook,希望在不久的将来可以有自己的原创啊。

希望Code作者以后不要使用n个单词的缩写组合在一起来命名标识符了,天才知道那是什么呢!我的生活、理想、习惯、内心都在不断的变化着,希望是向好的方向变化,而不是。。。

这是Inline Hook 的c Language Source Code。Inline Hook将改写函数头部n字节,以跳到y函数执行。另外该Code中有许多函数调用我没有查到,或者是逻辑语法我不理解,完全凭借笔者来猜测,如果猜测错误还请牛牛客气的指正。

PatchCommonDispatch Routine 用于处理IRP_MJ_XX,但是不包括IRP_MJ_DEVICE_CONTROL。分发函数的头部是固定的,2个参数分别是DEVICE_OBJECT的指针与Irp的指针。

在PatchCommonDispatch Routine中首先设置Irp结构的成员IoStatus.Status=STATUS_SUCCESS,然后在调用IoCompleteRequest函数来完成这个Irp请求,这时Irp将返回I/O管理器。最后PatchCommonDispatch Routine在返回STATUS_SUCCESS。

当前Code中非常重要的函数是tPatchDeviceControl,这个函数将处理IRP_MJ_DEVICE_CONTROL。这个函数首先通过调用IoGetCurrentIrpStackLocation Routine来获得Irp在设备栈中的结构地址。

Code作者定义的结构patch_info将保存被Hook 函数的相关信息,比如地址、长度、新函数地址、字节等。

通过判断Irp成员Parameters.DeviceIoControl.IoControlCode来决定如何来处理这个Irp,具体代表什么含义我还不清楚,呵呵。

在GetKernelFuncAddr Routine中关键的一条语句就是MmGetSystemRoutineAddress(),这个函数将获得函数地址,并且通过GetKernelFuncAddr()返回给调用者。

由于,我这里没有发现ade32.h 所以有些结构与函数我这里无法看到实现,也就没法看到完整的过程
真是可惜啊...

=======================Source COde=========================

//Include Head File
#include <ntddk.h>
#include "ade32.h" //The Is User Define Head File

//宏定义
//KERNEL_SEG == KERNEL_SEGMENT ?
#define KERNEL_SEG 0x0008

typedef void (*DBGPRINT)(); //The Type Is What

//Data Structure Define
typedef struct patch_info
{
//4个Member
int patch_len;
    BYTE org_bytes[32];
    PVOID org_func_addr;
    PVOID new_func_addr;
}PATCH_INFO,*PPATCH_INFO;

//声明全局变量

//ULONG == unsigned long ?
//The Variable Is What
ULONG g_uCr0=0;

//UNICODE_STRING Is a Kernel Structure
//Length Member Is Zero
UNICODE_STRING ObjPtrName={0};

//DBGPRINT Is User Define Type
//NULL == 0
DBGPRINT MyDbgPrint=NULL;

//The Routine Not Return Value
void WPOFF()
{
//Routine Body

//Local Variable
//ULONG == unsigned long
//uAttr前缀u是匈牙利命名写法,表示类型为ULONG
ULONG uAttr;
   
//嵌入Asm Code
//asm前缀是2个_还是1个下线,区别在于是嵌入一个语句块还是一条语句 ?
    __asm
    {
   ;The Is Assembly Comment Style
        
   ;eax As Save Routine Call Parameter
   ;Value Of eax Come Stack
   ;The Is Once Value Copy To Current Stack Top
   push eax;
        
   ;cr0 Is What
   ;Value Of cr0 To eax For Save
   ;Pass Over eax Value
   mov eax,cr0;
        
   ;uAttr Is ULONG Type Variable
   ;Value Of eax To uAttr For Save
   ;The Is Once Value Copy
   mov uAttr,eax;

   ;CR0 16 BIT =ro
   ;eax=eax&&0fffeffffh
   ;The Is What
        and eax,0FFFEFFFFh;
        
   ;Value Of eax To cr0 Save
   ;The Is Once Value Copy
   mov cr0,eax;

   ;Current Stack Top Value To eax Save
        pop eax;
        
   ;IF Flag Bit Zero
   ;The Code Change IF Flag Bit Is Zero
   cli
    };
   
//g_uCr0 Is a 全局 Variable
//g_uCr0 Type Is ULONG
//uAttr Is Current Routine Local Variable
//uAttr Type Is ULONG
//g_uCr0 In Current Routine Be Initialize Zero
//uAttr Save Is What
g_uCr0=uAttr;
}

//The Routine Not Return Value
//The Routine Is What
VOID WPON()
{
//Routine Body

//Implant Asm Code
    __asm
    {
   ;The Is Asm Code

   ;The Code 使 If Flag Bit 为 1
   ;The Is a CUP Control Code
        sti

   ;eax As Save Function Call Parameter
   ;Value Of eax Come Stack Pass Push
   ;The Is a Value Copy To Stack Top
        push eax;

   ;g_uCr0 Is 全局 Variable
   ;g_uCr0 Value To eax Save
        mov eax,g_uCr0;

   ;eax Value To cr0 Save
   ;cr0 Is What
        mov cr0,eax;

   ;Current Stack Top Value To eax Save
   ;Pass Current esp
        pop eax;
    };
}

//In The Routine Complete Irp
//The Routine 直接 Commplete Irp
//然后 Return a STATUS_SUCCESS
NTSTATUS PatchCommonDispatch(
        //Irp Send To a DeviceObject
        //p == Pointer
        //The Is Kernel Structure
        PDEVICE_OBJECT DeviceObject,
        
        //Irp Of Current Receive
        //Irp == I/O Request Pack
        //p == Pointer
        PIRP Irp
        )
{
//Set Irp Member
Irp->IoStatus.Status=STATUS_SUCCESS; //Set The Irp Complete
    Irp->IoStatus.Information=0;
   
//指定The Irp已经Complete
//已经Complete的Irp将Return To I/O Manager
//也就是说现在要把这个Irp返回到I/O管理器了,所有的处理已经完成了.
//The Routine Not Return Value
IoCompleteRequest(
  
   //The Is Current Irp
   //Irp Of 等待被Complete
   //The Parameter From Current Caller
   Irp,
  
   //Add优先级
   IO_NO_INCREMENT
   );
return STATUS_SUCCESS; //Return Success To Caller
}

//Get Kernel Function Address Of Function Name
//Current Routine Return a void Type Pointer To Caller
PVOID GetKernelFuncAddr(
       //Function Name From Caller
       //Find Function Address Of The Parameter
       PCHAR func_name
       )
{
//Function Body

//String For Ansi Version
//ANSI_STRING Is a Structure
    //Source Structure Name 一般都有一个_前缀,表示是一个原始结构被struct声明
//被typedef定义之后一般有2个类型,一个是普通无_前缀版本,另一个是p前缀版本,表示已个Pointer
//ANSI_STRING Member含义与UNICODE_STRING相同
//ANSI_STRING And UNICODE_STRING DataType As Is PCHAR
ANSI_STRING ansi_name;

//The Is UNICODE_STRING Structure
    UNICODE_STRING uni_name;
    PVOID func_addr; //Function Address be Save In a Pointer
   
//Initialize String Of Function Name
//func_name From Current Caller
//Finally String To ansi_name
RtlInitString(&ansi_name,func_name);

//AnsiString ConvertTo UnicodeString
//Current Function Receive Parameter Is Function Name Send To uni_name
//第三个参数为true将为uni_name Allocate Memory Space
    //uni_name Not Allocate Memory Space
RtlAnsiStringToUnicodeString(&uni_name,&ansi_name,TRUE);
   
//func_addr Is PVOID Type
//The Kernel Routine Return a Function Pointer Of Function Name
//Function Name From Current Routine Receive Parameter
//The Routine Call 实现了 Current Function的关键功能
//Return Function Address To func_addr
func_addr=MmGetSystemRoutineAddress(&uni_name);
   
//The Routine Free a Unicode String Of Receive Parameter
RtlFreeUnicodeString(&uni_name);
   
//Return By The Function Get Address To Caller
    return func_addr;
}

//The Routine 对比 func_addr And startbytes 是否相同 Length len
BOOLEAN IfDirty(
     //The Is Function Address
     //Type Is Void *
     //The Parameter From Caller
     PVOID func_addr,

     //Pointer To Char
     //startbytes Is What
     CHAR *startbytes,
   
     //The Is Length
     int len
     )
{
//Current Routine Body

//Current Routine Receive Parameter Save To addr
PCHAR addr=(PCHAR)func_addr;
    int i;
   
//Loop Structure
    for(i=0;i<len;++i)
    {
   //Loop Body
   //Function Address Save In addr
   //判断addr Array And startbytes Array是否相同
   if(addr[i]!=startbytes[i])
            return TRUE;
   else
    continue; //Continue Loop
    }   
    return FALSE;
}

//__declspec(naked) Is What Type
//The Routine Get DeviceObject Pointer
//The Routine Return a __declsped(naked) Type Value To Caller
__declspec(naked) NewStubForIoGetDeviceObjectPointer()
{
//Routine Body

//Pointer To Unicode String Structure
//The Is Object Name
//UNICODE_STRING Is a Kernel Structure
PUNICODE_STRING ObjectName;
   
//嵌入Asm Code
    __asm
    {
   ;空指令,被执行却没有任何效果.
        nop
        nop
        nop
        nop
        nop

   ;ebp Is Current Function Stack Bottom
   ;Save 之前 Function 栈帧
   ;Current Function ebp 入栈
   push ebp
        
   ;Change Current Function ebp pass esp
   ;Change Current Function Stack Bottom Pointer Pass esp  
   mov ebp,esp
        
   ;For Current Function Allocate Memory Space
   ;__LOCAL_SIZE Is Current Function Local Memory Space
   sub esp,__LOCAL_SIZE

   ;edi Sabe Current Function Stack Bottom 上一个单元的Data
   ;a 单元 Is 8 Byte
   mov edi,[ebp+8]
        
   ;ObjectName=edi;
   mov ObjectName,edi
    }
        
//难道asm前缀是一个下划线还是2个下划线的区别就在于
//是嵌入一条Asm Code还是以个Asm CodeBlock

//DbgPrint 被 Convert 为 DWORD Type And Save In edi
//DbgPrint Is What
_asm mov edi,DWORD PTR DbgPrint

//
_asm mov MyDbgPrint,edi
   
    //MyDbgPrint("object name %ws\n", ObjectName->Buffer);
    //_asm add esp, 8
   
//Compare UnicodeString
//RtlCompareUnicodeString Routine Return 0 Value 表示相等
//UNICODE_STRING Is a Kernel Structure
if(RtlCompareUnicodeString((PUNICODE_STRING)ObjectName,&ObjPtrName,TRUE)==0)
    {
        _asm
        {
            mov esp,ebp
            pop ebp
            mov eax,0xC000000D
            ret 10h
        }
    }
   
    __asm
    {
        mov esp,ebp
        pop ebp

        //must declare this tag for insert orginal function's starting bytes here
        _emit 0xaa
        _emit 0xaa
        _emit 0xaa
        _emit 0xaa
    }
}

//The Routine Is What
//The Routine Return int To Caller
//The Routine Get Length To Caller
//Get Routine Length Pass Function Address And
int GetPatchLength(
       //Pointer Char
       //Function Start Address
       //The Parameter Is IoGetDeviceObjectPointer
       PCHAR func_start,

       //Maximum Length
       //The Parameter Is Number 7
       int max_need_len
       )
{
//Routine Body

//op == opcode
//opcode Length
int one_oplen=0;
    int actual_oplen=0;
   
//The Structure Is Kernel Structure
//The Structure No Is By User Define
//The Is What Structure
struct disasm_struct dis;
   
//Loop Structure
//actual_oplen By Current Routine Define
//max_need_len From Caller
//Current Parameter max_need_len Is Number 7
    //Loop 从0到6
while(actual_oplen<max_need_len)
    {
   //Loop Body

   //ade32_disasm Function From ade32.h
        one_oplen=ade32_disasm(func_start,&dis);
        func_start+=one_oplen;
        actual_oplen+=one_oplen;
    }   
    return actual_oplen; //Return opcode Length To Caller
}

//PPATCH_INFO Is Pointer To patch_into Structure
//The Routine Return a BOOLEAN Type Value To Caller
BOOLEAN UnpatchX(PPATCH_INFO pach)
{
//Routine Body

//The Is What
if(pach->patch_len&&pach->org_func_addr)
{
   //Copy Memory Black By The Kernel Routine
   //From patch_info Structure
   RtlCopyMemory(pach->org_func_addr,pach->org_bytes,pach->patch_len);
        return TRUE;
    }
    return FALSE;
}

//typedef unsigned short int BOOOLEAN
BOOLEAN PatchX(
      //PCHAR == Pointer To Char
      //The Parameter Is Function Name
      PCHAR func_name,

      //PVOID == void*
      //The Parameter Is New Function      
      PVOID new_func,

      //The Parameter Is New Function Length
      int new_func_len,

      //The Parameter Is UserDefine Structure
      //Pointer To patch_info Structure
      PPATCH_INFO pach
      )
{
//Routine Body

int i;
    BOOLEAN bFoundTag=FALSE; //BOOLEAN Type 可以表示2个值 true or false
    WPOFF(); //Call The Function
   
    //get original function address In GetKernelFuncAddr Routine Return Value
//Parameter Is Current Receive Function Name
//Return Value Save In pach_info Structure
//Of Function Name Return a Function Address
    pach->org_func_addr=GetKernelFuncAddr(func_name);
   
//判断Get Address 是否 Success
//Kernel Function Address Pass MmGetSystemRoutineAddress Get
if(pach->org_func_addr)
    {
   //Call The User Define Routine Get Length To pach->patch_len
   //Of pach->org_func_addr And Number 7 Get Thr Routine Return Value
   pach->patch_len=GetPatchLength(pach->org_func_addr,7);

   //Return a Pool Memory To pach->new_func_addr
   //The Routine Return Type Is PVOID
        pach->new_func_addr=(PVOID)ExAllocatePoolWithTag(
    NonPagedPool,
    new_func_len,
    'kdD'
    );
        
   if(pach->new_func_addr)
        {
    //In The Hook ?
    RtlCopyMemory(pach->new_func_addr,new_func,new_func_len);
            
    //Loop Structure
    for(i=0;i<new_func_len-(pach->patch_len+7);++i)
            {
                //find tag for insert orginal function starting bytes
                //找符合条件的一段opcode
     if(
      ((BYTE*)new_func)[i]   == 0xaa &&
                    ((BYTE*)new_func)[i+1] == 0xaa &&
                    ((BYTE*)new_func)[i+2] == 0xaa &&
                    ((BYTE*)new_func)[i+3] == 0xaa)
                {
                    bFoundTag=TRUE;
                    break;
                }
            }
            
    //找到啦
            if(bFoundTag)
            {
     //save original function's starting bytes for later Unpatch
                RtlCopyMemory(pach->org_bytes,pach->org_func_addr,pach->patch_len);
               
                //modify new_func to jmp to original function
                RtlCopyMemory((BYTE *)pach->new_func_addr+i,pach->org_func_addr,pach->patch_len);
                ((BYTE *)pach->new_func_addr+i+pach->patch_len)[0]=0xea;
                *(ULONG *)((BYTE *)pach->new_func_addr+i+pach->patch_len+1)=(ULONG)pach->org_func_addr+pach->patch_len;
                *(USHORT *)((BYTE *)pach->new_func_addr+i+pach->patch_len+5)=KERNEL_SEG;
               
                //modify original function to jmp to new_func first
                ((BYTE *)pach->org_func_addr)[0]=0xea;
                *(ULONG *)((BYTE *)pach->org_func_addr+1)=(ULONG)pach->new_func_addr;
                *(USHORT *)((BYTE *)pach->org_func_addr+5)=KERNEL_SEG;
               
                return TRUE;
    }
            else
            {
                ExFreePool(pach->new_func_addr);
                pach->new_func_addr=NULL;
            }
        }
    }   
    WPON(); //Call The Function
    return FALSE;
}

//PatchDeviceControl Routine处理Irp
//The tPatchDeviceControl Routine Is What

//NTSTATUS Is a 32Bit Value
//By FinallyCode And ErrorCode 组成
//FinallyCode And ErrorCode各占32Bit的部分
//IO_ERR_XXX 为ErrorCode
//STATUS_XXX 为FinallyStatus
NTSTATUS
tPatchDeviceControl(
        //Parameter About Current Routine
        PDEVICE_OBJECT DeviceObject, //DeviceObject Of Irp Send
        PIRP Irp //Irp Of Current Routine Receiver
        )
{
//Routine Body

//Get Current Irp In Stack Location
PIO_STACK_LOCATION irpSp=IoGetCurrentIrpStackLocation(Irp);

WCHAR *DeviceName=L"\\Device\\Harddisk0\\DR0"; //The Is Harddisk Device
    UNICODE_STRING uni_name; //UNICODE_STRING Is a Structure
    PDEVICE_OBJECT TempDeviceObject; //The Is DeviceObject
   
//FILE_OBJECT Is a KernelMode DataStructure
//FILE_OBJECT 代表一个已经打开的文件或目录
//Pass FILE_OBJECT Can Get DEVICE_OBJECT
PFILE_OBJECT TempFileObject;

    NTSTATUS status; //NTSTATUS Is a 32Bit Int
    PATCH_INFO pach; //PATCH_INFO Is a User-Defined Structure
   
//多分支选择
//WinDbg应该可以看到内核结构,可惜现在我还不会用...
//我猜测一下PIO_STACK_LOCATION...
//irpSp Is PIO_STACK_LOCATION Type
    switch(irpSp->Parameters.DeviceIoControl.IoControlCode) //判断Irp的ControlCode
    {
   case 1:
    //Pass 0 Fill Memory Block
    //Fill PATCH_INFO Structure
    RtlZeroMemory(
     &pach, //Start Fill Address
     sizeof(PATCH_INFO) //Fill Length
     );
   
    //Call The Routine
    PatchX("IoGetDeviceObjectPointer",NewStubForIoGetDeviceObjectPointer,256,&pach);
   
    //Initialize UnicodeString To uni_name Of DeviceName
    //From WCHAR To UnicodeString
    RtlInitUnicodeString(&uni_name,DeviceName);
   
    //Return DeviceObject Pointer To status
    //
    status=IoGetDeviceObjectPointer(
   
     //Device Is Harddisk
     //DeviceObject Name
     //Type Is UNICODE_STRING
     &uni_name,
   
     FILE_READ_DATA, //Access 方式
     &TempFileObject, //FileObject Pointer
   
     //DeviceObject Pointer In The Out Parameter
     //DeviceObject Pointer
     &TempDeviceObject
     );        
    //Un(&pach);
    //status=IoGetDeviceObjectPointer(&uni_name,FILE_READ_DATA,&TempFileObject,&TempDeviceObject);
    break;
}
    return PatchCommonDispatch(DeviceObject,Irp); //ReturnValue From The Routine
}

//The Function Unload Current Driver
//The Routine Not Return Value
//The Routine Return a Void Value To Caller
//The Routine In Current Be Unload Time Call
void PatchUnload(
     //The Parameter Is Pointer DRIVER_OBJECT Structure
     //DriverObject 代表 Current Driver Program
     PDRIVER_OBJECT DriverObject
     )
{
//Routine Body

//UNICODE_STRING Is a Kernel Structure
//The Is a Symbolic Link
UNICODE_STRING uni_symbolic;

//The Routine Call Remove Current DeviceObject
//The Routine Not Return Value
//DriverObject->DeviceObject For Delete
//DeviceObject In DriverObject Get
IoDeleteDevice(DriverObject->DeviceObject);
   
//Initialize a Unicode String Pass The Routine Call
//Set Symbolic Link Pass The Routine Call
RtlInitUnicodeString(
  
   //Pointer To a Memory Buffer For Initialize Unicode String
   //The Paramter Is Local Variable
   //Save Symbolic Link
   &uni_symbolic,

   //Source Unicode String
   //The Is Symbolic Link
   //Pointer To Zero End String For Initialize
   L"\\DosDevices\\doptr"
   );

//Remove a Symbolic Link Pass The Routine Call
//The Routine Return a NTSTATUS Type Value To Caller
IoDeleteSymbolicLink(&uni_symbolic);
}

//Driver EntryPoint
//Driver Load之后First Call Function
//The Function负责Initialize Current Driver
NTSTATUS //The Type Is 32Bit int,被typedef,表示ErrorCode Or FinallyState
DriverEntry(
    //The Parameter By Caller提供,Is a Driver_Object Structure Pointer
    //Driver_Object代表Current Driver
    //Driver_Object Is a DriverImage
    //Driver_Object 的 Poiner被作为InputParameter传递到DriverEntry,为First Parameter
    //Initialize Driver By a Driver_Object来完成
    PDRIVER_OBJECT DriverObject, //Type的前缀P代表是Poiner,之后是用处的描述
   
    //The UnicodeString表示Current Driver的Path
    //P代表Poiner,可以被理解为Poiner To UnicodeString
    PUNICODE_STRING RegistryPath
    )
{
//Function Body

//DEVICE_OBJECT代表一个设备
//Input/Output Request将Send To The DEVICE_OBJECT
//每个Driver Must Create a DEVICE_OBJECT
//通过DEVICE_OBJECT可以Get DRIVER_OBJECT,也可以通过DRIVER_OBJECT Get DEVICE_OBJECT
//通过DEVICE_OBJECT可以Get Current PIRP
PDEVICE_OBJECT DeviceObject; //Pointer To a DEVICE_OBJECT Structure

//W==WideChar
//L前缀表示后面的String Is a UnicodeString
WCHAR *DeviceName=L"\\Device\\doptr"; //Set The Device Name,doptr Is What Device
WCHAR *SymbolicName=L"\\DosDevices\\doptr"; //Set The Device SymbolicName
   
//UNICODE_STRING Is a Structure
//Source Structure:
//struct _UNICODE_STRING{
//      Length //Current String Length
//      MaximumLength //Buffer Length
//      Buffer}
UNICODE_STRING uni_name,uni_symbolic; //声明Name And Symbolic
    NTSTATUS status; //The 表示 Current Driver Run State
    int i;
   
//Initialize a Unicode String
//The Function Not Return Value
//Parameter1: Pointer To a Buffer For Save UnicodeString
//Parameter2: Pointer To a Zero End String
RtlInitUnicodeString(
   &ObjPtrName, //The Is 全局变量 Length Member 被赋值为0
   L"\\Device\\Harddisk0\\DR0" //The Is Default Harddisk Device Path
   );
   
RtlInitUnicodeString(&uni_name,DeviceName); //Initialize DeviceName To uni_name Buffer

//Loop Body
//IRP_MJ_MAXIMUM_FUNCTION 表示irp的最大数量
//Loop And Find 每一个Irp
for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;++i)
   DriverObject->MajorFunction[i]=PatchCommonDispatch; //All Irp By The Routine 处理
   
//MajorFunction Array Save Pointer To DispatchFunction
//Irp==InputOutput Request Pack
//Driver 中的 Device_Object将Receive特定Type的Request
//IOCTL == InputOutput Control Code
//Driver Pass Request Control Device
//Driver是否能够处理Request,要看所绑定的Device Type
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=PatchDeviceControl; //Set Dispatch Function
    DriverObject->DriverUnload=PatchUnload; //Set Driver Unload Function
   
//Create And Initialize Device Object
    //status Is NTSTATUS Type
//Allocate Memory For a Device_Object And Initialize The Device_Object
status=IoCreateDevice(
0  
   //Pointer To DriverObject Structure By DriverEntry Routine Get,In System Call Current Driver
   DriverObject,
        
   //The Parameter 指定Byte Number Of Device的扩展Size
   0,

   //a Pointer To UnicodeString Is The DeviceName
        &uni_name,

   //The Is DeviceType,The Parameter By SystemDefine Constant指定
        0,

   //To The Device Add More Info
        0,

   //The Device 是否是HighLevel的
        FALSE,

   //If The Function Call Success 将 Return DeviceObject To The Parameter
        &DeviceObject
   );
   
//判断Device是否被Success Create
if(NT_SUCCESS(status))
    {
   //To Kernel Send a String
   //DbgPrint Return a ULONG Value
   //First Parameter Is a Format String
   //可以In DbgPrint Function中使用printf Function的FormatString
   //第二个Parameter Is 被Print的String
   //DbgPrint Routine Call Success Return STATUS_SUCCESS,否则Return ErrorCode
   DbgPrint("%ws\n",SymbolicName); //Output Device Symbolic Name

   //Initialize UnicodeString Of SymbolicName To uni_symbolic
        RtlInitUnicodeString(&uni_symbolic,SymbolicName);

   //For The Device Create a SymbolicLink
        //The Routine Call Success Return NTSTATUS_SUCCESS
   status=IoCreateSymbolicLink(
    &uni_symbolic, //The Is Symbolic Name
    &uni_name //Current Create 的 DeviceObject的Name
    );
    }   
   
//If Current Function Success则Return STATUS_SUCCESS
//否则Return a 相关的ErrorStatus,ErrorStatus被Define In ntstatus.h
return status; //最后一次To status 赋值Is In IoCreateSymbolicLink Routine
}

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞0
打赏
分享
最新回复 (6)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Liquidworm 2008-10-3 10:09
2
0
我主要是为这个code写相信的注释与汉字的描述,请高手客气的指教,一定要客气哦~千万不要伤害我那脆弱的心哦~
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Liquidworm 2008-10-3 10:59
3
0
有没有大牛大致看下,然后给点建议呀~
雪    币: 709
活跃值: (2265)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 25 2008-10-3 11:25
4
0
学习他人的code,不仅要写注释,还要调试通过啊.你编译通过了呀????

理论和实际还是有一定差距的,主要是要能动手~~~
雪    币: 225
活跃值: (10)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
dayed 1 2008-10-3 12:16
5
0
这个排版比你blog上清晰明了
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Liquidworm 2008-10-4 08:55
6
0
To-> Sudami:呵呵,貌似少个ade32.h,应该调试不过吧,我现在已经转向开始看另一份Inline Hook了.等俺多看点就开始调试Hello World 嘿嘿~

To-> Dayed:pediy的语言描述方式我不太习惯接受,还有页面貌似不太简洁呀 不过却是个不错的地方,我Blog总换模板....哈哈
雪    币: 213
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
classfree 2008-10-6 11:31
7
0
能写注释,表示能完全看懂了
游客
登录 | 注册 方可回帖
返回