Menu

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

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:

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

0000000NOP

0000101ADDW AX,AX

0000282INCC

000032084SUBW SP,#84H

000052086SUBW SP,#86H

000072088SUBW SP,#88H

00009208aSUBW SP,#8AH

0000b208cSUBW SP,#8CH

0000d208eSUBW SP,#8EH

0000f2090SUBW SP,#90H

000112092SUBW SP,#92H

000132001SUBW SP,#1H

00015247d23SUBW AX,#237DH

00018292494MOVA,9424H[C]

0001b2096SUBW SP,#96H

0001d203aSUBW SP,#3AH

0001f21?

00020be20 MOVW PM0,AX

000223c21SUBCA,#21H

0002492DECC

00025225921SUBW AX,!2159H

00028ba22 MOVW[DE+22H],AX

0002a9820MOV[SP+20H],A

0002c00NOP

0002d209aSUBW SP,#9AH

0002f209cSUBW SP,#9CH

00031209eSUBW SP,#9EH

0003320a0SUBW SP,#0A0H

0003520a2SUBW SP,#0A2H

0003720a4SUBW SP,#0A4H

0003920a6SUBW SP,#0A6H

0003b205eSUBW SP,#5EH

0003d23SUBW AX,BC

0003ed7 RET

0003f226023SUBW AX,!2360H

00042a820 MOVW AX,[SP+20H]

00044aa20 MOVW AX,[DE+20H]

00046ac20 MOVW AX,[HL+20H]

00048ae20 MOVW AX,PM0

0004ab020b2 DEC!0B220H

0004d20b4SUBW SP,#0B4H

0004f20b6SUBW SP,#0B6H

0005120b8SUBW SP,#0B8H

0005320baSUBW SP,#0BAH

0005520ffSUBW 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:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

0000-&gt;0100*RESET

0004-&gt;2082

0006-&gt;2086

0008-&gt;2088

000A-&gt;208A

000C-&gt;208C

000E-&gt;208E

0010-&gt;2090

0012-&gt;2092

0014-&gt;2401*INTST3

0016-&gt;237D*INTSR3

0018-&gt;2429*INTSRE3

001A-&gt;2094

001C-&gt;2096

001E-&gt;213A*INST0

0020-&gt;20BE*INTSR0

0022-&gt;213C*INTSRE0

0024-&gt;2292*INTST1

0026-&gt;2159*INTSR1

0028-&gt;22BA*INTSRE1

002A-&gt;2098

002C-&gt;2000*INTTM00

002E-&gt;209A

0030-&gt;209C

0032-&gt;209E

0034-&gt;20A0

0036-&gt;20A2

0038-&gt;20A4

003A-&gt;20A6

003C-&gt;235E*INTST2

003E-&gt;22D7*INTSR2

0040-&gt;2360*INTSRE2

0042-&gt;20A8

0044-&gt;20AA

0046-&gt;20AC

0048-&gt;20AE

004A-&gt;20B0

004C-&gt;20B2

004E-&gt;20B4

0050-&gt;20B6

0052-&gt;20B8

0054-&gt;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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

0209261fcRETI

0209461fcRETI

0209661fcRETI

0209861fcRETI

0209a61fcRETI

0209c61fcRETI

0209e61fcRETI

020a061fcRETI

020a261fcRETI

020a461fcRETI

020a661fcRETI

020a861fcRETI

020aa61fcRETI

020ac61fcRETI

020ae61fcRETI

020b061fcRETI

020b261fcRETI

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// INTST1

02292c1 PUSH AX

02293c3 PUSH BC

02294c7 PUSH HL

02295fbb6e0 MOVW HL,!0E0B6H

02298afb4e0 MOVW AX,!0E0B4H

0229b47CMPW AX,HL

0229cdd17 BZ$22B5H

0229edbb4e0 MOVW BC,!0E0B4H

022a149b8e4MOVA,0E4B8H[BC]// Get data from E4B8 using offset from E0B4

022a49e44MOV SIO10,A// Move to serial data TX register

022a6a2b4e0 INCW!0E0B4H// Increment the offset

022a9afb4e0 MOVW AX,!0E0B4H

022ac440a04CMPW AX,#40AH // Is the offset greater than 1034? If so reset to 0

022afdc04 BC$22B5H

022b1f6 CLRW AX

022b2bfb4e0 MOVW!0E0B4H,AX

022b5c6 POP HL

022b6c2 POP BC

022b7c0 POP AX

022b861fcRETI

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

// INTTM00

02000c1 PUSH AX

02001c3 PUSH BC

02002c7 PUSH HL

02003aefc MOVW AX,0FFFFCH

02005c1 PUSH AX

02006a0b3f6 INC!0F6B3H

020098fb3f6MOVA,!0F6B3H

0200c5c03ANDA,#3H

0200e4c03CMPA,#3H

02010df38 BNZ$204AH

02012a0b4f6 INC!0F6B4H

02015fcfc2801 CALL!!128FCH

02019fc932601 CALL!!12693H

0201dfcf22701 CALL!!127F2H

02021f45c CLRB0FFE5CH

02023fc132a01 CALL!!12A13H// 7SEG display

02027fcaa3201 CALL!!132AAH// Buttons

0202b8fb4f6MOVA,!0F6B4H

0202e5c03ANDA,#3H

02030dd08 BZ$203AH

0203291DECA

02033dd0b BZ$2040H

0203591DECA

02036dd0e BZ$2046H

02038ef10 BR$204AH

0203afccbff00 CALL!!0FFCBH// Analog

0203eef0a BR$204AH

02040fcd13101 CALL!!131D1H

02044ef04 BR$204AH

02046fc063301 CALL!!13306H

0204afc742e01 CALL!!12E74H

0204efc84ff00 CALL!!0FF84H

0205272MOVC,A

0205381INCA

02054dd24 BZ$207AH

0205662MOVA,C

0205770MOVX,A

02058f1 CLRBA

0205901ADDW AX,AX

0205a04b8f5ADDW AX,#0F5B8H

0205d16MOVW HL,AX

0205ef6 CLRW AX

0205fb1 DECW AX

02060bb MOVW[HL],AX

0206162MOVA,C

02062d1 CMP0A

02063dd11 BZ$2076H

020652c11SUBA,#11H

02067dd05 BZ$206EH

0206991DECA

0206add06 BZ$2072H

0206cef0c BR$207AH

0206ee46a ONEB0FFE6AH

02070ef08 BR$207AH

02072e46b ONEB0FFE6BH

02074ef04 BR$207AH

02076fcf7fc00 CALL!!0FCF7H

0207ac0 POP AX

0207bbefc MOVW0FFFFCH,AX

0207dc6 POP HL

0207ec2 POP BC

0207fc0 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:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

// Suspect from IO this is output to 7 seg

12a13d45d CMP00FFE5DH

12a15f1 CLRBA

12a1661f8SKNZ

12a18e1 ONEBA

12a199d5dMOV0FFE5DH,A

12a1bd45d CMP00FFE5DH

12a1ddd24 BZ$12A43H

12a1f8f46f6MOVA,!0F646H

12a22d448 CMP00FFE48H

12a24dd0a BZ$12A30H

12a2636b4f6MOVW HL,#0F6B4H

12a2931d50eBF[HL].5H,$12A3AH

12a2c51ffMOVA,#0FFH

12a2eef0a BR$12A3AH

12a30d446 CMP00FFE46H

12a32dd06 BZ$12A3AH

12a3436b4f6MOVW HL,#0F6B4H

12a3731f3f2BT[HL].7H,$12A2CH

12a3a712305CLR1 P5.2H// These are the common cathodes

12a3d713205SET1 P5.3H

12a409d06MOV P6,A// P6 is the 7SEG

12a42d7 RET

12a438f47f6MOVA,!0F647H

12a46d449 CMP00FFE49H

12a48dd0a BZ$12A54H

12a4a36b4f6MOVW HL,#0F6B4H

12a4d31d50eBF[HL].5H,$12A5EH

12a5051ffMOVA,#0FFH

12a52ef0a BR$12A5EH

12a54d447 CMP00FFE47H

12a56dd06 BZ$12A5EH

12a5836b4f6MOVW HL,#0F6B4H

12a5b31f3f2BT[HL].7H,$12A50H

12a5e712205SET1 P5.2H// common cathodes flip

12a61713305CLR1 P5.3H

12a649d06MOV P6,A

12a66d7 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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

// Button detection and debounce?

132aa31220217BT P2.2H,$132C5H// Button A

132ae4029e0ffCMP!0E029H,#0FFH

132b2dd24 BZ$132D8H

132b4a029e0 INC!0E029H

132b74029e007CMP!0E029H,#7H

132bbdf1b BNZ$132D8H

132bdcf29e0ff MOV!0E029H,#0FFH

132c1e445 ONEB0FFE45H

132c3ef13 BR$132D8H

132c5d529e0 CMP0!0E029H

132c8dd0e BZ$132D8H

132cab029e0 DEC!0E029H

132cd4029e0f8CMP!0E029H,#0F8H

132d1df05 BNZ$132D8H

132d3f529e0 CLRB!0E029H

132d6f445 CLRB0FFE45H

132d831320216BT P2.3H,$132F2H// Button B

132dc402ae0ffCMP!0E02AH,#0FFH

132e0dd23 BZ$13305H

132e2a02ae0 INC!0E02AH

132e5402ae007CMP!0E02AH,#7H

132e9df1a BNZ$13305H

132ebcf2ae0ff MOV!0E02AH,#0FFH

132efe444 ONEB0FFE44H

132f1d7 RET

132f2d52ae0 CMP0!0E02AH

132f5dd0e BZ$13305H

132f7b02ae0 DEC!0E02AH

132fa402ae0f8CMP!0E02AH,#0F8H

132fedf05 BNZ$13305H

13300f52ae0 CLRB!0E02AH

13303f444 CLRB0FFE44H

13305d7 RET

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

// Analog something or other

0ffcbf1 CLRBA

0ffcc71042aMOV1 CY,0FFE2AH.0H

0ffcf7189MOV1A.0H,CY

0ffd170MOVX,A

0ffd2f1 CLRBA

0ffd3710ce3MOV1 CY,ADIF

0ffd661dcROLCA,1

0ffd86158ANDA,X

0ffdadd23 BZ$0FFFFH

0ffdc710be3CLR1 ADIF

0ffdf4031ff07CMP!ADS,#7H

0ffe38d1fMOVA,ADCRH

0ffe5df0b BNZ$0FFF2H

0ffe79f0af6MOV!0F60AH,A

0ffea717b30CLR1 ADCS

0ffedce3106 MOV ADS,#6H

0fff0ef09 BR$0FFFBH

0fff29f0bf6MOV!0F60BH,A

0fff5717b30CLR1 ADCS

0fff8ce3107 MOV ADS,#7H

0fffb00NOP

0fffc717a30SET1 ADCS

0ffffd7 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.

I'm a security researcher and reverse engineer. By visiting this site, you must realise that any or all files on this site may be jam packed full of the finest exploits, tricks and other gubbins. You might also get geo-located and port-scanned for fun and profit.
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish.AcceptRead More
If I really want to track you, by tricking you into visiting this site, then it's going to be a lot more subtle than a browser cookie.