- Entrou
- Dez 10, 2010
- Mensagens
- 39
- Gostos Recebidos
- 0
Como já tinha publicado é possível ter as Openboxes V6 F7S V8S a funcionar sem problemas de imagem nos canais SD (problema conhecido onde temos som mas não temos imagem).
Para tal é necessário instalar a firmware da Solovox V8S plus seja este por USB ou RS232 (null modem).
O problema é que a Solovox não fornece as suas firmwares de forma grátis e tem um processo de licenciamento que deve ser feito por cabo RS232 e software deles.
Decidi abrir este tópico para tornar publico as estratégias que em conjunto com outros utilizadores temos vindo a trabalhar, bem como as nossas descobertas.
Não irei citar esses mesmos que se desejarem identifiquem-se neste tópico.
Ferramentas/Software/Firmware Solovox
http://www.solovox.xyz/download
Resumo do que sabemos em relação à firmware da solovox:
Com todas estas estratégias combinadas é certo que conseguimos colocar estas boxs com processador ALI3511 de volta a funcionar sem ter de se pagar licenças.
Toda ajuda é bem-vinda.
Tentarei de futuro organizar a informação melhor.
Para tal é necessário instalar a firmware da Solovox V8S plus seja este por USB ou RS232 (null modem).
O problema é que a Solovox não fornece as suas firmwares de forma grátis e tem um processo de licenciamento que deve ser feito por cabo RS232 e software deles.
Decidi abrir este tópico para tornar publico as estratégias que em conjunto com outros utilizadores temos vindo a trabalhar, bem como as nossas descobertas.
Não irei citar esses mesmos que se desejarem identifiquem-se neste tópico.
Ferramentas/Software/Firmware Solovox
http://www.solovox.xyz/download
Resumo do que sabemos em relação à firmware da solovox:
- A firmware no código vai ler uma chave à memoria (vou chamar password) e valida-a com o numero de serie se esta password está certa caso não estivesse dava "NO AUTH"
- Existe um servidor para gerir as licenças que a Solovox vende e é este que gerava as passwords para as boxes (actualmente em https://45.248.86.44)
- Existe um software (dpt_main_2.4.exe) para licenciar as boxes que:
- Pergunta à box qual o numero de serie
- Envia ao servidor o numero de serie
- Servidor gera a password e marca a licença como gasta
- Guarda na box essa password em processo OTP
- Anular licenciamento na firmware - reverse engeniring da firmware
É necessário usar um firmware decrypter para começar por separar as varias partes da firmware, apenas encontrei uma parte (AppsData) de diferença entre a firmware da solovox e a original, esta parte nada deve influenciar para o que queremos fazer, então extrai o maincode.
Este maincode em lzma se estiver tudo ok deve ser possível descompactar com 7-zip.
O problema é que está cifrado e não sabemos qual é a chave para fazer o decrypt.
Alguém sabe como passar este problema?
Código:[SIZE=2]File size = 7340032 bytes ( 7168 kB ) ---------------Part1--------------- Name : bootloader ID : 0x23010010 SIZE DATA : 0x00000000 OFFSET : 0x0001EE00 Version : DVBS2---0.1.0 Date : 2017-08-22 Actual CRC : 0x4E435243 No CRC! - OK! ------------------------------------ ---------------Part2--------------- Name : MemCfg ID : 0x07F80100 SIZE DATA : 0x00000870 OFFSET : 0x00001000 Version : 00000001 Date : 2014-5-15 Actual CRC : 0x4E435243 No CRC! - OK! ------------------------------------ ---------------Part3--------------- Name : upgcode ID : 0x05FA0100 SIZE DATA : 0x00000000 OFFSET : 0x00010200 Version : upg 1.0.0 Date : 2017-08-22 Actual CRC : 0x4E435243 No CRC! - OK! ------------------------------------ ---------------Part4--------------- Name : maincode ID : 0x01FE0101 SIZE DATA : 0x002613E6 OFFSET : 0x00380000 Version : M3511 HD Date : 2017-08-22 Actual CRC : 0x1242DF8D Calculate CRC : 0x1242DF8D - OK! ------------------------------------ ---------------Part5--------------- Name : seecode ID : 0x06F90101 SIZE DATA : 0x00111797 OFFSET : 0x0011FF80 Version : MSEE Demo Date : 2017-08-22 Actual CRC : 0xFA52204F Calculate CRC : 0xFA52204F - OK! ------------------------------------ ---------------Part6--------------- Name : AppsData ID : 0x50AF0100 SIZE DATA : 0x00010070 OFFSET : 0x00040080 Version : 1.0.0 Date : 2016-2-27 Actual CRC : 0x4E435243 No CRC! - OK! ------------------------------------ ---------------Part7--------------- Name : BOOTLOG ID : 0x02FD0200 SIZE DATA : 0x0000F3A9 OFFSET : 0x00010000 Version : 1.0.0 Date : 2017-08-22 Actual CRC : 0xDCB91805 Calculate CRC : 0xDCB91805 - OK! ------------------------------------ ---------------Part8--------------- Name : Radioback ID : 0x02FD0100 SIZE DATA : 0x00009566 OFFSET : 0x00010000 Version : 1.0.0 Date : 2017-08-22 Actual CRC : 0x9482F52C Calculate CRC : 0x9482F52C - OK! ------------------------------------ ---------------Part9--------------- Name : defaultdb ID : 0x03FC0100 SIZE DATA : 0x000193C0 OFFSET : 0x0001FF80 Version : 1.1.0 Date : 2014-4-15 Actual CRC : 0x2075EFDC Calculate CRC : 0x2075EFDC - OK! ------------------------------------ ---------------Part10--------------- Name : userdb ID : 0x04FB0100 SIZE DATA : 0x00170070 OFFSET : 0x00000000 Version : 1.0.0 Date : 2017-8-22 Actual CRC : 0x4E435243 No CRC! - OK! ------------------------------------[/SIZE]
Abaixo deixo ferramentas que usei:
FirmwareDecrypter_v8.9.zip
http://www.satedu.cba.pl/index.php?action=downloadfile&filename=FirmwareDecrypter_v8.9.zip&directory=Test%20Folder&
Ali__tools_Console_v4.0__CRC_FIXER.rar
http://www.satedu.cba.pl/index.php?action=downloadfile&filename=Ali__tools_Console_v4.0__CRC_FIXER.rar&directory=Test%20Folder&
- Snifar pedidos HTTP com Wireshark
Ainda sem sucesso devido aos chineses não serem amadores e terem usado no servidor de licenças certificado SSL (https) para dificultar o sniffing dos pedidos HTTP.
- Snifar porta serie (RS232) para perceber como é feito o licenciamento
Sei que começa pelo comando ".getsn 8." para pedir à box o numero de serie.
Ainda não tenho um snifing completo dos comandos da porta serie porque uma vez a box licenciada não dá para licenciar de novo.
Se alguém por licenciar uma box por favor use um snifer por software ou hardware e guarde os comandos trocados entre o software de autenticação e a box.
- Reverse engeniring do software de licencimento
Consegui fazer decompile ao software de autenticação da solovox (dpt_main_2.4.exe).
Já tenho uma versão em Python legível mas ainda não perfeita, contudo já descobri que estou certo na estratégia que usaram para licenciar as boxes.
Outra coisa que descobri foi os endpoints do servidor para a API.
RSC_ORDER_INFO = '/order_info'
RSC_PRODUCTION = '/chip_with_sn_production'
Exemplo order_info para receber informação das licenças:
https://45.248.86.44/dpt/api/order_info?key=bbd43b00-a99e-55e3-9828-71ba26097347
(com key vazia curiosamente tem licenças por usar)
https://45.248.86.44/dpt/api/order_info?key=
Exemplo chip_with_sn_production para receber password:
https://45.248.86.44/dpt/api/chip_with_sn_production?key=bbd43b00-a99e-55e3-9828-71ba26097347&chip_sn=Ainda_n_sei_formato
Continuo a tentar ler o código para perceber quais os comandos usados na porta serie.
Código Python das principais classes (tenho completo se alguém necessitar peça por mp)
Código:[SIZE=2]# -*- coding: utf-8 -*- __author__ = "Roy Wang (roy.dicovi@gmail.com)" __version__ = "2.4" __date__ = "$Date: 2013/11/26 14:00:00 $" __copyright__ = "Copyright (c) 2013 Dicovi" __license__ = "Dicovi" from PyQt4.QtGui import * from PyQt4.QtCore import * import sys, os from dpt_client import * from ui_dpt import * import serial import sip, decimal import dpt_qrc class DptClientCfg(): def __init__(self): self.port = 0 self.key = '' self.api = '' self.lan = "english" self.cfgfilename = './production.cfg' def readcfg(self): if not os.path.exists(self.cfgfilename): return False try: file_hander = open(self.cfgfilename, 'r') except (IOError, OSError): return False lines = file_hander.readlines() file_hander.close() for line in lines: line = str(line).strip() if line.startswith('#'): continue value = str(line.split('=')[1]).strip() if line.startswith('port') or line.startswith('PORT'): value = value.lstrip('COM') value = value.lstrip('com') if not value.isdigit(): return False self.port = int(value) if line.startswith('productionkey') or line.startswith('PRODUCTIONKEY'): self.key = value if line.startswith('LANGUAGE') or line.startswith('language'): self.lan = value if line.startswith('API') or line.startswith('api'): self.api = value if self.port == 0: return False if self.key == '': return False return True def writecfg(self): try: file_hander = open(self.cfgfilename, 'w') except (IOError, OSError): return False item = "language=" + self.lan + "\n" file_hander.write(item) item = "port=COM"+str(self.port) + "\n" file_hander.write(item) item = "productionkey=" + self.key + "\n" file_hander.write(item) item = "api=" + self.api + "\n" file_hander.write(item) file_hander.close() return True ''' class MovieSplashScreen(QSplashScreen): def __init__(self, movie, parent = None): movie.jumpToFrame(0) pixmap = QPixmap(movie.frameRect().size()) QSplashScreen.__init__(self, pixmap) self.movie = movie self.movie.frameChanged.connect(self.repaint) def showEvent(self, event): self.movie.start() def hideEvent(self, event): self.movie.stop() def paintEvent(self, event): painter = QPainter(self) pixmap = self.movie.currentPixmap() self.setMask(pixmap.mask()) painter.drawPixmap(0, 0, pixmap) def sizeHint(self): return self.movie.scaledSize() ''' class waitDlg(QDialog): def __init__(self, parent=None, win_x=0, win_y=0, win_w=0, win_h=0): super(waitDlg, self).__init__(parent) w = h = 128 x = win_x + (win_w - w)/2 y = win_y + (win_h - h)/2 self.setGeometry(x,y,w,h) self.resize(128,128) #self.gif = QGraphicsView("./icon/loading.gif") self.label = QLabel(self) #self.label.setText("Waitting...") self.label.resize(128,128) self.movie = QMovie(":/icon/loading.gif") #print self.movie.currentImage() #print self.movie.currentPixmap() self.label.setMovie(self.movie) self.setWindowFlags(Qt.FramelessWindowHint) self.setAutoFillBackground(True) self.movie.start() def __del__(self): self.movie.stop() class DptMainWin(QMainWindow): def scan_serial(self): """scan for available ports. return a list of tuples (num, name)""" available = [] for i in range(16): try: s = serial.Serial(i) available.append(s.portstr) s.close() # explicit close 'cause of delayed GC in java except serial.SerialException: pass return available def update_translate(self): self.setWindowTitle(self.tr("Production Tools")) self.ui.menuHelp.setTitle(self.tr("Help")) self.ui.actionAbout.setText(self.tr("About")) self.ui.label_lan.setText(self.tr("Language")) self.ui.label_port.setText(self.tr("Serial Port")) self.ui.label_api.setText(self.tr("API")) self.ui.label_key.setText(self.tr("Production Key")) self.ui.label_info.setText(self.tr("Information")) self.ui.label_model.setText(self.tr("Model")) self.ui.label_order.setText(self.tr("Order")) self.ui.label_total.setText(self.tr("Total")) self.ui.label_producted.setText(self.tr("Producted")) self.ui.start.setText(self.tr("Start")) def __init__(self, app, parent=None): super(DptMainWin, self).__init__(parent) self.app = app self.cfg = DptClientCfg() self.cfg.readcfg() self.trans = None if self.cfg.lan == "chinese": trans = QTranslator() trans.load(":/zh_CN.qm") self.app.installTranslator(trans) self.trans = trans ui = Ui_mainWindow() ui.setupUi(self) self.ui = ui self.update_translate() ui.lan.addItems((u"English", u"简体中文")) if self.cfg.lan == "chinese": ui.lan.setCurrentIndex(1) else: ui.lan.setCurrentIndex(0) self.connect(ui.lan, SIGNAL("currentIndexChanged(int)"), self.change_lan) available_port = self.scan_serial() ui.port.addItems(available_port) if self.cfg.port > 0: port = "COM" + str(self.cfg.port) idx = ui.port.findText(port) if idx >= 0: ui.port.setCurrentIndex(idx) if len(self.cfg.api) > 0: ui.api.setText(self.cfg.api) if len(self.cfg.key) > 0: ui.production_key.setText(self.cfg.key) ui.total.setProperty("intValue", 0) ui.producted.setProperty("intValue", 0) ui.result.setProperty("intValue", 0) #ui.info.setDisabled(True) #ui.model.setDisabled(True) #ui.order.setDisabled(True) self.connect(ui.start,SIGNAL("clicked()"),self.tweak_production) #self.connect(ui.actionAbout, SIGNAL("clicked()"), self.showAbout) ui.actionAbout.triggered.connect(self.showAbout) self.worker = DptClientWorker() self.connect(self.worker, SIGNAL("msg_out"), self.update_msg) self.connect(self.worker, SIGNAL("update_num"), self.update_num) self.connect(self.worker, SIGNAL("update_info"), self.update_info) self.connect(self.worker, SIGNAL("finished()"), self.stop_update_ui) self.connect(self.worker, SIGNAL("terminated()"), self.stop_update_ui) self.connect(self.worker, SIGNAL("update_result"), self.update_result_led) self.productioning = False self.wait = None def closeEvent(self, event): if self.productioning: self.worker.stop() if None == self.wait: self.wait = waitDlg(win_x=self.x(), win_y=self.y(), win_w=self.width(), win_h=self.height()) #waitDlg() self.wait.exec_() while self.productioning: time.sleep(0.1) def change_lan(self, idx): if idx == 1: self.cfg.lan = "chinese" else: self.cfg.lan = "english" self.cfg.writecfg() if self.trans is not None: self.app.removeTranslator(self.trans) self.trans = None if self.cfg.lan == "chinese": trans = QTranslator() trans.load(":/zh_CN.qm") self.app.installTranslator(trans) self.trans = trans self.update_translate() def tweak_production(self): if not self.productioning: key = self.ui.production_key.text() api = self.ui.api.text() key = str(key).strip() api = str(api).strip() if len(api)==0 or len(key) == 0: return if not str(api).startswith("https://"): return portstr = str(self.ui.port.currentText()) if len(portstr) == 0: return #print "start production" port = int(portstr.lstrip("COM").lstrip("com")) self.ui.api.setDisabled(True) self.ui.lan.setDisabled(True) self.ui.port.setDisabled(True) self.ui.production_key.setDisabled(True) self.ui.start.setText(self.tr("Stop")) self.ui.info.clear() self.worker.set_param(unicode(api), port, unicode(key)) self.cfg.port = port self.cfg.key = key self.cfg.api = api self.cfg.writecfg() self.worker.start() self.productioning = True else: #print "stop production" self.worker.stop() if None == self.wait: self.wait = waitDlg(win_x=self.x(), win_y=self.y(), win_w=self.width(), win_h=self.height()) self.wait.exec_() #if not self.wait.isActiveWindow(): # self.wait.exec_() def stop_update_ui(self): #print "stop_update_ui" ui = self.ui ui.lan.setDisabled(False) ui.port.setDisabled(False) ui.api.setDisabled(False) ui.production_key.setDisabled(False) ui.model.clear() ui.order.clear() ui.info.clear() ui.total.setProperty("intValue", 0) ui.producted.setProperty("intValue", 0) ui.result.setProperty("intValue", 0) #ui.info.clear() ui.start.setText(self.tr("Start")) ui.start.setDisabled(False) #self.******.finish(self) if None != self.wait: self.wait.close() self.wait.destroy() self.wait = None #if self.wait.isActiveWindow(): # self.wait.close() self.productioning = False def update_msg(self, clean=0, msg=""): ui = self.ui if clean == 1: ui.info.clear() if msg != "": ui.info.append(msg) def update_num(self, total=0, producted=0): ui = self.ui ui.total.setProperty("intValue", total) ui.producted.setProperty("intValue", producted) def update_result_led(self, result = 0): ui = self.ui ui.result.setProperty("intValue", result) def update_info(self, info): if not isinstance(info, dict): return ui = self.ui if dict(info).has_key('model_description'): ui.model.setText(info['model_description']) if dict(info).has_key('order_description'): ui.order.setText(info['order_description']) if dict(info).has_key('number'): ui.total.setProperty("intValue", info['number']) if dict(info).has_key('producted'): ui.producted.setProperty("intValue", info['producted']) def showAbout(self): QMessageBox.about(self, self.tr("About"), self.tr("DTP Version: ") + __version__) #trans = QTranslator() #trans.load("zh_CN") app=QApplication(sys.argv) #app.installTranslator(trans) #app.removeTranslator(trans) win=DptMainWin(app=app) win.show() app.exec_()[/SIZE]
https://pastebin.com/ZHt5DUqa
- Desenvolver ou corrigir problema numa firmware antiga
Alguém sabe onde se pode encontrar código fonte duma firmware para estes processadores?
Com todas estas estratégias combinadas é certo que conseguimos colocar estas boxs com processador ALI3511 de volta a funcionar sem ter de se pagar licenças.
Toda ajuda é bem-vinda.
Tentarei de futuro organizar a informação melhor.
Última edição: