猫の䞭のサむ-Kopycat゚ミュレヌタヌでファヌムりェアを実行する


2月16日の䌚議0x0A DC7831 DEF CONニゞニノノゎロドで、バむナリコヌド゚ミュレヌションの基本原則ず独自の開発ハヌドりェアプラットフォヌムKopycatの゚ミュレヌタヌに関するレポヌトを発衚したした。


この蚘事では、゚ミュレヌタヌでのデバむスファヌムりェアの起動に぀いお説明し、デバッガヌずの察話を瀺し、ファヌムりェアの小さな動的分析を実行したす。


背景


昔、遠くの銀河で


数幎前、私たちの研究宀では、デバむスのファヌムりェアを調査する必芁がありたした。 ファヌムりェアは圧瞮され、ブヌトロヌダヌによっお解凍されたした。 圌は非垞に混乱した方法でこれを行い、メモリ内のデヌタを数回シフトしたした。 はい、そしおファヌムりェア自䜓が呚蟺機噚ず積極的に察話したした。 そしお、これらすべおがMIPSコアにありたす。


客芳的な理由から、既存の゚ミュレヌタヌは私たちに合わなかったが、それでもコヌドを実行したかった。 その埌、私たちは独自の゚ミュレヌタヌを䜜成するこずにしたした。これにより、最小限になり、メむンファヌムりェアを展開できるようになりたす。 詊したした-刀明したした。 メむンファヌムりェアも実行するために呚蟺機噚を远加したらどうなるか考えたした。 それほど痛くありたせんでした 私たちはもう䞀床考え、本栌的な゚ミュレヌタを䜜るこずにしたした。


その結果、コンピュヌティングシステムKopycatの゚ミュレヌタヌができたした 。



Kopycatを遞ぶ理由

蚀葉の遊びがありたす。


  1. copycat 英語、n。[ˈkɒpɪkÊt]-copycat、暡倣者
  2. 猫 英語、n。[ˈkÊt]-猫、猫-プロゞェクトの䜜成者の1人のお気に入りの動物
  3. 文字「K」-Kotlinプログラミング蚀語から

コピキャット


゚ミュレヌタヌを䜜成するずきに、絶察に具䜓的な目暙が蚭定されたした。



その結果、実装、バスアヌキテクチャ仮想デヌタバスを介しおモゞュヌルが盞互に通信する堎合、デバむス蚘述圢匏ずしおJSON、デバッガヌず察話するためのプロトコルずしおGDB RSPにKotlinが遞択されたした。


開発は2幎匱前から行われおおり、積極的に進行䞭です。 この間、MIPS、x86、V850ES、ARM、PowerPCプロセッサコアが実装されたした。


プロゞェクトは成長しおおり、䞀般の人々に玹介する時が来たした。 プロゞェクトの詳现な説明は埌で行いたすが、ここではKopycatの䜿甚に焊点を圓おたす。


最も短気な人のために、゚ミュレヌタのプロモヌション版はここからダりンロヌドできたす 。


゚ミュレヌタヌのRhino


以前のSMARTRHINO-2018䌚議で、リバヌス゚ンゞニアリングスキルのトレヌニング甚にテストデバむス「Rhinoceros」が䜜成されたこずを思い出しおください。 静的ファヌムりェア分析のプロセスに぀いおは、 この蚘事で説明したした。


では、「スピヌカヌ」を远加しお、゚ミュレヌタヌでファヌムりェアを実行しおみたしょう。


必芁なもの
1Java 1.8
2Pythonおよび゚ミュレヌタヌ内でPythonを䜿甚するためのJepモゞュヌル。 Windows甹JepモゞュヌルのWHLアセンブリはここからダりンロヌドできたす 。


Windowsの堎合
1 com0com
2 PuTTY


Linuxの堎合
1socat


Eclipse、IDA Pro、radare2をGDBクラむアントずしお䜿甚できたす。


どのように機胜したすか


゚ミュレヌタでファヌムりェアを実行するには、実際のデバむスに類䌌した仮想デバむスを「アセンブル」する必芁がありたす。


実際のデバむス「rhino」はブロック図で衚瀺できたす。


実デバむス回路

゚ミュレヌタヌはモゞュヌル構造になっおおり、最終的な仮想デバむスはJSONファむルに蚘述できたす。


105行のJSON
{ "top": true, // Plugin name should be the same as file name (or full path from library start) "plugin": "rhino", // Directory where plugin places "library": "user", // Plugin parameters (constructor parameters if jar-plugin version) "params": [ { "name": "tty_dbg", "type": "String"}, { "name": "tty_bt", "type": "String"}, { "name": "firmware", "type": "String", "default": "NUL"} ], // Plugin outer ports "ports": [ ], // Plugin internal buses "buses": [ { "name": "mem", "size": "BUS30" }, { "name": "nand", "size": "4" }, { "name": "gpio", "size": "BUS32" } ], // Plugin internal components "modules": [ { "name": "u1_stm32", "plugin": "STM32F042", "library": "mcu", "params": { "firmware:String": "params.firmware" } }, { "name": "usart_debug", "plugin": "UartSerialTerminal", "library": "terminals", "params": { "tty": "params.tty_dbg" } }, { "name": "term_bt", "plugin": "UartSerialTerminal", "library": "terminals", "params": { "tty": "params.tty_bt" } }, { "name": "bluetooth", "plugin": "BT", "library": "mcu" }, { "name": "led_0", "plugin": "LED", "library": "mcu" }, { "name": "led_1", "plugin": "LED", "library": "mcu" }, { "name": "led_2", "plugin": "LED", "library": "mcu" }, { "name": "led_3", "plugin": "LED", "library": "mcu" }, { "name": "led_4", "plugin": "LED", "library": "mcu" }, { "name": "led_5", "plugin": "LED", "library": "mcu" }, { "name": "led_6", "plugin": "LED", "library": "mcu" }, { "name": "led_7", "plugin": "LED", "library": "mcu" }, { "name": "led_8", "plugin": "LED", "library": "mcu" }, { "name": "led_9", "plugin": "LED", "library": "mcu" }, { "name": "led_10", "plugin": "LED", "library": "mcu" }, { "name": "led_11", "plugin": "LED", "library": "mcu" }, { "name": "led_12", "plugin": "LED", "library": "mcu" }, { "name": "led_13", "plugin": "LED", "library": "mcu" }, { "name": "led_14", "plugin": "LED", "library": "mcu" }, { "name": "led_15", "plugin": "LED", "library": "mcu" } ], // Plugin connection between components "connections": [ [ "u1_stm32.ports.usart1_m", "usart_debug.ports.term_s"], [ "u1_stm32.ports.usart1_s", "usart_debug.ports.term_m"], [ "u1_stm32.ports.usart2_m", "bluetooth.ports.usart_m"], [ "u1_stm32.ports.usart2_s", "bluetooth.ports.usart_s"], [ "bluetooth.ports.bt_s", "term_bt.ports.term_m"], [ "bluetooth.ports.bt_m", "term_bt.ports.term_s"], [ "led_0.ports.pin", "u1_stm32.buses.pin_output_a", "0x00"], [ "led_1.ports.pin", "u1_stm32.buses.pin_output_a", "0x01"], [ "led_2.ports.pin", "u1_stm32.buses.pin_output_a", "0x02"], [ "led_3.ports.pin", "u1_stm32.buses.pin_output_a", "0x03"], [ "led_4.ports.pin", "u1_stm32.buses.pin_output_a", "0x04"], [ "led_5.ports.pin", "u1_stm32.buses.pin_output_a", "0x05"], [ "led_6.ports.pin", "u1_stm32.buses.pin_output_a", "0x06"], [ "led_7.ports.pin", "u1_stm32.buses.pin_output_a", "0x07"], [ "led_8.ports.pin", "u1_stm32.buses.pin_output_a", "0x08"], [ "led_9.ports.pin", "u1_stm32.buses.pin_output_a", "0x09"], [ "led_10.ports.pin", "u1_stm32.buses.pin_output_a", "0x0A"], [ "led_11.ports.pin", "u1_stm32.buses.pin_output_a", "0x0B"], [ "led_12.ports.pin", "u1_stm32.buses.pin_output_a", "0x0C"], [ "led_13.ports.pin", "u1_stm32.buses.pin_output_a", "0x0D"], [ "led_14.ports.pin", "u1_stm32.buses.pin_output_a", "0x0E"], [ "led_15.ports.pin", "u1_stm32.buses.pin_output_a", "0x0F"] ] } 

paramsセクションのファヌムりェアパラメヌタヌに泚意しおください。これは、ファヌムりェアずしお仮想デバむスにダりンロヌドできるファむルの名前です。


仮想デバむスずメむンオペレヌティングシステムずの盞互䜜甚は、次のように衚すこずができたす。


サヌキット゚ミュレヌトデバむス

゚ミュレヌタの珟圚のテストむンスタンスには、メむンOSのCOMポヌトずの察話が含たれたすデバッグUARTおよびBluetoothモゞュヌルのUART。 デバむスが接続されおいる実際のポヌトたたは仮想COMポヌトこのために必芁なのはcom0com / socatだけです 。


珟圚、倖郚から゚ミュレヌタず察話する䞻な方法は2぀ありたす。



仮想COMポヌト


タヌミナルを介しおロヌカルマシン䞊の仮想デバむスのUARTず察話するには、接続された仮想COMポヌトをいく぀か䜜成する必芁がありたす。 この堎合、1぀のポヌトぱミュレヌタヌを䜿甚し、2番目のポヌトはタヌミナルプログラムPuTTYたたは画面を䜿甚したす。


仮想COMポヌト

com0comを䜿甚する


仮想COMポヌトは、com0comキットのセットアップナヌティリティで構成されたすコン゜ヌルバヌゞョンはC\ Program Filesx86\ com0com \setup.exe、たたはGUIバヌゞョンはC\ Program Filesx86\ com0com \ setupg.exe  


仮想COMポヌトを構成する

䜜成されたすべおの仮想ポヌトのバッファヌオヌバヌランを有効にするチェックボックスをオンにしたす。そうしないず、゚ミュレヌタヌがCOMポヌトからの応答を埅機したす。


socatを䜿甚する


UNIXシステムでは、゚ミュレヌタによっおsocatナヌティリティを䜿甚しお仮想COMポヌトが自動的に䜜成されたす。このため、゚ミュレヌタの起動時にポヌト名にsocat:プレフィックスを指定するだけで十分です。


内郚コマンドラむンむンタヌフェむスArgparseたたはPython


Kopycatはコン゜ヌルアプリケヌションであるため、゚ミュレヌタヌはコマンドラむンむンタヌフェむスにオブゞェクトず倉数ず察話するための2぀のオプションを提䟛したすArgparseずPython。


ArgparseはKopycatに組み蟌たれたCLIであり、誰でもい぀でも利甚できたす。


別のCLIはPythonむンタヌプリタヌです。 これを䜿甚するには、Jep Pythonモゞュヌルをむンストヌルし、Pythonで動䜜するように゚ミュレヌタヌを構成する必芁がありたすナヌザヌのメむンシステムにむンストヌルされおいるPythonむンタヌプリタヌが䜿甚されたす。


Python Jepモゞュヌルのむンストヌル


Linuxでは、Jepはpipを介しおむンストヌルできたす。


 pip install jep 

JepをWindowsにむンストヌルするには、最初にWindows SDKず察応するMicrosoft Visual Studioをむンストヌルする必芁がありたす。 タスクを少し簡略化し、珟圚のバヌゞョンのPython for Windows の JEPのWHLアセンブリを䜜成したため、モゞュヌルをファむルからむンストヌルできたす。


 pip install jep-3.8.2-cp27-cp27m-win_amd64.whl 

Jepのむンストヌルを確認するには、コマンドラむンを実行する必芁がありたす。


 python -c "import jep" 

応答ずしお、メッセヌゞを受信する必芁がありたす。


 ImportError: Jep is not supported in standalone Python, it must be embedded in Java. 

システムの゚ミュレヌタバッチファむルWindowsの堎合はkopycat.bat 、Linuxの堎合はkopycat で、远加のパラメヌタヌDjava.library.pathをDEFAULT_JVM_OPTSパラメヌタヌのリストに远加したす。むンストヌル枈みのJepモゞュヌルぞのパスが含たれおいる必芁がありたす。


その結果、Windowsの堎合、次のような行を取埗する必芁がありたす。


 set DEFAULT_JVM_OPTS="-XX:MaxMetaspaceSize=256m" "-XX:+UseParallelGC" "-XX:SurvivorRatio=6" "-XX:-UseGCOverheadLimit" "-Djava.library.path=C:/Python27/Lib/site-packages/jep" 

Kopycatの起動


゚ミュレヌタヌはコン゜ヌルJVMアプリケヌションです。 起動は、オペレヌティングシステムのコマンドラむンスクリプトsh / cmdを介しお実行されたす。


Windowsで実行するコマンド


 bin\kopycat -g 23946 -n rhino -l user -y library -p firmware=firmware\rhino_pass.bin,tty_dbg=COM26,tty_bt=COM28 

socatナヌティリティを䜿甚しおLinuxで実行するコマンド


 ./bin/kopycat -g 23946 -n rhino -l user -y library -p firmware=./firmware/rhino_pass.bin,tty_dbg=socat:./COM26,tty_bt=socat:./COM28 


結果はPython > たたはArgparse >  Argparse > 


 18:07:59 INFO [eFactoryBuilder.create ]: Module top successfully created as top 18:07:59 INFO [ Module.initializeAndRes]: Setup core to top.u1_stm32.cortexm0.arm for top 18:07:59 INFO [ Module.initializeAndRes]: Setup debugger to top.u1_stm32.dbg for top 18:07:59 WARN [ Module.initializeAndRes]: Tracer wasn't found in top... 18:07:59 INFO [ Module.initializeAndRes]: Initializing ports and buses... 18:07:59 WARN [ Module.initializePortsA]: ATTENTION: Some ports has warning use printModulesPortsWarnings to see it... 18:07:59 FINE [ ARMv6CPU.reset ]: Set entry point address to 08006A75 18:07:59 INFO [ Module.initializeAndRes]: Module top is successfully initialized and reset as a top cell! 18:07:59 INFO [ Kopycat.open ]: Starting virtualization of board top[rhino] with arm[ARMv6Core] 18:07:59 INFO [ GDBServer.debuggerModule ]: Set new debugger module top.u1_stm32.dbg for GDB_SERVER(port=23946,alive=true) Python > 

IDA Proずの盞互䜜甚


テストを簡玠化するために、IDAでの分析の゜ヌスファむルずしお、RhinoファヌムりェアをELFファむルずしお䜿甚したす メタ情報はそこに保存されたす。


メタ情報なしでメむンファヌムりェアを䜿甚するこずもできたす。


IDA ProでKopycatを起動した埌、[デバッガ]メニュヌの[デバッガヌの切り替え... ]項目に移動し、[ リモヌトGDBデバッガヌ]を遞択したす。 次に、接続を構成したす デバッガヌメニュヌ-プロセスオプション...


倀を蚭定したす。



GDBサヌバヌぞの接続の構成

デバッグ開始ボタンが利甚可胜になりたしたF9キヌ



クリックしおください-゚ミュレヌタヌのデバッガヌモゞュヌルに接続したす。 IDAはデバッグモヌドになり、远加のりィンドりが䜿甚可胜になりたす。レゞスタに関する情報、スタックに関する情報です。


これで、デバッガヌを操䜜するすべおの暙準機胜を䜿甚できたす。



デバッガに接続するこずは、ファヌムりェアコヌドを開始するこずを意味したせん。 珟圚の実行䜍眮は、アドレス0x08006A74 - Reset_Handler関数の開始䜍眮でなければなりたせん。 䞋のリストを䞋にスクロヌルするず、 メむン関数の呌び出しを確認できたす。 この行アドレス0x08006ABE にカヌ゜ルを眮き、 カヌ゜ル操䜜たで実行 F4キヌを実行できたす 。


画像


次に、F7を抌しおメむン機胜を開始できたす。


プロセスの継続コマンドF9キヌを実行するず、「お埅ちください」りィンドりが衚瀺され、 䞀時停止ボタンが1぀衚瀺されたす。



Suspendを抌すず、ファヌムりェアコヌドの実行が䞭断され、䞭断されたコヌドの同じアドレスから続行できたす。


コヌドの実行を続行するず、仮想COMポヌトに接続された端末で次の行が衚瀺されたす。


画像


画像


文字列「state bypass」の存圚は、仮想BluetoothモゞュヌルがナヌザヌのCOMポヌトからデヌタを受信するモヌドに切り替わったこずを瀺したす。


Bluetoothタヌミナル図-COM29では、Rhinoプロトコルに埓っおコマンドを入力できたす。 たずえば、文字列「mur-mur」は、Bluetooth端末の「MEOW」コマンドに戻りたす。




完党に゚ミュレヌトしない


゚ミュレヌタを構築するずき、デバむスの詳现床/゚ミュレヌションを遞択できたす。 そのため、たずえば、Bluetoothモゞュヌルはさたざたな方法で゚ミュレヌトできたす。



゚ミュレヌタの珟圚のバヌゞョンでは、2番目のアプロヌチが䜿甚されたす。仮想Bluetoothモゞュヌルは構成を実行し、その埌、メむンシステムのCOMポヌトから゚ミュレヌタUARTポヌトにデヌタの「プロキシ」モヌドに切り替えたす。



呚蟺の䞀郚が実装されおいない堎合、コヌドの単玔なむンストルメンテヌションの可胜性を考慮しおください。 たずえば、DMAでのデヌタ転送を制埡するタむマヌが䜜成されおいない堎合怜蚌は0x08006840にあるws2812b_wait関数で実行され0x08006840 、ファヌムりェアは垞に0x200004C4にある0x200004C4がDMAデヌタラむンをリセットするのを0x200004C4たす



これを回避するには、 ビゞヌフラグを蚭定埌すぐに手動でリセットしたす。 IDA Proでは、Python関数を䜜成し、ブレヌクポむントで呌び出すこずができたす。ブレヌクポむント自䜓は、 busyフラグに倀1を曞き蟌んだ埌にコヌドに蚭定されたす。


ブレヌクポむントハンドラヌ


最初に、IDAでPython関数を䜜成したす。 [ファむル ]メニュヌ-スクリプトコマンド...


巊偎のリストに新しいスニペットを远加し、名前たずえば、 BPT を付けお、
右偎のテキストボックスに機胜コヌドを入力したす。


 def skip_dma(): print "Skipping wait ws2812..." value = Byte(0x200004C4) if value == 1: PatchDbgByte(0x200004C4, 0) return False 


その埌、[ 実行 ]をクリックしお、スクリプトりィンドりを閉じたす。


0x0800688Aのコヌドに0x0800688A 、ブレヌクポむントF2キヌを蚭定し、線集 ブレヌクポむントの線集...コンテキストメニュヌし、スクリプトタむプの蚭定を忘れないでください0x0800688A 




busyフラグの珟圚の倀が1の堎合、 skip_dma関数はスクリプト行で実行する必芁がありたす。



ファヌムりェアを実行する堎合、ブレヌクポむントハンドラヌコヌドは、IDAの出力りィンドりのSkipping wait ws2812...行に衚瀺されSkipping wait ws2812... これで、ファヌムりェアはビゞヌフラグのリセットを埅たなくなりたす。


゚ミュレヌタヌの盞互䜜甚


゚ミュレヌションのための゚ミュレヌションは、喜びず喜びをもたらすこずはほずんどありたせん。 ゚ミュレヌタが、研究者がメモリ内のデヌタを確認したり、フロヌの盞互䜜甚を確立したりするのに圹立぀堎合は、はるかに興味深いです。


RTOSタスクの盞互䜜甚を動的に確立する方法を瀺したす。 たず、実行䞭のコヌドの実行を䞀時停止したす。 「LED」コマンド凊理ブランチアドレス0x080057B8 でbluetooth_task_entry関数に切り替えるず、最初に䜜成されたものを確認でき、メッセヌゞがledControlQueueHandleシステムキュヌに送信されたす。


画像


0x20000624にあるledControlQueueHandle倉数にアクセスするようにブレヌクポむントを蚭定し、コヌドの実行を続行する必芁がありたす。



その結果、 osMailAlloc関数を呌び出す前にアドレス0x080057CA停止し、 osMailPut関数を呌び出す前にアドレス0x080057CA停止し、次にleds_task_entry関数LEDタスクに属するアドレス0x08005BD4  osMailGet関数を呌び出す前で停止したす。タスクの切り替えが発生し、コントロヌルがLEDタスクを受信したした。


画像


このような簡単な方法で、RTOSタスクが盞互にやり取りする方法を確立できたす。


もちろん、実際には、タスクの盞互䜜甚はより耇雑になる可胜性がありたすが、゚ミュレヌタを䜿甚しおこの盞互䜜甚を远跡するこずはそれほど難しくありたせん。


ここでは、゚ミュレヌタヌの起動ずIDA Proずの察話の短いビデオを芋るこずができたす。


Radare2で起動


Radare2などの汎甚ツヌルは無芖できたせん。


r2を䜿甚しお゚ミュレヌタに接続するには、コマンドは次のようになりたす。


 radare2 -A -a arm -b 16 -d gdb://localhost:23946 rhino_fw42k6.elf 

開始 dc および実行の䞀時停止Ctrl + Cが利甚可胜になりたした。


残念ながら、珟圚r2では、ハヌドりェアgdbサヌバヌずメモリマヌクアップで䜜業するずきに問題がありたす。これにより、ブレヌクポむントずステップ dsコマンドが機胜したせん。 これが近い将来修正されるこずを願っおいたす。


Eclipseで起動する


゚ミュレヌタを䜿甚するためのオプションの1぀は、開発䞭のデバむスのファヌムりェアのデバッグです。 明確にするために、Rhinoファヌムりェアも䜿甚したす。 ここからファヌムりェア゜ヌスをダりンロヌドできたす。


STM32スむヌト甚のSystem Workbenchの EclipseをIDEずしお䜿甚したす。


Eclipseで盎接アセンブルされたファヌムりェアを゚ミュレヌタヌにロヌドするには、 firmware=null起動コマンドにfirmware=nullパラメヌタヌを远加する必芁がありfirmware=null 。


 bin\kopycat -g 23946 -n rhino -l user -y library -p firmware=null,tty_dbg=COM26,tty_bt=COM28 

デバッグ構成


Eclipseで、[ Run-Debug Configurations ... ]メニュヌを遞択したす。開いたりィンドりの[ GDB Hardware Debugging]セクションで、新しい構成を远加し、[Main]タブでデバッグする珟圚のプロゞェクトずアプリケヌションを指定する必芁がありたす。



[デバッガ]タブで、GDBコマンドを指定する必芁がありたす。
${openstm32_compiler_path}\arm-none-eabi-gdb


たた、GDBサヌバヌに接続するためのパラメヌタヌホストずポヌトも入力したす。



[スタヌトアップ]タブで次のパラメヌタヌを指定する必芁がありたす。



Eclipseからファヌムりェアファむルをダりンロヌドしない堎合は、 Load imageおよびRun commandsパラメヌタヌを指定する必芁がないこずに泚意しおください 。



[デバッグ]をクリックするず、デバッグモヌドで䜜業できたす。



ご泚意 Eclipseには、うヌん...いく぀かの機胜がありたす...そしおあなたはそれらず䞀緒に暮らさなければなりたせん。 たずえば、デバッガヌの起動時に「No source available for」0x0「」ずいうメッセヌゞが衚瀺された堎合は、StepコマンドF5を実行したす



結論の代わりに


ネむティブコヌドの゚ミュレヌションは非垞に興味深いものです。 デバむス開発者にずっお、実際のデバむスなしでファヌムりェアをデバッグするこずが可胜になりたす。 研究者向け-動的コヌド分析を実行する機胜。これは、デバむスを䜿甚しおも垞に可胜ずは限りたせん。


䟿利で適床にシンプルで、蚭定ず起動に倚くの時間ず劎力をかけなかったツヌルを専門家に提䟛したいず考えおいたす。


ハヌドりェア゚ミュレヌタを䜿甚した経隓に぀いおのコメントを曞いおください。 私たちはあなたを議論に招埅し、質問に喜んでお答えしたす。



Source: https://habr.com/ru/post/J445798/


All Articles