re | [羊城杯 2020]babyre
linux x64
main函数很单纯,藏了一个smc,直接动调dump。
signed __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
signed int i; // [rsp+0h] [rbp-140h]
char v5; // [rsp+10h] [rbp-130h]
char v6; // [rsp+90h] [rbp-B0h]
char v7; // [rsp+A0h] [rbp-A0h]
char s; // [rsp+B0h] [rbp-90h]
char encrypted[72]; // [rsp+F0h] [rbp-50h]
unsigned __int64 v10; // [rsp+138h] [rbp-8h]
v10 = __readfsqword(0x28u);
smc(); // 这里调用了smc去自解密代码
__isoc99_scanf("%39s", &s);
if ( (unsigned int)strlen(&s) != 16 )
{
puts("Wrong!");
exit(0);
}
DES_string_to_key((__int64)"this is my key", (__int64)&v6);
if ( !(unsigned int)DES_set_key_checked((__int64)&v6, (__int64)&v5) )
{
memset(&v7, 0, 8uLL);
DES_ncbc_encrypt(&s, encrypted, 60LL, &v5, &v7, 1LL);
for ( i = 0; i <= 15; ++i )
{
if ( encrypted[i] != aim[i] ) // 16bytes对比
//
puts("wrong!");
}
if ( (*(unsigned int (__fastcall **)(char *, char *))byte_40272D)(&s, encrypted) )// 这里是一个smc
puts("Correct!");
else
puts("Wrong!");
exit(0);
}
puts("convert to key_schedule failed.");
return 0xFFFFFFFFLL;
}
接下来就是动调,顺带编译了一下openssl1.0.0,因为没有那个库(libcrypt.so)
本来想用gdb dump的,但是着实不够方便,只能一段一段dump,就用ida动调dump一下了:
__int64 __fastcall __noreturn sub_40272D(__int64 a1)
{
signed int i; // [rsp+18h] [rbp-128h]
int j; // [rsp+1Ch] [rbp-124h]
unsigned int v4; // [rsp+20h] [rbp-120h]
signed int k; // [rsp+24h] [rbp-11Ch]
signed int l; // [rsp+28h] [rbp-118h]
char v7; // [rsp+30h] [rbp-110h]
char s[31]; // [rsp+F0h] [rbp-50h]
char v9; // [rsp+10Fh] [rbp-31h]
unsigned __int64 v10; // [rsp+138h] [rbp-8h]
v10 = __readfsqword(0x28u);
__isoc99_scanf("%40s", s);
if ( (unsigned int)strlen(s) != 32 ) // 输入32字节
{
puts("Wrong!");
exit(0);
}
sub_400C91((__int64)&v7, a1); // 一眼AES,不用看了。
sub_401B8E(&v7, s);
sub_401B8E(&v7, &s[16]);
for ( i = 0; i <= 31; ++i )
{
for ( j = 0; i / 4 > j; ++j ) // 做一个xor
s[i] ^= s[j];
}
v4 = 1;
for ( k = 1; k <= 31; ++k )
convert[k - 1] = (2 * (s[k - 1] ^ 0x13) + 7) ^ ((unsigned __int8)s[k - 1] % 9u + s[k] + 2);
if ( v9 == 0xC4u )
{
for ( l = 0; l <= 30; ++l )
{
if ( convert[l] != byte_604100[l] ) // 最终对比
v4 = 0;
}
}
return v4;
}
由于上次手撕过一次AES,这次不用看了,一眼AES。
整理一下流程就是解des得到aes的key,然后位运算,最后对比。
反推的时候发现有的推不出来,看了一眼这个师傅的文章(https://blog.csdn.net/A951860555/article/details/120195840),才明白原来每个位可能是多解:
重新改写程序递归深度优先搜索答案:
exp:
from Crypto.Cipher import AES, DES
key = b"\xAD\x52\xF2\x4C\xE3\x2C\x20\xD6"
text = b"\x0A\xF4\xEE\xC8\x42\x8A\x9B\xDB\xA2\x26\x6F\xEE\xEE\xE0\xD8\xA2"
iv = b"\x00"*8
aes_key = DES.new(key, DES.MODE_CBC, iv).decrypt(text)
print(f'key: {aes_key}')
v9=0xc4
aim = [0xBD, 0xAD, 0xB4, 0x84, 0x10, 0x63, 0xB3, 0xE1, 0xC6, 0x84,
0x2D, 0x6F, 0xBA, 0x88, 0x74, 0xC4, 0x90, 0x32, 0xEA, 0x2E,
0xC6, 0x28, 0x65, 0x70, 0xC9, 0x75, 0x78, 0xA0, 0x0B, 0x9F,
0xA6, 0x00]
print(len(aim))
tmp = [0 for i in range(32)]
tmp[31] = v9
possible = []
def test_flag(i, tmp):
if i == -1:
possible.append(tmp[:])
print(tmp)
return
_tmp = tmp[:]
for j in range(256):
if ((((2 * (j ^0x13)) + 7) ^ ((j % 9) + _tmp[i+1] + 2))&0xff) == aim[i]:
_tmp[i] = j
test_flag(i-1,_tmp)
if j == 255 and ((((2 * (j ^0x13)) + 7) ^ ((j % 9) + _tmp[i+1] + 2))&0xff) != aim[i]:
return
test_flag(30, tmp)
print(possible)
print(len(possible))
for x in possible:
for i in range(31, -1, -1):
for j in range(int(i/4)):
x[i] ^= x[j]
tmp = AES.new(aes_key, AES.MODE_ECB).decrypt(bytes(x))
print(tmp)
标签:__,tmp,babyre,rbp,re,2020,key,int64,rsp
From: https://www.cnblogs.com/Mz1-rc/p/17037026.html