Reverse(五)
BUUCTF
1. xor
exeinfope查看无壳64位,ida64位打开,定位到main的伪C代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+2Ch] [rbp-124h]
char __b[264]; // [rsp+40h] [rbp-110h] BYREF
memset(__b, 0, 0x100uLL);
printf("Input your flag:\n");
get_line(__b, 256LL);
if ( strlen(__b) != 33 )
goto LABEL_7;
for ( i = 1; i < 33; ++i )
__b[i] ^= __b[i - 1];
if ( !strncmp(__b, global, 0x21uLL) )
printf("Success");
else
LABEL_7:
printf("Failed");
return 0;
}
可以看到输入的__b经过各位异或后和global对比,相同即可成功
查看global变量,正好33位,写出python逆向解密的脚本
data = ['f', 0xA, 'k', 0xC, 'w', '&', 'O', '.', '@', 0x11, 'x', 0xD, 'Z', ';', 'U', 0x11, 'p', 0x19, 'F', 0x1F, 'v',
'"', 'M', '#', 'D', 0xE, 'g', 6, 'h', 0xF, 'G', '2', 'O']
flag = 'f'
for i in range(0, len(data)):
if isinstance(data[i], str):
data[i] = ord(data[i])
for i in range(1, len(data)):
flag += chr(data[i] ^ data[i - 1])
print(flag)
得到flag{QianQiuWanDai_YiTongJiangHu}
也可以shift+E选中C unsigned char array(hex),可以直接 全部复制为十或十六进制
2. helloworld
使用ida打开apk文件时,开始要注意选择文件格式
shift+F12查找跟flag相关的字符串即可
3. reverse3
无壳32位,ida打开查看字符串,看到了和base64相关的信息,初步猜想有这方面的加密解密
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
const char *v4; // eax
size_t v5; // eax
char v7; // [esp+0h] [ebp-188h]
char v8; // [esp+0h] [ebp-188h]
signed int j; // [esp+DCh] [ebp-ACh]
int i; // [esp+E8h] [ebp-A0h]
signed int v11; // [esp+E8h] [ebp-A0h]
char Destination[108]; // [esp+F4h] [ebp-94h] BYREF
char Str[28]; // [esp+160h] [ebp-28h] BYREF
char v14[8]; // [esp+17Ch] [ebp-Ch] BYREF
for ( i = 0; i < 100; ++i )
{
if ( i >= 0x64 )
j____report_rangecheckfailure();
Destination[i] = 0;
}
sub_41132F("please enter the flag:", v7);
sub_411375("%20s", Str);
v3 = j_strlen(Str);
v4 = sub_4110BE(Str, v3, v14);
strncpy(Destination, v4, 0x28u);
v11 = j_strlen(Destination);
for ( j = 0; j < v11; ++j )
Destination[j] += j;
v5 = j_strlen(Destination);
if ( !strncmp(Destination, Str2, v5) )
sub_41132F("rigth flag!\n", v8);
else
sub_41132F("wrong flag!\n", v8);
return 0;
}
v4 = sub_4110BE(Str, v3, v14);
中的sub_4110BE是base64加密函数,然后for循环对每一位进行了移位操作后与Str2对比,查看Str2
首先脚本解密移位
data = 'e3nifIH9b_C@n@dH'
k = 0
flag = ''
for i in data:
flag += chr(ord(i) - k)
k += 1
print(flag)
得e2lfbDB2ZV95b3V9,再base64解密得{i_l0ve_you}
4. 不一样的flag
32位无壳,
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
_BYTE v3[29]; // [esp+17h] [ebp-35h] BYREF
int v4; // [esp+34h] [ebp-18h]
int v5; // [esp+38h] [ebp-14h] BYREF
int i; // [esp+3Ch] [ebp-10h]
_BYTE v7[12]; // [esp+40h] [ebp-Ch] BYREF
__main();
v3[26] = 0;
*(_WORD *)&v3[27] = 0;
v4 = 0;
strcpy(v3, "*11110100001010000101111#");
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v5);
if ( v5 == 2 )
{
++*(_DWORD *)&v3[25];
}
else if ( v5 > 2 ) // 大于2的输入为3、4才可
{
if ( v5 == 3 )
{
--v4;
}
else
{
if ( v5 != 4 )
LABEL_13:
exit(1);
++v4;
}
}
else
{
if ( v5 != 1 )
goto LABEL_13;
--*(_DWORD *)&v3[25];
}
for ( i = 0; i <= 1; ++i )
{
if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 )
exit(1);
}
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 49 )
exit(1);
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 35 )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}
转换十进制数为char,可以看出最后要到#位置,如果到了1就会失败退出
呃,貌似是走迷宫,就是这串字符*11110100001010000101111#
排列成5*5
* | 1 | 1 | 1 | 1 |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 0 | 0 | 1 | 0 |
1 | 1 | 1 | 1 | # |
这么走flag就是222441144222
5. SimpleRev
无壳64位,ida64查看伪代码
第一页没什么线索,关键在于进入了Decry的函数,这个函数里有了flag和输入的对比
unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h] BYREF
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
int v10; // [rsp+50h] [rbp-10h]
unsigned __int64 v11; // [rsp+58h] [rbp-8h]
v11 = __readfsqword(0x28u);
*(_QWORD *)src = 0x534C43444ELL;
v7 = 0LL;
v8 = 0;
v9[0] = 0x776F646168LL;
v9[1] = 0LL;
v10 = 0;
text = (char *)join(key3, v9);
strcpy(key, key1);
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
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;
}
printf("Please input your flag:");
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;
}
else
{
if ( v1 <= 96 || v1 > 122 )
{
if ( v1 > 64 && v1 <= 90 )
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
}
else
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
if ( !strcmp(text, str2) )
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v11;
}
定位到对比的是text和str2
先看text = (char *)join(key3, v9);
,由key3和v9组成
key3='kills',v9[0] = 0x776F646168LL;
转换为char同时大端改小端,v9=hadow,合起来text='killshadow',挺对头的
再看str2,定位到包含str2的部分代码
看到了97、26等貌似和大小写有关的字眼,同时关键在key字符串,定位到key
key1先复制到key,key再和src组合起来,查看key1和src的值
key1='ADSFK'
src='SLCDN',结合大端改小端,得到key='ADSFKNDCLS',又经过28-34行转换为小写key='adsfkndcls'
下面分析如何输入生成str2,str2就是text的值
str2 = 'killshadow'
key = 'adsfkndcls'
input = ''
for i in range(len(str2)):
for j in range(26):
if str2[i] == chr((j + 65 - 39 - ord(key[i % len(key)]) + 97) % 26 + 97):
input += chr(j+65)
print(input)
flag{KLDQCUDFZO}