Reverse engineering a CSL Dualcom GPRS part 16 – SMS remote commands

Sorry for the slow-down in posts – I stored up a load of posts, then posted them too quickly.

Since the last post, I have identified a lot of functionality in the code, including:

  • TX/RX subs for all the UARTS
  • Locations of TX/RX buffers for all UARTS
  • Multiply, divide, modulus and exponent subs
  • Conversion subs (ASCII->hex etc.)
  • EEPROM read/write subs
  • 7 segment display subs
  • Buzzer subs
  • Reading button state
  • Memory copy, search etc.
  • Hardware initilisation
  • Two intetesting subs that are called frequently to move working memory onto stack and back again

The board supports several GPRS modems – the Wavecom GR64 on the boards I have, but also Cinterion and Telit. The AT command set between the modems is completely different, so there are often several sections of code for common functionality like “Activate PDP context”. I’ve only looked at the Wavecom parts.

Having all this has given me enough to tie observed behaviour (just from using the Dualcom board, and the logic traces) back to specific areas of the code. Seeing the strings on the UART and searching for the address where that string is stored in flash/EEPROM is very useful.

I’m fairly sure the code is compiled C from IAR Embedded Workbench – the multiply, divide and startup are identical. If I compile code from Renesas Cubesuite, it looks very different.

There is still a lot of code that looks like assembly though – some of the memory operations, calling convention, and string searching look very odd to be compiled C.

One thing that caught my eye during the serial trace was that the board repeatedly checks for SMS messages. This suggests it is waiting for something to arrive, possibly commands

Digging around a bit, in the manual for the Dualcom GSM (not the GPRS), it mentions SMS remote control – sending commands to the CSL Dualcom:

SMS Remote commands

SMS Remote commands

This is interesting. A 6 digit PIN and some limited commands. It wouldn’t be the first time that PINs are defaulted to a certain value or derived from open information like the ICCID or number. It also wouldn’t be the first time that there are undocumented or hidden commands for a device, or even a backdoor.

We’re going to need to have a dig about in the code to see how these commands are dealt with. A good starting point would be to find where the string AT+CMGR (read text messages) is used, and follow on from there.

AT+CMGR is stored in the flash at 0x1BE6 (0x1000-0x2000 is almost exclusively strings and lookup tables). If we search for this address, we find the following chunk:

// State 0x86
// Request text messages
0c657        afc8f5      MOVW            AX,!0F5C8H // This is used as a time out
0c65a        7c80        XOR             A,#80H
0c65c        440180      CMPW            AX,#8001H
0c65f        dc07        BC              $0C668H
	0c661        d46a        CMP0            0FFE6AH
	0c663        61f8        SKNZ            
	0c665        ee3902      BR              $!0C8A1H
0c668        e1          ONEB            A
0c669        fc64d700    CALL            sub_Serial_ResetBuffers
0c66d        32b61e      MOVW            BC,#1EB6H // AT+CMGR=
0c670        e1          ONEB            A
0c671        fcd1e100    CALL            sub_Serial_WriteString_e1d1
0c675        8f49f7      MOV             A,!0F749H
0c678        72          MOV             C,A
0c679        f3          CLRB            B
0c67a        e1          ONEB            A
0c67b        fc04e200    CALL            sub_Serial_WriteHexAsDec_e204
0c67f        f46b        CLRB            0FFE6BH
0c681        f46a        CLRB            0FFE6AH
0c683        cf41f704    MOV             !0F741H,#4H
0c687        530d        MOV             B,#0DH //CR
0c689        e1          ONEB            A
0c68a        fcb2e100    CALL            sub_Serial_WriteChar_e1b3
0c68e        30a302      MOVW            AX,#2A3H
0c691        bfc8f5      MOVW            !0F5C8H,AX // set timeout to 675
0c694        cf4af704    MOV             !0F74AH,#4H // State 4 next
0c698        ee0602      BR              $!0C8A1H

This is a massive state machine. The “state” is stored in 0xF74A, checked at the beginning of the sub and then a branch performed to the current state.. State 0x86 sends “AT+CMGR=1” to UART1. It then sets the next state to 0x4.

Each one of the states sets a counter in 0xFF5C8 which is decremented in the timer interrupt. If this is hit, the state machine seems to be reset in most cases.

// State 0x4
// State after requesting text messages
0c69b        afc8f5      MOVW            AX,!0F5C8H // timeout
0c69e        7c80        XOR             A,#80H
0c6a0        440180      CMPW            AX,#8001H
0c6a3        dc42        BC              $0C6E7H
	0c6a5        8f19f7      MOV             A,!0F719H
	0c6a8        4c02        CMP             A,#2H
	0c6aa        61d8        SKNC            
	0c6ac        eef201      BR              $!0C8A1H
	0c6af        32c01e      MOVW            BC,#1EC0H  // "REC "
	0c6b2        e1          ONEB            A
	0c6b3        fcd3de00    CALL            sub_Serial_FindInRX_ded3
	0c6b7        d1          CMP0            A
	0c6b8        dd0d        BZ              $0C6C7H
	0c6ba        30a302      MOVW            AX,#2A3H
	0c6bd        bfc8f5      MOVW            !0F5C8H,AX
	0c6c0        cf4af718    MOV             !0F74AH,#18H // State 0x18 next
	0c6c4        eeda01      BR              $!0C8A1H

	0c6c7        32c61e      MOVW            BC,#1EC6H // "STO "
	0c6ca        e1          ONEB            A
	0c6cb        fcd3de00    CALL            sub_Serial_FindInRX_ded3
	0c6cf        d1          CMP0            A
	0c6d0        dd07        BZ              $0C6D9H
	0c6d2        cf4af717    MOV             !0F74AH,#17H // State 0x17 next
	0c6d6        eec801      BR              $!0C8A1H

	0c6d9        3152410a    BT              0FFE41H.5H,$0C6E7H
	0c6dd        afdef5      MOVW            AX,!0F5DEH
	0c6e0        7c80        XOR             A,#80H
	0c6e2        440180      CMPW            AX,#8001H
	0c6e5        dc0b        BC              $0C6F2H
0c6e7        cf49f70f    MOV             !0F749H,#0FH
0c6eb        cf4af796    MOV             !0F74AH,#96H // State 0x96 next
0c6ef        eeaf01      BR              $!0C8A1H

State 0x4 searches the receive buffer on UART1 for the characters “REC” or “STO”. “REC” is what we would see if there was a text message to read, and if this is found we move to stat 0x18. This calls 0xC301 and the flow continues from there. It might be better to describe this as a process rather than show ASM.

The format of the text message received would be as follows:

+CMGR: “REC UNREAD”,“+447747008670”,“Matt L”,“02/11/19,09:57:28+00”,145,36,0,0,“ +447785016005”,145,8

Test sms

The code, give or take, works as follows.

1. Search RX buffer for string READ – this finds REC UNREAD and REC READ, both found in text messages. If not found, abort.

2. Keep on going until a + is found – the start of the phone number

3. Loop until a non-numeric character is found, storing the number in 0xFE17F. The number is used later to send a text back.

4. Loop until a carriage return is found. This is the end of the text detail and the start of the actual text.

5. Copy the message to address 0xFE20E.

6. Read in a 6-digit PIN from EEPROM at 0x724. I can’t see where this is set in the Windows utility.

7. Check that the 6-digit PIN is at the beginning of the message.

8. Call a function to parse the rest of the message and act on it.

This is where it gets mildly interesting – not only are there the documented commands but there are ones that include “CALL” and “4 2 xxxxxxxxxx”….

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.