Fort-112 3g, лезем в душу

Fort-112 3g Front Fort-112 3g Side

Дано: Навигационный терминал Fort-112 3g от пермской компании Fort Telecom.

Задача: минимум - узнать явки и пароли, максимум - получить полное управление коробкой.

Погнали.

Как всегда, идём на сайт производителя, вникаем в мануалы. Понимаем, что одними смсками мы коробку не победим; она привязана к списку телефонных номеров и, мало того, хочет знать пароли. В этом месте производителю зачёт!:)

Ок... Для конфигурации устройства нам нужна некая софтина под кодовым названием «Конфигуратор». Здесь ждёт небольшой сюрприз. Если «Конфигуратор» можно найти на просторах интернета, то с драйверами явная проблема. Хорошо, просим софт у производителя... Ииии... в России есть странная особенность - у нас очень любят выпустить недопродукт, а-ля конструктор, накрутить поверх страшнючее ПО и никому ничего не давать:) Исключение, пожалуй, Александр Ерасов.

Александр Евгеньичу пламенный привет:) А мы продолжим.

Я не зря упомянул про конструктор... Смотрим на чём собран прибор - до боли знакомый сто пиновый микроконтроллер STM32F4 от швейцарской компании STMicroelectronics. Это значит, что прошивка коробки практически у нас в руках.

Для начала, конечно же, читаем даташит, смотрим распиновку, находим ногу BOOT0, смотрим куда распаяна.

Fort-112 3g STM32F407VG LQFP100 STM32F40xxx LQFP100 pinout

Ставим джампер в этом месте...

Fort-112 3g BOOT0 jmp

Теперь наша коробка будет стартовать в Device Firmware Update Mode (больше, чем на 5 сек.) с доступом ко всем разделам памяти.

Отлично, дальше нужно скачать пакет программ DfuSe c сайта st.com. Устанавливаем. Запускаем DFUSE Demo. Втыкаем коробку в USB порт. Подаём питание. Смотрим, что получилось.

Fort-112 3g DFUSE Demo

Шикарно!:) Смотрим права на Internal Flash, именно эта часть памяти нам понадобится.

Fort-112 3g DFUSE Demo Permissions

Полный доступ по всем фронтам. Это радует:) В секции Upload Action выбираем место, куда сохранять дамп памяти, жмём кнопарь Upload.

Fort-112 3g DFUSE Demo Upload

На выходе получаем файл с раширением .dfu... Запускаем программу DFU File Manager, делаем из .dfu multi BIN file (это важно, если править .dfu напрямую, будет много матюгов на CRC файла при обратных действиях) и открываем в HEX редакторе.

Fort-112 3g readable bin

Собственно, вот оно. Довольно много интересного для зоркого взгляда американского наблюдателя.

Заливка исправленной прошивки происходит ровно таким же образом, но наоборот... с небольшим финтом ушами:)

С этой коробкой пока всё. Ещё три на подходе:))))

upd 28.04.2017:
FORT Monitor
FORT-112 All

ГЛОНАСС

АСУ-Навигация

АСУ-Навигация

Расшифрованная и, чтобы не делала killout всем подряд, немного подхаченная процедура dbo.clcsp_MainCalculator3 из БД TRANSNAVI - Автоматизированная Система Учёта Транспортной Работы, НПП «Транснавигация».

USE [TRANSNAVI]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO



-- =============================================
-- Author: Dmitriy Def
-- Create date: 24.09.2015
-- Description: Encrypt
-- =============================================

--ОСНОВНАЯ ПРОЦЕДУРА ЯДРА
ALTER PROCEDURE [dbo].[clcsp_MainCalculator3Hack]
AS
set nocount on

--временная таблица
create table #NRD(NRD_Identificator int)

declare @CurDate                datetime
declare @CurInt                 int
declare @OldInt                 int
declare @ServiceDay int

set @ServiceDay=0

--Вносим строчку в журнал
insert into Logs values(GetDate(),'ЗАПУСК СЛУЖБЫ',0)

set @OldInt=-1

-------------------------------------------------------------------------------------------------------------------------
--ОСНОВНОЙ ЦИКЛ
-------------------------------------------------------------------------------------------------------------------------

StartService:

--читаем основные параметры
declare @enable_BDI bit
set @enable_BDI=case when dbo.fn_GetParam('enable_BDI','0')='1' then 1 else 0 end
declare @enable_kernel bit
set @enable_kernel=case when dbo.fn_GetParam('enable_kernel','1')='1' then 1 else 0 end
declare @enable_digithandle bit
set @enable_digithandle=case when dbo.fn_GetParam('enable_digithandle','0')='1' then 1 else 0 end
declare @enable_failwindow bit
set @enable_failwindow=case when dbo.fn_GetParam('enable_failwindow','1')='1' then 1 else 0 end
declare @enable_hotwindow bit
set @enable_hotwindow=case when dbo.fn_GetParam('enable_hotwindow','1')='1' then 1 else 0 end
declare @enable_kkphandle bit
set @enable_kkphandle=case when dbo.fn_GetParam('enable_kkphandle','1')='1' then 1 else 0 end
declare @enable_nariadcross bit
set @enable_nariadcross=case when dbo.fn_GetParam('enable_nariadcross','1')='1' then 1 else 0 end
declare @enable_navhandle bit
set @enable_navhandle=case when dbo.fn_GetParam('enable_navhandle','1')='1' then 1 else 0 end
declare @enable_rasphandle bit
set @enable_rasphandle=case when dbo.fn_GetParam('enable_rasphandle','1')='1' then 1 else 0 end
declare @enable_tablohandle bit
set @enable_tablohandle=case when dbo.fn_GetParam('enable_tablohandle','0')='1' then 1 else 0 end
--определяем сколько раз в минуту запускать обработчик
declare @startperminute int
set @startperminute=cast(dbo.fn_GetParam('clc_startperminute','4') as int)
declare @startonmin int
if (@startperminute>0) and (@startperminute<=60)
        set @startonmin=60/@startperminute
else
        set @startonmin=15
declare @failkeep int
set @failkeep=cast(dbo.fn_GetParam('clc_failkeep','7') as int)
declare @handlegraphdelta int
set @handlegraphdelta=cast(dbo.fn_GetParam('clc_handlegraphdelta','30') as int)

--если не разрешают запускать ядро, то выходим
if @enable_kernel=0 return(0)

--ждем время запуска службы
set @CurDate=GetDate()
set @CurInt=DatePart(hour,@CurDate)*3600+DatePart(minute,@CurDate)*60+DatePart(second,@CurDate)
while (@CurInt % @startonmin<>0) or (@CurInt=@OldInt)
begin
        waitfor delay '00:00:01'
        set @CurDate=GetDate()
        set @CurInt=DatePart(hour,@CurDate)*3600+DatePart(minute,@CurDate)*60+DatePart(second,@CurDate)
end
set @OldInt=@CurInt

--Определяем дату наряда
declare @NariadDate datetime
declare @ND_Identificator int
declare @CurTime int
set @NariadDate=@CurDate
set @CurTime=DatePart(hour,@NariadDate)*60+DatePart(minute,@NariadDate)-180
set @NariadDate=Cast(Floor(Cast(@NariadDate as float))as datetime)
if @CurTime<0
begin
set @CurTime=1440+@CurTime
set @NariadDate=DATEADD(day,-1,@NariadDate)
end
set @ND_Identificator=dbo.fn_GetNariadIndex(@NariadDate)

--Если время по чисам системы 3:00, то выполняем ряд процедур по инициализации следующего дня
if @CurInt between 10800 and 10860
begin
        if DatePart(day,@CurDate)<>@ServiceDay
        begin
                set @ServiceDay=DatePart(day,@CurDate)
                --Очищаем оперативную навиацию
                truncate table Nav
                --Очищаем таблицу
                truncate table Nav_cur
                --Очищаем LOG
                truncate table Logs
                --очищаем рабочую таблицу связок
                truncate table NRDCPLink
                --Очищаем файл паркового опроса
                if dbo.fn_TableExists('tbParkOpros')=1 truncate table tbParkOpros
                --Очищаем отметки по ККП
                if dbo.fn_TableExists('tbFreeNav')=1 truncate table tbFreeNav
                --Очищаем пересечения наряда
                if dbo.fn_TableExists('tbNariadInfo')=1 delete from tbNariadInfo where ND_Identificator<@ND_Identificator-@failkeep
                --очищаем горячее окно
                if dbo.fn_TableExists('tbErrorLog')=1 delete from tbErrorLog where ND_Identificator<@ND_Identificator-@failkeep
                --очищаем окно нарушений
                delete from tbMainWindow where ND_Identificator<@ND_Identificator-@failkeep
                truncate table tbMainWindow_cur
                --Очищаем оперативную цифровую модель
                if dbo.fn_TableExists('tbDigitPos')=1 truncate table tbDigitPos
                --обрабатываем новые мониторинговые таблицы
                insert into jobs (ND_Identificator,NRD_Identificator,JB_MinCalcTime,JB_MaxCalcTime,JB_MinCalcOrder,JB_MaxCalcOrder,JB_Command,NSIT_UniqueID)
                select ND_Identificator,NRD_Identificator,0,1439,-10000,1000000,1,NSIT_UniqueID
                from tbBaseNariad where ND_Identificator=@ND_Identificator
        end
end

--блок криптографической проверки
if (@CurInt % 3600)=0
begin
        declare @bad bit
        declare @alv_res int
        declare @spid smallint
        declare @spid_str varchar(15)
        set @bad=0
        if not exists(select * from TRANSNAVI.dbo.sysobjects where name='crysp_alv' and xtype='P')  or
                 not exists(select * from TRANSNAVI.dbo.sysobjects where name='crysp_dcb' and xtype='P')  or
                 not exists(select * from TRANSNAVI.dbo.sysobjects where name='crysp_dcl' and xtype='P')  or
                 not exists(select * from TRANSNAVI.dbo.sysobjects where name='crysp_gm' and xtype='P')  or
                 not exists(select * from TRANSNAVI.dbo.sysobjects where name='cryfn_gsn' and xtype='FN') set @bad=1
        else begin
                exec @alv_res=dbo.crysp_alv 255
                if @alv_res<0 set @bad=0
        end
        if @bad=1
        begin
                --всех убить
                declare killcur cursor
                local
                for
                select spid from master.dbo.sysprocesses sp
                inner join master.dbo.sysdatabases db on sp.dbid=db.dbid
                where db.name='TRANSNAVI' and spid<>@@spid
                open killcur
                fetch next from killcur into @spid
                while @@fetch_status=0
                begin
                        set @spid_str=cast(@spid as varchar)
                        exec ('KILL '+@spid_str)
                        fetch next from killcur into @spid
                end
                close killcur
                deallocate killcur
                --и выйти
                return(-1);
        end;
end

--если это первый вызов минуты, то набираем задание
if (@CurInt % 60)=0
begin
        --очищаем таблицу
        truncate table #NRD
        --заполняем ее новыми значениями
        insert into #NRD(NRD_Identificator)
        select NRD_Identificator from tbBaseNariad
        where (ND_Identificator=@ND_Identificator) and (NSIT_UniqueID>0) and
                                (NRD_ExitPark-@handlegraphdelta<=@CurTime and @CurTime<=NRD_EnterPark+@handlegraphdelta)
        --Очищаем окно нарушений от старых данных (которых нет в задании)
        delete from tbMainWindow_cur where not exists(select top 1 * from #NRD where tbMainWindow_cur.NRD_Identificator=#NRD.NRD_Identificator)
end

--Вносим строчку в журнал
insert into Logs values(GetDate(),'ВЫЗОВ',0)

--Проверяем скорость поступления данных
declare @CountBefore int
declare @CountAfter  int
declare @MaxInsSpeed int
set @MaxInsSpeed=cast(dbo.fn_GetParam('clc_maxinsspeed','10') as int)
set @CountBefore=(select count(*) from Nav_buf)
waitfor delay '00:00:01'
set @CountAfter=(select count(*) from Nav_buf)
if @CountAfter-@CountBefore>@MaxInsSpeed
begin
        insert into Logs values(GetDate(),'ВЫЗОВ ОТМЕНЕН',0)
        goto StartService
end

--Обновляем таблицу связанных КП
delete from NRDCPLink
where
not exists
(
        select top 1 * from tbBaseNariad
        where NRDCPLink.NRD_Identificator=tbBaseNariad.NRD_Identificator
)
insert into NRDCPLink(ND_Identificator,NRD_Identificator,NSIT_UniqueID,CP_Identificator,CNRD_EndStation)
select distinct BN.ND_Identificator,BN.NRD_Identificator,BN.NSIT_UniqueID,CN.CP_Identificator,CN.CNRD_EndStation
from tbBaseNariad BN inner join tbCardNariad CN on BN.NRD_Identificator=CN.NRD_Identificator
where not exists
(
        select top 1 * from NRDCPLink
        where NRDCPLink.NRD_Identificator=BN.NRD_Identificator
)

--Этап 0. Цифровая модель
if (@enable_digithandle=1)
begin
        insert into
 Logs values(GetDate(),'Начало цифровой модели',0)
        exec dgtsp_CalcNavPosition @ND_Identificator
        insert into Logs values(GetDate(),'Конец цифровой модели',0)
end

--Этап 1. Окапывание
declare @NRD_identificator int
declare @JobCount int
declare @JB_identificator uniqueidentifier
declare @JB_MinCalcTime    int
declare @JB_MaxCalcTime    int
declare @JB_MinCalcOrder   int
declare @JB_MaxCalcOrder   int
declare @JB_Command                        int
declare @NSIT_UniqueID           int
declare @RowCount        int
declare @RowResult                      int
set @RowCount=cast(dbo.fn_GetParam('clc_rowcount','10000') as int)
declare @MaxRestToCalc  int
set @MaxRestToCalc=cast(dbo.fn_GetParam('clc_maxresttocalc','300') as int)
declare @BufCount int
set @BufCount=(select count(*) from nav_buf)
if (@enable_navhandle=1)
begin
        insert into Logs values(GetDate(),'Начало Окапывания',@BufCount)
        exec clcsp_LinkCurNavToCP3 @RowCount,@RowResult output
        insert into Logs values(GetDate(),'Конец Окапывания',@BufCount)
        if @RowResult>@MaxRestToCalc
        begin
                goto StartService
        end
end

--Этап 2. Обработка
exec clcsp_GetCalcCur3
set @JobCount=(select count(*) from Jobs)
insert into Logs values(GetDate(),'Начало Обработки',@JobCount)
declare JobCur cursor
local
for select JB_Identificator,ND_Identificator,NRD_Identificator,JB_MinCalcTime,JB_MaxCalcTime,JB_MinCalcOrder,JB_MaxCalcOrder,JB_Command,NSIT_UniqueID
from Jobs
open JobCur
fetch next from JobCur into
@JB_Identificator,@ND_Identificator,@NRD_Identificator,@JB_MinCalcTime,@JB_MaxCalcTime,@JB_MinCalcOrder,@JB_MaxCalcOrder,@JB_Command,@NSIT_UniqueID
while @@fetch_status=0
begin
        --пересчитываем график
        if (@enable_rasphandle=1) exec clcsp_Calc3 @ND_Identificator,@NRD_Identificator,@JB_MinCalcOrder,@JB_MaxCalcOrder
        --пересчитываем окно нарушений
        if (@enable_failwindow=1) exec dspsp_MainWindow @NRD_Identificator
        --пересчитываем горячее окно
        if (@enable_hotwindow=1) exec dspsp_HotWindow @NRD_Identificator
        --пересчитываем приезд отъезд от конечных
        if (@JB_Command & 2)<>0
        begin
                if (@enable_kkphandle=1) exec dspsp_CalcFreeNav2 @NSIT_UniqueID
        end
        --вычисляем основные параметры графика (раз в минуту)(кол-во рейсов по плану)
        exec dspsp_CalcGraph_minute @ND_Identificator,@NRD_Identificator,@CurTime
        --расчитываем данные для БДИ
        if (@enable_BDI=1) exec msgsp_FormRasp @NSIT_UniqueID,0
        --удаляем график из задания
        delete from #NRD where NRD_Identificator=@NRD_Identificator
        --удаляем выполненное задание
        delete from Jobs where JB_Identificator=@JB_Identificator
        --переходим к следующему заданию
        fetch next from JobCur into
@JB_Identificator,@ND_Identificator,@NRD_Identificator,@JB_MinCalcTime,@JB_MaxCalcTime,@JB_MinCalcOrder,@JB_MaxCalcOrder,@JB_Command,@NSIT_UniqueID
end
close JobCur
deallocate JobCur
insert into Logs values(GetDate(),'Конец Обработки',@JobCount)

--если это последний вызов минуты, то отрабатываем оставшиеся графики
if (@CurInt % 60)+@startonmin>=60
begin
        set @JobCount=(select count(*) from #NRD)
        insert into Logs values(GetDate(),'Начало Оперы',@JobCount)
        declare cur cursor
        local
        for
        select NRD_Identificator from #NRD
        open cur
        fetch next from cur into @NRD_Identificator
while @@fetch_status=0
        begin
                declare @leftlim  int
                declare @rightlim int
                --перекрашиваем график
                if (@enable_rasphandle=1)
                begin
                        exec clcsp_CalcCurLimits @NRD_Identificator, @CurTime, @CurTime, 3, @leftlim OUTPUT , @rightlim OUTPUT
                        exec clcsp_ColorGraph3 @ND_Identificator,@NRD_Identificator,@leftlim,@rightlim,1
                end
                --пересчитываем окно нарушений
                if (@enable_failwindow=1) exec dspsp_MainWindow @NRD_Identificator
                --пересчитываем горячее окно
                if (@enable_hotwindow=1) exec dspsp_HotWindow @NRD_Identificator
                --вычисляем основные параметры графика (раз в минуту)
                exec dspsp_CalcGraph_minute @ND_Identificator,@NRD_Identificator,@CurTime
                --переходим к следующему графику
                fetch next from cur into @NRD_Identificator
        end
        close
 cur
        deallocate cur
        insert into Logs values(GetDate(),'Конец Оперы',@JobCount)
end

--расчет данных для табло
if (@enable_tablohandle=1)
begin
        insert into Logs values(GetDate(),'Начало табло',0)
        exec tblsp_CalculateTablo
        insert into Logs values(GetDate(),'Конец табло',0)
end

goto StartService

ГЛОНАСС

Обходим ГЛОНАСС контроль, часть 5

Обходим ГЛОНАСС контроль, часть 5

За дверью

Начал я тут было писать продолжение истории, потом плюнул и запил мега сервис. Прям, регистрируешься, выбираешь навигатор/протокол, строишь маршрут, жмёшь кнопку пуск, и оно ездит по удалённым экранам «радаров», как настоящее. Главное, железные навигаторы обесточить, чтобы без палева:)
Чуть-чуть потестим и запустим в массы...

ГЛОНАСС

Три пальца в OS X 10.11

Три пальца в OS X 10.11

Так, это надо не забыть:) А то Дима весь мозг сломал: Почему в El Capitan-е не получается таскать окна и выделять текст, елозя тремя пальцами по трекпаду?

Step 1: Open System Preferences
Step 2: Click Accessibility
Step 3: Click Mouse & Trackpad
Step 4: Click Trackpad Options…
Step 5: Click Enable dragging
Step 6: Select “three finger drag” in the drop down box

Извращенцы!:)

Apple

Копаем вечный триал стандартной комплектации, часть 2

Битрикс 15.5

В первой части мы разобрались, как работает пробный период системы. Ok, продолжим тянуть одеяло на себя.

Задача: изменить дату окончания пробного периода.

Погнали!

Смотрим, как дешифруются даты в файле ...modules/main/include.php:

$_1986987364 = COption::GetOptionString("main", "admin_passwordh");

while ($_1986987364) {
    $_461848715  = base64_decode($_1986987364);
    $_658498780  = "";
    $_2139208883 = "thRH4u67fhw87V7Hyr12Hwy0rFr";
    $_1215634966 = strlen($_2139208883);
    $_278722441  = 0;

    for ($_307887909 = 0; $_307887909 < strlen($_461848715); $_307887909++) {
        $_658498780 .= chr(ord($_461848715[$_307887909]) ^ ord($_2139208883[$_278722441]));
        if ($_278722441 == $_1215634966 - 1)
            $_278722441 = 0;
        else
            $_278722441 = $_278722441 + 1;
    }
    //SITEEXPIREDATE
    $_912457331 = mktime(0, 0, 0, intval($_658498780[6] . $_658498780[3]), intval($_658498780[1] . $_658498780[14]), intval($_658498780[10] . $_658498780[18] . $_658498780[7] . $_658498780[12]));

    unset($_2139208883);
    break;
}

@include($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/admin/define.php");

while (defined("TEMPORARY_CACHE")) {
    $_1494959871 = base64_decode(constant("TEMPORARY_CACHE"));
    $_464054490  = "";
    $_527681262  = "DO_NOT_STEAL_OUR_BUS";
    $_278722441  = 0;

    for ($_307887909 = 0; $_307887909 < strlen($_1494959871); $_307887909++) {
        $_464054490 .= chr(ord($_1494959871[$_307887909]) ^ ord($_527681262[$_278722441]));
        if ($_278722441 == 19)
            $_278722441 = 0;
        else
            $_278722441 = $_278722441 + 1;
    }
    //OLDSITEEXPIREDATE
    $_1749264640 = mktime(0, 0, 0, intval($_464054490[6] . $_464054490[16]), intval($_464054490[9] . $_464054490[2]), intval($_464054490[12] . $_464054490[7] . $_464054490[14] . $_464054490[3]));

    unset($_527681262);
    break;
}

Берётся значение, декодируется из base64, прогоняется через XOR, из результата выдираются отдельные символы и формируется юникс тайм... Вся прелесть XOR шифрования в том, что для получения исходника достаточно прогнать зашифрованные данные через тот же цикл с тем же ключом.

Отлично.

Напишем универсальную функцию и скормим ей +30 дней от текущей даты.

<?php
function BitrixExpireDate($date, $key){
    $outCode = '';
    $x = 0;
    for ($i = 0; $i < strlen($date); $i++) {
        $outCode .= chr(ord($date[$i]) ^ ord($key[$x]));
        if ($x == strlen($key) - 1)
            $x = 0;
        else
            $x = $x + 1;
    }
    return $outCode;
}

$key1 = 'DO_NOT_STEAL_OUR_BUS+'; // OLDSITEEXPIREDATE
$key2 = 'thRH4u67fhw87V7Hyr12Hwy0rFr+'; // SITEEXPIREDATE

$nowDate = date('mdY', time() + 60*60*24*30); // сегодня 07242015

$codeDate1 = 'XX'.$nowDate[3].$nowDate[7].'XX'.$nowDate[0].$nowDate[5].'X'.$nowDate[2].'XX'.$nowDate[4].'X'.$nowDate[6].'X'.$nowDate[1].'X'; // OLDSITEEXPIREDATE
$codeDate2 = 'X'.$nowDate[2].'X'.$nowDate[1].'XX'.$nowDate[0].$nowDate[6].'XX'.$nowDate[4].'X'.$nowDate[7].'X'.$nowDate[3].'XXX'.$nowDate[5]; // SITEEXPIREDATE

echo $outCode1 = base64_encode(BitrixExpireDate($codeDate1, $key1)); // OLDSITEEXPIREDATE
echo '<br>';
echo $outCode2 = base64_encode(BitrixExpireDate($codeDate2, $key2)); // SITEEXPIREDATE
?>

Запускаем, получаем результат.

HBdsexcMb2MMdxkUbRdkCmca
LFoKcGwtBgY+MEVgAg4EECEqAQ==

Шикарно!:) Меняем значения в файле ...modules/main/admin/define.php и в строке admin_passwordh (таблица b_option), чистим ...managed_cache/, смотрим, что получилось.

Битрикс, Было 27 дней Битрикс, стало 30 дней

Работает!

Дальше, думаю, понятно. Допиливаем скрипт, ложим на сервер, дёргаем кроном раз в сутки - вечные 30 дней триала и никаких модификаций ядра:)

Хак