[网鼎杯 2020 青龙组]singal
无壳,直接进IDA
主函数非常简单,将unk_403040
复制给v4
然后传递给vm_operad
,接着分析vm_operad
int __cdecl vm_operad(int *a1, int a2)
{
int result; // eax
char Str[200]; // [esp+13h] [ebp-E5h] BYREF
char v4; // [esp+DBh] [ebp-1Dh]
int v5; // [esp+DCh] [ebp-1Ch]
int v6; // [esp+E0h] [ebp-18h]
int v7; // [esp+E4h] [ebp-14h]
int v8; // [esp+E8h] [ebp-10h]
int v9; // [esp+ECh] [ebp-Ch]
v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
v5 = 0;
while ( 1 )
{
result = v9;
if ( v9 >= a2 )
return result;
switch ( a1[v9] )
{
case 1:
Str[v6 + 100] = v4;
++v9;
++v6;
++v8;
break;
case 2:
v4 = a1[v9 + 1] + Str[v8];
v9 += 2;
break;
case 3:
v4 = Str[v8] - LOBYTE(a1[v9 + 1]);
v9 += 2;
break;
case 4:
v4 = a1[v9 + 1] ^ Str[v8];
v9 += 2;
break;
case 5:
v4 = a1[v9 + 1] * Str[v8];
v9 += 2;
break;
case 6:
++v9;
break;
case 7:
if ( Str[v7 + 100] != a1[v9 + 1] )
{
printf("what a shame...");
exit(0);
}
++v7;
v9 += 2;
break;
case 8:
Str[v5] = v4;
++v9;
++v5;
break;
case 10:
read(Str);
++v9;
break;
case 11:
v4 = Str[v8] - 1;
++v9;
break;
case 12:
v4 = Str[v8] + 1;
++v9;
break;
default:
continue;
}
}
}
发现应该是根据传入参数a1不同位置的参数来决定每次的行为,观察到a1的第一个值是0xa
,对应的行为是10号读入,符合直接运行程序
v9: 0
Operation: 10
Operation: 10 Read Str
用python模拟出行为,然后观察,发现比较是最后15个行为,同时与read
函数对比,发现也是读入15位
Operation: 7
Compore position is 100
Encrypted_code: 34
v9: 86
Operation: 7
Compore position is 101
Encrypted_code: 63
v9: 88
Operation: 7
Compore position is 102
Encrypted_code: 52
v9: 90
Operation: 7
Compore position is 103
Encrypted_code: 50
v9: 92
Operation: 7
Compore position is 104
Encrypted_code: 114
v9: 94
Operation: 7
Compore position is 105
Encrypted_code: 51
v9: 96
Operation: 7
Compore position is 106
Encrypted_code: 24
v9: 98
Operation: 7
Compore position is 107
Encrypted_code: 167
v9: 100
Operation: 7
Compore position is 108
Encrypted_code: 49
v9: 102
Operation: 7
Compore position is 109
Encrypted_code: 241
v9: 104
Operation: 7
Compore position is 110
Encrypted_code: 40
v9: 106
Operation: 7
Compore position is 111
Encrypted_code: 132
v9: 108
Operation: 7
Compore position is 112
Encrypted_code: 193
v9: 110
Operation: 7
Compore position is 113
Encrypted_code: 30
v9: 112
Operation: 7
Compore position is 114
Encrypted_code: 122
然后前面每个数都是执行两个操作后,保存等待比较
v9: 1
Operation: 4
Operation: 4 arg1: 16 arg2: 48, xor
v9: 3
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 0
v9: 4
Operation: 3
Operation: 3 arg1: 32 arg2: 5, sub
v9: 6
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 100
v9: 7
Operation: 4
Operation: 4 arg1: 32 arg2: 48, xor
v9: 9
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 1
v9: 10
Operation: 5
Operation: 5 arg1: 3 arg2: 16, mul
v9: 12
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 101
v9: 13
Operation: 3
Operation: 3 arg1: 48 arg2: 2, sub
v9: 15
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 2
v9: 16
Operation: 11
Operation: 11 arg1: 46, sub 1
v9: 17
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 102
v9: 18
Operation: 12
Operation: 12 arg1: 48, add 1
v9: 19
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 3
v9: 20
Operation: 4
Operation: 4 arg1: 4 arg2: 49, xor
v9: 22
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 103
v9: 23
Operation: 5
Operation: 5 arg1: 3 arg2: 48, mul
v9: 25
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 4
v9: 26
Operation: 3
Operation: 3 arg1: 144 arg2: 33, sub
v9: 28
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 104
v9: 29
Operation: 11
Operation: 11 arg1: 48, sub 1
v9: 30
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 5
v9: 31
Operation: 11
Operation: 11 arg1: 47, sub 1
v9: 32
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 105
v9: 33
Operation: 4
Operation: 4 arg1: 9 arg2: 48, xor
v9: 35
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 6
v9: 36
Operation: 3
Operation: 3 arg1: 57 arg2: 32, sub
v9: 38
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 106
v9: 39
Operation: 2
Operation: 2 arg1: 81 arg2: 48, add
v9: 41
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 7
v9: 42
Operation: 4
Operation: 4 arg1: 36 arg2: 129, xor
v9: 44
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 107
v9: 45
Operation: 12
Operation: 12 arg1: 48, add 1
v9: 46
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 8
v9: 47
Operation: 11
Operation: 11 arg1: 49, sub 1
v9: 48
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 108
v9: 49
Operation: 5
Operation: 5 arg1: 2 arg2: 48, mul
v9: 51
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 9
v9: 52
Operation: 2
Operation: 2 arg1: 37 arg2: 96, add
v9: 54
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 109
v9: 55
Operation: 2
Operation: 2 arg1: 54 arg2: 48, add
v9: 57
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 10
v9: 58
Operation: 4
Operation: 4 arg1: 65 arg2: 102, xor
v9: 60
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 110
v9: 61
Operation: 2
Operation: 2 arg1: 32 arg2: 48, add
v9: 63
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 11
v9: 64
Operation: 5
Operation: 5 arg1: 1 arg2: 80, mul
v9: 66
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 111
v9: 67
Operation: 5
Operation: 5 arg1: 3 arg2: 48, mul
v9: 69
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 12
v9: 70
Operation: 2
Operation: 2 arg1: 37 arg2: 144, add
v9: 72
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 112
v9: 73
Operation: 4
Operation: 4 arg1: 9 arg2: 48, xor
v9: 75
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 13
v9: 76
Operation: 3
Operation: 3 arg1: 57 arg2: 32, sub
v9: 78
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 113
v9: 79
Operation: 2
Operation: 2 arg1: 65 arg2: 48, add
v9: 81
Operation: 8
Operation: 8 Push encrypted code to Str, now Str position is 14
v9: 82
Operation: 12
Operation: 12 arg1: 113, add 1
v9: 83
Operation: 1
Operation: 1 Push encrypted code to Str, now Str position is 114
所以写出exp
op = [0xa, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x51, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x72, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x33, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0xa7, 0xff, 0xff, 0xff, 0x7, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0xf1, 0xff, 0xff, 0xff, 0x7, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x84, 0xff, 0xff, 0xff, 0x7, 0x0, 0x0, 0x0, 0xc1, 0xff, 0xff, 0xff, 0x7, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x7a, 0x0, 0x0, 0x0]
v9 = 0
v8 = 0
v7 = 0
v6 = 0
v5 = 0
v4 = ""
Str = ["0"] * 200
cnt = 0
encrypted_codes = []
operations = [[] for _ in range(15)]
while True:
result = v9
if v9 >= 114:
break
match op[v9 * 4]:
case 1:
Str[v6 + 100] = v4
v9 += 1
v6 += 1
v8 += 1
case 2:
operations[v6].append({"opcode": 2, "arg": op[(v9 + 1) * 4]})
v4 = chr(op[(v9 + 1) * 4] + ord(Str[v8]))
v9 += 2
case 3:
operations[v6].append({"opcode": 3, "arg": op[(v9 + 1) * 4]})
v4 = chr(ord(Str[v8]) - op[(v9 + 1)*4])
v9 += 2
case 4:
operations[v6].append({"opcode": 4, "arg": op[(v9 + 1) * 4]})
v4 = chr(op[(v9 + 1) * 4] ^ ord(Str[v8]))
v9 += 2
case 5:
operations[v6].append({"opcode": 5, "arg": op[(v9 + 1) * 4]})
v4 = chr(op[(v9 + 1) * 4] * ord(Str[v8]))
v9 += 2
case 6:
v9 += 1
case 7:
cnt += 1
encrypted_codes.append(op[(v9 + 1) * 4])
v7 += 1
v9 += 2
case 8:
Str[v5] = v4
v5 += 1
v9 += 1
case 10:
v9 += 1
case 11:
operations[v6].append({"opcode": 11, "arg": 1})
v4 = chr(ord(Str[v8]) - 1)
v9 += 1
case 12:
operations[v6].append({"opcode": 12, "arg": 1})
v4 = chr(ord(Str[v8]) + 1)
v9 += 1
case _:
continue
pos = 0
ans = []
while True:
if pos >= len(encrypted_codes):
break
encrypted_code = encrypted_codes[pos]
for i in range(1, -1, -1):
match operations[pos][i]["opcode"]:
case 2:
encrypted_code = encrypted_code - operations[pos][i]["arg"]
case 3:
encrypted_code = encrypted_code + operations[pos][i]["arg"]
case 4:
encrypted_code = encrypted_code ^ operations[pos][i]["arg"]
case 5:
encrypted_code = encrypted_code // operations[pos][i]["arg"]
case 11:
encrypted_code = encrypted_code + operations[pos][i]["arg"]
case 12:
encrypted_code = encrypted_code - operations[pos][i]["arg"]
case _:
continue
ans.append(encrypted_code)
pos += 1
print("".join([chr(i) for i in ans]))
# buuoj: flag{757515121f3d478}
crackMe
无壳,直接进IDA
大致流程是输入用户名和密码,其中sub_401000
是检测输入是否为字母或者数字
核心的分析判断应该就是sub_401090
、loc_4011A0
和sub_401830
其中sub_401090
是RC4算法初始化,传入的a1
是刚刚输入的用户名,在题目提示有是welcomebeijing
,把初始化后的结果存放在byte_416050
,作为S-box
发现有脏东西,用NOP patch掉,保存然后重新解析
发现变成了sub_4011A0
,整理后发现这里面是准备验证后的提示词,没有任何有效信息,那就只有从sub_401830
里找信息了
果然校验逻辑在这里面,从后向前分析
最后v13
的结果要为0xAB94
,而v13
的值来自sub_401470
,sub_401470
的另一个参数v16
来自上面的while循环,这个对v5
的循环实际上是RC4加密,而在上面一个循环是对输入a2
即密码的一个转换处理。先进sub_401470
分析
观察可知v16
应该有8个东西组成,如果if不成立,那就是任意值都可以执行的计算,所以得出v16 = [0x64, 0x62, 0x61, 0x70, 0x70, 0x73, 0x65, 0x63]
,同验证也通过
在拿到v16
的值后,就是通过还原while循环的代码,得到password,写出脚本
v16 = [0x64, 0x62, 0x61, 0x70, 0x70, 0x73, 0x65, 0x63]
v5 = 0
v11 = 0
v10 = 0
byte_416050 = [i for i in range(256)]
v2 = 0
v9 = 0
v3 = 0
a1 = "welcomebeijing"
while v2 < 256:
v8 = byte_416050[v2]
v9 += (v8 + ord(a1[v3 % len(a1)]))
v9 &= 0xff
v7 = byte_416050[v9]
v3 += 1
byte_416050[v9] = v8
byte_416050[v2] = v7
v2 += 1
while v5 < 8:
v11 += 1
v10 += byte_416050[v11]
v10 &= 0xff
v12 = byte_416050[v11]
v7 = byte_416050[v10]
byte_416050[v10] = v12
byte_416050[v11] = v7
v16[v5] ^= byte_416050[(v12 + v7) & 0xff]
v5 += 1
password = "".join([hex(i)[2:] for i in v16])
print(f"password: {password}")
import hashlib
flag = hashlib.md5(password.encode()).hexdigest()
print(f"flag: {flag}")
[GUET-CTF2019]number_game
无壳,直接进IDA,分析主函数
发现判断有两个部分sub_4006D6
和sub_400917
两个函数,首先看第一个函数
__int64 __fastcall sub_4006D6(const char *a1)
{
int i; // [rsp+1Ch] [rbp-4h]
if ( strlen(a1) == 10 )
{
for ( i = 0; i <= 9; ++i )
{
if ( a1[i] > 52 || a1[i] <= 47 )
goto LABEL_2;
}
return 1LL;
}
else
{
LABEL_2:
puts("Wrong!");
return 0LL;
}
}
发现输入是10位数,且只能在0-4之间,接着分析sub_400917
__int64 sub_400917()
{
unsigned int v1; // [rsp+0h] [rbp-10h]
int i; // [rsp+4h] [rbp-Ch]
int j; // [rsp+8h] [rbp-8h]
int k; // [rsp+Ch] [rbp-4h]
v1 = 1;
for ( i = 0; i <= 4; ++i )
{
for ( j = 0; j <= 4; ++j )
{
for ( k = j + 1; k <= 4; ++k )
{
if ( *((_BYTE *)&unk_601060 + 5 * i + j) == *((_BYTE *)&unk_601060 + 5 * i + k) )
v1 = 0;
if ( *((_BYTE *)&unk_601060 + 5 * j + i) == *((_BYTE *)&unk_601060 + 5 * k + i) )
v1 = 0;
}
}
}
return v1;
}
这是把unk_601060
视为了一个5x5
的数组,检查每列和每行是否有相同的内容,没有就通过
那么接下来就是分析,怎么从输入变到这个unk_601060
回到主函数,发现输入分别经过了三个函数sub_400758
、sub_400807
和sub_400881
_QWORD *__fastcall sub_400758(__int64 a1, signed int a2, signed int a3)
{
char v5; // [rsp+1Fh] [rbp-11h]
_QWORD *v6; // [rsp+28h] [rbp-8h]
v5 = *(_BYTE *)(a2 + a1);
if ( v5 == 32 || v5 == 10 || a2 >= a3 )
return 0LL;
v6 = malloc(24uLL);
*(_BYTE *)v6 = v5;
v6[1] = sub_400758(a1, 2 * a2 + 1, a3);
v6[2] = sub_400758(a1, 2 * (a2 + 1), a3);
return v6;
}
这个函数应该是构建一个二叉树
__int64 __fastcall sub_400807(__int64 a1, __int64 a2)
{
__int64 result; // rax
result = a1;
if ( a1 )
{
sub_400807(*(_QWORD *)(a1 + 8), a2);
*(_BYTE *)(a2 + dword_601080++) = *(_BYTE *)a1;
return sub_400807(*(_QWORD *)(a1 + 16), a2);
}
return result;
}
这个函数进行了一次中序遍历
__int64 __fastcall sub_400881(char *a1)
{
__int64 result; // rax
byte_601062 = *a1;
byte_601067 = a1[1];
byte_601069 = a1[2];
byte_60106B = a1[3];
byte_60106E = a1[4];
byte_60106F = a1[5];
byte_601071 = a1[6];
byte_601072 = a1[7];
byte_601076 = a1[8];
result = (unsigned __int8)a1[9];
byte_601077 = a1[9];
return result;
}
而这个函数,则将刚刚中序遍历的结果拿去修改data区域的数据,根据地址推测,修改了前文提到的5x5
矩阵
然后。。原来就是数独简单版(
# [idc.get_wide_byte(0x601060 + i) for i in range(0x601078-0x601060+1)]
matrix = [0x31, 0x34, 0x23, 0x32, 0x33, 0x33, 0x30, 0x23, 0x31, 0x23, 0x30, 0x23, 0x32, 0x33, 0x23, 0x23, 0x33, 0x23, 0x23, 0x30, 0x34, 0x32, 0x23, 0x23, 0x31]
for i in range(5):
for j in range(5):
print(chr(matrix[i*5+j]), end=' ')
print()
1 4 # 2 3
3 0 # 1 #
0 # 2 3 #
# 3 # # 0
4 2 # # 1
所以“数独”解出来是0421421430
还需要通过中序遍历还原
ans = "0421421430"
order = []
ret = [0] * len(ans)
def inorder(i):
global order
if i >= len(ans):
return ""
inorder(2 * i + 1)
order.append(i)
inorder(2 * (i + 1))
inorder(0)
for i in range(len(ans)):
ret[order[i]] = ans[i]
print("".join(ret))
buuoj: flag{1134240024}
findKey
无壳,直接进IDA,看到是vc gui类程序,从字符串开始找线索
发现端倪,找到这个串的位置,查调用,然后。。。怎么有恶心东西啊!
nop!应用修补,重新打开,看到代码
分析一下大致逻辑,发现sub_40101E
是计算md5,sub_401005
是对v8做异或,然后与Str对比
还原异或结果得到c8837b23ff8aaa8a2dde915473ce0991
,解MD5得到原文是123321
符合前面,strlen(String1)>6
就推出程序的预期
接着发现从&unk_423030
取值,与123321
异或后输出结果,可以还原flag了
Str1 = "0kk`d1a`55k222k2a776jbfgd`06cjjb"
md5 = ""
for i in Str1:
md5 += chr(ord(i) ^ ord("S"))
print(md5)
Str2 = [0x57, 0x5e, 0x52, 0x54, 0x49, 0x5f, 0x1, 0x6d, 0x69, 0x46, 0x2, 0x6e, 0x5f, 0x2, 0x6c, 0x57, 0x5b, 0x54, 0x4c]
flag = ""
md55 = "123321"
pos = 0
for i in Str2:
flag += chr(i ^ ord(md55[pos % 6]))
pos += 1
print(flag)
# flag{n0_Zu0_n0_die}
[FlareOn5]Minesweeper Championship Registration
进jadx-gui,直接看到flag
[ACTF新生赛2020]SoulLike
无壳,进IDA
主函数逻辑还是比较清晰,首先比较前5位是不是actf{
开头,然后去LABEL_6
进行后序的比较,而后序的比较核心就在sub_83A
,但是由于函数巨大,ida会提示too big
,这时候就需要去ida/cfg/hexrays.cfg
修改MAX_FUNCSIZE
为更大就可以了
进sub_83A
发现是一对异或,对其处理一下,就得到了flag
把
sub_83A
的内容复制到file.txt
中,然后去头去尾import pathlib
file = pathlib.Path('func.txt')
file_out = pathlib.Path('func_out.py')
funcs = []
with file.open() as f:
while True:
line = f.readline()
if not line:
break
line = line.replace("\n", "")
line = line.replace("u;", "")
line = line.replace("u", "")
line = line.replace(";", "")
line = line.replace("*a1", "a1[0]")
line = line.replace("v3", "a1")
if line.startswith("++"):
line = line[2:] + " -= 1"
funcs.append(line)
funcs.append("a1 = [0] * 12")
with file_out.open("w") as f:
for i in range(len(funcs) - 1, -1, -1):
f.write(funcs[i] + "\n")
f.write('print("".join([chr(i) for i in a1]))')
最后执行python func_out.py
,得到flag
buuoj:flag{b0Nf|Re_LiT!}
[GWCTF 2019]re3
无壳,进IDA
发现是输入长度为32,但是有mprotect
,这个函数改变了内存段上的保护属性,允许该内存段可写可读可执行,结合下面的循环可知,在sub_402219
上代码被保护了,先把内容进行异或0x99
后再执行
第一次遇到这种,参考其他师傅的wp使用如下代码还原
import idc
funcAddr = 0x402219
for i in range(224):
enc = get_bytes(funcAddr + i, 1)
dec = ord(enc) ^ 0x99
patch_byte(funcAddr + i, dec)
就可以看到sub_402219
函数了,然后查看sub_400A71
和sub_40196E
都是和AES有关的函数,推测第一个是准备Key,第二个是计算AES,但是由于只有两个参数,那应该就没有iv,是ECB模式加密的。在加密完成后与byte_6030A0
的值对比
而Key则应该是由sub_40207B
计算出来的