收获

  • 熟悉大端序、小端序

  • 熟悉汇编中 str2 db 68h dup(?) 的写法


【BUUCTF】SimpleRev


思路

拖入 IDA,直接查看 main() 函数

BUUCTF-SimpleRev1.png

逻辑很简单,输入 "q/Q",执行语句:
(Decry)("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: ", argv);

查看函数 (Decry)

BUUCTF-SimpleRev2.png

注意这里的 src、v9 均为小端存放
而且 text = join(key3, v9) 中传入的参数是 v9 的首地址,即 v9[0] 的值

v9[0] 两位一组,逆序输出为字符串:v9[0] = 0x77 6F 64 61 68LL
即:0x68 0x61 0x64 0x6F 0x77,得到 “hadow

src 两位一组,逆序输出为字符串:*src = 0x53 4C 43 44 4ELL
即:0x4E 0x44 0x43 0x4C 0x53,得到 “NDCLS

根据 key3 的值 “kills

BUUCTF-SimpleRev3.png

依据题意,得到拼接处理后的字符串:
text: killshadow
key: ADSFKNDCLS

由于代码:

v5 = strlen(key);

for ( i = 0; i < v5; ++i )
{
	if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
		key[i] = key[v3 % v5] + 32;
	++v3;
}

只是一个初始化操作,并未涉及 flag 的值,直接跑一遍,发现该代码是将 key 由大写变成了小写
得到 key:adsfkndcls

最后的循环采用正向爆破来解决
循环一次读取一个输入的字符,当该字符是大写字母或者小写字母时,就进行操作:

str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;

如果是空格就跳过,处理下一个,直到全部处理完,遇到 '\n',循环结束
最后必须满足:text == str2

这里关于 str2 的定义:

BUUCTF-SimpleRev4.png

语句 str2 db 68h dup(?) 是指开辟一个 68h 长度的空间,且不进行初始化


脚本

#include <iostream>
#include <string.h>
#include <math.h>
#include <sstream>
using namespace std;
string little_endian(__int64 num, int width_num, int buffer_length, int width_buffer){
    std::stringstream ioss;     // 定义字符串流
    std::string s_temp;         // 存放转化后字符
    ioss << std::hex << num;      // 以十六制形式输出
    ioss >> s_temp;
    if(width_num > s_temp.size())
    {
        std::string s_0(width_num - s_temp.size(), '0');      // 位数不够则补0
        s_temp = s_0 + s_temp;                            // 合并
    }
    std::string s = "0x" + s_temp.substr(s_temp.length() - width_num, s_temp.length());    // 取右width位
    string buffer = "";
    for(int index=width_num; index>=2; index-=width_buffer){
        char sum = 0;
        int tmp[width_buffer];    // 存放十六进制的每一位字符转换后对应的十进制数
        for(int i=0; i<width_buffer; i++){  // 将width_buffer长度的字符串转换为十进制数,存放到sum
            if(s[index]>=97 && s[index]<=102)  // 处理a-f
                tmp[i] = 9 + s[index] - 96;
            else if(s[index]>=65 && s[index]<=70)   // 处理A-F
                tmp[i] = 9 + s[index] - 64;
            else    // 处理0-9
                tmp[i] = s[index] - 48;
            sum = sum + tmp[i] * pow(16,width_buffer-1 -i);
            index++;
        }
        index = index - width_buffer;   // 因为前面修改了index,后面还要用index控制循环,所以这里将其还原
        buffer += sum;  // 将字符sum逆向存储到 buffer字符串
        buffer_length--;
    }
    return buffer;
}

int main() {
    __int64 src = 0x534C43444ELL;
    __int64 v9[2] = {0x776F646168LL, 0LL};
    int v7 = 0LL, v8 = 0, v10 = 0;
    string key3 = "kills";
    string key1 = "ADSFK";
    string s_v9="", s_src="";// hadow   NDCLS
    s_v9 = little_endian(v9[0],10,5,2);
    s_src = little_endian(src,10,5,2);
    string text = key3 + s_v9;
    string key = key1 + s_src;
    cout<<"text: "<<text<<"   "<<"key: "<<key<<endl;
    int v5 = key.length();
    int v2 = 0, v3 = 0;
    for (int i = 0; i < v5; ++i )
    {
        if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
            key[i] = key[v3 % v5] + 32;
        ++v3;
    }
    cout<<"key: "<<key<<endl;
    for (int i = 0; i < text.length(); ++i) {
        for (int j = 32; j < 127; ++j) {
            if((j>=65 && j<=90) || (j>=97 && j<=122)){
                if(text[i] == (j - 39 - key[v3 % v5] + 97) % 26 + 97){
                    printf("%c",j);
                    ++v3;
                    break;
                }
            }
        }
        ++v2;
    }
    return 0;
}

结果

KLDQCUDFZO

BUUCTF-SimpleRev5.png