工具
DIE+IDA
思路展开
1.查壳和位数
无壳,64位
2.IDA启动
代码看着很乱,有很多很长的命令,解决办法:依据英文意思去猜测。
找关键变量的方法:从后往前找,看flag和输入关系。复杂代码本质应该是简洁的,这样才叫出题。
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
__int64 v4; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
__int64 v8; // rax
__int64 v9; // rax
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rax
__int64 v13; // rax
__int64 v14; // rax
__int64 v15; // rax
__int64 v16; // rax
char input; // [rsp+10h] [rbp-130h]
char v19; // [rsp+30h] [rbp-110h]
char v20; // [rsp+50h] [rbp-F0h]
char v21; // [rsp+70h] [rbp-D0h]
char temp; // [rsp+90h] [rbp-B0h]
char temp_2; // [rsp+B0h] [rbp-90h]
unsigned __int64 v24; // [rsp+128h] [rbp-18h]
v24 = __readfsqword(0x28u);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&input, argv, envp);
std::operator>><char,std::char_traits<char>,std::allocator<char>>(&std::cin, &input);
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "-------------------------------------------");
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Quote from people's champ");
std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
v5 = std::operator<<<std::char_traits<char>>(&std::cout, "-------------------------------------------");
std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
v6 = std::operator<<<std::char_traits<char>>(
&std::cout,
"*My goal was never to be the loudest or the craziest. It was to be the most entertaining.");
std::ostream::operator<<(v6, &std::endl<char,std::char_traits<char>>);
v7 = std::operator<<<std::char_traits<char>>(&std::cout, "*Wrestling was like stand-up comedy for me.");
std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
v8 = std::operator<<<std::char_traits<char>>(
&std::cout,
"*I like to use the hard times in the past to motivate me today.");
std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
v9 = std::operator<<<std::char_traits<char>>(&std::cout, "-------------------------------------------");
std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
HighTemplar::HighTemplar((DarkTemplar *)&temp_2, (__int64)&input);
v10 = std::operator<<<std::char_traits<char>>(&std::cout, "Checking....");
std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(__int64)&v19,
(__int64)&input);
func1((__int64)&v20, (__int64)&v19);
func2((__int64)&v21, (__int64)&v20);
func3((__int64)&v21, 0);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v21);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v20);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v19);
HighTemplar::calculate((HighTemplar *)&temp_2);
if ( (unsigned int)HighTemplar::getSerial((HighTemplar *)&temp_2) == 0 )
{
v11 = std::operator<<<std::char_traits<char>>(&std::cout, "/////////////////////////////////");
std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
v12 = std::operator<<<std::char_traits<char>>(&std::cout, "Do not be angry. Happy Hacking :)");
std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
v13 = std::operator<<<std::char_traits<char>>(&std::cout, "/////////////////////////////////");
std::ostream::operator<<(v13, &std::endl<char,std::char_traits<char>>);
ZN11HighTemplar7getFlagB5cxx11Ev((__int64)&temp, (__int64)&temp_2);
v14 = std::operator<<<std::char_traits<char>>(&std::cout, "flag{");
v15 = std::operator<<<char,std::char_traits<char>,std::allocator<char>>(v14, &temp);
v16 = std::operator<<<std::char_traits<char>>(v15, "}");
std::ostream::operator<<(v16, &std::endl<char,std::char_traits<char>>);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&temp);
}
HighTemplar::~HighTemplar((HighTemplar *)&temp_2);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&input);
return 0;
}
代码从下往上(从结果找输入)找到四句关键语句,代表的是四个处理函数,这四个函数将输入如何一步步变成flag,往下看
0x04ZN11HighTemplar7getFlagB5cxx11Ev((__int64)&temp, (__int64)&temp_2);
0x03if ( (unsigned int)HighTemplar::getSerial((HighTemplar *)&temp_2) == 0 )
0x02HighTemplar::calculate((HighTemplar *)&temp_2);
0x01HighTemplar::HighTemplar((DarkTemplar *)&temp_2, (__int64)&input);
这时从上往下看,缕清输入经历了什么。
0x01
HighTemplar::HighTemplar((DarkTemplar *)&temp_2, (__int64)&input);
unsigned __int64 __fastcall HighTemplar::HighTemplar(DarkTemplar *a1, __int64 a2)
{
char v3; // [rsp+17h] [rbp-19h]
unsigned __int64 v4; // [rsp+18h] [rbp-18h]
v4 = __readfsqword(0x28u);
DarkTemplar::DarkTemplar(a1);
*(_QWORD *)a1 = &zfc1;
*((_DWORD *)a1 + 3) = 0;
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string((__int64)a1 + 16, a2); //temp+16->输入
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string((__int64)a1 + 48, a2);//temp+48->输入
std::allocator<char>::allocator(&v3, a2);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(__int64)a1 + 80,
(__int64)"327a6c4304ad5938eaf0efb6cc3e53dc",
(__int64)&v3); //temp+80->"327a6c4304ad5938eaf0efb6cc3e53dc"
std::allocator<char>::~allocator(&v3);
return __readfsqword(0x28u) ^ v4;
}
三个赋值操作,两个位置赋值输入,一个位置赋值一串字符串
0x02
HighTemplar::calculate((HighTemplar *)&temp_2);
bool __fastcall HighTemplar::calculate(HighTemplar *this)
{
__int64 v1; // rax
_BYTE *v2; // rbx
bool result; // al
_BYTE *v4; // rbx
int i; // [rsp+18h] [rbp-18h]
int j; // [rsp+1Ch] [rbp-14h]
if ( std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16) != 32 ) //输入的长度32
{
v1 = std::operator<<<std::char_traits<char>>(&std::cout, "Too short or too long");
std::ostream::operator<<(v1, &std::endl<char,std::char_traits<char>>);
exit(-1);
}
for ( i = 0;
i <= (unsigned __int64)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);
++i )
{
v2 = (_BYTE *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](
(__int64)this + 16,
i);
*v2 = (*(_BYTE *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((__int64)this + 16, i) ^ 0x50) + 23;} //(每个字符^0x50)+23
for ( j = 0; ; ++j )
{
result = j <= (unsigned __int64)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);
if ( !result )
break;
v4=(_BYTE*)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](
(__int64)this + 16,
j);
*v4 = (*(_BYTE *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((__int64)this + 16, j) ^ 0x13)+ 11;} //(每个字符^0x13)+11
return result;
}
检查字符长度,两个简单异或运算。
0x03
if ( (unsigned int)HighTemplar::getSerial((HighTemplar *)&temp_2) == 0 )
验证函数
__int64 __fastcall HighTemplar::getSerial(HighTemplar *this)
{
char v1; // bl
__int64 v2; // rax
__int64 v3; // rax
__int64 v4; // rax
__int64 v5; // rax
unsigned int i; // [rsp+1Ch] [rbp-14h]
for ( i = 0;
(signed int)i < (unsigned __int64)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);
++i )
{
v1 = *(_BYTE *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](
(__int64)this + 80,
(signed int)i); //之前被复过值327a6c4304ad5938eaf0efb6cc3e53dc
if ( v1 != *(_BYTE *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](
(__int64)this + 16,
(signed int)i) ) //输入
{
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "You did not pass ");
v5 = std::ostream::operator<<(v4, i);
std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
*((_DWORD *)this + 3) = 1;
return *((unsigned int *)this + 3);
}
v2 = std::operator<<<std::char_traits<char>>(&std::cout, "Pass ");
v3 = std::ostream::operator<<(v2, i);
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
}
return *((unsigned int *)this + 3);
}
0x04
ZN11HighTemplar7getFlagB5cxx11Ev((__int64)&temp, (__int64)&temp_2);
__int64 __fastcall ZN11HighTemplar7getFlagB5cxx11Ev(__int64 a1, __int64 a2)
{
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(a1, a2 + 48);//取输入
return a1;
}
整体思路:一开始数据被分为三部分,一部分赋值输入,后面带入算法;一部分赋值输入,最后作为flag输出;一部分赋值一个字符串,作为比较对象。
脚本
temp='327a6c4304ad5938eaf0efb6cc3e53dc'
flag=''
for i in range(len(temp)):
n=ord(temp[i])
flag+=chr((((n-11)^0x13)-23)^0x50)
print('flag{'+flag+'}')
//flag{tMx~qdstOs~crvtwb~aOba}qddtbrtcd}
Wrestling was like stand-up comedy for me.
:p