首页
社区
课程
招聘
[原创]一种注入进程,获得完全操控的方法之二
发表于: 2007-12-12 16:50 23588

[原创]一种注入进程,获得完全操控的方法之二

2007-12-12 16:50
23588

看到了我的之一,我想大家会很清楚,因为这个方法的最大的BUG就是在回调函数之后来处理,如果前面已经处理了,
那么我们就无法处理了。而且又要修改系统DLL,比较不完美。我最近又发现了两种方法:
        一、修改RegisterClassA:
        相对前面的方法来说,这个方法很好用,因为,我们可以很容易把回掉函数改掉。类似如下代码:
//---------------------------------------------------------------------------
int CMuGame::InitRegClass()
{       
        //获取模块句柄:
        HINSTANCE hModule=::GetModuleHandle("User32.dll");
        //获取原始函数地址:
        fpsRegisterClassA=(REGWINCLASS)::GetProcAddress(hModule,"RegisterClassA");

        //获取当前内存块的保护类型:
        MEMORY_BASIC_INFORMATION _base;
        ::VirtualQuery((LPVOID)((DWORD)hModule+0x1000),&_base,sizeof(MEMORY_BASIC_INFORMATION));

        //处理为读写类型:
        ::VirtualProtect(_base.BaseAddress,_base.RegionSize,PAGE_READWRITE,&_base.Protect);

        //获得导出表的地址和大小:
        DWORD   dwExportSize=NULL;
        PDWORD  pdwExportAddr=NULL;

        appfun.Load(hModule);
        appfun.GetExportTable(&dwExportSize,&pdwExportAddr);

        //查找RegisterClassA函数地址:
        for(DWORD i=0;i<dwExportSize;i++,pdwExportAddr++)
        {
                if((*pdwExportAddr+(DWORD)hModule)==(DWORD)fpsRegisterClassA)
                {
                        //计算跳转地址:
                        DWORD  dword=(DWORD)fpnRegisterClassA-(DWORD)fpsRegisterClassA;
               
                        //声明结构对象:
                        _ASM_JMP _jmp;
                        _jmp._01cmd =0xE9;
                        memcpy((PDWORD)_jmp._02dat,&dword,4);
                        memcpy((LPVOID)((DWORD)fpsRegisterClassA-5),&_jmp,5);

                        //修改导出表地址:
                        DWORD  dwAddr=*pdwExportAddr-5;
                        memcpy(pdwExportAddr,&dwAddr,4);

                        break;
                }
        }

        //处理完成后,恢复保护类型:
        DWORD dwProctect=NULL;
        ::VirtualProtect(_base.BaseAddress,_base.RegionSize,_base.Protect,&dwProctect);
        return NULL;
}
//----------------------------------------------------------------------------

        当然,我们可以修改IAT表来实现,但是我们大家都明白,IAT表很不确定,有的程序还没有IAT表,我们必须找个通用
的方法,那就是直接把User32.dll的导出表修改掉,因此,我们让程序正常调用RegisterClassA这个之后,千万没想到的是,现
在的导处API函数的地址已经被修改,而在中途转到我们的DLL中,然后再回到真正的函数地址入口:

//-----------------------------------------------------------------------------

ATOM WINAPI fpnRegisterClassA(WNDCLASS *lpWndClass)
{
        //替换"XX"窗口的回调函数:
        if(lstrcmp(lpWndClass->lpszClassName,"XX")==0) //如果是我们要替换的窗口,就替换,不是就不替换
        {
                fpsWndProc=lpWndClass->lpfnWndProc;
                lpWndClass->lpfnWndProc=fpnWndProc;
        }
        ATOM  atom=fpsRegisterClassA(lpWndClass);
        return atom;
}

LRESULT CALLBACK fpnWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
        switch(message)
        {
        case WM_INITDIALOG:
                {
                        //保存窗口句柄:
                        theApp.game.hWnd=hDlg;
                        //修改标题,方便我们调用:
                        ::SetWindowText(hDlg,_T("[PhantomNet] XX"));  //我们把标题修改掉,方便通信,可以不修改的。
                        break;
                }
        case WM_CMD:   //自定义命令:
                {
                        if((DWORD)wParam==0x01){PostQuitMessage(0);} //收到命令,我们直接用API让程序结束。
                        if((DWORD)wParam==0x02){}   //……什么操作都可以
                        break;
                }
        default:{break;}
        }
        //转到游戏的回调函数:
        return fpsWndProc(hDlg,message,wParam,lParam);
}

//----------------------------------------------------------------------------------------

上面的代码就是实现修改RegisterClassA注册类,来转到我们的回调函数的。我们的回调函数,是在真正的回调函数
之前就被执行的,我们可以截获部分消息,让真正的回调函数收不到,因为,我们事先已经替它处理了事件。这样就避免了部
分消息收不到,但是这样的方法,是在程序没有启动,而随程序启动而加载……,我们就没办法对现有的进程进行操作。

        二、直接替换回调函数:
        怎么能直接替换呢?很多朋友都会想改这个改那个,实际KS给我们4个函数来让我们做这个工作。但是局限在同一进程,
//----------------------------------------------
GetClassLong(HWND hWnd,int Index);
GetWindowLong(HWND hWnd,int Index);
SetClassLong(HWND hWnd,int nIndex,LONG dwNewLong);
SetWindowLong(HWND hWnd,int nIndex,LONG dwNewLong);
//----------------------------------------------
        有必要对这两类函数做说明,GetClassLong和SetClassLong在RegisterClassA这个函数运行时才起作用,而GetWindowLong
和SetWindowLong在CreateWindowA后才有作用。我们完全可以不用CreateRemoteThread这个来触发,我们的程序。我们在替换回调
函数时可以在其他进程对目标进程处理,我们只需要把程序写入到目标进程,我们没必要专门去创建一条线程来加载DLL,我们直接
把它写进去后,再让某个消息来触发加载。那样就会隐蔽点,这里简要说一下,为了安全期间不贴代码了。

//--------------------------------------------------

int CMgMuAssistantApp::LoadMain()
{
        //初始化SOCKET:
        if (!AfxSocketInit())
        {
                AfxMessageBox("Error InitSocket!");
        }
        //查找窗口是否存在:
        pWnd=CWnd::FindWindow(NULL,"XX");
        if(pWnd!=NULL)
        {
                //由于窗口有可能在创建前被找到,所以我们完善期间不用GetWindowLong,
                //保存原始窗口回调函数:
                fpsWndProc=(WNDPROC)::GetClassLong(pWnd->m_hWnd,GCL_WNDPROC);

                //由于SetClassLong只在注册类时起作用,我们必须用SetWindowLong;
                //修改回调函数:
                ::SetWindowLong(pWnd->m_hWnd,GWL_WNDPROC,(LONG)fpnWndProc);       

                //修改Socket函数:
                hooksocket.InitHookApi(::GetModuleHandle(NULL),0x00376000,0x0568);

                //装载OpenGL:
                PDWORD pdwAddr=(PDWORD)((DWORD)::GetModuleHandle(NULL)+0x00375A00);
                *pdwAddr=(DWORD)fpnRender;
                pdwAddr        =(PDWORD)((DWORD)::GetModuleHandle(NULL)+0x002B5E69);
                *pdwAddr=(DWORD)((DWORD)::GetModuleHandle(NULL)+0x00375A00);
        }

        return 0;
}

//---------------------------------------------------
        上面的代码是我针对某个游戏做的,由于游戏是基于OpenGL的,所以我就把OpenGL的Render修改下来,来处理我的代码
比如,我们要用到程序内部函数:

//-----------------------------------------------------------
//原程序是如下的调用方法:
00664B75  |.  50            push    eax
00664B76  |.  8D55 8C       lea     edx, dword ptr [ebp-74]
00664B79  |.  52            push    edx
00664B7A  |.  A1 181E9E07   mov     eax, dword ptr [79E1E18]
00664B7F  |.  83C0 14       add     eax, 14
00664B82  |.  50            push    eax
00664B83  |.  8B0D 141E9E07 mov     ecx, dword ptr [79E1E14]
00664B89  |.  83C1 23       add     ecx, 23
00664B8C  |.  51            push    ecx
00664B8D  |.  E8 8E7CF2FF   call    0058C820

//我把它做成C函数调用,这样我们就可以直接用这个函数来调用程序内部函数了:
int CMgMuAssistantApp::SetMainText(int x,int y,LPSTR str,int unk1,int unk2,int unk3)
{
        ShowText=(MAINTEXT)0x0058C820;
        ShowText(x,y,str,unk1,unk2,unk3);
        return 0;
}

//---------------------------------------------------------------------

下面是我的回调函数,我们发现我们再发送命令给目标程序时,目标程序就乖乖的按我们说的做,让它放那,它就放那,让
它返回什么,它就乖乖返回什么,我们可以设置更多的命令来对程序操作:
//--------------------------------------------------------------------
LRESULT CALLBACK fpnWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
        //保存窗口句柄:
        theApp.game.hWnd=hDlg;

        switch(message)
        {
        case WM_INITDIALOG:{break;}
        case WM_PAINT:{break;}
        case WM_CMD:
                {
                        if((DWORD)wParam==0x01){PostQuitMessage(0);}
                        //返回的是主程序句柄:
                        if((DWORD)wParam==0x02){
                                //保存主程序句柄:
                                theApp.m_hWndMainApp=(HWND)lParam;
                                //返回游戏句柄:
                                ::SendMessage(theApp.m_hWndMainApp,WM_CMD,0x02,(LPARAM)hDlg);
                        }
                        if((DWORD)wParam==0x08){
                                //连接主程序,这里我创建了SOCKET来网络传输数据:
                                theApp.m_uPortMainApp=(UINT)lParam;
                                pClient=new CClient;
                                pClient->Close();
                                pClient->Create();
                                if(lstrcmp(theApp.m_strAddrMainApp,"")==0)
                                {
                                        //获取主机地址:
                                        char hostname[MAX_PATH]={0};
                                        ::gethostname(hostname,MAX_PATH);
                                        hostent *addr=::gethostbyname(hostname);
                                        theApp.m_strAddrMainApp=inet_ntoa(*(struct in_addr *)addr->h_addr_list[0]);
                                }
                                if(pClient->Connect(theApp.m_strAddrMainApp,theApp.m_uPortMainApp)==FALSE)
                                {
                                        ::SendMessage(theApp.m_hWndMainApp,WM_CMD,0x08,(LPARAM)-1);
                                }else{::SendMessage(theApp.m_hWndMainApp,WM_CMD,0x08,(LPARAM)1);}
                        }
                        if((DWORD)wParam==0x10){               
                                //修改标题,方便我们调用:
                                ::SetWindowText(hDlg,_T("[MG] MU"));
                        }
                        if((DWORD)wParam==0x11){
                                CRect rect;
                                //获取窗口矩形:
                                ::GetWindowRect(hDlg,&rect);
                                //移动窗口:
                                ::MoveWindow(hDlg,LOWORD(lParam),HIWORD(lParam),rect.Width(),rect.Height(),TRUE);
                        }
                        return TRUE; //直接返回,不让游戏回调处理,这个是我们的命令机密不能让程序知道:
                }
        case WM_COPYDATA:  //我们替我们的目标程序处理进程间通信消息,为了方便点:)
                {
                        //wParam:窗口句柄
                        //lParam:数据
                        theApp.OnCopyData(CWnd::FromHandle((HWND)wParam),(COPYDATASTRUCT*)lParam); return TRUE;
                }
        default:{break;}
        }
        //转到游戏的回调函数:
        return fpsWndProc(hDlg,message,wParam,lParam);
}

//-----------------------------------------------------------------------------------------------

        实际这回是在上回的基础而来的,我们总结一下就知道,当我们完全操作了回调函数时,一个应用程序就几乎成了你
手中的蛋糕,想怎么样吃就怎么样吃:).KS在进程的通信和相互性上没做多少,我们很多时候都要用CreateRemoteThread这个
函数来做DLL的加载,实际不用它的方法还是有很多的,只是没有被人发现而已,同过前面的说明,我想大家都会明白了,怎么
样把一个程序完全操控,但是回过头来一想,如果我们对一个进程做了完全操作,我们可以再用这个进程操作其它的进程,那么
会是烦琐点,但是是件很让人恐怖的事。前面的这个回调函数处理的事情很少,因为,我没把它做的有多强,我不想把它做多强
实际,当一个进程的回调函数交给你来处理,那么我们就可以做很多我们想做的事。当我们将DLL放入某个进程时,我们就可以
调用它的任意一个函数,来为我们工作,我们只需要做影射,把我们要调用的函数和地址影射到我们的DLL中,然后再加工~~~~

:)^^^^

                                                   -By EasyStudy For PhantomNet


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (30)
雪    币: 1657
活跃值: (291)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
2
此次,主要简洁点,代码少贴点,没必要的就没贴~~~喜欢的支持一下!不喜欢的就乐一下!!!
2007-12-12 16:56
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
LZ也是做外挂的坏蛋..
PS.我只看了下.没试验.貌似这种方法依然过不了反外挂= =||
2007-12-12 18:08
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
4
牛啊~
2007-12-12 21:11
0
雪    币: 97697
活跃值: (200824)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
5
Thanks.
2007-12-12 22:47
0
雪    币: 1505
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
6
2007-12-13 02:10
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
雾里看花。..........
2007-12-13 08:35
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
8
继续学习~~~~
2007-12-13 11:06
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
能不能附带一个个完整的例子程序呀
2007-12-13 12:31
0
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
10
嗯,写得不错,帮顶
2007-12-13 12:48
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
11
他写的东西都是基于你拥有能改变目标进程环境的权限。当你可以进入对方进程空间之后,可以玩的东西就多,可以根据你对系统的理解,在多种技术层面夺取EIP,例如玩玩系统提供的某个API,HOOK某个频繁调用的API,修改TEB/PEB里面某个回调的指针,当然还有SEH这个易于覆盖的东西。

因此,对于反外挂来说,其实就是不让不在白名单内的程序访问白名单。它的实现仅是禁止未授权程序获取受保护进程的HPROC、HTHREAD、HWND。

对于反外挂代码来说,保证自身效果的关键问题在于

1.如何保证自身文件不被修改
2.如何防止对方进入内核

假设正常情况下,用户在玩游戏的时候不应安装任何驱动程序,那么反外挂实际的问题便是与外挂运行先后的问题。即使网游在安装后,反外挂系统一直运行在用户系统,也可以通过先运行外挂,再装网游来解决。

一旦进入R0,爱怎么玩怎么玩~~~

想过反外挂系统,你需要一份WRK和2K的代码和一定反汇编及编写驱动的能力。剩下的仅是时间问题~~~

即LZ的文章,仅是为初学者普及编程知识,对抗反外挂,战场在R0,而不是R3,同样地,对抗主动防御,战场也在R0,而不是R3~~~

如何从R3切换到R0,这个问题则在NTDLL中有答案~~~KERNEL32和USER32没有你想要的答案
2007-12-13 13:01
0
雪    币: 1657
活跃值: (291)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
12

我从来没写过外挂~~~~~~
我也不想写,实际对于外挂来说在系统低层的应用来讲,外挂只用了九牛一毛!我是喜欢玩玩系统,分析系统~~~~~只是在最近研究的时候发现了很好玩的东西~,就拿XX游戏做了个试验!!!!发出来给大家,何况!请明白一点,我是研究系统低层,不是怎么研究突破反外挂~~~~~~~~我对外挂和反外挂不感什么兴趣!何况我这么几年来,很少去玩网络游戏,外挂不外挂跟我没关系。

2007-12-13 15:58
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
写得好,顶一下
2007-12-13 19:58
0
雪    币: 608
活跃值: (91)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
支持樓主,好東西.
2007-12-17 09:51
0
雪    币: 324
活跃值: (91)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
15
非常欣赏楼主这样的知识共享精神,支持!
2007-12-17 19:58
0
雪    币: 332
活跃值: (30)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
16
// fuckdll.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "fuckdll.h"
#include <tchar.h>
#define WM_CMD WM_USER+1
typedef ATOM (*REGWINCLASS)(CONST WNDCLASS *WndProc);
WNDPROC fpsWndProc;
REGWINCLASS fpsRegisterClassA;
typedef struct fuckyou  
{
        unsigned char _01cmd;
        unsigned long _02dat;
}_ASM_JMP;
char Buffer1[128];
_ASM_JMP _jmp;
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                                         )
{
    switch (ul_reason_for_call)
        {
                case DLL_PROCESS_ATTACH:
                        InitRegClass();
                case DLL_THREAD_ATTACH:
                case DLL_THREAD_DETACH:
                case DLL_PROCESS_DETACH:
                        break;
    }
    return TRUE;
}
LRESULT CALLBACK fpnWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
  switch(message)
  {
  case WM_INITDIALOG:
    {
      //保存窗口句柄:
      //修改标题,方便我们调用:
      SetWindowText(hDlg,_T("[PhantomNet] XX"));  //我们把标题修改掉,方便通信,可以不修改的。
      break;
    }
  case WM_CMD:   //自定义命令:
    {
      if((DWORD)wParam==0x01){PostQuitMessage(0);} //收到命令,我们直接用API让程序结束。
      if((DWORD)wParam==0x02){}   //……什么操作都可以
      break;
    }
  default:{break;}
  }
  //转到游戏的回调函数:
  return fpsWndProc(hDlg,message,wParam,lParam);
}

ATOM WINAPI fpnRegisterClassA(WNDCLASS *lpWndClass)
{
        MessageBox(NULL,"fuck you!  新窗口过程","look me",MB_OK);
  //替换"XX"窗口的回调函数:
  if(lstrcmp(lpWndClass->lpszClassName,"Afx:400000:0")==0) //如果是我们要替换的窗口,就替换,不是就不替换
  {
        //保存原始窗口过程
    fpsWndProc=lpWndClass->lpfnWndProc;
        //替换
    lpWndClass->lpfnWndProc=fpnWndProc;
  }
  ATOM  atom=fpsRegisterClassA(lpWndClass);
  return atom;
}

void InitRegClass()
{  
   MessageBox(NULL,"fuck you!initregclass","look me",MB_OK);
  //获取模块句柄:
  HINSTANCE hModule=GetModuleHandle("User32.dll");
  wsprintf(Buffer1,"address:%x",hModule);
  MessageBox(NULL,Buffer1,"user32.dll",MB_OK);
  if (hModule == NULL)
  {
          MessageBox(NULL,"fuck you!  error","look me",MB_OK);
          return;
  }
  //获取原始函数地址:
  fpsRegisterClassA=(REGWINCLASS)GetProcAddress(hModule,"RegisterClassA");
  wsprintf(Buffer1,"address:%x",fpsRegisterClassA);
  MessageBox(NULL,Buffer1,"RegisterClass导出表函数地址",MB_OK);
  if (fpsRegisterClassA == NULL)
  {
          MessageBox(NULL,"fuck you!  error","look me",MB_OK);
          return;
  }
  //获取当前内存块的保护类型:
  MEMORY_BASIC_INFORMATION _base;
  DWORD real;
  real=VirtualQuery((LPVOID)((DWORD)hModule+0x1000),&_base,sizeof(MEMORY_BASIC_INFORMATION));
  if (!real)
  {
          MessageBox(NULL,"fuck you!  error","look me",MB_OK);
          return;
  }
  //处理为读写类型:
  if(!VirtualProtect(_base.BaseAddress,_base.RegionSize,PAGE_READWRITE,&_base.Protect)){
          MessageBox(NULL,"fuck you!  error","look me",MB_OK);
          return;
  }
  //获得导出表的地址和大小:
  DWORD   dwExportSize=NULL;
  PIMAGE_EXPORT_DIRECTORY  pdwExportAddr=NULL;
  PIMAGE_DOS_HEADER  _dosHeader;
  PIMAGE_NT_HEADERS  _ntHeader;
  DWORD _exportDir=NULL;
  _dosHeader=(PIMAGE_DOS_HEADER)hModule;
  _ntHeader=(PIMAGE_NT_HEADERS)((LONG)_dosHeader+(LONG)(_dosHeader->e_lfanew));
  _exportDir=_ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  dwExportSize=_ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  //查找RegisterClassA函数地址:
  pdwExportAddr=(PIMAGE_EXPORT_DIRECTORY)(_exportDir+(DWORD)hModule);
  DWORD dwNum=pdwExportAddr->NumberOfFunctions;
  DWORD** dwaddr=(DWORD**)((DWORD)hModule+pdwExportAddr->AddressOfFunctions);
  for(DWORD i=0;i<dwNum;i++,dwaddr++)
  {
       
    if((DWORD)*dwaddr+(DWORD)hModule == (DWORD)fpsRegisterClassA)
    {
      //计算跳转地址:
      DWORD  dword=(DWORD)fpnRegisterClassA-(DWORD)fpsRegisterClassA;
      _jmp._01cmd =0xE9;
      memcpy(&_jmp._02dat,&dword,4);
          //在函数之前5字节写入跳转
      memcpy((LPVOID)((DWORD)fpsRegisterClassA-5),&_jmp,5);
          //更新函数地址
      DWORD  dwAddr=(DWORD)(*dwaddr)-5;
          //修改导出表地址
      memcpy(dwaddr,&dwAddr,4);
      break;
    }
  }
  //处理完成后,恢复保护类型:
  DWORD dwProctect=NULL;
  VirtualProtect(_base.BaseAddress,_base.RegionSize,_base.Protect,&dwProctect);
}

//fuckdll.h
#ifdef FUCKDLL_EXPORTS
#define FUCKDLL_API __declspec(dllexport)
#else
#define FUCKDLL_API __declspec(dllimport)
#endif
FUCKDLL_API void InitRegClass();
2007-12-19 10:41
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
强烈支持~~~
2007-12-23 12:40
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
不错。。。。很有参考价值啊!!
2007-12-23 23:26
0
雪    币: 200
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
19
新手,看不太懂
2007-12-23 23:47
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
新手看不懂,不过顶了,系统知识太强了,希望有天我会懂,顶了先
2007-12-24 06:51
0
雪    币: 375
活跃值: (12)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
21
楼主做的是奇迹外挂吧??

如果方便,我想要一份来研究下。。。。
2008-1-28 12:55
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
辛苦了,顶一下
2008-1-28 13:03
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
暂时搞不懂啊。顶楼主了。
2008-1-29 09:54
0
雪    币: 204
活跃值: (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
顶一下先,,
每次看楼主的帖子都能有新的收获。。
十分感谢!谢谢!向你致敬
2008-1-30 08:58
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
25
差点把这么好的文章错过了,边学边顶。。。
2008-1-30 09:56
0
游客
登录 | 注册 方可回帖
返回
//