0%

BeginCTF2024逆向方向wp

参赛ID:1K0CT

superguesser | 动态调试

静态分析发现函数全部被混淆 在入口下断点步过函数直到进入被还原的函数 找到核心加密逻辑:

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
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall sub_401530()
{
__int64 stack; // rbp
char v1; // zf
__int64 (*v2)(void); // rax
void *v3; // rsp
__int64 v4; // rcx
char v5; // of

(loc_46EB33)();
_disable();
(loc_46EB77)();
(loc_46EBB4)();
if ( v1 )
JUMPOUT(0x401548i64);
(loc_46EBF7)();
*(stack - 96) = 81;
*(stack - 95) = 81;
*(stack - 94) = 82;
*(stack - 93) = 95;
*(stack - 92) = 89;
*(stack - 91) = 67;
*(stack - 90) = 93;
*(stack - 89) = 95;
*(stack - 88) = 89;
*(stack - 87) = 73;
*(stack - 86) = 90;
*(stack - 85) = 89;
*(stack - 84) = 86;
*(stack - 83) = 46;
*(stack - 82) = 38;
*(stack - 81) = 29;
*(stack - 80) = 42;
*(stack - 79) = 55;
*(stack - 78) = 26;
*(stack - 77) = 39;
*(stack - 76) = 41;
*(stack - 75) = 23;
*(stack - 74) = 40;
*(stack - 73) = 36;
*(stack - 72) = 42;
*(stack - 71) = 56;
*(stack - 70) = 37;
*(stack - 69) = 33;
*(stack - 68) = 61;
*(stack - 67) = 15;
*(stack - 66) = 50;
*(stack - 65) = 58;
*(stack - 64) = 60;
*(stack - 63) = 61;
*(stack - 62) = 54;
*(stack - 61) = 51;
*(stack - 60) = 42;
*(stack - 59) = 0;
*(stack - 24) = (loc_46EC76)(stack - 96);
*(stack - 25) = 51;
v2 = (loc_46ECB3)();
__outbyte(0x2Fu, v2);
*(stack - 26) = v2();
*(stack - 40) = *(stack - 24) - 1i64;
(loc_46ECF6)();
(loc_46ED38)();
v3 = alloca((loc_46ED75)());
*(stack - 48) = alloc();
(scanf_0)(v4, *(stack - 48));
(loc_46EE32)();
(loc_46EEB1)();
if ( !v5 )
JUMPOUT(0x401651i64);
while ( *(stack - 20) < *(stack - 24) )
*(*(stack - 48) + (*(stack - 20))++) ^= *(stack - 20) + *(stack - 25) + 17 * *(stack - 26);// i + ? + 17 * ??
if ( !(cmp)(*(stack - 48), stack - 96, *(stack - 24)) )
{
(loc_46F030)();
JUMPOUT(0x4016E8i64);
}
(loc_46EF73)();
return (loc_46EFF3)();
}

动调发现stack-48处存放的就是输入的flag 而只有这一处加密 由于不确定*(stack - 26)的值是否因为反调试手段被修改 故用爆破方法解flag:

1
2
3
4
5
6
7
8
enc = [81, 81, 82, 95, 89, 67, 93, 95, 89, 73, 90, 89, 86, 46, 38, 29, 42, 55, 26, 39, 41, 23, 40, 36, 42, 56, 37, 33, 61, 15, 50, 58, 60, 61, 54, 51, 42]
for ran in range(128):
flag = ""
for i in range(len(enc)):
flag += chr((enc[i] ^ (i + 0x33 + 17 * ran)) & 0xff)
if flag[:5] == "begin":
print(flag)
# begin{debugging_is_an_anathor_choice}

ezpython | 注入解法

用pyinstxtractor解包出的key和enc无法通过sm4解密得到flag 故使用原程序的环境进行解密 原程序反编译后主要逻辑:

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
from gmssl import sm4
from secrets import key, enc
import base64

def pad_pkcs7(data):
"""PKCS#7填充"""
padding_len = 16 - len(data) % 16
padding = bytes([padding_len] * padding_len)
return data + padding


def unpad_pkcs7(padded_data):
"""PKCS#7去填充"""
padding_len = padded_data[-1]
return padded_data[:-padding_len]


class SM4:
def __init__(self):
self.gmsm4 = sm4.CryptSM4()

def encryptSM4(self, encrypt_key, value):
gmsm4 = self.gmsm4
gmsm4.set_key(encrypt_key.encode(), sm4.SM4_ENCRYPT)
padded_value = pad_pkcs7(value.encode())
encrypt_value = gmsm4.crypt_ecb(padded_value)
return base64.b64encode(encrypt_value)


if __name__ == "__main__":
flag = input("...")
sm4_instance = SM4()
flag_1 = sm4_instance.encryptSM4(key, flag)
if flag_1 == enc:
print("Success")
else:
print("Failed")

在powershell启动题目程序(用cmd或者直接启动貌似不行) 找到该程序的pid 使用de4py的PyShell功能将以下解密代码注入到程序:

1
2
3
4
5
6
7
8
9
10
def decryptSM4(self, encrypt_key, enc):
gmsm4 = self.gmsm4
gmsm4.set_key(encrypt_key.encode(), sm4.SM4_DECRYPT)
encrypt_value = base64.b64decode(enc)
decrypt_value = gmsm4.crypt_ecb(encrypt_value)
return unpad_pkcs7(decrypt_value).decode()

SM4.decrypt = decryptSM4
sm4_new = SM4()
print(sm4_new.decrypt(key, enc))

效果:

24/3/23更新正常解

​ –原题魔改了国密库

goforfun | go语言逆向

第一个加密的核心特征:

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
for ( i = 255; i >= 0; --i )
{
if ( i >= 0x100 )
runtime_panicIndex();
*(box + i) = -1 - i;
}
count = 0;
v7 = 0;
while ( count < 256 )
{
v8 = *(box + count);
v9 = count;
v10 = count - 12 * (((2863311531LL * count) >> 32) >> 3);
if ( v10 >= 0xC )
runtime_panicIndex();
v7 += v35[v10] + v8;
*(box + v9) = *(box + v7);
*(box + v7) = v8;
count = v9 + 1;
}
sub_462C00(&PRGA_result, box);
flag_context = v4;
lenth_of_context = v34;
v26 = v11;
main_PRGA(PRGA_result);

Sbox初始化 PRGA 但是不是普通的RC4加密 进入PRGA函数:

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
int __usercall main_PRGA@<eax>(char table)
{
int result; // eax
signed int v2; // ecx
unsigned int v3; // edx
signed int v4; // ebx
char v5; // bp
char v6; // si
char v7; // cl
char v8; // [esp+12h] [ebp-2h]
void *retaddr; // [esp+14h] [ebp+0h] BYREF

if ( &retaddr <= *(*__readfsdword(runtime_tls_g) + 8) )
runtime_morestack_noctxt();
result = runtime_makeslice(&uint8, STACK[0x11C], STACK[0x11C]);
v2 = STACK[0x11C];
v3 = STACK[0x118];
v4 = 0;
v5 = 0;
v6 = 0;
while ( v2 > v4 )
{
v7 = *(&table + (v5 + 1));
v8 = v7 + v6;
*(&table + (v5 + 1)) = *(&table + (v7 + v6));
*(&table + (v7 + v6)) = v7;
*(result + v4) = *(&table + (v7 + *(&table + (v5 + 1)))) ^ *(v3 + v4) ^ 0x2F;
++v4;
v2 = STACK[0x11C];
++v5;
v6 = v8;
}
STACK[0x124] = result;
STACK[0x128] = v2;
STACK[0x12C] = v2;
return result;
}

动调发现v3存放的就是输入的flag去除begin{}包裹的内容 所以加密只关心和其异或的东西 在最后异或步骤下状况断点 输出存放异或的数字的寄存器:

image-20240206140321081

得到异或内容:

xor_key = [i ^ 0x2f for i in [132, 14, 121, 193, 41, 61, 231, 134, 147, 244, 180, 102, 100, 175, 25, 151, 133, 7, 230, 74, 200, 3, 55]]

最后一处加密的核心特征:

image-20240206140631616

从64长度的表中按第二处加密得到的结果为下标取元素 最后和密文比较 猜测是换表base64

第二处加密:

1
2
v20 = main_byteArrayToBigInt(result, lenth_2);
v22 = main_bigIntModToArray(str_head);

动调发现第一个函数的作用就是将第一处加密得到的结果按小端序储存为Go中的一种大整型数据(没有位数上限 能储存多大取决于计算机)

第二个函数:

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
92
93
__int128 __golang main_bigIntModToArray(int *a1)
{
int *mod_result_instanc; // eax
int v2; // ecx
int v3; // edx
unsigned int i; // ebx
int v5; // ebp
int now_result; // ecx
int origin_data; // eax
unsigned int count_1; // ecx
int add_; // edx
int *final_procees; // ebx
int *result_; // [esp+Ch] [ebp-6Ch]
int *v12; // [esp+14h] [ebp-64h]
unsigned int v13; // [esp+18h] [ebp-60h]
int v14; // [esp+1Ch] [ebp-5Ch]
int v15; // [esp+20h] [ebp-58h]
unsigned int v16; // [esp+24h] [ebp-54h]
unsigned int v17; // [esp+28h] [ebp-50h]
int v18; // [esp+28h] [ebp-50h]
int mod_num_2; // [esp+2Ch] [ebp-4Ch] BYREF
int mod_num; // [esp+30h] [ebp-48h] BYREF
int v21; // [esp+44h] [ebp-34h]
int v22[4]; // [esp+48h] [ebp-30h] BYREF
int mod_n[4]; // [esp+58h] [ebp-20h] BYREF
int be_moded_instanc[4]; // [esp+68h] [ebp-10h] BYREF
void *retaddr; // [esp+78h] [ebp+0h] BYREF
__int128 result; // [esp+80h] [ebp+8h]

if ( &retaddr <= *(*__readfsdword(runtime_tls_g) + 8) )
runtime_morestack_noctxt();
mod_result_instanc = a1;
v2 = 0;
v3 = 0;
for ( i = 0; ; i = v16 )
{
if ( mod_result_instanc[2] )
v5 = *mod_result_instanc ? -1 : 1;
else
v5 = 0;
if ( v5 <= 0 )
break;
v17 = v2;
v21 = v3;
LOBYTE(be_moded_instanc[0]) = 0;
memset(&be_moded_instanc[1], 0, 12);
mod_num = 64;
LOBYTE(mod_n[0]) = 0;
mod_n[1] = &mod_num;
mod_n[2] = 1;
mod_n[3] = 1;
result_ = math_big__Int_Mod(be_moded_instanc, mod_result_instanc, mod_n);
if ( result_[2] )
now_result = *result_[1];
else
now_result = 0;
if ( *result_ )
origin_data = -now_result;
else
origin_data = now_result;
count_1 = i + 1;
add_ = v17;
if ( v17 < i + 1 )
{
v15 = origin_data;
v12 = runtime_growslice(v21, i + 1, v17, 1, &int);
count_1 = v13;
final_procees = v12;
add_ = v14;
origin_data = v15;
}
else
{
final_procees = v21;
}
v21 = final_procees;
v16 = count_1;
v18 = add_;
final_procees[count_1 - 1] = origin_data;
mod_num_2 = 0x40;
LOBYTE(v22[0]) = 0;
v22[1] = &mod_num_2;
v22[2] = 1;
v22[3] = 1;
math_big__Int_Div(a1, a1, v22);
mod_result_instanc = a1;
v3 = v21;
v2 = v18;
}
*&result = __PAIR64__(i, v3);
DWORD2(result) = v2;
return result;
}

核心是其中的大整型取模和大整型除法 动调发现取模和除法都是对第一个函数得到的大整型进行 另一个操作数是0x40也就是result = big_int & 0xFFFFFF, big_int >> 6符合之前base64的猜测(但是直接用base64解出来不对 所以自己写解密脚本):

1
2
3
4
5
6
7
8
9
10
11
12
xor_key = [i ^ 0x2f for i in [132, 14, 121, 193, 41, 61, 231, 134, 147, 244, 180, 102, 100, 175, 25, 151, 133, 7, 230, 74, 200, 3, 55]]
enc = ["8G+cazk2jqb7w01CtoKH4FsrgR3vVmQ9pPhXLAleOd/nB6DfIxMWYiUZ5SEJyNuT".index(i) for i in"HZ0sMJXqxHgUb2b9RNg+1xw"]
enc = [bin(i).replace("0b", "").zfill(6) for i in enc][::-1]
big_int = int("".join(enc), 2)
flag = []
while big_int > 0:
flag.append(big_int & 0xff)
big_int >>= 8
flag = flag[::-1]
for i in range(len(flag)):
print(chr(flag[i] ^ xor_key[i]), end="")
# go_a_nice_journey

not main | 反调试

IDA识别出的主函数:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // ecx
__int32 *pt_input1; // edi
unsigned __int32 now; // edx
int sum; // ebx
unsigned __int32 next; // esi
int v8; // edi
__int32 *pt_input3; // ecx
__int32 *v10; // edx
unsigned int v11; // esi
bool v12; // cf
unsigned int v13; // edx
int v14; // eax
int v16; // [esp-4h] [ebp-2Ch]
__int32 *pt_input2; // [esp+Ch] [ebp-1Ch]
__int128 v18; // [esp+10h] [ebp-18h] BYREF
int v19; // [esp+20h] [ebp-8h]

sub_141930(std::cin);
v3 = strlen(enc);
if ( v3 == 0x1A )
{
pt_input1 = enc;
pt_input2 = enc;
do
{
now = *pt_input1;
sum = 0; // TEA
next = pt_input1[1];
v8 = 32;
do
{
sum -= 0x61C88647;
now += ((next >> 5) + 97) ^ (16 * next + 102) ^ (sum + next);
next += ((now >> 5) + 101) ^ (16 * now + 107) ^ (sum + now);
--v8;
}
while ( v8 );
*pt_input2 = now;
pt_input2[1] = next;
pt_input1 = pt_input2 + 2;
pt_input2 = pt_input1;
}
while ( pt_input1 < &debug_flag_1 );
pt_input3 = enc;
v10 = to_cmp;
v11 = 28;
while ( *pt_input3 == *v10 )
{
++pt_input3;
++v10;
v12 = v11 < 4;
v11 -= 4;
if ( v12 )
{
v18 = xmmword_143220;
LOBYTE(v19) = 19;
v13 = 0;
v3 = strlen(&v18);
if ( v3 )
{
do
*(&v18 + v13++) ^= 0x13u;
while ( v13 < &v18 + strlen(&v18) + 1 - (&v18 + 1) );
}
goto LABEL_11;
}
}
}
else
{
LABEL_11: // fail
v14 = sub_141600(v3, sub_141830);
std::ostream::operator<<(v14, v16);
}
return 0;
}

包含一个TEA 但是解出来是假flag while ( pt_input1 < &debug_flag_1 );这一行对flag交叉引用到达一个异常处理函数:

1
2
3
4
5
6
7
8
9
10
int sub_141010()
{
uint8_t BeingDebugged; // al

BeingDebugged = NtCurrentPeb()->BeingDebugged;
debug_flag_1 = BeingDebugged != 0;
if ( BeingDebugged )
AddVectoredExceptionHandler(1u, Handler);
return atexit(sub_142AE0);
}

Handler应该就是程序正常运行过程中主函数触发异常后执行的处理函数:

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
LONG __userpurge Handler@<eax>(int a1@<edi>, struct _EXCEPTION_POINTERS *ExceptionInfo)
{
DWORD ExceptionCode; // eax
PCONTEXT ContextRecord; // eax
int sum; // ecx
unsigned __int32 temp; // eax
unsigned int v7; // ebx
unsigned int i; // edi
bool v9; // zf
_DWORD *real_enc; // edx
__int32 *v11; // ecx
unsigned int v12; // esi
bool v13; // cf
unsigned int j; // edx
int v15; // eax
int v16; // [esp-10h] [ebp-44h]
unsigned int addr_13503C; // [esp+4h] [ebp-30h]
int v19; // [esp+8h] [ebp-2Ch]
int v20; // [esp+Ch] [ebp-28h]
int temp_2; // [esp+10h] [ebp-24h]
int key[4]; // [esp+14h] [ebp-20h]
int v23[3]; // [esp+24h] [ebp-10h] BYREF

ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
if ( ExceptionCode == -2147483645 )
{
ContextRecord = ExceptionInfo->ContextRecord;
dword_145038 = 0;
++ContextRecord->Eip;
return -1;
}
else if ( ExceptionCode == 0xC0000094 )
{
return 0;
}
else
{
key[0] = 116;
addr_13503C = to_cmp ^ ::addr_13503C;
sum = 0;
::addr_13503C ^= to_cmp;
temp = enc_7_;
key[1] = 114;
key[2] = 117;
key[3] = 101;
v19 = 12;
temp_2 = enc_7_;
do
{
v20 = sum - 0x61C88647;
v7 = ((sum - 0x61C88647) >> 2) & 3;
for ( i = 0; i < 7; ++i )
{
enc[i] += ((v20 ^ enc_1_[i]) + (temp_2 ^ key[v7 ^ i & 3])) ^ (((16 * temp_2) ^ (enc_1_[i] >> 3))
+ ((temp >> 5) ^ (4 * enc_1_[i])));
temp = enc[i];
temp_2 = temp;
}
sum -= 0x61C88647;
temp = (((v20 ^ enc[0]) + (temp ^ key[v7 ^ i & 3])) ^ (((16 * temp) ^ (enc[0] >> 3)) + ((temp >> 5) ^ (4 * enc[0]))))
+ enc_7_;
v9 = v19-- == 1;
temp_2 = temp;
enc_7_ = temp;
}
while ( !v9 );
real_enc = addr_13503C;
v11 = enc;
v12 = 28;
while ( *v11 == *real_enc )
{
++v11;
++real_enc;
v13 = v12 < 4;
v12 -= 4;
if ( v13 )
{
v23[0] = 862354538;
v23[1] = 862418548;
v23[2] = 322070394;
for ( j = 0; j < strlen(v23); ++j )
*(v23 + j) ^= 0x13u;
v15 = sub_141600(sub_141830, a1);
std::ostream::operator<<(v15, v16);
break;
}
}
ExceptionInfo->ContextRecord->Ecx = 1;
return -1;
}
}

包含一个XXTEA加密 keygen:

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
#include <stdio.h>
#include <stdlib.h>

int delta = 0x61C88647;
unsigned __int32 enc[] = {
0xCFBE0F1B, 0x5F3083F, 0x4220E43B, 0x3383AFEE, 0xFA3237CE, 0xECADA66E, 0xA8D47CA7, 0xEFC51077
};

int key[4] = {116, 114, 117, 101};

//TEA decrypt
void main(){
int count = 11;
unsigned int sum = -12 * 0x61C88647;
int delta = 0x61C88647;
do{
int j = (sum >> 2) & 3;
enc[7] -= (((sum ^ enc[0]) + (enc[6] ^ key[j ^ 7 & 3])) ^ (((16 * enc[6]) ^ (enc[0] >> 3)) + ((enc[6] >> 5) ^ (4 * enc[0]))));
for(int i = 6; i >= 1; i--){
enc[i] -= (((sum ^ enc[i + 1]) + (enc[i - 1] ^ key[j ^ i & 3])) ^ (((16 * enc[i - 1]) ^ (enc[i + 1] >> 3)) + ((enc[i - 1] >> 5) ^ (4 * enc[i + 1]))));
}
enc[0] -= (((sum ^ enc[1]) + (enc[7] ^ key[j ^ 0 & 3])) ^ (((16 * enc[7]) ^ (enc[1] >> 3)) + ((enc[7] >> 5) ^ (4 * enc[1]))));
sum += delta;
for(int i = 0; i < 8; i++){
}
}while(count--);
for(int i = 0; i < 8; i += 2){
sum = -32 * 0x61C88647;
for(int _ = 0; _ < 32; _++){
enc[i + 1] -= ((enc[i] >> 5) + 101) ^ (16 * enc[i] + 107) ^ (sum + enc[i]);
enc[i] -= ((enc[i + 1] >> 5) + 97) ^ (16 * enc[i + 1] + 102) ^ (sum + enc[i + 1]);
sum += delta;
}
}
for(int i = 0; i < 8; i++){
for(int j = 0; j < 4; j++){
printf("%c", (enc[i] >> (8 * j)) & 0xff);
}
}
// begin{not_main_is_matter!}
}

出题人的密码是什么 | 不知道什么加密 | 混淆

最后的比较函数:

image-20240206142249939

看起来是对控制流进行了混淆 先猜测就是按顺序一个一个对比 主函数开头就加了反调试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.text:00AC8540 8B F4                         mov     esi, esp
.text:00AC8542 FF 15 00 C0 B3 00 call ds:IsDebuggerPresent
.text:00AC8542
.text:00AC8548 3B F4 cmp esi, esp
.text:00AC854A E8 6E AA FF FF call j___RTC_CheckEsp
.text:00AC854A
.text:00AC854F 85 C0 test eax, eax
.text:00AC8551 75 11 jnz short loc_AC8564 ; Keypatch modified this from:
.text:00AC8551 ; jz short loc_438564
.text:00AC8551 ; Keypatch modified this from:
.text:00AC8551 ; jz short loc_D38564
.text:00AC8551
.text:00AC8553 8B F4 mov esi, esp
.text:00AC8555 6A 00 push 0 ; uExitCode
.text:00AC8557 FF 15 08 C0 B3 00 call ds:ExitProcess

这里patch掉 接下来输入完flag后有很多无用函数干扰分析 没用的函数标记一下 在唯一一个有用的分支找到两个加密函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
j__gets_s(passw, 0x64u);
fzwufunc();
fzwufunc2();
j_fzwu();
fzwufunc();
sub_AC125D();
j_fzwu__();
...
int sub_D78120()
{
__CheckForDebuggerJustMyCode(byte_B3D0F4);
j_procees_func1();
j_procees_func2();
return 0;
}

第二个加密函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
int procees_func2()
{
int result; // eax
int i; // [esp+D0h] [ebp-8h]

result = __CheckForDebuggerJustMyCode(&byte_B3D0F4);
for ( i = 0; i < 48; ++i )
{
final_[i] = (passw[i] + 5) ^ 0x25;
result = i + 1;
}
return result;
}

对第一个函数加密后的数据进行加法和异或

第一个加密函数:

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
int procees_func1()
{
int v0; // edx
int result; // eax
__int64 v2; // [esp+D0h] [ebp-58h]
size_t v3; // [esp+ECh] [ebp-3Ch]
int j; // [esp+F8h] [ebp-30h]
int i; // [esp+104h] [ebp-24h]
__int64 v6; // [esp+110h] [ebp-18h]
char *v7; // [esp+120h] [ebp-8h]

__CheckForDebuggerJustMyCode(byte_B3D0F4);
v3 = j__strlen(user);
if ( v3 )
j__srand(byte_B39FD7[v3]);
else
j__srand(0x123456u);
v0 = j__rand() % 7; // v0 = 7
result = dword_B39000[2 * v0];
LODWORD(v2) = result;
HIDWORD(v2) = dword_B39004[2 * v0]; // v2 = 0x33077D
for ( i = 0; i < 6; ++i )
{
v7 = &passw[8 * i];
v6 = *v7;
for ( j = 0; j < 64; ++j )
{
if ( v6 < 0 )
v6 = v2 ^ (2 * v6);
else
v6 *= 2i64;
}
*v7 = v6;
result = i + 1;
}
return result;
}

对输入的flag进行32位小端序储存 然后根据当前数据块的正负(最高位)选择进行左移1位还是左移后再异或 这个异或会使左移后最后一位由0变成1 由此储存因左移丢失的数据 据此写出keygen 发现那个控制流混淆确实就是一位一位对比:

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
#include <stdio.h>
#include <stdlib.h>

int main(){
unsigned __int8 enc[] = {0xB4, 0xBB, 0xD8, 0xEB, 0xD0, 0x6E, 0xAB, 0xCA, 0x65, 0x8E,
0x4B, 0xE9, 0x4D, 0xD4, 0x4A, 0xF3, 0x7D, 0x29, 0xC2, 0xF9,
0x95, 0x89, 0xA4, 0x85, 0x9D, 0xCD, 0xDF, 0x77, 0xFD, 0x45,
0xCB, 0x5D, 0x7D, 0xFD, 0x93, 0x4B, 0xBC, 0xF6, 0x7C, 0xF3,
0x24, 0x42, 0xF5, 0xD2, 0xDD, 0xE3, 0x56, 0xAE};
__int64 d = 0x000000000033077D;
for(int i = 0; i < 48; i++){
enc[i] ^= 0x25;
enc[i] -= 5;
}
unsigned __int64 enc_[6];
for(int i = 0; i < 6; i++){
enc_[i] = 0;
for(int j = 0; j < 8; j++){
enc_[i] |= (__int64)enc[8 * i + j] << (j * 8);
}
}
for(int i = 0; i < 8; i++){
for(int j = 0; j < 64; ++j){
if(enc_[i] & 1){
enc_[i] ^= d;
enc_[i] >>= 1;
enc_[i] |= (__int64)(0x8000000000000000);
}
else{
enc_[i] >>= 1;
}
}
}
// save the data back to enc with big-ending
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
enc[i * 8 + j] = (enc_[i] >> (j * 8)) & 0xFF;
}
}
for(int i = 0; i < 48; i++){
printf("%c", enc[i]);
}
// begin{Th1s_reverse_pr0blem_may_t@ke_some_time#!}
}

俄语学习 | 防静态分析

主要加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int sub_1A1F80()
{
int v0; // eax
int result; // eax
int k; // [esp+D0h] [ebp-54h]
size_t j; // [esp+DCh] [ebp-48h]
size_t i; // [esp+E8h] [ebp-3Ch]
char Str[44]; // [esp+F4h] [ebp-30h] BYREF

__CheckForDebuggerJustMyCode(&unk_22F0F4);
qmemcpy(Str, cource, 0x25u);
for ( i = 0; i <= j__strlen(Str); ++i )
sourc_key[i] = Str[i] - 0x72;
for ( j = 0; j <= j__strlen(sourc_key); ++j )
key[j] = sourc_key[j];
v0 = j__strlen(sourc_key);
result = sub_19B6D0(table, sourc_key, v0);
for ( k = 0; k < 256; ++k )
{
copy_table[k] = table[k];
result = k + 1;
}
return result;
}

其中table初始化是干扰分析的 后面并不会用到 主要加密方式就是根据key对flag进行加减运算 以下是keygen:

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
int sub_1A1F80()
{
int v0; // eax
int result; // eax
int k; // [esp+D0h] [ebp-54h]
size_t j; // [esp+DCh] [ebp-48h]
size_t i; // [esp+E8h] [ebp-3Ch]
char Str[44]; // [esp+F4h] [ebp-30h] BYREF

__CheckForDebuggerJustMyCode(&unk_22F0F4);
qmemcpy(Str, cource, 0x25u);
for ( i = 0; i <= j__strlen(Str); ++i )
sourc_key[i] = Str[i] - 0x72;
for ( j = 0; j <= j__strlen(sourc_key); ++j )
key[j] = sourc_key[j];
v0 = j__strlen(sourc_key);
result = sub_19B6D0(table, sourc_key, v0);
for ( k = 0; k < 256; ++k )
{
copy_table[k] = table[k];
result = k + 1;
}
return result;
}
# flag{Russian_is_so_easy}

红白机 | 简单虚拟机

使用的是6502虚拟机 直接模拟其运行(或者分析后手画也行) 这里已经用文本编辑器替换过原来的6502指令

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
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

flag = np.array(Image.open('flag.png'))
with open("6502.txt") as f:
now_color = 255
offset = 0
while offset <= 0x3FF:
flag[int(offset / 32), offset % 32] = now_color
offset += 1
offset = 1
lines = f.readlines()
count = 0
for i in range(len(lines)):
lines[i] = lines[i].replace("\n", "")
for line in lines[36:]:
if line[:8] == "color = ":
now_color = int(line[8:], 16) * 255
if line[:10] == "load color":
flag[int((offset + int(line[15:18], 16) - 0x200) / 32), offset % 32] = now_color
count += 1
print(now_color, offset, int(offset / 32), offset % 32, count)
if line == "offset += 1":
offset += 1
if line[:8] == "offset =":
offset = int(line[8:], 16)
plt.figure("flag")
plt.imshow(flag)
plt.axis('off')
plt.show()

image-20240206144338244

stick game | js混淆

js中游戏的主要逻辑被混淆:

image-20240206144537026

用网站反混淆:

image-20240206144616490

直接找到flagimage-20240206144649583

xor

主要逻辑就是将flag分前后两半加密 用key正着异或一遍再倒着抑或一遍 再交换前后使用的key再重复上述过程 keygen:

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
key = [52,  49,  56,  48,  51,  56,  55,  51,  54,  50, 
53, 57, 48, 49, 51, 54, 51, 48, 57, 50,
54, 48, 54, 54, 51, 50, 55, 56, 55, 57,
52, 55]
key1 = [54, 51, 50, 57, 48, 55, 57, 52, 50, 48,
55, 55, 49, 53, 53, 56, 55, 54, 55, 57,
54, 50, 49, 51, 56, 54, 55, 51, 53, 48,
48, 48]
hbkey = key[0:16] + [0]
qmkey = key[16:32] + [0]
enc = [ord(i) for i in "`agh{^bvuwTooahlYocPtmyiijj|ek'p"]
qm = enc[0:16]
hb = enc[16:32]
for i in range(16):
qm[i] ^= qmkey[16 - i]
qm[i] ^= hbkey[16 - i]
hb[i] ^= hbkey[16 - i]
hb[i] ^= qmkey[16 - i]
for i in range(16):
qm[i] ^= qmkey[i]
qm[i] ^= hbkey[i]
hb[i] ^= hbkey[i]
hb[i] ^= qmkey[i]
hbkey = key1[0:16] + [0]
qmkey = key1[16:32] + [0]
for i in range(16):
qm[i] ^= qmkey[16 - i]
qm[i] ^= hbkey[16 - i]
hb[i] ^= hbkey[16 - i]
hb[i] ^= qmkey[16 - i]
for i in range(16):
qm[i] ^= qmkey[i]
qm[i] ^= hbkey[i]
hb[i] ^= hbkey[i]
hb[i] ^= qmkey[i]
flag = "".join([chr(i) for i in qm + hb])
print(flag)
# flag{Virus_gonna_be_terminated!}

babyvm | vmre

模拟虚拟机运行过程 :

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# emulate the procees of vm
from struct import unpack

with open("opcode.txt", "w") as opcode:
with open("opcode.vm", 'rb') as opcode_file:
with open("memory.vm", 'rb') as memory:
all_memory = []
input_text = []
output_text = []
data = memory.read(4)
while(data):
all_memory.append(unpack("<I", data)[0])
data = memory.read(4)
now_op = opcode_file.read(4)
in_pointer = 0
out_pointer = 0
count = 0
count_sum = 0
while(now_op):
print(unpack("<I", now_op)[0])
if unpack("<I", now_op)[0] == 1:
now_op = opcode_file.read(3 * 4)
all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] + all_memory[unpack("<I", now_op[8:12])[0]]
now_op = opcode_file.read(4)
continue
if unpack("<I", now_op)[0] == 2:
now_op = opcode_file.read(3 * 4)
opcode.write("sum[" + str(count_sum - 8) + "] == " + str(all_memory[unpack("<I", now_op[8:12])[0]]) + "\n")
count_sum += 1
all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] - all_memory[unpack("<I", now_op[8:12])[0]]
now_op = opcode_file.read(4)
continue
if unpack("<I", now_op)[0] == 3:
now_op = opcode_file.read(3 * 4)
opcode.write("key[" + str(int(count / 20)) +"][" + str(count % 20) + "] == " + str(all_memory[unpack("<I", now_op[8:12])[0]]) + ", ")
count += 1
all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] * all_memory[unpack("<I", now_op[8:12])[0]]
now_op = opcode_file.read(4)
continue
if unpack("<I", now_op)[0] == 4:
now_op = opcode_file.read(3 * 4)
print("mem[" + str(unpack("<I", (now_op[0:4]))[0]) + "] = mem[" + str(unpack("<I", now_op[4:8])[0]) + "] / mem[" + str(unpack("<I", now_op[8:12])[0]) + "]")
opcode.write("mem[" + str(unpack("<I", (now_op[0:4]))[0]) + "] = mem[" + str(unpack("<I", now_op[4:8])[0]) + "] / mem[" + str(unpack("<I", now_op[8:12])[0]) + "]\n")
print("mem[" + str(unpack("<I", now_op[0:4])[0]) + "] = " + str(all_memory[unpack("<I", now_op[0:4])[0]]), end = ", ")
opcode.write("mem[" + str(unpack("<I", now_op[0:4])[0]) + "] = " + str(all_memory[unpack("<I", now_op[0:4])[0]]) + "\n")
print("mem[" + str(unpack("<I", now_op[4:8])[0]) + "] = " + str(all_memory[unpack("<I", now_op[4:8])[0]]), end = ", ")
opcode.write("mem[" + str(unpack("<I", now_op[4:8])[0]) + "] = " + str(all_memory[unpack("<I", now_op[4:8])[0]]) + "\n")
print("mem[" + str(unpack("<I", now_op[8:12])[0]) + "] = " + str(all_memory[unpack("<I", now_op[8:12])[0]]))
opcode.write("mem[" + str(unpack("<I", now_op[8:12])[0]) + "] = " + str(all_memory[unpack("<I", now_op[8:12])[0]]) + "\n")
all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] / all_memory[unpack("<I", now_op[8:12])[0]]
now_op = opcode_file.read(4)
continue
#reset the in pointer
if unpack("<I", now_op)[0] == 5:
in_pointer = 0
print("in_pointer = 0")
opcode.write("in_pointer = 0\n")
now_op = opcode_file.read(4)
continue
#reset the out pointer
if unpack("<I", now_op)[0] == 6:
out_pointer = 0
print("out_pointer = 0")
opcode.write("out_pointer = 0\n")
now_op = opcode_file.read(4)
continue
#pop-in
if unpack("<I", now_op)[0] == 7:
now_op = opcode_file.read(4)
arg = opcode_file.read(4)
print("from input[" + hex(in_pointer) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to mem[" + str(unpack("<I", now_op)[0]) + "]")
opcode.write("from input[" + hex(in_pointer) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to mem[" + str(unpack("<I", now_op)[0]) + "]\n")
for i in range(unpack("<I", arg)[0]):
try:
all_memory[unpack("<I", now_op)[0] + i] = input_text[in_pointer]
in_pointer += 1
except:
break
now_op = opcode_file.read(4)
continue
#pop-out
if unpack("<I", now_op)[0] == 8:
now_op = opcode_file.read(4)
arg = opcode_file.read(4)
print("from mem[" + str(unpack("<I", now_op)[0]) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to output[" + hex(out_pointer) + "]")
opcode.write("from mem[" + str(unpack("<I", now_op)[0]) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to output[" + hex(out_pointer) + "]\n")
for i in range(unpack("<I", arg)[0]):
output_text.append(all_memory[unpack("<I", now_op)[0] + i])
out_pointer += 1
now_op = opcode_file.read(4)
continue
#read_buffer
if unpack("<I", now_op)[0] == 9:
now_op = opcode_file.read(4)
print("get_user_input and write in", unpack("<I", now_op)[0])
opcode.write("get_user_input and write in " + str(unpack("<I", now_op)[0]) + "\n")
input_text = [ord(c) for c in input()]
for i in range(len(input_text)):
all_memory[unpack("<I", now_op)[0] + i] = input_text[i]
now_op = opcode_file.read(4)
continue
#write_buffer
if unpack("<I", now_op)[0] == 10:
now_op = opcode_file.read(4)
print("print signal(correct or not)")
opcode.write("print signal(correct or not)\n")
print("".join([chr(c) for c in output_text]))
opcode.write("".join([chr(c) for c in output_text]) + "\n")
now_op = opcode_file.read(4)
continue
#jump
if unpack("<I", now_op)[0] == 11:
now_op = opcode_file.read(4)
arg = opcode_file.read(4)
now_mem = all_memory[unpack("<I", arg)[0]]
# if (arg and not(now_mem)):
# print("goto " + hex(unpack("<I", now_op)[0]))
# opcode_file.seek(unpack("<I", now_op)[0])
# now_op = opcode_file.read(4)
# continue
# else:
print("not jump")
opcode.write("not jump\n")
for _ in range(unpack("<I", now_op)[0] - 1):
now_op = opcode_file.read(4)
now_op = opcode_file.read(4)
continue
#not-jump
if unpack("<I", now_op)[0] == 12:
now_op = opcode_file.read(4)
arg = opcode_file.read(4)
now_mem = all_memory[unpack("<I", arg)[0]]
# if (arg and (now_mem)):
# print("goto " + hex(unpack("<I", now_op)[0]))
# opcode_file.seek(unpack("<I", now_op)[0])
# now_op = opcode_file.read(4)
# continue
# else:
print("not jump")
opcode.write("not jump\n")
for _ in range(unpack("<I", now_op)[0] - 2):
now_op = opcode_file.read(4)
now_op = opcode_file.read(4)
continue
#get-lenth-of-input
if unpack("<I", now_op)[0] == 13:
now_op = opcode_file.read(4)
arg = opcode_file.read(4)
print("mem[" + str(unpack("<I", arg)[0]) + "] = len(mem[" + str(unpack("<I", now_op)[0]) +"])")
opcode.write("mem[" + str(unpack("<I", arg)[0]) + "] = len(mem[" + str(unpack("<I", now_op)[0]) +"])\n")
all_memory[unpack("<I", arg)[0]] = len(input_text)
now_op = opcode_file.read(4)
continue
else:
print("error")
break

这里对所有flag错误导致的跳转进行剪枝 让虚拟机一直跑到结束以获得完整的运行过程 发现是用输入的20个字节构造20元方程组(所以这里的输出op的脚本进行了简化 只输出每一项的系数和0次项) 得到增广矩阵:

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
key[0][0] == 115, key[0][1] == 26, key[0][2] == 128, key[0][3] == 200, key[0][4] == 21, key[0][5] == 234, key[0][6] == 172, key[0][7] == 152, key[0][8] == 39, key[0][9] == 71, key[0][10] == 55, key[0][11] == 28, key[0][12] == 105, key[0][13] == 42, key[0][14] == 75, key[0][15] == 63, key[0][16] == 114, key[0][17] == 205, key[0][18] == 2, key[0][19] == 222, sum[0] == 217114
not jump
key[1][0] == 212, key[1][1] == 148, key[1][2] == 17, key[1][3] == 74, key[1][4] == 87, key[1][5] == 253, key[1][6] == 250, key[1][7] == 136, key[1][8] == 89, key[1][9] == 211, key[1][10] == 49, key[1][11] == 26, key[1][12] == 115, key[1][13] == 88, key[1][14] == 181, key[1][15] == 195, key[1][16] == 237, key[1][17] == 10, key[1][18] == 119, key[1][19] == 121, sum[1] == 270581
not jump
key[2][0] == 229, key[2][1] == 172, key[2][2] == 230, key[2][3] == 123, key[2][4] == 245, key[2][5] == 127, key[2][6] == 119, key[2][7] == 157, key[2][8] == 208, key[2][9] == 159, key[2][10] == 37, key[2][11] == 32, key[2][12] == 5, key[2][13] == 207, key[2][14] == 145, key[2][15] == 75, key[2][16] == 251, key[2][17] == 60, key[2][18] == 135, key[2][19] == 125, sum[2] == 291585
not jump
key[3][0] == 181, key[3][1] == 83, key[3][2] == 66, key[3][3] == 43, key[3][4] == 85, key[3][5] == 198, key[3][6] == 89, key[3][7] == 205, key[3][8] == 114, key[3][9] == 221, key[3][10] == 105, key[3][11] == 145, key[3][12] == 155, key[3][13] == 91, key[3][14] == 123, key[3][15] == 48, key[3][16] == 76, key[3][17] == 64, key[3][18] == 141, key[3][19] == 22, sum[3] == 234325
not jump
key[4][0] == 211, key[4][1] == 225, key[4][2] == 204, key[4][3] == 55, key[4][4] == 107, key[4][5] == 76, key[4][6] == 7, key[4][7] == 39, key[4][8] == 199, key[4][9] == 84, key[4][10] == 167, key[4][11] == 62, key[4][12] == 219, key[4][13] == 54, key[4][14] == 6, key[4][15] == 144, key[4][16] == 55, key[4][17] == 98, key[4][18] == 186, key[4][19] == 116, sum[4] == 240502
not jump
key[5][0] == 149, key[5][1] == 163, key[5][2] == 127, key[5][3] == 186, key[5][4] == 46, key[5][5] == 118, key[5][6] == 247, key[5][7] == 194, key[5][8] == 9, key[5][9] == 165, key[5][10] == 169, key[5][11] == 224, key[5][12] == 68, key[5][13] == 129, key[5][14] == 54, key[5][15] == 15, key[5][16] == 134, key[5][17] == 39, key[5][18] == 185, key[5][19] == 248, sum[5] == 277604
not jump
key[6][0] == 245, key[6][1] == 159, key[6][2] == 64, key[6][3] == 241, key[6][4] == 163, key[6][5] == 116, key[6][6] == 4, key[6][7] == 15, key[6][8] == 126, key[6][9] == 170, key[6][10] == 10, key[6][11] == 110, key[6][12] == 251, key[6][13] == 169, key[6][14] == 252, key[6][15] == 99, key[6][16] == 199, key[6][17] == 188, key[6][18] == 149, key[6][19] == 72, sum[6] == 286168
not jump
key[7][0] == 233, key[7][1] == 38, key[7][2] == 197, key[7][3] == 105, key[7][4] == 202, key[7][5] == 2, key[7][6] == 22, key[7][7] == 225, key[7][8] == 189, key[7][9] == 166, key[7][10] == 239, key[7][11] == 220, key[7][12] == 70, key[7][13] == 98, key[7][14] == 194, key[7][15] == 129, key[7][16] == 27, key[7][17] == 236, key[7][18] == 159, key[7][19] == 62, sum[7] == 290450
not jump
key[8][0] == 152, key[8][1] == 67, key[8][2] == 72, key[8][3] == 35, key[8][4] == 12, key[8][5] == 55, key[8][6] == 139, key[8][7] == 4, key[8][8] == 169, key[8][9] == 142, key[8][10] == 135, key[8][11] == 122, key[8][12] == 3, key[8][13] == 166, key[8][14] == 139, key[8][15] == 62, key[8][16] == 23, key[8][17] == 92, key[8][18] == 11, key[8][19] == 136, sum[8] == 179355
not jump
key[9][0] == 96, key[9][1] == 141, key[9][2] == 38, key[9][3] == 124, key[9][4] == 139, key[9][5] == 43, key[9][6] == 15, key[9][7] == 119, key[9][8] == 30, key[9][9] == 252, key[9][10] == 255, key[9][11] == 123, key[9][12] == 223, key[9][13] == 200, key[9][14] == 21, key[9][15] == 117, key[9][16] == 231, key[9][17] == 9, key[9][18] == 239, key[9][19] == 222, sum[9] == 272487
not jump
key[10][0] == 249, key[10][1] == 91, key[10][2] == 66, key[10][3] == 21, key[10][4] == 121, key[10][5] == 146, key[10][6] == 5, key[10][7] == 180, key[10][8] == 6, key[10][9] == 80, key[10][10] == 112, key[10][11] == 255, key[10][12] == 239, key[10][13] == 17, key[10][14] == 39, key[10][15] == 254, key[10][16] == 153, key[10][17] == 118, key[10][18] == 47, key[10][19] == 217, sum[10] == 249816
not jump
key[11][0] == 84, key[11][1] == 96, key[11][2] == 190, key[11][3] == 188, key[11][4] == 255, key[11][5] == 181, key[11][6] == 188, key[11][7] == 124, key[11][8] == 47, key[11][9] == 70, key[11][10] == 201, key[11][11] == 160, key[11][12] == 126, key[11][13] == 210, key[11][14] == 236, key[11][15] == 22, key[11][16] == 120, key[11][17] == 181, key[11][18] == 197, key[11][19] == 69, sum[11] == 305636
not jump
key[12][0] == 51, key[12][1] == 173, key[12][2] == 216, key[12][3] == 143, key[12][4] == 41, key[12][5] == 174, key[12][6] == 184, key[12][7] == 189, key[12][8] == 111, key[12][9] == 133, key[12][10] == 79, key[12][11] == 36, key[12][12] == 99, key[12][13] == 140, key[12][14] == 120, key[12][15] == 144, key[12][16] == 80, key[12][17] == 231, key[12][18] == 187, key[12][19] == 107, sum[12] == 276217
not jump
key[13][0] == 173, key[13][1] == 39, key[13][2] == 151, key[13][3] == 161, key[13][4] == 139, key[13][5] == 233, key[13][6] == 143, key[13][7] == 205, key[13][8] == 170, key[13][9] == 125, key[13][10] == 209, key[13][11] == 54, key[13][12] == 128, key[13][13] == 134, key[13][14] == 55, key[13][15] == 246, key[13][16] == 157, key[13][17] == 57, key[13][18] == 42, key[13][19] == 195, sum[13] == 294166
not jump
key[14][0] == 5, key[14][1] == 49, key[14][2] == 235, key[14][3] == 8, key[14][4] == 84, key[14][5] == 9, key[14][6] == 219, key[14][7] == 90, key[14][8] == 109, key[14][9] == 164, key[14][10] == 38, key[14][11] == 159, key[14][12] == 218, key[14][13] == 214, key[14][14] == 22, key[14][15] == 205, key[14][16] == 7, key[14][17] == 57, key[14][18] == 210, key[14][19] == 131, sum[14] == 237236
not jump
key[15][0] == 107, key[15][1] == 67, key[15][2] == 107, key[15][3] == 141, key[15][4] == 129, key[15][5] == 250, key[15][6] == 97, key[15][7] == 3, key[15][8] == 26, key[15][9] == 215, key[15][10] == 119, key[15][11] == 213, key[15][12] == 255, key[15][13] == 183, key[15][14] == 229, key[15][15] == 1, key[15][16] == 27, key[15][17] == 9, key[15][18] == 88, key[15][19] == 59, sum[15] == 242008
not jump
key[16][0] == 57, key[16][1] == 72, key[16][2] == 91, key[16][3] == 96, key[16][4] == 125, key[16][5] == 105, key[16][6] == 94, key[16][7] == 235, key[16][8] == 138, key[16][9] == 39, key[16][10] == 145, key[16][11] == 130, key[16][12] == 126, key[16][13] == 147, key[16][14] == 254, key[16][15] == 179, key[16][16] == 181, key[16][17] == 183, key[16][18] == 216, key[16][19] == 211, sum[16] == 289929
not jump
key[17][0] == 164, key[17][1] == 205, key[17][2] == 28, key[17][3] == 160, key[17][4] == 233, key[17][5] == 70, key[17][6] == 109, key[17][7] == 51, key[17][8] == 0, key[17][9] == 71, key[17][10] == 99, key[17][11] == 163, key[17][12] == 37, key[17][13] == 98, key[17][14] == 46, key[17][15] == 44, key[17][16] == 138, key[17][17] == 135, key[17][18] == 191, key[17][19] == 144, sum[17] == 221788
not jump
key[18][0] == 13, key[18][1] == 240, key[18][2] == 143, key[18][3] == 53, key[18][4] == 75, key[18][5] == 23, key[18][6] == 26, key[18][7] == 224, key[18][8] == 31, key[18][9] == 199, key[18][10] == 182, key[18][11] == 220, key[18][12] == 130, key[18][13] == 61, key[18][14] == 170, key[18][15] == 130, key[18][16] == 253, key[18][17] == 240, key[18][18] == 182, key[18][19] == 9, sum[18] == 268459
not jump
key[19][0] == 245, key[19][1] == 96, key[19][2] == 170, key[19][3] == 79, key[19][4] == 249, key[19][5] == 16, key[19][6] == 121, key[19][7] == 6, key[19][8] == 7, key[19][9] == 69, key[19][10] == 212, key[19][11] == 133, key[19][12] == 52, key[19][13] == 20, key[19][14] == 225, key[19][15] == 102, key[19][16] == 228, key[19][17] == 121, key[19][18] == 56, key[19][19] == 208, sum[19] == 247407

用z3解该方程组(建议使用z3++ python效率太低但是谁让我不会呢)

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
from z3 import *

flag = [Int("flag_%s" % i) for i in range(20)]
key = [[Int("key_%d_%d" % (i, j)) for j in range(20)] for i in range(20)]
sum = [Int('sum_%d' % i) for i in range(20)]
s = Solver()
for i in range(20):
s.add(sum[i] == 0)
s.add(key[0][0] == 115, key[0][1] == 26, key[0][2] == 128, key[0][3] == 200, key[0][4] == 21, key[0][5] == 234, key[0][6] == 172, key[0][7] == 152, key[0][8] == 39, key[0][9] == 71, key[0][10] == 55, key[0][11] == 28, key[0][12] == 105, key[0][13] == 42, key[0][14] == 75, key[0][15] == 63, key[0][16] == 114, key[0][17] == 205, key[0][18] == 2, key[0][19] == 222,
key[1][0] == 212, key[1][1] == 148, key[1][2] == 17, key[1][3] == 74, key[1][4] == 87, key[1][5] == 253, key[1][6] == 250, key[1][7] == 136, key[1][8] == 89, key[1][9] == 211, key[1][10] == 49, key[1][11] == 26, key[1][12] == 115, key[1][13] == 88, key[1][14] == 181, key[1][15] == 195, key[1][16] == 237, key[1][17] == 10, key[1][18] == 119, key[1][19] == 121,
key[2][0] == 229, key[2][1] == 172, key[2][2] == 230, key[2][3] == 123, key[2][4] == 245, key[2][5] == 127, key[2][6] == 119, key[2][7] == 157, key[2][8] == 208, key[2][9] == 159, key[2][10] == 37, key[2][11] == 32, key[2][12] == 5, key[2][13] == 207, key[2][14] == 145, key[2][15] == 75, key[2][16] == 251, key[2][17] == 60, key[2][18] == 135, key[2][19] == 125,
key[3][0] == 181, key[3][1] == 83, key[3][2] == 66, key[3][3] == 43, key[3][4] == 85, key[3][5] == 198, key[3][6] == 89, key[3][7] == 205, key[3][8] == 114, key[3][9] == 221, key[3][10] == 105, key[3][11] == 145, key[3][12] == 155, key[3][13] == 91, key[3][14] == 123, key[3][15] == 48, key[3][16] == 76, key[3][17] == 64, key[3][18] == 141, key[3][19] == 22,
key[4][0] == 211, key[4][1] == 225, key[4][2] == 204, key[4][3] == 55, key[4][4] == 107, key[4][5] == 76, key[4][6] == 7, key[4][7] == 39, key[4][8] == 199, key[4][9] == 84, key[4][10] == 167, key[4][11] == 62, key[4][12] == 219, key[4][13] == 54, key[4][14] == 6, key[4][15] == 144, key[4][16] == 55, key[4][17] == 98, key[4][18] == 186, key[4][19] == 116,
key[5][0] == 149, key[5][1] == 163, key[5][2] == 127, key[5][3] == 186, key[5][4] == 46, key[5][5] == 118, key[5][6] == 247, key[5][7] == 194, key[5][8] == 9, key[5][9] == 165, key[5][10] == 169, key[5][11] == 224, key[5][12] == 68, key[5][13] == 129, key[5][14] == 54, key[5][15] == 15, key[5][16] == 134, key[5][17] == 39, key[5][18] == 185, key[5][19] == 248,
key[6][0] == 245, key[6][1] == 159, key[6][2] == 64, key[6][3] == 241, key[6][4] == 163, key[6][5] == 116, key[6][6] == 4, key[6][7] == 15, key[6][8] == 126, key[6][9] == 170, key[6][10] == 10, key[6][11] == 110, key[6][12] == 251, key[6][13] == 169, key[6][14] == 252, key[6][15] == 99, key[6][16] == 199, key[6][17] == 188, key[6][18] == 149, key[6][19] == 72,
key[7][0] == 233, key[7][1] == 38, key[7][2] == 197, key[7][3] == 105, key[7][4] == 202, key[7][5] == 2, key[7][6] == 22, key[7][7] == 225, key[7][8] == 189, key[7][9] == 166, key[7][10] == 239, key[7][11] == 220, key[7][12] == 70, key[7][13] == 98, key[7][14] == 194, key[7][15] == 129, key[7][16] == 27, key[7][17] == 236, key[7][18] == 159, key[7][19] == 62,
key[8][0] == 152, key[8][1] == 67, key[8][2] == 72, key[8][3] == 35, key[8][4] == 12, key[8][5] == 55, key[8][6] == 139, key[8][7] == 4, key[8][8] == 169, key[8][9] == 142, key[8][10] == 135, key[8][11] == 122, key[8][12] == 3, key[8][13] == 166, key[8][14] == 139, key[8][15] == 62, key[8][16] == 23, key[8][17] == 92, key[8][18] == 11, key[8][19] == 136,
key[9][0] == 96, key[9][1] == 141, key[9][2] == 38, key[9][3] == 124, key[9][4] == 139, key[9][5] == 43, key[9][6] == 15, key[9][7] == 119, key[9][8] == 30, key[9][9] == 252, key[9][10] == 255, key[9][11] == 123, key[9][12] == 223, key[9][13] == 200, key[9][14] == 21, key[9][15] == 117, key[9][16] == 231, key[9][17] == 9, key[9][18] == 239, key[9][19] == 222,
key[10][0] == 249, key[10][1] == 91, key[10][2] == 66, key[10][3] == 21, key[10][4] == 121, key[10][5] == 146, key[10][6] == 5, key[10][7] == 180, key[10][8] == 6, key[10][9] == 80, key[10][10] == 112, key[10][11] == 255, key[10][12] == 239, key[10][13] == 17, key[10][14] == 39, key[10][15] == 254, key[10][16] == 153, key[10][17] == 118, key[10][18] == 47, key[10][19] == 217,
key[11][0] == 84, key[11][1] == 96, key[11][2] == 190, key[11][3] == 188, key[11][4] == 255, key[11][5] == 181, key[11][6] == 188, key[11][7] == 124, key[11][8] == 47, key[11][9] == 70, key[11][10] == 201, key[11][11] == 160, key[11][12] == 126, key[11][13] == 210, key[11][14] == 236, key[11][15] == 22, key[11][16] == 120, key[11][17] == 181, key[11][18] == 197, key[11][19] == 69,
key[12][0] == 51, key[12][1] == 173, key[12][2] == 216, key[12][3] == 143, key[12][4] == 41, key[12][5] == 174, key[12][6] == 184, key[12][7] == 189, key[12][8] == 111, key[12][9] == 133, key[12][10] == 79, key[12][11] == 36, key[12][12] == 99, key[12][13] == 140, key[12][14] == 120, key[12][15] == 144, key[12][16] == 80, key[12][17] == 231, key[12][18] == 187, key[12][19] == 107,
key[13][0] == 173, key[13][1] == 39, key[13][2] == 151, key[13][3] == 161, key[13][4] == 139, key[13][5] == 233, key[13][6] == 143, key[13][7] == 205, key[13][8] == 170, key[13][9] == 125, key[13][10] == 209, key[13][11] == 54, key[13][12] == 128, key[13][13] == 134, key[13][14] == 55, key[13][15] == 246, key[13][16] == 157, key[13][17] == 57, key[13][18] == 42, key[13][19] == 195,
key[14][0] == 5, key[14][1] == 49, key[14][2] == 235, key[14][3] == 8, key[14][4] == 84, key[14][5] == 9, key[14][6] == 219, key[14][7] == 90, key[14][8] == 109, key[14][9] == 164, key[14][10] == 38, key[14][11] == 159, key[14][12] == 218, key[14][13] == 214, key[14][14] == 22, key[14][15] == 205, key[14][16] == 7, key[14][17] == 57, key[14][18] == 210, key[14][19] == 131,
key[15][0] == 107, key[15][1] == 67, key[15][2] == 107, key[15][3] == 141, key[15][4] == 129, key[15][5] == 250, key[15][6] == 97, key[15][7] == 3, key[15][8] == 26, key[15][9] == 215, key[15][10] == 119, key[15][11] == 213, key[15][12] == 255, key[15][13] == 183, key[15][14] == 229, key[15][15] == 1, key[15][16] == 27, key[15][17] == 9, key[15][18] == 88, key[15][19] == 59,
key[16][0] == 57, key[16][1] == 72, key[16][2] == 91, key[16][3] == 96, key[16][4] == 125, key[16][5] == 105, key[16][6] == 94, key[16][7] == 235, key[16][8] == 138, key[16][9] == 39, key[16][10] == 145, key[16][11] == 130, key[16][12] == 126, key[16][13] == 147, key[16][14] == 254, key[16][15] == 179, key[16][16] == 181, key[16][17] == 183, key[16][18] == 216, key[16][19] == 211,
key[17][0] == 164, key[17][1] == 205, key[17][2] == 28, key[17][3] == 160, key[17][4] == 233, key[17][5] == 70, key[17][6] == 109, key[17][7] == 51, key[17][8] == 0, key[17][9] == 71, key[17][10] == 99, key[17][11] == 163, key[17][12] == 37, key[17][13] == 98, key[17][14] == 46, key[17][15] == 44, key[17][16] == 138, key[17][17] == 135, key[17][18] == 191, key[17][19] == 144,
key[18][0] == 13, key[18][1] == 240, key[18][2] == 143, key[18][3] == 53, key[18][4] == 75, key[18][5] == 23, key[18][6] == 26, key[18][7] == 224, key[18][8] == 31, key[18][9] == 199, key[18][10] == 182, key[18][11] == 220, key[18][12] == 130, key[18][13] == 61, key[18][14] == 170, key[18][15] == 130, key[18][16] == 253, key[18][17] == 240, key[18][18] == 182, key[18][19] == 9,
key[19][0] == 245, key[19][1] == 96, key[19][2] == 170, key[19][3] == 79, key[19][4] == 249, key[19][5] == 16, key[19][6] == 121, key[19][7] == 6, key[19][8] == 7, key[19][9] == 69, key[19][10] == 212, key[19][11] == 133, key[19][12] == 52, key[19][13] == 20, key[19][14] == 225, key[19][15] == 102, key[19][16] == 228, key[19][17] == 121, key[19][18] == 56, key[19][19] == 208)
for i in range(20):
for j in range(20):
sum[i] += flag[j] * key[i][j]
s.add(sum[0] == 217114, sum[1] == 270581, sum[2] == 291585, sum[3] == 234325, sum[4] == 240502, sum[5] == 277604, sum[6] == 286168, sum[7] == 290450, sum[8] == 179355, sum[9] == 272487, sum[10] == 249816, sum[11] == 305636, sum[12] == 276217, sum[13] == 294166, sum[14] == 237236, sum[15] == 242008, sum[16] == 289929, sum[17] == 221788, sum[18] == 268459, sum[19] == 247407)
if s.check() == sat:
m = s.model()
print(''.join([chr(m[flag[i]].as_long()) for i in range(20)]))
# have_fun_in_vm_hahaa

ezvm | vmre

与上一个vm不同的是引入了寄存器和flag位 采用函数表的方式存放op 还是先弄懂每个op的含义 然后模拟出加密过程:

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# emulate the procees of vm
'''
op_1_extract_v_from_reg_by_hb
op_1_extract_v_from_reg_by_lb
op_2_save_in_reg_by_hb
op_3_nop ; pt += 1
op_4_add ; reg[hb] += reg[lb]
op_5_minus ; reg[hb] -= reg[lb]
op_6_mul ; reg[hb] *= reg[lb]
op_7_div ; reg[hb] /= reg[lb]
op_8_inc ; reg[hb] += 1
op_9_dec ; reg[hb] -= 1
op_10_xor ; reg[hb] ^= reg[lb]
op_11_and ; reg[hb] &= reg[lb]
op_12_pop_in ; pop reg[hb] in stack
op_13 ; 组合op[9]接下来的4个数据(大端序)并入栈
op_14 ; esp += 4
op_15 ; reg[hb] = reg[lb]
op_16 ; reg[hb] = input[k]
op_17 ; input[k] = reg[hb]
op_18 ; check reg[3]:reg[3] = 1 -> *op[9] -= *(op[9] + 1)
op_19 ; set reg[4]:reg[4] = sign of (reg[hb] - reg[lb])
op_20 ; check reg[4]:reg[4] == -1 -> op[9] += 2 + *(op[9] + 1) else += 2
op_21 ; anti-op_20, reg[4] == 1
op_22 ; else reg[4] == 0
op_23 ; k++
op_24 ; k--
op_25 ; *(op[9] + i) ^= 0x66 for i in range(1, 16)
'''
stack = [0] * 0x100
input_text = [ord(i) for i in input()]
k = 0
reg = [0] * 5
esp = len(stack) - 1
opcode = [0x70, 0x00, 0x00, 0x00, 0x1E, 0x71, 0x30, 0x73, 0x00, 0x7A,
0x73, 0x10, 0x67, 0x01, 0x7B, 0x74, 0x00, 0x7A, 0x75, 0x0B,
0x70, 0x00, 0x00, 0x00, 0x1E, 0x71, 0x30, 0x7B, 0x75, 0x01,
0x70, 0x00, 0x00, 0x00, 0x1E, 0x71, 0x30, 0x73, 0x10, 0x7A,
0x73, 0x00, 0x6D, 0x01, 0x74, 0x00, 0x75, 0x09, 0x66, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xC7, 0x0B, 0xDB, 0x0C, 0xE5, 0x08,
0xAD, 0xDE, 0xAF, 0xCD, 0x67, 0xBF, 0x1F, 0xBF, 0x1E, 0x68,
0xFE, 0x25, 0xFD, 0x6F, 0x08, 0x50, 0xCD, 0x15, 0xB0, 0x21,
0x8B, 0x3E, 0xFD, 0x73, 0xED, 0x90, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
pointer_to_opcode = 0
while pointer_to_opcode < len(opcode):
print("==================opcode: " + hex(opcode[pointer_to_opcode]), opcode[pointer_to_opcode] - 0x67 + 4, f"is excuted=======================opcode at {pointer_to_opcode}=====================")
if opcode[pointer_to_opcode] == 0x66:
print("failed")
break
if opcode[pointer_to_opcode] == 0x67:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] += reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] += reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x68:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] -= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] -= reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x69:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] *= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] *= reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x6A:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] /= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] /= reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x6B:
print(reg[opcode[pointer_to_opcode + 1] >> 4], "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] += 1", "\n")
reg[opcode[pointer_to_opcode + 1] >> 4] += 1
pointer_to_opcode += 1
continue
if opcode[pointer_to_opcode] == 0x6C:
print(reg[opcode[pointer_to_opcode + 1] >> 4], "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] -= 1", "\n")
reg[opcode[pointer_to_opcode + 1] >> 4] -= 1
pointer_to_opcode += 1
continue
if opcode[pointer_to_opcode] == 0x6D:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] ^= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] ^= reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x6E:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] &= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] &= reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x6F:
print(reg[opcode[pointer_to_opcode + 1] >> 4], "\n", "pop reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] in stack")
esp -= 1
stack[esp] = reg[opcode[pointer_to_opcode + 1] >> 4]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x70:
data = opcode[pointer_to_opcode + 1] << 24 | opcode[pointer_to_opcode + 2] << 16 | opcode[pointer_to_opcode + 3] << 8 | opcode[pointer_to_opcode + 4]
print("pop " + hex(data) + " in stack")
esp -= 1
stack[esp] = data
pointer_to_opcode += 5
continue
if opcode[pointer_to_opcode] == 0x71:
reg[opcode[pointer_to_opcode + 1] >> 4] = stack[esp]
print(f"pop {stack[esp]} out to reg[{opcode[pointer_to_opcode + 1] >> 4}] and esp += 1")
esp += 1
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x72:
print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] = reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] = reg[opcode[pointer_to_opcode + 1] & 0x0F]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x73:
print("reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] = input[" + str(k) + "]")
reg[opcode[pointer_to_opcode + 1] >> 4] = input_text[k]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x74:
print("input[" + str(k) + "] = reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "]" )
input_text[k] = reg[opcode[pointer_to_opcode + 1] >> 4]
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x75:
if reg[3]:
print("jump to", hex(pointer_to_opcode - opcode[pointer_to_opcode + 1]))
print(f"reg[3] = {reg[3]}")
reg[3] -= 1
pointer_to_opcode -= opcode[pointer_to_opcode + 1]
else:
print("not jump")
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x76:
if reg[opcode[pointer_to_opcode + 1] >> 4] == reg[opcode[pointer_to_opcode + 1] & 0x0F]:
reg[4] = 0
pointer_to_opcode += 2
continue
reg[4] = 1 if reg[opcode[pointer_to_opcode + 1] >> 4] > reg[opcode[pointer_to_opcode + 1] & 0x0F] else -1
print("set reg[4] to", reg[4], "cause", reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F])
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x77:
if reg[4] == 0:
print("jump to", hex(pointer_to_opcode + opcode[pointer_to_opcode + 1]))
pointer_to_opcode += opcode[pointer_to_opcode + 1]
else:
print("not jump cause reg[4] = ", reg[4])
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x78:
if reg[4] == 1:
print("jump to", hex(pointer_to_opcode + opcode[pointer_to_opcode + 1]))
pointer_to_opcode += opcode[pointer_to_opcode + 1]
else:
print("not jump cause reg[4] = ", reg[4])
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x79:
if reg[4] == -1:
print("jump to", hex(pointer_to_opcode + opcode[pointer_to_opcode + 1]))
pointer_to_opcode += opcode[pointer_to_opcode + 1]
else:
print("not jump cause reg[4] = ", reg[4])
pointer_to_opcode += 2
continue
if opcode[pointer_to_opcode] == 0x7A:
print("k++")
k += 1
pointer_to_opcode += 1
continue
if opcode[pointer_to_opcode] == 0x7B:
print("k--")
k -= 1
pointer_to_opcode += 1
continue
if opcode[pointer_to_opcode] == 0x7C:
for i in range(1, 16):
print(opcode[pointer_to_opcode + 1], "\n", "opcode[" + str(pointer_to_opcode + i) + "] ^= 0x66")
stack[esp + i] ^= 0x66
pointer_to_opcode += 16
continue
pointer_to_opcode += 1

发现加密过程就是flag的每一位+=下一位(除最后一位) 然后再逆序每一位^=上一位(除第一位) 据此写出keygen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enc = [0xC7, 0x0B, 0xDB, 0x0C, 0xE5, 0x08, 0xAD, 0xDE, 0xAF, 0xCD, 
0x67, 0xBF, 0x1F, 0xBF, 0x1E, 0x68, 0xFE, 0x25, 0xFD, 0x6F,
0x08, 0x50, 0xCD, 0x15, 0xB0, 0x21, 0x8B, 0x3E, 0xFD, 0x73,
0xED, 0x90]
flag = ""
for i in range(len(enc) - 1, 0, -1):
enc[i] ^= enc[i - 1]
for i in range(len(enc) - 1, 0, -1):
enc[i - 1] -= enc[i]
print(enc)
for i in range(len(enc)):
flag += chr(enc[i])
print(flag)
# begin{r3@11y_A_B4by_34$y_FK_Vm!}