I’m currently working on a project involving a Canon ELPH100HS point and shoot camera and my first task was to tear it apart and find any low level hardware access that I could. I chose the IXUS115 mainly for it’s full 1080p video recording capabilities and there is a CHDK port for it, which, it was hoped, would make the reversing and hacking process easier. I was hoping to find a serial console port and JTAG access to the processor, to aid programming and debugging.
Teardown
Before I can start searching for hardware access, I need to get under the covers. The screwdrivers came out and the camera was disassembled with a minimum of fuss.
Â
 Some quick inspection identified a no-connect pin, ground, what looks like two supply rails with one missing a connecting component, and a variety of signals. Thanks to CHDK I knew there was more than likely a serial port on this connector and some quick probing with an oscilloscope revealed that pin 1 was TX and pin 2 (bottom left) was RX. Objective 1 complete.
Making the camera useful for hacking on
While a serial console on a point and shoot camera was fun (see Event and DryOS shell for what can be done with it) I wanted lower level access. I had to make it easier to hack on the camera as that connector was tiny and impossible to work with for any length of time. I was convinced that there was more to this connector, Canon have to get a bootloader onto the board one way or another, and without code, the serial console doesn’t work.
Using some 0.1mm enamel wire and a magnifying glass, I managed to get all the connections out onto a standard 0.1″ header strip. A bamboo skewer, a takeaway lid and a bit of glue later and I had all the camera parts securely mounted and accessible.
Hooking up the BusPirate in UART bridge mode to the previously identified serial port yielded a console:
Event[1]>drysh === Dry-shell start === Dry> ? [Debug]  task sem event mq mutex timer mkobjsize extask kill suspend resume  release delete prio mkcfg meminfo xd xm memmap objinfo [Misc]  vers exit dminfo Dry> meminfo usage: meminfo [-{l|s|m|L}]       -l allocated list       -s system memory info       -m malloc memory info       -L all list (corruption safe) Dry> meminfo -s System Memory Information  Start Address      = 0x00379c08  End Address        = 0x003ccc00  Total Size         = 0x00052ff8 (  339960)  Allocated Size     = 0x000358c8 (  219336)  Allocated Peak     = 0x000368d8 (  223448)  Allocated Count    = 0x00000045 (      69)  Free Size          = 0x0001d730 (  120624)  Free Block Max Size = 0x0001c6a0 (  116384)  Free Block Count   = 0x00000004 (       4) Dry> meminfo -m Malloc Information (onetime type)  Start Address      = 0x001745c8  End Address        = 0x00371de0  Total Size         = 0x001fd818 ( 2086936)  Allocated Size     = 0x001413c8 ( 1315784)  Allocated Peak     = 0x00147b38 ( 1342264)  Allocated Count    = 0x0000013b (     315)  Free Size          = 0x000bc450 (  771152)  Free Block Max Size = 0x000bb330 (  766768)  Free Block Count   = 0x00000003 (       3) Dry> memmap == ITCM == 00000000 : DRY_VECTOR_ADDR 000004b0 : DRY_HANDLER_ADDR           0x00000214(532) 000006c4 : DRY_HANDLER_END_ADDR 000006c4 : DRY_IRQ_STACK_START 000006c4 : DRY_RESET_STACK_START           0x0000093c(2364) 00001000 : DRY_IRQ_STACK 00001000 : DRY_RESET_STACK 00001000 : ITCM_END_ADDR == DTCM == 80000728 : DRY_VECTOR_FUNC           0x00000400(1024) 80000b28 : DRY_VECTOR_ARG           0x00000400(1024) 80001000 : DTCM_END_ADDR == ROM == ff810000 : text start           0x0046edd8(4648408) ffc7edd8 : romdata start           0x0000e9c0(59840) ffc8d798 : romdata end == DRAM == 00001900 : data start           0x0000e9c0(59840) 000102c0 : bss start           0x001642fc(1458940) 001745bc : heap start           0x001fd9c4(2087364) 00371f80 : DRY_HEAP_END 00371f80 : DRY_SYS_OBJS_START           0x00007c80(31872) 00379c00 : DRY_SYS_MEM_START           0x00053000(339968) 003ccc00 : DRY_ERREX_STACK_START           0x00000400(1024) 003cd000 : DRY_ERREX_STACK 003cd000 : DRY_EXCEP_STACK_START           0x00001000(4096) 003ce000 : DRY_EXCEP_STACK Dry> xd ff810000           0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef ff810000: 01 00 00 ea 67 61 6f 6e 69 73 6f 79 50 11 9f e5 ....gaonisoyP... ff810010: 00 00 a0 e3 00 00 81 e5 78 10 a0 e3 10 1f 01 ee ........x....... ff810020: 00 10 a0 e3 9a 1f 07 ee 15 1f 07 ee 16 1f 07 ee ................ ff810030: 3d 00 a0 e3 10 0f 06 ee bf 01 a0 e3 11 0f 06 ee =............... ff810040: 35 00 a0 e3 12 0f 06 ee d5 01 a0 e3 13 0f 06 ee 5............... ff810050: 5e 01 a0 e3 14 0f 06 ee 08 01 9f e5 15 0f 06 ee ^............... ff810060: 34 00 a0 e3 10 0f 02 ee 34 00 a0 e3 30 0f 02 ee 4.......4...0... ff810070: 34 00 a0 e3 10 0f 03 ee ec 00 9f e5 50 0f 05 ee 4...........P... ff810080: e4 00 9f e5 70 0f 05 ee 10 0f 11 ee 01 0a 80 e3 ....p........... ff810090: 04 00 80 e3 01 00 80 e3 10 0f 01 ee 1a 11 a0 e3 ................ ff8100a0: 11 1f 09 ee 06 10 a0 e3 31 1f 09 ee 10 1f 11 ee ........1....... ff8100b0: 05 18 81 e3 10 1f 01 ee b0 20 9f e5 01 10 a0 e3 ......... ...... ff8100c0: 0c 11 82 e5 ff 10 a0 e3 0c 10 82 e5 1c 10 82 e5 ................ ff8100d0: 2c 10 82 e5 3c 10 82 e5 4c 10 82 e5 5c 10 82 e5 ,...<...L...\... ff8100e0: 6c 10 82 e5 7c 10 82 e5 8c 10 82 e5 9c 10 82 e5 l...|........... ff8100f0: ac 10 82 e5 bc 10 82 e5 cc 10 82 e5 dc 10 82 e5 ................ Dry>
The memory information shown above will come in handy later when reversing the firmware. I may be able to use the xd/xm commands to query the Flash over CFI and determine what it is, the markings on it bring up no results.
Finding the pin functions
Now that the pins were all nicely accessible and I had a serial console, it was time to figure out what they all did.
Using the oscilloscope (a DMM would have worked too) I looked at the voltages present on all the pins and came up with the following information:
 TX - _ RX  GND - _ 3.3V   L - _ N/C  N/C - _ L   L - _ L   L - _ L   H - _ H   H - _ L   H - H = 3.3V, L = 0V
Next, using a 330Ω resistor and a wire I tried to see if I could change the state of any of the pins. If I could change the state they would be either an input or a high-z output, if I couldn’t, the pins would be an output. The resistor is in line to limit current in case the line is being actively driven. From this test I found:
 TX - _ RX  GND - _ 3.3V SHDN - _ N/C  N/C - _ PD  PD - _ PD  PD - _ PD  PU - _ PU  PU - _ PD /OFF - PD = Pull Down, PU = Pull Up
Taking SHDN high caused the camera to turn off gracefully, taking /OFF low immediately turned the camera off, no lens retraction. All the rest of the pins were either inputs or high impedance outputs. Having learnt a little more, I thought it was time to hammer on JTAG and see if I could find a chain. Using a STM32F3 development board and a utility of my own making, I hammered on all 9 of the unknown pins to see if JTAG showed up. It didn’t.
Back to the drawing board, I tried to see if any of the pins had special functions on boot. Inverting their state (A pulled up pin taken low, a pulled down pin taken high) one at a time found two interesting pins:
 TX - _ RX  GND - _ 3.3V SHDN - _ N/C  N/C - _ HALF_BAUD  PD - _ ALT_BOOT  PD - _ PD  PU - _ PU  PU - _ PD /OFF - PD = Pull Down, PU = Pull Up
When HALF_BAUD is active on boot, it causes the serial port to run at half it’s speed (57600 instead of 115200). I don’t know if this is because the system clock is running at half speed, but it’s interesting. When ALT_BOOT is active on boot a different serial console is shown:
 SiP check start Test Case : ? Test Case : 1  FROM sum is 0x3CE0C911 Test Case : 2  Write data is 0x55555555  Data bus check for all DRAM cell : [OK] Test Case : 3  Write data is 0xAAAAAAAA  Data bus check for all DRAM cell : [OK] Test Case : 4  Write data is 0x00000000  Data bus check for all DRAM cell : [OK] Test Case : 5  Write data is 0xFFFFFFFF  Data bus check for all DRAM cell : [OK] Test Case : 6  Address bus check for all DRAM cell : [OK] Test Case : 7  Data bus check (Simple version) : [OK] Test Case : 8  Address bus check (Simple version) : [OK] Test Case :
It allows for 8 memory and bus checks to be performed. An interesting note about this mode is that the power switch has to be held down, otherwise the board turns off. I’d reduced the candidates, but still hadn’t found a JTAG port. I also tried different combinations of power up modes to see if it was being disabled on startup.
The JTAG finder I was using (dubbed ‘JTAG Knocker’) only looked for TCK, TMS, TDI and TDO, it assumed that the JTAG port was active at all times. Some JTAG ports also come with nTRST pin to reset the chain and if that pin is pulled low, the JTAG port doesn’t work. So I decided the next course of action was to change the state of a pin while looking for a JTAG port on all the other pins. I started with the ones that were pulled low (more likely to be nTRST) and I hit paydirt:
JTAG Knocker [!] Potential Chain: TCK: 3 TMS: 5 TDO: 4 TDI: 2 [+] 1 Device(s) found, with total IR Length of 4 [+]Â Device 1 - ID CODE 15946009 [!] Potential Chain: TCK: 3 TMS: 5 TDO: 4 TDI: 2 [+] 1 Device(s) found, with total IR Length of 4 [+]Â Device 1 - ID CODE 15946009 Done.
The two statements with the same result are from the two different methods used to test a pin combination. The manufacturer in the ID code is Fujitsu, I guess they are the ones fabricating the Digic 4 chips for Canon. Updating the pin map:
 TX - _ RX  GND - _ 3.3V SHDN - _ N/C  N/C - _ HALF_BAUD  PD - _ ALT_BOOT  PD - _ /TRST  TDI - _ TMS  TCK - _ TDO /OFF -
Whipping up a quick openocd board definition and giving it a test:
Yup, it’s all working correctly. JTAG found.
So, why the desire for JTAG?
JTAG allows me to debug code (very slowly) on the processor instruction by instruction and gives me runtime information on the firmware, something that a static analysis can’t. I’m also able to program the flash, change things as I see fit, and recover if I brick it.
I rolled my own JTAG finder instead of buying one of the readily available ones (JTAG Enum, JTAGulator, etc) as they are expensive, a dedicated solution and/or require additional hardware I don’t currently have. Rolling my own on a dev board makes it useful, keeps the dev board available for other tasks and taught me a heap about the workings of JTAG. Oh yeah, and all it cost was time, which would have been spent waiting for the post.
Finishing Up
Doing a bit more testing on the pins, I’m fairly certain that /OFF above is actually /SRST (system reset) which promptly disables the power. SHDN above is probably the power switch, as it has similar behavour and if it’s held high on boot, the device won’t turn off. The pin below SHDN is probably a power supply pin (due to the wide trace) for development use, allowing the developers to power, control and debug the board from a single connector. As it’s not needed for production use, the linking component was not populated, but it can easily be replaced with a solder bridge. This is something for me to try in the near future. Finally the two unidentified PD pins could have something to do with the ARM Embedded Trace Macrocell, possibly an enable and return clock (RTCK).
I’m fairly confident that the same connector would be on all Digic 4 cameras, and it’s probably similar across most of Canon’s range of point and shoot cameras.
The next step is to improve JTAG Knocker to the point where it’s ready for release as a functional JTAG finder and USB based JTAG adapter for OpenOCD. The JTAG adapters I currently have don’t support TRST or SRST and I may be able to roll some other functionality in there too. The board definition file for the camera also needs some work, GDB has a few issues and there are currently no memory regions defined.
Stay Tuned.
#1 by lut on April 20, 2018 - 2:19 am
Hi, thank you very much for your article. The pinout is the same on my camera for JTAG (PowerShot S100), as for UART I didn’t test it.