1 (изменено: dab00, 2012-03-15 15:47:58)

Тема: VBS: Обфускация VBScript-кода

VBS-скрипт для преображения кода VBScript.
Возможности:
- удаление комментариев, пробелов, табуляций, переноса строк
- переименование функций, процедур, классов, свойств, методов, явно объявленных переменных, констант (только VBS)
В графическом режиме позволяет выбрать несколько файлов.
В консольном режиме принимает в качестве аргументов абсолютные, относительные пути или только имена файлов.
В секции объявления переменных можно изменить:
- максимальную длину нового случайного имени в символах
- процент символов алфавита в новом случайном имени
- необходимость переименования переменных и пр.
- необходимость создания файла журнала переименования
- необходимость трансформации символов (значительно увеличивает размер файла)
- префикс нового имени файла
- суффикс имени файла лога
Скрипт создает в каталоге с файлом исходного кода новый файл с указанным префиксом, а также, в случае необходимости, CSV-файл с отчетом о переименованных переменных и пр., в завершение работы отображает сообщение с отчетом о результате работы с каждым файлом.

Option Explicit
    On Error Resume Next
    Const strNewNamePref = "New" 'префикс нового имени файла    
    Const intMaxLen = 11 'максимальная длина имени в символах (Const-1)
    Const intPro = 60 'процент символов алфавита в новом рандомизированном имени    
    Const bStir = True ' необходимость взбалтывания имен переменных, False - не взбалтываем :)
    Const bWriteLog = False 'необходимость создания файла журнала переименования, False - не создаем
    Const bTransChr = False 'необходимость трансформации символов, False - не трансформируем
    Dim fso, ret
    Dim i, mesaga    
    Dim strNewLogSuf 'суффикс имени файла лога
    strNewLogSuf = "-log-" & Date() & ".csv" 
    
    '************** шаблоны **************
    Dim strRemoveCommentsPattern
    'шаблон удаления комментариев
    strRemoveCommentsPattern = _
            "^\s*(?:'|\brem\b).*$|(?:'|\brem\b)[^" & Chr(34) & "]*$|^\s+|\s+$"
    'шаблон объединения строк - символ подчеркивания в конце строки
    Dim strFindJumpPattern
    strFindJumpPattern = " _$" 
    'шаблон для поиска строк с объявлениями
    Dim strGetVarNameTestPattern
    strGetVarNameTestPattern = _
            "\b(?:sub|function|public|static|private|dim|const|class|property)\s+.*"
    'шаблон для удаления из строк с объявлениями
    Dim strGetVarNameReplacePattern
    strGetVarNameReplacePattern = _
            "\b(?:sub|function|public|static|private|dim|const|class|property|get|let|set)\b|\(|\)|,|\t|=.*$"
    
    Const ClassIni = "Class_Initialize" 'строка инициализации класса
    Const ClassTerm = "Class_Terminate" 'строка удаления класса
    '**************************************
    
    Dim strArr() 'массив для строк из файла с кодом    
    Dim strNameArr() 'массив имен переменных
    Redim strNameArr(2,0) 'необходимо инициализировать, переменные начнутся с индекса №1
    Dim CharArray 'массив символов - алфавит :)    
    CharArray = Array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")            

    Set fso = CreateObject("Scripting.FileSystemObject")

    If WScript.Arguments.Count = 0 Then
        Dim objDialog 'диалог выбора файла    
        Set objDialog = CreateObject("UserAccounts.CommonDialog")
        If Not IsObject(objDialog) Then 
            MsgBox "Не удалось создать диалоговое окно" & vbCrLf & _
                    "Используйте консольный режим",vbExclamation
            Set fso = Nothing
            WScript.Quit
        End If
        
        objDialog.Flags = &H0200 'возможность выбрать несколько файлов
        objDialog.Filter = "Visual Basic files (*.vb;*.vbs)|*.vb;*.vbs|Все файлы (*.*)|*.*"    
        
        'открываем диалог    
        ret = objDialog.ShowOpen    
        
        'если файл не выбран - завершаем выполнение скрипта    
        If Not ret Then 
            Set fso = Nothing
            WScript.Quit             
        End If
            
        'вызываем функцию удаления с массивом имен выбранных файлов
        ret = RemComm(Split(Trim(fso.GetFileName(objDialog.FileName))))
        
        Set objDialog = Nothing    
    Else    
        'вызываем функцию удаления с коллекцией аргументов скрипта        
        ret = RemComm(WScript.Arguments)    
    End If
    
    Set fso = Nothing
        
    'вывод информации о ходе выполнения
    mesaga = "Журнал:"
    For i = 0 To UBound(ret,2)
        mesaga = mesaga & vbCrLf & ret(0,i) & " - " & ret(1,i)
    Next
    MsgBox mesaga,vbInformation

'удаление комментариев, переименование переменных и пр.
Function RemComm(arrFiles)
    On Error Resume Next        
    Dim arrRemComm() 'массив для лога    
    Dim strFilePath 'путь к файлу кода    
    Dim strFile 'имя файла в коллекции    
    Dim regEx 'регулярные выражения    
    Dim ret(5) 'возвращенное значение
    Dim i, j
    'создаем регулярное выражение
    Set regEx = New RegExp 
    With regEx        
        .Global = True   'устанавливаем глобальность применения
        .IgnoreCase = True  'устанавливаем нечувствительность к регистру
    End With
    
    i = 0
    For Each strFile In arrFiles
        'собираем путь к файлу
        strFilePath = fso.BuildPath(fso.GetParentFolderName(fso.GetAbsolutePathName(strFile)), fso.GetFileName(strFile))            
        
        'поверяем наличие файла - пользительно для консольного варианта
        If Not fso.FileExists(strFilePath) Then             
            Redim Preserve arrRemComm(1,i)
            arrRemComm(0,i) = strFilePath
            arrRemComm(1,i) = "Файл не найден"            
        Else                
            'читаем файл - отправляем путь
            ret(1) = ReadFile(regEx,strFilePath)            
            
            If bStir Then 'проверяем необходимость переименования переменных
            
                'извлекаем имена функций, процедур, переменных, классов и пр.
                'в public переменную strNameArr
                ret(2) = GetVarName(regEx)            
                
                'переименуем переменные
                ret(3) = RenameVar(regEx)                
            
            End If
            
            'пишем в новый файл
            ret(4) = WriteFile(strFilePath)
            
            'складываем коды выполнения
            Redim Preserve arrRemComm(1,i)
            arrRemComm(0,i) = strFilePath            
            ret(0) = Err.Number
            For j = 1 To UBound(ret)
                ret(0) = ret(0) + ret(j)
            Next            
            'проверяем наличие ошибок
            If Not ret(0) Then
                arrRemComm(1,i) = "Успех"
            Else
                arrRemComm(1,i) = "Ошибка"
            End If            
        End If
        i = i + 1
    Next    
    Set regEx = Nothing
    
    RemComm = arrRemComm    
End Function

'чтение файла и удаление комментариев
Function ReadFile(regEx,strFilePath)
    On Error Resume Next
    Dim objFile 'файл с кодом
    Dim i
    'открываем файл с кодом для чтения    
    Set objFile = fso.OpenTextFile(strFilePath,1) 
    i = 0            
    Do While objFile.AtEndOfStream <> True 'читаем файл                
        ReDim Preserve strArr(i) 'перебиваем размерность массива
        'закидываем строки в массив и по ходу удаляем комменты
        strArr(i) = RemoveComments(regEx,objFile.ReadLine)
        
        If i <> 0 Then
            'если в конце предыдущей строки есть символ переноса строки -
            If FindJump(regEx,strArr(i-1)) Then 
                'объединяем строку с предыдущей
                strArr(i-1) = Left(strArr(i-1),Len(strArr(i-1))-1) & strArr(i) 
                Redim Preserve strArr(i-1) 'уменьшаем массив
            Else 'если нет символа переноса - продолжаем увеличивать массив
                i = i + 1 
            End If
        Else 'первую строку в любом случае читаем и увеличиваем массив
            i = i + 1
        End If                
    Loop
    objFile.Close 'закрываем файл
    Set objFile = Nothing 'удаляем ссылку на файл
    ReadFile = Err.Number
End Function

'удаление комментариев (вызываем из функции чтения файлов)
Function RemoveComments(regEx,strInput)
    On Error Resume Next    
    regEx.Pattern = strRemoveCommentsPattern 'собираем шаблон для удаления     
    RemoveComments = regEx.Replace(strInput,vbNullString) 'удаляем комменты и пр.    
End Function

'проверка наличия переноса строки (вызываем из функции чтения файлов)
Function FindJump(regEx,strInput)
    On Error Resume Next    
    regEx.Pattern = strFindJumpPattern
    If regEx.Test(strInput) Then         
        FindJump = True
    Else
        FindJump = False
    End If    
End Function

'получение имен переменных
Function GetVarName(regEx)
    On Error Resume Next
    Dim strMatchesArr()    'массив совпавших строк
    Dim colMatches', strMatch    
    Dim i, j, k
    Dim strSplitArr
    Dim strFindVarPatternStart 'начало строки шаблона для поиска переменной
    Dim strFindVarPatternEnd 'конец строки шаблона для поиска переменной
    strFindVarPatternStart = "\b"
    strFindVarPatternEnd = "\b(?!" & Chr(34) & ")"
    i = 0
    'шаблон для поиска строк с объявлениями
    regEx.Pattern = strGetVarNameTestPattern    
    For i = 0 To UBound(strArr) 'бежим по массиву строк из файла    
        'проверяем наличие шаблона в строке - наверное так будет быстрее
        If regEx.Test(strArr(i)) Then
            'шаблон для удаления лишнего из строк с объявлениями
            regEx.Pattern = strGetVarNameReplacePattern
            Redim Preserve strMatchesArr(i)
            'заменяем лишнее (согласно шаблону) пробелами
            strMatchesArr(i) = regEx.Replace(strArr(i),Chr(32))    
            'разбиваем строку в массив по пробелу - получаем имена переменных
            strSplitArr = Split(strMatchesArr(i)) 
            'вернули шаблон обратно
            regEx.Pattern = strGetVarNameTestPattern
            'побежали по массиву свежих переменных        
            For j = 0 To UBound(strSplitArr)
                'проверим валидность имени переменной
                If CheckName(strSplitArr(j)) Then
                    'проверим наличие имени переменной в массиве (чтобы не повторяться)                    
                    If Not CheckNameArr(strSplitArr(j),0) Then 
                        k = UBound(strNameArr,2) + 1 'к верхнему индексу добавляем 1
                        Redim Preserve strNameArr(2,k) 'перебиваем размерность
                        'добавляем в массив значения
                        strNameArr(0,k) = strSplitArr(j) 'имя переменной                         
                        strNameArr(1,k) = GetRandomName(CharArray,intMaxLen,intPro) 'новое имя    
                        'проверяем новое имя - возможны повторы
                        Do While CheckNameArr(strNameArr(1,k),1)
                            'если уже есть - формируем новое
                            strNameArr(1,k) = GetRandomName(CharArray,intMaxLen,intPro)
                        Loop
                        'собираем строку шаблона для поиска переменной в строке    
                        strNameArr(2,k) = strFindVarPatternStart & strSplitArr(j) & strFindVarPatternEnd                    
                    End If
                End If
            Next
        End If
    Next    
    GetVarName = Err.Number
End Function

'проверка имени на валидность (вызываем из функции получения имен переменных)
Function CheckName(strName)
    On Error Resume Next    
    'IsNumeric - на случай массивов (число в скобках)    
    If strName = ClassIni Or strName = ClassTerm Or IsNumeric(strName) Then
        CheckName = False
    Else
        CheckName = True
    End If
End Function

'проверка наличия имени переменной в массиве имен переменных
'(вызываем из функции получения имен переменных)
Function CheckNameArr(strName,intIndex)
    On Error Resume Next
    Dim i
    'если проверяем старое имя - вычитаем 0, если новое - 1
    For i = 0 To UBound(strNameArr,2) - intIndex
        If strNameArr(intIndex,i) = strName Then 
            CheckNameArr = True
            Exit Function
        End If
    Next
    CheckNameArr = False
End Function

'получаем случайное имя (вызываем из функции получения имен переменных)
Function GetRandomName(CharArray,intMaxLen,intPro)
    On Error Resume Next
    Dim arrReturnName() 'массив случайных букв и цифр для создания имени
    Dim i, j
    Dim strRandomName
    Randomize
    'рандомизируем количество символов в новом имени от 2 до 10
    j = Int((intMaxLen - 1) * Rnd) + 2
    
    Redim arrReturnName(j)
    
    'первый символ - буква
    arrReturnName(0) = CharArray(Int((UBound(CharArray) + 1) * Rnd))
    For i = 1 To j    
        If Rnd < intPro/100 Then 'вычисляем процент букв
            arrReturnName(i) = CharArray(Int((UBound(CharArray) + 1) * Rnd))
        Else 
            arrReturnName(i) = Int(10 * Rnd)
        End If
    Next
        
    GetRandomName = Join(arrReturnName,vbNullString)
End Function

'переименование переменных
Function RenameVar(regEx)
    On Error Resume Next
    Dim i, j
    For i = 0 To UBound(strArr) 'бежим по массиву строк из файла
        For j = 1 To UBound(strNameArr,2) 'дальше по массиву имен переменных
            'устанавливаем шаблон, заготовленный в 3-й размерности массива
            regEx.Pattern = strNameArr(2,j)
            'сначала проверяем - таким образом сокращаем количество итераций
            If regEx.Test(strArr(i)) Then                 
                strArr(i) = regEx.Replace(strArr(i),strNameArr(1,j))    
            End If
        Next
    Next
    RenameVar = Err.Number
End Function

'пишем новый файл
Function WriteFile(strFilePath)
    On Error Resume Next
    Dim objNewFile 'новый файл    
    Dim strNewFileName 'имя нового файла
    Dim strNewFilePath 'путь к новому файлу(с префиксом)
    Dim i
    Dim bTrans 'необходимость трансформации символов
    
    '************** константы для трансформации символов **************
    Const strFirstLine = "Execute(" 'первая строка нового файла
    Const strLastLine = "vbcrlf)" 'последняя строка нового файла    
    'константы для формирования символов новой строки
    Const strCrLf1 = "chr("
    Const strCrLf2 = ")"
    Const strCrLf3 = " & "
    Const strCrLf4 = " & _"
    '******************************************************************
    
    'собираем имя нового файла
    strNewFileName = strNewNamePref & "-" & fso.GetFileName(strFilePath)    
    'собираем путь к файлу            
    strNewFilePath = fso.BuildPath(fso.GetParentFolderName( _
            fso.GetAbsolutePathName(strFilePath)),strNewFileName)     
    'создаем новый файл, если существует - заменим    
    Set objNewFile = fso.CreateTextFile(strNewFilePath,True) 
    
    'собираем признак необходимости трансформации
    bTrans = bTransChr And CheckTransChr(strArr(i),strFirstLine)
    
    'если трансформируем символы - пишем первую строку
    If bTrans Then objNewFile.Write strFirstLine
        
    'пишем обновленный массив в новый файл
    For i = 0 To UBound(strArr) 'пропустим пустые строки            
        If strArr(i) <> vbNullString Then 
            'если трансформируем символы - отправляем строку в функцию трансформации
            If bTrans Then strArr(i) = TransChr(strArr(i)) & _
                    strCrLf1 & GetRandExp(13) & strCrLf2 & strCrLf3 & strCrLf1 & GetRandExp(10) & strCrLf2 & strCrLf4
            objNewFile.WriteLine strArr(i) 'пишем строку в новый файл
        End If
    Next
    
    'если трансформируем символы - пишем последнюю строку
    If bTrans Then objNewFile.WriteLine strLastLine    
    
    objNewFile.Close 'закрываем файл
    Set objNewFile = Nothing 'удаляем ссылку на файл
    
    'запись лога
    If bStir And bWriteLog Then 'проверяем необходимость
        'если нет ошибок - пишем лог
        If Not Err.Number Then 
            'собираем путь к файлу лога
            strNewFilePath = fso.BuildPath(fso.GetParentFolderName( _
                fso.GetAbsolutePathName(strFilePath)),strNewFileName & strNewLogSuf)     
            Set objNewFile = fso.CreateTextFile(strNewFilePath,True) 
            objNewFile.WriteLine "True name;Stirred name"
            'пишем обновленный массив в новый файл
            For i = 0 To UBound(strNameArr,2)         
                objNewFile.WriteLine strNameArr(0,i) & ";" & strNameArr(1,i)
            Next
            objNewFile.Close 'закрываем файл
            Set objNewFile = Nothing 'удаляем ссылку на файл
        End If
    End If
    WriteFile = Err.Number
End Function

'трансформация символов (вызываем из функции записи нового файла)
Function TransChr(strInput)
    Dim ret    
    For i = 1 To Len(strInput)
        ret = ret & "chr( " & GetRandExp(Asc(Mid(strInput,i,1)) ) & " ) & "        
    Next
    TransChr = ret
End Function

'получение случайного выражения 
'(вызываем из функций записи нового файла и трансформации символов)
Function GetRandExp(intChr)
    Dim intRandInt, intRandExp
    Randomize
    intRandInt = Int(rnd * 10000)
    intRandExp = Int(rnd * 3)
    If intRandExp = 0 Then 
        GetRandExp = (intRandInt+intChr) & "-" & intRandInt
    ElseIf intRandExp = 1 Then 
        GetRandExp = (intChr-intRandInt) & "+" & intRandInt
    Else 
        GetRandExp = (intChr*intRandInt) & "/" & intRandInt
    End If
End Function

'проверка файла на необходимость трансформации символов
'False - уже трансформированы
Function CheckTransChr(strInput,strFirstLine)
    If Left(strInput,8) = strFirstLine Then
        CheckTransChr = False
    Else
        CheckTransChr = True
    End If
End Function

Как выглядит скрипт после преображения собственного исходного кода с трансформацией символов и без - во вложении.
По причине нежного отношения к обфусцированному коду некоторых параноидальных антивирусов, пароль на архив - script-coding.com.

Post's attachments

VBShaker.zip 36.81 kb, 81 downloads since 2011-08-20 

You don't have the permssions to download the attachments of this post.

2 (изменено: dab00, 2012-03-15 15:54:31)

Re: VBS: Обфускация VBScript-кода

- Исправил баг. Скрипт объединяет строки, перенесенные с помощь символа нижнего подчеркивания - "_". Встречаются методы объектов, название которых заканчивается этим символом - например SpawnInstance_. Изменил шаблон объединения строк: strFindJumpPattern = " _$" - добавил пробел

- Исправил преамбулу поста с "VBS-скрипт для преображения кода VB" на "VBS-скрипт для преображения кода VBScript", т.к. скрипт работает только с кодом VBScript (согласно заголовку).

3 (изменено: dab00, 2013-11-07 16:40:28)

Re: VBS: Обфускация VBScript-кода

Сервис по мотивам скрипта.
HTA:


<html>
<head>
    <title>VBShaker - VBScript code obfuscation</title>
    <meta http-equiv=content-type content="text-html; charset=windows-1251">
    <meta http-equiv=MSThemeCompatible content=yes>
    <hta:application              
        icon=wscript.exe
        scroll=no
        windowstate=maximize
        version="1.0"
    >
</head>
<style type="text/css">
    textarea {width:49%; height:93%; font: normal 12px sans-serif}
    #scr1 {float:left;}
    #scr2 {float:right;}
    #btn,#btn1 {position:relative; font: bold 12px sans-serif; width:100px; height:25px; cursor:hand;}
    #btn {float:left; margin:0px 3px 3px 0px;}
    #btn1 {float:right; margin:0px 0px 3px 3px;}
    #tip {display:none; position:absolute; background:#fff; top:3px;left:110px; color:#000; padding:3px; font: bold italic 12px sans-serif;    filter:alpha(opacity=80);}
    #clr {clear:both;}
    #chk{float:left; position:relative;font: bold italic 12px sans-serif;}
    input {vertical-align:middle; margin:4px;}
    #min1,#max1,#proc1,#proc2 {height:18px; width:25px; font: bold 12px sans-serif;}
    #cr {font: bold italic 12px sans-serif; text-align: center;}
    
</style>

<script language="JavaScript">    
    function mainFunction() {
        var arrLines;        
        if (document.all){
            arrLines = scr1.value.split("\r\n");
        }
        else {
            arrLines = scr1.value.split("\n");
        }
        var ret = validateValues();
        if (ret != "") {
            alert(ret);
            return;
        }        
        if (chk1.checked) {
            removeComments(arrLines);
        }        
        if (chk2.checked) {
            var nameArr = getVarName(arrLines);
            if (log1.checked) {
                var log = open("","","height=400,width=600");
                if (log != null) {
                    var logHTML = ""
                    for(var i=0; i<nameArr.length; i++) {            
                        logHTML += nameArr[i][0] + " = " + nameArr[i][1] + "<br/>";                
                    }                
                    log.document.write(logHTML);
                    log.focus();
                }
            }
        }
        scr2.value = "";        
        scr2.value = arrLines.join("\n");        
    }    
    function validateValues() {    
        var ret = "";        
        var temp = parseInt(min1.value);
        if (min1.value.search(/\D/)!=-1 || temp < 2 || temp > 255) {
            ret += "min char should be an integer between 2 and 255 \n";
        }
        temp = parseInt(max1.value);
        if (max1.value.search(/\D/)!=-1 || temp < 2 || temp > 255) {
            ret += "max char should be an integer between 2 and 255 \n";
        }
        temp = parseInt(proc1.value);
        if (proc1.value.search(/\D/)!=-1 || temp < 0 || temp > 100) {
            ret += "% letters should be an integer between 0 and 100 \n";
        }
        temp = parseInt(proc2.value);
        if (proc2.value.search(/\D/)!=-1  || temp < 0 || temp > 100) {
            ret += "% upper case should be an integer between 0 and 100 \n";
        }        
        return ret;
    }
    function getVarName(arrLines) {
        var nameArr = [];
        for(var i=0; i<arrLines.length; i++) {            
            if (arrLines[i].search(/\b(?:dim|const|sub|function|public|private|class|property)\b[^(?:\"|_$)]/i)!=-1 && 
                arrLines[i].search(/\b(?:end|class_initialize|class_terminate)\b/i)==-1) {                
                var temp = arrLines[i].replace(/\b(?:dim|const|public|private|sub|function|class|property|get|let|set)\b|\(|\)|,|\d|=.*?(?:,|'.*$|\brem\b.*$|$)/gi," ")
                    .replace(/^\s+|\s+$/g,"").split(/\s+/);                
                for(var j=0; j<temp.length; j++) {                    
                    var nameFound = false;
                        for(var k=0; k<nameArr.length; k++) {
                            if(temp[j] == nameArr[k][0]) {
                                nameFound = true;
                                break;
                            }
                        }
                    if(!nameFound) {                        
                        var newnameFound = true;
                        while(newnameFound) {
                            var tempName = getRandomName();
                            for(var k=0; k<nameArr.length; k++) {
                                if (tempName == nameArr[k][1]) {                                    
                                    break;
                                }
                            }
                            if (checkRandomName(tempName)) {
                                newnameFound = false;
                            }
                        }                        
                        nameArr.push([temp[j],tempName,new RegExp('\\b'+temp[j]+'\\b(?!")','g')]);                                            
                    }
                }                            
            }            
        }
        for(var i=0; i<arrLines.length; i++) {            
            for(var j=0; j<nameArr.length; j++) {
                arrLines[i] = arrLines[i].replace(nameArr[j][2],nameArr[j][1]);
            }
        }
        return nameArr;
    }
    function getRandomName() {
        var max = parseInt(max1.value);
        var min = parseInt(min1.value);
        var proc = parseInt(proc1.value);
        var procU = parseInt(proc2.value);
        var charArray = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","_"]        
        if (Math.random() < procU/100) {
            var retArr = [charArray[Math.floor(Math.random() * 26)].toUpperCase()];
        }
        else {
            var retArr = [charArray[Math.floor(Math.random() * 26)]];
        }
        var varLen = Math.floor(Math.random() * (max - min + 1)) + min;        
        for (i=1; i<varLen; i++) {
            if (Math.random() < proc/100) {
                if (Math.random() < procU/100) {
                    retArr.push(charArray[Math.floor(Math.random() * 27)].toUpperCase());                    
                }
                else {                    
                    retArr.push(charArray[Math.floor(Math.random() * 27)]);
                }                
            }
            else {
                retArr.push(Math.floor(Math.random() * 10));
            }
        }
        return retArr.join("");
    }
    function checkRandomName(name) {        
        if (name.substring(0,1) == "vb") {
            return false;
        }        
        var arr = ["dim","const","public","private","sub","function","class","property","get","let","set","class_initialize","class_terminate",
            "if","or","and","not","then","else","elseif","end","for","each","in","to","step","next","do","while","loop","until","wend","select","case","exit","with",
            "xor","err","call","on","error","resume","goto","redim","preserve","me","mod","rem","new","true","false","option","explicit",
            "date","dateadd","datediff","datepart","dateserial","datevalue","day","formatdatetime","hour","isdate","minute","month","monthname",
            "now","second","time","timer","timeserial","timevalue","weekday","weekdayname","year",
            "asc","cbool","cbyte","ccur","cdate","cdbl","chr","cint","clng","csng","cstr","hex","oct",
            "formatcurrency","formatdatetime","formatnumber","formatpercent",
            "abs","atn","cos","exp","int","fix","log","oct","rnd","sgn","sin","sqr","tan",
            "array","filter","isarray","join","lbound","split","ubound",
            "instr","instrrev","lcase","left","len","ltrim","rtrim","trim","mid","replace","right","space","strcomp","string","strreverse","ucase",
            "createobject","eval","getlocale","getobject","getref","inputbox","isempty","isnull","isnumeric","isobject","loadpicture","msgbox",
            "rgb","round","scriptengine","scriptenginebuildversion","scriptenginemajorversion","scriptengineminorversion","setlocale","typename","vartype"];                    
        for(var i=0; i<arr.length; i++) {
            if(name == arr[i]) {
                return false;
            }
        }        
        return true;
    }
    function removeComments(arrLines) {        
        for(var i=0; i<arrLines.length; i++) {                        
            arrLines[i] = arrLines[i].replace(/^\s+|^\s*(?:'|\brem\b).*$|(?:'|\brem\b)[^(?:\"|_$)].*$|\s+$/gi,"");                        
            if (arrLines[i].search(/^\s*$/)!=-1) {
                arrLines.splice(i,1);
                i--;                
            }
        }    
    }    
    function clearFunction() {
        scr1.value = "";
        scr2.value = "";
        min1.value = "2";
        max1.value = "10";
        proc1.value = "60";
        proc2.value = "40";
        log1.checked = false;
    }
</script>

<body>
    <button id="btn" onclick="mainFunction()" onmouseover="tip.style.display = 'block'" onmouseout="tip.style.display = 'none'">S H A K E &nbsp;&nbsp;I T</button>    
    <div id="chk">
        <input id="chk1" type="checkbox" checked="checked" />remove comments
        <input id="chk2" type="checkbox" checked="checked" />rename explicitly declared variables
        <input id="min1" type="text" value="2" />min char
        <input id="max1" type="text" value="10" />max char
        <input id="proc1" type="text" value="60" />% letters
        <input id="proc2" type="text" value="40" />% upper case
        <input id="log1" type="checkbox" />log
    </div>
    <button id="btn1" onclick="clearFunction()">C L E A R</button>
    <span id="tip">don't break it, took me time to make it</span>
    <div id="clr"></div>
    <textarea id="scr1"></textarea>
    <textarea id="scr2"></textarea>
    <div id="cr">Copyright © by  <a href="http://www.daspot.ru">Anatoly Demidovich</a></div>
</body>
</html>

upd: В свете последних событий с народом, сервис на Google Drive.