#!/usr/bin/env python # -*- coding: utf-8 -*- import socket import struct import time import hashlib import sys import os import random import traceback # CONFIG server = "192.168.100.150" username = "" password = "" host_name = "LIYUANYUAN" host_os = "8089D" host_ip = "10.30.22.17" PRIMARY_DNS = "114.114.114.114" dhcp_server = "0.0.0.0" mac = 0xb888e3051680 CONTROLCHECKSTATUS = '\x20' ADAPTERNUM = '\x01' KEEP_ALIVE_VERSION = '\xdc\x02' ''' AUTH_VERSION: unsigned char ClientVerInfoAndInternetMode; unsigned char DogVersion; ''' AUTH_VERSION = '\x0a\x00' IPDOG = '\x01' ror_version = False # CONFIG_END keep_alive1_mod = False #If you have trouble at KEEPALIVE1, turn this value to True nic_name = '' #Indicate your nic, e.g. 'eth0.2'.nic_name bind_ip = '0.0.0.0' class ChallengeException (Exception): def __init__(self): pass class LoginException (Exception): def __init__(self): pass def bind_nic(): try: import fcntl def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) return get_ip_address(nic_name) except ImportError as e: print('Indicate nic feature need to be run under Unix based system.') return '0.0.0.0' except IOError as e: print(nic_name + 'is unacceptable !') return '0.0.0.0' finally: return '0.0.0.0' if nic_name != '': bind_ip = bind_nic() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((bind_ip, 61440)) s.settimeout(3) SALT = '' IS_TEST = True # specified fields based on version CONF = "/etc/drcom.conf" UNLIMITED_RETRY = True EXCEPTION = False DEBUG = False #log saves to file LOG_PATH = '/var/log/drcom_client.log' if IS_TEST: DEBUG = True LOG_PATH = 'drcom_client.log' def log(*args, **kwargs): s = ' '.join(args) print s if DEBUG: with open(LOG_PATH,'a') as f: f.write(s + '\n') def challenge(svr,ran): while True: t = struct.pack(">5)) return ret def gen_crc(data, encrypt_type): DRCOM_DIAL_EXT_PROTO_CRC_INIT = 20000711 ret = '' if encrypt_type == 0: # 加密方式无 return struct.pack('h', i)[0] # ret &= 0xFFFF # ret = ret * 0x2c7 # return ret def keep_alive2(*args): #first keep_alive: #number = number (mod 7) #status = 1: first packet user sended # 2: first packet user recieved # 3: 2nd packet user sended # 4: 2nd packet user recieved # Codes for test tail = '' packet = '' svr = server ran = random.randint(0,0xFFFF) ran += random.randint(1,10) # 2014/10/15 add by latyas, maybe svr sends back a file packet svr_num = 0 packet = keep_alive_package_builder(svr_num,dump(ran),'\x00'*4,1,True) while True: log('[keep-alive2] send1',packet.encode('hex')) s.sendto(packet, (svr, 61440)) data, address = s.recvfrom(1024) log('[keep-alive2] recv1',data.encode('hex')) if data.startswith('\x07\x00\x28\x00') or data.startswith('\x07' + chr(svr_num) + '\x28\x00'): break elif data[0] == '\x07' and data[2] == '\x10': log('[keep-alive2] recv file, resending..') svr_num = svr_num + 1 # packet = keep_alive_package_builder(svr_num,dump(ran),'\x00'*4,1, False) break else: log('[keep-alive2] recv1/unexpected',data.encode('hex')) #log('[keep-alive2] recv1',data.encode('hex')) ran += random.randint(1,10) packet = keep_alive_package_builder(svr_num, dump(ran),'\x00'*4,1,False) log('[keep-alive2] send2',packet.encode('hex')) s.sendto(packet, (svr, 61440)) while True: data, address = s.recvfrom(1024) if data[0] == '\x07': svr_num = svr_num + 1 break else: log('[keep-alive2] recv2/unexpected',data.encode('hex')) log('[keep-alive2] recv2',data.encode('hex')) tail = data[16:20] ran += random.randint(1,10) packet = keep_alive_package_builder(svr_num,dump(ran),tail,3,False) log('[keep-alive2] send3',packet.encode('hex')) s.sendto(packet, (svr, 61440)) while True: data, address = s.recvfrom(1024) if data[0] == '\x07': svr_num = svr_num + 1 break else: log('[keep-alive2] recv3/unexpected',data.encode('hex')) log('[keep-alive2] recv3',data.encode('hex')) tail = data[16:20] log("[keep-alive2] keep-alive2 loop was in daemon.") i = svr_num while True: try: time.sleep(20) keep_alive1(*args) ran += random.randint(1,10) packet = keep_alive_package_builder(i,dump(ran),tail,1,False) #log('DEBUG: keep_alive2,packet 4\n',packet.encode('hex')) log('[keep_alive2] send',str(i),packet.encode('hex')) s.sendto(packet, (svr, 61440)) data, address = s.recvfrom(1024) log('[keep_alive2] recv',data.encode('hex')) tail = data[16:20] #log('DEBUG: keep_alive2,packet 4 return\n',data.encode('hex')) ran += random.randint(1,10) packet = keep_alive_package_builder(i+1,dump(ran),tail,3,False) #log('DEBUG: keep_alive2,packet 5\n',packet.encode('hex')) s.sendto(packet, (svr, 61440)) log('[keep_alive2] send',str(i+1),packet.encode('hex')) data, address = s.recvfrom(1024) log('[keep_alive2] recv',data.encode('hex')) tail = data[16:20] #log('DEBUG: keep_alive2,packet 5 return\n',data.encode('hex')) i = (i+2) % 0xFF except: break def checksum(s): ret = 1234 x = 0 for i in [x*4 for x in range(0, -(-len(s)//4))]: ret ^= int(s[i:i+4].ljust(4, '\x00')[::-1].encode('hex'), 16) ret = (1968 * ret) & 0xffffffff return struct.pack(' data += '\00' * 4 #your ipaddress 2 data += '\00' * 4 #your ipaddress 3 data += '\00' * 4 #your ipaddress 4 data += md5sum(data + '\x14\x00\x07\x0B')[:8] #md53 data += IPDOG data += '\x00'*4 # unknown2 ''' struct _tagOSVERSIONINFO { unsigned int OSVersionInfoSize; unsigned int MajorVersion; unsigned int MinorVersion; unsigned int BuildNumber; unsigned int PlatformID; char ServicePack[128]; }; struct _tagHostInfo { char HostName[HOST_NAME_MAX_LEN]; unsigned int DNSIP1; unsigned int DHCPServerIP; unsigned int DNSIP2; unsigned int WINSIP1; unsigned int WINSIP2; struct _tagDrCOM_OSVERSIONINFO OSVersion; }; ''' data += host_name.ljust(32, '\x00') # _tagHostInfo.HostName data += ''.join([chr(int(i)) for i in PRIMARY_DNS.split('.')]) # _tagHostInfo.DNSIP1 data += ''.join([chr(int(i)) for i in dhcp_server.split('.')]) # _tagHostInfo.DHCPServerIP data += '\x00\x00\x00\x00' # _tagHostInfo.DNSIP2 data += '\x00' * 4 # _tagHostInfo.WINSIP1 data += '\x00' * 4 # _tagHostInfo.WINSIP2 data += '\x94\x00\x00\x00' # _tagHostInfo.OSVersion.OSVersionInfoSize data += '\x05\x00\x00\x00' # _tagHostInfo.OSVersion.MajorVersion data += '\x01\x00\x00\x00' # _tagHostInfo.OSVersion.MinorVersion data += '\x28\x0A\x00\x00' # _tagHostInfo.OSVersion.BuildNumber data += '\x02\x00\x00\x00' # _tagHostInfo.OSVersion.PlatformID # _tagHostInfo.OSVersion.ServicePack data += host_os.ljust(32, '\x00') data += '\x00' * 96 # END OF _tagHostInfo data += AUTH_VERSION if ror_version: ''' struct _tagLDAPAuth { unsigned char Code; unsigned char PasswordLen; unsigned char Password[MD5_LEN]; }; ''' data += '\x00' # _tagLDAPAuth.Code data += chr(len(pwd)) # _tagLDAPAuth.PasswordLen data += ror(md5sum('\x03\x01' + salt + pwd), pwd) # _tagLDAPAuth.Password ''' struct _tagDrcomAuthExtData { unsigned char Code; unsigned char Len; unsigned long CRC; unsigned short Option; unsigned char AdapterAddress[MAC_LEN]; }; ''' data += '\x02' # _tagDrcomAuthExtData.Code data += '\x0C' # _tagDrcomAuthExtData.Len data += checksum(data + '\x01\x26\x07\x11\x00\x00' + dump(mac)) # _tagDrcomAuthExtData.CRC data += '\x00\x00' # _tagDrcomAuthExtData.Option data += dump(mac) # _tagDrcomAuthExtData.AdapterAddress # END OF _tagDrcomAuthExtData if ror_version: data += '\x00' * (8 - len(pwd)) if len(pwd)%2: data += '\x00' else: data += '\x00' # auto logout / default: False data += '\x00' # broadcast mode / default : False data += '\xE9\x13' #unknown, filled numbers randomly =w= log('[mkpkt]',data.encode('hex')) return data def login(usr, pwd, svr): global SALT global AUTH_INFO i = 0 timeoutcount = 0 while True: salt = challenge(svr,time.time()+random.randint(0xF,0xFF)) SALT = salt packet = mkpkt(salt, usr, pwd, mac) log('[login] send',packet.encode('hex')) s.sendto(packet, (svr, 61440)) log('[login] packet sent.') try: data, address = s.recvfrom(1024) log('[login] recv',data.encode('hex')) if address == (svr, 61440) : if data[0] == '\x04': log('[login] loged in') AUTH_INFO = data[23:39] break else: log('[login] login failed.') if IS_TEST: time.sleep(3) else: time.sleep(30) continue else: if i >= 5 and UNLIMITED_RETRY == False : log('[login] exception occured.') sys.exit(1) else: i += 1 continue except socket.timeout as e: print(e) log('[login] recv timeout.') timeoutcount += 1 if timeoutcount >= 5: log('[login] recv timeout exception occured 5 times.') sys.exit(1) else: continue log('[login] login sent') #0.8 changed: return data[23:39] #return data[-22:-6] def logout(usr, pwd, svr, mac, auth_info): salt = challenge(svr, time.time()+random.randint(0xF, 0xFF)) if salt: data = '\x06\x01\x00' + chr(len(usr) + 20) data += md5sum('\x03\x01' + salt + pwd) data += usr.ljust(36, '\x00') data += CONTROLCHECKSTATUS data += ADAPTERNUM data += dump(int(data[4:10].encode('hex'),16)^mac).rjust(6, '\x00') # data += '\x44\x72\x63\x6F' # Drco data += auth_info s.send(data) data, address = s.recvfrom(1024) if data[:1] == '\x04': log('[logout_auth] logouted.') def keep_alive1(salt,tail,pwd,svr): if keep_alive1_mod: res='' while True: s.sendto('\x07' + struct.pack('!B',int(time.time())%0xFF) + '\x08\x00\x01\x00\x00\x00', (svr, 61440)) log('[keep_alive1_challenge] keep_alive1_challenge packet sent.') try: res, address = s.recvfrom(1024) log('[keep_alive1_challenge] recv', res.encode('hex')) except: log('[keep_alive1_challenge] timeout, retrying...') continue if address == (svr, 61440): if res[0] == '\x07': break else: raise ChallengeException else: continue seed = res[8:12] # encrypt_type = int(res[5].encode('hex')) encrypt_type = struct.unpack('