逆向攻防世界CTF系列50-testre
定位

跟进400D00

逻辑:接收输入,长度17,最后附上一个0符号(可能代表结束符)
跟进sub_400700
复杂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| __int64 __fastcall sub_400700(void *a1, _QWORD *a2, __int64 a3, size_t a4){ s = a1; v30 = a2; v29 = a3; v28 = a4; v27 = -559038737; 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 % 0x1D] ^ v13; *((_BYTE *)v26 + i) += *(_BYTE *)(v25 + i); } while ( 1 ){ v12 = 0; if ( v17 < v28 ) v12 = ~(*(_BYTE *)(v25 + v17) != 0); if ( (v12 & 1) == 0 ) break; ++v17; } n = 138 * (v28 - v17) / 0x64 + 1; v23 = ((v17 + v28) << 6) / 0x30 - 1; v11 = (unsigned __int8 *)v6 - ((138 * (v28 - v17) / 0x64 + 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) == 0 ) 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++]]; } *((_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)){ v6[1] = puts("correct!"); } v32 = 1; v14 = 1; } else{ *v30 = n + v17 - j + 1; v32 = 0; v14 = 1; } return v32 & 1; }
|
关键是最后得是s=D9cS9N9iHjMLTdA8YSMRMp
代码很长,硬着头看,第一部分:
1 2 3 4 5 6
| for ( i = 0LL; i < v28; ++i ) { v13 = *(unsigned __int8 *)(v25 + i); *((_BYTE *)v26 + i) = byte_400E90[i % 0x1D] ^ v13; *((_BYTE *)v26 + i) += *(_BYTE *)(v25 + i); }
|
v28是长度也就是a4 ,v13是输入,看了下后面v26好像没有怎么用到,并且这里的逻辑好像是v13=input,v26=input^a,v26=input,其实v26改成了input而已,跟踪也知道这暗示是个假的

1 2 3 4 5 6
| while ( 1 ){ v12 = 0; if ( v17 < v28 ) v12 = ~(*(_BYTE *)(v25 + v17) != 0); if ((v12 & 1) == 0 ) break; ++v17; }
|
如果想break,v12必须为0,~(*(_BYTE )(v25 + v17) != 0)为1,((_BYTE )(v25 + v17) != 0)为0,((_BYTE *)(v25 + v17) ≠0
总而言之没啥用,你会发现这里只是做了判断,本身并不会改变值,程序总能break。没啥用
下面代码我去除了无用变量v9,v27,v22 >>= 6;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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; v11[j] = v21 % 58; *((_BYTE *)v26 + j) = v22 & 0x3F; v21 /= 58; if ( !j ) break; } ++v20; v18 = j; }
|

看这里,之前有一个fake,然后下面有一个58长度的字符串,下面有个64长度的(无用),结合v11[j] = v21 % 58;,猜测可能是个Base58编码表
具体逻辑有点复杂,其实不用深究,看看下面,同样用不闪婚,直接过
1 2 3 4 5
| for ( j = 0LL; ; ++j ){ v8 = 0; if ( j < n ) v8 = ~(v11[j] != 0); if ( (v8 & 1) == 0 ) break; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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++]]; } *((_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)){ v6[1] = puts("correct!"); } v32 = 1; v14 = 1; }
|
先开辟空间,再在while循环里赋值,v26用不上

得flag,flag{base58_is_boring}