CSK.Blog--个人原创Weblog

Flash中共享库、atttachMovie和#initclip

好久好久没写教程了~一方面觉得最近自己也没学什么很有用的东东,不过今天这个还是要说说说的。


你是否值得看此文?

如果你遇到了下面的问题,那么此文对你可能有参考价值:

1.想了解Flash里面库元件中“连接”(Link)属性里面的为运行时共享导出、共享库URL、为运行时共享导入以及文件导入菜单中打开外部库这些功能的作用和用法

2.想实现如何让许多swf文件公用同一个swf文件中的库元件(运行的时候)

3.想实现用attachMovie加载其他swf文件库中的元件

4.想知道AS代码#initclip块的具体内涵

5.在编写用attachMovie加载其他swf文件库中的元件时遇到了问题

写本文的原因之一就是我在写自己Flash网站是也遇到了相同的困难,要让ReformUI能在外部加载的swf文件一面也使用,涉及的主要方法虽然外面也有介绍,但很多细节是没有公布的

由于时间关系,我不想讲一下细枝末节的东西,关于运行时共享的基本概念,大家如果还有不明白的就看adobe的官方教程:http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=tn_14767

................... 点击标题阅读全文

编写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

ActiveX不再Active了……

标题说的有点夸张了,其实是M$的KB912945对今后IE的一些修改

据说是和专利纠纷有关,M$打算在不久后发布一个新的IE补丁,同时也将被IE7采用。这个补丁十分的荒唐:

After you install this update, you cannot interact with ActiveX controls from certain Web pages until these controls are enabled. To enable an ActiveX control, manually click the control.

大意是:在安装好本次更新后,除非你事先手动将页面上的ActiveX控件激活,否则无法和他们交户

直白点就是比如网页上的一个Flash游戏,你先要去点击他一下,让IE把它激活,然后开能开始进行正常操作,下面是装了这个补丁的IE的画面:

 

如果不做修改,以后我Blog上的那个Flash鼠标移上去是这样的,然后你必须去点一下激活它,而且如果页面上有3个Flash或者是MeidaPlayer控件或者是Java程序,那么每个都需要你去手动激活……

真不明白这样有什么好处……幸好只是阻断了与用户的交互,相当于调用了EnableWindow(hActiveXWin,flase);这样的API,插件的非交互性操作都是正常的,但每次要去点一下总是很不爽的。这个补丁在2个月内就会公开发表,所以还是早做准备为好

在MSDN上有一篇教开发人员如何应对此改动的文章,地址是:

http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/overview/activating_activex.asp

里面最有价值的就是可以用JScript来绕过IE的阻挡,无须用户手动激活插件,大致方法就是把Object或者Applet块用document.write动态写入,同时包含此语句的JS必须是外部的.js文件,如果是该页面内的(inline)代码就无效了。

当然你也可以专门写个函数放在外部文件里,页面内再调用这个函数,以便应对不同情况,省得每个flash都要写长长的document.write了。

下面是我写的一个函数,常用的设置都包含了,不需要的项目就留空

 function WirteFlashBlock(strURL,nWidth,nHeight,strBkColor,strID,strAlignMode,strQuality,strFlashVars)
{
 var embedTxt;
 embedTxt = <embed;
 if (strURL==null)
 {
  return;
 }
 embedTxt += src=+strURL+;
 document.write(<object classid=clsid:d27cdb6e-ae6d-11cf-96b8-444553540000 codebase=http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0);
 if (nHeight)
 {
  document.write( height=+nHeight+);
  embedTxt += height=+nHeight+;
 }
 if (nWidth)
 {
  document.write( width=+nWidth+);
  embedTxt += width=+nWidth+;
 }
 if (strID)
 { 
  document.write( id=+strID+);
  embedTxt += name=+strID+;
 }
 if (strAlignMode)
 {
  document.write( align=+strAlignMode+);
  embedTxt += align=+strAlignMode+;
 }
 
 document.write(>);
 document.writeln(<param name=menu value=false>);
 embedTxt += menu=false;
 document.writeln(<param name=allowScriptAccess value=always />);
 embedTxt += allowScriptAccess=always;
 if (strFlashVars)
 {
  document.writeln(<PARAM NAME=FlashVars VALUE=+strFlashVars+>);
  embedTxt += FlashVars=+strFlashVars+;
 }
 
 document.writeln(<param name=movie value=+strURL+ />);
 if (strQuality)
 {
  document.writeln(<param name=quality value=+strQuality+ />);
  embedTxt += quality=+strQuality+;
 }
 else
 {
  document.writeln(<param name=quality value=High />);
  embedTxt += quality=High;
 }
 if (strBkColor)
 {
  document.writeln(<param name=bgcolor value=+strBkColor+ />);
  embedTxt += bgcolor=+strBkColor+;
 }
 embedTxt += type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer  swLiveConnect=true ></embed>;
 document.writeln(embedTxt);
 document.writeln(</object>);
}

最后提醒的是,如果IE将“禁用脚本调试”的选项勾去掉了,那么还是不会起作用,但普通用户不太可能会去调试脚本的,所以也无所谓,而且M$也承诺在后续的更新中解决此问题:

External script technique does not work when the Disable Script Debugging (Internet Explorer) check box is cleared

Microsoft is investigating this problem and plans to fix it in a future cumulative update.

好了,继续作PRP去了……

我写的TCP/IP教程

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

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

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

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

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

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

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

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

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

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

 

ajax缺陷的解决和自动xml分析器

可恶……你现在看到的文章之前我已经写过几乎一样的一篇,但随着IE突然崩溃,我也只好重新打了一篇,也就是你看到的……

最近要同时开发PRP的“强人隧道”网站、法学院网站的第2期开发,同时要管理计协,当然还有学业。所以基本上时间要精确到秒来用了。不过周末还是能和gf稍微过一点悠闲的生活,哪怕那只有短暂的2小时。

那么这个blog似乎又要死下去了,不过我承诺过每周至少一篇文章,所以就把最近开发中对ajax的体会和一些作品发布出来吧。

首先允许我评论下这个目前正被捧得大红大紫的AJAX技术。如果你不知道他是什么就先去google以下,关于他的教程和介绍到处都是。

ajax并不是最近才有的,更不是有些人所说的在asp.net中附带而来的。她很早就被MS采用,大家看看msdn网站的那个树形目录,如果你展开一个分支,它就会“非同步的”去更新这个分支的内容。我想似乎也只有js+xml才能做到吧。而且在我上高一时,第一次上msdn就有这个功能了,我现在读大二,那么就算算这项技术出现了多少年吧……

那么为什么他现在如此的红火呢?我想其中一个原因是gmail,他的web管理界面就是彻底的ajax应用。google似乎正企图破坏微软帝国的神话,成为新一代霸主,他对新技术的使用自然是空前的。第二个原因就是企图用这个技术来达到Flash网站同样的效果。也就是不需要刷新页面来获取新内容。Flash中可以采用loadMovie方法来加载新的对象,同时也支持xml文报(我的ReformPost就是很好的例子)。我想比起asp.net中的采用,更多的可能应该是需要模拟出和flash具有同样效果的页面罢了。

不过ajax似乎并没有传说的那么十全十美。

首先

它需要浏览器支持,并不是所有平台和所有浏览器都能显示ajax页面,而且一但不支持,整个页面可能都无法显示。

第二个缺陷

由于它不需要刷新页面而获得新的数据,很多人认为这有违于利用URL来唯一定位资源的规范。因为同一个url指向的页面可以用ajax显示截然不同的数据。那么你如果需要把你正在浏览的信息给别人看的话,复制url给他显然就是没有用的。

不过我并不这样认为,首先这并不是ajax才有的问题,使用flash的页面也是如此。而且所谓“有违于利用URL来唯一定位资源的规范”是错误的。我见过很多聪明的flash网站已经做到了解决方法,下面我稍微介绍一下:

如果你原先采用静态页面,那么很自然,每篇文章都是和url地址挂钩的:

比如本文保存在:http://www.csksoft.net/blog/post/XML_Parser_and_comments.html

那么用url地址就能来访问本文。

现在我把文章保存在数据库,采用asp页面动态的显示本文,那么利用QueryString还是能用url地址唯一的去定义本文:

http://www.csksoft.net/blog/cmd.asp?act=tb&id=84

那么在ajax和flash网站的情况下,我们也可以采用类似于QueryString的做法:把上面的?改为#即可

众所周知,url字符串中#字符之后的内容都会在发送http请求时被略去,所以网页的书签就是在页面url后面加上一个以#为前缀的参数,这样一方面不影响服务器获取正确的参数,另一方面可以在客户端利用JS来获取#之后的参数。

那么,在今后的flash网站中,或者今后本blog采用了ajax,这篇文章也能采用如下的url地址获得了:

http://www.csksoft.net/blog/index.asp#act=tb&id=84

不过这个页面目前是不起作用的。

下面提供一个能从像上面url地址格式中提取像指定参数数据的函数,它本是action代码,相信稍作修改就能用于js。

使用和转载时请保留我的作者信息。

//from ReformCore::mainsite

//Copyrights 2005-2006 CSK,csk@citiz.net

function GetQueryString(strURL:String, strStringName:String):String {
if (strURL == undefined || strURL == ) {
strURL = _root._url;
}
var strQueryStub:String;
strQueryStub = strURL.slice(strURL.lastIndexOf(#)+1);
if (strStringName == undefined || strStringName == ) {
return strQueryStub;
}
var nSubPosA:Number, nSubPosB:Number;
strQueryStub = &+strQueryStub;
nSubPosA = strQueryStub.lastIndexOf(&+strStringName+=);
if (nSubPosA == -1) {
return ;
}
nSubPosA += length(&+strStringName+=);
nSubPosB = strQueryStub.indexOf(&, nSubPosA);
if (nSubPosB == -1) {
nSubPosB = strQueryStub.length;
}
return unescape(strQueryStub.slice(nSubPosA, nSubPosB));
};

 

如果要获取www.csksoft.net/mypage#id=3 中的id的内容,只要这样写:

 

var id=GetQueryString(www.csksoft.net/mypage#id=3,id);

用了上述的方法,这个缺陷自然也就不复存在了

第三个缺陷

是由于很多情况下需要对xml文档进行翻译,因而即使像获取服务器时间这样简单的功能,也要专门写xml分析代码来从服务器传回的xml中得到需要的时间信息。

如果flash或者ajax页面需要采用高级的xml文报实现与服务器进行更强大的RPC远程交互(类似于SOAP),那么就需要编写常常的xml分析代码。

对于ReformPost,如果需要获得主服务器的时间,客户端的发送的文报是这样的:

<ReformCorePost>
<Type Ver=1.0>generaPost</Type>
<PosterInfo type=desktop;fla>FlashMainSite</PosterInfo>
<Core_RPC>
<Name>GetServerTime</Name>
<args />
</Core_RPC>
</ReformCorePost>

ReformCore传回的xml文报是这样的:

<ReformCorePost>
<Type Ver=1.0>CmdResponse</Type>
<PosterInfo type=WebCoreServer />
<RPC_result>
<DTYPE>date;servertime</DTYPE>
<CurrentTime>2006-3-5 15:20:09</CurrentTime>
</RPC_result>
</ReformCorePost>

如果要实现上面的xml交互,首先客户端必须编写生成指定格式xml的代码,而对于每种请求xml的不同,也需要不同的代码,同时分析服务器返回的xml也需要相当多的代码来完成。

这样无疑是加重了ajax开发的复杂性和延长了开发周期。

我在开发PRP项目时写了一套函数,它可以做到下面的功能:

1.如果我要生成如下的xml文档:

<MyXML>
<MyItem>
<Item>a</Item>
</MyItem>
</MyXML>

里用接下来提供的函数,开发者只需要写如下代码:

var objXML,objArglist;
objArglist = new Object();
objArglist.MyItem = new Object();
objArglist.MyItem.Item = a;
objXML=ConstructXmlDoc(MyXML,objArguList);

这样,上述xml已经自动产生并保存在objXML中了。这样就免去了繁琐的CreateElements、appendChild之类的操作函数了。

2.如果服务器传回了下面的xml文档:

<ReformCorePost>
<Type Ver=1.0>CmdResponse</Type>
<PosterInfo type=WebCoreServer />
<RPC_result>
<DTYPE>date;servertime</DTYPE>
<CurrentTime>2006-3-5 15:20:09</CurrentTime>
</RPC_result>
</ReformCorePost>
假设采用objResponseXML保存这个文报,那么采用下面代码:
var objParsedXML;
objParsedXML = ParseXml(objResponseXML);
上述XML已经自动转化为等价的object类型,如果我要读取xml中CurrentTime字段的数据,只需用代码:
var strCurrentTime = objParsedXML.RPC_result[0].CurrentTime[0].value;
是不是简单多了?
这两个函数就是将Object对象中的成员数据和xml文档进行了互换,由于篇幅有限,其中的函数我就作为附件给出下载地址。具体的使用可以直接来询问我。对于asp版本暂时不打算公开
转载和修改时请保留原作者信息。
上述函数库js下载地址:
http://www.csksoft.net/data/legacyftp/Products/code_and_lib/reformcore_xmlparser.rar
好了,终于写完了

连载:《windows亲手灭毒宝典》之三

作为对曾经我提过的要写些教程的兑现,这里先把我在交大计算机协会作的讲座《windows亲手灭毒宝典》放上来。当然其中的内容比我实际讲的要多,且要难。
由于第一次写教程,加上自己水平有限,文中出现的问题希望各位及时指正,谢谢!
文章为CSK原创,转载请保留原作者和引用作者的版权信息。
CSK版权所有

---------------------------------------------------------------------------------
第二回的地址:http://www.csksoft.net/blog/post/killvirusDIY2.html

第三回:亲手杀毒的一般步骤

本文不需要你具有诸如程序开发等方面的专业技能,但如果有一定的经验可以帮助你更好的理解

如果你还没有看过前一篇文章,不要紧,但是本文是建立在你已经掌握前篇文章所提及知识的基础之上的,所以遇到不明白的可以参考前一篇

其实事情很简单,自然就是先找出那些病毒文件,然后将他们删除

但是硬盘上保存了那么多程序,哪些才是病毒文件呢?本文将告诉你一个快速确定并找出病毒文件方位的方法

由前文我们了解到,所有在windows环境中运作的病毒,一般都是以具体的文件形式存在的,并且往往是那些可执行文件。但是,单单是这些保存在硬盘上的文件还是不能起什么作用的。一个程序的运行必须是由系统将它们从磁盘的文件中读取出来,然后存放在内存中并加以执行。这个过程常被我们称作:加载。

病毒也是一种程序体,自然的,他也需要有系统事先加载到内存中执行才能做恶。当然这种加载有2种途径:

  1. 你可能不小心点击打开了一个病毒文件(你主动加载了它,往往是你第一次感染病毒的途径)
  2. 系统自动加载了它

自然,我们更关心第二种情况,因为你应该知道中毒的机器就算是重新启动,病毒还是照样会驻留在内存中运行(除非那个病毒自身也有缺陷……)这就是通过系统自动加载完成的。

作为病毒自然是希望一直在你机器中生存着,等待它发作的那一天……所以他肯定要告诉系统:每次启动的时候也加载我把~,然后为了让系统去加载他,病毒还会告诉自己文件保存的地点-文件路径

正因为这样,病毒就在我们的系统中留下了它的作案痕迹。我们的杀毒过程也就是从查找这些作案痕迹开始的。

所以,第一步就是:找到病毒在系统中留下的痕迹,从而找出那些可能的病毒

2.1.系统的备忘录-注册表

或许你很早就知道很多程序在系统启动时也会自己启动,比如你在使用的MSN Messenger或者QQ,他们在系统每次启动完毕后都会自己“弹”出来。

 

图:每次开机后你的QQ程序是不是会自己“弹”出来呢?

其实在这个过程中,那些该死的病毒也偷偷的进入你的内存开始运作了,只不过做贼心虚,不会“弹”出来说“喂,小样,我是病毒,嘿嘿,有种来杀我啊”之类的话

这些程序其实都是由系统自动加载运行的,那么windows就必须要有一张“清单”好使他在启动时仍然记得要去启动这些程序。而这里说的清单其实就是注册表

 或许你听过这个名字,而且可能对他有一种神秘的感觉。其实他的作用就上上面所说的那样:只是一个清单。用来记录一些系统需要记住的事,同时很多应用程序也用它来记录一些配置:比如IE会用它记录主页的地址。

不过我们这里只对其中一小部分感兴趣,那就是系统用来记录开机时需要启动哪些程序的地方

windows提供了一个程序来供我们察看和修改注册表,那就是regedit

 

图:注册表编辑器(regedit.exe)

你可以从[开始]菜单->[运行],输入regedit.exe启动他,如果系统提示找不到该文件,很不幸的,可能病毒已经删除它了:-<,如果这样你就需要从别人那里复制来一份。

regedit和资源管理器很类似,也提供了类似目录和文件方式的界面。其中系统把每一种清单保存在不同的目录下面,而具体清单的信息就是那些“文件”了。

那么系统每次启动时加载的程序清单在哪里呢?其中一个清单你可以根据下面的这个路径找到:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

你可能会看到这样的画面:

 

 其中最左边一栏是程序的名字,当然他们作用不大,而最右边的就是程序的路径了。系统启动后就会按照这张清单一次加载文件。

不过很不巧的时,其实病毒已经隐藏在了上面这个清单中了。或许你已经有所发现。你也可以看看自己注册表中的那些条目。

就上面这张图中,下面这些路径下的文件都可能是病毒:

  • AutoUpdate c:\windows\winsys.exe
  • Explorer c:\windows\system32\explorer.exe
  • (默认) c:\commond.com

首先,这里只能说是可能是病毒,并不能马上确定,但是为什么说这些文件的嫌疑最大呢?下面给出一些规则

  1. 在加载清单中大部分程序都是系统中安装的应用程序,而很少是系统自身的组件
  2. 由第一条得出,系统组件几乎不会出现在清单中
  3. 有第一条得出,清单中的程序并不是系统所必须的,也就是说即使不去加载他们,你的windows还是照样可以运行。
  4. 正常情况下,(默认)这个条目应该是空白的
  5. 病毒喜欢隐藏:多藏于windows目录之下或者是很简单的路径格式:如C:\virus.com。这样有利于其传播
  6. 为了伪装自己,目前大多是病毒喜欢将自己的名字伪造成系统中的一些组件名

所以对于第一次尝试手工杀毒的人来说,如果很难确定哪些是病毒的话不妨删除所有的清单条目(注意,那个叫做“默认”的条目是无法清除的,但你可以把它的内容删除)

那么为什么那些文件可能为病毒呢?首先我们看“AutoUpdate ”这个文件。第一从他的名字上,很多人会以为他是windows的自动更新程序。而且它的途径:windows系统目录下,又叫做winsys.exe(暗示你它是windows system的一部分),似乎他是个正常的程序?如果你这么想就是中了全套。按照上面给出的第2条规则,如果真的是“自动更新程序”,他不太可能出现在这个清单中(真正的自动更新程序是一个系统服务,具体会在今后的文章中论述)。那么这个家伙就非常可疑了

其次是explorer。或许你也会觉得这很正常,造成这种想法的原因可能是他正好是windows资源管理器的名字。而且细心的你可能发现每次系统开机的确会有个叫做explorer.exe的文件在运行(其实它是在其他地方加载的,今后的文章中你会知道,explorer.exe叫做系统外壳:shell,除了资源管理器的功能外,你的桌面也是他“变”成的)。但是真正的资源管理器是位于windows\目录下而非windows\system32\下。并且根据第二条规则,自然也就有很大嫌疑了

那么这个叫做(默认)项目为什么也会是病毒呢?其实注册表的每个目录下都会有一个(默认)的项目。它是注册表自动产生的。而根据规则第四条,这里的“默认”条目一般是留空的,所以马上就能确定c:\commond.com有很大嫌疑了。并且很高笑的是,这个程序的作者似乎想和以前DOS系统的命令行提示程序command.com取同样名字来欺骗我们。但是,他拼错了……

事实上,上面提到的的确就是病毒,不过这里只是我为了演示所以加进去的,但现实中如果你真看到了这样的项目,那么别犹豫,他们99%就是病毒或恶意程序!

接下来要做的就是先找到那些文件的位置,然后将他们清除即可,最后再删除注册表中的那些项目。不过为了预防万一,往往删除前我们还需要一个确认的过程。而且很糟糕的时,windows一项混乱的作风使得启动程序的清单并不是只有这一个,并且还有一类叫做系统服务的程序,他们也会自我启动。所以在下回中,我将告诉你所有的启动清单的地方,同时介绍系统服务的一些事情

不过60%-70%的病毒都是在上述的清单中加入自己的作案痕迹的,所以今后如果怀疑自己系统中毒那么先看看这里吧

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

但怎么来记住这么长的目录呢?下面给一个敲门:

  • HKEY_LOCAL_MACHINE表示本地系统
  • SOFTWARE记录的都是软件信息(区别于硬件的驱动信息)
  • Microsoft windows是微软公司自己的产品
  • Windows\CurrentVersion 当前版本的windows系统
  • Run 要运行的清单

最后附上一些清单中常见程序的说明

  • CnsMin:

Rundll32.exe C:\WINDOWS\DOWNLO~1\CnsMin.dll,Rundll32
3721中文实名hook的主进程,难怪一段时间被诺顿视为病毒

  • helper.dll:

C:\WINDOWS\system32\rundll32.exe C:\PROGRA~1\3721\helper.dll,Rundll32
3721上网助手,一个熊样……就是毒!

  • TkBellExe:

C:\Program Files\Common Files\Real\Update_OB\realsched.exe  -osboot
RealPlayer的广告客户端,可以del掉

  • ctfmon.exe:

C:\WINDOWS\system32\ctfmon.exe
M$别出心裁的为了配合office XP以上版本进行输入法监控(就是微软拼音)和文档检索用的监控进程

好了,这回就到这里,最后祝各位情人节快乐

CSK 2006.2.14

CSK版权所有,演讲ppt在ftp.csksoft.net中下载。

如何自动让你的blog和msn space同步内容

好东西自然不敢独享,于是我把ReformCore的这部分代码专门抽出来写了个插件,如果你有自己的空间,并且使用Z-blog([url]http://www.rainbowsoft.org/zblog/[/url]),那你直接就可以用这个插件并且按照此文的设置便可实现将你在blog上的文章自动发往MSN space。 不过我希望你在传播和修改这些文件时保留里面的原始作者信息,不但是我的,也最好能保留Z-blog的作者信息。 首先简要介绍下原理:其实我都不好意思说,因为比较没“技术含量”呵呵。 这以前能轻松实现要多亏MSN space支持通过发送给他email内容作为新发布的文章。如果你的网站空间支持通过编写脚本来发送邮件,那么只要修改下你使用的blog的代码,让他在你发表新文章以后自动发一份带有文章内容和标题的email到msn space的专门地址后便能做到自动更新MSN space了。 所以这里很遗憾的是如果你有自己的空间,但Blog仍旧是其他运营商提供的话,那仍旧没有办法实现的。 下面来看看MSN space这头如何设置: 1.进入space的管理页面,选择[设置]->[电子邮件发布]: 2.就像上图看到的那样,先把“打开电子邮件发布”钩上 3.填入你用来发送日志的email地址。这里要注意,如果你的空间附带了企业邮局,建议用它,外面服务上提供的email地址最好不要作为发送email。当然你也可以留一个自己常用的邮箱 4.填写机密字,其实只要胡乱填写一通便可,他只是简单的加载生成的用以接受你日志的email地址用户名后面罢了 5.选择"立即发布网络日志项"。这个不用解释了 6.记下那个"xxx.xxx@spaces.msn.com"的邮件地址,今后日志就是发到这里面去的,最好不要将他公布。 ok,MSN space的必要设置已经结束了,如果你在用Z-blog。那么只要把我写的插件覆盖到blog目录下,并且修改下那个"helper_mail_packer.asp"里面关于你email信息的配置就能使用了。在编写文章时,你会发现编辑页面多出了“将此文发送至MSN space”。把它钩上就以为这系统会把这篇文章发送到space上。 对于其他blog系统的朋友我就稍微说明一些注意点了。首先我推荐用CDO组件而不是Jmail。其中的原因是我原先使用Jmail一旦文章正文由中文字符,msn上就会显示乱码。我怀疑是编码不一致,但jmail把发信编码改为utf-8后发出的信件也成乱码了。但可能是我水平不够,所以你也可以尝试一下。 对于CDO组件唯一缺点就是有些人反映支持他的空间服务商不多,如果你的空间不支持那就只能用jmail了,至少发过去的标题是正常的。CDO的使用外面有很多资料,我就不多说了,同时这里提供的Z-blog的插件中发信时作为单独的函数提供的,所以也可以直接用里面的代码。 至于具体如何修改你的blog就看各位本事了,也可以问问这个blog的开发者,如果是自己做的那就更不用说了吧。 好了,下面是Z-blog的msn space同步更新插件下载地址: [url]ftp://FTP_visitor:visitor@ftp.csksoft.net/Public/Products/Misc/pug_msnspace_updater_by_csk.rar[/url]

连载:《windows亲手灭毒宝典》之二

前沿:作为对曾经我提过的要写些教程的兑现,这里先把我在交大计算机协会作的讲座《windows亲手灭毒宝典》放上来。当然其中的内容比我实际讲的要多,且要难。 由于第一次写教程,加上自己水平有限,文中出现的问题希望各位及时指正,谢谢! 文章为CSK原创,转载请保留原作者和引用作者的版权信息。 CSK版权所有 --------------------------------------------------------------------------------- 呵呵,上次第一篇还是很久前写的了~~ 第一回的地址:[url]http://www.csksoft.net/blog/post/7.html[/url] 第二回:进入正题 windows下亲手灭毒之完全解决方案 本文不需要你具有诸如程序开发等方面的专业技能,但如果有一定的经验可以帮助你更好的理解 1.感性认识的建立-病毒的文件形式和各自特征 所谓病毒,一般都是指可以执行的数据体,说白了就是那些exe,dll等程序文件,当然情况也许更复杂,程序这个概念是脱离与具体的文件形式的,他们只是一段数据而以,应该所谓的病毒可能包括与诸如txt文件中,但很少见(.txt就算包含病毒也是无法自我加载的)。 目前在win32环境下,常见的病毒是以exe;com;dll;scr等扩展名存在的。同时也能见到cmd;bat;vbs这类脚本性病毒(你可以了解些脚本script的知识)。 一般情况下,我们把.exe的文件叫做应用程序,这样说的原因一方面是因为他是可执行的,也就是无需借助其他程序而自我启动(严格的说都无法做到自我启动,这里就不涉及了)。对于病毒体,为了能在复制后马上感染侵占系统,它需要这方面的特征。 所以在下面的文章中,你会发现给出的病毒例子都是.exe文件 dll文件叫做“动态链接库”(dynamic link library),它的名字含义这里不再深究,不过你需要明白他是无法自我启动,也就是不可直接执行的。dll文件中同样也包含程序的代码,但他们是需要被其他可执行程序,如exe加载以后才能执行其中的代码部分的。
图:作为系统核心之一的user32.dll,正因为是dll文件,它能结合到每个程序进程,提供必要的系统支持
所以我们就知道,以dll格式存在的病毒无法直接运行,他们需要另一个如exe的程序事先加载后才能工作(有3种可供参考的方式,一是另一个exe程序也是病毒体,它直接加载dll文件作为自身一部分,第二种方式采用系统自带的rundll32.exe加载,第三种是比较讨厌的情况,dll文件开始又另一个exe文件主动加载后,利用被称为钩子hook技术将dll注入到其他的程序进程中。这用的病毒是最难清除的)。
图:在任务管理器中看到的rundll32.exe的进程实际起作用是加载了的dll文件
如果病毒主体以dll文件存在以后,他必须指明加载它的程序,这可能给其传播造成一定障碍,但有带来了很多优势。比如: 1.由于windows自带的进程管理器(WindowNT)只能以主进程文件为单位察看进程,可以认为是只能看到正在运行的exe文件,而一般看不到正在执行的dll文件(因为dll是exe加载的,它映射到了exe为进程的地址空间了)。所以一般在没有第3放工具的情况下,是无法通过任务管理器找到正在运行的dll文件病毒的。 2.无法直接将正在运行的dll文件病毒关闭,这样说是因为dll文件都映射到了加载它的exe文件中了,利用进程管理器只能将它属于的进程程序一起关闭。比如word因中毒而加载了virus.dll病毒的文件体,那么想从内存中清除病毒只能把word也关闭了 3.利用上面的特点,可以做到病毒体永远驻留内存而无法清除。其实方法很简单,利用钩子技术,将dll注入到系统所有的进程中,同时这些dll监控着每个进程是否被自己注入,如果没有则重新注入。这样除非关闭所有程序,否则永远无法关闭运行中的病毒。
图:采用PEid自带的任务察看器,可以发现实际上所有进程都加载了其他的dll文件。而且无法把其中莫一个dll关闭
当然还有更极端的情况,那就是利用驱动程序来编写病毒(几乎没有这种情况,所以你可以跳过)。 首先这里说一下x86保护模式的事情。你应该知道目前你正在运行windows的CPU工作在成为32位保护模式的环境下。你不用被这个神秘的名词吓倒,他其实就是一种等级管理机制:程序在运行时有ring0和ring3的2种权限,ring0程序拥有很高的权利,它能操作计算机所有的硬件设备,而ring3程序则十分可怜,他只能乖乖受ring0程序管理,同时基本上无法直接对硬件进行操作,而必须通过ring0的程序中转。 这就是windows中各类程序的现状:操作系统的内核、一些服务程序、驱动程序都是ring0级别的,他们能对你的电脑做任何能做的事情,而一般意义上的程序,如exe文件的程序都是ring3的。 这样做一方面是为了实现多任务环境,同时更重要的是能使系统运行的非常稳定:ring3程序无法直接控制硬件,必须通过ring0程序,这样如果有个设计有缺陷或者不怀好意的程序企图进行破坏性操作时,他就能被ring0程序截获并强行中止。 所以可以知道,如果病毒写成了一个驱动程序(ring0级别),那是很危险的,最好的例子就是CIH! 这类病毒的名字往往以wdm和drv为主(后者是win9x的标准,在最新的windows内核中以被淘汰)。不果他们和dll文件一样,无法自我加载。 上面以程序文件的角度分析了几类病毒格式的工作方式,当然大家不用被提到的极端例子吓怕了。下回将告诉你这些病毒是如何感染并永久的在系统中存活下去的 CSK版权所有,演讲ppt在ftp.csksoft.net中下载。
分页:[«][1]2[3][»]

日历

<< 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)