Ich habe in einem anderen Beitrag hier
(Beitrag "Funktion Reifendruckanlerngerät EL-50448; OEC-T5; Welches Bauelement ist das?") zu einem RDSK-Trigger
Gerät Fragen zum darauf befindlichen PIC Mikrocontroller. Das RDSK-Thema
ist aber vermutlich zu speziell, daher frage ich hier nochmal allgemein.
Herzstück hier ist ein PIC12F508I auf dem Board. Den habe ich
runtergelötet und mit einem Flash-Programmer ausgelesen.
Laut Datenblatt hat dieser PIC einen Flash-Speicher von 512 words, also
1024 Bytes (0x400) und 25 Bytes RAM. Das BIN und HEX davon habe ich ins
ZIP eingefügt. Ebenso ein Disassembly (mit PICDisasm erzeugt).
Wenn jetzt hier keine speziellen Protections greifen, dann dürfte das
wirklich der komplette Code sein.
Vom Board her konnte ich ermitteln das folgende IO-Pins belegt sind:
* OSC1/OSC2 gehen direkt zu einem 4MHz Oszillator.
* GP0 konnte ich noch nicht ermitteln, wüsste auch grad nicht wozu es
gut sein sollte da das Gerät nicht mehr Funktionen hat.
* GP1 geht über einen Transistor auf ein LCR, bestehend aus Antenne,
Kondensator und Widerstand, nach Masse. Hierüber wird gesendet (125 kHz
LF-Band)
* GP2 geht über einen 220 Ohm auf die Kathode einer grünen LED, welche
den Sendebetrieb anzeigt (flackert beim drücken von T1)
* GP3 kommt über einen 4,7k von einem Taster T1 welcher auf (+) gelegt
ist, er erzeugt also eine steigende Flanke.
Nun versuche ich aus der Software schlau zu werden und da könnte ich was
Hilfe gebrauchen da ich mich mit den PICs überhaupt nicht auskenne.
Das FSR-Register sollte hier wohl keine Rolle spielen, da der 12F508 nur
eine Speicherbank hat? Der Reset-Vector ist immer 0x0000, hier startet
die Softwareausführung also.
Auf Adresse 0x1FF soll beim 12F508 ein MOVLW Kommando mit dem Wert für
die interne Oszillator-Kalibration liegen. Dieser liegt in meinem Dump
jedoch auf 0x3FF und hat den Wert 0x2A.
Die Register liegen im RAM (Register File Map). Ich habe mit dann einen
PIC-Simulator runtergeladen (https://gputils.sourceforge.io/) und
versucht das alles nachzuvollziehen und hier ergeben sich die ersten
Fragen:
Der erste Befehl ist laut Datenblatt die letzte Speicheradresse der
ersten Page, dort wird das einzige Register "W" mit dem Wert 0x2A
geladen. Danach geht der Programm-Counter automatisch auf 0x0000 und
fängt an dort den Code auszuführen. Gleich die erste Anweisung ist ein
NOP (warum nur?). Zunächst wird dann das OSCCAL-Register mit dem Wert
aus W aus 0x2A beladen. Das kann ich im Simulator gut nachvollziehen.
Dann überspringt der Code einige Stellen die eher nach Daten als nach
Programmcode aussehen um an Postion 0x0014 weiter zu machen. Dort ruft
er eine Subroutine auf (LADR_0x0016) aus der er irgendwann mit einem
return zurückkehren wird um dann anschließend an die Adresse LADR_0x0148
zu springen. Ab dieser Adresse stehen aber nur noch NOPs im
Programmcode. Die führt er bis zuende aus um dann vermutlich wieder auf
0x0000 zu gehen und das Programm von vorn zu starten?
Der Code ab 0x0016 sieht aus wie eine Initialisierung der GPIOs. Hier
wird das GPIO-Register (RAM Adresse 0x06) zunächst auf 0b00000100
eingestellt, was zur Folge hat das GP2 auf HIGH geht. Dadurch ist die
grüne LED erstmal aus. Das nachfolgende MOVLW 0x08 und TRIS GPIO setzt
wohl den GP3 (Taster-Eingang) auf Tri-State.
Nun wird der zuvor in W geladene Wert 0b01001111 mit dem "OPTION" Befehl
in das gleichnamige Register geschrieben. Das bedeutet:
- setze den Prescaler des WDT auf 1:128
- setzte Wakeup auf Pin-Änderung von GP0, GP1 oder GP3 (hier sitzt der
Taster)
Laut Datenblatt liest der Chip nach dem RESET das Configuration Word von
der Speicheradresse 0x3FF. Hier steht im Dump ein 0b00001100 was soviel
bedeutet wie "Use GP3 as input", "Use LP oscillator (200 kHz)", "Copy
Protection OFF" und "Watchdog-Timer enabled". Das bedeutet das nach 18
ms nach dem POR der Watchdog auslöst. Ein solcher Auslöser ist immer ein
RESET, es gibt also keine speziellen Watchdog-Vectoren/Code.
Soweit glaube ich noch mit zu kommen... aber jetzt geht es mit dieser
ominösen Schleife los:
1
MOVLW 0x07 ; b'00000111' d'007'
2
MOVWF FSR
3
CLRF INDF
4
LADR_0x001F
5
INCF FSR,F
6
CLRF INDF
7
MOVLW 0xFF ; b'11111111' d'255'
8
SUBWF FSR,W
9
BTFSS STATUS,Z
10
GOTO LADR_0x001F
11
RETLW 0x00 ; b'00000000' d'000'
12
MOVWF LRAM_0x09
Was genau macht dieser Code? Und sehe ich das richtig das nach der
Schleife ein einfacher Return "RETLW 0x00" steht welcher die Subroutine
und damit dann das Programm faktisch beendet? Das kann es ja nicht
gewesen sein. Wie wird der code danach ausgeführt?
Olli Z. schrieb:> Soweit glaube ich noch mit zu kommen... aber jetzt geht es mit dieser> ominösen Schleife los:> MOVLW 0x07 ; b'00000111' d'007'> MOVWF FSR> CLRF INDF> LADR_0x001F> INCF FSR,F> CLRF INDF> MOVLW 0xFF ; b'11111111' d'255'> SUBWF FSR,W> BTFSS STATUS,Z> GOTO LADR_0x001F> RETLW 0x00 ; b'00000000' d'000'> MOVWF LRAM_0x09>> Was genau macht dieser Code?
Der löscht die GPRs.
> Und sehe ich das richtig das nach der> Schleife ein einfacher Return "RETLW 0x00" steht welcher die Subroutine> und damit dann das Programm faktisch beendet? Das kann es ja nicht> gewesen sein. Wie wird der code danach ausgeführt?
Es geht danach einfach im Hauptprogamm weiter.
H. H. schrieb:> Es geht danach einfach im Hauptprogamm weiter.
Der Hauptprogramm ist dann aber:
GOTO LADR_0x0148
was zu NOPs führt. Am ende aber ist ein
MOVLW 0x2A ; b'00101010' d'042' "*"
das ist doch aber die Osszilator Kalibration.
Rest von Code sehe ich nicht angesprungen. Habe ich da etwas übersehen?
H. H. schrieb:> Nach 1ffh kommt 0h.
Ja klar. So hat man damals die Osszicaltor Trimmungswerte übergeben. Ich
glaube bei einigen PICs war der Resetvector nicht 0 sondern 0x1FFF.
Damit wurde W mit den Trimmwerten geladen, und man musste das
abspeichern. Egal, das sind jetzt Detail Sachen.
Wenn ich mir den Code angucke, macht der meist garnix. Hälfte sind
einfach NOPs und bisschen hin und her springen. Habe bestimmte etwas
übersehen, aber so wie ich es verstanden habe, macht der etwas am
Anfang, dann kommen irgendwie viele NOPs, dann überrollt der PC wieder
auf 0 und fängt von vorne wieder an.
Hier bin ich unsicher:
BTFSS STATUS,Z
GOTO LADR_0x001F
RETLW 0x00 ; b'00000000' d'000'
MOVWF LRAM_0x09
Sprint der RETLW wieder auf
GOTO LADR_0x0148
, richtig? Es gibt hier noch keinen Stack wo man die Rücksprungadressen
gespeichert hat. Das Ding meine ich hatte einen Hardcoded Stack von 3
und man konnte nur da für den CALL verwenden.
Wenn das so der Fall ist, lässt sich der Code so vereinfachen:
; Reset-Vector
NOP
MOVWF OSCCAL
GOTO LADR_0x0014
LADR_0x0014
CALL LADR_0x0016
GOTO DelayShort
LADR_0x0016
MOVLW 0x04 ; b'00000100' d'004'
MOVWF GPIO
MOVLW 0x08 ; b'00001000' d'008'
TRIS GPIO
MOVLW 0x4F ; b'01001111' d'079' "O"
OPTION
MOVLW 0x07 ; b'00000111' d'007'
MOVWF FSR
CLRF INDF
LADR_0x001F
INCF FSR,F
CLRF INDF
MOVLW 0xFF ; b'11111111' d'255'
SUBWF FSR,W
BTFSS STATUS,Z
GOTO LADR_0x001F
RETLW 0x00 ; b'00000000' d'000'
DelayShort
NOP
MOVLW 0x2A ; b'00101010' d'042' "*"
End
Andras H. schrieb:> Habe eben mit MPLAB simuliert. Das Ding macht ja nix. Hälfte der Code> ist meiner Meinung nach nur als Platzhalter da.
Lustiger Zufall. Genau das Gleiche trifft auf die meisten Leute hier im
Forum zu.
Bist Du Dir sicher dass das Auslesen ohne Fehler funktioniert hat? Womit
hast Du ausgelesen, der PICkit ist nach meinen bisherigen Erfahrungen
zuverlässig.
Ich frage weil der Code meiner Meinung nach wenig Sinn ergibt. Es gibt
bei dem Code auch nichts zu verschleiern was eine eventuell absichtlich
unsinnige Struktur erkären würde. Die erzeugte Modulation kann man ja
einfach mit einem Logic-Analyzer abgreifen und damit weiss man bereits
alles, wie genau das im Code gemacht wird spielt keine Rolle.
Andras H. schrieb:> Am ende aber ist ein> MOVLW 0x2A ; b'00101010' d'042' "*"> das ist doch aber die Osszilator Kalibration.
Nö, das ist ganz normaler Code.
Stephan S. schrieb:> H. H. schrieb:>> Andras H. schrieb:>>> Am ende aber ist ein>>> MOVLW 0x2A ; b'00101010' d'042' "*">>> das ist doch aber die Osszilator Kalibration.>>>> Nö, das ist ganz normaler Code.>> auch bei PIC12F508 gilt> https://www.sprut.de/electronic/pic/projekte/osccal/osccal.htm
Und hier eben ganz normaler Code, kein Kalibrierwert.
H. H. schrieb:> Und hier eben ganz normaler Code, kein Kalibrierwert.
Also ja ist halt normaler Code. Aber der PIC kommt so aus dem Werk
vorprogrammiert, dass da ein movlw Befehl liegt der einen Wert in W
lädt. Der Wärt wird ja im Werk ermittelt. Beim flashen, muss der Flasher
den Wert auslesen, und wieder reinschreiben. Sonst ist der wer, und man
muss noch einmal den irgendwie (wie?) ermitteln. Ist nicht so schlimm.
Der Code erzeugt aber das Signal an der Antenne und am GP gemessen.
Ausgelesen habe ich mit einem hochwertigen RT809H Flash Programmer,
mehrmals, kam immer das gleiche Ergebnis. Habe noch einen anderen
Trigger, kleinerer Buart, hat das gleiche PIC und die gleiche Software.
Einen partiellen Kopierschutz für den Code gibt es ja nicht. Es wäre
jetzt noch eine Option für mich einen neuen PIC mit dem Code zu
programmieren und zu schauen ob dieser die gleiche Funktion erfüllt.
Olli Z. schrieb:> Laut Datenblatt hat dieser PIC einen Flash-Speicher von 512 words, also> 1024 Bytes (0x400)
Nö, weil bei dem Controller ist ein instruction-word zwölf und nicht
sechszehn bit breit.
Klaus K. schrieb:> Olli Z. schrieb:>>> Laut Datenblatt hat dieser PIC einen Flash-Speicher von 512 words, also>> 1024 Bytes (0x400)>> Nö, weil bei dem Controller ist ein instruction-word zwölf und nicht> sechszehn bit breit.
Wenn Du einen nativen 12 Bit Speicher kennst... also wird auf 16
gepadded und meine Aussage stimmt wieder.
> Wenn Du einen nativen 12 Bit Speicher kennst... also wird auf 16> gepadded und meine Aussage stimmt wieder.
Der Speicher ist native 12 bit, Blockbild nicht beachtet?!
Leider fehlt das Configuration Word im Hexfile. Aber der Prozessor ist
vermutlich einfach Code Protected, deshalb stehen nach dem Auslesen von
0x040 bis 0x01fe nur Nullen (Kapitel 7.10 im Datenblatt).
7.10 Program Verification/Code Protection
If the code protection bit has not been programmed, the on-chip program
memory can be read out for verification purposes.
The first 64 locations and the last location (OSCCAL) can be read,
regardless of the code protection bit setting.
The last memory location can be read regardless of the code protection
bit setting on the PIC12F508/509/16F505 devices.
Oliver F. schrieb:> The first 64 locations and the last location (OSCCAL) can be read,> regardless of the code protection bit setting.
Man lernt nie aus.
Danke für die Info.
Oliver F. schrieb:> Leider fehlt das Configuration Word im Hexfile. Aber der Prozessor ist> vermutlich einfach Code Protected, deshalb stehen nach dem Auslesen von> 0x040 bis 0x01fe nur Nullen (Kapitel 7.10 im Datenblatt).
Das erklärt warum der Code keinen Sinn macht. Allerdings frage ich mich
warum das verwendete Tool zum Auslesen des PIC die Code Protection nicht
anzeigt, Zugriff auf das Configuration Word hat es ja.
Ist das Code Protection Word eventuell die letzten Bytes E5 0F im
Binary von hier (tpms-trigger-tool_small.zip) ?
Beitrag "Re: Funktion Reifendruckanlerngerät EL-50448; OEC-T5; Welches Bauelement ist das?"
Laut diesem Datenblatt
http://ww1.microchip.com/downloads/en/DeviceDoc/41227B.pdf
ist das im "Configuration Word" enthalten. Dieses liegt beim 12F508 an
der statischen Adresse 0x3FF und ist nachdem einschalten vorhanden bis
der erste PC increment stattfindet.
Zuständig ist Bit 3.
Im Dump ist das der Teil wo dieser als MOVLW 0x2A interpretierte Befehl.
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
000003F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2A 0C
..............*.
Ich meine 0x2A wäre das OSCCAL Byte und 0x0C müsste das Configuration
word sein. 0x0C wäre 0b0000 1100 und somit wäre das CP-Bit gesetzt, was
bedeuten würde der Chip hätte keine Copy protection.
Aber die Ausführungen meines Namensvetters sind absolut schlüssig und
die einzige Erklärung für den merkwürdig funktionslosen Code mit den
vielen NOPs.
Jetzt zu fragen ob man diesen alten PIC evtl. knacken kann spare ich
mir, das wäre die Mühe nicht wert. Ich werde wohl meinen eigenen Code
schreiben müssen und ihn dann in dem Tool zum laufen bringen.
Der Befehl an Adresse 0x01FF (= Adresse 0x03FE im Hexfile) - MOVLW 0x2A
- ist der Kalibrierwert für den Oszillator.
Das Config Word steht im Flash an Adresse 0x03FF.
> Ist das Code Protection Word eventuell die letzten Bytes E5 0F im> Binary von hier (tpms-trigger-tool_small.zip) ?>> Beitrag "Re: Funktion Reifendruckanlerngerät EL-50448; OEC-T5; Welches Bauelement ist das?"
Das könnte durchaus sein. Wenn man es entsprechend interpretiert, kommt
etwas sinnvolles heraus:
0x0FE5 = 1111 1110 0101
1111 111 unbenutzte Bits
0 MCLRE GP3 ist digitaler Eingang, Reset intern erzeugt
0 CP Code Protection on
1 WDTE Watchdog Timer enabled
01 FOSC XT Oscillator
So, nun mal mit einem PICKit2 (Clone) - Guess what: "Protected"
Davon ab das es natürlich nicht lohnen wird, gäbe es nun zwei
Möglichkeiten doch an den Code zu kommen:
Hack-Methode 1) Decap vom Chip, Fuses localisieren, den Flash-Bereich
mit Tonband abdecken und UV-Licht schräg auf die Fuses geben um diese
zurück zu setzen.
Aufwand ist sehr hoch, Decap benötigt spezielle Chemikalien (einige
davon dienen auch zum Bau von Sprengstoffen, also nicht einfach
erhältlich) und man kann den Chip dabei schnell komplett ruinieren.
Hack-Methode 2) Ein interessanter Ansatz bei dem nicht der ganze Flash
gelöscht wird, sondern nur ein Teil, eine Bank. Dabei werden die Fuses
mit zurückgesetzt und man kann den Chip auslesen. Eine erweiterte Option
davon ist, in die erste Bank, in der sich normalerweise ein Bootloader
befindet, ein kleines Stück Dump-Software zu programmieren, welches dann
beim Reset den Inhalt des Flash auf einen IO-Port (bei größeren Chips
ein UART) pumpt.
Hat man dann noch einen zweiten Chip programmiert man alles bis auf den
Bootloader (1st Bank) mit NOP und schreibt den Dump-Code ans Ende des
Flash. Der Bootloader wird irgendwann an eine Speicherstelle springen wo
er normalerweise den Main-Code ausführt, dort führen ihn die NOPs dann
unweigerlich zum eigenen Trojaner-Code.
Durchführen kann man diesen partiellen Erase/Program nicht aus einem
MPLAB o.ä. sondern nur mit Big-Banging der Signale.
Methode 2 wäre nicht schlecht, aber der kleine 12F508 hat keine Banks
und keinen Bootloader, wird also vermutlich nicht funktionieren. Toll
wäre ja wenn man genau die ersten Bytes die man ohnehin frei auslesen
kann überschreiben könnte um an den Rest zu kommen. Laut Datenblatt hat
der PIC12F508 nur zwei Bulk-Erase Modes, die jeweils angestoßen, den
gesamten Chip leeren.
Ich habe mir das Timing mal etwas näher angesehen und folgendes daraus
ermittelt:
Modulationsverfahren: ASK
1 Impuls = 1 µS + 7 µS Pause (=125 kHz)
Symbole
K = 16 Pulse (120 µS) + 134 µS Pause
K' = 16 Pulse (120 µS) + 262 µS Pause
M = 32 Pulse (248 µS) + 262 µS Pause
M' = 32 Pulse (248 µS) + 138 µS Pause
L = 48 Pulse (376 µS) + 376 µS Pause
Sendefolge = Sync + Data
Sync = 17 x K
Data = L K M M K K' M K M M' K' M K M M M M M K K M M M M
Das entspricht dem was Dieter schon vor langer Zeit in dem anderen
Thread mitteilte:
------------------------------------------
Schau Dir mal im Datenblatt des SP40T
(Infineon-SP400-15-11-DataSheet-v01_01-EN.pdf) auf Seite 54 "Figure 5-17
LF telegram modulated on a 125 kHz carrier" an. Das passt ganz gut:
- 17 Bits Preamble
- Synchronization pattern (laut Datenblatt fest vorgegeben)
- 32 Bits Daten (Manchester codiert)
------------------------------------------
Ein "K" entspricht also einem Bit.