首页
社区
课程
招聘
用于提取EXE/DLL中C++类与继承关系的DHTML脚本
发表于: 2006-4-10 16:46 5255

用于提取EXE/DLL中C++类与继承关系的DHTML脚本

2006-4-10 16:46
5255
这是用于idapro 4.9插件IdaHTML的脚本,完整代码可从http://dreaman.haolinju.net/IdaHTML/ClassGraph.htm另存。
因为是脚本,不知道发在这里有没有违规,呵呵,不过内容确实是与逆向工程相关的,而且主要用于比较大的C++程序(有内部对象模型的那种了,比如游戏,不多说了,不清楚有用没用呢)。

脚本代码如下:(又改了一下)
<html xmlns:v>
        <head>
                <title>分析.rdata段的VTBL并据此构造类继承图</title>
        <STYLE>
                v\:*{behavior:url(#default#VML);}
        </STYLE>
        </head>
        <body scroll="no" leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">               
                <table style="width:100%;height:100%">               
                        <tr>
                                <td colspan="2">
                                        <div style="width:100%;height:100%;overflow:scroll;" onmouseup="zoomGraph()">
                                                <v:group id="flowGraph" style="position:relative;width:100%;height:100%" coordsize="500,300">
                                                </v:group>
                                        </div>
                                </td>
                        </tr>
                        <tr style="height:80px">
                                <td width="80px">
                                        <select id="caList" style="width:100%;height:100%;" size="2" ondblclick="drawGraph()">
                                        </select>
                                </td>
                                <td>
                                        <textarea id="scpArea" style="width:100%;height:100%" WRAP="off">
                                        </textarea>
                                </td>
                        </tr>
                        <tr style="height:16px">
                                <td colspan="2">
                                        <input type="button" value="Run" onclick="eval(scpArea.value)">
                                        <input type="button" value="Analysis" onclick="startAnalysis()">
                                        <input type="button" value="LoadGraph" onclick="loadTxtGraph()">
                                </td>
                        </tr>
                </table>
                <script src="res://IdaHTML.plw/const.js"></script>
                <script>
                        function ClassInfo()
                        {
                                this.level=0;
                                this.index=0;                       
                                this.funcs=new Array();
                                this.subClasses=new Object();
                                this.addFunc=function(f)
                                {
                                        this.funcs.push(f);
                                }
                                this.addSubClass=function(c)
                                {
                                        this.subClasses[c]=true;
                                }
                                this.delSubClass=function(c)
                                {
                                        delete this.subClasses[c];
                                }
                                this.after=new Object();//被依赖类
                                this.addAfter=function(c)
                                {
                                        this.after[c]=true;
                                }
                                this.haveAfter=function(c)
                                {
                                        if(this.after[c])
                                                return true;
                                        return false;
                                }
                        }
                        function FuncInfo()
                        {
                                this.classes=new Array();
                                this.refCount=0;
                                this.callFuncs=new Array();
                                this.addClass=function(c)
                                {
                                        this.classes.push(c);
                                        this.refCount++;
                                }
                                this.addCallFunc=function(f)
                                {
                                        this.callFuncs.push(f);
                                }
                        }
                        var classes=new Object();
                        var funcs=new Object();
                        //继承图相关的数据
                        var maxLevel=0,maxIndex=0;//当前图的最大层及最大索引,也就是图在二维平面上的高与宽的度量
                        var layerIndex=null;//图上每一层的当前最大索引,一个数组
                        var dx=0,dy=0;
                        var txtGraphs=new Object();
                        var curW=500,curH=300;
                </script>
                <script>
                        function window.onload()
                        {                               
                                scpArea.value="";
                        }
                        function getRoundRect(x,y)
                        {
                                return document.createElement("<v:roundrect style='position:relative;z-index:1;LEFT:"+(x-32)+";TOP:"+(y-9)+";width:64;height:18;' fillcolor='yellow'/>");
                        }
                        function getLine(x1,y1,x2,y2,rx,ry)
                        {
                                if(Math.abs((y2-y1)/(x2-x1))>ry/rx)
                                {
                                        x1-=(x2-x1)*ry/(y2-y1);
                                        y1-=ry;
                                        x2+=(x2-x1)*ry/(y2-y1);
                                        y2+=ry;
                                }
                                else if(x1<x2)
                                {
                                        x1+=rx;
                                        y1+=(y2-y1)*rx/(x2-x1);
                                        x2-=rx;
                                        y2-=(y2-y1)*rx/(x2-x1);
                                }
                                else
                                {
                                        x1-=rx;
                                        y1-=(y2-y1)*rx/(x2-x1);
                                        x2+=rx;
                                        y2+=(y2-y1)*rx/(x2-x1);
                                }
                                x1=Math.floor(x1);
                                y1=Math.floor(y1);
                                x2=Math.floor(x2);
                                y2=Math.floor(y2);
                                return document.createElement("<v:line style='position:relative;z-index:1;' from='"+x1+","+y1+"' to='"+x2+","+y2+"' />");
                        }
                        function getStroke()
                        {
                                return document.createElement("<v:stroke dashstyle='solid' endarrow='None' opacity='0.5' />");
                        }
                        function getText(x,y,text)
                        {
                                var r=document.createElement("<v:roundrect style='position:relative;z-index:1;left:"+(x-30)+";top:"+(y-7)+";width:60;height:14;font-size:14px' stroked='f' />");
                                var f=document.createElement("<v:fill type='frame' opacity='0.5' />");
                                r.appendChild(f);
                                var t=document.createElement("<v:textbox inset='1,1,1,1' />");
                                t.innerText=text;
                                r.appendChild(t);
                                return r;
                        }
                        function getX(p)
                        {
                                var lvl=classes

.level;
                                var maxIx=layerIndex[lvl];
                                var m=Math.floor(maxIx/2);                               
                                return Math.floor((maxIndex+1)/2*dx+(classes

.index-m)*dx);
                        }
                        function getY(p)
                        {
                                return Math.floor(dy*classes

.level)+10;
                        }
                        function zoomGraph()
                        {
                                if(!event.altKey)return;
                                if(event.button==1)
                                {
                                        curW/=2;
                                        curH/=2;
                                }
                                else if(event.button==2)
                                {
                                        curW*=2;
                                        curH*=2;
                                }
                                else
                                {
                                        return;
                                }
                                flowGraph.coordSize=""+curW+","+curH;
                        }
                        function window.drawGraph()
                        {
                                if(caList.selectedIndex<0)                               
                                        return;
                                var firstClass=window.external.HexToInt(caList.options[caList.selectedIndex].value);
                                var w=500;
                                var h=300;                       
                                //初始化流程绘制相关的数据                               
                                maxLevel=0;
                                maxIndex=0;
                                layerIndex=new Array();
                                flowGraph.innerHTML="";
                                scpArea.value=txtGraphs[firstClass];
                                //广度优先遍历确定节点层次与层序号
                                var line=new Array();//当前层
                                line.push(firstClass);
                                layerIndex.push(0);//第一层就一个节点,即首过程结点
                                maxLevel=0;
                                for(;;)
                                {
                                        var tline=new Array();//下一层
                                        for(var i=0;i<line.length;i++)
                                        {
                                                var a=line[i];
                                                if(classes[a])
                                                {
                                                        var ns=classes[a].subClasses;
                                                        var pix=classes[a].index;
                                                        var ct=0;
                                                        for(var j in ns)ct++;
                                                        var m=Math.floor(ct/2);
                                                        var ix=0;
                                                        for(var j in ns)
                                                        {
                                                                var tx=pix+ix-m;
                                                                if(maxIndex<tx)
                                                                        maxIndex=tx;
                                                                ix++;                                                       
                                                                tline.push(j);
                                                                var cx=tline.length-1;       
                                                                classes[j].index=(cx>tx ? cx : tx);
                                                                classes[j].level=maxLevel+1;
                                                        }
                                                }       
                                        }
                                        if(tline.length==0)
                                        {
                                                break;
                                        }
                                        else                                               
                                        {
                                                if(maxIndex<tline.length-1)                                               
                                                        maxIndex=tline.length-1;
                                                layerIndex.push(maxIndex);//压入新发现的一层的最大层索引
                                                maxLevel++;
                                        }
                                        line=tline;
                                }                               
                                //
                                dx=Math.floor(w/(maxIndex+2));
                                dy=Math.floor(h/(maxLevel+2));
                                //再次广度优先遍历绘制流程图
                                line=new Array();//当前层
                                line.push(firstClass);
                                //绘制初始节点
                                flowGraph.appendChild(getRoundRect(getX(firstClass),getY(firstClass)));
                                flowGraph.appendChild(getText(getX(firstClass),getY(firstClass),window.external.IntToHex(firstClass)));
                                for(;;)
                                {
                                        var tline=new Array();//下一层
                                        for(var i=0;i<line.length;i++)
                                        {
                                                var a=line[i];
                                                if(classes[a])
                                                {
                                                        var ns=classes[a].subClasses;
                                                        for(var j in ns)
                                                        {
                                                                tline.push(j);
                                                                //绘制节点
                                                                flowGraph.appendChild(getRoundRect(getX(j),getY(j)));
                                                                flowGraph.appendChild(getText(getX(j),getY(j),window.external.IntToHex(j)));
                                                                //绘制连线
                                                                var l=getLine(getX(j),getY(j),getX(a),getY(a),20,9);
                                                                l.appendChild(getStroke());
                                                                flowGraph.appendChild(l);
                                                        }
                                                }       
                                        }
                                        if(tline.length==0)
                                        {
                                                break;
                                        }
                                        line=tline;
                                }                               
                        }
                        function compare(a,b)
                        {
                                var al=classes[a].funcs.length;
                                var bl=classes.funcs.length;
                                if(al<bl)
                                        return -1;
                                else if(al==bl)
                                {
                                        if(classes[a].haveAfter(b))
                                                return 1;
                                        else if(classes.haveAfter(a))
                                                return -1;
                                        else
                                                return 0;
                                }
                                else
                                        return 1;
                        }
                        function decideSubClass(carray,ix)
                        {
                                var len=carray.length;
                                if(ix>=len-1)
                                        return;
                                var c=carray[0];
                                var c1=carray[ix];                               
                                for(var ii=ix+1;ii<len;ii++)
                                {
                                        if(carray[ii]==0)
                                                continue;//空项目表明已经被添加为子类了
                                        var c2=carray[ii];
                                        if(classes[c1].haveAfter(c2))
                                        {
                                                classes[c].delSubClass(c2);
                                                classes[c1].addSubClass(c2);
                                                decideSubClass(carray,ii);
                                                carray[ii]=0;
                                        }
                                }                               
                        }
                        function iterateGraph(fp,c0,c,lvl)
                        {
                                c=parseInt(""+c,10);
                                for(var i=0;i<lvl;i++)
                                {
                                        app.IdcApi.writestr(fp,"\t");
                                        txtGraphs[c0]+="\t";
                                }
                                var info=app.IdcApi.form("%8.8X\r\n",c);
                                app.IdcApi.writestr(fp,info);
                                txtGraphs[c0]+=info;
                                for(var sc in classes[c].subClasses)
                                {
                                        iterateGraph(fp,c0,sc,lvl+1);
                                }
                        }
                        function startAnalysis()
                        {
                                var path=app.IdcApi.AskFile(1,"classes.txt","请指定一个文件用于存储类分析的结果:");
                                if(!path)
                                        return;
                                var a=app.IdcApi.FirstSeg();
                                var s=app.IdcApi.SegName(a);
                                while(s!=".rdata")
                                {
                                        a=app.IdcApi.NextSeg(a);
                                        s=app.IdcApi.SegName(a);
                                }
                                var e=app.IdcApi.NextSeg(a);
                                app.IdcApi.Message("找到.rdata段:%8.8X-%8.8X,现在开始分析可能的VTBL...\r\n",a,e);
                                var fp=app.IdcApi.fopen(path,"w");
                                app.IdcApi.writestr(fp,".classmember--------------------------------------------------\r\n");
                                var curClass=null;
                                for(var i=a;i<e;)
                                {       
                                        s=app.IdcApi.GetDisasm(i);
                                        if(app.IdcApi.strstr(s,"dd offset")>=0)
                                        {
                                                //取出VTBL中的一项,查看是否函数
                                                var v=app.IdcApi.Dword(i);
                                                var f=app.IdcApi.GetFlags(v);
                                                //查看是否有名称,有名称的表明有被引用,可能是VTBL的开始
                                                var label=app.IdcApi.Name(i);
                                                if(typeof(label)=="string" && label.length>0)//如果是RTTI或MFC动态类,则第一项可能不是函数
                                                {
                                                        curClass=i;
                                                        classes[curClass]=new ClassInfo();
                                                        app.IdcApi.writestr(fp,app.IdcApi.form("class:%8.8X\r\n",curClass));
                                                        classes[curClass].addFunc(v);
                                                        if(!funcs[v])
                                                        {
                                                                funcs[v]=new FuncInfo();
                                                        }
                                                        funcs[v].addClass(curClass);
                                                        app.IdcApi.writestr(fp,app.IdcApi.form("=>member:%8.8X\r\n",v));
                                                }
                                                else if((f & MS_CLS)==FF_CODE && curClass)
                                                {
                                                        classes[curClass].addFunc(v);
                                                        if(!funcs[v])
                                                        {
                                                                funcs[v]=new FuncInfo();
                                                        }
                                                        funcs[v].addClass(curClass);
                                                        app.IdcApi.writestr(fp,app.IdcApi.form("=>member:%8.8X\r\n",v));
                                                }
                                                else//不是VTBL成员
                                                {
                                                        curClass=null;
                                                }
                                        }
                                        i=app.IdcApi.ItemEnd(i);
                                }
                                //删除只有一个虚函数的类(通常这可能不是类)
                                var nullClasses=new Array();
                                for(var c in classes)
                                {
                                        if(classes[c].funcs.length<=1)
                                                nullClasses.push(c);
                                }
                                for(var i=0;i<nullClasses.length;i++)
                                {
                                        delete classes[nullClasses[i]];
                                }                               
                                app.IdcApi.writestr(fp,".classarray---------------------------------------------------\r\n");
                                app.IdcApi.Message("VTBL分析完毕,现在分析可能的类簇...\r\n");
                                //分析类簇
                                var classesArray=new Array();
                                var accessed=new Object();
                                for(var c in classes)
                                {
                                        c=parseInt(""+c,10);
                                        if(!accessed[c])//发现一个新的类簇,并构造出此类簇
                                        {
                                                accessed[c]=true;                                               
                                                app.IdcApi.writestr(fp,app.IdcApi.form("class Array:\r\n"));               
                                                app.IdcApi.writestr(fp,app.IdcApi.form("=>%8.8X\t(起始类)\r\n",c));                                                                               
                                               
                                                var        curClasses=new Array();
                                                curClasses.push(c);
                                                classesArray.push(curClasses);
                                               
                                                var queue=new Array();
                                                queue.push(c);
                                                while(queue.length>0)
                                                {
                                                        var cc=queue[0];
                                                        for(var i=0;i<classes[cc].funcs.length;i++)
                                                        {
                                                                var f=classes[cc].funcs[i];
                                                                for(var ii=0;ii<funcs[f].classes.length;ii++)
                                                                {
                                                                        var fc=funcs[f].classes[ii];
                                                                        if(!accessed[fc] && classes[fc])
                                                                        {
                                                                                app.IdcApi.writestr(fp,app.IdcApi.form("=>%8.8X\t(共用:%8.8X[%8.8X])\r\n",fc,cc,f));
                                                                                accessed[fc]=true;
                                                                                curClasses.push(fc);
                                                                                queue.push(fc);
                                                                        }
                                                                }
                                                        }
                                                        queue.shift();
                                                }
                                        }
                                }
                                app.IdcApi.writestr(fp,".callvfunc----------------------------------------------------\r\n");
                                app.IdcApi.Message("类簇分析完毕,现在开始分析虚函数调用关系...\r\n");
                                var fcount=0;
                                for(var f in funcs)
                                {
                                        /*
                                        if(fcount>=100)
                                        {
                                                break;
                                        }
                                        fcount++;
                                        */
                                        f=parseInt(""+f,10);
                                        var st=f;
                                        var ed=app.IdcApi.FindFuncEnd(f);
                                        for(var i=st;i<ed;)
                                        {
                                                for(var x=app.IdcApi.Rfirst(i);x!=BADADDR;x=app.IdcApi.Rnext(i,x))
                                                {
                                            var xt=app.IdcApi.XrefType();
                                                        if(xt == fl_CN && funcs[x])
                                                        {
                                                                funcs[f].addCallFunc(x);                                                               
                                                                app.IdcApi.writestr(fp,app.IdcApi.form("%8.8X=>%8.8X\r\n",f,x));
                                                        }
                                                }
                                                i=app.IdcApi.ItemEnd(i);
                                        }
                                }                               
                                app.IdcApi.Message("函数调用关系分析完毕,现在据此构造类的依赖关系...\r\n");                               
                                for(var f in funcs)
                                {
                                        for(var i=0;i<funcs[f].callFuncs.length;i++)
                                        {
                                                var cf=funcs[f].callFuncs[i];
                                                for(var ii=0;ii<funcs[cf].classes.length;ii++)
                                                {
                                                        var cc=funcs[cf].classes[ii];
                                                        for(var iii=0;iii<funcs[f].classes.length;iii++)
                                                        {
                                                                var c=funcs[f].classes[iii];
                                                                classes[cc].addAfter(c);
                                                        }
                                                }
                                        }
                                }
                                app.IdcApi.writestr(fp,".classorder---------------------------------------------------\r\n");                               
                                app.IdcApi.Message("类簇分析完毕,挑选VTBL尺寸最小的类作基类...\r\n");
                                //对每个类簇的类按VTBL的大小排序
                                for(var i=0;i<classesArray.length;i++)
                                {
                                        var ca=classesArray[i];                                       
                                        ca=ca.sort(compare);
                                        classesArray[i]=ca;
                                       
                                        app.IdcApi.writestr(fp,"class inherit order:\r\n");
                                        for(var ii=0;ii<ca.length;ii++)
                                        {
                                                app.IdcApi.writestr(fp,app.IdcApi.form("=>%8.8X size:%d\r\n",ca[ii],classes[ca[ii]].funcs.length));
                                        }
                                }
                                //每簇类以最小尺寸的类作基类
                                for(var i=0;i<classesArray.length;i++)
                                {
                                        var ca=classesArray[i];                                       
                                        for(var ii=1;ii<ca.length;ii++)
                                        {
                                                classes[ca[0]].addSubClass(ca[ii]);
                                        }
                                }                               
                                app.IdcApi.Message("类簇排序完毕,依据依赖细化继承关系...\r\n");
                                for(var i=0;i<classesArray.length;i++)
                                {
                                        var ca=classesArray[i];
                                        decideSubClass(ca,1);
                                }
                                app.IdcApi.writestr(fp,".graph--------------------------------------------------------\r\n");
                                app.IdcApi.Message("分析完毕,现在输出继承关系描述...\r\n");
                                caList.size=classesArray.length;
                                for(var i=0;i<classesArray.length;i++)
                                {
                                        var ca=classesArray[i];
                                        var c=ca[0];
                                        if(ca.length>=2)
                                        {
                                                var opt=document.createElement("option");
                                                opt.text=window.external.IntToHex(c);
                                                opt.value=window.external.IntToHex(c);                                       
                                                caList.add(opt);
                                        }
                                        txtGraphs[c]="";
                                        iterateGraph(fp,c,c,0);
                                }
                                app.IdcApi.Message("全部分析完成!\r\n");
                                app.IdcApi.fclose(fp);
                        }
                        function loadClass(c,addr,lines,ix,lvl)
                        {
                                for(var ii=ix;ii<lines.length;)
                                {
                                        var line=lines[ii];
                                        for(var i=0;i<line.length;i++)
                                        {
                                                if(line.charAt(i)!="\t")
                                                        break;                                               
                                        }
                                        if(i<=lvl)
                                                return ii;
                                        else
                                        {
                                                var ca=window.external.HexToInt(line.substr(i));
                                                classes[ca]=new ClassInfo();
                                                classes[addr].addSubClass(ca);
                                                txtGraphs[c]+=line;
                                                ii=loadClass(c,ca,lines,ii+1,i);
                                        }
                                }
                        }
                        function loadTxtGraph()
                        {
                                //目前只装入绘制类继承图相关的信息                               
                                var path=app.IdcApi.AskFile(0,"classes.txt","请指定存储了类分析的结果的文本文件");
                                if(!path)
                                        return;
                                classes=new Object();//清空类信息
                                txtGraphs=new Object();
                                while(caList.options.length>0)
                                        caList.options.remove(0);
                                app.IdcApi.Message("装入开始...\r\n");
                                var content=window.external.Setup.ReadTxtFile(path);//将文本文件内容读到字符串中
                                var lines=content.split("\r\n");
                                for(var i=lines.length-1;i>=0;i--)
                                {
                                        if(lines[i].indexOf(".graph")==0)
                                                break;
                                }                               
                                for(var j=i+1;j<lines.length;)
                                {
                                        var addr=window.external.HexToInt(lines[j]);
                                       
                                        classes[addr]=new ClassInfo();
                                        txtGraphs[addr]=lines[j];
                                        var nj=loadClass(addr,addr,lines,j+1,0);
                                        if(nj>j+1)
                                        {
                                                var opt=document.createElement("option");
                                                opt.text=lines[j];
                                                opt.value=lines[j];
                                                caList.add(opt);
                                        }
                                        j=nj;
                                }
                                app.IdcApi.Message("装入完成!\r\n");                               
                        }
                </script>
        </body>
</html>

主要分析思路:
1、在.rdata段中查找可能的VTBL,并构造相应的类与成员函数的对应关系;
2、VTBL有公共函数的认为是同一簇的类(不一定正确);
3、分析虚函数间的调用关系,据此构造类的依赖;
4、对2中得到的同一簇的类按VTBL大小与依赖关系排序;
5、根据4中顺序与依赖关系构造继承图(只是参考,不完全正确);
6、用VML绘制类继承图(双击分析结果列表中的某行即绘制)。

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 0
支持
分享
最新回复 (14)
雪    币: 768
活跃值: (515)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
2
不懂JAVA HTML :( 只能看看了!!!
支持楼主!!!!!!!!!!
同时恭喜楼主。
2006-4-10 16:52
0
雪    币: 234
活跃值: (370)
能力值: ( LV9,RANK:530 )
在线值:
发帖
回帖
粉丝
3
只能支持了:D
2006-4-10 16:58
0
雪    币: 106
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
inr
4
看不懂
2006-4-10 17:29
0
雪    币: 303
活跃值: (461)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
看不懂
2006-4-10 18:25
0
雪    币: 236
活跃值: (35)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
不知道 这些都是干什么用的!
2006-4-10 18:48
0
雪    币: 1325
活跃值: (507)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
7
就是假设有一个程序,是C++写的,采用了面向对象的思路,那么它的主要功能架构表现为一个对象模型图,这个脚本就是试图找到这个对象模型图,再配合一些特定下断点的方法,有助于了解一个软件是如何工作的。

举个例子,可能不是很恰当(偶假想的,没试过),假设现在有一个游戏,游戏里的主要角色与精灵通常都是从同一个基类派生而来,他们的主要功能具有相似性,并且通常由他们共同的基类提供,如果找到这个基类,那么相当于找到了这个游戏的对外的API,因为你可以调用它们来操纵游戏里的角色了。(估计许多游戏外挂就是这样的原理了)。

当然,写一个外挂肯定不是这么简单的事,不过作为辅助分析的工具,我觉得也许是有用的,呵呵。
2006-4-10 19:01
0
雪    币: 257
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
收藏
2006-4-10 19:37
0
雪    币: 260
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
不太明白,正好学习一下
2006-4-10 21:34
0
雪    币: 1325
活跃值: (507)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
10
晕,好象大家都主要是对程序的序列号有兴趣,对整个程序的工作情况不想了解吗?
比如,研究清楚一个游戏是如何工作的,按理这也很吸引人的啊?
要不偶找个游戏来分析分析.
2006-4-11 20:16
0
雪    币: 153
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
楼主还是改改你的插件吧,把NAG去掉,OD在各种插件的折磨下已经够卡了,你倒好,还弄个Nag出来,去掉吧,谢谢
2006-4-11 20:19
0
雪    币: 1325
活跃值: (507)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
12
那个Nag已经去掉了啊,上次我就改了的。
2006-4-11 20:23
0
雪    币: 153
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
去掉了就好了,谢谢
2006-4-11 20:27
0
雪    币: 1325
活跃值: (507)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
14
呵呵,那个Nag窗口本来也不是有意要加的,因为IE窗口没办法直接隐藏,显示一个白窗口难看,就把插件名写上了,我后来让窗口跑屏幕外边去了,然后再自动隐藏起来了。
2006-4-11 20:31
0
雪    币: 50
活跃值: (145)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
15
浏览一下,熟悉熟悉
2006-4-11 23:02
0
游客
登录 | 注册 方可回帖
返回
//