MRCTF2020 EasyCPP
两个月前做过一次 当时逆向功底太浅了 记录下以现在的视角来看这道题
main逻辑不难
大致放下分析后的代码:
for ( i = 0; i <= 8; ++i )
{
std::istream::operator>>(&std::cin, &INPUT[i]);
std::to_string((std::__cxx11 *)v24, INPUT[i], (unsigned int)INPUT[i], v4, v5, v6);
std::string::operator+=(v20, v24);
std::string::~string(v24);
}
v30 = INPUT;
v31 = INPUT;
v29 = (int *)&unk_55B3A773E3E4;
while ( v31 != v29 )
{
v19 = *v31;
std::vector<int>::push_back(_INPUT_, &v19);
++v31;
}
v7 = std::vector<int>::end(_INPUT_);
v8 = std::vector<int>::begin(_INPUT_);
std::for_each<__gnu_cxx::__normal_iterator<int *,std::vector<int>>,main::{lambda(int &)#1}>(v8, v7);// foreach xor 0x1??? 应该是做了某种分隔
v28 = _INPUT_;
v18 = std::vector<int>::begin(_INPUT_);
v17 = std::vector<int>::end(v28);
while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int>>(&v18, &v17) )
{
v27 = *(_DWORD *)__gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator*((__int64)&v18);
std::allocator<char>::allocator(&v25);
std::string::basic_string(v16, &unk_55B3A773B00E, &v25);
std::allocator<char>::~allocator(&v25);
depart(v27, (__int64)v16); // !!! depart!!! ctm这看漏了...
{lambda(std::string &)#1}::operator()((__int64)&func, (__int64)v16);// 替换某些字符
std::string::basic_string(v26, v16);
v9 = !{lambda(std::string,int)#2}::operator()((__int64)&check, (__int64)v26, v33);// cmp比较
std::string::~string(v26);
与第一遍相比 这次能够独立的找到上次没发现的点
至少同第一次相比 对于c++的lamda/vector等没那么反感了 反而因为逆向逆多了有种莫名亲切感:(
这里很容易找到foreach xor 1
关键是从最后的check入手 发现里面有个没有初始赋值的ans数组 查看交叉引用就可以找到(虽然我是瞎翻翻到的 殊途同归)
if ( a1 == 1 && a2 == 0xFFFF )
{
std::ios_base::Init::Init((std::ios_base::Init *)&std::__ioinit);
__cxa_atexit((void (__fastcall *)(void *))&std::ios_base::Init::~Init, &std::__ioinit, &_dso_handle);
std::allocator<char>::allocator(&v3);
std::string::basic_string(&ans[abi:cxx11], "=zqE=z=z=z", &v3);
std::allocator<char>::~allocator(&v3);
std::allocator<char>::allocator(&v4);
std::string::basic_string((char *)&ans[abi:cxx11] + 32, "=lzzE", &v4);
std::allocator<char>::~allocator(&v4);
std::allocator<char>::allocator(&v5);
std::string::basic_string((char *)&ans[abi:cxx11] + 64, "=ll=T=s=s=E", &v5);
std::allocator<char>::~allocator(&v5);
std::allocator<char>::allocator(&v6);
std::string::basic_string((char *)&ans[abi:cxx11] + 96, "=zATT", &v6);
std::allocator<char>::~allocator(&v6);
std::allocator<char>::allocator(&v7);
std::string::basic_string((char *)&ans[abi:cxx11] + 128, "=s=s=s=E=E=E", &v7);
std::allocator<char>::~allocator(&v7);
std::allocator<char>::allocator(&v8);
std::string::basic_string((char *)&ans[abi:cxx11] + 160, "=EOll=E", &v8);
std::allocator<char>::~allocator(&v8);
std::allocator<char>::allocator(&v9);
std::string::basic_string((char *)&ans[abi:cxx11] + 192, "=lE=T=E=E=E", &v9);
std::allocator<char>::~allocator(&v9);
std::allocator<char>::allocator(&v10);
std::string::basic_string((char *)&ans[abi:cxx11] + 224, "=EsE=s=z", &v10);
std::allocator<char>::~allocator(&v10);
std::allocator<char>::allocator(v11);
std::string::basic_string((char *)&ans[abi:cxx11] + 256, "=AT=lE=ll", v11);
std::allocator<char>::~allocator(v11);
return __cxa_atexit(_tcf_0, 0LL, &_dso_handle);
}
这里看到一些奇奇怪怪的字符串
继续往前回溯
前面有个lamda1
这就找到第一次竟然没找到的点...
qmemcpy(v25, "O0", sizeof(v25));
v2 = std::string::end(a2);
v3 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v3, v2, &v25[1], v25);
qmemcpy(v26, "l1", sizeof(v26));
v4 = std::string::end(a2);
v5 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v5, v4, &v26[1], v26);
qmemcpy(v27, "z2", sizeof(v27));
v6 = std::string::end(a2);
v7 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v7, v6, &v27[1], v27);
qmemcpy(v28, "E3", sizeof(v28));
v8 = std::string::end(a2);
v9 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v9, v8, &v28[1], v28);
qmemcpy(v29, "A4", sizeof(v29));
v10 = std::string::end(a2);
v11 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v11, v10, &v29[1], v29);
qmemcpy(v30, "s5", sizeof(v30));
v12 = std::string::end(a2);
v13 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v13, v12, &v30[1], v30);
qmemcpy(v31, "G6", sizeof(v31));
v14 = std::string::end(a2);
v15 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v15, v14, &v31[1], v31);
qmemcpy(v32, "T7", sizeof(v32));
v16 = std::string::end(a2);
v17 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v17, v16, &v32[1], v32);
qmemcpy(v33, "B8", sizeof(v33));
v18 = std::string::end(a2);
v19 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v19, v18, &v33[1], v33);
qmemcpy(v34, "q9", sizeof(v34));
v20 = std::string::end(a2);
v21 = std::string::begin(a2);
std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v21, v20, &v34[1], v34);
qmemcpy(v35, "= ", 2);
v22 = std::string::end(a2);
v23 = std::string::begin(a2);
return std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v23, v22, &v35[1], v35);
就是把0~9作了个map映射 而且'='是' '分隔符
这样替换完就是这种:
enc = [" 293 2 2 2"," 1223"," 11 7 5 5 3"," 2477"," 5 5 5 3 3 3"," 3011 3"," 13 7 3 3 3"," 353 5 2"," 47 13 11"]
开始猜测是在输入那儿作了些处理? 动调在那儿看了看 啥也没看出来
结果发现眼瞎漏掉了已经符号化的depart函数... 服了
__int64 __fastcall depart(int a1, __int64 a2)
{
__int64 v2; // rcx
__int64 v3; // r8
int v4; // r9d
char v6[32]; // [rsp+20h] [rbp-60h] BYREF
char v7[40]; // [rsp+40h] [rbp-40h] BYREF
int i; // [rsp+68h] [rbp-18h]
int v9; // [rsp+6Ch] [rbp-14h]
v9 = a1;
for ( i = 2; std::sqrt<int>((unsigned int)a1) >= (double)i; ++i )// 找因子! 质因数分解
{
if ( !(a1 % i) )
{
v9 = i;
depart(a1 / i, a2);
break;
}
}
std::to_string((std::__cxx11 *)v7, v9, (unsigned int)v9, v2, v3, v4);
std::operator+<char>(v6, &unk_55B3A773B00C, v7);
std::string::operator+=(a2, v6);
std::string::~string(v6);
return std::string::~string(v7);
}
这就是个很明显的质因数分解了 看看enc 确实是质数乘积的形式
那么我们每个里面乘回去 记得xor 1 就可以得到最初的key 运行验证正确
enc = ["=zqE=z=z=z","=lzzE","=ll=T=s=s=E","=zATT","=s=s=s=E=E=E","=EOll=E","=lE=T=E=E=E","=EsE=s=z","=AT=lE=ll"]
enc = [" 293 2 2 2"," 1223"," 11 7 5 5 3"," 2477"," 5 5 5 3 3 3"," 3011 3"," 13 7 3 3 3"," 353 5 2"," 47 13 11"]
key =[293*2*2*2,1223,11*7*5*5*3,2477,5*5*5*3*3*3,3011*3,13*7*3*3*3,353*5*2,47*13*11]
for x in key:
print(x^1,end=' ')
最后大写md5(234512225774247633749032245635316720)
flag{4367FB5F42C6E46B2AF79BF409FB84D3}
总结:
发现练了两个月逆向能力还是有点提升的:(