вторник, 26 июля 2011 г.

Синхронизация Microsoft DNS с MySQL (VBScript)

Иногда полезно иметь реплику записей DNS на сервере MySQL. Эти данные можно использовать для построения различных схем сети, подсчета компьютеров и т.д.


В данном примере я использовал WMI для синхронизации базы Microsoft DNS с MySQL сервером.

В начале скрипт делает полную копию базы DNS. Затем устанавливает обработчик для каждого из событий Создания/Изменения/Удаления


Каждое событие вносит изменения в MySQL. Такой подход позволяет иметь точную реплику записей DNS в MySQL без заметных задержек.


Исходный код можно увидеть ниже.
Не забудьте изменить имя NetBios сервера DNS и учетные данные MySQL в верху кода.

'NetBios имя DNS сервера
Const SERVERNAME = "SERVER"

'Учетные данные MySQL
Const host="localhost"
Const Db="system"
Const login= "user"
Const password="userpassword"

'Опции подключения к MySQL
Const MYDRIVER = "MySQL ODBC 5.1 Driver"
Const FLAG_BIG_PACKETS = 8 'Allow big results
Const FLAG_NO_PROMPT = 16 'Dont prompt anything
Const FLAG_DYNAMIC_CURSOR = 32 'Allow dynamic cursor
Const FLAG_COMPRESSED_PROTO = 2048 'Use compressed protocol
Const FLAG_NO_BIGINT = 16384 'Change bigint(8) to int(4)
Const FLAG_MULTI_STATEMENTS = 67108864 'Enable batch statements
Const FLAG_AUTO_RECONNECT = 4194304 'Auto reconnect

'ADODB connection
Dim conn

'Создание глобальных объектов
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}\\" & SERVERNAME & "\root\MicrosoftDNS")
Set objSink = WScript.CreateObject("WBemScripting.SWbemSink","event_")
Set objShell = CreateObject("WScript.Shell")

'Выход, если уже запущен
Set oProcess = Nothing
If alreadyRunning() Then: WScript.Quit

If Not MySQLConnect() Then
WScript.Quit
Else
PrepareDatabase
End If

'Инициализация таблицы
MySQLExecute "DELETE FROM dns_cache"
Set dnsRecords = objWMIService.ExecQuery( "SELECT * FROM MicrosoftDNS_AType", "WQL", 48 )
For Each objRecord in dnsRecords
domain = objRecord.DomainName
name = Replace(objRecord.OwnerName,domain,"")
ip = objRecord.IPAddress 
ttl = objRecord.TTL
timestamp = objRecord.Timestamp
OnCreation domain,name,ip,timestamp,ttl
Next

'Установка обработчика событий
objWMIService.ExecNotificationQueryAsync objSink, "Select * from __InstanceOperationEvent within 1 where TargetInstance ISA 'MicrosoftDNS_AType'"

'Бесконечный цикл
Do
WScript.Sleep 1000
Loop

'Обработчик событий
Sub event_OnObjectReady( objEvent, objContext )
With objEvent
domain = objEvent.TargetInstance.DomainName
name = Replace(objEvent.TargetInstance.OwnerName,domain,"")
ip = objEvent.TargetInstance.IPAddress 
ttl = objEvent.TargetInstance.TTL
timestamp = objEvent.TargetInstance.timestamp
if name <> "" Then
Select Case .Path_.Class
Case "__InstanceModificationEvent"
OnModify domain,name,ip,timestamp,ttl
Case "__InstanceCreationEvent"
OnCreation domain,name,ip,timestamp,ttl
Case "__InstanceDeletionEvent"
OnDeletion domain,name,ip
End Select
End If
End With
End Sub

'Обработчик для события изменения
Sub OnModify( domain, name,ip,timestamp,ttl )
update = "domainname='" & domain & "',hostname='" & name & "',ipaddress=inet_aton('" & ip & "')," & _ 
"refreshon=IF(" & timestamp & "=0,Null,'1601-01-01 00:00') + INTERVAL " & timestamp & " HOUR,ttl=" & ttl
MySQLExecute "INSERT INTO dns_cache SET " & update & " ON DUPLICATE KEY UPDATE " & update
End Sub

'Обработчик для события создания
Sub OnCreation( domain, name,ip,timestamp,ttl )
update = "domainname='" & domain & "',hostname='" & name & "',ipaddress=inet_aton('" & ip & "')," & _
"refreshon=IF(" & timestamp & "=0,Null,'1601-01-01 00:00') + INTERVAL " & timestamp & " HOUR,ttl=" & ttl
MySQLExecute "INSERT INTO dns_cache SET " & update & " ON DUPLICATE KEY UPDATE " & update 
End Sub

'Обработчик для события удаления
Sub OnDeletion( domain, name,ip )
MySQLExecute "DELETE FROM dns_cache WHERE hostname='" & name & "' AND ipaddress=inet_aton('" & ip & "') AND domainname='" & domain & "'"
End Sub

'Создание базы данных, если еще не создана
Function PrepareDatabase
CreateDatabase = False
On Error Resume Next
MySQLExecute "CREATE DATABASE IF NOT EXISTS " & db & " CHARACTER SET utf8 COLLATE utf8_general_ci"
On Error Goto 0
MySQLExecute "USE " & db
MySQLExecute "CREATE TABLE IF NOT EXISTS dns_cache(" & _
"hostname VARCHAR(255) NOT NULL," & _
"domainname VARCHAR(255) NOT NULL," & _
"ipaddress INT(11) UNSIGNED NOT NULL," & _
"refreshon DATETIME DEFAULT NULL," & _
"ttl INT(11) NOT NULL DEFAULT 0," & _
"PRIMARY KEY (ipaddress, hostname, domainname)," & _
"INDEX IX_dns_cache_deadline (refreshon)," & _
"INDEX IX_dns_cache_domainname (domainname)," & _
"INDEX IX_dns_cache_ipaddress (ipaddress)," & _
"INDEX IX_dns_cache_name (hostname)," & _
"INDEX IX_dns_cache_ttl (ttl)" & _
") " & _
"ENGINE = INNODB " & _
"AVG_ROW_LENGTH = 68 " & _
"CHARACTER SET utf8 " & _
"COLLATE utf8_general_ci;"
If Err.Number <> 0 Then: CreateDatabase = True
End Function

Function alreadyRunning()
alreadyRunning = False
wscrCount = ProcessCount( "%wscript%" & WScript.ScriptName & "%" )
cscrCount = ProcessCount( "%cscript%" & WScript.ScriptName & "%" )
If wscrCount > 1 or cscrCount > 1 Then:alreadyRunning = True
End Function

Public Function ProcessCount(likestr)
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}\\.\root\cimv2")
Set colItems = objWMI.ExecQuery("SELECT Name,CommandLine FROM Win32_Process WHERE CommandLine Like '" & likestr & "'")
ProcessCount = colItems.Count
End Function 

'Процедуры MySQL
Function MySQLExecute( cmd )
On Error Resume Next
Set rst = conn.Execute( cmd )
If conn.Errors.Count > 0 Then
If conn.Errors(conn.Errors.Count-1).NativeError = 2006 Then 
conn.Errors.Clear
If InitConnection() Then
Set rst = conn.Execute( cmd )
End If
End If 
End If
If rst.State = 1 And Err.Number = 0 Then
Set MySQLExecute = rst
Else
Set MySQLExecute = conn.Execute( "SELECT Null LIMIT 0" )
End If
On Error Goto 0
End Function

Function MySQLConnect
Set conn = CreateObject("ADODB.Connection")
MySQLConnect = False
On Error Resume next
conn.ConnectionString = "DRIVER={" & MYDRIVER & "};" & _
"SERVER=" & host & ";" & _
"UID=" & login & ";" & _
"PWD=" & password & ";" & _
"OPTION=" & (FLAG_BIG_PACKETS + FLAG_COMPRESSED_PROTO + FLAG_NO_BIGINT + FLAG_MULTI_STATEMENTS)
conn.ConnectionTimeout = 3
conn.Open
If Err.Number = -2147467259 Then
MsgBox "MyODBC isn't installed. Can't connect to MySQL!"
Exit Function
End If
If Err.Number <> 0 Then
MsgBox err.description
Exit Function
End If
MySQLConnect = True
On Error GoTo 0
End Function

Sub MySQLDisconnect
conn.Close
Set conn = Nothing
End Sub

суббота, 16 июля 2011 г.

Мониторинг подключения/отключения USB устройств на VBScript

Некоторое время назад у меня завялся телефон на Android. Чтобы управлять им с компьютера я установил MyPhoneExplorer.
Это отличная программа, но все-же в ней не хватает одной важной для меня функции, а именно: автоматического переподключения при подключении телефона к USB. С другой стороны в ней есть такая опция, как "Подключаться при запуске".
Отсюда у меня появилась идея написать скриптик, который будет прибивать процесс MyPhoneExplorer при отключении телефона и запускать при подключении.
Наконец я оформил это на VBScript. Этот скрипт наблюдает за подключением/отключением устройства под названием "Android ADB Interface" и выполняет соответствующие действия:
Const DEVICENAME = "Android ADB Interface"
Const EXENAME = "MyPhoneExplorer.exe"
Dim lastOperation
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}\\.\root\cimv2")

'Выйти, если скрипт уже запущен
If alreadyRunning() Then: WScript.Quit

Set objSink = WScript.CreateObject("WBemScripting.SWbemSink","event_")
Set objShell = CreateObject("WScript.Shell")
Set deviceIDs = CreateObject("Scripting.Dictionary")

'Установим перехватчик событий
objWMIService.ExecNotificationQueryAsync objSink, "Select * from __InstanceOperationEvent within 1 where TargetInstance ISA 'Win32_PnPEntity'"

'Получим ID устройств по заданному имени
EnumerateDevices DEVICENAME
objShell.Popup "Мониторинг USB начат!",2
'Бесконечный цикл
Do
 WScript.Sleep 1000
Loop

'Перехватчик событий подключения/отключения USB устройств
Sub event_OnObjectReady( objEvent, objContext )
 With objEvent
  If deviceIDs.Exists(.TargetInstance.DeviceId) Then
   Select Case .Path_.Class
    Case "__InstanceCreationEvent"
     If lastOperation <> "Insert" Then
      lastOperation = "Insert"
      OnInsert
     End If
      
    Case "__InstanceDeletionEvent"
     If lastOperation <> "Remove" Then
      lastOperation = "Remove"
      OnRemove
     End If
    End Select
  End If
 End With
End Sub

Sub OnInsert
 objShell.Run EXENAME,1,0
End Sub

Sub OnRemove
 objShell.Run "taskkill /f /im " & EXENAME,0,0
End Sub

Sub EnumerateDevices(name)
 Set objDevices = objWMIService.ExecQuery("SELECT DeviceId FROM Win32_PnPSignedDriver WHERE Description='" & name & "'")
 For Each dev in objDevices
  deviceId = dev.DeviceId
  If Not deviceIDs.Exists(deviceId) Then
   deviceIDs.Add deviceId, deviceId
  End If
  d = d + 1
 Next
End Sub

Function alreadyRunning()
 alreadyRunning = False
 wscrCount = ProcessCount( "%wscript%" & WScript.ScriptName & "%" )
 cscrCount = ProcessCount( "%cscript%" & WScript.ScriptName & "%" )
 If  wscrCount > 1 or cscrCount > 1 Then:alreadyRunning = True
End Function

Public Function ProcessCount(likestr)
 Set colItems = objWMIService.ExecQuery("SELECT Name,CommandLine FROM Win32_Process WHERE CommandLine Like '" & likestr & "'")
 ProcessCount = colItems.Count
End Function   

VBS-файл можно скачать здесь

пятница, 22 января 2010 г.

Взлом пароля Excel. Макрос VBA, на основе Excel

Существует простой способ взломать забытый пароль Excel. И что немаловажно, сделать это можно абсолютно бесплатно с помощью самого Excel.
Итак если файл открывается, но Вам необходимо убрать защиту листа или книги, используйте надстройку, которую я написал:


Идея алгоритма заключается в использовании недостатка стандартного метода шифрования Excel. Программа перебирает пароли от 1 до 8 символов. Последний символ пароля подбирается из диапазона кодов от 32 до 255. Остальные символы подбираются из кодов 65 и 66. В результате используется пароль отличный от оригинального, но тем не менее рабочий. К сожалению для открытия файла, через Workbook.Open(), этот метод не подходит. Метод также не работает в Excel 2007, где используется более стойкий алгоритм шифрования. Исключение составляет французская версия Excel 2007, где из-за местных законов шифрование остается прежним.

Ниже приведен исходный код надстройки для взлома пароля в Excel:

Const MENUNAME = "ЗАЩИТА"
'Установка ярлыка меню
Sub Auto_Open()
    Install
    MsgBox "Меню установлено, используйте ""ЗАЩИТА->Снять защиту"" для снятия защиты с активной книги Excel и всех листов"
End Sub

'Взлом всех паролей, путем перебора.
Sub BruteForceUnprotect()
    Dim ProtectedObjects As New Collection
    Const LastCharStart = 32
    Const LastCharFinish = 255
    
    Application.DisplayAlerts = False
    
    'Добавление защищенной книги в набор объектов для вскрытия
    If (ActiveWorkbook.ProtectStructure Or ActiveWorkbook.ProtectWindows) Then
        ProtectedObjects.Add ActiveWorkbook
    End If
    
    'Добавление в набор защищенных листов
    On Error Resume Next
    For Each WSheet In ActiveWorkbook.Worksheets
        WSheet.Protect ("")
        If Not WSheet.Unprotect("") Then: ProtectedObjects.Add WSheet
    Next
    On Error GoTo 0
    
    'Поиск подставного пароля. Оригинальный пароль не может быть восстановлен этим способом.
    For i = 1 To 255
        fakepassword = FakePass(i)
        If ProtectedObjects.Count = 0 Then: Exit For
        For LastCharIndex = LastCharStart To LastCharFinish
            Password = fakepassword & Chr(LastCharIndex)
            If ProtectedObjects.Count > 0 Then
                For j = 1 To ProtectedObjects.Count
                    If UnprotectObject(ProtectedObjects(j), Password) = True Then
                        ProtectedObjects.Remove (j)
                        If ProtectedObjects.Count > 0 Then: j = j - 1
                    End If
                Next
            End If
        Next
    Next
    
    If ProtectedObjects.Count = 0 Then
        MsgBox "Пароли на текущую книгу и листы сняты!"
    Else
        MsgBox "Похоже используется нестандартное шифрование. Защита некоторых объектов не может быть снята."
    End If
    Application.DisplayAlerts = True
End Sub
Function UnprotectObject(obj, pass)
  UnprotectObject = False
  On Error GoTo WrongPassword
  obj.Unprotect pass
  UnprotectObject = True
WrongPassword:
End Function
'Возвращает пароль на основе переданного числового значения
Function FakePass(Value)
    Mask = 1
    FakePass = ""
    While Mask <= Value
        If (Value And Mask) = 0 Then
            FakePass = "A" & FakePass
        Else
            FakePass = "B" & FakePass
        End If
        Mask = Mask * 2
    Wend
    If Len(FakePass) > 0 Then: FakePass = Right(FakePass, Len(FakePass) - 1)
End Function
'Установка меню
Sub Install()
    Uninstall True
    AddButton MENUNAME, "Снять защиту", "BruteForceUnprotect"
    AddButton MENUNAME, "Удалить меню надстройки", "Uninstall"
End Sub
'Удаление меню надстройки
Sub Uninstall(Optional silent = False)
    If Not silent Then
        If MsgBox("Вы действительно желаете удалить меню надстройки ?", vbYesNo) = vbNo Then
            Exit Sub
        End If
    End If
    On Error Resume Next
    Application.CommandBars("Worksheet Menu Bar").Controls(MENUNAME).Delete
    On Error GoTo 0
End Sub
'Добавить пункт в меню
Sub AddButton(menu As String, submenu As String, macro As String, Optional descr As String = "")
    On Error GoTo createmenu
    If IsNull(Application.CommandBars("Worksheet Menu Bar").Controls(menu)) Then: GoTo createmenu
    On Error GoTo create
    If IsNull(Application.CommandBars("Worksheet Menu Bar").Controls(menu).Controls(submenu)) Then: GoTo create
    End
createmenu:
    Set mnu = Application.CommandBars("Worksheet Menu Bar").Controls.Add(Type:=10)
    mnu.Caption = "&" & menu
    mnu.Visible = True
    
create:
    Set Button = Application.CommandBars("Worksheet Menu Bar").Controls(menu).Controls.Add(Type:=1, ID:=2950)
    With Button
        .DescriptionText = descr
        .TooltipText = descr
        .Caption = "&" & submenu
        .Style = 3
        .OnAction = macro
    End With
End Sub