แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

เป็นส่วนหนึ่งของการประชุม 0x0A DC7831 เดฟ คอน นิจนี นอฟโกรอด เมื่อวันที่ 16 กุมภาพันธ์ เราได้นำเสนอรายงานเกี่ยวกับหลักการพื้นฐานของการจำลองรหัสไบนารี่และการพัฒนาของเราเอง - โปรแกรมจำลองแพลตฟอร์มฮาร์ดแวร์ เลียนแบบ.

ในบทความนี้ เราจะอธิบายวิธีเรียกใช้เฟิร์มแวร์ของอุปกรณ์ในโปรแกรมจำลอง สาธิตการโต้ตอบกับดีบักเกอร์ และทำการวิเคราะห์แบบไดนามิกเล็กน้อยของเฟิร์มแวร์

ประวัติศาสตร์

กาลครั้งหนึ่งนานมาแล้วในกาแล็กซีอันไกลโพ้น

เมื่อสองสามปีก่อนในห้องปฏิบัติการของเรา มีความจำเป็นต้องตรวจสอบเฟิร์มแวร์ของอุปกรณ์ เฟิร์มแวร์ถูกบีบอัดและแตกไฟล์ด้วยโปรแกรมโหลดบูต เขาทำสิ่งนี้ด้วยวิธีที่ซับซ้อนมาก โดยย้ายข้อมูลในหน่วยความจำหลายครั้ง และเฟิร์มแวร์เองก็โต้ตอบกับอุปกรณ์ต่อพ่วงอย่างแข็งขัน และทั้งหมดนี้อยู่บนคอร์ MIPS

ด้วยเหตุผลวัตถุประสงค์ โปรแกรมจำลองที่มีอยู่ไม่เหมาะกับเรา แต่เรายังคงต้องการเรียกใช้โค้ด จากนั้นเราตัดสินใจสร้างโปรแกรมจำลองของเราเอง ซึ่งจะทำขั้นต่ำสุดและช่วยให้เราแกะเฟิร์มแวร์หลักได้ เราลองแล้วได้ผล เราคิดว่าจะเกิดอะไรขึ้นถ้าเราเพิ่มอุปกรณ์ต่อพ่วงเพื่อใช้เฟิร์มแวร์หลักด้วย มันไม่ได้เจ็บมากนัก - และมันก็ได้ผลด้วย เราคิดอีกครั้งและตัดสินใจสร้างโปรแกรมจำลองที่ครบครัน

ผลลัพธ์ที่ได้คือโปรแกรมจำลองระบบคอมพิวเตอร์ เลียนแบบ.

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat
ทำไมต้อง Kopycat?

มีการเล่นคำด้วย

  1. เลียนแบบ (อังกฤษ คำนาม [ˈkɒpɪkæt]) - ผู้ลอกเลียนแบบ ผู้ลอกเลียนแบบ
  2. แมว (อังกฤษ คำนาม [ˈkæt]) - แมว แมว - สัตว์ตัวโปรดของหนึ่งในผู้สร้างโครงการ
  3. ตัวอักษร “K” มาจากภาษาโปรแกรม Kotlin

เลียนแบบ

เมื่อสร้างโปรแกรมจำลอง มีการกำหนดเป้าหมายที่เฉพาะเจาะจงมาก:

  • ความสามารถในการสร้างอุปกรณ์ต่อพ่วงโมดูลคอร์โปรเซสเซอร์ใหม่ได้อย่างรวดเร็ว
  • ความสามารถในการประกอบอุปกรณ์เสมือนจากโมดูลต่างๆ
  • ความสามารถในการโหลดข้อมูลไบนารี (เฟิร์มแวร์) ลงในหน่วยความจำของอุปกรณ์เสมือน
  • ความสามารถในการทำงานกับสแน็ปช็อต (สแนปชอตของสถานะระบบ)
  • ความสามารถในการโต้ตอบกับโปรแกรมจำลองผ่านดีบักเกอร์ในตัว
  • ภาษาสมัยใหม่ที่ดีสำหรับการพัฒนา

ด้วยเหตุนี้ Kotlin จึงได้รับเลือกให้นำไปใช้งาน ซึ่งเป็นสถาปัตยกรรมบัส (นี่คือเวลาที่โมดูลสื่อสารกันผ่านบัสข้อมูลเสมือน) JSON เป็นรูปแบบคำอธิบายอุปกรณ์ และ GDB RSP เป็นโปรโตคอลสำหรับการโต้ตอบกับดีบักเกอร์

การพัฒนาดำเนินไปเป็นเวลากว่าสองปีเล็กน้อยและยังคงดำเนินไปอย่างต่อเนื่อง ในช่วงเวลานี้ แกนประมวลผล MIPS, x86, V850ES, ARM และ PowerPC ได้ถูกนำมาใช้

โครงการนี้กำลังเติบโต และถึงเวลาที่จะนำเสนอต่อสาธารณชนในวงกว้างแล้ว เราจะอธิบายรายละเอียดของโครงการในภายหลัง แต่สำหรับตอนนี้ เราจะเน้นไปที่การใช้ Kopycat

สำหรับผู้ที่ใจร้อนที่สุด คุณสามารถดาวน์โหลดโปรแกรมจำลองเวอร์ชันส่งเสริมการขายได้จาก ลิงค์.

แรดในโปรแกรมจำลอง

ให้เราระลึกว่าก่อนหน้านี้สำหรับการประชุม SMARTRHINO-2018 มีการสร้างอุปกรณ์ทดสอบ "Rhinoceros" เพื่อสอนทักษะวิศวกรรมย้อนกลับ กระบวนการวิเคราะห์เฟิร์มแวร์แบบคงที่อธิบายไว้ใน บทความนี้.

ตอนนี้เรามาลองเพิ่ม "ลำโพง" และเรียกใช้เฟิร์มแวร์ในโปรแกรมจำลอง

เราจำเป็นต้องใช้:
1) จาวา 1.8
2) Python และโมดูล Jep เพื่อใช้ Python ภายในโปรแกรมจำลอง คุณสามารถสร้างโมดูล WHL Jep สำหรับ Windows ได้ ดาวน์โหลดได้ที่นี่.

สำหรับ Windows:
1) คอมทูคอม
2) ฉาบ

สำหรับลินุกซ์:
1) โซกัต

คุณสามารถใช้ Eclipse, IDA Pro หรือ Radae2 เป็นไคลเอ็นต์ GDB ได้

มันทำงานอย่างไร

เพื่อที่จะใช้งานเฟิร์มแวร์ในเครื่องจำลอง จำเป็นต้อง "ประกอบ" อุปกรณ์เสมือนซึ่งเป็นอะนาล็อกของอุปกรณ์จริง

อุปกรณ์จริง (“แรด”) สามารถแสดงได้ในแผนภาพบล็อก:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

โปรแกรมจำลองมีโครงสร้างแบบโมดูลาร์และสามารถอธิบายอุปกรณ์เสมือนขั้นสุดท้ายได้ในไฟล์ JSON

JSON 105 บรรทัด

{
  "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 คือชื่อของไฟล์ที่สามารถโหลดลงในอุปกรณ์เสมือนเป็นเฟิร์มแวร์ได้

อุปกรณ์เสมือนและการโต้ตอบกับระบบปฏิบัติการหลักสามารถแสดงได้ด้วยแผนภาพต่อไปนี้:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

อินสแตนซ์การทดสอบปัจจุบันของโปรแกรมจำลองเกี่ยวข้องกับการโต้ตอบกับพอร์ต COM ของระบบปฏิบัติการหลัก (ดีบัก UART และ UART สำหรับโมดูล Bluetooth) สิ่งเหล่านี้อาจเป็นพอร์ตจริงที่อุปกรณ์เชื่อมต่ออยู่หรือพอร์ต COM เสมือน (สำหรับสิ่งนี้คุณเพียงแค่ต้องมี com0com/โซกัต).

ขณะนี้มีสองวิธีหลักในการโต้ตอบกับโปรแกรมจำลองจากภายนอก:

  • โปรโตคอล GDB RSP (ดังนั้นเครื่องมือที่รองรับโปรโตคอลนี้คือ Eclipse / IDA / Radae2)
  • บรรทัดคำสั่งโปรแกรมจำลองภายใน (Argparse หรือ Python)

พอร์ต COM เสมือน

ในการโต้ตอบกับ UART ของอุปกรณ์เสมือนบนเครื่องท้องถิ่นผ่านเทอร์มินัล คุณต้องสร้างพอร์ต COM เสมือนที่เกี่ยวข้องคู่หนึ่ง ในกรณีของเรา อีมูเลเตอร์ใช้พอร์ตหนึ่งพอร์ต และพอร์ตที่สองถูกใช้โดยโปรแกรมเทอร์มินัล (PuTTY หรือหน้าจอ):

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

การใช้งาน com0com

พอร์ต COM เสมือนได้รับการกำหนดค่าโดยใช้ยูทิลิตี้การตั้งค่าจากชุด com0com (เวอร์ชันคอนโซล - C: ไฟล์โปรแกรม (x86) com0comsetupс.exe, หรือเวอร์ชัน GUI - C: ไฟล์โปรแกรม (x86) com0comsetupg.exe):

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

ทำเครื่องหมายในช่อง เปิดใช้งานการโอเวอร์รันบัฟเฟอร์ สำหรับพอร์ตเสมือนที่สร้างขึ้นทั้งหมด มิฉะนั้นโปรแกรมจำลองจะรอการตอบสนองจากพอร์ต COM

ใช้โซกัต

บนระบบ UNIX พอร์ต COM เสมือนจะถูกสร้างขึ้นโดยอัตโนมัติโดยโปรแกรมจำลองโดยใช้ยูทิลิตี้ socat ในการดำเนินการนี้ เพียงระบุคำนำหน้าในชื่อพอร์ตเมื่อเริ่มโปรแกรมจำลอง socat:.

อินเทอร์เฟซบรรทัดคำสั่งภายใน (Argparse หรือ Python)

เนื่องจาก Kopycat เป็นแอปพลิเคชั่นคอนโซล โปรแกรมจำลองจึงมีตัวเลือกอินเทอร์เฟซบรรทัดคำสั่งสองตัวเลือกสำหรับการโต้ตอบกับอ็อบเจ็กต์และตัวแปร: Argparse และ Python

Argparse เป็น CLI ที่สร้างไว้ใน Kopycat และทุกคนสามารถใช้ได้เสมอ

CLI ทางเลือกอื่นคือล่าม Python หากต้องการใช้งาน คุณต้องติดตั้งโมดูล Jep Python และกำหนดค่าโปรแกรมจำลองให้ทำงานกับ Python (จะใช้ล่าม Python ที่ติดตั้งบนระบบหลักของผู้ใช้)

การติดตั้งโมดูล Python Jep

ภายใต้ Linux Jep สามารถติดตั้งผ่าน pip:

pip install jep

หากต้องการติดตั้ง Jep บน Windows คุณต้องติดตั้ง Windows SDK และ Microsoft Visual Studio ที่เกี่ยวข้องก่อน เราได้ทำให้มันง่ายขึ้นเล็กน้อยสำหรับคุณและ WHL สร้าง JEP สำหรับ Python สำหรับ Windows เวอร์ชันปัจจุบัน ดังนั้นสามารถติดตั้งโมดูลจากไฟล์ได้:

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.

ในไฟล์แบตช์โปรแกรมจำลองสำหรับระบบของคุณ (copycat.bat - สำหรับวินโดวส์ เลียนแบบ - สำหรับ Linux) ไปยังรายการพารามิเตอร์ DEFAULT_JVM_OPTS เพิ่มพารามิเตอร์เพิ่มเติม Djava.library.path — จะต้องมีเส้นทางไปยังโมดูล 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:

binkopycat -g 23946 -n rhino -l user -y library -p firmware=firmwarerhino_pass.bin,tty_dbg=COM26,tty_bt=COM28

คำสั่งให้ทำงานภายใต้ Linux โดยใช้ยูทิลิตี้ socat:

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

  • -g 23646 — พอร์ต TCP ที่จะเปิดให้เข้าถึงเซิร์ฟเวอร์ GDB
  • -n rhino — ชื่อของโมดูลระบบหลัก (อุปกรณ์ที่ประกอบ)
  • -l user — ชื่อของไลบรารีเพื่อค้นหาโมดูลหลัก
  • -y library — เส้นทางเพื่อค้นหาโมดูลที่รวมอยู่ในอุปกรณ์
  • firmwarerhino_pass.bin — เส้นทางไปยังไฟล์เฟิร์มแวร์
  • COM26 และ COM28 เป็นพอร์ต COM เสมือน

ด้วยเหตุนี้ ข้อความแจ้งจะปรากฏขึ้น Python > (หรือ 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

เพื่อให้การทดสอบง่ายขึ้น เราใช้เฟิร์มแวร์ Rhino เป็นไฟล์ต้นฉบับสำหรับการวิเคราะห์ใน IDA ในรูปแบบ ไฟล์เอลฟ์ (ข้อมูลเมตาจะถูกเก็บไว้ที่นั่น)

คุณยังสามารถใช้เฟิร์มแวร์หลักโดยไม่มีข้อมูลเมตาได้

หลังจากเปิดตัว Kopycat ใน IDA Pro ในเมนู Debugger ให้ไปที่รายการ “สลับดีบักเกอร์..." และเลือก "ดีบักเกอร์ GDB ระยะไกล". จากนั้นตั้งค่าการเชื่อมต่อ: เมนู ดีบักเกอร์ - ตัวเลือกกระบวนการ...

ตั้งค่า:

  • แอปพลิเคชัน - ค่าใดก็ได้
  • ชื่อโฮสต์: 127.0.0.1 (หรือที่อยู่ IP ของเครื่องระยะไกลที่ Kopycat ทำงานอยู่)
  • พอร์ต: ฮิต

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

ตอนนี้ปุ่มแก้ไขข้อบกพร่องพร้อมใช้งานแล้ว (ปุ่ม F9):

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

คลิกเพื่อเชื่อมต่อกับโมดูลดีบักเกอร์ในโปรแกรมจำลอง IDA เข้าสู่โหมดการดีบัก หน้าต่างเพิ่มเติมจะพร้อมใช้งาน: ข้อมูลเกี่ยวกับรีจิสเตอร์เกี่ยวกับสแต็ก

ตอนนี้เราสามารถใช้คุณสมบัติมาตรฐานทั้งหมดของดีบักเกอร์ได้แล้ว:

  • การดำเนินการตามคำแนะนำทีละขั้นตอน (ก้าวเข้ามา и ก้าวข้าม — ปุ่ม F7 และ F8 ตามลำดับ)
  • การเริ่มและหยุดการดำเนินการชั่วคราว
  • การสร้างเบรกพอยต์สำหรับทั้งโค้ดและข้อมูล (คีย์ F2)

การเชื่อมต่อกับดีบักเกอร์ไม่ได้หมายถึงการรันโค้ดเฟิร์มแวร์ ตำแหน่งการดำเนินการปัจจุบันจะต้องเป็นที่อยู่ 0x08006A74 — จุดเริ่มต้นของฟังก์ชั่น รีเซ็ต_ตัวจัดการ. หากคุณเลื่อนรายการลง คุณจะเห็นการเรียกใช้ฟังก์ชัน หลัก. คุณสามารถวางเคอร์เซอร์บนบรรทัดนี้ (address 0x08006ABE) และดำเนินการ วิ่งจนกระทั่งเคอร์เซอร์ (ปุ่ม F4)

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

จากนั้นคุณสามารถกด F7 เพื่อเข้าสู่ฟังก์ชันได้ หลัก.

หากคุณรันคำสั่ง ดำเนินการต่อไป (ปุ่ม F9) จากนั้นหน้าต่าง “โปรดรอสักครู่” จะปรากฏขึ้นพร้อมกับปุ่มเดียว เลื่อน:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

เมื่อคุณกด เลื่อน การเรียกใช้โค้ดเฟิร์มแวร์ถูกระงับและสามารถดำเนินการต่อได้จากที่อยู่เดียวกันในโค้ดที่ถูกขัดจังหวะ

หากคุณยังคงรันโค้ดต่อไป คุณจะเห็นบรรทัดต่อไปนี้ในเทอร์มินัลที่เชื่อมต่อกับพอร์ต COM เสมือน:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

การมีอยู่ของบรรทัด "บายพาสสถานะ" บ่งชี้ว่าโมดูล Bluetooth เสมือนได้เปลี่ยนไปใช้โหมดการรับข้อมูลจากพอร์ต COM ของผู้ใช้

ขณะนี้อยู่ในเทอร์มินัล Bluetooth (COM29 ในภาพ) คุณสามารถป้อนคำสั่งตามโปรโตคอล Rhino ได้ ตัวอย่างเช่น คำสั่ง “MEOW” จะส่งคืนสตริง “mur-mur” ไปยังเทอร์มินัล Bluetooth:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

เลียนแบบฉันไม่สมบูรณ์

เมื่อสร้างโปรแกรมจำลอง คุณสามารถเลือกระดับรายละเอียด/การจำลองของอุปกรณ์เฉพาะได้ ตัวอย่างเช่น โมดูล Bluetooth สามารถจำลองได้หลายวิธี:

  • อุปกรณ์ได้รับการจำลองอย่างสมบูรณ์พร้อมชุดคำสั่งครบชุด
  • จำลองคำสั่ง AT และรับสตรีมข้อมูลจากพอร์ต COM ของระบบหลัก
  • อุปกรณ์เสมือนให้การเปลี่ยนเส้นทางข้อมูลโดยสมบูรณ์ไปยังอุปกรณ์จริง
  • เป็น stub ธรรมดาที่ส่งคืน "OK" เสมอ

โปรแกรมจำลองเวอร์ชันปัจจุบันใช้วิธีการที่สอง - โมดูล Bluetooth เสมือนทำการกำหนดค่าหลังจากนั้นจะเปลี่ยนไปที่โหมดของข้อมูล "พร็อกซี" จากพอร์ต COM ของระบบหลักไปยังพอร์ต UART ของโปรแกรมจำลอง

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

ลองพิจารณาความเป็นไปได้ของเครื่องมือวัดอย่างง่าย ๆ ของโค้ดในกรณีที่ไม่ได้ใช้งานส่วนต่อพ่วงบางส่วน ตัวอย่างเช่น หากไม่ได้สร้างตัวจับเวลาที่รับผิดชอบในการควบคุมการถ่ายโอนข้อมูลไปยัง DMA (การตรวจสอบจะดำเนินการในฟังก์ชัน ws2812b_รอตั้งอยู่ที่ 0x08006840) จากนั้นเฟิร์มแวร์จะรอให้รีเซ็ตแฟล็กเสมอ ไม่ว่างตั้งอยู่ที่ 0x200004C4ซึ่งแสดงการครอบครองของสายข้อมูล DMA:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

เราสามารถแก้ไขสถานการณ์นี้ได้ด้วยการรีเซ็ตแฟล็กด้วยตนเอง ไม่ว่าง ทันทีหลังจากติดตั้ง ใน IDA Pro คุณสามารถสร้างฟังก์ชัน Python และเรียกใช้ฟังก์ชันดังกล่าวในเบรกพอยต์ และใส่เบรกพอยต์เองในโค้ดหลังจากเขียนค่า 1 ลงในแฟล็ก ไม่ว่าง.

ตัวจัดการเบรกพอยต์

ขั้นแรก เรามาสร้างฟังก์ชัน Python ใน IDA กันก่อน เมนู ไฟล์ - คำสั่งสคริปต์...

เพิ่มตัวอย่างข้อมูลใหม่ในรายการทางด้านซ้าย ตั้งชื่อ (เช่น BPT),
ในช่องข้อความทางด้านขวา ให้ป้อนโค้ดฟังก์ชัน:

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

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

หลังจากนั้นเรากด วิ่ง และปิดหน้าต่างสคริปต์

ทีนี้มาดูโค้ดกันที่ 0x0800688A, ตั้งค่าเบรกพอยต์ (ปุ่ม F2), แก้ไข (เมนูบริบท แก้ไขเบรกพอยท์...) อย่าลืมตั้งค่าประเภทสคริปต์เป็น Python:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat
แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

หากค่าสถานะปัจจุบัน ไม่ว่าง เท่ากับ 1 จากนั้นคุณควรรันฟังก์ชัน ข้าม_dma ในบรรทัดสคริปต์:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

หากคุณเรียกใช้เฟิร์มแวร์เพื่อดำเนินการ คุณจะเห็นการทริกเกอร์โค้ดตัวจัดการเบรกพอยต์ในหน้าต่าง IDA เอาท์พุต ตามบรรทัด Skipping wait ws2812.... ตอนนี้เฟิร์มแวร์จะไม่รอให้รีเซ็ตแฟล็ก ไม่ว่าง.

การโต้ตอบกับเครื่องจำลอง

การจำลองเพื่อประโยชน์ในการจำลองไม่น่าจะทำให้เกิดความปีติยินดี สิ่งที่น่าสนใจกว่านั้นคือถ้าโปรแกรมจำลองช่วยให้ผู้วิจัยเห็นข้อมูลในหน่วยความจำหรือสร้างการโต้ตอบของเธรด

เราจะแสดงวิธีสร้างปฏิสัมพันธ์ระหว่างงาน RTOS แบบไดนามิก คุณควรหยุดการเรียกใช้โค้ดชั่วคราวก่อนหากโค้ดกำลังทำงานอยู่ ถ้าไปร่วมงาน bluetooth_task_entry ไปยังสาขาการประมวลผลของคำสั่ง “LED” (address 0x080057B8) จากนั้นคุณจะเห็นสิ่งที่สร้างขึ้นก่อนแล้วจึงส่งไปยังคิวของระบบ ledControlQueueHandle ข้อความบางอย่าง

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

คุณควรตั้งค่าเบรกพอยต์เพื่อเข้าถึงตัวแปร ledControlQueueHandleตั้งอยู่ที่ 0x20000624 และดำเนินการโค้ดต่อไป:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

ด้วยเหตุนี้การหยุดจะเกิดขึ้นที่ที่อยู่ก่อน 0x080057CA ก่อนที่จะเรียกใช้ฟังก์ชัน osMailAllocจากนั้นตามที่อยู่ 0x08005806 ก่อนที่จะเรียกใช้ฟังก์ชัน osMailPutหลังจากนั้นไม่นาน - ไปยังที่อยู่ 0x08005BD4 (ก่อนที่จะเรียกใช้ฟังก์ชัน osMailGet) ซึ่งอยู่ในฟังก์ชัน leds_task_entry (งาน LED) นั่นคืองานถูกสลับ และตอนนี้งาน LED ได้รับการควบคุมแล้ว

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

ด้วยวิธีง่ายๆ นี้ คุณสามารถสร้างวิธีที่งาน 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

หนึ่งในตัวเลือกในการใช้โปรแกรมจำลองคือการดีบักเฟิร์มแวร์ของอุปกรณ์ที่กำลังพัฒนา เพื่อความชัดเจน เราจะใช้เฟิร์มแวร์ Rhino ด้วย คุณสามารถดาวน์โหลดแหล่งเฟิร์มแวร์ได้ ด้วยเหตุนี้.

เราจะใช้ Eclipse จากชุดเป็น IDE โต๊ะทำงานระบบสำหรับ STM32.

เพื่อให้โปรแกรมจำลองโหลดเฟิร์มแวร์ที่คอมไพล์โดยตรงใน Eclipse คุณต้องเพิ่มพารามิเตอร์ firmware=null ไปที่คำสั่งเปิดตัวโปรแกรมจำลอง:

binkopycat -g 23946 -n rhino -l user -y modules -p firmware=null,tty_dbg=COM26,tty_bt=COM28

การตั้งค่าการกำหนดค่าการแก้ไขข้อบกพร่อง

ใน Eclipse ให้เลือกเมนู เรียกใช้ - แก้ไขข้อบกพร่องการกำหนดค่า... ในหน้าต่างที่เปิดขึ้นในส่วน การดีบักฮาร์ดแวร์ GDB คุณต้องเพิ่มการกำหนดค่าใหม่จากนั้นในแท็บ "หลัก" ระบุโครงการปัจจุบันและแอปพลิเคชันสำหรับการดีบัก:

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

บนแท็บ "ดีบักเกอร์" คุณต้องระบุคำสั่ง GDB:
${openstm32_compiler_path}arm-none-eabi-gdb

และป้อนพารามิเตอร์สำหรับการเชื่อมต่อกับเซิร์ฟเวอร์ GDB (โฮสต์และพอร์ต):

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

บนแท็บ "เริ่มต้น" คุณต้องระบุพารามิเตอร์ต่อไปนี้:

  • เปิดใช้งานช่องทำเครื่องหมาย โหลดรูปภาพ (เพื่อให้อิมเมจเฟิร์มแวร์ที่ประกอบถูกโหลดลงในโปรแกรมจำลอง)
  • เปิดใช้งานช่องทำเครื่องหมาย โหลดสัญลักษณ์;
  • เพิ่มคำสั่งเปิดตัว: set $pc = *0x08000004 (ตั้งค่า PC register ให้เป็นค่าจากหน่วยความจำตามที่อยู่ 0x08000004 - ที่อยู่ถูกเก็บไว้ที่นั่น รีเซ็ตตัวจัดการ).

หมายเหตุหากคุณไม่ต้องการดาวน์โหลดไฟล์เฟิร์มแวร์จาก Eclipse ให้เลือกตัวเลือกต่างๆ โหลดรูปภาพ и เรียกใช้คำสั่ง ไม่จำเป็นต้องระบุ

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

หลังจากคลิก Debug คุณสามารถทำงานในโหมดดีบักเกอร์ได้:

  • การดำเนินการโค้ดทีละขั้นตอน
    แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat
  • การโต้ตอบกับเบรกพอยต์
    แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

หมายเหตุ. Eclipse มี อืม... มีนิสัยแปลกๆ บางอย่าง... และคุณต้องอยู่กับมัน ตัวอย่างเช่น หากเมื่อเริ่มดีบักเกอร์ข้อความ "ไม่มีแหล่งที่มาสำหรับ "0x0" ปรากฏขึ้น ให้ดำเนินการคำสั่งขั้นตอน (F5)

แรดในแมว - รันเฟิร์มแวร์ในโปรแกรมจำลอง Kopycat

แทนการสรุป

การเลียนแบบโค้ดเนทีฟเป็นสิ่งที่น่าสนใจมาก นักพัฒนาอุปกรณ์สามารถแก้ไขข้อบกพร่องของเฟิร์มแวร์ได้โดยไม่ต้องใช้อุปกรณ์จริง สำหรับนักวิจัย นี่คือโอกาสในการวิเคราะห์โค้ดแบบไดนามิก ซึ่งไม่สามารถทำได้เสมอไปแม้จะใช้อุปกรณ์ก็ตาม

เราต้องการมอบเครื่องมือที่สะดวก เรียบง่ายปานกลางให้กับผู้เชี่ยวชาญ และไม่ต้องใช้ความพยายามและเวลามากนักในการตั้งค่าและเรียกใช้

เขียนความคิดเห็นเกี่ยวกับประสบการณ์ของคุณโดยใช้โปรแกรมจำลองฮาร์ดแวร์ เราขอเชิญคุณมาพูดคุยและยินดีที่จะตอบคำถาม

เฉพาะผู้ใช้ที่ลงทะเบียนเท่านั้นที่สามารถเข้าร่วมในการสำรวจได้ เข้าสู่ระบบ, โปรด.

คุณใช้โปรแกรมจำลองเพื่ออะไร?

  • ฉันพัฒนา (ดีบัก) เฟิร์มแวร์

  • ฉันกำลังค้นคว้าเฟิร์มแวร์

  • ฉันเปิดตัวเกม (Dendi, Sega, PSP)

  • อย่างอื่น (เขียนในความคิดเห็น)

ผู้ใช้ 7 คนโหวต ผู้ใช้ 2 รายงดออกเสียง

คุณใช้ซอฟต์แวร์ใดเพื่อเลียนแบบโค้ดเนทีฟ

  • QEMU

  • เครื่องยนต์ยูนิคอร์น

  • โพรทูส

  • อย่างอื่น (เขียนในความคิดเห็น)

ผู้ใช้ 6 คนโหวต ผู้ใช้ 2 รายงดออกเสียง

คุณต้องการปรับปรุงอะไรในโปรแกรมจำลองที่คุณใช้อยู่

  • ฉันต้องการความเร็ว

  • ฉันต้องการความง่ายในการติดตั้ง/เปิดใช้งาน

  • ฉันต้องการตัวเลือกเพิ่มเติมสำหรับการโต้ตอบกับโปรแกรมจำลอง (API, hooks)

  • ฉันมีความสุขกับทุกสิ่ง

  • อย่างอื่น (เขียนในความคิดเห็น)

ผู้ใช้ 8 คนโหวต ผู้ใช้ 1 รายงดออกเสียง

ที่มา: will.com

เพิ่มความคิดเห็น