题就不重复了,不知道自己去搜吧。
首先明确的是
1. start为dummy的低地址起第一字节,stride为第二字节
2. stride为大于等于2的正整数(因为是1字节的,故小于等于127),否则是个死循环
3. 如果dummy=1,那么start=1, stride=0,因此在process_keys12(&key1, &key2);这一行代码必然改变了dummy的值
好,有了以上三点认识,我们来看看process_keys12()的代码:
[code=c]
void process_keys12 (int * key1, int * key2) {
*((int *) (key1 + *key1)) = *key2;
}
[/code]
显然这语句的意思是key1的地址向后位移key1的值个单位,等于key2的值。因为我们必须改变dummy的值,按照所谓的activation record,dummy的地址在key1后3个单位(都在一个堆栈里),因此确定key1=3。key2的值无法确定,但是关系到两个重要参数start和stride的值。我们必须分析char * extract_message1(int start, int stride)函数,该函数如下:
[code=c]
char * extract_message1(int start, int stride) {
int i, j, k;
int done = 0;
for (i = 0, j = start + 1; ! done; j++) {
for (k = 1; k < stride; k++, j++, i++) {
if (*(((char *) data) + j) == '\0') {
done = 1;
break;
}
message[i] = *(((char *) data) + j);
}
}
message[i] = '\0';
return message;
}
[/code]
我们分析如下:
1. 内层循环结束后外层循环将j+1,而不改变i值。也就是说,必然每个1个单位取stride-1个字母
2. 对于每个整数而言,没字节顺序是相反的
3. 已知的5个字母的ascii码为0x46726f6d3a,显然,不是连续取5个,同样,也没有46726f6d这样4个连在一起的,而46726f的情况在data中有1组,在prologue中有两组(会取到prologue的前提是这三个数组在内存分配上是连续的,我们假设这样),如果是三个一组,那么在46726f后隔一字节必能找到6d3a的连续,但是没有说明也不是3个一组
4. 若两个一组,则必有4672xx6f6dxx3a这样的序列,因6d较少,只有4个,因此按6d分析。不论是两个一组还是一个一组,必有6dxx3a的序列,仅有data[3]=0x6F6D6F72中的6d符合条件,进而可以分析出是两个一组,因此可以计算出start=9, stride=3
5. 因此可以算出summy=key2=0x????0309,这里网上很多人用穷举算出key2=777这是不完全的,只要满足key2=0x????0309的整数都可以满足条件。
下面开搞key3和key4分析main剩下的代码:
[code=c]
if (key3 != 0 && key4 != 0) {
process_keys34(&key3, &key4);
}
msg1 = extract_message1(start, stride);
if (*msg1 == '\0') {
process_keys34(&key3, &key4);
msg2 = extract_message2(start, stride);
printf("%s\n", msg2);
}
else {
printf("%s\n", msg1);
}
[/code]
1. 经过process_keys34(&key3, &key4);一折腾,原来好好的msg1就变成NULL了
2. 首先想是不是process_keys34(&key3, &key4);把start和stride换了,导致上来msg1就是NULL,因为后面代码已经不能再修改start和stride了,也就是说必有0x0046这样的组合连在一起,因为start+1==0x00,start==0x46
3. 遗憾的是找不到这样的组合,那么我们换个思路:process_keys34(&key3, &key4);修改返回地址,直接到我们想去的地方,返回地址和key3地址的位置为-1因此不能得出key3=-1,下面算key4:
[code=shell]
#假设目标文件为decode
$ objdump -d decode > as.txt
[/code]
得到的as.txt就是我们程序的反汇编文件找到main我们需要的部分
[code=asm]
804871a: e8 cb fd ff ff call 80484ea <process_keys34>
804871f: 8b 44 24 34 mov 0x34(%esp),%eax
8048723: 89 44 24 04 mov %eax,0x4(%esp)
8048727: 8b 44 24 38 mov 0x38(%esp),%eax
804872b: 89 04 24 mov %eax,(%esp)
804872e: e8 e3 fd ff ff call 8048516 <extract_message1>
8048733: 89 44 24 20 mov %eax,0x20(%esp)
8048737: 8b 44 24 20 mov 0x20(%esp),%eax
804873b: 0f b6 00 movzbl (%eax),%eax
804873e: 84 c0 test %al,%al
8048740: 75 3a jne 804877c <main+0x184>
8048742: 8d 44 24 24 lea 0x24(%esp),%eax
8048746: 89 44 24 04 mov %eax,0x4(%esp)
804874a: 8d 44 24 28 lea 0x28(%esp),%eax
804874e: 89 04 24 mov %eax,(%esp)
8048751: e8 94 fd ff ff call 80484ea <process_keys34>
8048756: 8b 44 24 34 mov 0x34(%esp),%eax
804875a: 89 44 24 04 mov %eax,0x4(%esp)
804875e: 8b 44 24 38 mov 0x38(%esp),%eax
8048762: 89 04 24 mov %eax,(%esp)
8048765: e8 35 fe ff ff call 804859f <extract_message2>
[/code]
也就是第一次调用process_key34和调用extract_message2之间的代码,第一次调用返回代码应为extract_message1,其地址为2e(忽略前面相同的部分),我们要转到的地址为65,因此key4=0x65-0x2e=0x37=55
这个值是根据你操作系统编译结果得来的,因此不同机器上不同,最后程序结果为:
From: CTE
To: You
Excellent!You got everything!