Part 4 - Hacking Hello World

In the last lesson we reviewed how to properly debug our very simple binary in Radare2. Today we are going to hack that static .elf binary and convert it to the .uf2 format and flash to our Pico and see the magic happen.

Let’s review our very simple program once more.

  1. #include <stdio.h>
  2. #include "pico/stdlib.h"
  3. int main()
  4. {
  5. stdio_init_all();
  6. while(1)
  7. {
  8. printf("Hello world!\n");
  9. sleep_ms(1000);
  10. }
  11. return 0;
  12. }

Let’s load up our binary.

  1. radare2 -w arm -b 16 0x02_hello_world.elf

Let’s auto analyze.

  1. aaaa

Let’s seek to main.

  1. s main

Let’s use Visual mode and press p twice to get our our favorite debugger view.

  1. V

Let’s review the simple ARM32 Assembly.

Part 4 - Hacking Hello World - 图1

I would hack this binary in two ways. As we discussed in the last lesson we see the contents inside the memory location 0x00000338 holding the value of our string. Let’s press the colon : and press enter.

  1. :> psz @ [0x00000338]
  2. Hello world!

Let’s review our strings. I want you to pay attention to the, “Hello world!” as you will see two addresses. The one on the left is the physical address and the one directly to the right is the virtual address. We will be concerned with the virtual address. To better understand let’s do the following.

  1. :> iz~ | less

As you can see our string is at the top.

  1. [Strings]
  2. nth paddr vaddr len size section type string
  3. ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――
  4. 0 0x00014cf8 0x00004cf8 12 13 .rodata ascii Hello world!
  5. 1 0x00014d08 0x00004d08 26 27 .rodata ascii No spinlocks are available
  6. 2 0x00014d24 0x00004d24 33 34 .rodata ascii Hardware alarm %d already claimed
  7. 3 0x00014d48 0x00004d48 15 16 .rodata ascii \n*** PANIC ***\n
  8. 4 0x00014d5c 0x00004d5c 11 12 .rodata ascii Hard assert
  9. 5 0x00014d68 0x00004d68 7 8 .rodata ascii Release
  10. 6 0x00014d70 0x00004d70 5 6 .rodata ascii 1.0.0
  11. 7 0x00014d78 0x00004d78 4 5 .rodata ascii pico
  12. 8 0x00014d80 0x00004d80 16 17 .rodata ascii 0x02_hello_world
  13. 9 0x00014d94 0x00004d94 11 12 .rodata ascii Mar 21 2021
  14. 10 0x00014db2 0x00004db2 4 5 .rodata ascii uBhM
  15. 11 0x00014dbc 0x00004dbc 10 11 .rodata ascii UART stdin
  16. 12 0x00014dc8 0x00004dc8 11 12 .rodata ascii UART stdout
  17. 13 0x00014dd4 0x00004dd4 19 20 .rodata ascii UART stdin / stdout
  18. 14 0x00014dfc 0x00004dfc 18 19 .rodata ascii USB stdin / stdout
  19. 15 0x00014e1c 0x00004e1c 12 13 .rodata ascii Raspberry Pi
  20. 16 0x00014e2c 0x00004e2c 4 5 .rodata ascii Pico
  21. 17 0x00014e34 0x00004e34 12 13 .rodata ascii 000000000000
  22. 18 0x00014e44 0x00004e44 9 10 .rodata ascii Board CDC
  23. 19 0x00014ec4 0x00004ec4 19 20 .rodata ascii Unhandled IRQ 0x%x\n
  24. 20 0x00014ed8 0x00004ed8 39 40 .rodata ascii Isochronous wMaxPacketSize %d too large
  25. 21 0x00014f00 0x00004f00 30 31 .rodata ascii ep %d %s was already available
  26. 22 0x00014f20 0x00004f20 40 41 .rodata ascii Can't continue xfer on inactive ep %d %s
  27. 23 0x00014f4c 0x00004f4c 35 36 .rodata ascii Transferred more data than expected
  28. 0 0x00020135 0x10000135 5 6 .data ascii V\n`\eh
  29. 1 0x0002018b 0x1000018b 5 6 .data ascii &CF\eh
  30. 2 0x000201a0 0x100001a0 4 5 .data ascii CF\ey
  31. 3 0x000201a8 0x100001a8 4 5 .data ascii CF\eh
  32. 4 0x000201d0 0x100001d0 4 5 .data ascii \thAq
  33. 5 0x0002028d 0x1000028d 5 6 .data ascii GpF\t8
  34. 6 0x00020805 0x10000805 5 11 .data utf16le \a \b \b
  35. 7 0x00020905 0x10000905 5 11 .data utf16le \b \t \t
  36. 8 0x00020a05 0x10000a05 5 11 .data utf16le \t \n \n
  37. 9 0x00020b05 0x10000b05 5 11 .data utf16le \n \v \v
  38. (END)

You can see the value of 0x00004cf8 holds our string to prove it we can do the following.

  1. :> psz @ 0x00004cf8
  2. Hello world!

Let’s hack this.

  1. :> w Hacked World! @ [0x00000338]

Let’s now verify the value is changed.

  1. :> psz @ 0x00004cf8
  2. Hacked World!

The other thing I would like to hack is the sleep_ms which is currently set at 1000. Remember it is showing 250 decimal or 0xfa hex and we logical shift left twice as we discuss in the last lesson. The first logical shift left will multiply by 2 bringing us to 500 and the 2nd logical shift left will multiply by 2 brining us to 1000.

  1. lsls r0, r0, 2

Let’s hack this by changing the 2 to a 1. This will make the delay 500 ms or a half a second.

  1. :> wa lsls r0, r0, 1 @ 0x00000330
  2. Written 2 byte(s) (lsls r0, r0, 1) = wx 4000

Let’s verify.

  1. :> pd 1 @ 0x00000330
  2. 0x00000330 4000 lsls r0, r0, 1

We can clearly see it changed.

All we have to do now is exit and convert our .elf to .uf2!

  1. ./elf2uf2/elf2uf2 0x02_hello_world.elf 0x02_hello_world.uf2

Plug in the Pico and make sure you hold down BOOTSEL or use the setup I provided in the last lesson.

  1. cp 0x02_hello_world.uf2 /Volumes/RPI-RP2

Let’s screen it!

  1. screen /dev/tty.usbmodem0000000000001

AHH yea!

  1. Hacked World!
  2. Hacked World!
  3. Hacked World!
  4. Hacked World!
  5. Hacked World!
  6. Hacked World!
  7. Hacked World!
  8. Hacked World!
  9. Hacked World!
  10. Hacked World!
  11. Hacked World!
  12. Hacked World!
  13. Hacked World!
  14. Hacked World!
  15. Hacked World!
  16. Hacked World!
  17. Hacked World!
  18. Hacked World!
  19. Hacked World!
  20. Hacked World!
  21. Hacked World!
  22. Hacked World!
  23. Hacked World!
  24. Hacked World!
  25. Hacked World!

Every half a second!

Next lesson we will discuss variables.