int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
__int64 v4; // rdx
__int64 v5; // rax
size_t v6; // rax
__int64 v7; // rax
__int64 v8; // rdx
__int64 v9; // rax
__int64 v11; // rdx
__int64 v12; // rax
char *s1; // [rsp+8h] [rbp-68h]
char s2[8]; // [rsp+10h] [rbp-60h] BYREF
__int64 v15; // [rsp+18h] [rbp-58h]
__int64 v16; // [rsp+20h] [rbp-50h]
__int64 v17; // [rsp+28h] [rbp-48h]
char v18; // [rsp+30h] [rbp-40h]
char s[40]; // [rsp+40h] [rbp-30h] BYREF
unsigned __int64 v20; // [rsp+68h] [rbp-8h]
v20 = __readfsqword(0x28u);
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "Welcome To Reverier-Encode Program!", envp);
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
v5 = std::operator<<<std::char_traits<char>>(&std::cout, "Input Your flag:", v4);
std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
*(_QWORD *)s2 = 0xFD370FEB59C9B9ELL;
v15 = 0xDEAB7F029C4FD1B2LL;
v16 = 0xFACD9D40E7636559LL;
v17 = 4LL;
v18 = 0;
__isoc99_scanf("%33s", s);
s1 = (char *)RxEncode(s, 33);
if ( strlen(s) == 32 )
{
if ( !strcmp(s1, s2) )
v12 = std::operator<<<std::char_traits<char>>(&std::cout, "Congratulations!", v11);
else
v12 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong!", v11);
std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
return 0;
}
else
{
v6 = strlen(s);
v7 = std::ostream::operator<<(&std::cout, v6);
std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
v9 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong!", v8);
std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
return 0;
}
}
估计是base64, 但是仔细读一下RxEncode
函数, 发现是b64解码函数, 拿工具编码一下
void *__fastcall RxEncode(const char *a1, int a2)
{
int v3; // [rsp+18h] [rbp-38h]
int v4; // [rsp+1Ch] [rbp-34h]
int v5; // [rsp+20h] [rbp-30h]
int v6; // [rsp+24h] [rbp-2Ch]
int v7; // [rsp+28h] [rbp-28h]
int v8; // [rsp+28h] [rbp-28h]
int i; // [rsp+2Ch] [rbp-24h]
_BYTE *v10; // [rsp+30h] [rbp-20h]
void *s; // [rsp+38h] [rbp-18h]
v3 = 3 * (a2 / 4);
v4 = 0;
v5 = 0;
if ( a1[a2 - 1] == 61 )
v4 = 1;
if ( a1[a2 - 2] == 61 )
++v4;
if ( a1[a2 - 3] == 61 )
++v4;
if ( v4 == 3 )
{
v3 += 2;
}
else if ( v4 <= 3 )
{
if ( v4 == 2 )
{
v3 += 3;
}
else if ( v4 )
{
if ( v4 == 1 )
v3 += 4;
}
else
{
v3 += 4;
}
}
s = malloc(v3);
if ( s )
{
memset(s, 0, v3);
v10 = s;
while ( v5 < a2 - v4 )
{
v6 = 0;
v7 = 0;
while ( v6 <= 3 && v5 < a2 - v4 )
{
v7 = (v7 << 6) | (char)find_pos(a1[v5]);
++v6;
++v5;
}
v8 = v7 << (6 * (4 - v6));
for ( i = 0; i <= 2 && i != v6; ++i )
*v10++ = v8 >> (8 * (2 - i));
}
*v10 = 0;
return s;
}
else
{
puts("No enough memory.");
return 0LL;
}
}
int __cdecl __noreturn main_0(int argc, const char **argv, const char **envp)
{
int (__cdecl *v3)(int); // [esp-4h] [ebp-D0h]
printf("please Input the flag:\n");
scanf_s("%s", &input);
MessageBoxW(0, L"Exception", L"Warning", 0);
v3 = sub_41100F;
MEMORY[0] = 1;
sub_411136(HIWORD(v3));
}
void __noreturn sub_4132E0()
{
if ( !j_strcmp(Str1, Str2) )
printf("right\n");
else
printf("wrong\n");
system("pause");
exit(0);
}
静态代码的逻辑找不到线索, 动调一下, 进入下面这个函数, 大小写互换
输入flag之后, 会进入exception处理, 这里会被AddVectoredExceptionHandler
hook, 然后调用handler
执行, 点进去
int __stdcall Handler_0(_DWORD **a1)
{
char v2[20]; // [esp+D0h] [ebp-18h] BYREF
if ( **a1 == -1073741819 )
{
qmemcpy(v2, "where_are_u_now?", 16);
sub_951172(&unk_95A218, v2);
SetUnhandledExceptionFilter(TopLevelExceptionFilter);
}
return 0;
}
int __cdecl sub_951F50(int a1, unsigned int *a2)
{
int result; // eax
unsigned int v3; // [esp+D0h] [ebp-B8h]
unsigned int v4; // [esp+DCh] [ebp-ACh]
unsigned int v5; // [esp+E0h] [ebp-A8h]
unsigned int v6; // [esp+E4h] [ebp-A4h]
int v7[35]; // [esp+E8h] [ebp-A0h]
unsigned int v8; // [esp+174h] [ebp-14h]
unsigned int v9; // [esp+178h] [ebp-10h]
unsigned int v10; // [esp+17Ch] [ebp-Ch]
unsigned int v11; // [esp+180h] [ebp-8h]
v3 = 0;
v8 = _byteswap_ulong(*a2);
v9 = _byteswap_ulong(a2[1]);
v10 = _byteswap_ulong(a2[2]);
v11 = _byteswap_ulong(a2[3]);
v4 = v8 ^ 0xA3B1BAC6;
v5 = dword_957A68[1] ^ v9;
v6 = dword_957A68[2] ^ v10;
result = 12;
v7[0] = dword_957A68[3] ^ v11;
while ( v3 < 0x20 )
{
v7[v3 + 1] = *(&v4 + v3) ^ sub_9514E0(dword_957A78[v3] ^ v7[v3] ^ v7[v3 - 1] ^ *(&v5 + v3));
*(_DWORD *)(a1 + 4 * v3) = v7[v3 + 1];
result = ++v3;
}
return result;
}
跟进去发现逻辑看不懂, 试用findcrypt
找下一下是否有密码函数
发现SM4
的特征值, 猜测sub_951F50
是SM4加密, 密钥是where_are_u_now?
, 继续跟TopLevelExceptionFilter
int __cdecl sub_952C30(_DWORD *a1)
{
int result; // eax
char v2; // [esp+D3h] [ebp-11h]
size_t i; // [esp+DCh] [ebp-8h]
result = (int)a1;
if ( *(_DWORD *)*a1 == 0xC0000005 )
{
for ( i = 0; i < j_strlen(Str2); i += 2 ) // process str2
{
v2 = Str2[i];
Str2[i] = Str2[i + 1];
Str2[i + 1] = v2;
}
Str1 = (char *)sub_95126C(byte_95A180); // process str1
*(_DWORD *)(a1[1] + 176) = *(_DWORD *)(*a1 + 20);
*(_DWORD *)(a1[1] + 164) = *(_DWORD *)(*a1 + 24);
*(_DWORD *)(a1[1] + 172) = *(_DWORD *)(*a1 + 28);
*(_DWORD *)(a1[1] + 168) = *(_DWORD *)(*a1 + 32);
*(_DWORD *)(a1[1] + 156) = *(_DWORD *)(*a1 + 36);
*(_DWORD *)(a1[1] + 160) = *(_DWORD *)(*a1 + 40);
*(_DWORD *)(a1[1] + 184) = checkfunc;
return -1;
}
return result;
}
_BYTE *__cdecl sub_953090(char *Str)
{
int k; // [esp+E4h] [ebp-5Ch]
int v3; // [esp+F0h] [ebp-50h]
int j; // [esp+FCh] [ebp-44h]
int v5; // [esp+108h] [ebp-38h]
signed int i; // [esp+114h] [ebp-2Ch]
_BYTE *v7; // [esp+120h] [ebp-20h]
signed int v8; // [esp+12Ch] [ebp-14h]
int v9; // [esp+138h] [ebp-8h]
v5 = 0;
v8 = j_strlen(Str);
if ( v8 % 3 )
v9 = 4 * (v8 / 3) + 4;
else
v9 = 4 * (v8 / 3);
v7 = malloc(__CFADD__(v9, 1) ? -1 : v9 + 1);
v7[v9] = 0;
for ( i = 0; i < v8; i += 3 )
{
v3 = 0;
for ( j = 0; j < 3; ++j )
v3 |= (unsigned __int8)Str[j + i] << (8 * (2 - j));
for ( k = 0; k < 4; ++k )
{
if ( k >= 4 - (i + 3 - v8) && i + 3 > v8 )
v7[v5] = 33;
else
v7[v5] = BASE64_table_95A080[sub_9510FF((v3 >> (6 * (3 - k))) & 0x3F)];
++v5;
}
}
return v7;
}
int __cdecl sub_952760(int a1)
{
return (a1 + 24) % 64;
}
Str2经过奇偶位交换后得到, Str1是经过类似base64编码处理, 跟进去发现sub_952760
会进行变表, 猜测是变表base64
最后Str1和Str2进行比较, 逆向思路: Str2处理后, 经过变表base64解码, 然后SM4解密
import base64
from pysm4 import decrypt
def b64_change_decode(encodestr):
changebase64 = "yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx"
originbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
trans_encodestr = encodestr.translate(str.maketrans(changebase64,originbase64))
res = base64.b64decode(trans_encodestr)
return res
Str2 = [
0x31, 0x55, 0x54, 0x41, 0x4F, 0x49, 0x6B, 0x70, 0x79, 0x4F,
0x53, 0x57, 0x47, 0x76, 0x2F, 0x6D, 0x4F, 0x59, 0x46, 0x59,
0x34, 0x52, 0x21, 0x21
]
Str2_exc = [0 for _ in range(len(Str2))]
for i in range(0, len(Str2), 2):
Str2_exc[i] = chr(Str2[i + 1])
Str2_exc[i + 1] = chr(Str2[i])
Str2 = ''.join(Str2_exc)
print(Str2)
tmp_flag = b64_change_decode(Str2[:len(Str2) - 2] + '==')
mid_flag = int.from_bytes(tmp_flag, byteorder='big')
print(tmp_flag, hex(mid_flag))
key = 'where_are_u_now?'
key_tmp = key.encode('utf-8')
key_int = int.from_bytes(key_tmp, byteorder='big')
print(hex(key_int))
decrypt_flag = decrypt(mid_flag, key_int)
flag = bytes.fromhex(hex(decrypt_flag)[2:]).decode()
# {{ stands for /, }} stands for /
print('flag{{{}}}'.format(flag))
接下来是头尾的单字节比较, 要求前5个字符是flag{
,第38个字符是}
, 中间32位字节分别 xor 和 add N个硬编码数据, 如下面的操作, 即对32个字节进行xor操作之后, 再add操作
这些操作可以叠加起来看作是只有一次xor和add, 所以有checklist
可以直接爆破
checklist = [
217, 44, 39, 214, 216, 42, 218, 45, 215, 44,
220, 225, 219, 44, 217, 221, 39, 45, 42, 220,
219, 44, 225, 41, 218, 218, 44, 218, 42, 217,
41, 42
]
def add(xx, kk):
return [(x+kk) & 0xFF for x in xx]
def xor(xx, kk):
return [x ^ kk for x in xx]
def check(xx):
for x in xx:
if x < ord('0') or (x > ord('9') and x < ord('a')) or x > ord('f'):
return False
return True
if __name__ == '__main__':
for k1 in range(0x100):
tmp_add = add(checklist, k1)
for k2 in range(0x100):
tmp_xor = xor(tmp_add, k2)
if check(tmp_xor):
print(bytes(tmp_xor))
print(k1, k2)
'''
b'1dc20f6e3d497d15cef47d9a66d6f1af'
42 50
b'1dc20f6e3d497d15cef47d9a66d6f1af'
74 18
b'1dc20f6e3d497d15cef47d9a66d6f1af'
170 178
b'1dc20f6e3d497d15cef47d9a66d6f1af'
'''
直接逆找不到线索, 搜索一下 perlapp 逆向找到一个帖子
perl打包的exe需要找到解压函数, 动态调试, 断点到这个函数之后可以定位到关键代码, 这个解压函数会带有特征字符串script
rax就是解压函数的返回值, 点进去就发现解压出来的flag
__int64 __fastcall main(int a1, char **a2, char **a3)
{
unsigned int v3; // eax
unsigned int length; // eax
char v6[4]; // [rsp+4h] [rbp-93Ch] BYREF
int i; // [rsp+8h] [rbp-938h]
int v8; // [rsp+Ch] [rbp-934h]
char v9[1040]; // [rsp+10h] [rbp-930h] BYREF
char v10[16]; // [rsp+420h] [rbp-520h] BYREF
char input[256]; // [rsp+430h] [rbp-510h] BYREF
char encrypt[1032]; // [rsp+530h] [rbp-410h] BYREF
unsigned __int64 v13; // [rsp+938h] [rbp-8h]
v13 = __readfsqword(0x28u);
v10[0] = 16;
v10[1] = 32;
v10[2] = 48;
v10[3] = 48;
v10[4] = 32;
v10[5] = 32;
v10[6] = 16;
v10[7] = 64;
memset(input, 0, sizeof(input));
v8 = strlen(input);
memset(encrypt, 0, 0x400uLL);
printf("please input your flag:");
scanf("%s", input);
memset(v9, 0, 0x408uLL);
func1(v9, v10, 8LL);
v3 = strlen(input);
func2(v9, input, v3);
length = strlen(input);
func3(input, length, encrypt, v6);
for ( i = 0; i <= 50; ++i )
{
if ( encrypt[i] != checklist[i] )
{
puts("Wrong");
return 0LL;
}
}
puts("Good");
return 0LL;
}
bool __fastcall sub_4006B6(_DWORD *a1, __int64 a2, int a3)
{
bool result; // al
int i; // [rsp+1Ch] [rbp-18h]
int j; // [rsp+1Ch] [rbp-18h]
int v6; // [rsp+20h] [rbp-14h]
int v7; // [rsp+24h] [rbp-10h]
int v8; // [rsp+28h] [rbp-Ch]
_DWORD *v9; // [rsp+2Ch] [rbp-8h]
*a1 = 0;
a1[1] = 0;
v9 = a1 + 2;
for ( i = 0; i <= 255; ++i )
v9[i] = i;
v7 = 0;
result = 0;
LOBYTE(v6) = 0;
for ( j = 0; j <= 255; ++j )
{
v8 = v9[j];
v6 = (unsigned __int8)(v6 + v8 + *(_BYTE *)(v7 + a2));
v9[j] = v9[v6];
v9[v6] = v8;
result = ++v7 >= a3;
if ( v7 >= a3 )
v7 = 0;
}
return result;
}
_DWORD *__fastcall func2(_DWORD *a1, __int64 input, int a3)
{
_DWORD *result; // rax
int i; // [rsp+18h] [rbp-1Ch]
int v5; // [rsp+1Ch] [rbp-18h]
int v6; // [rsp+20h] [rbp-14h]
int v7; // [rsp+24h] [rbp-10h]
int v8; // [rsp+28h] [rbp-Ch]
_DWORD *v9; // [rsp+2Ch] [rbp-8h]
v5 = *a1;
v6 = a1[1];
v9 = a1 + 2;
for ( i = 0; i < a3; ++i )
{
v5 = (unsigned __int8)(v5 + 1);
v7 = v9[v5];
v6 = (unsigned __int8)(v6 + v7);
v8 = v9[v6];
v9[v5] = v8;
v9[v6] = v7;
*(_BYTE *)(i + input) ^= LOBYTE(v9[(unsigned __int8)(v7 + v8)]);
}
*a1 = v5;
result = a1;
a1[1] = v6;
return result;
}
_DWORD *__fastcall func3(__int64 input, int length, const char *encrypt, _DWORD *a4)
{
int v4; // eax
int v5; // eax
unsigned __int8 v6; // al
int v7; // eax
unsigned __int8 v8; // al
int v9; // eax
int v10; // edx
_DWORD *result; // rax
char v13; // [rsp+2Dh] [rbp-13h]
unsigned __int8 v14; // [rsp+2Eh] [rbp-12h]
unsigned __int8 v15; // [rsp+2Fh] [rbp-11h]
int v16; // [rsp+30h] [rbp-10h]
int i; // [rsp+34h] [rbp-Ch]
v16 = 0;
i = 0;
while ( i < length )
{
v4 = i++;
v13 = *(_BYTE *)(v4 + input);
if ( i >= length )
{
v6 = 0;
}
else
{
v5 = i++;
v6 = *(_BYTE *)(v5 + input);
}
v14 = v6;
if ( i >= length )
{
v8 = 0;
}
else
{
v7 = i++;
v8 = *(_BYTE *)(v7 + input);
}
v15 = v8;
encrypt[v16] = ((v13 >> 2) & 0x3F) + '=';
encrypt[v16 + 1] = ((((int)v14 >> 4) | (16 * v13)) & 0x3F) + '=';
encrypt[v16 + 2] = ((((int)v8 >> 6) | (4 * v14)) & 0x3F) + '=';
v9 = v16 + 3;
v16 += 4;
encrypt[v9] = (v15 & 0x3F) + '=';
}
if ( length % 3 == 1 )
{
encrypt[--v16] = '=';
}
else if ( length % 3 != 2 )
{
goto LABEL_15;
}
encrypt[v16 - 1] = 61;
LABEL_15:
v10 = strlen(encrypt);
result = a4;
*a4 = v10;
return result;
}
RC4加密, 动调拿xor数组, 写逆
#include
int data0[258] = {
0x00, 0x00, 0xB0, 0x31, 0x75, 0x70, 0xF8, 0xDF,
0x07, 0x3C, 0x78, 0x71, 0x50, 0x29, 0x2C, 0x16,
0x69, 0x12, 0xC8, 0x2B, 0x3B, 0x7F, 0xB2, 0xE7,
0x4B, 0x68, 0x8C, 0xC5, 0xA6, 0x15, 0x03, 0x58,
0x47, 0x04, 0x13, 0x8D, 0x87, 0x26, 0x09, 0xED,
0x17, 0x8A, 0xC2, 0xF2, 0x43, 0xC0, 0xAC, 0x59,
0x97, 0xF5, 0x3F, 0x67, 0x5E, 0x39, 0x86, 0xD5,
0x72, 0x61, 0xDA, 0xF7, 0x01, 0x05, 0x8B, 0xC3,
0xB1, 0x77, 0xAF, 0x1D, 0x30, 0xC6, 0x45, 0x0E,
0x5F, 0xEE, 0xAE, 0xF0, 0x28, 0xCE, 0xCD, 0xA7,
0x9B, 0x2A, 0x19, 0x48, 0x08, 0x44, 0x20, 0xFE,
0x6D, 0xB5, 0x2E, 0x6A, 0xF1, 0x34, 0xBC, 0x1E,
0x3E, 0xCC, 0x41, 0x92, 0xD8, 0xBD, 0xA5, 0xE8,
0x4D, 0x0A, 0x49, 0x0D, 0xA2, 0xFA, 0x62, 0x74,
0xD4, 0x83, 0x96, 0x94, 0x3D, 0xCB, 0x18, 0x63,
0x99, 0x46, 0xCA, 0xB7, 0x8E, 0xCF, 0xFB, 0xA3,
0x6C, 0x7E, 0x51, 0x27, 0x60, 0x9A, 0x11, 0xF3,
0x5C, 0x6E, 0xBA, 0x42, 0x76, 0x2F, 0xEF, 0xBF,
0x21, 0xAA, 0xE4, 0xD6, 0x1B, 0x55, 0x7D, 0xBE,
0xEA, 0xD3, 0x10, 0xF4, 0xC7, 0x4A, 0x23, 0x79,
0x84, 0xA4, 0x1C, 0xAB, 0x14, 0xDB, 0x4C, 0x3A,
0xB8, 0x52, 0xEC, 0x37, 0x38, 0xB6, 0xD2, 0xA0,
0x5A, 0x5B, 0x98, 0x66, 0x54, 0x9E, 0x4E, 0x4F,
0xB4, 0xC4, 0xC9, 0xD0, 0x25, 0x9C, 0x80, 0xDE,
0x2D, 0x06, 0x22, 0x0B, 0x91, 0x6B, 0x9F, 0xF6,
0xE6, 0xE2, 0xC1, 0x0F, 0x93, 0x90, 0x7B, 0x9D,
0x8F, 0xDD, 0xE5, 0x65, 0x35, 0xAD, 0xA9, 0xDC,
0x82, 0xBB, 0x00, 0x53, 0xD1, 0xA8, 0x33, 0xE9,
0x40, 0x1A, 0xFF, 0xA1, 0x95, 0x36, 0xD9, 0xEB,
0x89, 0xE3, 0x7C, 0x73, 0x85, 0x88, 0x7A, 0xE0,
0xFD, 0x64, 0x0C, 0x57, 0x32, 0xB3, 0xB9, 0x1F,
0xD7, 0xFC, 0x81, 0xE1, 0x02, 0xF9, 0x5D, 0x56,
0x6F, 0x24
};
unsigned char checklist[52] = {
0x5a, 0x60, 0x54, 0x7A, 0x7A, 0x54, 0x72, 0x44, 0x7C, 0x66, 0x51, 0x50, 0x5B, 0x5F, 0x56, 0x56,
0x4C, 0x7C, 0x79, 0x6E, 0x65, 0x55, 0x52, 0x79, 0x55, 0x6D, 0x46, 0x6B, 0x6C, 0x56, 0x4A, 0x67,
0x4C, 0x61, 0x73, 0x4A, 0x72, 0x6F, 0x5A, 0x70, 0x48, 0x52, 0x78, 0x49, 0x55, 0x6C, 0x48, 0x5C,
0x76, 0x5A, 0x45, 0x3D
};
void exchange(unsigned char*flag, int len) {
int v7, v8,i,v3,v4;
v7 = data0[0];
v8 = data0[1];
int* v9 = data0 + 2;
for (i = 0; i < len; ++i) {
v7 = (unsigned char)(v7 + 1);
v3 = v9[v7];
v8 = (unsigned char)(v8 + v3);
v4 = v9[v8];
v9[v7] = v4;
v9[v8] = v3;
flag[i] ^= v9[(unsigned char)(v3 + v4)];
}
}
int main() {
unsigned char flag[40] = { 0 };
int i = 0,j = 0;
for (i = 0; i < 52; i++)
checklist[i] -= 61;
for (i = 0, j = 0; i < 52; i += 4, j += 3) {
flag[j] = checklist[i] << 2 | checklist[i + 1] >> 4;
flag[j + 1] = (checklist[i + 1] & 0xF) << 4 | checklist[i + 2] >> 2;
flag[j + 2] = (checklist[i + 2] & 0xF) << 6 | checklist[i + 3];
}
exchange(flag, 39);
flag[38] = 0;
printf("%s\n", (char*)flag);
return 0;
}