前言


Outernet[1]是一家旨在让访问国际互联网更加方便自由的公司,他们使用卫星来广播维基百科或者其他网站。目前,他们的广播主要使用三颗国际海事卫星[3]的L波段[2],使其广播覆盖全球,大多数接收机是开源的,可是,他们的关键部分是闭源的,比如二进制的数据分发模式和信号的详细信息。实际上,Outernet可能违反了GPL ,因为他们的sdr100[4]是基于librtl SDR和libmirisdr[5]开发的,而这两个使用了GPL开源协议。

详情


最近。我逆向了 Outernet 的信号,并完成了一个完全开源的的解码器,他由一个GNU Radio流图 gr-outernet[6]和python脚本free-outernet[7]组成,前者负责获取信号,后者负责提取出传输的文件。

在这篇文章中,我将描述GNU Radio是如何工作的还会介绍一些我用来逆向信号的工具和技术。这些技术可以同样应用于其他的类型的信号,特别是用于卫星通讯的信号(逆向结束之后,我才知道它使用了现成的卫星广播通讯方式,Datum Systems M7[8]),你可以在我的博客[9]中找到更多有关于Outernet的信息和其他项目。

处理射频信号的第一步始终都是调整设备的频率和带宽。即使你不知道怎么解调信号,他在瀑布图上,频率和带宽是很明显的。在这里,我使用Scott Chapman(K4KDR)[10]从 I-4 F3卫星上获取的I/Q数据信号,它在美国上空的广播频率是1539.8725 MHz,我们可以清楚的看见带宽大概是4.8kHz。如果你运行下面的流图,将会看到输出。

我们如果只看这些,基本对信号一无所知,他看起来像一个4.8khz的宽峰噪音,正如 Phil Karn (KA9Q)[11]所说:“任何一个先进的通讯方案都无法区别噪音。”因为它是一个窄带卫星信号,我们猜测它使用的是PSK方式调制的,但是采用的BPSK还是QPSK?这两种都是有可能的。有一种简单的方式可以猜测PSK的类型而不用把它恢复到星图。这个方法是:首先,我们把信号功率提升到2倍(源信号乘以本身),如果我们发现了直流成分,那么这个是BPSK信号,如果没有,我们提升到4倍,如果这时产生直流成分,那么是QPSK信号。这也适用于高阶PSK信号(不适用于QAM),对于一个M-PSK信号来说,提升一个整数倍m时,会产生直流成分。

你可以看下面的流程,当提升2倍时,出现来直流脉冲,这表明,Outernet是BPSK信号。

下面的任务是获取信号的波特率,有一种叫循环平稳分析的方法可以用来获取信号的波特率。使用延时之后的信号复共轭相乘。最好的解释方式就是看下面的流图。

循环平稳分析的输出显示来一个特定频率下的波特率频率分量,在下面的图中,我们可以看到在4200hz处有分量,这表明,波特率是4.2kbaud。频率图中的高平均是很重要的,否则4200hz的频率分量是很难看到的。

现在,我们知道了波特率,我们可以把它恢复成星图,发现它确实是BPSk信号,有关于PSK的解调[12],GNU Radio入门介绍网页[13]有一篇很好的说明。下面,你可以看到我们的BPSK解调器流图和星图,正如预期,这是一个BPSK信号。

Outernet对外所说比特率约为2 kbps,或为20MB每天,而我们分析得到的比特率是4.2kbaud,所以,很有可能它使用了r=1/2正向纠错编码,参数r被称为速率, R = 1 / 2意味着数据流使用了1/2bits用来在接收器中纠正错误位,实际速率只有我们测得速率的一半,也就是2.1kbps。

对于参数是r=1/2的数据,最流行的是使用国际空间数据系统咨询委员会提出的,r=1/2,卷积码K = 7的协议式。针对这种编码的Viterbi解码器在GNU radio中有相应的模块,叫做“Decode CCSDS 27”。然而,这种编码允许在几个变量上有所更改。我们可以使用Balint Seeber[14]的Auto FEC[15]监视Viterbi译码器的误码率并尝试不同的组合参数,直到发现一个可以正常使用的组合。 Auto FEC也可以删余一些数据(超过1/2的部分)。实际上,你很可能不知道它使用了何种删余率,因为变化太多了。

如果想使用Auto FEC,你需要在GNU Radio上打一个补丁,因为 Viterbi 解码器和 “Decode CCSDS 27”模块需要修改以便输出误码率。在这里[16],你可以找到一个用于GNU Radio当前版本的补丁(3.7.10.1测试版),同样,Auto FEC需要输入的是QPSK信号,这有一个补丁[17]可以让他与BPSK 信号工作。

从下面的流图,你可以看到Auto FEC的运行和他的输出,Auto FEC在控制台上打印各种组合,以尝试得到正确的参数。在这个输出中,需要注意的是把  “Viterbi swap”设置为true。他的含义是在CCSDS编码这个特定的环境中,多项式的数值是交换的。通常,A决定第一位,B 决定第二位。而在这里,第一位来自B,而第二位来自A。为了抵消这一点,我们需要交换每对数据,再把他们送入CCSDS协议解码器。

现在,我们实现了一个 Viterbi 译码器并检查了它的工作。“Swap”模块是一个自定义的模块,它交换每一对浮点数。对于BPSK信号,我们要把两个Viterbi译码器放在输入流上,

其中一个比另一个延后一个样本,因为我们不知道刚开始捕获数据的时候,是一对数据的第一个还是第二个。

你可能会看到如下的输出,其中metric变量表示Viterbi解码器的误码率,当误码率很低的时候metric变量很高,而且几乎有一个恒定的数值,相反,如果解码器没有工作,metric值会很低,并具有类似随机的值。当然,两个译码器只有一个正常工作。当BPSK解调错过一个值或者插入来一个值,(样本流多了或者少了一个bit),这两个Viterbi解码器的工作状态(是否工作正常)就会交换,如果信号质量好,不应该发生这种情况,在这个过程中,是由于树木在风中的移动干扰来信号。另外一个有趣的尝试是关闭“Swap”模块,这样的话两个Viterbi解码器都不会正常工作了。

现在,我们对Viterbi译码器是否工作很有信心,我们接下来把数据流放入raster图,观察是否使用了扰频器,如果使用了,数据流会看起来随机化,如果没有,我们会看到一些比特流的特有结构,实际上,我们基本已经确定它使用了扰频器,因为我们之前看到的BPSK信号很像噪声,而不是展现BPSK的特有频谱结构。

正如你下面看到的,比特流的出现是随机的,所以我们还需要一个解扰器。

选择正确的解扰器是很困难的,因为我们没有办法去猜测它的算法,如果您知道它使用来那种卫星调制解调器,请尝试它支持的所有算法,如果您不知道,那就尝试所有流行的算法。这一步通常需要大量的试验和错误。然而,如果选用正确来,效果也是很明显的,你可你看到他的输出比特流结构,如果不对,输出还是随机的。

最常用的一种是G3RUH的复数乘法器(它用于9.6kbaud业余无线电组和几个业余卫星),数据可以使用GNU  radio中的 “Descrambler” 模块加扰,它使用0x21作为掩码,长度为16 ,这个模块的参数选择很麻烦,详见我的博客。[18]

在这种情况中,G3RUH加扰器是无法工作的。有这样的事实,我们的二进制代码要传递给寄存器进行处理, sdr100在Outernet的软件中作为sdr接收器,那么,他只可能是基于ARM或者86-64架构上运行的Linux操作系统,而最新的软件版本只对arm进行支持,所以,Outernet上用于接收的部分应该是像树莓派3一样的arm板。

我对x86-64架构下的客户端程序中的sdr100二进制文件进行了逆向,来获取Outernet解扰算法,原来,这是 IESS-30解码器,很显然,这个算法的详细细节在卫星地球站的文档中没有公开。但是,我还是找到了一个文档[19](见28页),里面的描述有助于我的逆向。

我设计了一个模块用于 IESS-308 解码,您可以在这里[20]看到这个模块的代码。如果你熟悉乘法加扰器,你会发现这个加扰器很普通,但是,它用了一个计数器。

下面的流图可以测试我们的 IESS-308 解码器

输入流显示出了很明显的结构,所以我们有信心,这个解码器是正常的。你可以看到一些白色和青色的水平线,这符合长时间连续二进制0,1传输的特征。这张图中的每行每列的水平线的数量和分布代表着二进制的数据,如果把它们垂直摆放在一条线上,看起来可能更明显,我们会很容易发现什么数据是不改变的(例如报文头)或者改变的(例如数据段)。在这条推文中[21],你可以看到进行如上工作的一个例子。

下一步工作是解帧,通常,我们可以通过仔细观察比特流来识别帧标记,但是,在这里我们可以通过逆向sdr100二进制代码的方式减轻工作量。sdr100中,有一些函数的名称中含有HDLC,所以我们猜测可能是使用来HDLC帧,我们尝试从数据流中恢复HDLC帧。

GNU Radio中,提供了用于解HDLC帧的模块,但是,我准备用我自己的gr-kiss[22]模块。这个模块的好处是可以去保留CRC码校验错误的数据帧。有的时候,可能一个数据帧只有几个bit是错误的,他就被完全丢弃了。然而,保留CRC校验错误的帧对于逆向协议和分析测试是很有用的。有时候,HDLC帧会有几个bit的错误,那可能是因为干扰或者解码器参数没有优化,也有可能碰巧只有16位的CRC码出现了错误。在这种情况下,保留错误帧也是很有用的。

到现在为止,我们还没有考虑信号的极性,在接受 BPSK信号的时候,你不知到他是一个原始信号还是一个翻转信号(即0,1的互换),是否进行了180度的相位翻转是模糊的,很多时候,采用差分编码来消除这种模糊性。HDLC 可能采用的是NRZ-I,也可能没有采用差分编码,而采用其他方式消除模糊,这又是一个实验和试错的过程。

实际上,Outernet不使用任何一种差分编码,因此我们需要一个正置的数据流和一个反置的数据流,只有一个可以正常工作,但是我们实现不知道是哪一个。(当我们失去信号之后,下一次连接,它可能改变。)

下面是HDLC解帧的流图,“Invert bit”是一个自定义的模块,他的功能就是进行位翻转。也可以使用程序提供的模块实现这一功能。下面,我把两个HDLC解帧模块连接在数据流上,在其中一个前面进行位翻转。

当我们运行这个流图之后,在控制台上会看到数据帧的出现。因为我们开启了CRC检查,

所以我们确信我们的接收机可以正常工作。毕竟,如果我们在处理的时候有错误,是不可能出现这么多通过CRC校验的数据帧。

我们GNU Radio阶段的任务就完成了,一旦提取了HDLC数据帧,就需要使用free-outernet[23]这个Python脚本进行UDP发送,或者把它们存在一个文件里。free-outernet会回复被传输的文件,它还会打印一些有趣的调试和技术信息。

下面你可以看到脚本可以恢复的两个文件,e89f-messages-0.html.tbz2包含了用于业余无线电的APRS[25]信息,和ed57-amazon.com.html.tbz2,其中包含亚马逊的维基百科网页[26]。大部分的文件是以tbz2压缩格式发送的。另一个有趣的事情是,每分钟,会有一个时间数据包。这用来更新接收器的时钟信号,因为使用的是小型ARM,所以没有真实的时钟或者网络连接。

提取文件后,我们可以在Web浏览器中打开亚马逊的维基百科页面。这页是一个HTML文件,其中包含CSS样式表和图片。它为独立的查看而进行了小尺寸优化,所以所有的超链接已被删除。

对广播文件协议的介绍超出了本文的范围,你可以在我的博客[27]中找到完整的描述。我唯一不能逆向的是使用了应用级FEC的LDPC编码。它可以使接受程序在一些数据帧错误的情况下恢复文件,由于LDPC码的译码没有实现,所以你需要获取一个文件所有的数据帧才能使用我们的脚本恢复,你可以看到github上有关于LDPC的进展[28]。

参考链接


[1]https://outernet.is/

[2]https://en.wikipedia.org/wiki/L_band

[3]https://en.wikipedia.org/wiki/Inmarsat

[4]https://github.com/Outernet-Project/outernet-linux-lband/blob/master/bin/sdr100-1.0.4

[5]http://sdr.osmocom.org/trac/wiki/rtl-sdr

[5]http://cgit.osmocom.org/libmirisdr/

[6]https://github.com/daniestevez/gr-outernet

[7]https://github.com/daniestevez/free-outernet

[8]http://datumsystems.com/m7

[9]http://destevez.net/tag/outernet/

[10]https://twitter.com/scott23192

[11]http://www.ka9q.net/oldquotes.html

[12]http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_PSK_Demodulation

[13]http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorials

[14]http://spench.net/

[15]http://wiki.spench.net/wiki/Gr-baz#auto_fec

[16]https://gist.github.com/daniestevez/79f6f9971e1c6f883cb67a2989ba33e6

[17]https://gist.github.com/daniestevez/70d570292493daac33efb1767fc478ed

[18]http://destevez.net/2016/05/scramblers-and-their-implementation-in-gnuradio/

[19]http://www.etsi.org/deliver/etsi_etr/100_199/192/01_60/etr_192e01p.pdf

[20]https://github.com/daniestevez/gr-outernet/blob/master/lib/descrambler308_impl.cc#L72

[21]https://twitter.com/ea4gpz/status/786518040141717505

[22]https://github.com/daniestevez/gr-kiss

[23]https://github.com/daniestevez/free-outernet

[24]http://www.ax25.net/kiss.aspx

[25] http://aprs.org/outnet.html

[26]https://en.wikipedia.org/wiki/Amazon.com

[27]http://destevez.net/2016/10/reverse-engineering-outernet-time-and-file-services/

[28]https://github.com/daniestevez/free-outernet/issues/1

发表于360安全客http://bobao.360.cn/learning/detail/3181.html

我的翻译--针对Outernet卫星信号的逆向工程的更多相关文章

  1. Lantern卫星接收器:为你提供免费上网服务

    包括笔者在内,许多现代人的日常生活都无法离开网络,因为在网络上我们几乎可以找到任何我们需要的信息.但你是否有想过在户外无网络信号的情况下如何接收网络数据呢?一个名为Outernet Inc.的公司为我 ...

  2. 转:python signal信号

    转自:http://www.jb51.net/article/74844.htm 在liunx系统中要想每隔一分钟执行一个命令,最普遍的方法就是crontab了,如果不想使用crontab,经同事指点 ...

  3. (13)odoo翻译

    -------------------更新时间:15:52 2016-09-28 星期三 增加模型名翻译17:26 2016-05-20 星期五17:58 2016-05-17 星期二12:14 20 ...

  4. Python标准库07 信号 (signal包,部分os包)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在了解了Linux的信号基础之后,Python标准库中的signal包就很容易学习 ...

  5. Linux 进程通信之 ——信号和信号量总结

    如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存.       所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...

  6. ReactiveCocoa的冷信号与热信号 探讨

    背景 ReactiveCocoa(简称RAC)是最初由GitHub团队开发的一套基于Cocoa的FRP框架.FRP即Functional Reactive Programming(函数式响应式编程), ...

  7. 【转】GLONASS全球卫星导航系统

    GLONASS是“GLOBAL NAVIGATION SATELLITE SYSTE(全球卫星导航系统)”的缩写,作用类似于美国的GPS.欧洲的伽利略卫星定位系统.最早开发于苏联时期,后由俄罗斯继续该 ...

  8. Python模块之信号(signal)

    在了解了Linux的信号基础之 后,Python标准库中的signal包就很容易学习和理解.signal包负责在Python程序内部处理信号,典型的操作包括预设信号处理函数,暂 停并等待信号,以及定时 ...

  9. 2018-10-18读文献总结之DCB码分多址、零基线、信号产生

    ---恢复内容开始--- 今天心血来潮,想开始把自己读文献的过程和每篇文献的收获总结一下,不知道CSDN怎么回事,一直登陆不进去,搞得我注册了一个博客园的账户,博客园新注册的还需要认证,但是很快,所以 ...

随机推荐

  1. MFC/QT 学习笔记(一)——认识windows基础库

    MFC (微软基础类库),Windows系统平台做GUI尚且OK,但不支持跨平台. //Windows消息机制: //1.SDK与API Software Development Kit,为特定软件框 ...

  2. 3.Python运算符详解

    1.算数运算符 符号:+   -   *   /   %(取余.取模)   //(取整)   **(开方) 2.比较运算符 符号:>   >=   <   <=   ==(全等 ...

  3. oracle中sql语句的to_date语法

    完整日期:TO_DATE('2009-4-28 00:00:00', 'yyyy-mm-dd hh24:mi:ss'); to_date('2008/09/20','yyyy/mm/dd') 创建视图 ...

  4. oracle数据泵导入导出部分用户

    问题描述:需要将140服务器中的tbomnew实例下的部分用户导入到118服务器下的tbompx实例中,本次导入导出的两个数据库均为19C 部分用户名:CORE,MSTDATA,BOMMGMT,CFG ...

  5. 10maven依赖继承、统一版本/编码

    A >  B  >  C A依赖于B,B依赖于C,如果A想间接依赖C,那么B和C之间的依赖范围必须是compile,不然A依赖不了C 但是有点麻烦,因为每次A想依赖于C都要确认B和C之间的 ...

  6. C语言实现读取字符转换为浮点数,不使用scanf函数

    c语言读取int或者float数据,我们习惯于使用scanf函数,但是如果不使用scanf函数,该怎么实现呢. 这里就来尝试一下,不使用scanf来读取数据并转换为float类型. 下面的getflo ...

  7. OptaPlanner 7.32.0.Final版本彩蛋 - SolverManager之异步求解

    因为工作和其它原因,很长一段时间没有出新的.关于OptaPlanner的文章了,但工余时间并没有停止对该引擎的学习.与此同时Geoffrey大神带领的KIE项目团队并没有闲下来,尽管在工业可用性.易用 ...

  8. CSS3中新增的对文本和字体的设置

    文字阴影 text-shadow: 水平偏移 垂直偏移  模糊 颜色 兼容性:IE10+ <!DOCTYPE html> <html lang="en" mani ...

  9. Bash脚本编程学习笔记05:用户交互与脚本调试

    用户交互 在<学习笔记04>中我们有提到位置参数,位置参数是用来向脚本传递参数的一种方式.还有一种方式,是read命令. [root@c7-server ~]# read name alo ...

  10. P1980 计数问题(int,string,stringstream)

    题目描述 试计算在区间 1 到 n 的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1 到 11 中,即在 1,2,3,4,5,6,7,8,9,10,11 中,数字 1 出现了 4 ...