Reverse engineering a CSL Dualcom GPRS part 15 – interpreting disassembly 2

In addition to finding the most frequently called functions, we should go through the memory map and identify importants parts of it.

1154 memory map

One part of this that is very important to how the device operates is the vector table, right at the bottom of the flash.

The vector table contains addresses that are called when certain interrupts are triggered. For these microcontrollers, this is structured like this:
Vector table

So we take a look right at the beginning of the disassembly:

00000        00          NOP             
00001        01          ADDW            AX,AX
00002        82          INC             C
00003        2084        SUBW            SP,#84H
00005        2086        SUBW            SP,#86H
00007        2088        SUBW            SP,#88H
00009        208a        SUBW            SP,#8AH
0000b        208c        SUBW            SP,#8CH
0000d        208e        SUBW            SP,#8EH
0000f        2090        SUBW            SP,#90H
00011        2092        SUBW            SP,#92H
00013        2001        SUBW            SP,#1H
00015        247d23      SUBW            AX,#237DH
00018        292494      MOV             A,9424H[C]
0001b        2096        SUBW            SP,#96H
0001d        203a        SUBW            SP,#3AH
0001f        21          ?               
00020        be20        MOVW            PM0,AX
00022        3c21        SUBC            A,#21H
00024        92          DEC             C
00025        225921      SUBW            AX,!2159H
00028        ba22        MOVW            [DE+22H],AX
0002a        9820        MOV             [SP+20H],A
0002c        00          NOP             
0002d        209a        SUBW            SP,#9AH
0002f        209c        SUBW            SP,#9CH
00031        209e        SUBW            SP,#9EH
00033        20a0        SUBW            SP,#0A0H
00035        20a2        SUBW            SP,#0A2H
00037        20a4        SUBW            SP,#0A4H
00039        20a6        SUBW            SP,#0A6H
0003b        205e        SUBW            SP,#5EH
0003d        23          SUBW            AX,BC
0003e        d7          RET             
0003f        226023      SUBW            AX,!2360H
00042        a820        MOVW            AX,[SP+20H]
00044        aa20        MOVW            AX,[DE+20H]
00046        ac20        MOVW            AX,[HL+20H]
00048        ae20        MOVW            AX,PM0
0004a        b020b2      DEC             !0B220H
0004d        20b4        SUBW            SP,#0B4H
0004f        20b6        SUBW            SP,#0B6H
00051        20b8        SUBW            SP,#0B8H
00053        20ba        SUBW            SP,#0BAH
00055        20ff        SUBW            SP,#0FFH

The disassembler has tried to disassemble when it shouldn’t – a common issue. Though, to be honest, it should know that this area is a vector table.

So if we re-organise the hex file into something a bit more readable, we get this:

0000 -> 0100 * RESET
0004 -> 2082
0006 -> 2086
0008 -> 2088
000A -> 208A
000C -> 208C
000E -> 208E
0010 -> 2090
0012 -> 2092
0014 -> 2401 * INTST3
0016 -> 237D * INTSR3
0018 -> 2429 * INTSRE3
001A -> 2094 
001C -> 2096 
001E -> 213A * INST0 
0020 -> 20BE * INTSR0 
0022 -> 213C * INTSRE0
0024 -> 2292 * INTST1
0026 -> 2159 * INTSR1
0028 -> 22BA * INTSRE1
002A -> 2098
002C -> 2000 * INTTM00
002E -> 209A
0030 -> 209C
0032 -> 209E
0034 -> 20A0
0036 -> 20A2
0038 -> 20A4
003A -> 20A6
003C -> 235E * INTST2
003E -> 22D7 * INTSR2
0040 -> 2360 * INTSRE2
0042 -> 20A8
0044 -> 20AA
0046 -> 20AC
0048 -> 20AE
004A -> 20B0
004C -> 20B2
004E -> 20B4
0050 -> 20B6
0052 -> 20B8
0054 -> 20BA

Notice how a lot of the addresses are just incrementing- 20AA, 20AC, 20AE. This is just a massive block of RETI instructions – i.e. the interrupt handler just returns immediately – it is not implemented.

02092        61fc        RETI            
02094        61fc        RETI            
02096        61fc        RETI            
02098        61fc        RETI            
0209a        61fc        RETI            
0209c        61fc        RETI            
0209e        61fc        RETI            
020a0        61fc        RETI            
020a2        61fc        RETI            
020a4        61fc        RETI            
020a6        61fc        RETI            
020a8        61fc        RETI            
020aa        61fc        RETI            
020ac        61fc        RETI            
020ae        61fc        RETI            
020b0        61fc        RETI            
020b2        61fc        RETI     

All of the vectors that are marked with an asterisk and with a name are implemented or used by the board. There are some important handlers here – mainly the serial IO.

Reset jumps to 0x100. I’ll save looking at that for another time – mostly the reset vector will be setting up buffers, memory, pointers, some checks.

You can also see we have groups of interrupt handlers for INTST* (transmit finished), INTSR* (receive finished), INTSRE* (receive error). These are for the the UARTs 0-3 respectively. Their implementation is very similar – let’s look at UART1 which is used for the GPRS modem.

// INTST1
	02292        c1          PUSH            AX
	02293        c3          PUSH            BC
	02294        c7          PUSH            HL
		02295        fbb6e0      MOVW            HL,!0E0B6H
		02298        afb4e0      MOVW            AX,!0E0B4H
		0229b        47          CMPW            AX,HL
		0229c        dd17        BZ              $22B5H
		0229e        dbb4e0      MOVW            BC,!0E0B4H
		022a1        49b8e4      MOV             A,0E4B8H[BC] 	// Get data from E4B8 using offset from E0B4
		022a4        9e44        MOV             SIO10,A 		// Move to serial data TX register
		022a6        a2b4e0      INCW            !0E0B4H	    // Increment the offset
		022a9        afb4e0      MOVW            AX,!0E0B4H
		022ac        440a04      CMPW            AX,#40AH 		// Is the offset greater than 1034? If so reset to 0
		022af        dc04        BC              $22B5H
		022b1        f6          CLRW            AX
		022b2        bfb4e0      MOVW            !0E0B4H,AX
	022b5        c6          POP             HL
	022b6        c2          POP             BC
	022b7        c0          POP             AX
	022b8        61fc        RETI  

Again – I’m not really currently interested in precise detail, just an idea of what is happening. This handler takes a byte from a buffer at 0xE4B8 and writes it into the transmit register. That buffer will appear elsewhere in the code and hint to us when something is being sent out of UART1.

We can then go through all of the other UART/serial functions and identify potential transmit/receive buffers.

Interestingly, INTST0 and INTST2 are just RETI instructions. Why do these not require a transmit empty interrupt handler? Is it handled in software elsewhere?

The next handler that stands out from the others is INTTM00. This is the timer interrupt for timer 0 which will fire when the timer hits a certain value.

// INTTM00        
	02000        c1          PUSH            AX
	02001        c3          PUSH            BC
	02002        c7          PUSH            HL
	02003        aefc        MOVW            AX,0FFFFCH
	02005        c1          PUSH            AX
	02006        a0b3f6      INC             !0F6B3H
	02009        8fb3f6      MOV             A,!0F6B3H
	0200c        5c03        AND             A,#3H
	0200e        4c03        CMP             A,#3H
	02010        df38        BNZ             $204AH
		02012        a0b4f6      INC             !0F6B4H
		02015        fcfc2801    CALL            !!128FCH
		02019        fc932601    CALL            !!12693H
		0201d        fcf22701    CALL            !!127F2H
		02021        f45c        CLRB            0FFE5CH

		02023        fc132a01    CALL            !!12A13H // 7SEG display
		02027        fcaa3201    CALL            !!132AAH // Buttons

		0202b        8fb4f6      MOV             A,!0F6B4H
		0202e        5c03        AND             A,#3H
		02030        dd08        BZ              $203AH
		02032        91          DEC             A
		02033        dd0b        BZ              $2040H
		02035        91          DEC             A
		02036        dd0e        BZ              $2046H
		02038        ef10        BR              $204AH
		0203a        fccbff00    CALL            !!0FFCBH // Analog
		0203e        ef0a        BR              $204AH
		02040        fcd13101    CALL            !!131D1H
		02044        ef04        BR              $204AH
		02046        fc063301    CALL            !!13306H
	0204a        fc742e01    CALL            !!12E74H
	0204e        fc84ff00    CALL            !!0FF84H
	02052        72          MOV             C,A
	02053        81          INC             A
	02054        dd24        BZ              $207AH
        02056        62          MOV             A,C
        02057        70          MOV             X,A
        02058        f1          CLRB            A
        02059        01          ADDW            AX,AX
        0205a        04b8f5      ADDW            AX,#0F5B8H
        0205d        16          MOVW            HL,AX
        0205e        f6          CLRW            AX
        0205f        b1          DECW            AX
        02060        bb          MOVW            [HL],AX
        02061        62          MOV             A,C
        02062        d1          CMP0            A
        02063        dd11        BZ              $2076H
        02065        2c11        SUB             A,#11H
        02067        dd05        BZ              $206EH
        02069        91          DEC             A
        0206a        dd06        BZ              $2072H
        0206c        ef0c        BR              $207AH
        0206e        e46a        ONEB            0FFE6AH
        02070        ef08        BR              $207AH
        02072        e46b        ONEB            0FFE6BH
        02074        ef04        BR              $207AH
        02076        fcf7fc00    CALL            !!0FCF7H
        0207a        c0          POP             AX
	0207b        befc        MOVW            0FFFFCH,AX
	0207d        c6          POP             HL
	0207e        c2          POP             BC
	0207f        c0          POP             AX

This looks like it is fired periodically. A number of counters are used so that portions of the subroutine are only run now and then.

There are a lot of calls, and if we look to them we can clearly identify function:

// Suspect from IO this is output to 7 seg
	12a13        d45d        CMP0            0FFE5DH
	12a15        f1          CLRB            A
	12a16        61f8        SKNZ            
	12a18        e1          ONEB            A
	12a19        9d5d        MOV             0FFE5DH,A
	12a1b        d45d        CMP0            0FFE5DH
	12a1d        dd24        BZ              $12A43H
	12a1f        8f46f6      MOV             A,!0F646H
	12a22        d448        CMP0            0FFE48H
	12a24        dd0a        BZ              $12A30H
	12a26        36b4f6      MOVW            HL,#0F6B4H
	12a29        31d50e      BF              [HL].5H,$12A3AH
	12a2c        51ff        MOV             A,#0FFH
	12a2e        ef0a        BR              $12A3AH
	12a30        d446        CMP0            0FFE46H
	12a32        dd06        BZ              $12A3AH
	12a34        36b4f6      MOVW            HL,#0F6B4H
	12a37        31f3f2      BT              [HL].7H,$12A2CH
	12a3a        712305      CLR1            P5.2H // These are the common cathodes
	12a3d        713205      SET1            P5.3H
	12a40        9d06        MOV             P6,A // P6 is the 7SEG
	12a42        d7          RET       

	12a43        8f47f6      MOV             A,!0F647H
	12a46        d449        CMP0            0FFE49H
	12a48        dd0a        BZ              $12A54H
	12a4a        36b4f6      MOVW            HL,#0F6B4H
	12a4d        31d50e      BF              [HL].5H,$12A5EH
	12a50        51ff        MOV             A,#0FFH
	12a52        ef0a        BR              $12A5EH
	12a54        d447        CMP0            0FFE47H
	12a56        dd06        BZ              $12A5EH
	12a58        36b4f6      MOVW            HL,#0F6B4H
	12a5b        31f3f2      BT              [HL].7H,$12A50H
	12a5e        712205      SET1            P5.2H // common cathodes flip
	12a61        713305      CLR1            P5.3H
	12a64        9d06        MOV             P6,A
	12a66        d7          RET   

From the IO, we can see this is likely to be updating the 7 segment LED displays.

The method used – of setting one common cathode, then the segments for that half, then the other common cathode, then the segments for that half – means that this needs to be called relatively frequently otherwise flicker will be detected by the eye.

// Button detection and debounce?
	132aa        31220217    BT              P2.2H,$132C5H // Button A
		132ae        4029e0ff    CMP             !0E029H,#0FFH
		132b2        dd24        BZ              $132D8H
		132b4        a029e0      INC             !0E029H
		132b7        4029e007    CMP             !0E029H,#7H
		132bb        df1b        BNZ             $132D8H
		132bd        cf29e0ff    MOV             !0E029H,#0FFH
		132c1        e445        ONEB            0FFE45H
		132c3        ef13        BR              $132D8H
	132c5        d529e0      CMP0            !0E029H
	132c8        dd0e        BZ              $132D8H
	132ca        b029e0      DEC             !0E029H
	132cd        4029e0f8    CMP             !0E029H,#0F8H
	132d1        df05        BNZ             $132D8H
	132d3        f529e0      CLRB            !0E029H
	132d6        f445        CLRB            0FFE45H

	132d8        31320216    BT              P2.3H,$132F2H // Button B
		132dc        402ae0ff    CMP             !0E02AH,#0FFH
		132e0        dd23        BZ              $13305H
		132e2        a02ae0      INC             !0E02AH
		132e5        402ae007    CMP             !0E02AH,#7H
		132e9        df1a        BNZ             $13305H
		132eb        cf2ae0ff    MOV             !0E02AH,#0FFH
		132ef        e444        ONEB            0FFE44H
		132f1        d7          RET             
	132f2        d52ae0      CMP0            !0E02AH
	132f5        dd0e        BZ              $13305H
	132f7        b02ae0      DEC             !0E02AH
	132fa        402ae0f8    CMP             !0E02AH,#0F8H
	132fe        df05        BNZ             $13305H
	13300        f52ae0      CLRB            !0E02AH
	13303        f444        CLRB            0FFE44H
	13305        d7          RET 

Again, from the IO, we can see that the buttons are being polled. There’s also some counters changing – probably some debounce.

// Analog something or other
	0ffcb        f1          CLRB            A
	0ffcc        71042a      MOV1            CY,0FFE2AH.0H
	0ffcf        7189        MOV1            A.0H,CY
	0ffd1        70          MOV             X,A
	0ffd2        f1          CLRB            A
	0ffd3        710ce3      MOV1            CY,ADIF
	0ffd6        61dc        ROLC            A,1
	0ffd8        6158        AND             A,X
	0ffda        dd23        BZ              $0FFFFH
	0ffdc        710be3      CLR1            ADIF
	0ffdf        4031ff07    CMP             !ADS,#7H
	0ffe3        8d1f        MOV             A,ADCRH
	0ffe5        df0b        BNZ             $0FFF2H
	0ffe7        9f0af6      MOV             !0F60AH,A
	0ffea        717b30      CLR1            ADCS
	0ffed        ce3106      MOV             ADS,#6H
	0fff0        ef09        BR              $0FFFBH
	0fff2        9f0bf6      MOV             !0F60BH,A
	0fff5        717b30      CLR1            ADCS
	0fff8        ce3107      MOV             ADS,#7H
	0fffb        00          NOP             
	0fffc        717a30      SET1            ADCS
	0ffff        d7          RET     

This does something with one of the ADC inputs. I’ve not seen anything of interest that uses analog yet, so I’ll not look into this more currently. It could be the input voltage (the boare can alarm on this) or PSTN line voltage.

There aren’t many other clearly idenfiable subroutines, but these few clearly identifiable ones give me confidence that this interrupt handler is most handling periodic IO.

This program structure of calling time-sensitive IO using a timer interrupt is fairly common in embedded systems. It means that IO is serviced regularly, allowing more time consuming (or non deterministic time) processing to happen outside of the interrupt in the main code. It means there are a lot of buffers and global variables to pass data back and forth that we can look at and play with.

From a security perspective, it can also produce problems. If we can stall something in the timer interrupt – by buffer overflow, bad input or so on – it can be possile to lock up a device. I’d hope that the board used a watchdog timer to recover from this though.

Leave a Reply

Your email will not be published. Name and Email fields are required.

This site uses Akismet to reduce spam. Learn how your comment data is processed.