เป็นส่วนหนึ่งของการประชุม 0x0A DC7831
ในบทความนี้ เราจะอธิบายวิธีเรียกใช้เฟิร์มแวร์ของอุปกรณ์ในโปรแกรมจำลอง สาธิตการโต้ตอบกับดีบักเกอร์ และทำการวิเคราะห์แบบไดนามิกเล็กน้อยของเฟิร์มแวร์
ประวัติศาสตร์
กาลครั้งหนึ่งนานมาแล้วในกาแล็กซีอันไกลโพ้น
เมื่อสองสามปีก่อนในห้องปฏิบัติการของเรา มีความจำเป็นต้องตรวจสอบเฟิร์มแวร์ของอุปกรณ์ เฟิร์มแวร์ถูกบีบอัดและแตกไฟล์ด้วยโปรแกรมโหลดบูต เขาทำสิ่งนี้ด้วยวิธีที่ซับซ้อนมาก โดยย้ายข้อมูลในหน่วยความจำหลายครั้ง และเฟิร์มแวร์เองก็โต้ตอบกับอุปกรณ์ต่อพ่วงอย่างแข็งขัน และทั้งหมดนี้อยู่บนคอร์ MIPS
ด้วยเหตุผลวัตถุประสงค์ โปรแกรมจำลองที่มีอยู่ไม่เหมาะกับเรา แต่เรายังคงต้องการเรียกใช้โค้ด จากนั้นเราตัดสินใจสร้างโปรแกรมจำลองของเราเอง ซึ่งจะทำขั้นต่ำสุดและช่วยให้เราแกะเฟิร์มแวร์หลักได้ เราลองแล้วได้ผล เราคิดว่าจะเกิดอะไรขึ้นถ้าเราเพิ่มอุปกรณ์ต่อพ่วงเพื่อใช้เฟิร์มแวร์หลักด้วย มันไม่ได้เจ็บมากนัก - และมันก็ได้ผลด้วย เราคิดอีกครั้งและตัดสินใจสร้างโปรแกรมจำลองที่ครบครัน
ผลลัพธ์ที่ได้คือโปรแกรมจำลองระบบคอมพิวเตอร์
ทำไมต้อง Kopycat?
มีการเล่นคำด้วย
- เลียนแบบ (อังกฤษ คำนาม [ˈkɒpɪkæt]) - ผู้ลอกเลียนแบบ ผู้ลอกเลียนแบบ
- แมว (อังกฤษ คำนาม [ˈkæt]) - แมว แมว - สัตว์ตัวโปรดของหนึ่งในผู้สร้างโครงการ
- ตัวอักษร “K” มาจากภาษาโปรแกรม Kotlin
เลียนแบบ
เมื่อสร้างโปรแกรมจำลอง มีการกำหนดเป้าหมายที่เฉพาะเจาะจงมาก:
- ความสามารถในการสร้างอุปกรณ์ต่อพ่วงโมดูลคอร์โปรเซสเซอร์ใหม่ได้อย่างรวดเร็ว
- ความสามารถในการประกอบอุปกรณ์เสมือนจากโมดูลต่างๆ
- ความสามารถในการโหลดข้อมูลไบนารี (เฟิร์มแวร์) ลงในหน่วยความจำของอุปกรณ์เสมือน
- ความสามารถในการทำงานกับสแน็ปช็อต (สแนปชอตของสถานะระบบ)
- ความสามารถในการโต้ตอบกับโปรแกรมจำลองผ่านดีบักเกอร์ในตัว
- ภาษาสมัยใหม่ที่ดีสำหรับการพัฒนา
ด้วยเหตุนี้ Kotlin จึงได้รับเลือกให้นำไปใช้งาน ซึ่งเป็นสถาปัตยกรรมบัส (นี่คือเวลาที่โมดูลสื่อสารกันผ่านบัสข้อมูลเสมือน) JSON เป็นรูปแบบคำอธิบายอุปกรณ์ และ GDB RSP เป็นโปรโตคอลสำหรับการโต้ตอบกับดีบักเกอร์
การพัฒนาดำเนินไปเป็นเวลากว่าสองปีเล็กน้อยและยังคงดำเนินไปอย่างต่อเนื่อง ในช่วงเวลานี้ แกนประมวลผล MIPS, x86, V850ES, ARM และ PowerPC ได้ถูกนำมาใช้
โครงการนี้กำลังเติบโต และถึงเวลาที่จะนำเสนอต่อสาธารณชนในวงกว้างแล้ว เราจะอธิบายรายละเอียดของโครงการในภายหลัง แต่สำหรับตอนนี้ เราจะเน้นไปที่การใช้ Kopycat
สำหรับผู้ที่ใจร้อนที่สุด คุณสามารถดาวน์โหลดโปรแกรมจำลองเวอร์ชันส่งเสริมการขายได้จาก
แรดในโปรแกรมจำลอง
ให้เราระลึกว่าก่อนหน้านี้สำหรับการประชุม SMARTRHINO-2018 มีการสร้างอุปกรณ์ทดสอบ "Rhinoceros" เพื่อสอนทักษะวิศวกรรมย้อนกลับ กระบวนการวิเคราะห์เฟิร์มแวร์แบบคงที่อธิบายไว้ใน
ตอนนี้เรามาลองเพิ่ม "ลำโพง" และเรียกใช้เฟิร์มแวร์ในโปรแกรมจำลอง
เราจำเป็นต้องใช้:
1) จาวา 1.8
2) Python และโมดูล
สำหรับ Windows:
1)
2)
สำหรับลินุกซ์:
1) โซกัต
คุณสามารถใช้ Eclipse, IDA Pro หรือ Radae2 เป็นไคลเอ็นต์ GDB ได้
มันทำงานอย่างไร
เพื่อที่จะใช้งานเฟิร์มแวร์ในเครื่องจำลอง จำเป็นต้อง "ประกอบ" อุปกรณ์เสมือนซึ่งเป็นอะนาล็อกของอุปกรณ์จริง
อุปกรณ์จริง (“แรด”) สามารถแสดงได้ในแผนภาพบล็อก:
โปรแกรมจำลองมีโครงสร้างแบบโมดูลาร์และสามารถอธิบายอุปกรณ์เสมือนขั้นสุดท้ายได้ในไฟล์ 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 คือชื่อของไฟล์ที่สามารถโหลดลงในอุปกรณ์เสมือนเป็นเฟิร์มแวร์ได้
อุปกรณ์เสมือนและการโต้ตอบกับระบบปฏิบัติการหลักสามารถแสดงได้ด้วยแผนภาพต่อไปนี้:
อินสแตนซ์การทดสอบปัจจุบันของโปรแกรมจำลองเกี่ยวข้องกับการโต้ตอบกับพอร์ต COM ของระบบปฏิบัติการหลัก (ดีบัก UART และ UART สำหรับโมดูล Bluetooth) สิ่งเหล่านี้อาจเป็นพอร์ตจริงที่อุปกรณ์เชื่อมต่ออยู่หรือพอร์ต COM เสมือน (สำหรับสิ่งนี้คุณเพียงแค่ต้องมี com0com/โซกัต).
ขณะนี้มีสองวิธีหลักในการโต้ตอบกับโปรแกรมจำลองจากภายนอก:
- โปรโตคอล GDB RSP (ดังนั้นเครื่องมือที่รองรับโปรโตคอลนี้คือ Eclipse / IDA / Radae2)
- บรรทัดคำสั่งโปรแกรมจำลองภายใน (Argparse หรือ Python)
พอร์ต COM เสมือน
ในการโต้ตอบกับ UART ของอุปกรณ์เสมือนบนเครื่องท้องถิ่นผ่านเทอร์มินัล คุณต้องสร้างพอร์ต COM เสมือนที่เกี่ยวข้องคู่หนึ่ง ในกรณีของเรา อีมูเลเตอร์ใช้พอร์ตหนึ่งพอร์ต และพอร์ตที่สองถูกใช้โดยโปรแกรมเทอร์มินัล (PuTTY หรือหน้าจอ):
การใช้งาน com0com
พอร์ต COM เสมือนได้รับการกำหนดค่าโดยใช้ยูทิลิตี้การตั้งค่าจากชุด com0com (เวอร์ชันคอนโซล - C: ไฟล์โปรแกรม (x86) com0comsetupс.exe, หรือเวอร์ชัน GUI - C: ไฟล์โปรแกรม (x86) com0comsetupg.exe):
ทำเครื่องหมายในช่อง เปิดใช้งานการโอเวอร์รันบัฟเฟอร์ สำหรับพอร์ตเสมือนที่สร้างขึ้นทั้งหมด มิฉะนั้นโปรแกรมจำลองจะรอการตอบสนองจากพอร์ต 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 ที่เกี่ยวข้องก่อน เราได้ทำให้มันง่ายขึ้นเล็กน้อยสำหรับคุณและ
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 ทำงานอยู่)
- พอร์ต: ฮิต
ตอนนี้ปุ่มแก้ไขข้อบกพร่องพร้อมใช้งานแล้ว (ปุ่ม F9):
คลิกเพื่อเชื่อมต่อกับโมดูลดีบักเกอร์ในโปรแกรมจำลอง IDA เข้าสู่โหมดการดีบัก หน้าต่างเพิ่มเติมจะพร้อมใช้งาน: ข้อมูลเกี่ยวกับรีจิสเตอร์เกี่ยวกับสแต็ก
ตอนนี้เราสามารถใช้คุณสมบัติมาตรฐานทั้งหมดของดีบักเกอร์ได้แล้ว:
- การดำเนินการตามคำแนะนำทีละขั้นตอน (ก้าวเข้ามา и ก้าวข้าม — ปุ่ม F7 และ F8 ตามลำดับ)
- การเริ่มและหยุดการดำเนินการชั่วคราว
- การสร้างเบรกพอยต์สำหรับทั้งโค้ดและข้อมูล (คีย์ F2)
การเชื่อมต่อกับดีบักเกอร์ไม่ได้หมายถึงการรันโค้ดเฟิร์มแวร์ ตำแหน่งการดำเนินการปัจจุบันจะต้องเป็นที่อยู่ 0x08006A74
— จุดเริ่มต้นของฟังก์ชั่น รีเซ็ต_ตัวจัดการ. หากคุณเลื่อนรายการลง คุณจะเห็นการเรียกใช้ฟังก์ชัน หลัก. คุณสามารถวางเคอร์เซอร์บนบรรทัดนี้ (address 0x08006ABE
) และดำเนินการ วิ่งจนกระทั่งเคอร์เซอร์ (ปุ่ม F4)
จากนั้นคุณสามารถกด F7 เพื่อเข้าสู่ฟังก์ชันได้ หลัก.
หากคุณรันคำสั่ง ดำเนินการต่อไป (ปุ่ม F9) จากนั้นหน้าต่าง “โปรดรอสักครู่” จะปรากฏขึ้นพร้อมกับปุ่มเดียว เลื่อน:
เมื่อคุณกด เลื่อน การเรียกใช้โค้ดเฟิร์มแวร์ถูกระงับและสามารถดำเนินการต่อได้จากที่อยู่เดียวกันในโค้ดที่ถูกขัดจังหวะ
หากคุณยังคงรันโค้ดต่อไป คุณจะเห็นบรรทัดต่อไปนี้ในเทอร์มินัลที่เชื่อมต่อกับพอร์ต COM เสมือน:
การมีอยู่ของบรรทัด "บายพาสสถานะ" บ่งชี้ว่าโมดูล Bluetooth เสมือนได้เปลี่ยนไปใช้โหมดการรับข้อมูลจากพอร์ต COM ของผู้ใช้
ขณะนี้อยู่ในเทอร์มินัล Bluetooth (COM29 ในภาพ) คุณสามารถป้อนคำสั่งตามโปรโตคอล Rhino ได้ ตัวอย่างเช่น คำสั่ง “MEOW” จะส่งคืนสตริง “mur-mur” ไปยังเทอร์มินัล Bluetooth:
เลียนแบบฉันไม่สมบูรณ์
เมื่อสร้างโปรแกรมจำลอง คุณสามารถเลือกระดับรายละเอียด/การจำลองของอุปกรณ์เฉพาะได้ ตัวอย่างเช่น โมดูล Bluetooth สามารถจำลองได้หลายวิธี:
- อุปกรณ์ได้รับการจำลองอย่างสมบูรณ์พร้อมชุดคำสั่งครบชุด
- จำลองคำสั่ง AT และรับสตรีมข้อมูลจากพอร์ต COM ของระบบหลัก
- อุปกรณ์เสมือนให้การเปลี่ยนเส้นทางข้อมูลโดยสมบูรณ์ไปยังอุปกรณ์จริง
- เป็น stub ธรรมดาที่ส่งคืน "OK" เสมอ
โปรแกรมจำลองเวอร์ชันปัจจุบันใช้วิธีการที่สอง - โมดูล Bluetooth เสมือนทำการกำหนดค่าหลังจากนั้นจะเปลี่ยนไปที่โหมดของข้อมูล "พร็อกซี" จากพอร์ต COM ของระบบหลักไปยังพอร์ต UART ของโปรแกรมจำลอง
ลองพิจารณาความเป็นไปได้ของเครื่องมือวัดอย่างง่าย ๆ ของโค้ดในกรณีที่ไม่ได้ใช้งานส่วนต่อพ่วงบางส่วน ตัวอย่างเช่น หากไม่ได้สร้างตัวจับเวลาที่รับผิดชอบในการควบคุมการถ่ายโอนข้อมูลไปยัง DMA (การตรวจสอบจะดำเนินการในฟังก์ชัน ws2812b_รอตั้งอยู่ที่ 0x08006840
) จากนั้นเฟิร์มแวร์จะรอให้รีเซ็ตแฟล็กเสมอ ไม่ว่างตั้งอยู่ที่ 0x200004C4
ซึ่งแสดงการครอบครองของสายข้อมูล DMA:
เราสามารถแก้ไขสถานการณ์นี้ได้ด้วยการรีเซ็ตแฟล็กด้วยตนเอง ไม่ว่าง ทันทีหลังจากติดตั้ง ใน 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
หลังจากนั้นเรากด วิ่ง และปิดหน้าต่างสคริปต์
ทีนี้มาดูโค้ดกันที่ 0x0800688A
, ตั้งค่าเบรกพอยต์ (ปุ่ม F2), แก้ไข (เมนูบริบท แก้ไขเบรกพอยท์...) อย่าลืมตั้งค่าประเภทสคริปต์เป็น Python:
หากค่าสถานะปัจจุบัน ไม่ว่าง เท่ากับ 1 จากนั้นคุณควรรันฟังก์ชัน ข้าม_dma ในบรรทัดสคริปต์:
หากคุณเรียกใช้เฟิร์มแวร์เพื่อดำเนินการ คุณจะเห็นการทริกเกอร์โค้ดตัวจัดการเบรกพอยต์ในหน้าต่าง IDA เอาท์พุต ตามบรรทัด Skipping wait ws2812...
. ตอนนี้เฟิร์มแวร์จะไม่รอให้รีเซ็ตแฟล็ก ไม่ว่าง.
การโต้ตอบกับเครื่องจำลอง
การจำลองเพื่อประโยชน์ในการจำลองไม่น่าจะทำให้เกิดความปีติยินดี สิ่งที่น่าสนใจกว่านั้นคือถ้าโปรแกรมจำลองช่วยให้ผู้วิจัยเห็นข้อมูลในหน่วยความจำหรือสร้างการโต้ตอบของเธรด
เราจะแสดงวิธีสร้างปฏิสัมพันธ์ระหว่างงาน RTOS แบบไดนามิก คุณควรหยุดการเรียกใช้โค้ดชั่วคราวก่อนหากโค้ดกำลังทำงานอยู่ ถ้าไปร่วมงาน bluetooth_task_entry ไปยังสาขาการประมวลผลของคำสั่ง “LED” (address 0x080057B8
) จากนั้นคุณจะเห็นสิ่งที่สร้างขึ้นก่อนแล้วจึงส่งไปยังคิวของระบบ ledControlQueueHandle ข้อความบางอย่าง
คุณควรตั้งค่าเบรกพอยต์เพื่อเข้าถึงตัวแปร ledControlQueueHandleตั้งอยู่ที่ 0x20000624
และดำเนินการโค้ดต่อไป:
ด้วยเหตุนี้การหยุดจะเกิดขึ้นที่ที่อยู่ก่อน 0x080057CA
ก่อนที่จะเรียกใช้ฟังก์ชัน osMailAllocจากนั้นตามที่อยู่ 0x08005806
ก่อนที่จะเรียกใช้ฟังก์ชัน osMailPutหลังจากนั้นไม่นาน - ไปยังที่อยู่ 0x08005BD4
(ก่อนที่จะเรียกใช้ฟังก์ชัน osMailGet) ซึ่งอยู่ในฟังก์ชัน leds_task_entry (งาน LED) นั่นคืองานถูกสลับ และตอนนี้งาน LED ได้รับการควบคุมแล้ว
ด้วยวิธีง่ายๆ นี้ คุณสามารถสร้างวิธีที่งาน RTOS โต้ตอบซึ่งกันและกันได้
แน่นอนว่าในความเป็นจริง การโต้ตอบของงานอาจซับซ้อนกว่า แต่การใช้โปรแกรมจำลอง การติดตามการโต้ตอบนี้จะลำบากน้อยลง
เปิดตัวด้วย 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
เพื่อให้โปรแกรมจำลองโหลดเฟิร์มแวร์ที่คอมไพล์โดยตรงใน Eclipse คุณต้องเพิ่มพารามิเตอร์ firmware=null
ไปที่คำสั่งเปิดตัวโปรแกรมจำลอง:
binkopycat -g 23946 -n rhino -l user -y modules -p firmware=null,tty_dbg=COM26,tty_bt=COM28
การตั้งค่าการกำหนดค่าการแก้ไขข้อบกพร่อง
ใน Eclipse ให้เลือกเมนู เรียกใช้ - แก้ไขข้อบกพร่องการกำหนดค่า... ในหน้าต่างที่เปิดขึ้นในส่วน การดีบักฮาร์ดแวร์ GDB คุณต้องเพิ่มการกำหนดค่าใหม่จากนั้นในแท็บ "หลัก" ระบุโครงการปัจจุบันและแอปพลิเคชันสำหรับการดีบัก:
บนแท็บ "ดีบักเกอร์" คุณต้องระบุคำสั่ง GDB:
${openstm32_compiler_path}arm-none-eabi-gdb
และป้อนพารามิเตอร์สำหรับการเชื่อมต่อกับเซิร์ฟเวอร์ GDB (โฮสต์และพอร์ต):
บนแท็บ "เริ่มต้น" คุณต้องระบุพารามิเตอร์ต่อไปนี้:
- เปิดใช้งานช่องทำเครื่องหมาย โหลดรูปภาพ (เพื่อให้อิมเมจเฟิร์มแวร์ที่ประกอบถูกโหลดลงในโปรแกรมจำลอง)
- เปิดใช้งานช่องทำเครื่องหมาย โหลดสัญลักษณ์;
- เพิ่มคำสั่งเปิดตัว:
set $pc = *0x08000004
(ตั้งค่า PC register ให้เป็นค่าจากหน่วยความจำตามที่อยู่0x08000004
- ที่อยู่ถูกเก็บไว้ที่นั่น รีเซ็ตตัวจัดการ).
หมายเหตุหากคุณไม่ต้องการดาวน์โหลดไฟล์เฟิร์มแวร์จาก Eclipse ให้เลือกตัวเลือกต่างๆ โหลดรูปภาพ и เรียกใช้คำสั่ง ไม่จำเป็นต้องระบุ
หลังจากคลิก Debug คุณสามารถทำงานในโหมดดีบักเกอร์ได้:
- การดำเนินการโค้ดทีละขั้นตอน
- การโต้ตอบกับเบรกพอยต์
หมายเหตุ. Eclipse มี อืม... มีนิสัยแปลกๆ บางอย่าง... และคุณต้องอยู่กับมัน ตัวอย่างเช่น หากเมื่อเริ่มดีบักเกอร์ข้อความ "ไม่มีแหล่งที่มาสำหรับ "0x0" ปรากฏขึ้น ให้ดำเนินการคำสั่งขั้นตอน (F5)
แทนการสรุป
การเลียนแบบโค้ดเนทีฟเป็นสิ่งที่น่าสนใจมาก นักพัฒนาอุปกรณ์สามารถแก้ไขข้อบกพร่องของเฟิร์มแวร์ได้โดยไม่ต้องใช้อุปกรณ์จริง สำหรับนักวิจัย นี่คือโอกาสในการวิเคราะห์โค้ดแบบไดนามิก ซึ่งไม่สามารถทำได้เสมอไปแม้จะใช้อุปกรณ์ก็ตาม
เราต้องการมอบเครื่องมือที่สะดวก เรียบง่ายปานกลางให้กับผู้เชี่ยวชาญ และไม่ต้องใช้ความพยายามและเวลามากนักในการตั้งค่าและเรียกใช้
เขียนความคิดเห็นเกี่ยวกับประสบการณ์ของคุณโดยใช้โปรแกรมจำลองฮาร์ดแวร์ เราขอเชิญคุณมาพูดคุยและยินดีที่จะตอบคำถาม
เฉพาะผู้ใช้ที่ลงทะเบียนเท่านั้นที่สามารถเข้าร่วมในการสำรวจได้
คุณใช้โปรแกรมจำลองเพื่ออะไร?
-
ฉันพัฒนา (ดีบัก) เฟิร์มแวร์
-
ฉันกำลังค้นคว้าเฟิร์มแวร์
-
ฉันเปิดตัวเกม (Dendi, Sega, PSP)
-
อย่างอื่น (เขียนในความคิดเห็น)
ผู้ใช้ 7 คนโหวต ผู้ใช้ 2 รายงดออกเสียง
คุณใช้ซอฟต์แวร์ใดเพื่อเลียนแบบโค้ดเนทีฟ
-
QEMU
-
เครื่องยนต์ยูนิคอร์น
-
โพรทูส
-
อย่างอื่น (เขียนในความคิดเห็น)
ผู้ใช้ 6 คนโหวต ผู้ใช้ 2 รายงดออกเสียง
คุณต้องการปรับปรุงอะไรในโปรแกรมจำลองที่คุณใช้อยู่
-
ฉันต้องการความเร็ว
-
ฉันต้องการความง่ายในการติดตั้ง/เปิดใช้งาน
-
ฉันต้องการตัวเลือกเพิ่มเติมสำหรับการโต้ตอบกับโปรแกรมจำลอง (API, hooks)
-
ฉันมีความสุขกับทุกสิ่ง
-
อย่างอื่น (เขียนในความคิดเห็น)
ผู้ใช้ 8 คนโหวต ผู้ใช้ 1 รายงดออกเสียง
ที่มา: will.com