LocalSMB.exe

original
LocalSMB.exe が何やってるか分からなかったので適当に調べて車輪の再発明
LocalSMB.exe は仮想 NICTCP/445 を使えるようにするプログラム。

"""MicrosoftDSDisabler.py
Free TCP/445 (microsoft-ds) in Windows.
Alternative LocalSMB.exe <http://www.sshvpn.de/>.

install
-------
1. Install Python and pywin32.
2. Do the command below as Administrator:
  >MicrosoftDSDisabler.py install --startup auto
3. Reboot the machine.
"""
import socket, time
import win32service, win32serviceutil, win32event


class Service(object):

    def __init__(self, scHandle, name,
                 desiredAccess=win32service.SERVICE_ALL_ACCESS):
        self.scHandle = scHandle
        self.handle = win32service.OpenService(
            scHandle, name, desiredAccess)

    def __del__(self):
        import win32service
        win32service.CloseServiceHandle(self.handle)

    @property
    def Config(self):
        return win32service.QueryServiceConfig(self.handle)

    @property
    def ServiceType(self):
        return self.Config[0]

    def getStartType(self):
        return self.Config[1]

    def setStartType(self, value):
        win32service.ChangeServiceConfig(self.handle,
            win32service.SERVICE_NO_CHANGE, #serviceType
            value, #startType
            win32service.SERVICE_NO_CHANGE, #errorControl
            None, #binaryFile
            None, #loadOrderGroup
            0, #bFetchTag
            None, #serviceDeps
            None, #acctName
            None, #password
            None, #displayName
            )

    StartType = property(getStartType, setStartType)

    @property
    def ErrorControl(self):
        return self.Config[2]

    @property
    def BinaryPathName(self):
        return self.Config[3]

    @property
    def LoadOrderGroup(self):
        return self.Config[4]

    @property
    def TagId(self):
        return self.Config[5]

    @property
    def Dependencies(self):
        return self.Config[6]

    @property
    def ServiceStartName(self):
        return self.Config[7]

    @property
    def DisplayName(self):
        return self.Config[8]

    @property
    def StatusEx(self):
        return win32service.QueryServiceStatusEx(self.handle)

    @property
    def CurrentState(self):
        return self.StatusEx['CurrentState']

    @property
    def ControlsAccepted(self):
        return self.StatusEx['ControlsAccepted']

    @property
    def Win32ExitCode(self):
        return self.StatusEx['Win32ExitCode']

    @property
    def ServiceSpecificExitCode(self):
        return self.StatusEx['ServiceSpecificExitCode']

    @property
    def CheckPoint(self):
        return self.StatusEx['CheckPoint']

    @property
    def WaitHint(self):
        return self.StatusEx['WaitHint']

    @property
    def ProcessId(self):
        return self.StatusEx['ProcessId']

    @property
    def Description(self):
        win32service.QueryServiceConfig2(
            self.handle, win32service.SERVICE_CONFIG_DESCRIPTION)

    def Start(self, args=[]):
        win32service.StartService(self.handle, args)

    def Stop(self):
        win32service.ControlService(
            self.handle, win32service.SERVICE_CONTROL_STOP)


class ServiceManager(object):

    def __init__(self, machineName=None, dbName=None,
                 desiredAccess=win32service.SC_MANAGER_ALL_ACCESS):
        self.handle = win32service.OpenSCManager(
            machineName, dbName, desiredAccess)

    def __del__(self):
        import win32service
        win32service.CloseServiceHandle(self.handle)

    def __getitem__(self, name):
        return self.OpenService(name)

    def LockDatabase(self):
        self.lock = win32service.LockServiceDatabase(self.handle)

    def UnlockDatabase(self):
        win32service.UnlockServiceDatabase(self.lock)
        del self.lock

    def OpenService(self, name, desiredAccess=win32service.SERVICE_ALL_ACCESS):
        return Service(self.handle, name, desiredAccess)


class MyService(win32serviceutil.ServiceFramework):
    _svc_name_ = _svc_display_name_ = 'MicrosoftDSDisabler'

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)

    def SvcDoRun(self):
        socks = []

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('0.0.0.0', 445))
        socks.append(sock)

        sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        sock.bind(('[::]', 445))
        socks.append(sock)

        service = ServiceManager()['LanmanServer']
        service.StartType = win32service.SERVICE_DEMAND_START

        service.Start()
        while service.CurrentState != win32service.SERVICE_RUNNING:
            time.sleep(1)

        for sock in socks:
            sock.close()

        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)

        service.Stop()
        service.StartType = win32service.SERVICE_DISABLED

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)

    SvcShutdown = SvcStop


if __name__ == '__main__':

    def customOptionHandler(options):
        print 'Disabling LanmanServer'
        service = ServiceManager()['LanmanServer']
        service.StartType = win32service.SERVICE_DISABLED

    win32serviceutil.HandleCommandLine(
        MyService, customOptionHandler=customOptionHandler)

  1. Install
    • MicrosoftDSDisabler.py install --startup auto
      • LanmanServer を無効にする
    • この段階ではなぜか net stop LanmanServer しても :445 が解放されない
  2. Reboot
  3. MicrosoftDSDisabler Start
    • IPv4IPv6TCP/445 を確保した状態で LanmanServer を起動
    • LanmanServer が SERVICE_RUNNING になったらソケットを解放

副作用として LanmanServer の再起動が出来る。 (TCP/445 を無効にしているので完全ではないが)