666
放入detectit查看发现是64位elf文件,peid什么都没发现。
看看ida中的伪代码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+0h] [rbp-1E0h]
char v5; // [rsp+F0h] [rbp-F0h]
memset(&s, 0, 0x1EuLL);
printf("Please Input Key: ", 0LL);
__isoc99_scanf("%s", &v5);
encode(&v5, &s);
if ( strlen(&v5) == key )
{
if ( !strcmp(&s, enflag) )
puts("You are Right");
else
puts("flag{This_1s_f4cker_flag}");
}
return 0;
}
结构很简单,输入的flag放到v5里面,然后再encode中加密,加密后的变量是s,然后比较长度,长度是key,key的值给出来了是18,然后加密后的s与系统中的变量enflag进行比较,相同则答案正确。
再看看encode中的加密过程:
int __fastcall encode(const char *a1, __int64 a2)
{
char v3[32]; // [rsp+10h] [rbp-70h]
char v4[32]; // [rsp+30h] [rbp-50h]
char v5[40]; // [rsp+50h] [rbp-30h]
int v6; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]
i = 0;
v6 = 0;
if ( strlen(a1) != key )
return puts("Your Length is Wrong");
for ( i = 0; i < key; i += 3 )
{
v5[i] = key ^ (a1[i] + 6);
v4[i + 1] = (a1[i + 1] - 6) ^ key;
v3[i + 2] = a1[i + 2] ^ 6 ^ key;
*(_BYTE *)(a2 + i) = v5[i];
*(_BYTE *)(a2 + i + 1LL) = v4[i + 1];
*(_BYTE *)(a2 + i + 2LL) = v3[i + 2];
}
return a2;
}
将输入的字符串每三个为一组,第一个字母加6异或key的值也就是18,第二个字母减6异或key,第三个异或6异或key
然后逆向写出脚本:
a=[0x69,0x7a,0x77,0x68,0x72,0x6f,0x7a,0x22,0x22,0x77,0x22,0x76,0x2e,0x4b,0x22,0x2e,0x4e,0x69]
key=18
flag=''
for i in range(0,18,3):
flag+=chr((a[i]^key)-6)
flag+=chr((a[i+1]^key)+6)
flag+=chr(a[i+2]^key^6)
print(flag)
流浪者
是一个elf的文件,程序逻辑很简单,因为找不到main函数,所以直接用字符串找到有加密的地方就好了。
直接给出脚本
a='abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ'
b='KanXueCTF2019JustForhappy'
c=[]
for i in range(len(b)):
for j in range(len(a)):
if a[j] == b[i]:
c.append(j)
print(c)
for i in range(0,len(c)):
if c[i]>9 or c[i]<0:
if c[i]>35 or c[i]<10:
if c[i]>61 or c[i]<36:
print("error")
else:
c[i] = c[i]+29
else:
c[i]=c[i]+87
else:
c[i]=c[i]+48
print(c)
flag=''
for i in range(len(c)):
flag+=chr(c[i])
print(flag)
testre
__int64 __fastcall sub_400700(void *a1, _QWORD *a2, __int64 a3, size_t a4)
{
unsigned __int8 *v4; // rcx
__int64 v6; // [rsp+0h] [rbp-C0h]
int c; // [rsp+8h] [rbp-B8h]
char v8; // [rsp+Fh] [rbp-B1h]
int v9; // [rsp+10h] [rbp-B0h]
bool v10; // [rsp+17h] [rbp-A9h]
unsigned __int8 *v11; // [rsp+18h] [rbp-A8h]
char v12; // [rsp+27h] [rbp-99h]
int v13; // [rsp+28h] [rbp-98h]
int v14; // [rsp+2Ch] [rbp-94h]
unsigned __int64 i; // [rsp+30h] [rbp-90h]
size_t n; // [rsp+38h] [rbp-88h]
size_t v17; // [rsp+40h] [rbp-80h]
size_t v18; // [rsp+48h] [rbp-78h]
size_t j; // [rsp+50h] [rbp-70h]
size_t v20; // [rsp+58h] [rbp-68h]
int v21; // [rsp+64h] [rbp-5Ch]
unsigned __int64 v22; // [rsp+68h] [rbp-58h]
int v23; // [rsp+74h] [rbp-4Ch]
__int64 *v24; // [rsp+78h] [rbp-48h]
__int64 v25; // [rsp+80h] [rbp-40h]
void *v26; // [rsp+88h] [rbp-38h]
int v27; // [rsp+94h] [rbp-2Ch]
size_t v28; // [rsp+98h] [rbp-28h]
__int64 v29; // [rsp+A0h] [rbp-20h]
_QWORD *v30; // [rsp+A8h] [rbp-18h]
void *s; // [rsp+B0h] [rbp-10h]
char v32; // [rsp+BFh] [rbp-1h]
s = a1;
v30 = a2;
v29 = a3;
v28 = a4;
v27 = 0xDEADBEEF;
v26 = malloc(0x100uLL);
v25 = v29;
v24 = &v6;
v22 = 0LL;
v17 = 0LL;
for ( i = 0LL; i < v28; ++i )
{
v13 = *(unsigned __int8 *)(v25 + i);
*((_BYTE *)v26 + i) = byte_400E90[i % 29] ^ v13;
*((_BYTE *)v26 + i) += *(_BYTE *)(v25 + i);
} //欺骗的部分,后面没有调用
while ( 1 )
{
v12 = 0;
if ( v17 < v28 )
v12 = ~(*(_BYTE *)(v25 + v17) != 0);
if ( !(v12 & 1) )
break;
++v17;
}
n = ((unsigned __int64)(0x28F5C28F5C28F5C3LL * (unsigned __int128)(138 * (v28 - v17) >> 2) >> 64) >> 2) + 1;
v23 = ((unsigned __int64)(0xAAAAAAAAAAAAAAABLL * (unsigned __int128)((v17 + v28) << 6) >> 64) >> 5) - 1;
v11 = (unsigned __int8 *)&v6
- ((((unsigned __int64)(0x28F5C28F5C28F5C3LL * (unsigned __int128)(138 * (v28 - v17) >> 2) >> 64) >> 2) + 16) & 0xFFFFFFFFFFFFFFF0LL);
memset(v11, 0, n);
v20 = v17;
v18 = n - 1;
while ( v20 < v28 )
{
v21 = *(unsigned __int8 *)(v25 + v20);
for ( j = n - 1; ; --j )
{
v10 = 1;
if ( j <= v18 )
v10 = v21 != 0;
if ( !v10 )
break;
v22 = v11[j] << 6;
v21 += v11[j] << 8;
v9 = 64;
v11[j] = v21 % 58;
*((_BYTE *)v26 + j) = v22 & 0x3F;
v22 >>= 6;
v21 /= 58;
v27 /= v9;
if ( !j )
break;
}
++v20;
v18 = j;
}
for ( j = 0LL; ; ++j )
{
v8 = 0;
if ( j < n )
v8 = ~(v11[j] != 0);
if ( !(v8 & 1) )
break;
}
if ( *v30 > n + v17 - j )
{
if ( v17 )
{
c = 61;
memset(s, 49, v17);
memset(v26, c, v17);
}
v20 = v17;
while ( j < n )
{
v4 = v11;
*((_BYTE *)s + v20) = byte_400EB0[v11[j]];
*((_BYTE *)v26 + v20++) = byte_400EF0[v4[j++]];//base64的符号表,但是这里也没有调用,看整个函数都使用的是base58的结构(因为有除以58)这个标志
}
*((_BYTE *)s + v20) = 0;
*v30 = v20 + 1;
if ( !strncmp((const char *)s, "D9", 2uLL)
&& !strncmp((const char *)s + 20, "Mp", 2uLL)
&& !strncmp((const char *)s + 18, "MR", 2uLL)
&& !strncmp((const char *)s + 2, "cS9N", 4uLL)
&& !strncmp((const char *)s + 6, "9iHjM", 5uLL)
&& !strncmp((const char *)s + 11, "LTdA8YS", 7uLL) )
{
HIDWORD(v6) = puts("correct!");
}
v32 = 1;
v14 = 1;
}
else
{
*v30 = n + v17 - j + 1;
v32 = 0;
v14 = 1;
}
return v32 & 1;
}
找到这一段后,可以发现有两块是虚假的,函数中都标注出来了。
直接使用base58解码就好了
key
本题是对动态调试的考察,ida中的main函数如下:
int sub_401100()
{
signed int v0; // esi
signed int v1; // esi
unsigned int v2; // edi
void **v3; // ebx
void **v4; // eax
int v5; // ecx
int v6; // ST04_4
int v7; // ST08_4
int v8; // ST0C_4
int v9; // eax
char *v10; // esi
int v11; // ecx
void **v12; // eax
signed int v13; // eax
int v14; // ecx
int v15; // eax
int v16; // eax
int v17; // eax
int v18; // eax
int v19; // eax
int v20; // eax
int v21; // eax
const char *v22; // edx
int v23; // eax
int result; // eax
int Dst; // [esp+14h] [ebp-124h]
char v26[4]; // [esp+20h] [ebp-118h]
char v27; // [esp+24h] [ebp-114h]
int v28; // [esp+5Ch] [ebp-DCh]
char v29; // [esp+61h] [ebp-D7h]
int v30; // [esp+64h] [ebp-D4h]
int v31; // [esp+68h] [ebp-D0h]
char v32; // [esp+6Ch] [ebp-CCh]
FILE *File; // [esp+70h] [ebp-C8h]
char v34; // [esp+84h] [ebp-B4h]
void *v35; // [esp+CCh] [ebp-6Ch]
int v36; // [esp+DCh] [ebp-5Ch]
unsigned int v37; // [esp+E0h] [ebp-58h]
void *v38; // [esp+E4h] [ebp-54h]
unsigned int v39; // [esp+F4h] [ebp-44h]
unsigned int v40; // [esp+F8h] [ebp-40h]
void *Memory[4]; // [esp+FCh] [ebp-3Ch]
unsigned int v42; // [esp+10Ch] [ebp-2Ch]
unsigned int v43; // [esp+110h] [ebp-28h]
__int128 v44; // [esp+114h] [ebp-24h]
__int16 v45; // [esp+124h] [ebp-14h]
char v46; // [esp+126h] [ebp-12h]
int v47; // [esp+134h] [ebp-4h]
v40 = 15;
v39 = 0;
LOBYTE(v38) = 0;
v47 = 0;
v37 = 15;
v36 = 0;
LOBYTE(v35) = 0;
LOBYTE(v47) = 1;
v0 = 0;
v42 = 1684630885;
LOWORD(v43) = 97;
*Memory = xmmword_40528C;
v45 = '.<';
v46 = 0;
v44 = xmmword_4052A4;
do
{
sub_4021E0(&v35, 1u, (*(Memory + v0) ^ *(&v44 + v0)) + 22);
++v0;
}
while ( v0 < 18 );
v1 = 0;
v43 = 15;
v42 = 0;
LOBYTE(Memory[0]) = 0;
LOBYTE(v47) = 2;
v2 = v37;
v3 = v35;
do
{
v4 = &v35;
if ( v2 >= 16 )
v4 = v3;
sub_4021E0(Memory, 1u, *(v4 + v1++) + 9);
}
while ( v1 < 18 );
memset(&Dst, 0, 184u);
sub_401620(&Dst, v5, v6, v7, v8);
LOBYTE(v47) = 3;
if ( v26[*(Dst + 4)] & 6 )
{
v9 = sub_402A00(std::cerr, "?W?h?a?t h?a?p?p?e?n?");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v9, sub_402C50);
exit(-1);
}
sub_402E90(&Dst, &v38);
v10 = &v27;
if ( File )
{
if ( !sub_4022F0(&v27) )
v10 = 0;
if ( fclose(File) )
v10 = 0;
}
else
{
v10 = 0;
}
v32 = 0;
v29 = 0;
std::basic_streambuf<char,std::char_traits<char>>::_Init(&v27);
v30 = dword_408590;
File = 0;
v31 = dword_408594;
v28 = 0;
if ( !v10 )
std::basic_ios<char,std::char_traits<char>>::setstate(&Dst + *(Dst + 4), 2, 0);
v12 = Memory;
if ( v43 >= 16 )
v12 = Memory[0];
v13 = sub_4020C0(&v38, v11, v39, v12, v42);
v14 = std::cout;
if ( v13 )
{
v22 = "=W=r=o=n=g=K=e=y=";
}
else
{
v15 = sub_402A00(std::cout, "|------------------------------|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v15, sub_402C50);
v16 = sub_402A00(std::cout, "|==============================|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v16, sub_402C50);
v17 = sub_402A00(std::cout, "|==============================|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v17, sub_402C50);
v18 = sub_402A00(std::cout, "|==============================|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v18, sub_402C50);
v19 = sub_402A00(std::cout, "\\ /\\ /\\ /\\ /\\==============|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v19, sub_402C50);
v20 = sub_402A00(std::cout, " \\/ \\/ \\/ \\/ \\=============|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v20, sub_402C50);
v21 = sub_402A00(std::cout, " |-------------|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v21, sub_402C50);
std::basic_ostream<char,std::char_traits<char>>::operator<<(std::cout, sub_402C50);
v14 = std::cout;
v22 = "Congrats You got it!";
}
v23 = sub_402A00(v14, v22);
std::basic_ostream<char,std::char_traits<char>>::operator<<(v23, sub_402C50);
sub_401570(&v34);
std::basic_ios<char,std::char_traits<char>>::~basic_ios<char,std::char_traits<char>>(&v34);
if ( v43 >= 0x10 )
sub_402630(Memory[0], v43 + 1);
if ( v2 >= 0x10 )
sub_402630(v3, v2 + 1);
result = v40;
if ( v40 >= 0x10 )
result = sub_402630(v38, v40 + 1);
return result;
}
该程序是要在指定的位置建立一个规定的内容文件,程序才能通过。
先建立好一个文本文件里面随便输入一些内容,然后在od中动态调试
用智能搜索字符串找到?W?h?a?t h?a?p?p?e?n?,然后对照ida反汇编找到main函数的入口位置,从头开始调试。
伪代码这个位置
v0 = 0;
v42 = 1684630885;
LOWORD(v43) = 97;
*Memory = xmmword_40528C;
v45 = '.<';
v46 = 0;
v44 = xmmword_4052A4;
do
{
sub_4021E0(&v35, 1u, (*(Memory + v0) ^ *(&v44 + v0)) + 22);
++v0;
}
while ( v0 < 18 );
这段是系统内的两个变量生成的字符串,输入不影响。
对应的反汇编的位置是
.text:004011A0 loc_4011A0: ; CODE XREF: sub_401100+C4↓j
.text:004011A0 mov al, byte ptr [ebp+esi+var_24]
.text:004011A4 lea ecx, [ebp+var_6C]
.text:004011A7 xor al, byte ptr [ebp+esi+Memory]
.text:004011AB add al, 16h
.text:004011AD mov [ebp+var_128], al
.text:004011B3 push dword ptr [ebp+var_128] ; char
.text:004011B9 push 1 ; Size
.text:004011BB call sub_4021E0
.text:004011C0 inc esi
.text:004011C1 cmp esi, 12h
.text:004011C4 jl short loc_4011A0
继续往下看
do
{
v4 = &v35;
if ( v2 >= 16 )
v4 = v3;
sub_4021E0(Memory, 1u, *(v4 + v1++) + 9);
}
while ( v1 < 18 );
这一段和上面的函数调用相同,同样生成了一组字符串
反汇编
.text:004011E0 loc_4011E0: ; CODE XREF: sub_401100+108↓j
.text:004011E0 cmp edi, 10h
.text:004011E3 lea eax, [ebp+var_6C]
.text:004011E6 lea ecx, [ebp+Memory]
.text:004011E9 cmovnb eax, ebx
.text:004011EC mov al, [eax+esi]
.text:004011EF add al, 9
.text:004011F1 mov [ebp+var_128], al
.text:004011F7 push dword ptr [ebp+var_128] ; char
.text:004011FD push 1 ; Size
.text:004011FF call sub_4021E0
.text:00401204 inc esi
.text:00401205 cmp esi, 12h
.text:00401208 jl short loc_4011E0
经过动态调试后,sub_401620这个函数是用来读取建立的文件中的内容的
再往下走
if ( v43 >= 16 )
v12 = Memory[0];
v13 = sub_4020C0(&v38, v11, v39, v12, v42);
v14 = std::cout;
if ( v13 )
{
v22 = "=W=r=o=n=g=K=e=y=";
}
else
{
v15 = sub_402A00(std::cout, "|------------------------------|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v15, sub_402C50);
v16 = sub_402A00(std::cout, "|==============================|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v16, sub_402C50);
v17 = sub_402A00(std::cout, "|==============================|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v17, sub_402C50);
v18 = sub_402A00(std::cout, "|==============================|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v18, sub_402C50);
v19 = sub_402A00(std::cout, "\\ /\\ /\\ /\\ /\\==============|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v19, sub_402C50);
v20 = sub_402A00(std::cout, " \\/ \\/ \\/ \\/ \\=============|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v20, sub_402C50);
v21 = sub_402A00(std::cout, " |-------------|");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v21, sub_402C50);
std::basic_ostream<char,std::char_traits<char>>::operator<<(std::cout, sub_402C50);
v14 = std::cout;
v22 = "Congrats You got it!";
}
这一段是比较字符串的地方,用动态调试通过寄存器监视可以看出来,一个部分是你输入的字符串,另一个是第二个循环出来的字符串。如果正确就会输出congrats,如果不通过就输出wrong
对应的反汇编是
.text:00401310 loc_401310: ; CODE XREF: sub_401100+1F4↑j
.text:00401310 cmp [ebp+var_28], 10h
.text:00401314 lea eax, [ebp+Memory]
.text:00401317 push [ebp+var_2C]
.text:0040131A cmovnb eax, [ebp+Memory]
.text:0040131E push eax
.text:0040131F push [ebp+var_44]
.text:00401322 push ecx
.text:00401323 lea ecx, [ebp+var_54]
最后的flag就是第二次的循环的字符串
BabyXor
本题考查的是手动脱壳。
先把文件放入ida中看源代码,反汇编是成堆的数据,显然是加壳了,但是又在查壳软件中找不到壳,可能是作者手动改文件头了,官方的wp中给的是把段地址改了。
把文件放到od中看看有什么突破口,
0043F000 > 60 pushad
0043F001 B9 00100300 mov ecx,0x31000
0043F006 BB 00100000 mov ebx,0x1000
0043F00B BA 00004000 mov edx,babyXor.00400000
0043F010 03DA add ebx,edx ; babyXor.<ModuleEntryPoint>
0043F012 8033 23 xor byte ptr ds:[ebx],0x23
0043F015 43 inc ebx
0043F016 E0 FA loopdne short babyXor.0043F012
0043F018 61 popad
0043F019 E9 82D4FCFF jmp babyXor.0040C4A0
pushad和popad都在眼前,直接试试esp定律脱壳好了
先单走一个F8执行以下pushad,然后再右边的寄存器监视一栏右键esp点击HW break[ESP]再单走一个f9,来到了jmp处,再F8来到一个一堆数据的地方,使用ctrl+a这就是原文件本来的入口处,然后再push ebp的地方右键点击用olldump脱壳调试进程,进去后再点击脱壳。
生成新的文件后,程序内容很简单,有两种做法,一种是用ida写脚本输出flag,另一种是动态调试,这边给出ida脚本。
a=[0x66,0x6d,0x63,0x64,0x7f,0x37,0x35,0x30,0x30,0x6b,0x3a,0x3c,0x3b,0x20]
b=[]
e=[0x1a,0x0,0x0,0x51,0x5,0x11,0x54,0x56,0x55,0x59,0x1d,0x9,0x5d,0x12,0x0,0x0,0x0,0x0]
c=[0x37,0x6f,0x38,0x62,0x36,0x7c,0x37,0x33,0x34,0x76,0x33,0x62,0x64,0x7a]
for i in range(14):
b.append(i^a[i])
print(b)
flag1=''
for i in range(14):
flag1+=chr(b[i])
print(flag1)
d=[0x37]
flag2=''
for i in range(1,14):
d.append(a[i]^c[i]^a[i-1])
for i in range(len(d)):
flag2+=chr(d[i])
print(flag2)
#print(len(d))
f=[]
for i in range(13):
f.append(e[i+1]^d[i]^i)
flag3=chr(0x37^0x1a)
for i in range(13):
flag3+=chr(f[i])
print(flag3)
flag=flag1+flag2+flag3
print(flag)
动态调试比较简单,可以自己尝试。
Replace
本题是AES的算法题
先把程序放入detectit里,然后发现有UPX的壳在里面,可以直接用软件脱掉不需要手脱。
脱完壳后放入ida查看源代码,有main函数就进入main函数。
代码如下
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // kr00_4
char Buf; // [esp+4h] [ebp-2Ch]
char Dst; // [esp+5h] [ebp-2Bh]
Buf = 0;
memset(&Dst, 0, 0x27u);
printf("Welcome The System\nPlease Input Key:");
gets_s(&Buf, 40u);
v3 = strlen(&Buf);
if ( (v3 - 35) <= 2 )
{
if ( sub_401090(&Buf, v3) == 1 )
printf("Well Done!\n");
else
printf("Your Wrong!\n");
}
return 0;
}
进入if比较的那个函数sub_401090。
如下:
signed int __fastcall sub_401090(int a1, int a2)
{
int v2; // ebx
int v4; // edx
char v5; // al
int v6; // esi
int v7; // edi
char v8; // al
int v9; // eax
char v10; // cl
int v11; // eax
int v12; // ecx
v2 = a1;
if ( a2 != 35 )
return -1;
v4 = 0;
while ( 1 )
{
v5 = *(v4 + v2);
v6 = (v5 >> 4) % 16;
v7 = (16 * v5 >> 4) % 16;
v8 = byte_402150[2 * v4];
if ( v8 < 48 || v8 > '9' )
v9 = v8 - 87;
else
v9 = v8 - 48;
v10 = byte_402151[2 * v4];
v11 = 16 * v9;
if ( v10 < '0' || v10 > '9' )
v12 = v10 - 87;
else
v12 = v10 - 48;
if ( byte_4021A0[16 * v6 + v7] != ((v11 + v12) ^ 25) )
break;
if ( ++v4 >= 35 )
return 1;
}
return -1;
}
有点像AES,但是可以发现可以写个脚本求出16*v6+v7,flag就是这个,就是要把最后一个字符变成}
脚本如下:
a='2a49f69c38395cde96d6de96d6f4e025484954d6195448def6e2dad67786e21d5adae6'
#print(len(a)//2)
v8=[]
v9=[]
for i in range(len(a)//2):
v8.append(ord(a[2*i]))
for i in range(len(v8)):
if v8[i] < 48 or v8[i] > 57:
v9.append(v8[i]-87)
else:
v9.append(v8[i]-48)
#print(v9)
v11=[]
v10='a49f69c38395cde96d6de96d6f4e025484954d6195448def6e2dad67786e21d5adae6'
for i in range(len(v9)):
v11.append(16*v9[i])
print(v11)
v12=[]
v13=[]
print(len(v10)//2)
for i in range(len(v10)//2):
v13.append(ord(v10[2*i]))
for i in range(len(v13)):
if v13[i] < 48 or v13[i] > 57:
v12.append(v13[i]-87)
else:
v12.append(v13[i]-48)
v12.append(0)
for i in range(len(v11)):
print((v11[i]+v12[i])^25)
sbox=[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
208, 239, 170, 251, 67, 77, 51, 133, 69 ,249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56 ,245, 188 ,182, 218 , 33, 16 ,255, 243 ,210,
205, 12 , 19, 236, 95, 151 , 68 , 23, 196 ,167, 126 , 61, 100 , 93 , 25 ,115,
96, 129 , 79, 220 , 34, 42 ,144 ,136, 70 ,238, 184 , 20, 222 , 94 ,11, 219,
224, 50, 58, 10, 73, 6 , 36 , 92, 194 ,211, 172 ,98, 145 ,149, 228 ,121,
231, 200, 55, 109, 141, 213 , 78 ,169, 108 , 86, 244 ,234, 101 ,122, 174, 8,
186, 120, 37, 46, 28, 166 ,180 ,198, 232 ,221, 116 ,31, 75, 189, 139, 138,
112, 62, 181, 102, 72, 3 ,246 , 14, 97 , 53, 87 ,185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217 ,142 ,148, 155, 30, 135, 233, 206, 85, 40 ,223,
140, 161, 137, 13, 191, 230 , 66 ,104, 65 ,153, 45, 15, 176, 84, 187, 22,]
number=[]
for i in range(len(v11)):
for j in range(256):
if sbox[j] == ((v11[i]+v12[i])^25):
number.append(j)
print(number)
flag1=''
for i in range(len(number)):
flag1+=chr(number[i])
print(flag1)
babyre1
xxtea加上CRC16的加密
进入main函数看加密的部分:
else if ( v6 == 16 )
{
v7 = sub_556D83F90C00(&v14, 16, &ptr);
if ( v7
&& (v8 = sub_556D83F91180(ptr, v7, &byte_556D84192010, 16, &v12), (v9 = v8) != 0LL)
&& v12 > 0
&& sub_556D83F913D0(v8, v12) == 0x69E2 )
{
for ( i = 0LL; v12 > i; ++i )
v9[i] ^= 0x17u;
puts(v9);
if ( ptr )
free(ptr);
free(v9);
}
题目中说答案对了会输出Bingo!
可以看到后面的puts(v9),在这之前v9还进行了和0x17的异或。
可以求出v9的变换之前的答案。
这是前六位还有10位不清楚
原题目还给出了MD5(rctf{your answer}) == 5f8243a662cf71bf31d2b2602638dc1d
还有第一个函数是说把你输入的字符转换为十六进制比如输入‘1234567890’就变成了0x12,0x34,0x56,0x78,0x90
第二个函数是xxtea加密。
第三个函数是经过两个函数变换之后的CRC校验
看一下脚本:
from hashlib import md5
import xxtea
def cmd5():
hh = '5f8243a662cf71bf31d2b2602638dc1d'
s = '557e79707836%02x%02x'
for j in range(256):
for i in range(256):
t = s%(i,j)
enc = xxtea.encrypt_hex(t.decode('hex'),'C7E0C7E0D7D3F1C6D3C6D3C6CED2D0C4'.decode('hex'),padding = False)
flag = 'rctf{'+enc+'}'
if md5(flag).hexdigest() == hh:
print flag,t
break
def main():
cmd5()
print 'end.'
if __name__ == '__main__':
main()
just reverse it
一道md5的密码题目,关键看一下关键部分
signed int __cdecl sub_4025E3(int a1, unsigned __int8 *a2)
{
char v2; // al
char v3; // al
char v4; // al
char v5; // al
int v7; // [esp+4h] [ebp-1Ch]
int v8; // [esp+8h] [ebp-18h]
int v9; // [esp+Ch] [ebp-14h]
int v10; // [esp+10h] [ebp-10h]
int v11; // [esp+14h] [ebp-Ch]
int j; // [esp+18h] [ebp-8h]
int i; // [esp+1Ch] [ebp-4h]
v8 = 0;
v9 = 0;
v10 = 0;
v11 = 0;
v7 = 0;
if ( *a2 >> 4 <= 9 )
v2 = (*a2 >> 4) + 48;
else
v2 = (*a2 >> 4) + 87;
HIBYTE(v7) = v2;
if ( (*a2 & 0xF) <= 9 )
v3 = (*a2 & 0xF) + 48;
else
v3 = (*a2 & 0xF) + 87;
BYTE1(v7) = v3;
if ( a2[1] >> 4 <= 9 )
v4 = (a2[1] >> 4) + 48;
else
v4 = (a2[1] >> 4) + 87;
LOBYTE(v7) = v4;
if ( (a2[1] & 0xF) <= 9 )
v5 = (a2[1] & 0xF) + 48;
else
v5 = (a2[1] & 0xF) + 87;
BYTE2(v7) = v5;
for ( i = 0; i <= 3; ++i )
{
if ( !*(&v8 + i) && *(&v7 + i) == *(i + a1) )
*(&v8 + i) = 1;
}
for ( j = 0; j <= 3; ++j )
{
if ( !*(&v8 + j) )
return 0;
}
return 1;
}
主要是对前面输入的值进行了变换位置然后变形,官方wp说是MD5加密。
位置变换如下abcd->dbac
看下解密脚本:
import hashlib
for i in "0123456789abcdef":
for j in "0123456789abcdef":
for k in "0123456789abcdef":
for l in "0123456789abcdef":
md5=hashlib.md5()
md5.update((i+j+k+l).encode())
#print(md5.hexdigest())
if md5.hexdigest()[:4]==l+j+i+k:
print(i+j+k+l)
#31795a469327c6e6
answer='31795a469327c6e6'
flag=''
box=[100,1,64,102,108,81,65,105,122,65,83,84,8,105,84,66]
for i in range(16):
flag+=chr(box[i]^ord(answer[i]))
print(flag)