DASCTF 2023六月挑战赛|二进制专项
二进制专项-签到
1
2
3
简单统计下参与人数,祝大家玩得开心~
DASCTF{Welcome_to_DASCTF5}
Reverse-careful
题目给出了一个恶意样本,请分析出样本请求服务器的域名(flag的形式为DASCTF{md5(域名)}) 其中md5值都是小写
拿到题目直接 IDA Pro 打开, 一眼就可以看 gethostbyname();
动态调试可以获取name的值,但是这个地方获取的name不是真正的
直接 快捷键 x 看 gethostbyname() 交叉引用 还有另一处
直在这里下断点,然后动态调试
得到 域名 Just_An_APIH00k11.com
1
2
3
4
5
6
7
8
9
from hashlib import md5
def md5sum(string):
return md5(string.encode('utf-8')).hexdigest()
pass
x = md5sum('Just_An_APIH00k11.com')
print(x)
# f18566f93963f72f463fdfa2d163c37c
# flag{f18566f93963f72f463fdfa2d163c37c}
Reverse-babyRe
so easy
根据字符串 error! 引用处一步一步往上找交叉引用的函数
应该是函数的主要逻辑的地方了
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
__int64 __fastcall sub_140007A80(int a1, __int64 a2)
{
char *v2; // rdi
__int64 i; // rcx
char v5[32]; // [rsp+0h] [rbp-40h] BYREF
char v6; // [rsp+40h] [rbp+0h] BYREF
DWORD dwProcessId; // [rsp+44h] [rbp+4h]
HANDLE v8; // [rsp+68h] [rbp+28h]
char Parameter[132]; // [rsp+90h] [rbp+50h] BYREF
int j; // [rsp+114h] [rbp+D4h]
HRSRC hResInfo; // [rsp+138h] [rbp+F8h]
size_t Size; // [rsp+154h] [rbp+114h]
HGLOBAL hResData; // [rsp+178h] [rbp+138h]
void *Src; // [rsp+198h] [rbp+158h]
void *v15; // [rsp+1B8h] [rbp+178h]
__int64 v16; // [rsp+1D8h] [rbp+198h]
__int64 v17; // [rsp+1F8h] [rbp+1B8h]
int k; // [rsp+214h] [rbp+1D4h]
__int64 v19; // [rsp+2E8h] [rbp+2A8h]
v2 = &v6;
for ( i = 130i64; i; --i )
{
*(_DWORD *)v2 = -858993460;
v2 += 4;
}
sub_1400012A8(&unk_1400140F4);
dwProcessId = GetCurrentProcessId();
v8 = OpenProcess(0x1FFFFFu, 0, dwProcessId);
if ( a1 != 2 )
exit(0);
for ( j = 0; ; ++j )
{
v19 = j;
if ( j >= strlen(*(const char **)(a2 + 8)) )
break;
Parameter[j] = *(_BYTE *)(*(_QWORD *)(a2 + 8) + j);
}
hResInfo = FindResourceW(0i64, (LPCWSTR)0x65, L"cod");
LODWORD(Size) = SizeofResource(0i64, hResInfo);
hResData = LoadResource(0i64, hResInfo);
Src = LockResource(hResData);
v15 = malloc((unsigned int)Size);
memcpy(v15, Src, (unsigned int)Size);
sub_140001087(v15);
v16 = qword_14000FC30(v8, 0i64, 874i64, 4096i64, 64);
qword_14000FC28(v8, v16, v15, 874i64, 0i64);
v17 = qword_14000FC18(v8, 0i64, 0i64, v16, Parameter, 0, 0i64);
Sleep(0x1F4u);
for ( k = 0; k < 44; ++k )
;
CreateThread(0i64, 0i64, (LPTHREAD_START_ROUTINE)StartAddress, Parameter, 0, 0i64);
Sleep(0x190u);
sub_140001253(v5, &unk_14000BEE0);
return 0i64;
}
直接看的话还不是很好看,我先修复下函数的名字
可以看注释
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
__int64 __fastcall sub_140007A80(int argv_value, char **argv)
{
char *v2; // rdi
__int64 i; // rcx
char v5[32]; // [rsp+0h] [rbp-40h] BYREF
char v6; // [rsp+40h] [rbp+0h] BYREF
DWORD dwProcessId; // [rsp+44h] [rbp+4h]
HANDLE v8; // [rsp+68h] [rbp+28h]
char Parameter[132]; // [rsp+90h] [rbp+50h] BYREF
int j; // [rsp+114h] [rbp+D4h]
HRSRC hResInfo; // [rsp+138h] [rbp+F8h]
size_t Size; // [rsp+154h] [rbp+114h]
HGLOBAL hResData; // [rsp+178h] [rbp+138h]
void *Src; // [rsp+198h] [rbp+158h]
void *data; // [rsp+1B8h] [rbp+178h]
__int64 v16; // [rsp+1D8h] [rbp+198h]
__int64 v17; // [rsp+1F8h] [rbp+1B8h]
int k; // [rsp+214h] [rbp+1D4h]
__int64 v19; // [rsp+2E8h] [rbp+2A8h]
v2 = &v6;
for ( i = 130i64; i; --i )
{
*v2 = -858993460;
v2 += 4;
}
sub_1400012A8(&unk_1400140F4); // 检测调试,需要给patch掉,直接进去把里面的代码改成 ret
dwProcessId = GetCurrentProcessId();
v8 = OpenProcess(0x1FFFFFu, 0, dwProcessId);
if ( argv_value != 2 ) // 必须有2个参数
exit(0);
for ( j = 0; ; ++j )
{
v19 = j;
if ( j >= strlen(argv[1]) )
break;
Parameter[j] = argv[1][j]; // 将第一个参数赋值给 Parameter
// bbre.exe flagstrings
}
hResInfo = FindResourceW(0i64, 0x65, L"cod");
LODWORD(Size) = SizeofResource(0i64, hResInfo);
hResData = LoadResource(0i64, hResInfo);
Src = LockResource(hResData);
data = malloc(Size);
memcpy(data, Src, Size);
Jmp_Xor_data(data); // 这里一个异或加解密的操作 长度是 874
v16 = qword_14000FC30(v8, 0i64, 874i64, 4096i64, 64);
qword_14000FC28(v8, v16, data, 874i64, 0i64);
v17 = qword_14000FC18(v8, 0i64, 0i64, v16, Parameter, 0, 0i64);// Parameter 只有在这个函数才被加密
Sleep(0x1F4u);
for ( k = 0; k < 44; ++k )
;
CreateThread(0i64, 0i64, StartAddress, Parameter, 0, 0i64);// startAddress 是一个检测flag的
Sleep(0x190u);
sub_140001253(v5, &unk_14000BEE0);
return 0i64;
}
原来还可以这样读资源文件
- Xor_data()
1
2
3
4
5
6
7
8
9
10
11
12
13
__int64 __fastcall Xor_data(char a1[])
{
__int64 result; // rax
int i; // [rsp+24h] [rbp+4h]
result = sub_1400012A8(&unk_1400140F4);
for ( i = 0; i < 874; ++i )
{
a1[i] ^= byte_14000F000[i % 4];
result = (unsigned int)(i + 1);
}
return result;
}
需要注意的是 byte_14000F000,
如果 程序处于调试状态他会修改 byte_14000F000,这里等会给它 patch 掉
- IsDebuggerPresent()
1
2
3
#返回值
如果当前进程在调试器上下文中运行,则返回值为非零。
如果当前进程未在调试器的上下文中运行,则返回值为零。
byte_14000F000 初始值是
18h, 57h, 68h, 64h
经过动态调试后 才发现执行完 Jmp_Xor_data() 后, data 是一堆代码
- 动态调试需要传参
直接去看 data,data里存的地址才是数据
如果说你看到 or [rcx+43F8ECh], al
就说明,初始的 byte_14000F000 还是被改了
这样的话,可以断点在异或解密的前一条直接,然后把 byte_14000F000 改回去
随便打个断点
直接给它改回去
然后继续运行动态解密完后我们在看下data
有些花指令,我们给它处理一下
花指令
出来完花指令后 快捷键p 创建函数 然后可以直接F5 看C 伪代码和里面我写好的注释
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
__int64 __fastcall sub_22777CDEDAD(char a1[])
{
char *v1; // rdi
__int64 i; // rcx
__int64 result; // rax
char v4; // [rsp+20h] [rbp+0h] BYREF
char v5[292]; // [rsp+30h] [rbp+10h] BYREF
unsigned int k; // [rsp+154h] [rbp+134h]
unsigned int v7; // [rsp+174h] [rbp+154h]
unsigned int v8; // [rsp+194h] [rbp+174h]
int v9; // [rsp+1B4h] [rbp+194h]
char v10[44]; // [rsp+1D8h] [rbp+1B8h] BYREF
unsigned int v11; // [rsp+204h] [rbp+1E4h]
char *__attribute__((__org_arrdim(0,0))) j; // [rsp+228h] [rbp+208h]
int v13; // [rsp+244h] [rbp+224h]
__int64 v14; // [rsp+3D8h] [rbp+3B8h]
v1 = &v4;
for ( i = 150i64; i; --i )
{
*v1 = -858993460;
v1 += 4;
}
memset(v5, 0, 0x101ui64);
qmemcpy(v10, "]Bb)", 4);
v10[4] = 3;
v10[5] = 54;
v10[6] = 71;
v10[7] = 65;
v10[8] = 21;
v10[9] = 54;
v11 = 0;
for ( j = a1; *j; ++j )
++v11;
for ( k = 0; k < 0x100; ++k )
v5[k] = k;
v8 = 0;
v7 = 0;
for ( k = 0; k < 0x100; ++k )
{
v9 = v5[k];
v7 = (v10[v8] + v9 + 2 * v7) % 0x100;
v5[k] = v5[v7];
v5[v7] = v9;
if ( ++v8 >= 0xA )
v8 = 0;
}
v8 = 0;
sub_22777CDEF9E(); // 没用,等会nop掉; 随便在 nop 处下个断点,来获取上面生成v5的值,用来给下面的解密
v7 = v8;
for ( k = 0; ; ++k )
{
result = v11;
if ( k >= v11 )
break;
v7 = (v8 + v7) % 0x100;
v8 = (v5[v7] + v8) % 0x100;
v9 = v5[v7];
v5[v7] = v5[v8];
v5[v8] = v9;
v13 = v5[(v5[v7] + v8 + v5[v8]) % 0x100];
a1[k] ^= v13; // 加密处,毫无疑问 a1 就是我们传入的flag
v14 = k;
a1[k] += k % 0xD;
}
return result;
}
nop 掉 call sub_22777CDEF9E
然后打断点,然后F9运行到这
F9 后,然后把这个int 3 也 nop 掉, 接下在上面的开头处 快捷键p ,然后f5 看C 伪代码
再把上面的 v5 给他提取出来
密文在Xor_data()函数里可以找到
然后写解密脚本
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
v5 = [
0x04, 0xFD, 0x67, 0xF4, 0x3F, 0x13, 0xC6, 0x86, 0x29, 0xAA,
0x89, 0x68, 0x93, 0x41, 0x6B, 0x9F, 0x95, 0x7C, 0x96, 0x87,
0x0C, 0x1C, 0x18, 0x7E, 0x23, 0x51, 0x2B, 0x72, 0x55, 0x94,
0x75, 0x3E, 0xFE, 0x00, 0x16, 0x30, 0x9B, 0x9C, 0xF6, 0x43,
0x5F, 0x69, 0x85, 0xE2, 0xE7, 0xAB, 0x7A, 0x5A, 0x0A, 0xA6,
0x81, 0x77, 0x17, 0x6C, 0xF2, 0x33, 0x6D, 0x35, 0x49, 0x0B,
0x61, 0x06, 0x34, 0xD7, 0x4B, 0x9E, 0xA3, 0x3C, 0xB5, 0x5C,
0x48, 0xB3, 0x05, 0xDC, 0xA7, 0x80, 0x71, 0x09, 0xAE, 0x28,
0x5B, 0xA8, 0xE6, 0x44, 0x14, 0xE3, 0x63, 0x4E, 0xF3, 0x1E,
0xC1, 0xDF, 0x26, 0x46, 0x07, 0x2F, 0xB1, 0x0D, 0xED, 0x6A,
0x19, 0xD1, 0xDE, 0x5E, 0x6F, 0x1D, 0x97, 0xC8, 0x66, 0xD6,
0x7B, 0xA0, 0x62, 0x3A, 0x40, 0xC5, 0x59, 0x1B, 0xCF, 0x83,
0x50, 0xC2, 0x8F, 0x58, 0xE5, 0xEA, 0x84, 0x38, 0x11, 0xC9,
0x37, 0x2E, 0xCE, 0xB8, 0x10, 0x90, 0xD9, 0x98, 0x45, 0xCD,
0xD5, 0x03, 0x57, 0x99, 0x25, 0x08, 0x74, 0xDD, 0x7D, 0xD4,
0x24, 0x12, 0x22, 0xB9, 0xBE, 0x0E, 0x4A, 0x20, 0xAF, 0xB4,
0x4F, 0x21, 0xF5, 0xCA, 0xEB, 0x0F, 0x9D, 0x36, 0xD0, 0xC3,
0x91, 0x3B, 0x2C, 0xEE, 0x1F, 0xE0, 0xB7, 0x70, 0xA2, 0x56,
0x9A, 0xB2, 0xA1, 0x60, 0xC0, 0xCC, 0xAC, 0x7F, 0xF9, 0x8A,
0xBD, 0xCB, 0x8C, 0xB6, 0x8D, 0xDB, 0x39, 0xFC, 0xD3, 0x88,
0xDA, 0x4D, 0x78, 0xFB, 0xBF, 0x1A, 0x02, 0x76, 0xBC, 0x47,
0x64, 0xE4, 0xA4, 0x4C, 0x15, 0x5D, 0xD2, 0xA5, 0x2D, 0xAD,
0xF7, 0xBA, 0x54, 0xF0, 0x8E, 0xA9, 0xEC, 0x52, 0x27, 0x42,
0xD8, 0xBB, 0xB0, 0x53, 0x31, 0x82, 0x8B, 0xEF, 0xC7, 0xF8,
0x32, 0xF1, 0xE9, 0xE8, 0x01, 0xFF, 0xC4, 0xFA, 0xE1, 0x65,
0x79, 0x73, 0x92, 0x6E, 0x2A, 0x3D, 0x00
]
flag = [0] * 45
flag[0] = 0xF7
flag[1] = 0x2E
flag[2] = 0x34
flag[3] = 0xF0
flag[4] = 0x72
flag[5] = 0xCF
flag[6] = 94
flag[7] = 10
flag[8] = 0xBB
flag[9] = 0xEC
flag[10] = 0xB1
flag[11] = 0x2B
flag[12] = 0x70
flag[13] = 0x88
flag[14] = 0x88
flag[15] = 0xED
flag[16] = 0x46
flag[17] = 0x38
flag[18] = 0xDB
flag[19] = 0xDA
flag[20] = 0x6C
flag[21] = 0xBD
flag[22] = 0xD4
flag[23] = 6
flag[24] = 0x77
flag[25] = 0xF2
flag[26] = 0xCF
flag[27] = 0x56
flag[28] = 0x88
flag[29] = 0xC6
flag[30] = 0x31
flag[31] = 0xD2
flag[32] = 0xB7
flag[33] = 90
flag[34] = 0xC1
flag[35] = 0x42
flag[36] = 0xB0
flag[37] = 0xF4
flag[38] = 72
flag[39] = 0x37
flag[40] = 0xF5
flag[41] = 0x2C
flag[42] = 245
flag[43] = 88
v8 = 0
v7 = 0
for k in range(44):
v7 = (v8 + v7) % 0x100
v8 = (v5[v7] + v8) % 0x100
v9 = v5[v7]
v5[v7] = v5[v8]
v5[v8] = v9
v13 = v5[(v5[v7] + v8 + v5[v8]) % 0x100]
flag[k] -= k % 0xD
flag[k] ^= v13
flag[k] = flag[k] % 128
print(flag)
print(''.join(map(chr,flag)))
1
2
[68, 65, 83, 67, 84, 70, 123, 48, 51, 52, 52, 54, 99, 50, 99, 45, 100, 102, 102, 55, 45, 49, 49, 101, 100, 45, 57, 50, 56, 53, 45, 53, 52, 101, 49, 97, 100, 57, 56, 100, 54, 52, 57, 125, 0]
DASCTF{03446c2c-dff7-11ed-9285-54e1ad98d649}
Reverse-ez_exe
一共三个文件
ez_exe.exe 是 python3.11 打包的
用 python3.11 执行 pyinstxtractor.py 去解包
再用 Pycdc 去还原 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
37
38
39
40
41
42
43
44
45
46
47
48
49
#=[09:17:03]-➤ /opt/reverse/Pycdc ez_py.pyc
# Source Generated with Decompyle++
# File: ez_py.pyc (Python 3.11)
import ctypes
from time import *
from ctypes import *
from ctypes import wintypes
from hashlib import md5
class _STARTUPINFO(Structure):
_fields_ = [
('cb', c_ulong),
('lpReserved', c_char_p),
('lpDesktop', c_char_p),
('lpTitle', c_char_p),
('dwX', c_ulong),
('dwY', c_ulong),
('dwXSize', c_ulong),
('dwYSize', c_ulong),
('dwXCountChars', c_ulong),
('dwYCountChars', c_ulong),
('dwFillAttribute', c_ulong),
('dwFlags', c_ulong),
('wShowWindow', c_ushort),
('cbReserved2', c_ushort),
('lpReserved2', c_char_p),
('hStdInput', c_ulong),
('hStdOutput', c_ulong),
('hStdError', c_ulong)]
class _PROCESS_INFORMATION(Structure):
_fields_ = [
('hProcess', c_void_p),
('hThread', c_void_p),
('dwProcessId', c_ulong),
('dwThreadId', c_ulong)]
StartupInfo = _STARTUPINFO()
ProcessInfo = _PROCESS_INFORMATION()
key1 = bytes(md5(b'bin1bin1bin1').hexdigest().encode())
file = open('bin1', 'rb').read()
arr = range(len(file))()
open('bin1', 'wb').write(bytes(arr))
sleep(0)
bet = ctypes.windll.kernel32.CreateProcessA(b'bin1', ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), byref(StartupInfo), byref(ProcessInfo))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ProcessInfo.hProcess), ctypes.c_int(-1))
open('bin1', 'wb').write(file)
直接看的话,好像有点奇怪,key1 都没有调用的地方
主要还是解密了bin1, 用 python3.11 运行 ez_py.pyc,会生成一个 gmon.out
运行后,bin1 会从密文状态解密成一个 PE32 可执行程序,
HeD 打开 这个 ez_py.pyc 然后将 bin1 替换成bin2, 然后再去运行这个 ez_py.pyc
也是意料之中成长解密了bin2也运行了
接下来用 IDA Pro 分析 bin2
一个 btea 加密
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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int flag[11]; // [esp+10h] [ebp-B8h]
int key[4]; // [esp+3Ch] [ebp-8Ch] BYREF
int v6[12]; // [esp+4Ch] [ebp-7Ch] BYREF
char Str[50]; // [esp+7Eh] [ebp-4Ah] BYREF
int k; // [esp+B0h] [ebp-18h]
int j; // [esp+B4h] [ebp-14h]
size_t i; // [esp+B8h] [ebp-10h]
char *v11; // [esp+BCh] [ebp-Ch]
__main();
printf("please input your flag:\n");
scanf("%s", Str);
if ( strlen(Str) != 44 )
{
MessageBoxA(0, "worng length!", &Caption, 0);
exit(0);
}
v11 = Str;
for ( i = 0; strlen(Str) >> 2 > i; ++i )
{
v6[i] = *(_DWORD *)v11;
v11 += 4;
}
key[0] = 0x4B5F;
key[1] = 0xDEAD;
key[2] = 0x11ED;
key[3] = 0xB3CC;
btea((unsigned int *)v6, 11, key); // 加密
for ( j = 0; j <= 10; ++j )
;
flag[0] = 0xCC45699D;
flag[1] = 0x683D5352;
flag[2] = 0xB8BB71A0;
flag[3] = 0xD3817AD;
flag[4] = 0x7547E79E;
flag[5] = 0x4BDD8C7C;
flag[6] = 0x95E25A81;
flag[7] = 0xC4525103;
flag[8] = 0x7049B46F;
flag[9] = 0x5417F77C;
flag[10] = 0x65567138;
for ( k = 0; k <= 10; ++k )
{
if ( flag[k] != v6[k] )
{
MessageBoxA(0, "error!", &Caption, 0);
exit(0);
}
}
MessageBoxA(0, "right!", &Caption, 0);
return 0;
}
- btea
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
int __cdecl btea(unsigned int a1[], int a2, int a3[])
{
unsigned int *v3; // eax
int *v4; // eax
int result; // eax
unsigned int *v6; // eax
int v7; // [esp+8h] [ebp-20h]
int v8; // [esp+8h] [ebp-20h]
int v9; // [esp+Ch] [ebp-1Ch]
int v10; // [esp+Ch] [ebp-1Ch]
unsigned int j; // [esp+10h] [ebp-18h]
int i; // [esp+10h] [ebp-18h]
unsigned int v13; // [esp+14h] [ebp-14h]
unsigned int v14; // [esp+14h] [ebp-14h]
unsigned int v15; // [esp+18h] [ebp-10h]
unsigned int v16; // [esp+1Ch] [ebp-Ch]
int a2a; // [esp+34h] [ebp+Ch]
if ( a2 <= 1 )
{
if ( a2 < -1 )
{
a2a = -a2;
v10 = 52 / a2a + 6;
v14 = 2033695134 * v10;
v16 = *a1;
do
{
v8 = (v14 >> 2) & 3;
for ( i = a2a - 2; i; --i )
{
v6 = &a1[i];
*v6 -= ((v16 ^ v14) + (a1[i - 1] ^ a3[v8 ^ i & 3])) ^ (((4 * v16) ^ (a1[i - 1] >> 5))
+ ((v16 >> 3) ^ (16 * a1[i - 1])));
v16 = *v6;
}
*a1 -= (((4 * v16) ^ (a1[a2a - 1] >> 5)) + ((v16 >> 3) ^ (16 * a1[a2a - 1]))) ^ ((v16 ^ v14)
+ (a1[a2a - 1] ^ a3[v8]));
result = *a1;
v16 = *a1;
v14 -= 2033695134;
--v10;
}
while ( v10 );
}
}
else
{
v9 = 52 / a2;
v13 = 0;
v15 = a1[a2 - 1];
do
{
v13 += 0x7937B99E;
v7 = (v13 >> 2) & 3;
for ( j = 0; j < a2 - 1; ++j )
{
v3 = &a1[j];
*v3 += ((a1[j + 1] ^ v13) + (v15 ^ a3[v7 ^ j & 3])) ^ (((4 * a1[j + 1]) ^ (v15 >> 5))
+ ((a1[j + 1] >> 3) ^ (16 * v15)));
v15 = *v3;
}
v4 = (int *)&a1[a2 - 1];
*v4 += ((*a1 ^ v13) + (v15 ^ a3[v7 ^ j & 3])) ^ (((4 * *a1) ^ (v15 >> 5)) + ((*a1 >> 3) ^ (16 * v15)));
result = *v4;
v15 = result;
--v9;
}
while ( v9 );
}
return result;
}
baidu 到了俩解密的,需要修改部分代码,也简单,改完解密直接flag
- btea解密脚本1
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MX (z>>5^y<<2) + (y>>3^z<<4)^(sum^y) + (k[p&3^e]^z);
//long btea(long* v, long n, long* k) {
int btea(int* v, int n, int* k) {
unsigned long z=v[n-1], y=v[0], sum=0, e, DELTA=0x7937B99E;
long p, q ;
if (n > 1) { /* Coding Part */
//q = 6 + 52/n;
q = 52/n;
while (q-- > 0) {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) y = v[p+1], z = v[p] += MX;
y = v[0];
z = v[n-1] += MX;
}
return 0 ;
} else if (n < -1) { /* Decoding Part */
n = -n;
//q = 6 + 52/n;
q = 52/n;
sum = q*DELTA ;
while (sum != 0) {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) z = v[p-1], y = v[p] -= MX;
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}
return 0;
}
return 1;
}
int main(int argc, char const *argv[])
{
int key[4]={0};
key[0] = 0x4B5F;
key[1] = 0xDEAD;
key[2] = 0x11ED;
key[3] = 0xB3CC;
int flag[11] = {0};
flag[0] = 0xCC45699D;
flag[1] = 0x683D5352;
flag[2] = 0xB8BB71A0;
flag[3] = 0xD3817AD;
flag[4] = 0x7547E79E;
flag[5] = 0x4BDD8C7C;
flag[6] = 0x95E25A81;
flag[7] = 0xC4525103;
flag[8] = 0x7049B46F;
flag[9] = 0x5417F77C;
flag[10] = 0x65567138;
btea(flag,-11,key);
printf("%s\n",flag);
return 0;
}
- btea解密脚本2
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
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x7937B99E
// #define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) { /* Coding Part */
rounds = 52/n;
//rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) {
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
} while (--rounds);
} else if (n < -1) { /* Decoding Part */
n = -n;
rounds = 52/n;
//rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) {
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
} while ((sum -= DELTA) != 0);
}
}
int main()
{
//uint32_t const key[4]={0x01234567,0x89ABCDEF,0xFEDCBA98,0x76543210};
uint32_t key[4] = {0};
key[0] = 0x4B5F;
key[1] = 0xDEAD;
key[2] = 0x11ED;
key[3] = 0xB3CC;
//uint32_t data[2]={0x12345678,0x87654321};
uint32_t data[11];
data[0] = 0xCC45699D;
data[1] = 0x683D5352;
data[2] = 0xB8BB71A0;
data[3] = 0x0D3817AD;
data[4] = 0x7547E79E;
data[5] = 0x4BDD8C7C;
data[6] = 0x95E25A81;
data[7] = 0xC4525103;
data[8] = 0x7049B46F;
data[9] = 0x5417F77C;
data[10]= 0x65567138;
uint32_t *sent=data;
//btea(sent,1,key);
btea(sent,-11,key);
//printf("%s\n\n",data);
for (int i = 0; i < 44; i++){
printf("%c",*((char *)data +i) & 0xff);
}
return 0;
}
1
DASCTF{7eb20cb2-deac-11ed-ae42-94085339ce84}
Reverse-cap
capture what?
- 主要逻辑代码
- 大概就是获取屏幕的图片 bmp 然后加密保存为cap.bin
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
__int64 __fastcall sub_7FF651DA1030(HWND hWnd)
{
HBITMAP v2; // r14
HDC hdcSrc; // r13
HDC DC; // rsi
HDC CompatibleDC; // r15
int hSrc; // ebx
int wSrc; // eax
HBITMAP CompatibleBitmap; // rax
signed int v9; // ebx
HANDLE FileW; // rax
void *v11; // r12
signed int v12; // r10d
_BYTE *v13; // r9
int v14; // ecx
int v15; // edx
void *lpBuffer; // [rsp+60h] [rbp-59h]
HGLOBAL hMem; // [rsp+68h] [rbp-51h]
struct tagRECT Rect; // [rsp+70h] [rbp-49h] BYREF
struct tagBITMAPINFO bmi; // [rsp+80h] [rbp-39h] BYREF
char v21; // [rsp+ACh] [rbp-Dh]
char v22; // [rsp+ADh] [rbp-Ch]
char v23; // [rsp+AEh] [rbp-Bh]
char v24; // [rsp+AFh] [rbp-Ah]
char v25; // [rsp+B0h] [rbp-9h]
char v26; // [rsp+B1h] [rbp-8h]
int v27; // [rsp+B2h] [rbp-7h]
DWORD NumberOfBytesWritten; // [rsp+B8h] [rbp-1h] BYREF
char pv[4]; // [rsp+C0h] [rbp+7h] BYREF
LONG v30; // [rsp+C4h] [rbp+Bh]
UINT cLines; // [rsp+C8h] [rbp+Fh]
NumberOfBytesWritten = 0;
v2 = 0i64;
hdcSrc = GetDC(0i64);
DC = GetDC(hWnd); // GetDC函数为一个指定窗口的客户端区域或者整个屏幕从一个设备上下文(DC)中提取一个句柄
CompatibleDC = CreateCompatibleDC(DC);
if ( CompatibleDC )
{
GetClientRect(hWnd, &Rect);
SetStretchBltMode(DC, 4);
hSrc = GetSystemMetrics(1);
wSrc = GetSystemMetrics(0);
if ( StretchBlt(DC, 0, 0, Rect.right, Rect.bottom, hdcSrc, 0, 0, wSrc, hSrc, 0xCC0020u) )
{
CompatibleBitmap = CreateCompatibleBitmap(DC, Rect.right - Rect.left, Rect.bottom - Rect.top);// CreateCompatibleBitmap函数创建的位图的颜色格式与hdc参数标识的设备的颜色格式匹配
v2 = CompatibleBitmap;
if ( CompatibleBitmap )
{
SelectObject(CompatibleDC, CompatibleBitmap);
if ( BitBlt(CompatibleDC, 0, 0, Rect.right - Rect.left, Rect.bottom - Rect.top, DC, 0, 0, 0xCC0020u) )
{
GetObjectW(v2, 32, pv);
bmi.bmiHeader.biWidth = v30;
bmi.bmiHeader.biHeight = cLines;
bmi.bmiHeader.biSize = 0x28;
*&bmi.bmiHeader.biPlanes = 2097153i64;
memset(&bmi.bmiHeader.biSizeImage, 0, 20);
v9 = 4 * cLines * ((32 * v30 + 31) / 32);
hMem = GlobalAlloc(0x42u, v9);
lpBuffer = GlobalLock(hMem);
GetDIBits(DC, v2, 0, cLines, lpBuffer, &bmi, 0);
FileW = CreateFileW(L"cap.bin", 0x40000000u, 0, 0i64, 2u, 0x80u, 0i64);
v23 ^= 0x64u;
v24 ^= 0x61u;
v11 = FileW;
v25 ^= 0x73u;
v26 ^= 0x63u;
bmi.bmiHeader.biSize ^= 0x79625F63u;
bmi.bmiHeader.biWidth ^= 0x7361645Fu;
bmi.bmiHeader.biHeight ^= 0x65667463u;
*&bmi.bmiHeader.biPlanes ^= 7017839094296175470ui64;
bmi.bmiColors[0].rgbReserved = ((v9 + 54) >> 8) ^ 0x62;
v21 = ((v9 + 54) >> 16) ^ 0x79;
v22 = ((v9 + 54) >> 24) ^ 0x5F;
v27 = 1852139074;
qmemcpy(bmi.bmiColors, ",.", 2);
bmi.bmiColors[0].rgbRed = (v9 + 54) ^ 0x5F;
v12 = 0;
bmi.bmiHeader.biSizeImage ^= 0x66746373u;
bmi.bmiHeader.biXPelsPerMeter ^= 0x5F636E65u;
bmi.bmiHeader.biYPelsPerMeter ^= 0x645F7962u;
bmi.bmiHeader.biClrUsed ^= 0x74637361u;
bmi.bmiHeader.biClrImportant ^= 0x636E6566u;
if ( v9 > 0 )
{
v13 = lpBuffer;
do
{
v14 = v12 + 3;
v15 = (1321528399i64 * (v12 + 3)) >> 32;
++v12;
*v13++ ^= key[v14 - 13 * ((v15 >> 31) + (v15 >> 2))];
}
while ( v12 < v9 );
}
WriteFile(FileW, bmi.bmiColors, 0xEu, &NumberOfBytesWritten, 0i64);
WriteFile(v11, &bmi, 0x28u, &NumberOfBytesWritten, 0i64);
WriteFile(v11, lpBuffer, v9, &NumberOfBytesWritten, 0i64);
GlobalUnlock(hMem);
GlobalFree(hMem);
CloseHandle(v11);
}
else
{
MessageBoxW(hWnd, L"BitBlt has failed", L"Failed", 0);
}
}
else
{
MessageBoxW(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", 0);
}
}
else
{
MessageBoxW(hWnd, L"StretchBlt has failed", L"Failed", 0);
}
}
else
{
MessageBoxW(hWnd, L"CreateCompatibleDC has failed", L"Failed", 0);
}
DeleteObject(v2);
DeleteObject(CompatibleDC);
ReleaseDC(0i64, hdcSrc);
ReleaseDC(hWnd, DC);
return 0i64;
}
最后写入的lpBuffer也就是bmp 图像的数据段
v3 指向的地址也就是 plBuffer
- 接下来就是找到v3 是和谁异或的,取得是key[]的值。动态分析一下把和 v13 异或的值取出来
1
*v13++ ^= key[v14 - 13 * ((v15 >> 31) + (v15 >> 2))];
- 断点脚本
1
2
eax = get_reg_value('eax')
print(chr(eax),end='')
基本就是按照这个循环去异或
1
_by_dasctfenc
- 先拿一个正常的BMP 看一下结构
现在除了前0x36不知道是啥,但是后面的信息我们已经清楚加密流程了
- 解密
1
2
3
4
5
6
7
8
9
10
11
key = list(b'_by_dasctf')
f1 = open('C:/Users/GameG/Downloads/cap/cap.bin','rb').read()[0x36:]
f2 = open('C:/Users/GameG/Downloads/cap/data.bmp','wb')
f1 = bytearray(f1)
for i in range(len(f1)):
f1[i] = f1[i] ^ key[i % len(key)]
f2.write(bytes([0]*0x36))
f2.write(bytes(f1))
f2.close()
- 结果,考虑到这里的数据是异或加密的,那前面的也可以尝试解一下
- 正常的bmp 这个地方都是00 00 , 但加密后 是 我们的 密钥 enc_by_dasctf ,任何数异或0都是它本身,正好呢,0x36位置异或的是 _ 正好和前面的 enc 衔接上,大概前面也是异或,只是异或key的顺序不同
1
2
3
4
5
6
7
8
9
10
11
key = list(b'nc_by_dasctfe')
f1 = open('C:/Users/GameG/Downloads/cap/cap.bin','rb').read()
f2 = open('C:/Users/GameG/Downloads/cap/data.bmp','wb')
f1 = bytearray(f1)
for i in range(len(f1)):
f1[i] = f1[i] ^ key[i % len(key)]
f2.write(bytes(f1))
f2.close()
得到 原始图片
Reverse-unsym
看到字符串里有 go 的特征,先用脚本恢复一下go符号https://github.com/renshareck/IDAGolangHelper_SupportGo1.20
用 Findcrypt 找到了一些加密算法 AES
NoNo~~~~~~~~~~~