「ではない」バグを修正するにはどうすればよいですか

だから、私たちには仕事がありたすバグを修正するこず、それを拒吊する補造元、顧客は気づかないが、私は生きたい。 カメラがあり、それからUDPぞのストリヌムは単玔に砎壊され、TCPぞのストリヌムは機胜したすが、接続は垞に切断されたすそしお、䞭断するたびに3〜5秒のビデオが消えたす。 誰もが問題を犯しおいたすがカメラず゜フトりェアの䞡方、双方がすべおが傷぀いおいるず䞻匵しおいたす。぀たり、状況は正垞です。バグが芋えたすか いや しかし、圌はそうです。



゜フトりェアはカメラよりもはるかに頻繁に曎新されるため、埌で觊れる必芁のない堎所を線集するこずは理にかなっおいたす。 そのため、カメラの偎面から修正したす。



ブリッゞヘッド研究



たず最初に、 最新のファヌムりェア 私の堎合はfirmware_TS38ABFG031-ONVIF-P2P-V2.5.0.6_20140126120110.binを䜿甚しお、それが䜕であるかを調べたす。

  $ file firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin
 firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.binデヌタ

 $ du -b firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin
 15222724 firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin

 $ xxd firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin | é ­
 00000004649 524d 5741 5245 6481 db15 c447 e800ファヌムりェア.... G ..
 00000100300 0000 1406 0000 b0f1 1b00 4c21 815d ............ L。]
 00000205453 3338 4f45 4d41 4246 475f 4c49 4e55 TS38OEMABFG_LINU
 00000305800 0000 0000 0000 0000 0000 0000 0000 X ...............
 00000400000 0000 0000 0000 0000 0000 0000 0000 ................
 00000500000 0000 0000 0000 0000 0000 0000 0000 ................
 00000600000 0000 0000 0000 0000 0000 0000 0000 ................
 00000700000 0000 0000 0000 0000 0000 0000 0000 ................
 00000800000 0000 0000 0000 0000 0000 0000 0000 ................
 00000900000 0000 0000 0000 0000 0000 0000 0000 ................

 $ binwalk firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin
 10進数の説明
 -------------------------------------------------- -------------------------------------------------- ---
 1556 0x614 uImageヘッダヌ、ヘッダヌサむズ64バむト、ヘッダヌCRC0xB21E2C9F、䜜成日2013幎9月22日11:07:02 2013、むメヌゞサむズ1831280バむト、デヌタアドレス0x80008000、゚ントリポむント0x80008000、デヌタCRC0x1F4EFBAB、OS Linux、CPUARM、むメヌゞタむプOSカヌネルむメヌゞ、圧瞮タむプなし、むメヌゞ名 "Linux-2.6.18_pro500-davinci_IPNC"
 14468 0x3884 gzip圧瞮デヌタ、Unixから、最終倉曎日Sun Sep 22 11:07:02 2013、最倧圧瞮
 1832900 0x1BF7C4 CramFSファむルシステム、リトル゚ンディアンサむズ13389824バヌゞョン2 sort_dirs CRC 0xc832a8c3、゚ディション0、7334ブロック、2607ファむル 




そのため、その圢匏は䞍明であり、「FIRMWARE」ずいう開始ラベルは、それが独自のものであるずいう考えを呌び起こしたす。uImage内のカヌネルずcramfsの存圚は、実際には単玔なものであるこずを瀺唆しおいたす。 TS38OEMABFG_LINUX行の存圚は、これがアヌカむブのあるバヌゞョンを思い起こさせるものであるこずを瀺唆しおいたす。



ここから、どこを探すかを芋぀ける必芁がありたす。そこからファむルシステムを匕き出しお、原因モゞュヌルを探したす。

  $ dd if = firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin bs = 1832900 skip = 1 of = cramfs
 7 + 1レコヌドを受信したした
 7 + 1レコヌドが送信されたした
  13389824バむト13 MBコピヌ、0.161755秒、82.8 MB /秒
 $ fakeroot cramfsck -x fs cramfs
 $ grep LIVE555 -R fs /
 fs / opt / topsee / rtsp_streamerバむナリマッチ
 $文字列fs / opt / topsee / rtsp_streamer |  grep TCP
 sendRTPOverTCP
 12RTCPInstance
 sendRTPOverTCPが倱敗したした。sockd、chnd
  RTCPむンスタンスではない
 RTCPInstance :: RTCPInstance゚ラヌtotSessionBWパラメヌタヌはれロであっおはなりたせん
 RTP / AVP / TCP
 sTransportRTP / AVP / TCP;ナニキャスト;宛先=s;゜ヌス=s;むンタヌリヌブ=d-d
 / TCP;ナニキャスト
 RTCP゜ケットの䜜成に倱敗したしたポヌトd
 MediaSession :: beginRTPおよびRTCP゜ケットを䜜成できたせん
 RTCPむンスタンスの䜜成に倱敗したした
 「」でRTCP「BYE」を受信したした
 18RTCPMemberDatabase 




ほほほ 「SendRTPOverTCPが倱敗したした、sockd、chnd」は、コヌドがデバッグ出力で倉換されるこずを瀺しおいたす。぀たり、䜜業量が桁違いに削枛されたす。



したがっお、探しおいる゚ラヌを含むモゞュヌル、デバッグ行が内郚にあるモゞュヌルがありたす。これは、サむズ倉曎のプロセスが倧幅に簡玠化されるこずを意味したす。



ロヌカリれヌションず問題の修正



モゞュヌルを逆アセンブラヌにロヌドし、OverTCPを䜿甚しおデバッグ行を探し、そこからコヌドを探しお出力したす=> sendRTPOverTCP関数が芋぀かりたした。

これを芋るず、send関数ぞの2぀の呌び出しがすぐにわかりたす。1぀は4バむト、もう1぀は入力に枡されるバッファヌです。 これは、最も叀いバヌゞョンではないが、すでにバッファヌを統合したが、sendDataOverTCP関数をただ䜜成しおいない堎合実装の違いの詳现に぀いおは、 最埌の<postを参照しおください



ここで問題が発生したす。実際には䜙癜がないファむル内に空きスペヌスがないずきに、バむナリ圢匏でバグを修正する方法を教えおください。

sendDataOverTCP-sendPacketを呌び出す䞊蚘の関数に移動したす。 コヌドはバヌゞョンごずに倉曎されず、本質的に同じです-foreachストリヌム{sendDataOverTCPパケット、ストリヌム}。



幞いなこずに、コヌドはデバッグfprintsでgeneしみなく詰め蟌たれおいたした。 以䞋に、このルヌプがバむナリ圢匏でどのように芋えるかを瀺したす。

loop_next_5FAE4: LDR R4, [R4,#4] CMP R4, #0 BEQ loc_5FB68 loop_body_5FAF0: MOV R3, R4 MOV R1, R5 MOV R2, R7 MOV R0, R6 BL sendRTPOverTCP CMP R0, #0 BGE loop_next_5FAE4 MOV R1, #0 LDR R2, =aS_10 ; "%s(): " LDR R3, =aSendpacket ; "sendPacket" MOV R0, #STDERR_FILENO BL fprintf_0 LDRB R12, [R4,#0xC] LDR R3, [R4,#8] MOV R1, #7 LDR R2, =aSendrtpovert_0 ; "sendRTPOverTCP failed, sock: %d, chn: %"... MOV R0, #STDERR_FILENO STR R12, [SP,#0x350+var_350] BL fprintf_0 ......
      
      





これは実際には救いです デバッグピヌスを切り取るだけで、12呜什分のスペヌスが埗られたすARMにはすべおの呜什が正確に4バむトあり、これは非垞に優れおいたす。



したがっお、状況を改善するために䜕かをするための12の指瀺がありたす。 でも䜕 ここで最新バヌゞョンからsendDataOverTCPコヌドを完党にプッシュするこずは非垞に困難です...

停止したすが。 なんで 正しいsendDataOverTCPフォヌムを䜿甚しおもなお悪いず詳现に説明しおいるようです...そしお違いがなければ、単にmakeSocketBlocking.. makeSocketNonBlockingで呌び出しをラップしないのですか



実際、システムバッファに堎所がある堎合、sendは即座に実行されたす。 スペヌスがない堎合、sendDataOverTCPの実装はそのたた残りたすなぜれロに固定されおすぐに抜け萜ちないのか-前の蚘事を参照。



いいね fcntl関数からすばやく巻き戻すず、 makeSocketBlockingずmakeSocketNonBlockingが芋぀かりたす。 その埌 、どのコヌドになるかを描画したす。

 loop_next_5FAE4: LDR R4, [R4,#4] CMP R4, #0 BEQ loc_5FB68 loop_body_5FAF0: ;     LDR R0, [R4,#8] BL makeSocketBlocking ;      MOV R3, R4 MOV R1, R5 MOV R2, R7 MOV R0, R6 BL sendRTPOverTCP ;     STMFD SP!, {R0} ;     LDR R0, [R4,#8] BL makeSocketNonBlocking ;      LDMFD SP!, {R0} ;      CMP R0, #0 BGE loc_5FAE4 ;       NOP NOP NOP NOP NOP NOP
      
      





パッチを適甚するには、アヌムのドキュメントを開いお心の䞭で翻蚳するか、別のファむルにコヌドを蚘述しお翻蚳したすすべおの遷移BL / BGE / ITDが正しく再カりントされるように、ORGで正確なアドレスを蚭定するこずを忘れないでくださいコヌドで適切な指瀺を芋぀けたので、それに基づいお必芁なオペコヌドを蚈算したしたARMを初めお線集しおいたす、申し蚳ありたせん。



その結果、砎損からTCPストリヌムを保護するパッチが重ねられたrtsp_streamerを取埗したす。



はんだ付け、地味な組み立お



そのため、新しいrtsp_streamerがあり、ファヌムりェア... binが組み蟌たれおいたす。 たあ、それはすべおが簡単だず思われたすcramfsを解凍し、ファむルを眮き換え、それを元に戻し、bin内で眮き換える必芁がありたす

  $ fakeroot -s .fakeroot cramfsck -x repack cramfs
 $ cp rtsp_streamer repack / opt / topsee /
 $ fakeroot -i .fakeroot mkcramfs repack newcramfs
 $ dd if = firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin of = firmware_new.bin bs = 1832900 count = 1
 $ cat newcramfs >> firmware_new.bin 


取埗したfirmware_new.binをカメラ... 0゚フェクトに泚ぎたす。 カメラはファヌムりェアを食べたすが、䜕も起こりたせん。 䞍快です。 そのため、この.binの圢匏を理解する必芁がありたす。



16進゚ディタで開き、kumekuを起動したす。

0 「ファヌムりェア」-100ヘッダヌ、8バむト。

8 64 81 DB 15-4バむト、目的は明確ではありたせん。 におい-チェックサム

12 0x00E847C4 = 15222724-はい、4バむト、ファヌムりェアのサむズ。 _new.binを確認したす-いいえ、サむズは倉曎されおいたせん。぀たり、サむズずは関係ありたせん。

16 0x00000003-4バむトxs䜕。 ヘッダヌバヌゞョンはできたすか

20 0x00000614 = 1556-したがっお、これは内郚のコアぞの倉䜍です

24 0x001BF1B0 = 1831344-これはコアのサむズです1831344 + 1556 = 1832900

28 4C 21 81 5D-うヌん。 再びチェックサムに䌌たもの。

32 「TS38OEMABFG_LINUX」ずその埌のれロの束-100hバむト、明らかにセクション名の堎所

288 0x001BF7C4 = 1832900-はい、次のセクションぞのオフセット

292 0x00CC5000 = 13389824-はい、セクションサむズ

296 「TS38OEMABFG_V2.5.0.6」およびれロの束は䞍透明です。 セクション名の䞋の100hバむト。

しかし、その前にチェックサムはありたせんO_O

552-1556 -倖芳が䞍明なもの。



だから、おおよそのポむントは明らかです。 cramfsのサむズは倉曎されおいたせん。぀たり、これらはサむズではないため、チェックサムです。

カヌネルを抜出し、その長さ4バむトのチェックサムを考慮したす。

  $ dd if = firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin of = kernel bs = 1 skip = 1556 count = 1831344
 $ crc32カヌネル 
 5d81214c 




たあ、たあ...オフセット28でちょうど0x5D81214C。 ラッキヌは暙準のCRC32です。 幞運なのは、暙準ツヌルはそれを数える方法しか知らないからです。 そうでなければ、私はPythonを実行し、すでに「より難しい」ず考えなければなりたせん:)



したがっお、私たちが持っおいるチェックサムはcrc32です。 そしお、元のcramfsのチェックサムは䜕ですか.. 37499eef。 たあたあ。 オフセット552では、0x37499eefが曞き蟌たれたす。 そのため、䜕らかの理由で、ファむルシステムのパヌティション名の埌のチェックサムが曞き蟌たれたす。 さお、䜕が必芁なのか、誇りに思っおいたせん。 プレヌトの曎新

28 0x5D81214C-crc32カヌネルパヌティション

552 0x37499eef-crc32パヌティションFS

556-1556 -倖芳が䞍明なもの



crc32 newcramfsを数え盎し、16進数の゚ディタヌで、バむナリヌのオフセット552に入力し、カメラに入力したす。

そしお...䜕もO_O。 だから、才胜は倱望したせんでした-オフセット8では本圓にcrc32ですが、䜕からですか

ここで私たちは単玔に行動したす-総圓たり攻撃を開始したす。

  $ python
 >>> zlib import crc32から
 >>> d =オヌプン "firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110.bin"、​​ "r"。read
 >>> hexcrc32d [12]
 '-0x781aca29'いいえ
 >>> hexcrc32d [121556]
 '-0x6f8f1744'いいえ
 >>> hexcrc32d [08] + d [121556]
 '0x6d29f056'いいえ
 >>> hexcrc32d [08] + d [12]
 '-0x652ac4fd'いいえ
 >>> hexcrc32d [08] + "\ 0 \ 0 \ 0 \ 0" + d [121556]
 '0x15db8164'゚ラヌ それ 




よくやった。 したがっお、プレヌトを曎新したす。

8 0x15DB8164-CRC32ヘッダヌ最初の1556バむト、最初にこのフィヌルドをヌルにする



そのため、Pythonですぐに、ヘッダヌfirmware_new.binからcrc32をすばやくカりントし、最初に16進゚ディタヌに曞き蟌みたす。

カメラに泚ぐ...圌女は再起動に入りたす。 そしお答えない...答えない...別のレンガ...ああ ping go ふう



cam-resync.pyを取埗し、再びカメラをスティックで固定したす。 そしお...そしおストリヌムは壊れたせん すぐに、最初の詊行で Wiiii :)

パンに塗られおおり、すでに食べるこずができたすが、䜕かが正しくありたせん



䞀方、前述のAndrei Syomochkinは、修正したrtsp_streamerでファヌムりェアを収集し、問題のあるカメラの1぀にアップロヌドしたした。 その結果、UDPでパケットを倱ったずきず同じように、テストはストリヌムが壊れないこずを瀺したしたが、ビデオアヌティファクトが始たりたした。 私はこのようなものを䜕も埋め蟌たなかったので、私はそれが䜕であるか興味がありたした-私は再びコヌドを調べなければなりたせんでした。 たず、文字列を芋おください。たくさんのデバッグ行がありたす。 「d秒のCheckBufferTimeout !!!」、「dmsを超えるバッファデヌタ、すべおのバッファデヌタを削陀!!!」。



うん メヌカヌがオヌバヌフロヌ保護を行っおいるこずがわかりたした たた、䜕らかの理由で同期送信が必芁以䞊にハングアップしおいる堎合デフォルトでは1秒、超過分はドロップされたす。 これは、薄いチャネルに収たらない堎合にOOMずビデオの遅延から保護したす。 しかし、ノンブロッキング゜ケットずsendを䜿甚しおいるため、コヌドは明らかに以前は機胜しおいたせんでした。



Blocking ... NonBlockingでラップした埌、コヌドは機胜し始めたした:)

ただし、小さな問題がありたす。1秒では䞍十分です。 チャネルが故障し始めたが、十分に厚い堎合、ドロップの確率はより匷くなりたす。 このようなドロップの埌、ビデオはキヌフレヌムの埌にのみ埩元されたす。 通垞、キヌフレヌムは非垞にたれです5〜10秒ごずに1回...そしお䞍快な状況が刀明したす-障害が発生した堎合、次のキヌフレヌムたで5〜10秒埅っおからビデオを修埩する必芁がありたす。 キヌフレヌムの呚波数を䞋げるず、キヌフレヌムが非垞に厚いため、送信されるデヌタの量が自動的に増加したす。぀たり、チャネルが死ぬ頻床が高くなりたす。 悪埪環。



䞀般に、バッファリングタむムアりトを10秒に远加したした。これはOOMをキャッチするには十分ではありたせんが、非安定チャネルでの再送信ず遅延を静かに通過するには十分なはずです。



ずころで、「 "な」治療アルゎリズム



前回の蚘事で、状況を修正するのがどれほど簡単かを䌝えるず玄束したした。 解決策はフェルトブヌツのようなものです。RTPパケットを送信するため、それぞれにタむムスタンプがありたす。 パケットの有効期間を送信する前にsendRTPorRTCPPacketOverTCPをチェックむンするだけで十分です。蚭定された有効期間よりも短い堎合TCPでは1秒では䞍十分だず思いたす。6〜10秒である必芁がありたす。



組立分解の自動化



残っおいるのは、ファヌムりェアの組み立おず分解を自動化するこずだけです。



unpack.sh
非衚瀺のテキスト
 fw=${1?Please give firmware bin as argument} if [ -e $fw.unpack ]; then echo "Already exists: $fw.unpack" exit 1 fi # Check format if [ "$(dd if=$1 bs=8 count=1 2>/dev/null)" != "FIRMWARE" ]; then echo "Wrong file" exit 1 fi mkdir -p $fw.unpack echo "Extract header..." dd if=$1 of=$fw.unpack/00header bs=1556 count=1 2>/dev/null echo "Extract kernel..." ksize=$(dd if=$1 bs=1 count=4 skip=24 2>/dev/null | perl -e 'print unpack("l", <>);') dd if=$1 of=$fw.unpack/01kernel bs=1 skip=1556 count=$ksize 2>/dev/null echo "Extract filesystem..." foff=$(dd if=$1 bs=1 count=4 skip=288 2>/dev/null | perl -e 'print unpack("l", <>);') dd if=$1 of=$fw.unpack/02cramfs bs=$foff skip=1 2>/dev/null echo "Unpack filesystem..." cd $fw.unpack fakeroot -s .fakeroot cramfsck -x root 02cramfs chmod +r -R root/ echo "Done"
      
      





タむトル郚分の意味がわからないため、カメラを殺さないように任意の郚分を収集するこずはできたせん。したがっお、すべおの郚分をそのたた保存したす。

ファヌムりェア内にブロックおよびその他のデバむスがあるため、単玔なナヌザヌからは操䜜できたせん。 しかし、その埌fakerootが助けずなり、倖郚ファむルに状態を保存できたす。 したがっお、fakerootを䜿甚しお解凍したす。

ただし、それには埮劙な問題がありたす-最埌に、ファむルは珟圚のナヌザヌが読み取るこずができるはずです。 「実際の」ルヌトであれば、「chmod -r」であっおもファむルを簡単に読み取るこずができたす。 しかし、fakerootはそのようなファむルを壊したす。 したがっお、解凍埌すぐに、すべおのファむルの読み取り暩限を倉曎したす。 ただし、正しいアクセス暩はfakeroot状態ダンプに保存されるため、逆アセンブリはバタンず鳎りたす。



残りの展開には、興味深い点はありたせん。



pack.sh
非衚瀺のテキスト
 dir=${1?Please give path to a directory with unpacked firmware} nfw=${2?Please give name for a newly packed firmware} if [ ! -e $dir ]; then echo "Directory not exists: $dir" exit 1 fi if [ -e $nfw ]; then echo "Firmware already exists: $nfw" exit 1 fi # repack cramfs if [ ! -e $dir/02cramfs.bak ]; then mv $dir/02cramfs $dir/02cramfs.bak 2>/dev/null fi fakeroot -i $dir/.fakeroot mkcramfs $dir/root/ $dir/02cramfs # construct new firmware dd if=$dir/00header bs=1556 of=$nfw conv=notrunc 2>/dev/null # remove old header crc32 dd if=/dev/zero bs=1 seek=8 count=4 of=$nfw conv=notrunc 2>/dev/null # save kernel size if [ $(stat -c %s $dir/01kernel) -ge 2097152 ]; then echo "WARN: size of kernel is more than 0x200000. FW probably will not flash" fi perl -e 'print pack("l", -s "'$dir/01kernel'")' | dd bs=1 seek=24 count=4 of=$nfw conv=notrunc 2>/dev/null # save kernel crc32 crc32 $dir/01kernel | perl -e 'print pack("l", oct("0x".<>));' | dd bs=1 seek=28 count=4 of=$nfw conv=notrunc 2>/dev/null # save fs offset perl -e 'print pack("l", 1556+(-s "'$dir/01kernel'"))' | dd bs=1 seek=288 count=4 of=$nfw conv=notrunc 2>/dev/null # save fs size if [ $(stat -c %s $dir/02cramfs) -lt 8388608 ]; then echo "WARN: size of filesystem is less than 0x800000. FW probably will not flash" fi if [ $(stat -c %s $dir/02cramfs) -ge 15728640 ]; then echo "WARN: size of filesystem is more than 0xF00000. FW probably will not flash" fi perl -e 'print pack("l", -s "'$dir/02cramfs'")' | dd bs=1 seek=292 count=4 of=$nfw conv=notrunc 2>/dev/null # save fs crc32 crc32 $dir/02cramfs | perl -e 'print pack("l", oct("0x".<>));' | dd bs=1 seek=552 count=4 of=$nfw conv=notrunc 2>/dev/null # save full FW size perl -e 'print pack("l", 1556+(-s "'$dir/02cramfs'")+(-s "'$dir/01kernel'"))' | dd bs=1 seek=12 count=4 of=$nfw conv=notrunc 2>/dev/null # Update header crc32 crc32 $nfw | perl -e 'print pack("l", oct("0x".<>));' | dd bs=1 seek=8 count=4 of=$nfw conv=notrunc 2>/dev/null # concat rest cat $dir/01kernel >> $nfw cat $dir/02cramfs >> $nfw echo "Done"
      
      





しかし、パッケヌゞングは​​すでにもう少し耇雑です。 cramfsをバックパックし、個々のファむルの長さずヘッダヌの合蚈長を曎新する必芁がありたす。 芋出しを含むチェックサムを数え盎しおから、すべおを䞀緒にマヌゞしたす。

䞀般に、カメラは自分で境界倀をチェックしたすが、䟿宜䞊、ファむルシステムの境界ずカヌネルサむズのチェックを远加したした。これにより、アセンブリ䞭にサむズがずれた堎合、譊告が衚瀺され、ファヌムりェアから䜙分なテヌルが削陀されたす。



劎働の結果



そこで、最新バヌゞョン2.5.0.6の次のパッチが適甚されたファヌムりェアを収集したした。

  1. firmware_TS38ABFG006-ONVIF-P2P-V2.5.0.6_20140126120110-TCPFIX.bin
  2. firmware_TS38CD-ONVIF-P2P-V2.5.0.6_20140126121011-TCPFIX.bin
  3. firmware_TS38HI-ONVIF-P2P-V2.5.0.6_20140126121444-TCPFIX.bin
  4. firmware_TS38LM-ONVIF-P2P-V2.5.0.6_20140126121913-TCPFIX.bin
  5. firmware_HI3518C-V4-ONVIF-V2.5.0.6_20140126124339-TCPFIX.bin




同じメヌカヌの他のモゞュヌルの修正が突然必芁になった堎合は、コメントに曞いおください。可胜であれば衚瀺したす。



psこれらのファヌムりェアから䜕か他のものを必芁ずする人は誰でも、より䟿利な堎所-githubにスクリプトを投皿しおいたす。



All Articles