WriteUp – 第三届上海市大学生信息安全赛

Reverse

crackme

  • 拿到题目之后放入IDA,一开始并没注意到有壳的事,后来另一位队员起床了才告诉我。在没脱壳的情况下用IDA动态调试,在start接近return的地方下断点,单步几次之后提示EIP Points to an address which is not defined as code,点击Yes进入数据区执行代码。
  • 进入数据区之后看到输入和判断逻辑,第一次判断输入长度是否为42,更改ZF标志先绕过之后进入比对。
  • 比对部分是用输入和一个内存中的数组(mod 16逐个取)进行XOR,内存中提取该值发现是this_is_not_flag,23333,然后再和另一个数组比较。这里只需根据汇编的逻辑编写C语言代码复原一下即可得到flag。

#include <stdio.h>
int main(int argc, char *argv[]) {
    int ecx = 0, eax = 0;
//  题目的输入,也就是flag。
    char input[42] = {0};
//  第一步XOR的数组,实际上只有前16位有意义。
    char toXor[42] = {0x74,0x68,0x69,0x73,0x5F,
    0x69,0x73,0x5F,0x6E,0x6F,0x74,0x5F,0x66,
    0x6C,0x61,0x67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0x12,0,0,0,4,0,0,0,8,0};
//  第二步用于比较的数组。
    char toCmp[42] = {0x12,4,8,0x14,0x24,0x5C,0x4A,
    0x3D,0x56,0x0A,0x10,0x67,0,0x41,0,1,0x46,0x5A,
    0x44,0x42,0x6E,0x0C,0x44,0x72,0x0C,0x0D,0x40,
    0x3E,0x4B,0x5F,2,1,0x4C,0x5E,0x5B,0x17,0x6E,
    0x0C,0x16,0x68,0x5B,0x12};
//  循环XOR比较
    for(;eax!=42;eax++) {
        ecx = eax;
//      这段实际上是mod 16,但是直接按汇编的逻辑写下来也可以。
        ecx &= 0x8000000F;  //and ecx,8000000FH
        if ((ecx & 0x80000000) == 0x80000000) {
            ecx--;
            ecx |= 0xFFFFFFF0; //or ecx,0FFFFFFF0H
            ecx++;
        }
//      进行XOR操作
        input[eax] = toXor[ecx] ^ toCmp[eax];
    }
    printf("%s\n",input);
    return 0;
}
  • 最终程序输出:
flag{59b8ed8f-af22-11e7-bb4a-3cf862d1ee75}