Forum: Mikrocontroller und Digitale Elektronik Programm aus PIC12F508 laden und verstehen


von Olli Z. (z80freak)



Lesenswert?

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?

von H. H. (Gast)


Lesenswert?

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.

von Andras H. (kyrk)


Lesenswert?

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?

von H. H. (Gast)


Lesenswert?

Andras H. schrieb:
> Habe ich da etwas übersehen?

Nach 1ffh kommt 0h.

von Andras H. (kyrk)


Lesenswert?

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

von Andras H. (kyrk)


Lesenswert?

Das Ding macht nichts? Sehe ich das richtig? Die SW ist meiner Meinung 
nach Unsinn.

von Andras H. (kyrk)


Lesenswert?

Habe eben mit MPLAB simuliert. Das Ding macht ja nix. Hälfte der Code 
ist meiner Meinung nach nur als Platzhalter da.

von Cyblord -. (cyblord)


Lesenswert?

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.

von Dieter S. (ds1)


Lesenswert?

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.

von H. H. (Gast)


Lesenswert?

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.

von Stephan S. (uxdx)


Lesenswert?

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

von H. H. (Gast)


Lesenswert?

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.

von Andras H. (kyrk)


Lesenswert?

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.

von H. H. (Gast)


Lesenswert?

In der vorliegenden Anwendung ist der Kalibrierwert egal, der µC läuft 
ja mit 4 MHz Keramikresonator.

von Olli Z. (z80freak)



Lesenswert?

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.

: Bearbeitet durch User
von H. H. (Gast)


Lesenswert?

Nirgendwo im Code wird an den GPIO gewackelt.

von Klaus K. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Olli Z. (z80freak)


Lesenswert?

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.

von Olli Z. (z80freak)


Lesenswert?

H. H. schrieb:
> Nirgendwo im Code wird an den GPIO gewackelt.

Ich bin komplett be Euch und versteh es selbst nicht...

von Klaus K. (Gast)


Lesenswert?

> 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?!

von Oliver F. (ogf)


Lesenswert?

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.

von H. H. (Gast)


Lesenswert?

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.

von Dieter S. (ds1)


Lesenswert?

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?"

von Olli Z. (z80freak)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von Oliver F. (ogf)


Lesenswert?

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

von Olli Z. (z80freak)



Lesenswert?

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.

: Bearbeitet durch User
von Olli Z. (z80freak)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Lieber Moderator, lösche bitte den vorherigen Beitrag von mir, ich habe 
ihn im falschen Thread platziert. Der richtige ist hier 
Beitrag "Re: Funktion Reifendruckanlerngerät EL-50448; OEC-T5; Welches Bauelement ist das?"
Danke!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.