收获

  • 熟悉大端序、小端序存放方式

  • 找一下如果 IDA 反编译出的伪代码有问题时,有没有好的解决办法


【攻防世界】logmein


思路

将得到的 64位 elf 文件拖入 IDA

攻防世界-logmein1.png

逻辑很简单,sub_4007C0() 函数用来提示输入错误并结束程序,执行 sub_4007F0() 就代表破解成功

而通过

if ( v3 < strlen(v8) )
	sub_4007C0();

if ( i >= strlen(v8) )
	sub_4007C0();

并且循环条件 i 的范围是 for ( i = 0; i < strlen(s); ++i )
可以推断输入的字符串 s 的长度 strlen(s) = strlen(v8) = 17

因此只需满足 s[i] == (char)(v8[i % v6 - 8] ^ v8[i]) 的 s[i] 组成的就是 flag

但是这里想半天也没有搞明白 v8[i % v6 - 8] 是个什么写法,第一次循环的时候 i = 0,岂不是 v8[ -8 ]

后来看网上的 writeup,发现别人反汇编出来的伪代码跟我不一样 … …
虽然做题的时候也遇到过好几次这样的情况,但是也找不到好的解决办法
别人的伪代码:

攻防世界-logmein2.png

这里的条件是:s[i] == (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )

注意这里 v7 的定义:

__int64 v7;
v7 = 0x65 62 6D 61 72 61 68LL;

v7 的类型为 int64,即 64位 整型,属于 dq 类型的数据,存放时采用 小端序

所以 v7 的首地址处存的是 0x68,以此类推:

*((_BYTE *)&v7 + 0 % v6) = 0x68

*((_BYTE *)&v7 + 1 % v6) = 0x61

*((_BYTE *)&v7 + 2 % v6) = 0x72

*((_BYTE *)&v7 + 3 % v6) = 0x61

*((_BYTE *)&v7 + 4 % v6) = 0x6D

*((_BYTE *)&v7 + 5 % v6) = 0x62

*((_BYTE *)&v7 + 6 % v6) = 0x65

根据 (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) ) ,求解出 s[i] 并输出,得到 flag


脚本

#include <iostream>
#include <string.h>
using namespace std;
int main() {
    string v8 = ":\"AL_RT^L*.?+6/46";
    __int64 v7 = 0x65626D61726168LL;
    int key[] = {0x68,0x61,0x72,0x61,0x6d,0x62,0x65};
    int v9 = 0,v6 = 7;
    string flag = "";
    for (int i = 0; i < v8.length(); ++i )
    {
        flag += (char)(key[i % v6] ^ v8[i]);
    }
    cout<<flag;
    return 0;
}

结果

RC3-2016-XORISGUD

攻防世界-logmein3.png