CSK.Blog--个人原创Weblog

Sence Demo程序专用壳:kkrunchy

以前一向以为那些64kb intro常用的壳就是UPX或者就是UPX的farbrausch修改版本,后来发现原来有专用的了...

这就是kkrunchy,当然仍旧是farbrausch做得壳...

利用peid查看程序签名,会发现程序section只有一个,就是"kkrunchy"。并且只有这一个段了

下面是官方对这个壳的描述:

http://www.farbrausch.de/~fg/kkrunchy/

well, kkrunchy is a small exe packer primarily meant for 64k intros. it's relatively useless for anything else actually, because the depacker was relatively slow in older releases (about 1-2MB per second on my machine) and is dog slow in the newest version (about 90-120k per second for typical data on my p4 2.4GHz). kkrunchy also doesn't try to pack DLLs and can't handle exports or TLS (thread local storage) - as said, it's meant for 64ks.

据说是采用了PAQ7压缩算法,具有很高的压缩比,不过代价就是上文中提到的“ slow in older releases “ 一秒钟内只能解压缩1-2MB数据,不过对于64kb intro这根本不会让用户察觉什么。

后来发现很多手头的demo都用了这个壳,当然有一部分是用demo引擎制作的,至少CONSPIRACY和farbrausch都在用它。还有一些小组织的手写demo作品最终也用了kkrunchy加壳。大家可以验证下~

我简单说下这个壳的一些特点

首先它采用了段合并,这也是为什么它加壳的程序都只有"kkrunchy"这个section的道理,要知道平时编译参数中的段合并一般是不提倡加上的,不过这的确对文件体积减小有积极作用,但未必所有程序都能这么干...

所以并不是所有程序都适合用这个壳来压缩的,同时由于段合并,资源(resource)的提取也造成了一定的问题。因为资源段也被合并了...

不过对于demo而言这不会带来什么问题...

当然如果把软件保护寄希望于它那就错了...我是用OllyICE直接用OEP定律就脱掉了...没费一点功夫...

好了,Sence Demo不只能停留在那些工具本身,从根本上去了解还是有必要的。今天介绍了这个罕见的壳希望能对大家有用~

编写QQ外挂插件的提示[4]

上一篇写得有点凌乱了,所以把前面的内容再重写下....

2.编写QQ显IP插件

2.1 编写加载外挂dll的程序

这里采用VC作为开发环境,我使用的是VS2005

首先说下大体的思路:

这里仿造coralQQ一样,将真正的外挂代码写入dll,然后编写一个exe文件去加载qq.exe,并把我们写得dll注入。

这一步在前一篇文章中已经给出了具体代码。

2.2 编写插件主体

感觉自己如果一涉及具体代码就回说不来话,所以这次就先谈思路,然后给出部分代码。

dll要做的事:

将我们前面分析过的关键API挂钩,以便得到IQQCore *,Uin,以及在qq聊天窗口弹出时进行捕获以便显示IP信息。

要做到上面的要求,首先就是要在dll加载后开始做API hook的工作。

不过这件事情不能在DllMain里面写,推荐的做法是在DllMain里面创建一个新的线程,线程的执行函数我们设为:WorkerProc(VC编写的话推荐用_beginthread创建这个线程,否则无法使用CRT函数),为什么不能直接在DllMain里面写我稍候分析

然后就是在WorkerProc里面写入具体的hook代码。

1.拦截QQHelperDll.dll中的IsLogin函数

前面分析过了,IQQCore *指针可以通过拦截这个API来获取。

这里我们采用的是《windows核心编程》中推荐的拦截API hook的办法(修改入口地址跳转相对他烦了些,而且我们这里只是想做hook):通过动态修改API调用者模块的IAT表,将原先API的入口地址替换成我们函数的。具体的替换代码我们就采用书中提供的了的ReplaceIATEntryInOneMod(见前一篇)。

现在要注意一个问题,我们用来替换原先API的函数必须和原函数采用同样的调用规范,这个IsLogin本身就是cdecl得,所以只要用个形参和返回值一样的函数取替换即可:

给出实现本功能的代码:

typedef int (*OrgIsLogin)(DWORD ptrIQQCore);

int PokeIsLogin(DWORD ptrIQQCore)
{
 global_ptrIQQCore = ptrIQQCore;
 return ((OrgIsLogin)(PROC)OrgIsLoginProc)(ptrIQQCore);
}

////下面代码在WorkerProc函数中///

  OrgIsLoginProc = GetProcAddress( GetModuleHandleA(QQHelperDll.dll),?IsLogin@@YAHPAUIQQCore@@@Z);
  if (ReplaceIATEntryInOneMod(QQHelperDll.dll,OrgIsLoginProc,(PROC)&PokeIsLogin,GetModuleHandleA(qq.exe)))
  {
   //替换成功
  }

//

今后,只要QQ.exe调用IsLogin,我们的PokeIsLogin函数就会调用,并把IQQCore纪录下来,注意替换的函数要最后去调用原函数,否则就会让程序崩溃。

2.拦截SetForegroundWindow API

拦截该API是因为每次弹出新的QQ聊天窗口时,CQQApplication.dll都会去调用它,以便把聊天窗口至于前景显示。所以拦截CQQApplication.dll对他的调用就能在由新的聊天窗口出现时调用我们插件的代码去显示IP信息,而不必傻傻的去写循环等待了

这里就要注意SetForegroundWindow 是采用stdall调用规范的,所以别忘在替换函数名前加上__stdcall(或WINAPI宏)标记。

该部分的替换代码如下:

typedef BOOL  ( __stdcall *OrgSetForegrandWindow)(HWND hWnd);

extern C  BOOL  APIENTRY OnQQWndShow(HWND hWnd)
{

bool trueResult = ((OrgSetForegrandWindow)(PROC)OrgFuncProc)(hWnd);
 return trueResult;

}

//下面代码在WorkerProc函数或由其调用的函数中

OrgFuncProc = GetProcAddress( GetModuleHandleA(user32),SetForegroundWindow);
  if (ReplaceIATEntryInOneMod(user32.dll,OrgFuncProc,(PROC)&OnQQWndShow,global_hCQQAppModule))
  {
//替换函数入口成功   

  }

其中global_hCQQAppModule是CQQApplication.dll在qq.exe中的模块句柄,可以调用GetModuleHandleA(CQQApplication.dll)来实现。不过现在存在一个问题

用od加载qq.exe就会发现实际上CQQApplication.dll并不是在qq.exe启动后加载的,而是在登录以后。所以如果我们的dll插件在被加载之后立刻调用GetModuleHandleA的话就会返回NULL,那么之后的函数替换就不可能实现了。

这里我用了个比较笨的办法,在替换SetForegroundWindow前编写循环不断的去掉用GetModuleHandleA,直到返回非null,而为了防止频率过快可以在循环中加上Sleep函数。(之前也尝试loadlibrary提前加载,但一直失败。还有中办法就是从前面的IsLogin来判断是否登录了QQ。但没有试验过。总之如果你有比较好的办法也希望告诉我)

这部分的代码如下:

bool WaitforLogon()
{
 while(!bIsDllUnload)
 {

  global_hCQQAppModule = GetModuleHandleA(CQQApplication.dll);
  if (global_hCQQAppModule) return true;
  Sleep(300);
 }
 return false;
}

这就是为什么前面说过不能再dllmain里面作函数替换的工作了,否则会导致dllmain无法退出,从而会锁死整个qq

3获取Uin

现在IQQCore *已经获得了,同时只要在OnQQWndShow中写入得到用户IP信息的代码,再使用FindWindow的方法把原先的广告去除,再创建个Edit或者Static来显示我们的数据即可。

但之前还要得到Uin,也就是对方好友的QQ号。

其实这里有个很笨的办法:QQ聊天对话框中有对方的号码的:比如“&heaven(27605046)(后面是个性签名)。的确可以用FindWindow+GetWindowText获取,然后得到括号里面的数据就好了,但是是否有更简单办法呢?有

这里要感谢明日帝国(sunwangme)的教程,这里就是用他的方法了,具体原理还是大家去他blog看吧(google一下)

大体的方法是:在QQ准备显示聊天对话框时,上面“&heaven(27605046)(后面是个性签名)这段文字会调用位于QQBaseClassInDll.dll中的CAllInOneStatusBar::SetUin(unsigned long);这个函数,其中参数就是我们要的QQ号了。而且可以保证CQQApplication.dll仅仅在要显示对话框前才会调用它。(再次感谢明日帝国)

所以和上面一样,这次拦截CAllInOneStatusBar::SetUin(unsigned long);

OrgSetUINProc =

GetProcAddress(GetModuleHandleA(QQBaseClassInDll.dll),?SetUin@CAllInOneStatusBar@@QAEX_J@Z);

  if (ReplaceIATEntryInOneMod(QQBaseClassInDll.dll,OrgSetUINProc,(PROC)&Poke_GETUIDA,global_hCQQAllInOne)){

}

今后就会先调用我们的OrgSetUINProc,其中获取参数即可。

不过要注意2个问题,第一这个QQBaseClassInDll.dll也不是一开始加载,更不是在登录后加载,而是在第一次要显示QQ聊天窗口才加载,不过比较幸运的是可以直接LoadLibrary把它先载过来。

还有一个问题就是SetUin是thiscall规范的……哎,自己对thiscall还不是很了解,所以怕出错,那个OrgSetUINProc只能用naked调用规范了,同时要自己写汇编去完成细节的事:

__declspec( naked ) int Poke_GETUIDA()
{
 _asm
 {
 
   push ecx
   mov ecx,[esp+8]
   mov dwRecentUINA,ecx
   pop ecx
   jmp OrgSetUINProc
 }
}

ok,这样一切都完成了

3.编写获取IP信息的代码

先整理下上面我们3个替换函数的执行顺序:

PokeIsLogin:最好执行,且今后不断被调用

Poke_GETUIDA:在将要显示QQ聊天窗口时执行

OnQQWndShow:在Poke_GETUIDA之后运行。

所以可以保证在OnQQWndShow中可以得到我们获取IP信息所有必要的参数了。

那么就开始编写获取IP的代码:

按照前面分析的,先用BasicCtr.GetFriendQQData得到当前好友的IQQData *:

 DWORD MainHandle;
 if (ptrBasicCtr_GetFriendQQData==NULL || global_ptrIQQCore==NULL) return 0;
 _asm
 {
  
  mov edx,dwID
  mov eax,global_ptrIQQCore
  lea ecx,MainHandle
  push ecx
  push edx
  push eax
      
  call ptrBasicCtr_GetFriendQQData                                   ; BasicCtr.GetFriendQQData

  add esp,0xC

 }

其中dwID是Uin,即用DWORD保存的QQ号码

global_ptrIQQCore就是前面获得的IQQCore *

ptrBasicCtr_GetFriendQQData 是GetFriendQQData的入口地址,用GetProcAddress得到

最终MainHandle将保存IQQData *,如果运行失败,会返回null

接下来就是通过QQUSER_DYNAMIC_DATA(暂时命名)函数来得到动态信息类的指针:

char *szQQUSER_DYNAMIC_DATA = QQUSER_DYNAMIC_DATA;

DWORD tmpInfo;
 DWORD returnVal;
 tmpInfo = 0xba863a1e;
 if (mainHandle == NULL)
 {
  return NULL;
 }
 _asm
 {
  mov eax,mainHandle
  lea edx,returnVal
  push edx
     lea edx,tmpInfo
  push edx
  mov ecx,[eax]
  push szQQUSER_DYNAMIC_DATA
  push eax
  call [ecx+54h]
 }

结果将保存在returnVal中,同样,如果执行错误returnVal=NULL

最后就是去获取IP地址了

char *szwProcotol = wProcotol;
char *szRecentip=dwRecentIP;
char *szwRecentPort=wRecentPort;
char *szdwC2CIP=dwC2CIP;
char *szwC2CPort=wC2CPort;
char *szdwIP=dwIP;
char *szwPort=wPort;

bool GetDestIPInfo(DWORD ptrClassHandle,DWORD *ptrDestIp,DWORD *ptrDestPort)
{

 
 if (ptrClassHandle==NULL || ptrDestIp==NULL || ptrDestPort==NULL) return false;
 //Using Std Info Buffer
 _asm
 {
  pushad
  pushf 
  mov eax,ptrClassHandle
  mov ecx,[eax]
  mov edx,ptrDestIp
  push edx
  push szRecentip
  push eax
  mov eax,[ecx+34h]
  call eax

  mov eax,ptrClassHandle
  mov ecx,[eax]
  mov edx,ptrDestPort
  push edx
  push szwRecentPort
  push eax
  mov eax,[ecx+30h]
  call eax
  popf
  popad  
 }
 (*ptrDestPort) &= 0xFFFF;
 if ((*ptrDestIp) != NULL && (*ptrDestPort) != NULL) return true;
 
 _asm
 {
  pushad
  pushf 
  mov eax,ptrClassHandle
  mov ecx,[eax]
  mov edx,ptrDestIp
  push edx
  push szdwC2CIP
  push eax
  mov eax,[ecx+34h]
  call eax
  mov eax,ptrClassHandle
  mov ecx,[eax]
  mov edx,ptrDestPort
  push edx
  push szwC2CPort
  push eax
  mov eax,[ecx+30h]
  call eax
  popf
  popad  
 }
 (*ptrDestPort) &= 0xFFFF;
 if ((*ptrDestIp) != NULL && (*ptrDestPort) != NULL) return true;

 _asm
 {
  pushad
  pushf  
  mov eax,ptrClassHandle
  mov ecx,[eax]
  mov edx,ptrDestIp
  push edx
  push szdwIP
  push eax
  mov eax,[ecx+34h]
  call eax
  mov eax,ptrClassHandle
  mov ecx,[eax]
  mov edx,ptrDestPort
  push edx
  push szwPort
  push eax
  mov eax,[ecx+30h]
  call eax
  popf
  popad
 }
 (*ptrDestPort) &= 0xFFFF;
 return ((*ptrDestIp) != NULL && (*ptrDestPort) != NULL);
 
}

ptrClassHandle是前面得到的returnVal,IP地址的DWORD数据和WORD的port信息将保存在后2个参数指针的地址中。(代码借鉴了CoralQQ)

到目前为止已大功告成!其他的细节代码就请各位发挥吧

4.扩展

上面并没有介绍如何得到对方QQ版本的信息,其实和获取IP一样,你在CQQApplication.dll中找到wProcotol的字符串参考,就会发现它和获取IP的代码很像,直接抄下来用就是了

CoralQQ还能在鼠标移动到好友头像上弹出的信息卡片下方显示IP,其实机制是一样的,这里就不说了,可以看看明日帝国的教程~

好了,我的教程就到此为止,希望能对大家有用~有什么错误希望能立刻指正

编写QQ外挂插件的提示[3]


前面说了一大堆的原理,现在终于能具体介绍插件的编写了。

2 编写QQ显外挂插件

2.1 插件存在形式

这里说的插件是编写一个外部的dll文件,至于为何要用dll我就不想多说了。QQ自身不支持插件特性,所以做出显ip外挂的可能无非有3

  • 直接修改QQ本身的程序文件->不具备版本无关性,容易引发法律纠纷
  • 使用外部exe进程->必须采用调试进程的办法,效率低且浪费系统资源
  • 编写dll文件让QQ加载->效率高,稳定

好了,现在就不讨论前面2种情况了。

2.2 如何加载dll

dll文件是不可能自己执行的,必须要又调用它的程序主动去加载。这应该是常识。那么如何让qq.exe去“主动”加载我们的插件呢?

同样采用外部插件的coralQQ,你会发现实际上它包含2个文件

coralQQ.exe和coralqq.dll

而平时点击第一个文件就是用来加载珊瑚虫版QQ的,但你千万别认为这个exe文件就是外挂的核心,核心是那个dll。

CoralQQ.exe实际上只做了一件事:加载qq.exe,然后把coralqq.dll注入到qq.exe的进程中去。

关于如何实现该方法我不多说了,可以参考网上关于珊瑚虫外挂原理的文章(当然实际上它没有介绍原理……)

将dll文件注入到程序的方法有2

1.首先通过CreateProcess创建进程,然后模拟windows加载一个dll的全过程,在加载程序主体

2.采用远程线程植入技术,即使用CreateRemoteThread

我们采用后者。

2.3 开始具体编写

2.3.1 插件加载程序

编写一个用于加载我们插件dll的exe,好比coralQQ.exe

其流程伪代码:

int WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){

pinfo=CreateProcess(<加载qq.exe>);

if (hProcess){
HANDLE processHandle;
DWORD Exitcode;
processHandle=pinfo.hProcess;
HANDLE hThread;
char szLibPath[MAX_PATH];
void* pLibRemote;
DWORD hLibModule;
HMODULE hKernel32 = GetModuleHandle(TEXT(Kernel32));
strcpy(szLibPath,<插件名称>);

pLibRemote = VirtualAllocEx( processHandle, NULL, sizeof(szLibPath),MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( processHandle, pLibRemote, (void*)szLibPath,sizeof(szLibPath), NULL );
hThread = CreateRemoteThread( processHandle, NULL, 0,(LPTHREAD_START_ROUTINE)GetProcAddress( hKernel32,LoadLibraryA ),pLibRemote, 0, NULL );
WaitForSingleObject( hThread, INFINITE );

GetExitCodeThread( hThread, &hLibModule );
CloseHandle( hThread );
VirtualFreeEx( processHandle, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
}
else
{
MessageBox(NULL,TEXT(Err,Cannot Load qq.exe),TEXT(Err!),MB_OK);
}}

该部分的代码实际上是通过CreateRemoteThread将LoadLibraryA(<插件dll文件名>);语句注入了qq.exe执行。这样就做到了qq主动加载我们插件的目的。

2.3.2 编写具体插件

这里部分参考了目子版qq的方法。我们拦截CQQApplication.dll中对user32.dll SetForegroundWindow API的调用来判断QQ聊天对话框弹出的时机,以便显示IP信息。

主要的思路是:

DllMain函数:

创建一个多线程(VC环境推荐采用_beginthread这个crt函数,否则将无法在新创建的线程中调用crt函数)。新创建线程的函数名比如为workproc,他将在我们dll插件被植入qq.exe后开始执行

workproc函数:

主要的功能就是去修改qq.exe内部程序,使得我们能够拦截相关的函数,比如以前提到的获取IQQCore和Uin的函数,以及上面说的SetForegroundWindow 函数。

所谓API函数拦截前一篇文章已经说过了大致的方法,这里我们采用《windows核心编程》中推荐的ReplaceIATEntryInOneMod函数。为了方便,我把函数代码给出:

bool ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew,HMODULE hmodCaller)
{
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hmodCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,
&ulSize);
if (pImportDesc == NULL)
{
return false;
}

for (;pImportDesc->Name;pImportDesc++)
{
PSTR pszModName = (PSTR)
((PBYTE) hmodCaller + pImportDesc->Name);
if (lstrcmpiA(pszModName,pszCalleeModName)==0)
break;
}

if (pImportDesc->Name == 0)
{
return false;
}
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
((PBYTE)hmodCaller + pImportDesc->FirstThunk);
for (;pThunk->u1.Function;pThunk++)
{
PROC *ppfn = (PROC *)&pThunk->u1.Function;
BOOL fFound = (*ppfn == pfnCurrent);
if (fFound)
{
HANDLE hProcess = GetCurrentProcess();
DWORD oldAttr;
VirtualProtectEx(hProcess, ppfn, sizeof(pfnNew), PAGE_READWRITE, &oldAttr);
if (WriteProcessMemory(hProcess,ppfn,&pfnNew,sizeof(pfnNew),NULL)==TRUE)
{
VirtualProtectEx(hProcess, ppfn, sizeof(pfnNew), oldAttr, &oldAttr);
return true;
}
else
{
VirtualProtectEx(hProcess, ppfn, sizeof(pfnNew), oldAttr, &oldAttr);
return false;
}

}
}
return false;
}

函数的作用是将所用在hmodCaller句柄指向模块中对pszCalleeModName指向文件名dll中提供的入口地址在pfnCurrent的函数的调用,用pfnNew指向的函数去替换。也就是说原先要调用pfnCurrent函数的,现在就会执行pfnNew指向的函数。

要拦截上面说的SetForegroundWindow,就用如下代码:

OrgFuncProc = GetProcAddress( GetModuleHandleA(user32),SetForegroundWindow);
if (ReplaceIATEntryInOneMod(user32.dll,OrgFuncProc,(PROC)&OnQQWndShow,global_hCQQAppModule))
{

//替换成功
}

其中global_hCQQAppModule是通过GetModuleHandle获取的CQQApplication.dll文件在qq.exe中的句柄。上面代码调用成功后,以后CQQApplication.dll中代码要调用SetForegroundWindow时,实际上将执行我们编写的OnQQWndShow函数。

现在我们看OnQQWndShow的申明:

extern C BOOL APIENTRY OnQQWndShow(HWND hWnd);

为什么要有extern C 和APIENTRY (也就是__stdcall)前缀呢?因为原先的SetForegroundWindow是采用stdcall调用规范的,如果替换函数的调用规范不同,将引发程序崩溃。

同时替换函数的参数也要和原函数一致。

经过这样的替换后,以后每当新弹出一个qq聊天窗口,我们的OnQQWndShow就会被执行,在其中我们就可以负责获取ip,并创建一个edit或者static窗口在qq聊天窗口上显示ip信息

OnQQWndShow函数:

前面已经说了它的作用,具体流程如下:

获取对应好友QQ号码

获取对应的IP信息

在qq聊天窗口,也就是函数hWnd参数指出的窗口中寻找窗口上的广告框,然后把它销毁,创建一个edit或者static窗口,显示ip信息。

最后调用原先的SetForegroundWindow函数(这步很重要,否则正常的代码逻辑会破坏)

---------------------------

不好,马上要熄灯了,就先提供目前版本的下载,还是相当简陋的东东,假期完善……

明天继续写第二篇:-P

http://www.csksoft.net/data/legacyftp/Products/Crack/OpenPugin_alpha.rar

 

编写QQ外挂插件的提示[2]

写教程是需要激情的,所以趁激情还在继续写……

发现自己没有把文章组织好,可能一开始看我写得会觉得头大,没事,最后具体讲编写插件时会好的……抱歉

上次最后说到了从调试的角度来看,如果要调用显示IP等信息的QQ内部函数,关键问题就是通过调用

1.3 IQQCore和Uin

int GetFriendQQData(struct IQQCore *,unsigned long,struct IQQData * *);

这个函数,从而获得那个struct IQQData *指针。但问题就是要调用这个函数必须要提供2个参数:IQQCore *和一个unsigned long(DWORD)的神秘数据。

在开始正式分析前请各位思考下,如果要你编写一个能显示好友IP的函数,你需要先知道什么呢?

至少需要知道要去获取哪个QQ好友吧。这个肯定是必须的,否则函数就没有执行的意义了

现在我们跟踪下上面这个GetFriendQQData函数。在其入口点下断点。然后小心的把鼠标移动到QQ好友列表中某个头像上(需要使用CoralQQ……有点不厚道)。这时候应该程序就会被断下。

因为正常理鼠标移至好友头像会显示信息卡片,CoralQQ会在下面显示IP信息,所以按照上一篇文章反汇编的代码,GetFriendQQData必然会调用。我们从堆栈里面找到这个unsigned long对应的数据:

0x1A53836

因为是DWORD数据,把它转化为10进制看看:27605046

呵呵,这不是我的QQ号码么……的确,先前鼠标是移动在我的头像上了。

所以可以猜测这个unsigned long就是好友的QQ号码。

 

经过多次验证,的确如此。

所以,这个神秘的unsigned long明确:他是要获取好友信息的号码,顺便补充下,这个unsigned long在QQ中可是有专门名字的:Uin

接下来就是struct IQQCore*,我想他的作用从名字中应该就能猜出大概来。虽然具体他的结构我还没弄清,但可以肯定他好比是QQ程序内核信息的指针。而现在最关键的问题是如何去获得它。

如果你研究过BasicCtrlDll.dll中导出的函数,你会发现几乎一半的函数的参数都由这个IQQCore,比如:

int GetCurrentStatus(struct IQQCore *,int *)

int GetCurrentUin(struct IQQCore *,unsigned long *)

int GetFriendStat(struct IQQCore *,unsigned long)

那么我们就拦截其中的一部分函数,看看提供给他们的这个struct IQQCore *参数具体是什么。

如果你的确这样做了,那么会发现所有的函数,无论在什么时候,这个struct IQQCore *的值是确定的唯一的。如果你这个IQQCore *指针的地址区域下内存写入断点的话会发现struct IQQCore *实际上在QQ进行登录初始化时就创建了,以后就不再被修改。

所以现在的问题就很简单了,我们可以暂时不用理会struct IQQCore *到底是什么,只要能获取到他就ok

1.4 如何获取struct IQQCore *?

如果只是调试个QQ,得到struct IQQCore *是非常容易的,但记住我们是要编写外挂。所以就是说我们要问:外挂如果通过程序来获取这个指针呢?

最野蛮的办法:把外挂写成一个调试器,模拟手工调试的过程,获得这个IQQCore *。ok,我很佩服你这样做,这也是我原先的想法。虽然写这个一个调试器是很简单的,但是他基本上没有实际意义,因为不能应对各种版本的QQ程序,而且也就无法再使用OD这些调试器来调试你的程序了

下面的方法要感谢明日帝国(sunwangme)写的教程了,可能一开始你看他教程会不知所云,但相信你现在去看他的文章就会很有感触。

上面说过这个IQQCore 是不会改变的,而且BasicCtrlDll.dll导出的那么多函数又偏偏要用到他,为什么不去拦截一个有IQQCore *参数的函数来获取这个IQQCore *呢?

具体的做法我会在编写插件时说明。可能你会想拦截导出函数(也就是API)不也是调试器作的事么?其实也有别的办法,这里就是用API Hook技术来实现的(建议先了解下win32的hook技术)。

问题是API SetWindowsHookEx是不可能hook一个API的。所以这里要用比较“底层”的办法:

一个导出函数的入口内存地址可以用GetProcAddress API获取,我们只要修改程序的代码,使得他在原先函数入口点执行时跳入我们的函数取执行,然后再跳转回来即可。(实际做法不是这样,在说明如何编写插件时我会说到)

现在问题就是要在BasicCtrlDll.dll导出函数中选取一个比较理想的函数取拦截,得到IQQCore

要拦截的函数应该具有如下特点:

  • 函数形参简单,最好只有IQQCore *一个参数
  • 函数能尽早被调用,这样能及早的获取IQQCore *
  • 函数不能是thiscall规范的,也就是说函数必须是全局函数,不是一个成员函数

为何要这些特点应该都能理解,我对最后一个做下说明,thiscall规范的函数还需要一个类的this指针地址,这会给拦截造成一定麻烦(今后就会遇到这样的情况,以后再讨论)。

最终我们选取的函数是QQHelperDll.dll中的一个导出函数:

int IsLogin(struct IQQCore *);

很满足我们的要求,而且用OD跟踪发现,他在QQ登录后就不停的调用,太爽了……

总结一下:要获取struct IQQCore *通过拦截API获取参数实现,我们拦截的函数选用了IsLogin()。

1.5 Uin和struct IQQData *

 现在还有2个问题要去研究,第一,在调用GetFriendQQData时候,Uin(就是那个unsigned long参数)如何确定呢?

这个问题要等到我介绍插件编写时在讨论,但可以先做下暗示,我们编写的插件是需要在打开和好友聊天的对话框以及将鼠标移动到好友头像上时,显示对方的IP信息,就第一个情况:QQ的聊天对话框里面不就有好友的QQ号码(Uin)么?第二个情况:虽然探出的信息卡片没有号码,但可以猜测QQ也是先需要获取相关信息的。

现在我们再说说这个IQQData *的作用,看看BasicCtrlDll.dll的一些导出函数:

long GetQQDataBuf(struct IQQData *,char const *,class CString &)

long GetQQDataStr(struct IQQData *,char const *,class CString &)

其中需要IQQData *参数,那么我们看看这些函数有什么作用呢?以GetQQDataStr在CoralQQ中的使用情况为例:

0056DAC4     57                       push edi
0056DAC5     68 DCBA5900      push CoralQQ.0059BADC   ; ASCII NAME
0056DACA     52                       push edx
0056DACB     FF15 44AB5A00  call dword ptr ds:[5AAB44]    ; BasicCtr.GetQQDataStr
0056DAE5     8B4424 24           mov eax,dword ptr ss:[esp+24]
0056DAE9     8D56 34               lea edx,dword ptr ds:[esi+34]
0056DAEC     52                       push edx
0056DAED     68 ECBA5900      push CoralQQ.0059BAEC   ; ASCII REMARK_REALNAME
0056DAF2     50                       push eax
0056DAF3     FF15 44AB5A00  call dword ptr ds:[5AAB44]    ; BasicCtr.GetQQDataStr
0056DAF9     8B5424 30           mov edx,dword ptr ss:[esp+30]
0056DAFD     8D4E 38            lea ecx,dword ptr ds:[esi+38]
0056DB00     51                       push ecx
0056DB01     68 FCBA5900      push CoralQQ.0059BAFC    ; ASCII COUNTRY
0056DB06     52                      push edx
0056DB07     FF15 44AB5A00    call dword ptr ds:[5AAB44]  ; BasicCtr.GetQQDataStr
0056DB0D     8B4C24 3C          mov ecx,dword ptr ss:[esp+3C]
0056DB11     8D46 3C              lea eax,dword ptr ds:[esi+3C]
0056DB14     50                       push eax
0056DB15     68 04BB5900       push CoralQQ.0059BB04    ; ASCII PROVINCE
0056DB1A     51                   push ecx
0056DB1B     FF15 44AB5A00   call dword ptr ds:[5AAB44]  ; BasicCtr.GetQQDataStr

这些代码是在获取IP信息后出现的,猜猜在做什么呢?NAME,COUNTRY,PROVINCE这些词汇来看,应该是在获取当前要显示ip好友的名字、国籍、省份。而具体的执行函数就是GetQQDataStr。

再结合这个函数的参数来看,IQQData *,很有可能就是存放着一个用户相关信息的结构

事实也是如此的,到目前为止编写QQ外挂插件的条件已经具备

--------------------------------------

下一篇开始介绍如何编写插件了,所以文章应该也会有趣些了

CSK版权所有,如需转载请告知作者

www.csksoft.net

编写QQ外挂插件的提示[1]

前一段时间研究了下QQ目前各种外挂的机理,包括著名的coralQQ。也大致写了个一样的东西,不过马上要考试了,所以还是等暑假完善吧……反正8月份就要来学校。

鉴于目前网上关于这方面的文章少之又少,一般能找到的应该就这下面3篇(由于可能涉及版权问题,我链接就不给出了):

a.木子版显IPQQ的制作教程

b.关于QQ外挂DLL的加载原理的分析

c.明日帝国(sunwangme)写的我是这样来做破解qq,做QQ外挂的系列

在开始我的分析前我简要对上面这些资料作下评价,首先我觉得如果你也想写个类似的外挂插件,他们的文章你是必看的,而且特别是你想真的写出什么有用的东西的话,明日帝国得文章一定要看,而且必须看懂(呵呵,你去看看就明白我的意思)。对于木子版的教程应该说是最早“公开”的资料了,很多人都是看了这个教程开始写自己的外挂的。但是他通过直接修改QQ来做显IP补丁,可能引起的法律问题不说(如果你只是自娱自乐的话),他不能适应不同版本的QQ,而且用户也不太能接受直接的修改,而且教程已经不能直接用于目前版本的QQ了。

第二个教程是做外挂DLL插件必看的,但是他丝毫没涉及显示IP的问题,只是简单介绍了DLL注入的问题,并对win9x环境下手动加载dll到进程空间作了分析。但是目前win9x已逐渐退出舞台,所以一般只要使用CreateRemoteThread即可。

好了,现在就开始我的分析过程。

第一部分:

1.1 主流的外挂插件如何获取IP和其他信息的?

 也许你会认为他拦截了底层的Socket通讯?当然不至于,但这样肯定是最有效的办法。

让我们换个思路:如果你现在需要和一个QQ好友传输文件或者进行语音聊天或者发送了图片或自定义表情。那么QQ必须知道对方的IP地址和端口信息,这样才能把数据传给对方。

所以,很有可能QQ内部已经实现了获取IP地址和其他信息的相关函数了。的确如此。这也是木子版QQ教程里面提到的办法,调用QQ内部的函数。

下面是截至QQ组件之一的CQQApplication.dll中的汇编代码:(建议先浏览木子版QQ的教程)

027832C7     8B45 F0     mov eax,dword ptr ss:[ebp-10]
027832CA     53             push  ebx
027832CB     68 38558302     push CQQAppli.02835538    ; ASCII dwIP
027832D0     50                     push eax
027832D1     8B08                 mov ecx,dword ptr ds:[eax]
027832D3     FF51 18            call dword ptr ds:[ecx+18]
027832D6     8B45 F0           mov eax,dword ptr ss:[ebp-10]
027832D9     53                   push ebx
027832DA     68 40558302    push CQQAppli.02835540     ; ASCII wPort
027832DF     50                    push eax
027832E0     8B08                mov ecx,dword ptr ds:[eax]
027832E2     FF51 14            call dword ptr ds:[ecx+14]

CQQApplication.dll通俗来说就是负责显示和实现QQ聊天窗口的模块。就是那些和xxx聊天中的窗口,所以这就是为什么要在其中寻找这样的代码的依据。

从上面的汇编来看,显然是调用了2个thiscall规范的函数,也就是我们所说的C++类成员函数。

2个成员函数的的大致形式是this->Func(void *ptr1,char *cmd,DWORD *ptr2);其中cmd就是上面dwIP、wPort这些字符串,而ptr2也很容易知道是函数返回值得存储指针。现在关键是要获取this指针,也就是ecx寄存器的数据和ptr1这个神秘指针的数据。

如果你有兴趣反汇编CoralQQ中相关的代码,也会发现与上面类似的调用部分。

这里暂时不深入这些函数的作用和那个cmd指针的细节,我们先来研究如何获取this指针和ptr2吧。

注意

027832DF     50                    push eax
027832E0     8B08                mov ecx,dword ptr ds:[eax]

这2段代码,也就是说ptr2获取了,那么this指针也可以得到。所以现在一切的关键就是找出ptr2的来历。这样我们就能很轻松的实现显示ip了。

2.2 神秘的ptr2指针

为了能更快的说明问题,这里就不厚道的引用CoralQQ.dll的汇编了~

0056D97F     51                             push ecx
0056D980     52                             push edx
0056D981     50                             push eax
0056D982     FF15 38AB5A00        call dword ptr ds:[5AAB38]  ; BasicCtr.GetFriendQQData
0056D988     8B4424 14                 mov eax,dword ptr ss:[esp+14]
0056D98C     83C4 0C                   add esp,0C
0056D98F     3BC3                       cmp eax,ebx
0056D991     0F84 03020000       je CoralQQ.0056DB9A
0056D997     57                             push edi
0056D998     895C24 14                mov dword ptr ss:[esp+14],ebx
0056D99C     8D5424 14              lea edx,dword ptr ss:[esp+14]
0056D9A0     52                             push edx
0056D9A1     68 50BB5900           push CoralQQ.0059BB50
0056D9A6     C64424 30 01           mov byte ptr ss:[esp+30],1
0056D9AB     8B08                           mov ecx,dword ptr ds:[eax]
0056D9AD     68 C8BA5900        push CoralQQ.0059BAC8   ; ASCII QQUSER_DYNAMIC_DATA
0056D9B2     50                            push eax
0056D9B3     8B41 54                 mov eax,dword ptr ds:[ecx+54]
0056D9B6     FFD0                    call eax
0056D9B8     8B4424 14             mov eax,dword ptr ss:[esp+14]
0056D9BC     3BC3                     cmp eax,ebx
0056D9BE     0F84 F9000000       je CoralQQ.0056DABD
0056D9C4     8B08                       mov ecx,dword ptr ds:[eax]
0056D9C6     8D5424 1C             lea edx,dword ptr ss:[esp+1C]
0056D9CA     52                       push edx
0056D9CB     68 ACA15900          push CoralQQ.0059A1AC       ; ASCII wProcotol
0056D9D0     50                             push eax
0056D9D1     8B41 30                  mov eax,dword ptr ds:[ecx+30]
0056D9D4     FFD0                      call eax
0056D9D6     8B4424 14              mov eax,dword ptr ss:[esp+14]
0056D9DA     8B08                      mov ecx,dword ptr ds:[eax]
0056D9DC     8D5424 10            lea edx,dword ptr ss:[esp+10]
0056D9E0     52                          push edx
0056D9E1     68 94A15900         push CoralQQ.0059A194    ; ASCII dwRecentIP
0056D9E6     50                         push eax
0056D9E7     8B41 34               mov eax,dword ptr ds:[ecx+34]
0056D9EA     FFD0                   call eax

以上代码正式coralQQ 4.5版获取IP信息的片断。我们只需要关注上面的0056D982和0056D9B6地址的2个调用函数。

为什么这样说了,先看下面获取dwRecentIP数据的代码,它和上面提到的那个成员函数是属于一个类的(这里没提供出完整代码,你可以自己验证下:-P)。那么这里的this指针从哪里来呢?

0056D9DA     8B08                      mov ecx,dword ptr ds:[eax]

0056D9D6     8B4424 14              mov eax,dword ptr ss:[esp+14]

按照thiscall规范,ecx就保存了this指针,上面代码说明ecx是来自[esp+14]的,我们在往上看:

0056D99C     8D5424 14              lea edx,dword ptr ss:[esp+14]
0056D9A0     52                             push edx
0056D9A1     68 50BB5900           push CoralQQ.0059BB50
0056D9A6     C64424 30 01           mov byte ptr ss:[esp+30],1
0056D9AB     8B08                           mov ecx,dword ptr ds:[eax]
0056D9AD     68 C8BA5900        push CoralQQ.0059BAC8   ; ASCII QQUSER_DYNAMIC_DATA
0056D9B2     50                            push eax
0056D9B3     8B41 54                 mov eax,dword ptr ds:[ecx+54]
0056D9B6     FFD0                    call eax

看到么0056D99C lea edx,dword ptr ss:[esp+14]!!

也就是说this指针和ptr2时由这个函数获得的,我们暂时以它的一个参数命名:QQUSER_DYNAMIC_DATA。

但不幸的是,这个函数同样也是thiscall调用规范的,也就说也是需要得到this指针……不过不慌:

0056D97F     51                             push ecx
0056D980     52                             push edx
0056D981     50                             push eax
0056D982     FF15 38AB5A00        call dword ptr ds:[5AAB38]  ; BasicCtr.GetFriendQQData
0056D988     8B4424 14                 mov eax,dword ptr ss:[esp+14]
0056D9AB     8B08                           mov ecx,dword ptr ds:[eax]


注意上面2段代码,QQUSER_DYNAMIC_DATA函数的this指针最终是[esp+14],而esp+14的数据是

0056D97F     51                             push ecx

这段代码压入的。所幸的是GetFriendQQData是个导出函数(位于BasicCtrDll.dll),我们看看他的申明:

int GetFriendQQData(struct IQQCore *,unsigned long,struct IQQData * *);

上面这个push ecx实际上是压入了参数struct IQQData * *。

所以现在的只要获得struct IQQCore *,和第二个神秘参数的含义就能实现显示IP的功能了。

---------------

好了,快熄灯了,也累了,今天就到这里。

下回将说明IQQCore 的具体含义和如何去获得,以及第二的神秘参数的作用,以及IQQData 的含义。同时具体介绍如何编写一个具有实际意义的外挂dll插件。

CSK版权所有,如需转载请告知作者

www.csksoft.net

我写的TCP/IP教程

这是明天(2006.3.14)要在协会中做的讲座的PPT。目的很明确,因为这周日他们网管部要笔试,所以协会就趁这个时机办次辅导讲座。加上自己好久没亲自做讲座了~

这个讲座的题目叫做“互联网的故事”(好土的名字~~哎,我的语文水平就这么些),其实说白了就是此网络基础知识讲座。

加上以前和网络部有过一段不太好的经历,所以基本上我本人是和他们对着干的。

TCP/IP和网络方面的知识,比如那个人人看了都会头痛的OSI模型……所以我也没期望明天的讲座会如何如何,现在最担心的是没人去,要知道上次作亲手灭毒宝典时,协会宣传失误,弄得我差点气死……

这个讲座我认为最大的优势是直观性,因为每个概念点我都会有具体的演示和实践:用IRIS修探器抓包给他们看。同时会涉及一些黑客技术。

同时自我认为还是把其中相关知识的来龙去脉说清楚了,当然也有为了应试而专门整理的知识点。

里面的内容虽然算不上原创,但有些解释和归类和图片应该还是我自己独创出来的。

不过里面估计还是会犯一些错误的,所以请各位多多包涵,有问题直接留言提出,呵呵

下载地址:http://www.csksoft.net/data/legacyftp/Article/Presentation/internets_story.rar

注:我保留本文件的版权,请不要擅自传播。否则以后就不会公开提供这类信息了。

 

利用动态修改API函数创建“同名”文件及其利用

作者该文章保留对文章的版权,转载时请注明出处。 文章中需要WinFileKiller工具,你可以在我的blog:blog.csksoft.net找到说明文章和下载地址 工具下载地址:[url]http://www.csksoft.net/blog/post/11.html[/url] 不要被标题那拗口的文字弄晕了,不过用这种办法可以做很多事情哦~~ 首先要从和一个朋友的对话说起:他曾经在用FlashGet下载文件时候突然发些在桌面上产生了类似于这样的两个文件 download.rar download.rar. 注意第二个文件名后面有一个点"."。我一开始也没觉得有什么大不了的,但后来他对我说这两个文件中只能删除其中一个,假设删除了"download.rar."。这是奇怪的事情发生了:留下的“download.rar”或自动更名成为“download.rar.”。然后就删不掉了。 我不知道为什么FlashGet会产生这样的文件,但当时我的朋友正苦于想办法删除那两个文件,于是我想到了以前发布过的WinFileKiller,就是那个用来创建con.txt的工具(请参见[url]http://www.csksoft.net/blog/post/11.html[/url]),毕竟那个是通过修改内核进行工作的,可能管用,于是就传给他,用里面的删除功能。果然有效!文件被删掉了。 后来经过我研究,WinFileKiller还可以创建这样的文件:即文件名以"."作为结尾。同样这样的文件是用正常办法无法删除的。 不过如果问题就仅仅如此简单那也就罢了。下面就来说说这个以"."结尾的文件的一些有趣的问题: 除了上面所说的无法删除和自动更名以外,如果你在创建一个前面文件名字相同,但没有最后的"."的文件,比如: file.txt file.txt. 你会发现它们2者均能正常访问,如果用记事本修改其中一个的数据,那个打开另外一个文件时,会发现显示出来的数据是相同的! 当然还有更有趣的现象,那就是能创建出“同名”的文件(对于这个的解释后面会详细说明) 这是在windows explorer里面显示的情况: 上面的图绝对不是我处理出来的哦。其实只要在explorer里面把test1.txt.改名为test1.txt即可。但我是给重名文件加上引号的,因为这种重名现象很不稳定,你只要刷新下explorer显示就会回到前面的状态了。 但我不是要重点说这个的,现在就来分析下产生这些现象的原因吧。 首先在explorer中是无法直接创建以"."结尾的文件的:比如我要创建"file.txt.",如果起先没有"file.txt"这个文件,那么当你在创建文件输入文件名"file.txt."以后,系统会自动为你改名,你实际就创建了"file.txt"。对于原先存在"file.txt"的情况,当你要创建"file.txt."以后,系统就会提示你有同名文件存在。 可以说是系统把最后面的"."给略去了,这样正好能解释上面的现象。那为什么要略去呢?我们来研究下文件系统吧。 一般文件名分为标题名和扩展名两部分,这大部分人是知道的,比如上面的file.txt。他的标题名是file,扩展名是txt。这没问题,那么请问中间的"."属于什么呢?可能只能算是分割符吧。 但实际上文件系统中文件名是不保存分割符"."的,所以上面的file.txt在磁盘上其实就记录成下面的形式 file txt。其中空格可能是用一个0字节来将2部分分割开来了(当然本文不是要论述文件系统的,具体解释请参考资料)。 所以上面的“file.txt”,实际上那个"."是不记录在文件系统里面的,只是在显示的时候由文件系统负责加上去了而已。 知道了这点那么我们就来研究“file.txt.”这样的文件: 按照规定,扩展名部分是文件末端到由右向左出现的第一个"."位置的部分,如果没有出现".",则表示没有扩展名。 于是得出的结论是上面这个“file.txt.”是没有扩展名的。按照上面的说法,文件系统中他的记录形式可以是: file.txt<分割字节><空字符串> 也就是说最后面的"."是被去掉也是无所谓的。但他和“file.txt”实际上不是同名的文件。 但是我们知道除了文件系统内部,一般程序都是用以“.”作为分割符的文件名的,对于普通程序,由于略去了最后的“.”,“file.txt.”和“file.txt”在字符串形式上就成了同名文件。 如果你打开了“file.txt.”,由于略去了最后的".",实际上最后访问了“file.txt”。这就是为什么修改了其中的一个文件,另外一个文件就会跟着改变的原因。 而对于文件的删除,由于2个文件的等效性,无论删除哪一个,实际上都是“file.txt”被删除。所以总会留下那个“file.txt.”,因此就会感觉是自动被改名了。 同样,如果再想删除留下的那个“file.txt.”,因为实际要删除的是“file.txt”,但这个文件已不存在了,所以系统当然就会报错,那也就无法删除了。 这样一来,上面的问题就解释好了,不过为什么系统会显示file.txt.而不把"."在显示中略去的原因我还没有弄清楚。 这里顺便说一下以前看到的建立带有"\"文件夹的办法,大家还记得创建的方法吗? md c:\aa..\ 为什么在文件夹后面要带上“.”。同时建立的文件夹也和我这里说的带有点的文件具有相同的性质!后来经过我反汇编CreateDirectoryW API发现,其中调用完RtlDosPathNameToNtPathName_U以后,没有对文件名正确性进行检查。这和我的WinFileKiller修改的目的一致:绕过了正确性检查。 而我尝试用WinFileKiller建立如下文件“file..\”。但失败了,“\”在RtlDosPathNameToNtPathName_U调用完毕以后就被略去了,在CreateDirectoryW 中也是如此(这是说的是WinNT内核下面的情况) 所以我猜测其实md c:\aa..\是建立了以“.”作为结尾的文件夹而不是先前认为的带有“\”。 呵呵,扯远了。 下面就来说说利用的问题。 接着上面说的“file.txt.”和“file.txt”。因为按照常规的操作,实际上都只是“file.txt.”这个文件被访问,所以“file.txt.”可以被认为是“中立”了。 但是如果我们想办法把数据写入到其中,在需要时在通过特殊手段读取出来不是很好玩吗? 比如我把很重要的数据注入“file.txt.”,又附上“file.txt”里面存着无关的数据。这样可以很好的保护自己的信息,别人即使打开“file.txt.”,那也是在看“file.txt”得文件,而要删除“file.txt.”,那也是删除了“file.txt”,呵呵,很有趣不是? 如果有种病毒能利用这个原理复制自己的话,那我想目前所有的杀毒软件都会失效^_^ 对于这种文件的制作和数据植入我已经在WinFileKiller里面实现了,具体办法可以看[url]http://www.csksoft.net/blog/post/11.html[/url]。对于写入数据其实就是用同样办法修改MoveFile API。 说下简单的文件注入: 启动了WinFileKiller以后,选择2:"copy a File".此时按照提示,现输入要注入数据的源文件路径,然后输入带有"."结尾的文件路径即可。 其实这只是利用了文件系统的一些运作机制而已,并无高深技术。 本文适用于windowsXP和win2k,理论上支持winNT内核系统。测试环境winxp sp2_RTM

[下载]你会创建c:\con.txt吗?windows文件系统漏洞

呵呵,正常来说带有con、prn、com1这样字眼的文件或目录是不能创建的(原因自己找),但我想到了以前在安全焦点的一篇文章,是教你创建带"\"的文件夹的。当时的方法是用控制台命令(如果你叫dos命令那是不标准的)mkdir csk..\这样的语法创建的。看来这是windows一个文件系统的漏洞了,没错…… 我后来就在想其中的原理,可能你会发现像上面的csk..\在创建后是csk.,而他实际被windows解释为访问mkdir csk.\的目录。看来有字符在创建时被略去了。而一次偶然机会我发现mkdir C:\con\是成功的,在c下面出现了c:\con文件夹,而且删不掉……呵呵,有一个bug…… ... ... 点击下载:ftp://FTP_visitor:visitor@ftp.csksoft.net/Public/Products/Crack/WinFileKiller.rar

[下载]windowsXP sp2 TCP并发数限制破解程序

似乎最近身边的人都在玩破解,我也不例外…… 如果你不知道我在讲什么那先听我解释,如果知道那就 jmp FAR PTR [下载] (呵呵,最近昏头了) 事情是这样的:如果你发觉自己机器自从装了XP sp2补丁后发现上网速度慢了,尤其是Bt、eMule、P2p这种软件的下载速度变得慢了,那很有就是我要说的这个原因。 简单的说,在sp2中,microsoft为了防止windows因遭受冲击波等病毒的攻击而造成的网络瘫痪,“好心”的将TCP/IP的并发连接数限制在十个(说的通俗点就是同...

[下载]去除时间间隔限制的QQ挂机程序

不知是谁出的主意,QQ多了一个当时看似无关紧要的功能:等级(或者称经验)。不过我估计一方面可能是为了针对当时的其他及时聊天软件的对策,因为网易Popo就有经验和等级这回事。然而Tencent聪明之处就在于他将QQ等级与一些原先只有会员(在我看来那是浪费钱啊~~)才能享有的功能挂钩起来,就比如自定义头像。 ... 不说废话了,文件在此! http://www.csksoft.net/data/cracked_qq_yfk.rar
分页:[«][1]2[»]

日历

<< 2015-6 >>

Sun

Mon

Tue

Wed

Thu

Fri

Sat

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

Copyright Shikai Chen 2000-2012. Powered By Z-Blog(CSK Modified)