首先看secret.cpp的代码结合“From:”来进行切入。
由于前面进行的都是声明变量,变量赋值的工作,所以从第103行开始分析。
process_key12(int * key1,int * key2)函数中*((int *) (key1 + *key1)) = *key2;
表示了将*key1
(实际变量存储地址)的所在位置向高地址增加 *key1
的偏移量处的值赋为key2的值。当然这和偏移量有关,所以现在还不知道那个值被修改了。
继续向下看源码,发现start = 0, stride =1。
然后是process_key34(),查看代码后发现实类似的操作,先放着。
然后开始extract_message1(start, stride)
密文的decode操作。将start = 0,stride = 1带代入,发现是一个死循环,所以此时start和stride的值并不对,那么如何修改呢,发现是process_key12()的影响,于是研究此函数:
- 局部变量的生成顺序是dummy,start,stride,key1,key2,由于栈是从高地址向低地址进行分配的,所以
*key
是一个正数并且process函数只能修改一个数的值而start和stride都由dummy来初始决定,所以显而易见修改了dummy的值,所以key1的值为3(因为有dummy,start,stride三个4字节int值),接下来需要确定key2的值。 -
start = (int)(*(((char *) &dummy)));
stride = (int)(*(((char *) &dummy) + 1));
这两段是start的赋值,可以看到先转成char指针,在转成int值,而char占用1字节,int占用4字节,所以(_ _ _ _
,表示dummy的四个字节,而程序里以字节为单位来逆序排列dummy的四个字节,如dummy=340,内存内dummy的字节序列是(低地址到高地址)15 04 00 00
,由此可以看出,不仅栈是从高地址向低地址来分配的,而且变量的字节是由高地址向低地址00000415读取的)。 - 现在根据From:的ascii码值来找,发现为46 72 6F 6D 3A,然后在data中查找,注意data在内存中以4字节唯一单位,四字节内部顺序是高地址向低地址读取,所以并不是纯粹的data中的那些顺序,而且data中的4字节是从最后一个开始压进栈中的。所以加法操作后到高地址,正好可以到达data后面的字节中。
- 现在来看for循环,i变量只是提供message[i]中i的作用,内部变量循环stride-1次,出来后又+1,现在来观察几个字节出现的顺序,后面的数值是距离*data的距离,即+j。
46: 9 *10* 20
72: *11* 12 21
6F: *13* 15
6D: *14* 19
3A: *16*
可以看到内部循环为两次,所以stride=3,start = 10 -1 =9,所以key2=0x00000309=777.
之后得到结果
From: Friend
To: You
Good! Now try choosing keys3,4 to force a call to extract2 and
avoid the call to extract1
发现还有第二段密文,然我们用key3和key4来绕过extract1,所以需要更改process_key34之后的返回地址。
process_key34的函数过程为*(((int *)&key3) + *key3) += *key4;
,*key3
为偏移量,此处&key3指的是形参中的key3,所以就和函数栈有关。我们知道形参是从右往左入栈的,而在形参入栈后,会把函数返回地址加上,所以函数返回地址是在key3的下面(低地址处),所以*key3
的值为-1,所以函数的返回地址增加多少才能绕过exetract_message1呢,此时我们反汇编源程序,查看exetract_message1和exetract_message2的函数地址。
0x100000ead <+253>: callq 0x100000c10 ; process_keys34 at main.c:57
0x100000eb2 <+258>: movl -0x18(%rbp), %edi
0x100000eb5 <+261>: movl -0x1c(%rbp), %esi
0x100000eb8 <+264>: callq 0x100000c40 ; extract_message1 at main.c:62
0x100000ebd <+269>: movq %rax, -0x38(%rbp)
0x100000ec1 <+273>: movq -0x38(%rbp), %rax
0x100000ec5 <+277>: movsbl (%rax), %esi
0x100000ec8 <+280>: cmpl $0x0, %esi
0x100000ece <+286>: jne 0x100000f0a ; <+346> at main.c:128
0x100000ed4 <+292>: leaq -0x28(%rbp), %rdi
0x100000ed8 <+296>: leaq -0x2c(%rbp), %rsi
0x100000edc <+300>: callq 0x100000c10 ; process_keys34 at main.c:57
0x100000ee1 <+305>: movl -0x18(%rbp), %edi
0x100000ee4 <+308>: movl -0x1c(%rbp), %esi
0x100000ee7 <+311>: callq 0x100000d30 ; extract_message2 at main.c:82
所以key4= 311 - 264 = 47。
虽然key3和key4带进去都没有得到正确的值,但是我尽力了。~~
综上,key1 = 3,key2 = 777,key = -1,key4 = 47。