看代码:

 #include <stdio.h>
#include <fcntl.h>
int key1(){
asm("mov r3, pc\n");
}
int key2(){
asm(
"push {r6}\n"
"add r6, pc, $1\n"
"bx r6\n"
".code 16\n"
"mov r3, pc\n"
"add r3, $0x4\n"
"push {r3}\n"
"pop {pc}\n"
".code 32\n"
"pop {r6}\n"
);
}
int key3(){
asm("mov r3, lr\n");
}
int main(){
int key=;
printf("Daddy has very strong arm! : ");
scanf("%d", &key);
if( (key1()+key2()+key3()) == key ){
printf("Congratz!\n");
int fd = open("flag", O_RDONLY);
char buf[];
int r = read(fd, buf, );
write(, buf, r);
}
else{
printf("I have strong leg :P\n");
}
return ;
}

C Code

 #include <stdio.h>
#include <fcntl.h>
int key1(){
asm("mov r3, pc\n");
}
int key2(){
asm(
"push {r6}\n"
"add r6, pc, $1\n"
"bx r6\n"
".code 16\n"
"mov r3, pc\n"
"add r3, $0x4\n"
"push {r3}\n"
"pop {pc}\n"
".code 32\n"
"pop {r6}\n"
);
}
int key3(){
asm("mov r3, lr\n");
}
int main(){
int key=;
printf("Daddy has very strong arm! : ");
scanf("%d", &key);
if( (key1()+key2()+key3()) == key ){
printf("Congratz!\n");
int fd = open("flag", O_RDONLY);
char buf[];
int r = read(fd, buf, );
write(, buf, r);
}
else{
printf("I have strong leg :P\n");
}
return ;
}

分析代码,key1()+key2()+key3()==key时,得到flag

那么来分析给定的汇编代码:

 (gdb) disass key1
Dump of assembler code for function key1:
0x00008cd4 <+>: push {r11} ; (str r11, [sp, #-4]!)
0x00008cd8 <+>: add r11, sp, #
0x00008cdc <+>: mov r3, pc
0x00008ce0 <+>: mov r0, r3
0x00008ce4 <+>: sub sp, r11, #
0x00008ce8 <+>: pop {r11} ; (ldr r11, [sp], #4)
0x00008cec <+>: bx lr
End of assembler dump.

返回地址是r0而r0等于pc,且为arm指令

补充知识:

PC代表程序计数器,流水线使用三个阶段,因此指令分为三个阶段执行:.取指(从存储器装载一条指令);.译码(识别将要被执行的指令);.执行(处理指令并将结果写回寄存器)。而R15
(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC总是指向第三
条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址加8字节的地址,即:PC值=当前程序执行位置+;
ARM指令是三级流水线,取指,译指,执行时同时执行的,现在PC指向的是正在取指的地址,那么cpu正在译指的指令地址是PC-(假设在ARM状态下,一个指令占4个字节),cpu正在执行的指令地
址是PC-,也就是说PC所指向的地址和现在所执行的指令地址相差8。

所以

r0的地址等于0x8cdc+0x8

再看key2:

(gdb) disass key2
Dump of assembler code for function key2:
0x00008cf0 <+>: push {r11} ; (str r11, [sp, #-4]!)
0x00008cf4 <+>: add r11, sp, #
0x00008cf8 <+>: push {r6} ; (str r6, [sp, #-4]!)
0x00008cfc <+>: add r6, pc, #
0x00008d00 <+>: bx r6
0x00008d04 <+>: mov r3, pc
0x00008d06 <+>: adds r3, #
0x00008d08 <+>: push {r3}
0x00008d0a <+>: pop {pc}
0x00008d0c <+>: pop {r6} ; (ldr r6, [sp], #4)
0x00008d10 <+>: mov r0, r3
0x00008d14 <+>: sub sp, r11, #
0x00008d18 <+>: pop {r11} ; (ldr r11, [sp], #4)
0x00008d1c <+>: bx lr
End of assembler dump.

返回地址为r3,bx r6跳转为thumb指令,所以r3=0x8d04+0x4+0x4;

附:arm与thumb跳转:

http://blog.csdn.net/itismine/article/details/4753701

再看key3:

 (gdb) disass key3
Dump of assembler code for function key3:
0x00008d20 <+>: push {r11} ; (str r11, [sp, #-4]!)
0x00008d24 <+>: add r11, sp, #
0x00008d28 <+>: mov r3, lr
0x00008d2c <+>: mov r0, r3
0x00008d30 <+>: sub sp, r11, #
0x00008d34 <+>: pop {r11} ; (ldr r11, [sp], #4)
0x00008d38 <+>: bx lr
End of assembler dump.
(gdb)

返回地址为r0,r0=lr,而lr保存返回地址

返回到main函数:

 (gdb) disass main
Dump of assembler code for function main:
0x00008d3c <+>: push {r4, r11, lr}
0x00008d40 <+>: add r11, sp, #
0x00008d44 <+>: sub sp, sp, #
0x00008d48 <+>: mov r3, #
0x00008d4c <+>: str r3, [r11, #-16]
0x00008d50 <+>: ldr r0, [pc, #104] ; 0x8dc0 <main+132>
0x00008d54 <+>: bl 0xfb6c <printf>
0x00008d58 <+>: sub r3, r11, #
0x00008d5c <+>: ldr r0, [pc, #96] ; 0x8dc4 <main+136>
0x00008d60 <+>: mov r1, r3
0x00008d64 <+>: bl 0xfbd8 <__isoc99_scanf>
0x00008d68 <+>: bl 0x8cd4 <key1>
0x00008d6c <+>: mov r4, r0
0x00008d70 <+>: bl 0x8cf0 <key2>
0x00008d74 <+>: mov r3, r0
0x00008d78 <+>: add r4, r4, r3
0x00008d7c <+>: bl 0x8d20 <key3>
0x00008d80 <+>: mov r3, r0
0x00008d84 <+>: add r2, r4, r3
0x00008d88 <+>: ldr r3, [r11, #-16]
0x00008d8c <+>: cmp r2, r3
0x00008d90 <+>: bne 0x8da8 <main+>
0x00008d94 <+>: ldr r0, [pc, #44] ; 0x8dc8 <main+140>
0x00008d98 <+>: bl 0x1050c <puts>
0x00008d9c <+>: ldr r0, [pc, #40] ; 0x8dcc <main+144>
0x00008da0 <+>: bl 0xf89c <system>
0x00008da4 <+>: b 0x8db0 <main+>
0x00008da8 <+>: ldr r0, [pc, #32] ; 0x8dd0 <main+148>
0x00008dac <+>: bl 0x1050c <puts>
0x00008db0 <+>: mov r3, #
0x00008db4 <+>: mov r0, r3
0x00008db8 <+>: sub sp, r11, #
0x00008dbc <+>: pop {r4, r11, pc}
0x00008dc0 <+>: andeq r10, r6, r12, lsl #
0x00008dc4 <+>: andeq r10, r6, r12, lsr #
0x00008dc8 <+>: ; <UNDEFINED> instruction: 0x0006a4b0
0x00008dcc <+>: ; <UNDEFINED> instruction: 0x0006a4bc
0x00008dd0 <+>: andeq r10, r6, r4, asr #
End of assembler dump.

第20行,key3的地址为0x8d80,

python得到key的值:

 #/usr/bin/python

 key1=0x8cdc+0x8
key2=0x8d04+0x4+0x4
key3=0x8d80 key=key1+key2+key3 print key

得到结果:

pwnable.kr leg之write up的更多相关文章

  1. 【pwnable.kr】leg

    pwnable从入门到放弃第八题. Download : http://pwnable.kr/bin/leg.cDownload : http://pwnable.kr/bin/leg.asm ssh ...

  2. pwnable.kr详细通关秘籍(二)

    i春秋作家:W1ngs 原文来自:pwnable.kr详细通关秘籍(二) 0x00 input 首先看一下代码: 可以看到程序总共有五步,全部都满足了才可以得到flag,那我们就一步一步来看 这道题考 ...

  3. pwnable.kr的passcode

    前段时间找到一个练习pwn的网站,pwnable.kr 这里记录其中的passcode的做题过程,给自己加深印象. 废话不多说了,看一下题目, 看到题目,就ssh连接进去,就看到三个文件如下 看了一下 ...

  4. pwnable.kr bof之write up

    这一题与前两题不同,用到了静态调试工具ida 首先题中给出了源码: #include <stdio.h> #include <string.h> #include <st ...

  5. pwnable.kr col之write up

    Daddy told me about cool MD5 hash collision today. I wanna do something like that too! ssh col@pwnab ...

  6. pwnable.kr brainfuck之write up

    I made a simple brain-fuck language emulation program written in C. The [ ] commands are not impleme ...

  7. pwnable.kr login之write up

    main函数如下: auth函数如下: 程序的流程如下: 输入Authenticate值,并base64解码,将解码的值代入md5_auth函数中 mad5_auth()生成其MD5值并与f87cd6 ...

  8. pwnable.kr simple login writeup

    这道题是pwnable.kr Rookiss部分的simple login,需要我们去覆盖程序的ebp,eip,esp去改变程序的执行流程   主要逻辑是输入一个字符串,base64解码后看是否与题目 ...

  9. pwnable.kr第二天

    3.bof 这题就是简单的数组越界覆盖,直接用gdb 调试出偏移就ok from pwn import * context.log_level='debug' payload='A'*52+p32(0 ...

随机推荐

  1. android设置横竖屏

    android:screenOrientation="portrait"

  2. 安装nginx+lua开发环境

    一.安装nginx及搭建本地测试环境 1.创建安装目录:    /data/nginx2.安装make:        yum-y install gcc automake autoconf libt ...

  3. java 字符串全排列 和 去重

    用递归进行排序 , 用TreeSet 去重. public class test { public static void main(String []args){ String str = &quo ...

  4. cmake的安装和卸载

    cmake介绍: CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程).他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性 ...

  5. 个人开源项目testall 持续更新中···

    项目在GitHub上:https://github.com/x113773/testall ,喜欢的给个星星呀,亲~ 打算把用到过的和学习过的,所有前后端技术都集成到这个项目里,并在issues里配以 ...

  6. DOM编程从入门到忘记

    文档对象模型(Document Object Model,DOM)是使用 W3C 定义的 API (Application Program Interface) 来操作 HTML 文档 (此处不局限于 ...

  7. java 关于 hashmap 的实现原理的测试

    网上关于HashMap的工作原理的文章多了去了,所以我也不打算再重复别人的文章.我就是有点好奇,我怎么样能更好的理解他的原理,或者说使用他的特性呢?最好的开发就是测试~ 虽说不详讲hashmap的工作 ...

  8. 图论基础之Dijkstra算法的初探

         图论,顾名思义就是有图有论.        图:由点"Vertex"和边"Edge "组成,且图分为有向图和无向图(本文讨论有向图),之前做毕业设计的 ...

  9. vijos1062题解

    题目: 交谊舞是2个人跳的,而且一男一女 -____-||||. 由于交谊舞之前的节目安排,所有的表演者都站成了一排.这一排人的顺序满足2点: ①对于一对舞伴男生站在女生的左边. ②任何一对舞伴之间, ...

  10. pgsql 递归查询 分页

    --向下查询 WITH RECURSIVE res AS ( union ALL SELECT t_tree.* FROM t_tree, res WHERE t_tree.pid = res.id ...