0x1
MIPS架构,可以用能成功反编译的ida版本去反编译,内容的理解实际上不用动调,个人采取了动调,一是正好配置相关环境,二是尝试一下MIPS架构的动调。
之前配置过,但是运行不起来,只能重装
0x2
反汇编后,
pre中(将函数修改成无返回值后):
void __fastcall pre(int a1)
{
int v1; // $v0
_BOOL4 v2; // $s0
int v3; // $v0
char v5[4]; // [sp+20h] [+20h] BYREF
char v6[24]; // [sp+24h] [+24h] BYREF
char v7[24]; // [sp+3Ch] [+3Ch] BYREF
if ( std::__cxx11::basic_string,std::allocator>::length(a1) != 14 )// len==14
{
v1 = std::operator<<>(&std::cout, "redemption code format error");
std::ostream::operator<<(v1, &std::endl>);
exit(-1);
}
std::allocator::allocator(v5);
std::__cxx11::basic_string,std::allocator>::basic_string(
v6,
"Ninja Must Die 3 Is A Cruel Game, So Hard For Me",
v5); // 将字符串保存到v6中
std::__cxx11::basic_string,std::allocator>::basic_string(v7, a1);// 将flag传递给v7
v2 = server_check_redemption_code((int)v6, (int)v7) == -1;// 不能返回-1,说明有解
std::__cxx11::basic_string,std::allocator>::~basic_string(v7);
std::__cxx11::basic_string,std::allocator>::~basic_string(v6);
std::allocator::~allocator(v5);
if ( v2 )
{
v3 = std::operator<<>(&std::cout, "game error");
std::ostream::operator<<(v3, &std::endl>);
exit(-2);
}
}
server_check_redemption_code内:
int __fastcall server_check_redemption_code(int cmp, int flag)
{
unsigned int len2; // $v0
int tmp; // [sp+18h] [+18h]
int i; // [sp+1Ch] [+1Ch]
int j; // [sp+20h] [+20h]
int v7; // [sp+24h] [+24h]
int k; // [sp+28h] [+28h]
int len1; // [sp+34h] [+34h]
int flag_len; // [sp+38h] [+38h]
void *s; // [sp+3Ch] [+3Ch]
if ( std::operator==<char>(flag, &unk_401D94) )
return 0;
len1 = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(cmp);
len2 = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(flag);
flag_len = len2;
if ( len2 >= 0x200000 )
_cxa_throw_bad_array_new_length();
s = (void *)operator new[](len2 << 10);
memset(s, 0, flag_len << 10);
*((_DWORD *)s
+ *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](flag, 0)) = 1;// 开拓空间
tmp = 0;
for ( i = 1; i < flag_len; ++i )
{
for ( j = 0; j < 256; ++j )
{
if ( j != *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](
flag,
i) ) // j != flag[i]
*((_DWORD *)s + 256 * i + j) = *((_DWORD *)s + 256 * tmp + j);// s[i][j] = s[tmp][j]
else
*((_DWORD *)s + 256 * i + j) = i + 1; // s[i][j] = i+1
}
tmp = *((_DWORD *)s
+ 256 * tmp
+ *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](flag, i));// tmp = s[tmp][flag[i]]
}
v7 = 0;
for ( k = 0; k < len1; ++k )
{
v7 = *((_DWORD *)s
+ 256 * v7
+ *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](cmp, k));// v7 = s[v7][cmp[k]]
if ( v7 == flag_len ) // 判断s[v7][cmp[k]]位置处的值是否为14
return k - flag_len + 1;
}
return -1;
}
两个函数都看完后,确定pre函数功能:判断输入值长度是否为14,输入值其中与指定字符串相同的字符数至少有一个。
主函数server_check_redemption_code函数返回值为7,有:
k - flag_len + 1 =7
//flag_len=14
==> k = 20
可以得到如下关系:
flag ∈ "Ninja Must Die 3 Is A Cruel Game, So Hard For Me"
flag ∈ "I Love Ninja Must Die 3. Beautiful Art And Motive Operation Is Creative."[:21]
len(flag)==14
直接推出flag:
Ninja Must Die
套个壳:
flag{Ninja Must Die}