[原创]JScript实现的病毒清除脚本

Posted by c4pr1c3 on December 30, 2007

经常分析SREng日志的人都会有体会,远程帮人清除病毒真是一件体力活。特别当对方是个电脑“白痴”的时候,那真是各种的无法沟通。。。你教她删文件、改注册表、停服务?算了吧,还是让windows的脚本来帮我们搞定一切吧!

折腾了2天,终于release了我的VirusCleanerUtils.js~~

由于脚本的一些局限性,我的这个病毒清除脚本还依赖于2个小工具分别是ps和spt,关于这2个文件的更多信息可以分别看下面的链接:

X-PS: http://www.unnoo.com/research/tools/xps/

spt: http://www.syssafety.com/leaktests.141.html

目前版本支持的功能包括:

  1. 停止服务
  2. 注册表键值的删除/修改/创建
  3. 进程终止(正常终止/借助spt的16种进程终止技术)
  4. 运行中进程的dll强行卸载(借助X-PS)
  5. 文件删除(支持绝对路径/相对路径/带环境变量)
  6. 文本文件修改
  7. 文件拷贝
  8. 目录删除(不支持“非法”[如autorun..和通过NativeAPI创建的dos保留关键字目录,如con]目录删除)

在源代码中加入了测试代码,方便即改即测~

使用方法:

将VirusCleanerUtils.js、ps.exe、spt.exe三个文件放在同一个目录下,通过以下命令行启动

cscript //nologo VirusCleanerUtils.js

当然了,嫌这样麻烦,自己把上面的启动代码放到一个bat文件里,双击启动,更加傻瓜点~

源代码:VirusCleanerUtils.js

******************************************************************************
 * Author:              TrojanJason@NEWSMTH
 * Created on:          2007-12-28      
 * Last Modified:       2007-12-29
 * Version:             0.1
 */
//-----------------全局变量开始-----------------------
var objWSH      =       new ActiveXObject("wscript.shell");
var fso         =       new ActiveXObject("scripting.filesystemobject");
var hasExceptions = 0;

//OpenTextFile 中读写标志位
var ForRead     =       1;
var ForWrite    =       2;
var ForAppend   =       8;

//custom input dialog vars
var vbOKCancel          =       1;       // 确定/取消
var vbOKOnly            =       0;          //确定
var vbInformation       =       64;
var vbCancel = 2; //终止 重试 忽略,对于Popup的返回值来说表示用户点击'取消'

//special folders spec
var WindowsFolder       =       0;
var SystemFolder        =       1;
var TemporaryFolder     =       2;
//spt kill level constant
/*
        1       - standard process termination;
        2       - terminate process by terminating all its threads;
        3       - terminate process using remote thread;
        4       - terminate process by instruction pointer (IP) modification;
        5       - crash process by resetting memory attributes;
        6       - crash process by rewriting critical process data;
        7       - terminate process as part of a job;
        8       - terminate process using debuger;
        9       - terminate process as a task;
        10      - terminate process by sending WM_CLOSE;
        11      - terminate process by sending WM_SYSCOMMAND;
        12      - terminate process using windows station message;
        13      - terminate process using DLL injection 1;
        14      - terminate process using DLL injection 2;
        15      - simulation of normal process exit;
        16      - terminate process by "bruteforce" message posting;
*/
//-----------------全局变量结束-----------------------

//-----------------全局对象定义开始-----------------------
function VCHelper()
{
}

VCHelper.prototype.stopSystemService    =       stopSystemService;
VCHelper.prototype.deleteRegKey         =       deleteRegKey;
VCHelper.prototype.createRegKey         =       createRegKey;
VCHelper.prototype.readRegKey           =       readRegKey;
VCHelper.prototype.killProcessByName    =       killProcessByName;
VCHelper.prototype.killProcessByPid     =       killProcessByPid;
VCHelper.prototype.findProcessByPid     =       findProcessByPid;
VCHelper.prototype.killProcessByPidSpt  =       killProcessByPidSpt;
VCHelper.prototype.unloadDll            =       unloadDll;
VCHelper.prototype.deleteFile           =       deleteFile;
VCHelper.prototype.deleteFileByEnvVar   =       deleteFileByEnvVar;
VCHelper.prototype.writeTextToFile      =       writeTextToFile;
VCHelper.prototype.copyFile             =       copyFile;
VCHelper.prototype.deleteFolder         =       deleteFolder;
function UtilsHelper()
{
}

UtilsHelper.prototype.hex               =       hex;
UtilsHelper.prototype.info              =       info;

function TestVCHelper()
{

}

TestVCHelper.prototype.buildTestCase = function(){
        try{
                fso.OpenTextFile("test.txt", ForWrite, true).Close();
                fso.OpenTextFile("d:\\temp\\sss.txt", ForWrite, true).Close();
                fso.CreateFolder("d:\\中文 目录");
                fso.OpenTextFile("d:\\中文 目录\\test.txt", ForWrite, true).Close();
                fso.OpenTextFile(fso.GetSpecialFolder(TemporaryFolder)+"temp.ani", ForWrite, true).Close();

        }catch(Err){
        }
}

TestVCHelper.prototype.runTestCase = function(){
        var TestCase = new VCHelper();

        //display program info
        info();

        //test copy file
        TestCase.copyFile("test.txt", "d:\\temp\\test2222.txt");
        TestCase.copyFile("test.txt","d:\\temp\\test22222.txt");
        TestCase.copyFile("test.txt","d:\\nonexist\\test22222.txt");
        TestCase.deleteFile("d:\\temp\\sss.txt");
        TestCase.deleteFile("d:\\中文 目录\\test.txt");
        TestCase.deleteFolder("d:\\中文 目录");
        TestCase.deleteFileByEnvVar("%temp%\\temp.ani");
        TestCase.writeTextToFile("111\n2222\n333", "test.txt", ForAppend, false);
        TestCase.writeTextToFile("111\n2222\n333", "test.txt", ForWrite, true);
        TestCase.writeTextToFile("444\n2222\n333", "test.txt", ForAppend, true);
        //test process termination
        TestCase.unloadDll("SciLexer.DLL");
        TestCase.killProcessByName("calc.exe");
        TestCase.killProcessByPid(3968);
        TestCase.killProcessByPidSpt(3532,2);

        //test stopping service
        TestCase.stopSystemService("MSIServer");

        //test registry operations
        TestCase.createRegKey("HKCU\\Software\\ACME\\FortuneTeller\\",1,"REG_BINARY");
        TestCase.createRegKey("HKCU\\Software\\ACME\\FortuneTeller\\MindReader", "Goocher!", "REG_SZ");
        WScript.StdErr.WriteLine(readRegKey("HKCU\\Software\\ACME\\FortuneTeller\\MindReader"));
        TestCase.deleteRegKey("HKCU\\Software\\ACME\\FortuneTeller\\MindReader");
        TestCase.deleteRegKey("HKCU\\Software\\ACME\\FortuneTeller\\");
        TestCase.deleteRegKey("HKCU\\Software\\ACME\\");

}

//-----------------全局对象定义结束-----------------------

/**************************************
 ************ 系统服务操作 **************
 **************************************/
//停止服务
function stopSystemService(srvcName)
{
        try{
                var strcomputer, objwmi, servicelist, service, sname;
                strcomputer =".";
                objwmi = GetObject("winmgmts:\\\\" + strcomputer + "\\root\\cimv2");
                //确保只停止当前状态为'Running'或'Unknown'的服务
                servicelist = objwmi.ExecQuery("Select * from Win32_Service where (State='Running' or State='Unknown') and Name='" + srvcName + "'");
                var e = new Enumerator(servicelist);
                for (;!e.atEnd();e.moveNext()) {
                        var service = e.item();
                        if(service.stopservice()){
                                WScript.StdErr.WriteLine("!!!!!停止服务:'" + srvcName + "'失败");
                        }else{
                                WScript.StdOut.WriteLine("*****停止服务:'" + srvcName + "'成功");
                        }
                }
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

/**************************************
 ************ 注册表操作 ***************
 **************************************/
//删除注册表键值
function deleteRegKey(regKeyName)
{
        try{
                objWSH.RegDelete(regKeyName);
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

//创建/修改注册表键值
function createRegKey(regKeyName, regKeyValue, regType)
{
        try{
                objWSH.RegWrite(regKeyName, regKeyValue, regType);
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

//读取注册表键值
function readRegKey(regKeyName)
{
        try{
                return objWSH.RegRead(regKeyName);
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

/**************************************
 ************ 进程操作 ***************
 **************************************/
//进程终结 by name
function killProcessByName(procName)
{
        try{
                var w = GetObject("winmgmts:");
                var processlist = w.execquery("select * from win32_process where name='" + procName + "'");
                var e = new Enumerator(processlist);
                for(;!e.atEnd();e.moveNext()){
                        var process = e.item();
                        if(process.terminate()){
                                objWSH.Popup("终止进程:'" + procName + "'失败");
                        }
                }
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}
//进程终结 by pid
function killProcessByPid(pid)
{
        try{
                var w = GetObject("winmgmts:");
                var processlist = w.execquery("select * from win32_process where ProcessId='" + pid + "'");
                var e = new Enumerator(processlist);
                for(;!e.atEnd();e.moveNext()){
                        var process = e.item();
                        process.terminate;           //结束进程    
                }
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

function findProcessByPid(pid)
{
        try{
                var w = GetObject("winmgmts:");
                var processlist = w.execquery("select * from win32_process where ProcessId='" + pid + "'");
                var e = new Enumerator(processlist);
                for(;!e.atEnd();e.moveNext()){
                        var process = e.item();
                        return process;
                }
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }

}

//进程终结 by pid 使用spt.exe
function killProcessByPidSpt()
{
        var pid, level, params;
        if(arguments == null || arguments.length < 2){
                return;
        }else{
                pid = arguments[];
                level = arguments[1];
                params = arguments[2] == null ? null : arguments[2];
        }
        try{
                if(findProcessByPid(pid) == null){//不存在pid所代表的进程
                        WScript.StdErr.WriteLine("!!!!!不存在进程(pid=" + pid + ", level=" + level + ")");
                        return;
                }
                var oExec;
                if(params == null || params.length < 1){
                        oExec = objWSH.Exec("spt " + pid + " " + level);
                }else{
                        oExec = objWSH.Exec("spt " + pid + " " + level + " " + params);
                }
                var isSuccessful = false;
                while(!oExec.StdOut.AtEndOfStream)
                {
                        var output = oExec.StdOut.ReadLine();
                        if(output.indexOf("succeed") > -1){//程序执行成功
                                isSuccessful = true;
                                break;
                        }
                }
                if(!isSuccessful){
                        WScript.StdErr.WriteLine("!!!!!强制终止进程(pid=" + pid + ", level=" + level + ")失败");
                }else{
                        WScript.StdOut.WriteLine("*****强制终止进程(pid=" + pid + ", level=" + level + ")成功");
                }

        }catch(err){
                objWSH.Popup("请将第三方程序spt.exe与本专杀放在同一目录下",64,"注意");
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

//dll文件卸载
function unloadDll(dllName)
{
        try{
                var oExec = objWSH.Exec("ps /e * " + dllName);
                var output = "";
                var isSuccessful = false;
                while(!oExec.StdOut.AtEndOfStream)
                {
                        var output = oExec.StdOut.ReadLine();
                        if(output.indexOf("succeed") > -1){//程序执行成功
                                isSuccessful = true;
                                break;
                        }
                }
                if(!isSuccessful){
                        WScript.StdOut.WriteLine("!!!!!强制卸载dll文件:" + dllName + "失败,请确认dll文件名是否正确");
                }else{
                        WScript.StdOut.WriteLine("*****强制卸载dll文件:" + dllName + "成功");
                }
        }catch(err){
                objWSH.Popup("请将第三方程序ps.exe与本专杀放在同一目录下",64,"注意");
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}

/**************************************
 ************ 文件操作 ***************
 **************************************/
//删除文件(根据全路径+文件名,注意路径中的斜杠是\\)
function deleteFile(fileName)
{
        try{
                if(fso.FileExists(fileName)){
                        var v = fso.GetFile(fileName);
                        v.attributes = 0;
                        v.Delete(true);//force delete if read-only flag is set
                        if(fso.FileExists(fileName)){//check if file has been deleted
                                WScript.StdErr.WriteLine("!!!!!删除文件'" + fileName + "'失败");
                        }else{
                                WScript.StdOut.WriteLine("*****删除文件'" + fileName + "'成功");
                        }
                }

        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}
//删除文件(根据环境变量名+文件名,注意路径中的斜杠是\\)
function deleteFileByEnvVar(fileSpec){
        try{
                var d = objWSH.ExpandEnvironmentStrings(fileSpec);
                if(fso.FileExists(d)){
                        var v = fso.GetFile(d);
                        v.attributes = 0;
                        v.Delete(true);//force delete if read-only flag is set
                        if(fso.FileExists(d)){//check if file has been deleted
                                WScript.StdErr.WriteLine("!!!!!删除文件'" + fileSpec + "'失败");
                        }else{
                                WScript.StdOut.WriteLine("*****删除文件'" + fileSpec + "'成功");
                        }
                }
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}
//强制删除文件(借助第三方工具)

//写文本文件
function writeTextToFile(txt, fileName, iomode, ForceCreate)
{
        try{
                var re = fso.OpenTextFile(fileName, iomode, ForceCreate);
                re.Write(txt);
                re.Close();

        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }
}
//复制文件
function copyFile(src, dst)
{
        try{
                if(fso.FileExists(src)){
                        var tempDst = dst.substring(0,dst.lastIndexOf("\\") + 1);
                        if(!fso.FolderExists(tempDst)){//检查是否存在目标文件所在的目录
                                if(objWSH.Popup("不存在目标目录" + tempDst + "自动创建?",64,"注意",vbOKCancel) == vbCancel){//放弃复制
                                        return;
                                }
                                        fso.CreateFolder(tempDst);
                }
                        if(fso.FileExists(dst)){//检查目标文件是否已经存在
                                if(objWSH.Popup("目标文件" + dst + "已存在,是否覆盖?",64,"注意",vbOKCancel) == vbCancel){//放弃覆盖
                                        return;
                                }
                        }
                        fso.GetFile(src).Copy(dst);

                }else{
                        objWSH.Popup("要拷贝的源文件" + src + "不存在",64,"注意",vbOKOnly);
                }
        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);
        }

}
//删除目录
function deleteFolder(folderName)
{
        try{
                if(fso.FolderExists(folderName)){
                        var folder = fso.GetFolder(folderName);
                        folder.attributes = 0;
                        folder.Delete(true);
                        if(fso.FolderExists(folderName)){
                                WScript.StdErr.WriteLine("!!!!!删除目录'" + folderName + "'失败");
                        }else{
                                WScript.StdOut.WriteLine("*****删除目录'" + folderName + "'成功");
                        }
                }

        }catch(err){
                hasExceptions ++;
                WScript.StdErr.WriteLine("Error " + hasExceptions + " occurred\nCode: " + hex(err.number) + "\nDescriptions: " + err.description);

        }
}

/**************************************
 ************ UtilsHelper类 ***************
 **************************************/
function hex(nmb)
{
    if (nmb > 0)
        return nmb.toString(16);
    else
        return (nmb + 0x100000000).toString(16);
}

function info()
{
        var _name = "Virus Clean Helper";
        var _author = "All rights by TrojanJason@NEWSMTH";
        var _version = "Version 0.1";
        objWSH.Popup(_author + "\n" + _version, 64, _name);
}

//run TestCase
var TestCase = new TestVCHelper();
TestCase.buildTestCase();
TestCase.runTestCase();