[{"data":1,"prerenderedAt":1586},["Reactive",2],{"kb-chapters":3,"kb-doc:/knowledge-base/reverse-engineering/ghidra/":181},[4,11,17,23,29,35,41,47,53,59,65,71,77,83,89,96,102,108,114,120,126,132,138,144,150,156,163,169,175],{"_path":5,"title":6,"description":7,"part":8,"_file":9,"chapterNumber":10},"/knowledge-base/networks/introduction","Introduction","Overview of the communication networks used in modern vehicles, from LIN to Automotive Ethernet.","Vehicle Networks & Protocols","7.knowledge-base/1.networks/1.introduction.md",1,{"_path":12,"title":13,"description":14,"part":8,"_file":15,"chapterNumber":16},"/knowledge-base/networks/vehicle-documentation","Vehicle Documentation","Where to find manufacturer wiring diagrams, J2534 passthrough devices, and the different types of diagrams that are useful when researching a vehicle.","7.knowledge-base/1.networks/2.vehicle-documentation.md",2,{"_path":18,"title":19,"description":20,"part":8,"_file":21,"chapterNumber":22},"/knowledge-base/networks/lin-bus","Local Interconnect Network (LIN)","Local Interconnect Network — a single-wire low-speed bus used as a low-cost alternative to CAN for non-critical body electronics.","7.knowledge-base/1.networks/3.lin-bus.md",3,{"_path":24,"title":25,"description":26,"part":8,"_file":27,"chapterNumber":28},"/knowledge-base/networks/controller-area-network","Controller Area Network (CAN)","ISO 11898 — the differential bus that became the backbone of automotive networking. Frames, bit timing, errors, CAN FD, message contents, and practical attacks.","7.knowledge-base/1.networks/4.controller-area-network.md",4,{"_path":30,"title":31,"description":32,"part":8,"_file":33,"chapterNumber":34},"/knowledge-base/networks/secure-onboard-communication","Secure Onboard Communication (SecOC)","AUTOSAR's standard for cryptographic message authentication on in-vehicle networks — freshness values, MAC computation and key management.","7.knowledge-base/1.networks/5.secure-onboard-communication.md",5,{"_path":36,"title":37,"description":38,"part":8,"_file":39,"chapterNumber":40},"/knowledge-base/networks/flexray","FlexRay","Time-triggered, deterministic automotive bus standardized as ISO 17458, designed for higher speeds and drive-by-wire systems.","7.knowledge-base/1.networks/6.flexray.md",6,{"_path":42,"title":43,"description":44,"part":8,"_file":45,"chapterNumber":46},"/knowledge-base/networks/automotive-ethernet","Automotive Ethernet","Automotive variants of Ethernet — 100BASE-T1, 1000BASE-T1, and 10BASE-T1S — built around single twisted-pair cabling and strict EMC requirements.","7.knowledge-base/1.networks/7.automotive-ethernet.md",7,{"_path":48,"title":6,"description":49,"part":50,"_file":51,"chapterNumber":52},"/knowledge-base/diagnostics/introduction","Overview of automotive diagnostic protocols — ISO-TP, OBD-II, UDS, CCP and XCP — and how they layer on top of CAN.","Diagnostic Protocols","7.knowledge-base/2.diagnostics/1.introduction.md",8,{"_path":54,"title":55,"description":56,"part":50,"_file":57,"chapterNumber":58},"/knowledge-base/diagnostics/iso-tp","ISO 15765-2 (ISO-TP)","ISO 15765-2 transport layer for sending diagnostic payloads larger than 8 bytes over CAN — single, first, consecutive and flow-control frames.","7.knowledge-base/2.diagnostics/2.iso-tp.md",9,{"_path":60,"title":61,"description":62,"part":50,"_file":63,"chapterNumber":64},"/knowledge-base/diagnostics/vw-tp20","VW Transport Protocol 2.0 (TP 2.0)","Volkswagen's pre-ISO-TP transport layer for KWP2000 over CAN — channel setup, parameter negotiation, and the data exchange counter scheme.","7.knowledge-base/2.diagnostics/3.vw-tp20.md",10,{"_path":66,"title":67,"description":68,"part":50,"_file":69,"chapterNumber":70},"/knowledge-base/diagnostics/obd-ii","On-board diagnostics (OBD-II)","On-Board Diagnostics II — the J1962 connector, signal protocols, service IDs, parameter IDs, and DTC encoding.","7.knowledge-base/2.diagnostics/4.obd-ii.md",11,{"_path":72,"title":73,"description":74,"part":50,"_file":75,"chapterNumber":76},"/knowledge-base/diagnostics/uds","Unified Diagnostic Services (UDS)","ISO 14229-1 — the modern diagnostic protocol for sessions, Read/Write DID, Security Access, Routine Control and firmware Request Download / Upload.","7.knowledge-base/2.diagnostics/6.uds.md",12,{"_path":78,"title":79,"description":80,"part":50,"_file":81,"chapterNumber":82},"/knowledge-base/diagnostics/ccp","CAN Calibration Protocol (CCP)","A low-level debug/calibration protocol over CAN — Command Receive Object, Data Transfer Object, and the commands used to read and write ECU memory.","7.knowledge-base/2.diagnostics/7.ccp.md",13,{"_path":84,"title":85,"description":86,"part":50,"_file":87,"chapterNumber":88},"/knowledge-base/diagnostics/xcp","Universal Measurement and Calibration Protocol (XCP)","ASAM XCP — successor to CCP supporting CAN, CAN FD, FlexRay, and Ethernet, with synchronous data acquisition, stimulation, and calibration.","7.knowledge-base/2.diagnostics/8.xcp.md",14,{"_path":90,"title":91,"description":92,"part":93,"_file":94,"chapterNumber":95},"/knowledge-base/reverse-engineering/ecu-flashing","ECU Flashing","How a control unit is reprogrammed over the wire with UDS, walked through step by step, why the sequence is staged the way it is, how the SecurityAccess seed/key gate works from weak proprietary LFSR ciphers to the Volkswagen SA2 script, and the levels of image authenticity from no signature validation through HSM-backed secure boot.","Reverse Engineering","7.knowledge-base/3.reverse-engineering/1.ecu-flashing.md",15,{"_path":97,"title":98,"description":99,"part":93,"_file":100,"chapterNumber":101},"/knowledge-base/reverse-engineering/oem-update-files","OEM Update Files","Where to find official ECU firmware, why OEMs ship it, and how the major manufacturer update container formats (VW FRF/ODX, Toyota CUW, Ford VBF, BMW psdzdata, Tesla BHX) are structured, decrypted, and unpacked.","7.knowledge-base/3.reverse-engineering/2.oem-update-files.md",16,{"_path":103,"title":104,"description":105,"part":93,"_file":106,"chapterNumber":107},"/knowledge-base/reverse-engineering/ghidra","Ghidra Tutorial","Practical use of Ghidra on automotive ECU images. Project setup, p-code and SLEIGH, auto-analysis configuration, locating code in raw images, configuring the memory map and Small Data Area for PPC VLE, TriCore and RH850, and recognising UDS dispatchers, CAN tables, and AUTOSAR fingerprints.","7.knowledge-base/3.reverse-engineering/3.ghidra.md",17,{"_path":109,"title":110,"description":111,"part":93,"_file":112,"chapterNumber":113},"/knowledge-base/reverse-engineering/wireless-rf","Wireless and RF","Practical reverse engineering of automotive sub-GHz radio links. Radio architectures (heterodyne, integrated transceivers, SDR), unlicensed ISM bands, binary modulation schemes (ASK, FSK, BPSK), Manchester line coding, the software ecosystem (GNU Radio, Gqrx, URH, rtl_433), and a walkthrough of decoding a Hitag2 keyfob capture in URH.","7.knowledge-base/3.reverse-engineering/4.wireless-rf.md",18,{"_path":115,"title":6,"description":116,"part":117,"_file":118,"chapterNumber":119},"/knowledge-base/existing-research/introduction","Landmark papers from 2010 to 2016 that defined automotive security research and demonstrated the first complete remote exploit chain against a production vehicle.","Existing Research","7.knowledge-base/4.existing-research/1.introduction.md",19,{"_path":121,"title":122,"description":123,"part":117,"_file":124,"chapterNumber":125},"/knowledge-base/existing-research/engine-control-units","Engine Control Units","Public reverse-engineering work on engine ECUs, focusing on bri3d's documented exploit chains for the Volkswagen Group Simos 18 ECU and its Infineon TriCore TC1791 processor.","7.knowledge-base/4.existing-research/2.engine-control-units.md",20,{"_path":127,"title":128,"description":129,"part":117,"_file":130,"chapterNumber":131},"/knowledge-base/existing-research/ev-charging","EV Charging","Research covering two distinct attack surfaces introduced by electric vehicle charging, the HomePlug Green PHY powerline data layer used by the Combined Charging System, and the AC charger as a peer device with its own firmware and bidirectional communications.","7.knowledge-base/4.existing-research/3.ev-charging.md",21,{"_path":133,"title":134,"description":135,"part":117,"_file":136,"chapterNumber":137},"/knowledge-base/existing-research/fault-injection","Fault Injection","Published fault injection research relevant to automotive microcontrollers, covering voltage glitching, EMFI, debug access, and secure-boot bypasses on Renesas, Infineon, NXP/Freescale, and Tesla compute platforms.","7.knowledge-base/4.existing-research/4.fault-injection.md",22,{"_path":139,"title":140,"description":141,"part":117,"_file":142,"chapterNumber":143},"/knowledge-base/existing-research/infotainment-telematics","Infotainment & Telematics","Sixteen published research entries covering remote exploitation of infotainment and telematics systems across Tesla, BMW, Mercedes-Benz, Volkswagen Group, and Nissan vehicles, plus a cross-industry web API survey.","7.knowledge-base/4.existing-research/5.infotainment-telematics.md",23,{"_path":145,"title":146,"description":147,"part":117,"_file":148,"chapterNumber":149},"/knowledge-base/existing-research/sensors-and-radios","Other Wireless Attack Surfaces","Research covering wireless attack surfaces beyond the primary CAN and telematics interfaces, including tire pressure sensors and DAB radio receivers, both of which accept untrusted RF input and have historically performed no authentication or input validation.","7.knowledge-base/4.existing-research/6.sensors-and-radios.md",24,{"_path":151,"title":152,"description":153,"part":117,"_file":154,"chapterNumber":155},"/knowledge-base/existing-research/remote-keyless-entry","Remote Keyless Entry and Immobilisers","Research on cryptographic attacks against passive keyless entry systems, transponder-based immobilisers, rolling-code RKE, and the CAN-injection theft chain.","7.knowledge-base/4.existing-research/7.remote-keyless-entry.md",25,{"_path":157,"title":158,"description":159,"part":160,"_file":161,"chapterNumber":162},"/knowledge-base/tools/can-adapters","CAN Adapters","USB-to-CAN adapters — comma.ai red panda and PEAK-System PCAN — and the standard DB-9 pinout for CAN.","Tools","7.knowledge-base/5.tools/1.can-adapters.md",26,{"_path":164,"title":165,"description":166,"part":160,"_file":167,"chapterNumber":168},"/knowledge-base/tools/can-analysis","CAN Analysis","Tools for analysing and reverse-engineering CAN traffic — comma.ai cabana, SavyCAN, VehicleSpy, and Wireshark.","7.knowledge-base/5.tools/2.can-analysis.md",27,{"_path":170,"title":171,"description":172,"part":160,"_file":173,"chapterNumber":174},"/knowledge-base/tools/scripting","Scripting","Python libraries and CLI tools for talking to a CAN bus — comma.ai panda, SocketCAN can-utils, python-can, and Scapy with ISO-TP and UDS examples.","7.knowledge-base/5.tools/3.scripting.md",28,{"_path":176,"title":177,"description":178,"part":160,"_file":179,"chapterNumber":180},"/knowledge-base/tools/dbc-files","DBC Files","The DBC file format used to describe the contents of CAN messages — nodes, messages, signals, comments, and value tables.","7.knowledge-base/5.tools/4.dbc-files.md",29,{"_path":103,"_dir":182,"_draft":183,"_partial":183,"_locale":184,"title":104,"description":105,"part":93,"references":185,"body":207,"_type":1582,"_id":1583,"_source":1584,"_file":106,"_extension":1585},"reverse-engineering",false,"",[186,191,195,200],{"id":187,"authors":188,"title":189,"url":190},"ghidra","National Security Agency","Ghidra software reverse engineering framework","https://ghidra-sre.org/",{"id":192,"authors":188,"title":193,"url":194},"sleigh","SLEIGH, a language for rapid processor specification","https://htmlpreview.github.io/?https://github.com/NationalSecurityAgency/ghidra/blob/master/GhidraDocs/languages/html/sleigh.html",{"id":196,"authors":197,"title":198,"url":199},"autosar-re","Renault Group","autosar-re, Ghidra scripts for reverse engineering AUTOSAR firmware","https://github.com/grouperenault/autosar-re",{"id":201,"authors":202,"title":203,"publisher":204,"year":205,"url":206},"sstic2023-autosar-re","Quentin Tillequin, Florian Charron","Rétro-ingénierie de systèmes embarqués AUTOSAR","SSTIC 2023",2023,"https://www.sstic.org/media/SSTIC2023/SSTIC-actes/Retro-ingenierie_de_systemes_embarques_AUTOSAR/SSTIC2023-Slides-Retro-ingenierie_de_systemes_embarques_AUTOSAR-tillequin_charron.pdf",{"type":208,"children":209,"toc":1561},"root",[210,218,230,237,242,328,337,343,383,388,397,402,408,413,425,433,439,458,531,539,551,557,562,596,604,610,622,669,695,703,709,714,766,771,779,785,813,825,831,859,879,887,892,1088,1093,1099,1112,1124,1204,1212,1225,1233,1239,1244,1251,1256,1324,1329,1337,1343,1348,1356,1362,1367,1390,1395,1403,1409,1414,1420,1455,1460,1465,1473,1501,1551,1557],{"type":211,"tag":212,"props":213,"children":215},"element","h1",{"id":214},"ghidra-tutorial",[216],{"type":217,"value":104},"text",{"type":211,"tag":219,"props":220,"children":221},"p",{},[222,224,228],{"type":217,"value":223},"Ghidra is the NSA's open-source software reverse engineering suite ",{"type":211,"tag":225,"props":226,"children":227},"citation",{"id":187},[],{"type":217,"value":229},". It is well suited to automotive work: it is free, scriptable in Python and Java, and its decompiler supports the cores commonly found in ECUs (PowerPC VLE, TriCore, RH850), which other tools either do not support or only support at significant cost. This chapter covers the practical steps of using it on a raw firmware image, from import through to a labelled UDS dispatcher.",{"type":211,"tag":231,"props":232,"children":234},"h2",{"id":233},"the-codebrowser",[235],{"type":217,"value":236},"The CodeBrowser",{"type":211,"tag":219,"props":238,"children":239},{},[240],{"type":217,"value":241},"The CodeBrowser is the main analysis window. The relevant panes are:",{"type":211,"tag":243,"props":244,"children":245},"ul",{},[246,258,268,278,288,298,308,318],{"type":211,"tag":247,"props":248,"children":249},"li",{},[250,256],{"type":211,"tag":251,"props":252,"children":253},"strong",{},[254],{"type":217,"value":255},"Listing",{"type":217,"value":257},": the disassembly with markup (labels, comments, references).",{"type":211,"tag":247,"props":259,"children":260},{},[261,266],{"type":211,"tag":251,"props":262,"children":263},{},[264],{"type":217,"value":265},"Decompiler",{"type":217,"value":267},": the pseudo-C view of the function under the cursor.",{"type":211,"tag":247,"props":269,"children":270},{},[271,276],{"type":211,"tag":251,"props":272,"children":273},{},[274],{"type":217,"value":275},"Symbol Tree",{"type":217,"value":277},": imports, exports, namespaces, and defined symbols.",{"type":211,"tag":247,"props":279,"children":280},{},[281,286],{"type":211,"tag":251,"props":282,"children":283},{},[284],{"type":217,"value":285},"Data Type Manager",{"type":217,"value":287},": built-in and imported types, and user-defined structures.",{"type":211,"tag":247,"props":289,"children":290},{},[291,296],{"type":211,"tag":251,"props":292,"children":293},{},[294],{"type":217,"value":295},"Memory Map",{"type":217,"value":297},": the section table, edited through this pane.",{"type":211,"tag":247,"props":299,"children":300},{},[301,306],{"type":211,"tag":251,"props":302,"children":303},{},[304],{"type":217,"value":305},"Bookmarks",{"type":217,"value":307},": analysis warnings and user notes.",{"type":211,"tag":247,"props":309,"children":310},{},[311,316],{"type":211,"tag":251,"props":312,"children":313},{},[314],{"type":217,"value":315},"Defined Strings",{"type":217,"value":317},": every string Ghidra recognised. Firmware images contain few strings, but those that exist (debug messages, AUTOSAR module names, version banners) are useful starting points for analysis.",{"type":211,"tag":247,"props":319,"children":320},{},[321,326],{"type":211,"tag":251,"props":322,"children":323},{},[324],{"type":217,"value":325},"Function Graph",{"type":217,"value":327},": the control-flow view of the current function.",{"type":211,"tag":219,"props":329,"children":330},{},[331],{"type":211,"tag":332,"props":333,"children":336},"img",{"alt":334,"src":335},"Ghidra CodeBrowser with Listing, Decompiler, Symbol Tree, Data Type Manager and Memory Map panes visible on an automotive firmware image.","/images/knowledge-base/reverse-engineering/ghidra-codebrowser.png",[],{"type":211,"tag":231,"props":338,"children":340},{"id":339},"sleigh-and-p-code",[341],{"type":217,"value":342},"SLEIGH and P-code",{"type":211,"tag":219,"props":344,"children":345},{},[346,348,351,353,358,360,365,367,374,376,381],{"type":217,"value":347},"SLEIGH is the specification language Ghidra uses to describe a processor ",{"type":211,"tag":225,"props":349,"children":350},{"id":192},[],{"type":217,"value":352},". Each instruction is defined in two parts. A ",{"type":211,"tag":251,"props":354,"children":355},{},[356],{"type":217,"value":357},"constructor",{"type":217,"value":359}," matches a bit pattern and decodes it to a mnemonic and operands. A ",{"type":211,"tag":251,"props":361,"children":362},{},[363],{"type":217,"value":364},"semantic block",{"type":217,"value":366}," in ",{"type":211,"tag":368,"props":369,"children":371},"code",{"className":370},[],[372],{"type":217,"value":373},"{}",{"type":217,"value":375}," emits ",{"type":211,"tag":251,"props":377,"children":378},{},[379],{"type":217,"value":380},"p-code",{"type":217,"value":382},", the architecture-neutral intermediate representation that the rest of Ghidra (the decompiler, the data-flow analyser, scripts) operates on.",{"type":211,"tag":219,"props":384,"children":385},{},[386],{"type":217,"value":387},"A simplified example of a SLEIGH entry:",{"type":211,"tag":389,"props":390,"children":392},"pre",{"code":391},":add Rd, Rs1, Rs2  is op=0b000000 & Rd & Rs1 & Rs2  {\n    Rd = Rs1 + Rs2;\n}\n",[393],{"type":211,"tag":368,"props":394,"children":395},{"__ignoreMap":184},[396],{"type":217,"value":391},{"type":211,"tag":219,"props":398,"children":399},{},[400],{"type":217,"value":401},"The decompiler operates only on p-code, with no per-architecture code. Any architecture with a SLEIGH specification therefore produces full decompiler output. PowerPC VLE, TriCore, and RH850 are usable in Ghidra for this reason, and adding a new automotive core requires only a new SLEIGH file.",{"type":211,"tag":231,"props":403,"children":405},{"id":404},"recognising-automotive-firmware-layout",[406],{"type":217,"value":407},"Recognising Automotive Firmware Layout",{"type":211,"tag":219,"props":409,"children":410},{},[411],{"type":217,"value":412},"An ECU image typically splits into a small bootloader (CBOOT) and a larger application (ASW).",{"type":211,"tag":219,"props":414,"children":415},{},[416,418,423],{"type":217,"value":417},"The ",{"type":211,"tag":251,"props":419,"children":420},{},[421],{"type":217,"value":422},"Entropy",{"type":217,"value":424}," strip on the right of the Listing makes the split visible. Code and packed lookup tables sit around 6 bits per byte. Calibration constants and pointer tables are lower. Padding gaps drop to near zero. Compressed or signed blobs remain flat near 8. The typical pattern is a small dense band (CBOOT), a low gap, a much larger dense band (ASW), with occasional flat regions for tables and a tail of padding. This indicates where to place the loader sections before any disassembly.",{"type":211,"tag":219,"props":426,"children":427},{},[428],{"type":211,"tag":332,"props":429,"children":432},{"alt":430,"src":431},"Ghidra entropy legend.","/images/knowledge-base/reverse-engineering/ghidra-entropy.png",[],{"type":211,"tag":231,"props":434,"children":436},{"id":435},"loading-a-firmware-image",[437],{"type":217,"value":438},"Loading a Firmware Image",{"type":211,"tag":219,"props":440,"children":441},{},[442,444,449,451,456],{"type":217,"value":443},"For a raw memory dump, use ",{"type":211,"tag":251,"props":445,"children":446},{},[447],{"type":217,"value":448},"File, Import",{"type":217,"value":450}," with the format set to ",{"type":211,"tag":251,"props":452,"children":453},{},[454],{"type":217,"value":455},"Raw Binary",{"type":217,"value":457},". The processor dropdown is the only field that has to be set carefully, and selecting the correct variant matters:",{"type":211,"tag":243,"props":459,"children":460},{},[461,487,505],{"type":211,"tag":247,"props":462,"children":463},{},[464,469,471,477,479,485],{"type":211,"tag":251,"props":465,"children":466},{},[467],{"type":217,"value":468},"PowerPC",{"type":217,"value":470},": select ",{"type":211,"tag":368,"props":472,"children":474},{"className":473},[],[475],{"type":217,"value":476},"PowerPC:BE:32:e200",{"type":217,"value":478}," for the Power Architecture e200 cores common in MPC55xx/57xx parts. The ",{"type":211,"tag":368,"props":480,"children":482},{"className":481},[],[483],{"type":217,"value":484},"default",{"type":217,"value":486}," variant is plain Book-E and will not decode VLE.",{"type":211,"tag":247,"props":488,"children":489},{},[490,495,497,503],{"type":211,"tag":251,"props":491,"children":492},{},[493],{"type":217,"value":494},"TriCore",{"type":217,"value":496},": ",{"type":211,"tag":368,"props":498,"children":500},{"className":499},[],[501],{"type":217,"value":502},"tricore:LE:32:default",{"type":217,"value":504}," covers Infineon AURIX TC1.6.x.",{"type":211,"tag":247,"props":506,"children":507},{},[508,513,515,521,523,529],{"type":211,"tag":251,"props":509,"children":510},{},[511],{"type":217,"value":512},"RH850",{"type":217,"value":514},": shipped as a variant of ",{"type":211,"tag":368,"props":516,"children":518},{"className":517},[],[519],{"type":217,"value":520},"V850",{"type":217,"value":522},", typically ",{"type":211,"tag":368,"props":524,"children":526},{"className":525},[],[527],{"type":217,"value":528},"V850:LE:32:default",{"type":217,"value":530}," with the RH850 extensions enabled.",{"type":211,"tag":219,"props":532,"children":533},{},[534],{"type":211,"tag":332,"props":535,"children":538},{"alt":536,"src":537},"Import dialog loading a PowerPC VLE binary with a loading offset of 0x80000","/images/knowledge-base/reverse-engineering/ghidra-import-language.png",[],{"type":211,"tag":219,"props":540,"children":541},{},[542,544,549],{"type":217,"value":543},"After import, the entire image is loaded as a single block at the address given. Most automotive images require a finer split. Open ",{"type":211,"tag":251,"props":545,"children":546},{},[547],{"type":217,"value":548},"Window, Memory Map",{"type":217,"value":550}," and split the block so CBOOT and ASW are mapped at their real addresses. Keep in mind that TriCore PFLASH is mapped at both 0x8000_0000 and 0xA000_0000.",{"type":211,"tag":231,"props":552,"children":554},{"id":553},"setting-up-the-memory-map",[555],{"type":217,"value":556},"Setting Up the Memory Map",{"type":211,"tag":219,"props":558,"children":559},{},[560],{"type":217,"value":561},"The Memory Map editor is also used to define RAM and peripheral regions. From the datasheet:",{"type":211,"tag":243,"props":563,"children":564},{},[565,577],{"type":211,"tag":247,"props":566,"children":567},{},[568,570,575],{"type":217,"value":569},"A ",{"type":211,"tag":251,"props":571,"children":572},{},[573],{"type":217,"value":574},"RAM",{"type":217,"value":576}," block at the chip's SRAM base. Read/Write. Executable depending on context. Some applications copy part of the code to RAM for faster execution, this is especially common on TriCore.",{"type":211,"tag":247,"props":578,"children":579},{},[580,582,587,589,594],{"type":217,"value":581},"One or more ",{"type":211,"tag":251,"props":583,"children":584},{},[585],{"type":217,"value":586},"MMIO",{"type":217,"value":588}," blocks for the peripherals. Mark these ",{"type":211,"tag":251,"props":590,"children":591},{},[592],{"type":217,"value":593},"Volatile",{"type":217,"value":595},". Without Volatile, the decompiler folds repeated reads of a status register to a single value and constant-propagates the result, so polling loops appear as infinite loops and the surrounding logic disappears from the output.",{"type":211,"tag":219,"props":597,"children":598},{},[599],{"type":211,"tag":332,"props":600,"children":603},{"alt":601,"src":602},"Memory Map editor populated with Flash sections, SRAM blocks, and a peripheral block marked Volatile.","/images/knowledge-base/reverse-engineering/ghidra-memory-map.png",[],{"type":211,"tag":231,"props":605,"children":607},{"id":606},"auto-analysis-options",[608],{"type":217,"value":609},"Auto-Analysis Options",{"type":211,"tag":219,"props":611,"children":612},{},[613,615,620],{"type":217,"value":614},"Ghidra runs a stack of analysers after import. Two of them produce more noise than signal on raw automotive images and should be disabled in ",{"type":211,"tag":251,"props":616,"children":617},{},[618],{"type":217,"value":619},"Analyze, Auto Analyze",{"type":217,"value":621}," before the first run:",{"type":211,"tag":243,"props":623,"children":624},{},[625,635],{"type":211,"tag":247,"props":626,"children":627},{},[628,633],{"type":211,"tag":251,"props":629,"children":630},{},[631],{"type":217,"value":632},"Address Tables",{"type":217,"value":634}," speculatively interprets aligned, pointer-shaped regions as jump or pointer tables and disassembles the targets. It runs early, before the code finder has identified real code, so an incorrect guess (the common case on a stripped image with unknown section boundaries) claims a data region as a table, disassembles into it, and prevents later analysers from revisiting that region. Disable it. Switch tables can be defined by hand once the dispatcher is understood.",{"type":211,"tag":247,"props":636,"children":637},{},[638,643,645,651,653,659,661,667],{"type":211,"tag":251,"props":639,"children":640},{},[641],{"type":217,"value":642},"Non-Returning Functions",{"type":217,"value":644}," heuristically marks functions such as ",{"type":211,"tag":368,"props":646,"children":648},{"className":647},[],[649],{"type":217,"value":650},"panic",{"type":217,"value":652},", ",{"type":211,"tag":368,"props":654,"children":656},{"className":655},[],[657],{"type":217,"value":658},"abort",{"type":217,"value":660}," or ",{"type":211,"tag":368,"props":662,"children":664},{"className":663},[],[665],{"type":217,"value":666},"exit",{"type":217,"value":668}," as no-return. A single false positive truncates control flow at every call site and leaves unreachable code behind each call. Reversing it is time-consuming because the fall-through has already been removed everywhere it applied. Leave this disabled and mark genuine no-return functions manually once identified.",{"type":211,"tag":219,"props":670,"children":671},{},[672,674,679,681,686,688,693],{"type":217,"value":673},"Two further options are worth reviewing: ",{"type":211,"tag":251,"props":675,"children":676},{},[677],{"type":217,"value":678},"Decompiler Parameter ID",{"type":217,"value":680}," is slow on large images and is better left for a second pass once the bulk of the labelling is done. ",{"type":211,"tag":251,"props":682,"children":683},{},[684],{"type":217,"value":685},"Embedded Media",{"type":217,"value":687}," and ",{"type":211,"tag":251,"props":689,"children":690},{},[691],{"type":217,"value":692},"DWARF",{"type":217,"value":694}," are not useful on stripped firmware and can also be disabled.",{"type":211,"tag":219,"props":696,"children":697},{},[698],{"type":211,"tag":332,"props":699,"children":702},{"alt":700,"src":701},"Analysis Options dialog with Address Tables and Non-Returning Functions unticked.","/images/knowledge-base/reverse-engineering/ghidra-analysis-options.png",[],{"type":211,"tag":231,"props":704,"children":706},{"id":705},"finding-the-boot-header",[707],{"type":217,"value":708},"Finding the Boot Header",{"type":211,"tag":219,"props":710,"children":711},{},[712],{"type":217,"value":713},"The boot header is the fixed-format structure the mask ROM reads first to decide how to start the chip. Each architecture defines its own:",{"type":211,"tag":243,"props":715,"children":716},{},[717,733,757],{"type":211,"tag":247,"props":718,"children":719},{},[720,724,726,731],{"type":211,"tag":251,"props":721,"children":722},{},[723],{"type":217,"value":468},{"type":217,"value":725}," (MPC55xx/57xx) uses a ",{"type":211,"tag":251,"props":727,"children":728},{},[729],{"type":217,"value":730},"Boot Assist Flag (BAF)",{"type":217,"value":732}," record near the reset vector, with magic bytes, an entry point address and configuration words.",{"type":211,"tag":247,"props":734,"children":735},{},[736,740,742,747,749,755],{"type":211,"tag":251,"props":737,"children":738},{},[739],{"type":217,"value":494},{"type":217,"value":741}," AURIX uses a ",{"type":211,"tag":251,"props":743,"children":744},{},[745],{"type":217,"value":746},"Boot Mode Header (BMH)",{"type":217,"value":748}," at fixed addresses (typically 0x80000000, 0x80020000, and so on), with a ",{"type":211,"tag":368,"props":750,"children":752},{"className":751},[],[753],{"type":217,"value":754},"0xA0000020",{"type":217,"value":756}," magic word, the entry point, and a CRC.",{"type":211,"tag":247,"props":758,"children":759},{},[760,764],{"type":211,"tag":251,"props":761,"children":762},{},[763],{"type":217,"value":512},{"type":217,"value":765}," stores option bytes and the reset vector in dedicated regions defined by the device's datasheet.",{"type":211,"tag":219,"props":767,"children":768},{},[769],{"type":217,"value":770},"Locate the header, confirm that the entry point references plausible startup code (a stack pointer load, an unconditional branch to higher addresses), and label it. The rest of this chapter assumes the load address is correct, and the boot header is the structure that confirms it.",{"type":211,"tag":219,"props":772,"children":773},{},[774],{"type":211,"tag":332,"props":775,"children":778},{"alt":776,"src":777},"Datasheet excerpt showing the boot header layout for one of the supported architectures, with the magic word, entry point and configuration fields identified.","/images/knowledge-base/reverse-engineering/ghidra-boot-header.png",[],{"type":211,"tag":231,"props":780,"children":782},{"id":781},"disassembling-code",[783],{"type":217,"value":784},"Disassembling Code",{"type":211,"tag":219,"props":786,"children":787},{},[788,790,795,797,803,805,811],{"type":217,"value":789},"With the auto-analysis options adjusted, run ",{"type":211,"tag":251,"props":791,"children":792},{},[793],{"type":217,"value":794},"Analyze",{"type":217,"value":796},". Review the result and identify regions that were skipped. Long runs of ",{"type":211,"tag":368,"props":798,"children":800},{"className":799},[],[801],{"type":217,"value":802},"??",{"type":217,"value":804}," (undefined bytes) between functions are typically code that the auto-analysis did not reach. Select the start address and press ",{"type":211,"tag":368,"props":806,"children":808},{"className":807},[],[809],{"type":217,"value":810},"D",{"type":217,"value":812},".",{"type":211,"tag":219,"props":814,"children":815},{},[816,818,823],{"type":217,"value":817},"On PowerPC VLE, the analyser disassembles in Book-E mode by default. The two encodings overlap sufficiently that Book-E will decode VLE bytes into syntactically valid but incorrect instructions. In automotive typically only VLE is used, so press ",{"type":211,"tag":251,"props":819,"children":820},{},[821],{"type":217,"value":822},"F12",{"type":217,"value":824}," to disassemble the region in VLE.",{"type":211,"tag":231,"props":826,"children":828},{"id":827},"the-entrypoint-and-global-registers",[829],{"type":217,"value":830},"The Entrypoint and Global Registers",{"type":211,"tag":219,"props":832,"children":833},{},[834,836,841,843,849,851,857],{"type":217,"value":835},"Each of the architectures above reserves one or two registers as bases for the ",{"type":211,"tag":251,"props":837,"children":838},{},[839],{"type":217,"value":840},"Small Data Area (SDA)",{"type":217,"value":842},". The compiler emits global accesses as ",{"type":211,"tag":368,"props":844,"children":846},{"className":845},[],[847],{"type":217,"value":848},"reg + offset16",{"type":217,"value":850},", avoiding a ",{"type":211,"tag":368,"props":852,"children":854},{"className":853},[],[855],{"type":217,"value":856},"lis/ori",{"type":217,"value":858},"-style pair on every load and store. The SDA bases are set once in the startup code and remain fixed for the lifetime of the program.",{"type":211,"tag":219,"props":860,"children":861},{},[862,864,870,872,877],{"type":217,"value":863},"The decompiler has no knowledge of the SDA base values until they are configured. Until then, every global access decompiles as ",{"type":211,"tag":368,"props":865,"children":867},{"className":866},[],[868],{"type":217,"value":869},"*(int *)(r13 + 0x1234)",{"type":217,"value":871}," and produces no cross-references. Select all code where the found SDA values apply, typically bootloader or application code. Although microcontrollers with multiple cores might use different register values per core. Use ",{"type":211,"tag":251,"props":873,"children":874},{},[875],{"type":217,"value":876},"Right-click in Listing, Set Register Values",{"type":217,"value":878}," to tell Ghidra about the correct register values. This will clean up the decompilation and calculate the correct X-refs on the next Auto Analysis pass.",{"type":211,"tag":219,"props":880,"children":881},{},[882],{"type":211,"tag":332,"props":883,"children":886},{"alt":884,"src":885},"Edit Register Values dialog with r2 and r13 set to their SDA base addresses on a PPC VLE entry function.","/images/knowledge-base/reverse-engineering/ghidra-edit-register-values.png",[],{"type":211,"tag":219,"props":888,"children":889},{},[890],{"type":217,"value":891},"The bases are loaded immediately after reset:",{"type":211,"tag":243,"props":893,"children":894},{},[895,959,1019],{"type":211,"tag":247,"props":896,"children":897},{},[898,903,904,910,912,918,920,926,928,934,936,942,944,949,950,954],{"type":211,"tag":251,"props":899,"children":900},{},[901],{"type":217,"value":902},"PowerPC VLE",{"type":217,"value":496},{"type":211,"tag":368,"props":905,"children":907},{"className":906},[],[908],{"type":217,"value":909},"r2",{"type":217,"value":911}," is SDA2 (",{"type":211,"tag":368,"props":913,"children":915},{"className":914},[],[916],{"type":217,"value":917},".sdata2",{"type":217,"value":919},"/const), ",{"type":211,"tag":368,"props":921,"children":923},{"className":922},[],[924],{"type":217,"value":925},"r13",{"type":217,"value":927}," is SDA (",{"type":211,"tag":368,"props":929,"children":931},{"className":930},[],[932],{"type":217,"value":933},".sdata",{"type":217,"value":935},"). Startup typically loads them with ",{"type":211,"tag":368,"props":937,"children":939},{"className":938},[],[940],{"type":217,"value":941},"e_lis r2, hi ; e_or2i r2, lo",{"type":217,"value":943}," and the same for ",{"type":211,"tag":368,"props":945,"children":947},{"className":946},[],[948],{"type":217,"value":925},{"type":217,"value":812},{"type":211,"tag":951,"props":952,"children":953},"br",{},[],{"type":211,"tag":332,"props":955,"children":958},{"alt":956,"src":957},"Typical PPC VLE startup code setting r2 and r13 to the SDA bases.","/images/knowledge-base/reverse-engineering/ghidra-ppc-vle-startup.png",[],{"type":211,"tag":247,"props":960,"children":961},{},[962,966,967,973,974,980,982,988,989,995,997,1003,1005,1010,1011,1014],{"type":211,"tag":251,"props":963,"children":964},{},[965],{"type":217,"value":494},{"type":217,"value":496},{"type":211,"tag":368,"props":968,"children":970},{"className":969},[],[971],{"type":217,"value":972},"a0",{"type":217,"value":687},{"type":211,"tag":368,"props":975,"children":977},{"className":976},[],[978],{"type":217,"value":979},"a1",{"type":217,"value":981}," cover the small data areas, ",{"type":211,"tag":368,"props":983,"children":985},{"className":984},[],[986],{"type":217,"value":987},"a8",{"type":217,"value":687},{"type":211,"tag":368,"props":990,"children":992},{"className":991},[],[993],{"type":217,"value":994},"a9",{"type":217,"value":996}," are reserved for the OS/application split. Startup uses ",{"type":211,"tag":368,"props":998,"children":1000},{"className":999},[],[1001],{"type":217,"value":1002},"movh.a a0, hi ; lea a0, [a0]lo",{"type":217,"value":1004}," and similar for ",{"type":211,"tag":368,"props":1006,"children":1008},{"className":1007},[],[1009],{"type":217,"value":979},{"type":217,"value":812},{"type":211,"tag":951,"props":1012,"children":1013},{},[],{"type":211,"tag":332,"props":1015,"children":1018},{"alt":1016,"src":1017},"Typical TriCore startup code setting a0 and a1.","/images/knowledge-base/reverse-engineering/ghidra-tricore-startup.png",[],{"type":211,"tag":247,"props":1020,"children":1021},{},[1022,1026,1027,1033,1035,1041,1043,1049,1050,1056,1058,1064,1066,1072,1074,1079,1080,1083],{"type":211,"tag":251,"props":1023,"children":1024},{},[1025],{"type":217,"value":512},{"type":217,"value":496},{"type":211,"tag":368,"props":1028,"children":1030},{"className":1029},[],[1031],{"type":217,"value":1032},"r4",{"type":217,"value":1034}," is ",{"type":211,"tag":368,"props":1036,"children":1038},{"className":1037},[],[1039],{"type":217,"value":1040},"gp",{"type":217,"value":1042}," (globals), ",{"type":211,"tag":368,"props":1044,"children":1046},{"className":1045},[],[1047],{"type":217,"value":1048},"r5",{"type":217,"value":1034},{"type":211,"tag":368,"props":1051,"children":1053},{"className":1052},[],[1054],{"type":217,"value":1055},"tp",{"type":217,"value":1057}," (thread/task pointer). ",{"type":211,"tag":368,"props":1059,"children":1061},{"className":1060},[],[1062],{"type":217,"value":1063},"r0",{"type":217,"value":1065}," is hard-wired to zero and requires no setup. Startup uses ",{"type":211,"tag":368,"props":1067,"children":1069},{"className":1068},[],[1070],{"type":217,"value":1071},"movhi hi, r0, r4 ; movea lo, r4, r4",{"type":217,"value":1073}," to load ",{"type":211,"tag":368,"props":1075,"children":1077},{"className":1076},[],[1078],{"type":217,"value":1040},{"type":217,"value":812},{"type":211,"tag":951,"props":1081,"children":1082},{},[],{"type":211,"tag":332,"props":1084,"children":1087},{"alt":1085,"src":1086},"Typical RH850 startup code setting gp and tp.","/images/knowledge-base/reverse-engineering/ghidra-rh850-startup.png",[],{"type":211,"tag":219,"props":1089,"children":1090},{},[1091],{"type":217,"value":1092},"Configure the registers once at the reset entry function. Edit Register Values can be set to propagate forward through called functions, which avoids repeating the setup on every callee.",{"type":211,"tag":231,"props":1094,"children":1096},{"id":1095},"finding-the-uds-handlers",[1097],{"type":217,"value":1098},"Finding the UDS Handlers",{"type":211,"tag":219,"props":1100,"children":1101},{},[1102,1104,1110],{"type":217,"value":1103},"A practical entry point on a stripped image is to search for constants that the firmware is required to contain. The negative response codes from the ",{"type":211,"tag":1105,"props":1106,"children":1107},"a",{"href":72},[1108],{"type":217,"value":1109},"UDS chapter",{"type":217,"value":1111}," are suitable for this: every ECU that implements UDS must return them, the values are fixed by ISO 14229, and they appear as immediate constants in the handler code.",{"type":211,"tag":219,"props":1113,"children":1114},{},[1115,1117,1122],{"type":217,"value":1116},"Useful constants for ",{"type":211,"tag":251,"props":1118,"children":1119},{},[1120],{"type":217,"value":1121},"Search, For Scalars",{"type":217,"value":1123},":",{"type":211,"tag":243,"props":1125,"children":1126},{},[1127,1138,1149,1160,1171,1182,1193],{"type":211,"tag":247,"props":1128,"children":1129},{},[1130,1136],{"type":211,"tag":368,"props":1131,"children":1133},{"className":1132},[],[1134],{"type":217,"value":1135},"0x35",{"type":217,"value":1137}," invalidKey",{"type":211,"tag":247,"props":1139,"children":1140},{},[1141,1147],{"type":211,"tag":368,"props":1142,"children":1144},{"className":1143},[],[1145],{"type":217,"value":1146},"0x33",{"type":217,"value":1148}," securityAccessDenied",{"type":211,"tag":247,"props":1150,"children":1151},{},[1152,1158],{"type":211,"tag":368,"props":1153,"children":1155},{"className":1154},[],[1156],{"type":217,"value":1157},"0x12",{"type":217,"value":1159}," subFunctionNotSupported",{"type":211,"tag":247,"props":1161,"children":1162},{},[1163,1169],{"type":211,"tag":368,"props":1164,"children":1166},{"className":1165},[],[1167],{"type":217,"value":1168},"0x13",{"type":217,"value":1170}," incorrectMessageLengthOrInvalidFormat",{"type":211,"tag":247,"props":1172,"children":1173},{},[1174,1180],{"type":211,"tag":368,"props":1175,"children":1177},{"className":1176},[],[1178],{"type":217,"value":1179},"0x11",{"type":217,"value":1181}," serviceNotSupported",{"type":211,"tag":247,"props":1183,"children":1184},{},[1185,1191],{"type":211,"tag":368,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":217,"value":1190},"0x22",{"type":217,"value":1192}," conditionsNotCorrect",{"type":211,"tag":247,"props":1194,"children":1195},{},[1196,1202],{"type":211,"tag":368,"props":1197,"children":1199},{"className":1198},[],[1200],{"type":217,"value":1201},"0x7F",{"type":217,"value":1203}," negative response marker, often written into the response buffer before transmit",{"type":211,"tag":219,"props":1205,"children":1206},{},[1207],{"type":211,"tag":332,"props":1208,"children":1211},{"alt":1209,"src":1210},"Search For Scalars dialog with 0x35 entered, and the results window showing several hits in the application region.","/images/knowledge-base/reverse-engineering/ghidra-nrc-search.png",[],{"type":211,"tag":219,"props":1213,"children":1214},{},[1215,1217,1223],{"type":217,"value":1216},"Select a value, run the search, and walk the xrefs back. An NRC literal sits in a specific service handler. Each service handler is reached from a dispatcher, which is either a ",{"type":211,"tag":368,"props":1218,"children":1220},{"className":1219},[],[1221],{"type":217,"value":1222},"switch",{"type":217,"value":1224}," on the SID or an indexed call through a table. The dispatcher is reached from the diagnostic message receive path. Two hops back from one NRC is generally sufficient to reach the top of the diagnostic stack, from which every service handler can be enumerated.",{"type":211,"tag":219,"props":1226,"children":1227},{},[1228],{"type":211,"tag":332,"props":1229,"children":1232},{"alt":1230,"src":1231},"Xref chain from an NRC literal back through a per-service handler to the dispatcher table.","/images/knowledge-base/reverse-engineering/ghidra-nrc-xref.png",[],{"type":211,"tag":231,"props":1234,"children":1236},{"id":1235},"typical-configuration-structures",[1237],{"type":217,"value":1238},"Typical Configuration Structures",{"type":211,"tag":219,"props":1240,"children":1241},{},[1242],{"type":217,"value":1243},"Much of an ECU's behaviour is driven by static tables of structures: UDS dispatchers, CAN message descriptors, RTOS task lists. Defining the structure once in the Data Type Manager and applying it to the table base causes the Listing to label every field of every entry, which generally yields a full inventory of the relevant subsystem in a single pass.",{"type":211,"tag":1245,"props":1246,"children":1248},"h3",{"id":1247},"uds-handlers",[1249],{"type":217,"value":1250},"UDS Handlers",{"type":211,"tag":219,"props":1252,"children":1253},{},[1254],{"type":217,"value":1255},"The UDS handler table commonly contains fields like:",{"type":211,"tag":243,"props":1257,"children":1258},{},[1259,1272,1283,1302,1314,1319],{"type":211,"tag":247,"props":1260,"children":1261},{},[1262,1264,1270],{"type":217,"value":1263},"SID (",{"type":211,"tag":368,"props":1265,"children":1267},{"className":1266},[],[1268],{"type":217,"value":1269},"u8",{"type":217,"value":1271},")",{"type":211,"tag":247,"props":1273,"children":1274},{},[1275,1277,1282],{"type":217,"value":1276},"minimum request length (",{"type":211,"tag":368,"props":1278,"children":1280},{"className":1279},[],[1281],{"type":217,"value":1269},{"type":217,"value":1271},{"type":211,"tag":247,"props":1284,"children":1285},{},[1286,1288,1293,1294,1300],{"type":217,"value":1287},"session mask (",{"type":211,"tag":368,"props":1289,"children":1291},{"className":1290},[],[1292],{"type":217,"value":1269},{"type":217,"value":660},{"type":211,"tag":368,"props":1295,"children":1297},{"className":1296},[],[1298],{"type":217,"value":1299},"u16",{"type":217,"value":1301},"): the sessions in which the service is permitted",{"type":211,"tag":247,"props":1303,"children":1304},{},[1305,1307,1312],{"type":217,"value":1306},"security mask (",{"type":211,"tag":368,"props":1308,"children":1310},{"className":1309},[],[1311],{"type":217,"value":1269},{"type":217,"value":1313},"): the required security levels",{"type":211,"tag":247,"props":1315,"children":1316},{},[1317],{"type":217,"value":1318},"handler function pointer",{"type":211,"tag":247,"props":1320,"children":1321},{},[1322],{"type":217,"value":1323},"pointer to further configuration of sub-function handlers",{"type":211,"tag":219,"props":1325,"children":1326},{},[1327],{"type":217,"value":1328},"Sometimes the table contains the SIDs directly, or those are stored separately.",{"type":211,"tag":219,"props":1330,"children":1331},{},[1332],{"type":211,"tag":332,"props":1333,"children":1336},{"alt":1334,"src":1335},"UDS handler table struct applied to the table base, with each entry's SID, masks and handler pointer labelled.","/images/knowledge-base/reverse-engineering/ghidra-uds-handler-table.png",[],{"type":211,"tag":1245,"props":1338,"children":1340},{"id":1339},"can-parsing",[1341],{"type":217,"value":1342},"CAN Parsing",{"type":211,"tag":219,"props":1344,"children":1345},{},[1346],{"type":217,"value":1347},"The CAN parsing table typically contains a list of signals. For each signal the bit layout inside a message is specified. Functions that pack or unpack CAN messages typically contain multiple calls to a generic packer/unpacker function with the signal IDs belonging to that message.",{"type":211,"tag":219,"props":1349,"children":1350},{},[1351],{"type":211,"tag":332,"props":1352,"children":1355},{"alt":1353,"src":1354},"CAN parsing table defining the signals.","/images/knowledge-base/reverse-engineering/ghidra-can-table.png",[],{"type":211,"tag":1245,"props":1357,"children":1359},{"id":1358},"rtos-threads",[1360],{"type":217,"value":1361},"RTOS Threads",{"type":211,"tag":219,"props":1363,"children":1364},{},[1365],{"type":217,"value":1366},"Automotive ECUs run an OSEK or AUTOSAR OS variant in which tasks are statically configured at build time. The task table is fixed in flash and commonly contains one or more of the following values per task:",{"type":211,"tag":243,"props":1368,"children":1369},{},[1370,1375,1380,1385],{"type":211,"tag":247,"props":1371,"children":1372},{},[1373],{"type":217,"value":1374},"task ID or name pointer",{"type":211,"tag":247,"props":1376,"children":1377},{},[1378],{"type":217,"value":1379},"priority",{"type":211,"tag":247,"props":1381,"children":1382},{},[1383],{"type":217,"value":1384},"stack base pointer and stack size",{"type":211,"tag":247,"props":1386,"children":1387},{},[1388],{"type":217,"value":1389},"entry function pointer",{"type":211,"tag":219,"props":1391,"children":1392},{},[1393],{"type":217,"value":1394},"Locating the task table gives the full set of periodic and event-driven entry points in the firmware. Each entry function is a useful starting point for understanding what the ECU does at runtime, and the priorities indicate which tasks the scheduler favours under load.",{"type":211,"tag":219,"props":1396,"children":1397},{},[1398],{"type":211,"tag":332,"props":1399,"children":1402},{"alt":1400,"src":1401},"RTOS task table struct applied to the table base, with each task's priority, stack pointer and entry function labelled.","/images/knowledge-base/reverse-engineering/ghidra-rtos-tasks.png",[],{"type":211,"tag":231,"props":1404,"children":1406},{"id":1405},"autosar",[1407],{"type":217,"value":1408},"AUTOSAR",{"type":211,"tag":219,"props":1410,"children":1411},{},[1412],{"type":217,"value":1413},"Most automotive firmware produced in the last decade conforms to AUTOSAR Classic. The specification defines hundreds of modules with fixed APIs, fixed numeric IDs, and standardised error-reporting patterns. This regularity is useful for reverse engineering.",{"type":211,"tag":1245,"props":1415,"children":1417},{"id":1416},"det_reporterror",[1418],{"type":217,"value":1419},"Det_ReportError",{"type":211,"tag":219,"props":1421,"children":1422},{},[1423,1429,1431,1437,1439,1445,1447,1453],{"type":211,"tag":368,"props":1424,"children":1426},{"className":1425},[],[1427],{"type":217,"value":1428},"Det_ReportError(ModuleId, InstanceId, ApiId, ErrorId)",{"type":217,"value":1430}," is the most productive of the AUTOSAR call sites to exploit. Every AUTOSAR module is required to call it on every detectable error, with all four arguments as compile-time constants. The AUTOSAR Standardized Names document assigns each module a number (CAN driver = 80, COM = 50, PduR = 51, EcuM = 10, and so on), and each public API within a module has its own ID. A call such as ",{"type":211,"tag":368,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":217,"value":1436},"Det_ReportError(80, 0, 6, 1)",{"type":217,"value":1438}," therefore identifies the CAN driver module, instance 0, API 6 (",{"type":211,"tag":368,"props":1440,"children":1442},{"className":1441},[],[1443],{"type":217,"value":1444},"Can_Write",{"type":217,"value":1446},"), error 1 (",{"type":211,"tag":368,"props":1448,"children":1450},{"className":1449},[],[1451],{"type":217,"value":1452},"CAN_E_PARAM_POINTER",{"type":217,"value":1454},"), which is sufficient to name both the surrounding function and the error path.",{"type":211,"tag":219,"props":1456,"children":1457},{},[1458],{"type":217,"value":1459},"Depending on the AUTOSAR OS implementation, there might be leftovers of this Det_ReportError. Sometimes it's stripped out completely, but often the call to Det_ReportError remains while only the logging or debugging functionality is removed from the function body.",{"type":211,"tag":219,"props":1461,"children":1462},{},[1463],{"type":217,"value":1464},"If the function is still present in the binary, it's often one of the most referenced/called functions. It can be easily found by going through the list of functions sorted by Reference Count.",{"type":211,"tag":219,"props":1466,"children":1467},{},[1468],{"type":211,"tag":332,"props":1469,"children":1472},{"alt":1470,"src":1471},"Decompiler view of a Det_ReportError call site with the four constant arguments inlined, and a comment showing the looked-up module and API name.","/images/knowledge-base/reverse-engineering/ghidra-det-reporterror.png",[],{"type":211,"tag":219,"props":1474,"children":1475},{},[1476,1478,1483,1485,1490,1492,1495,1497,1500],{"type":217,"value":1477},"The process of determining which function called Det_ReportError can be automated with a Ghidra script that walks every xref to ",{"type":211,"tag":368,"props":1479,"children":1481},{"className":1480},[],[1482],{"type":217,"value":1419},{"type":217,"value":1484},", reads the four constants from the argument registers (or the stack, on architectures that pass them there), looks the IDs up in tables transcribed from the AUTOSAR specification, and renames the surrounding function. A complete implementation, including the lookup tables and the renamer, is published as ",{"type":211,"tag":368,"props":1486,"children":1488},{"className":1487},[],[1489],{"type":217,"value":196},{"type":217,"value":1491}," ",{"type":211,"tag":225,"props":1493,"children":1494},{"id":196},[],{"type":217,"value":1496},". The underlying methodology is described in the SSTIC 2023 talk by Tillequin and Charron ",{"type":211,"tag":225,"props":1498,"children":1499},{"id":201},[],{"type":217,"value":812},{"type":211,"tag":219,"props":1502,"children":1503},{},[1504,1506,1512,1513,1519,1520,1526,1527,1533,1535,1541,1543,1549],{"type":217,"value":1505},"The same approach applies to any AUTOSAR API that takes constant module, API, or error IDs as arguments: ",{"type":211,"tag":368,"props":1507,"children":1509},{"className":1508},[],[1510],{"type":217,"value":1511},"Dem_ReportErrorStatus",{"type":217,"value":652},{"type":211,"tag":368,"props":1514,"children":1516},{"className":1515},[],[1517],{"type":217,"value":1518},"Det_ReportRuntimeError",{"type":217,"value":652},{"type":211,"tag":368,"props":1521,"children":1523},{"className":1522},[],[1524],{"type":217,"value":1525},"Com_SendSignal",{"type":217,"value":687},{"type":211,"tag":368,"props":1528,"children":1530},{"className":1529},[],[1531],{"type":217,"value":1532},"Com_ReceiveSignal",{"type":217,"value":1534}," (signal IDs are constants in generated code), ",{"type":211,"tag":368,"props":1536,"children":1538},{"className":1537},[],[1539],{"type":217,"value":1540},"PduR_RxIndication",{"type":217,"value":1542}," (PDU IDs are constants), and the ",{"type":211,"tag":368,"props":1544,"children":1546},{"className":1545},[],[1547],{"type":217,"value":1548},"EcuM_*",{"type":217,"value":1550}," state APIs. Each labelled call site provides a fixed reference point that can be used to name a number of surrounding functions.",{"type":211,"tag":231,"props":1552,"children":1554},{"id":1553},"references",[1555],{"type":217,"value":1556},"References",{"type":211,"tag":1558,"props":1559,"children":1560},"chapter-references",{},[],{"title":184,"searchDepth":16,"depth":16,"links":1562},[1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1578,1581],{"id":233,"depth":16,"text":236},{"id":339,"depth":16,"text":342},{"id":404,"depth":16,"text":407},{"id":435,"depth":16,"text":438},{"id":553,"depth":16,"text":556},{"id":606,"depth":16,"text":609},{"id":705,"depth":16,"text":708},{"id":781,"depth":16,"text":784},{"id":827,"depth":16,"text":830},{"id":1095,"depth":16,"text":1098},{"id":1235,"depth":16,"text":1238,"children":1574},[1575,1576,1577],{"id":1247,"depth":22,"text":1250},{"id":1339,"depth":22,"text":1342},{"id":1358,"depth":22,"text":1361},{"id":1405,"depth":16,"text":1408,"children":1579},[1580],{"id":1416,"depth":22,"text":1419},{"id":1553,"depth":16,"text":1556},"markdown","content:7.knowledge-base:3.reverse-engineering:3.ghidra.md","content","md",1779615358732]