DASCTF2023二进制专项Reverse复现

j1ya Lv5

Reverse

careful

一开始直接逆向得到第一个字符串

交叉引用发现另一个域名,且在dasctf之后

下断点步入gethostbyname之后也确实能看到

实际上存在内联hook,hook这个API函数以修改传入的参数,然后调用真正的API

babyre

flag输入由参数argv传递,后面读取名称为cod的资源

用 resource hacker 把资源复制下来

也可以IDA加载exe时设置Load Resource,大小为874字节就能看到要加载的资源

循环异或四位

但是有反调试,直接静态分析

1
2
3
4
5
6
7
8
arr = [0x18, 0x57, 0x68, 0x64]
with open('COD101.bin', 'rb') as f:
b = f.read()
b = bytearray(b)
for i in range(len(b)):
b[i] = b[i] ^ arr[i % 4]
with open('dump', 'wb') as f:
f.write(b)

花指令1d到28全部nop

然后把几处call到retn全部nop

img

魔改rc4

rc4魔改

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
def rc4(data, key):
S = list(range(256))
out = []

v7 = 0
v8 = 0

for i in range(256):
v9 = S[i]
v7 = (key[v8] + v9 + 2 * v7) & 0xFF
S[i] = S[v7]
S[v7] = v9
v8 += 1
if v8 >= 10:
v8 = 0

j2 = 0
i3 = 0
cnt = 0

for char in data:
# 逆向的时候先减
char = (char - (cnt % 0xD)) & 0xFF
cnt += 1

i3 = (i3 + j2) & 0xFF
j2 = (S[i3] + j2) & 0xFF

S[i3], S[j2] = S[j2], S[i3]

rnd = S[(S[i3] + j2 + S[j2]) & 0xFF]
out.append(char ^ rnd)

return bytes(out)

data = bytes([
0xF7, 0x2E, 0x34, 0xF0, 0x72, 0xCF, 0x5E, 0x0A,
0xBB, 0xEC, 0xB1, 0x2B, 0x70, 0x88, 0x88, 0xED,
0x46, 0x38, 0xDB, 0xDA, 0x6C, 0xBD, 0xD4, 0x06,
0x77, 0xF2, 0xCF, 0x56, 0x88, 0xC6, 0x31, 0xD2,
0xB7, 0x5A, 0xC1, 0x42, 0xB0, 0xF4, 0x48, 0x37,
0xF5, 0x2C, 0xF5, 0x58
])

key = bytes([93, 66, 98, 41, 3, 54, 71, 65, 21, 54])

decrypted = rc4(data, key)
print(decrypted)
#DASCTF{03446c2c-dff7-11ed-9285-54e1ad98d649}

也可以调试,下断点到sleep之前

查看v16的内容,作为地址访问数据,可以看到shellcode

ez_exe

exe反编译得到pyc,但是代码逻辑不全

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
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: 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)

对应python去运行pyc提示decrypt bin2

此时去看bin1已经解密,运行就得到上面的字符串,考虑把pyc里的bin1改成bin2,一共五处

明显的xxtea,直接套模板

只有轮数和delta有魔改

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;
}

DASCTF{7eb20cb2-deac-11ed-ae42-94085339ce84}

cap

获取BMP图片然后加密保存为cap.bin,后面有异或操作,可以动调看密钥或者直接去看加密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
129
__int64 __fastcall sub_140001030(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);
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);
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 = 40;
*(_QWORD *)&bmi.bmiHeader.biPlanes = 2097153i64;
memset(&bmi.bmiHeader.biSizeImage, 0, 20);
v9 = 4 * cLines * ((32 * v30 + 31) / 32);
hMem = GlobalAlloc(0x42u, (unsigned int)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;
*(_QWORD *)&bmi.bmiHeader.biPlanes ^= 0x61645F79625F636Eui64;
bmi.bmiColors[0].rgbReserved = ((unsigned __int16)(v9 + 54) >> 8) ^ 0x62;
v21 = ((unsigned int)(v9 + 54) >> 16) ^ 0x79;
v22 = ((unsigned int)(v9 + 54) >> 24) ^ 0x5F;
v27 = 1852139074;
bmi.bmiColors[0].rgbGreen = 46;
bmi.bmiColors[0].rgbBlue = 44;
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 = (unsigned __int64)(1321528399i64 * (v12 + 3)) >> 32;
++v12;
*v13++ ^= aEncByDasctf[v14 - 13 * (((unsigned int)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;
}

bmp文件头和加密字节前两文异或,就是密钥的二三位

根据格式后面位信息头有部分是0,异或密钥刚好就等于密钥

bin文件里看到一些enc_by_das,那大概率就是循环异或

1
2
3
4
5
6
7
key = "enc_by_dasctf"
with open('cap.bin', 'rb') as f:
s = bytearray(f.read())
for i in range(len(s)):
s[i] ^= ord(key[(i+1) % len(key)])
with open('flag.bmp', 'wb') as f:
f.write(s)

直接就能得到图片

unsym

go写的程序,搜索main_main函数

exp函数最容易想到的就是RSA算法,v238 作为底数,v247 作为指数

模数n,考虑用yafu分解

密文c

e为0x10001

1
2
3
4
5
6
7
8
9
10
11
12
13
import gmpy2
from Crypto.Util.number import long_to_bytes

n = 0x1d884d54d21694ccd120f145c8344b729b301e782c69a8f3073325b9c5
p = 37636318457745167234140808130156739
q = 21154904887215748949280410616478423
c = 0xfad53ce897d2c26f8cad910417fbdd1f0f9a18f6c1748faca10299dc8
e = 0x10001
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
# E@sy_RSA_enc7ypt

说明解出来的是key

aes_cbc

最后保存为加密bin文件

只设置key,iv随机

1
2
3
4
5
6
7
8
from Crypto.Cipher import AES

key = b"E@sy_RSA_enc7ypt"
aes=AES.new(key,AES.MODE_CBC)
c = open("encrypted.bin","rb").read()
print(c)
m = aes.decrypt(c)
open("dec.dump","wb").write(m)

动调发现key和iv一样,也能得到结果

1
2
3
4
5
6
7
8
9
from Crypto.Cipher import AES
password = b'E@sy_RSA_enc7ypt'
iv = b'E@sy_RSA_enc7ypt'
with open('encrypted.bin','rb') as f:
en_text = f.read()
aes = AES.new(password, AES.MODE_CBC, iv)
de_text = aes.decrypt(en_text)
with open('decrypt.exe','wb') as f:
f.write(de_text)
  • 标题: DASCTF2023二进制专项Reverse复现
  • 作者: j1ya
  • 创建于 : 2023-08-13 21:40:17
  • 更新于 : 2026-09-18 10:37:38
  • 链接: https://redefine.ohevan.com/2023/08/13/DASCTF2023二进制专项Reverse复现/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
DASCTF2023二进制专项Reverse复现