Android
题目比较简单,使用反编译工具查看java代码如下:
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;
class a
implements View.OnClickListener
{
a(MainActivity paramMainActivity, EditText paramEditText, Context paramContext) {}
public void onClick(View paramView)
{
if (this.a.getText().toString().equals(String.format("flag{%s}", new Object[] { MainActivity.m.substring(12, 24) })))
{
Toast.makeText(this.b, "You are right!", 1).show();
return;
}
Toast.makeText(this.b, "You are wrong!", 1).show();
}
}
程序的主要算法流程是将
gUIDP@Rt}T10n$C#3m3Gu]d_par7|t)OnSCH3M3
这个字符串经过substring(12, 24)变化之后得到新的字符串,substring() 方法用于提取字符串中介于两个指定下标之间的字符,也就是说将下标12到下标20之间的字符串提取出来,结果是0n$C#3m3Gu]。
warmup-re
拖到IDA里看一下伪代码:
// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax@1
__int64 v4; // rdx@1
__int64 v5; // rax@1
__int64 v6; // rbx@1
__int64 v7; // rdx@1
__int64 v8; // rax@1
__int64 v9; // rdx@1
__int64 v10; // rax@2
__int64 v11; // rdx@2
int result; // eax@2
__int64 v13; // rax@5
__int64 v14; // rdx@5
unsigned __int64 v15; // rbx@7
unsigned __int64 v16; // rax@7
__int64 v17; // rax@8
__int64 v18; // rdx@8
char v19[48]; // [sp+20h] [bp-60h]@1
char v20[48]; // [sp+50h] [bp-30h]@1
char v21[48]; // [sp+80h] [bp+0h]@4
int v22; // [sp+B0h] [bp+30h]@1
int v23; // [sp+B4h] [bp+34h]@1
int v24; // [sp+B8h] [bp+38h]@1
int v25; // [sp+BCh] [bp+3Ch]@1
int v26; // [sp+C0h] [bp+40h]@1
int v27; // [sp+C4h] [bp+44h]@1
int v28; // [sp+C8h] [bp+48h]@1
int v29; // [sp+CCh] [bp+4Ch]@1
int v30; // [sp+D0h] [bp+50h]@1
int v31; // [sp+D4h] [bp+54h]@1
int v32; // [sp+D8h] [bp+58h]@1
int v33; // [sp+DCh] [bp+5Ch]@1
int v34; // [sp+E0h] [bp+60h]@1
int v35; // [sp+E4h] [bp+64h]@1
int v36; // [sp+E8h] [bp+68h]@1
int v37; // [sp+ECh] [bp+6Ch]@1
int v38; // [sp+F0h] [bp+70h]@1
int v39; // [sp+F4h] [bp+74h]@1
int v40; // [sp+F8h] [bp+78h]@1
int v41; // [sp+FCh] [bp+7Ch]@1
int v42; // [sp+100h] [bp+80h]@1
char v43; // [sp+10Ah] [bp+8Ah]@4
char v44; // [sp+10Bh] [bp+8Bh]@4
int i; // [sp+10Ch] [bp+8Ch]@3
_main();
v22 = 86;
v23 = 30;
v24 = 24;
v25 = 1;
v26 = 21;
v27 = 90;
v28 = 27;
v29 = 29;
v30 = 6;
v31 = 29;
v32 = 76;
v33 = 84;
v34 = 22;
v35 = 20;
v36 = 85;
v37 = 28;
v38 = 22;
v39 = 21;
v40 = 30;
v41 = 29;
v42 = 23;
LODWORD(v3) = std::operator>><char,std::char_traits<char>>(*(_QWORD *)&argc, argv, v19, refptr__ZSt3cin);
std::operator>><char,std::char_traits<char>>(*(_QWORD *)&argc, argv, v20, v3);
LODWORD(v5) = strlen(*(_QWORD *)&argc, argv, v4, v19);
v6 = v5;
LODWORD(v8) = strlen(*(_QWORD *)&argc, argv, v7, v20);
if ( v6 == v8 )
{
for ( i = 0; ; ++i )
{
v15 = i;
LODWORD(v16) = strlen(*(_QWORD *)&argc, argv, v9, v19);
if ( v15 >= v16 )
break;
v44 = v19[i];
v43 = v20[i];
v21[i] = v43 ^ v44;
v9 = (unsigned int)v21[i];
if ( (_DWORD)v9 != *(&v22 + i) )
{
LODWORD(v13) = std::operator<<<std::char_traits<char>>(*(_QWORD *)&argc, argv, "key error", refptr__ZSt4cout);
std::ostream::operator<<(
*(_QWORD *)&argc,
argv,
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_,
v13);
system(*(_QWORD *)&argc, argv, v14, "pause");
return 0;
}
}
LODWORD(v17) = std::operator<<<std::char_traits<char>>(
*(_QWORD *)&argc,
argv,
"Yes!input is flag",
refptr__ZSt4cout);
std::ostream::operator<<(
*(_QWORD *)&argc,
argv,
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_,
v17);
system(*(_QWORD *)&argc, argv, v18, "pause");
result = 0;
}
else
{
LODWORD(v10) = std::operator<<<std::char_traits<char>>(*(_QWORD *)&argc, argv, "lenth error", refptr__ZSt4cout);
std::ostream::operator<<(
*(_QWORD *)&argc,
argv,
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_,
v10);
system(*(_QWORD *)&argc, argv, v11, "pause");
result = 0;
}
return result;
}
程序的意思就是输入两个长度相等的字符串之后进行异或运算,将运算结果和程序给出的v22的数组中的内容比较,提示给出其中一个字符串是goodgoodstudydaydayup,解密脚本如下:
v1=[86,30,24,1,21,90,27,29,6,29,76,84,22,20,85,28,22,21,30,29,23]
v2=[103,111,111,100,103,111,111,100,115,116,117,100,121,100,97,121,100,97,121,117,112]
flag=[]
for i in xrange(0,21):
flag+=chr(list(v1)[i]^list(v2)[i])
print(flag)
结果是
['1', 'q', 'w', 'e', 'r', '5', 't', 'y', 'u', 'i', '9', '0', 'o', 'p', '4', 'e', 'r', 't', 'g', 'h', 'g']
reverse1
使用IDA分析,关键函数是encrypt()
v19 = 0;
LODWORD(v16) = std::string::operator[](a2, 0LL);
while ( *v16 )
{
LODWORD(v2) = std::string::operator[](a2, v19);
v3 = *v2;
LODWORD(v4) = std::vector<int,std::allocator<int>>::operator[](&primos, v19);
v18 = v3 + *v4;
LODWORD(v5) = std::string::operator[](a2, v19);
if ( (unsigned __int8)is_lower(*v5) )
{
v6 = 122;
}
else
{
LODWORD(v7) = std::string::operator[](a2, v19);
if ( (unsigned __int8)is_upper(*v7) )
{
v6 = 90;
}
else
{
LODWORD(v8) = std::string::operator[](a2, v19);
v6 = *v8;
}
}
while ( v18 > v6 )
v18 -= 26;
LODWORD(v9) = std::string::operator[](a2, v19);
v10 = v9;
LODWORD(v11) = std::string::operator[](a2, v19);
if ( *v11 == 123 )
{
v14 = 125;
}
else
{
LODWORD(v12) = std::string::operator[](a2, v19);
if ( *v12 == 125 )
{
v14 = 123;
}
else
{
LODWORD(v13) = std::string::operator[](a2, v19);
if ( (unsigned __int8)is_alphabet(*v13) )
{
v14 = v18;
}
else
{
LODWORD(v15) = std::string::operator[](a2, v19);
v14 = *v15;
}
}
}
*v10 = v14;
LODWORD(v16) = std::string::operator[](a2, ++v19);
}
std::string::string(a1, a2);
return a1;
}
查找字符串还找到了个flag
LNLNGW}o3A3g5Z_1b_Xv5d_WbzgGnbG{
程序流程是将你输入的正确的flag,每一位加上prime[]相应位置的值,如果是{}的话,{换成},}换成{。如果是字母,判断大小写运算后是否超出范围,如果超出范围就减去26直到符合大小写范围为止,然后逆推算法就可以了。比较麻烦的是prime[]是什么,程序里还有一个initial()
for ( i = 2; i <= 1023; ++i )
ehprimo[(signed __int64)i] = (i & 1) != 0;
for ( j = 3; ; j += 2 )
{
result = j;
if ( (signed int)j > 1023 )
break;
if ( ehprimo[(signed __int64)(signed int)j] )
{
std::vector<int,std::allocator<int>>::push_back(&primos, &j);
for ( k = j * j; (signed int)k <= 1023; k += j )
ehprimo[(signed __int64)(signed int)k] = 0;
}
}
return result;
}
这个函数是求0~1024之间的素数,不包括2作为prime[]的数据。
最后逆推出来flag为IIECTF{r3V3r5E_1s_Ea5y_DeadBeeF}
CrackMe
IDA反编译发现想要获得flag需要通过4个check函数:
第一个cheack
signed int check1(void)
{
signed int v1; // [sp+10h] [bp-8h]@7
puts("Give me your favourite prime number");
scanf("%lld", &n);
a = 0x100000LL;
b = 0LL;
c = 0LL;
while ( !(a & 1) )
{
a /= 2LL;
++b;
}
while ( !(b & 1) )
{
b /= 2LL;
++c;
}
if ( c == n )
{
flag += n;
v1 = 1;
}
else
{
puts("^^^^Your math is bad^^^^");
v1 = 0;
}
return v1;
}
python跑出来符合条件的数是2
a=1048576
b=0
c=0
var=a&1
while var==0:
a=a/2
var=a&1
b=b+1
print(b)
vbr=b&1
while vbr==0:
b=b/2
vbr=b&1
c=c+1
print(c)
chack2
signed int check2(void)
{
signed int v1; // [sp+24h] [bp-14h]@10
__int64 v2; // [sp+28h] [bp-10h]@1
puts("Do you know how to calculate the number");
puts("please enter a number");
scanf("%lld", &n);
v2 = n;
if ( tmpans != n * tmp % mod || n > 999999 )
goto LABEL_15;
while ( n )
{
x[++pos] = n % 10;
n /= 10LL;
}
if ( dword_448044 >= dword_448048
|| dword_448048 >= dword_44804C
|| dword_44804C >= dword_448050
|| dword_448050 >= dword_448054
|| dword_448054 >= dword_448058 )
{
LABEL_15:
puts("You do not know how to calculate the mod~~~~");
v1 = 0;
}
else
{
flag += v2;
v1 = 1;
}
return v1;
}
python代码得出符合条件的数是654321
tmpans=779852816
tmp=123456
mod=1000000007
i=1
for i in xrange(1,1000000):
if(i*tmp%mod==tmpans):
print(i)
check3
python脚本得出符合条件的字符串是Lcont=gpfoog`q
str1=[]
for i in range(14):
j=i%6+1
str1.append(j)
print(str1)
v18="MerryChristmas"
list=list(v18)
for i in range(len(list)):
list[i]=ord(list[i])
print(list)
flag=[]
for i in range(14):
flag.append(list[i]-str1[i])
print(flag)
flag1=""
for i in range(14):
flag1+=chr(flag[i])
print(flag1)
check4
在OD里动态调试修改跳转最后一个符合条件的数字是176455667
四关都过了,最后将每一关的key输入就可以了。
flag is:176455667HqGpGpFoFoEnGpHqBk
61dre
int __cdecl main(int argc, const char **argv, const char **envp)
{
bool v3; // r13@2
int v4; // eax@5
const char *v5; // rdi@11
size_t v6; // rax@11
size_t v7; // rax@15
char *v8; // rcx@15
const char *v9; // rsi@15
bool v10; // di@17
const char **v12; // [sp+0h] [bp-80h]@2
unsigned __int64 v13; // [sp+8h] [bp-78h]@11
int v14; // [sp+14h] [bp-6Ch]@5
char *s1; // [sp+18h] [bp-68h]@2
const char **v16; // [sp+20h] [bp-60h]@2
const char ***v17; // [sp+28h] [bp-58h]@2
bool v18; // [sp+37h] [bp-49h]@2
int *v19; // [sp+38h] [bp-48h]@2
const char ***v20; // [sp+40h] [bp-40h]@2
const char **v21; // [sp+48h] [bp-38h]@1
int v22; // [sp+54h] [bp-2Ch]@1
v22 = argc;
v21 = argv;
if ( !(((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1) )
goto LABEL_20;
while ( 1 )
{
v12 = v21;
v3 = (((_BYTE)x - 106 + 105) * (_BYTE)x & 1) == 0;
v20 = &v12 - 2;
v19 = (int *)&v12;
v18 = (_DWORD)v21 != 2;
v17 = &v12;
v16 = (const char **)&v12;
s1 = (char *)(&v12 - 6);
if ( ((y < 10 && v3) | (unsigned __int8)((y < 10) ^ v3)) & 1 )
break;
LABEL_20:
LODWORD(v12) = 0;
*((_DWORD *)&v12 - 4) = v22;
*(&v12 - 2) = v21;
}
if ( v18 )
{
while ( !(((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1) )
;
LABEL_5:
v4 = printf("Usage: %s flag\n", **v17, v12);
*v19 = 0;
v14 = v4;
return *v19;
}
*v16 = (const char *)&unk_400E54;
if ( strlen((*v17)[1]) != 32 )
{
while ( !(((y < 10 && (((_BYTE)x - 1) * (_BYTE)x & 1) == 0) | (unsigned __int8)((y >= 10) ^ ((((_BYTE)x - 1)
* (_BYTE)x & 1) != 0))) & 1) )
;
goto LABEL_5;
}
if ( !(((y < 10 && (((_BYTE)x - 1) * (_BYTE)x & 1) == 0) | (unsigned __int8)((y >= 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) != 0))) & 1) )
goto LABEL_23;
while ( 1 )
{
*(_DWORD *)v20 = 0;
if ( ((y < 10 && (((_BYTE)x - 1) * (_BYTE)x & 1) == 0) | (unsigned __int8)((y >= 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) != 0))) & 1 )
break;
LABEL_23:
*(_DWORD *)v20 = 0;
}
while ( 1 )
{
v5 = (*v17)[1];
v13 = *(_DWORD *)v20;
v6 = strlen(v5);
if ( v13 >= v6 )
break;
if ( !(((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1) )
goto LABEL_24;
while ( 1 )
{
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x89 | ~*(_BYTE *)v20 & 0x76) ^ ((*v17)[1][*(_DWORD *)v20] & 0x89 | ~(*v17)[1][*(_DWORD *)v20] & 0x76);
if ( ((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1 )
break;
LABEL_24:
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x38 | ~*(_BYTE *)v20 & 0xC7) ^ ((*v17)[1][*(_DWORD *)v20] & 0x38 | ~(*v17)[1][*(_DWORD *)v20] & 0xC7);
}
*(_DWORD *)v20 = *(_DWORD *)v20 - 403331085 + 403331086;
}
v7 = strlen((*v17)[1]);
v8 = s1;
s1[v7] = 0;
v9 = *v16;
if ( !strcmp(v8, *v16) )
HIDWORD(v12) = printf("yes\n", v9, v12);
do
v10 = (((_BYTE)x - 1) * (_BYTE)x & 1) == 0;
while ( !(((y < 10 && v10) | (unsigned __int8)((y < 10) ^ v10)) & 1) );
*v19 = 0;
return *v19;
}
代码很多,猛地一看肯定有点蒙,我也是看了人家的writeup才懂。。。
关键就在
(((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y< 10&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1)
这段代码里的通过动态调试x,y一直都是0,这个条件始终为真。
那么算法逻辑接下来就是
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x89 | ~*(_BYTE *)v20 & 0x76) ^ ((*v17
)[1][*(_DWORD *)v20] & 0x89 | ~(*v17)[1][*(_DWORD *)v20] & 0x76);
最后s1与
0x36,0x62,0x76,0x65,0x7F,0x6D,0x63,0x6B,0x64,0x66,0x55,0x7C,0x63,0x7
F,0x62,0x6B,0x4F,0x65,0x7A,0x76,0x4B,0x7A,0x74,0x71,0x79,0x6A,0x79,0x7A,0x68
,0x72,0x6C,0x62]
这串字符比较,爆破脚本如下:
str=[ 0x36,0x62,0x76,0x65,0x7F,0x6D,0x63,0x6B,
0x64,0x66,0x55,0x7C,0x63,0x7F,0x62,0x6B,
0x4F,0x65,0x7A,0x76,0x4B,0x7A,0x74,0x71,
0x79,0x6A,0x79,0x7A,0x68,0x72,0x6C,0x62]
flag=""
for i in range(len(str)):
for j in xrange(32,128):
if((j&0x89 | ~j&0x76)^(i&0x89 | ~i&0x76)==str[i]):
flag=flag+chr(j)
print(flag)