das四月

Crackme

0x01

打开程序,是MFC写的,用XSPY找到主窗口的响应函数

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
int __thiscall sub_AA31E0(int this)
{
const void *v1; // eax
const void *v2; // eax
int result; // eax
unsigned int Size; // [esp+18h] [ebp-230h]
size_t pdwDataLen; // [esp+20h] [ebp-228h] BYREF
void *Buf1; // [esp+24h] [ebp-224h] BYREF
const void *v8; // [esp+28h] [ebp-220h] BYREF
BYTE *v9; // [esp+2Ch] [ebp-21Ch] BYREF
size_t dwDataLen; // [esp+30h] [ebp-218h] BYREF
size_t v11; // [esp+34h] [ebp-214h] BYREF
DWORD v12; // [esp+38h] [ebp-210h] BYREF
BYTE flag[260]; // [esp+3Ch] [ebp-20Ch] BYREF
BYTE key[260]; // [esp+140h] [ebp-108h] BYREF

CWnd::UpdateData((CWnd *)this, 1);
memset(key, 0, sizeof(key));
memset(flag, 0, sizeof(flag));
Size = sub_AA3E70(this + 216);
pdwDataLen = sub_AA3E70(this + 212);
dwDataLen = 0;
v11 = 0;
v12 = 0;
v1 = (const void *)sub_AA2590(Size);
memmove(key, v1, Size);
v2 = (const void *)sub_AA2590(pdwDataLen);
memmove(flag, v2, pdwDataLen);
if ( Size != 8 && pdwDataLen != 32 )
return wrong((CWnd *)this);
sub_AA3510(key, Size >> 1, 0x8003u, (int)&Buf1, (int)&dwDataLen);
sub_AA3510(&key[4], Size >> 1, 0x8004u, (int)&v8, (int)&v11);
sub_AA3510(key, Size, 0x8003u, (int)&v9, (int)&v12);
memcmp(Buf1, (const void *)(this + 220), dwDataLen);
if ( memcmp(v8, (const void *)(this + 480), v11) )
return wrong((CWnd *)this);
sub_AA36E0(v9, v12, flag, &pdwDataLen, 0x104u);
if ( !memcmp(flag, (const void *)(this + 740), pdwDataLen) )
result = sucess((CWnd *)this);
else
result = wrong((CWnd *)this);
return result;
}

大概流程就是,对输入的key分四位分别加密,然后进行判断,再用整个加密后的key加密flag,最后进行比较。

0x02

然后就是分析一下sub_AA3510和sub_AA36E0两个函数了,里面用的都是API,查了一下是wincrypt.h的函数

1
2
3
sub_AA3510(key, Size >> 1, 0x8003u, (int)&Buf1, (int)&dwDataLen);
sub_AA3510(&key[4], Size >> 1, 0x8004u, (int)&v8, (int)&v11);
sub_AA3510(key, Size, 0x8003u, (int)&v9, (int)&v12);

0x8003u是md5,0x8004u是sha1

对key的前四位md5加密生成buf1,后四位sha1生成V8

再对整个key进行md5生成v9

1
sub_AA36E0(v9, v12, flag, &pdwDataLen, 0x104u);

这个函数大概是个AES,只要有v9的值和之后比较的密钥,就能解出flag

0x03

然后就是找到密钥了,但是密钥是动态的,ida一直断不在里面,怀疑有反调试,但是跟了跟也没跟出来

直接od跑,strongod直接断在里面了,找到密钥解完AES,flag就出了

IAT_HOOK

原理

修改IAT表中导入函数的地址,实现在调用函数时执行自己的代码

步骤

1.获取目标函数的地址,获取待Hook模块输入表的起始地址

柏鹭杯

babygo

go语言写的程序,先恢复一下符号

分析main函数

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
void __cdecl main_main()
{
_OWORD *v0; // rax
__int64 v1; // [rsp+10h] [rbp-1C0h]
int v2; // [rsp+10h] [rbp-1C0h]
_OWORD *v3; // [rsp+18h] [rbp-1B8h]
__int64 v4; // [rsp+18h] [rbp-1B8h]
__int128 v5; // [rsp+28h] [rbp-1A8h]
_QWORD *v6; // [rsp+30h] [rbp-1A0h]
_QWORD *v7; // [rsp+30h] [rbp-1A0h]
__int128 v8; // [rsp+38h] [rbp-198h]
__int64 v9; // [rsp+48h] [rbp-188h]
_BYTE v10[65]; // [rsp+77h] [rbp-159h] BYREF
__int64 v11; // [rsp+B8h] [rbp-118h]
_OWORD *v12; // [rsp+C0h] [rbp-110h]
__int128 v13; // [rsp+C8h] [rbp-108h] BYREF
__int128 v14; // [rsp+D8h] [rbp-F8h]
__int128 v15; // [rsp+E8h] [rbp-E8h]
char v16; // [rsp+F8h] [rbp-D8h] BYREF

while ( (unsigned __int64)&v10[25] <= *(_QWORD *)(*(_QWORD *)NtCurrentTeb()->NtTib.ArbitraryUserPointer + 16LL) )
runtime_morestack_noctxt();
if ( !argc )
runtime_panicSliceB();
if ( argc - 1 < 2 )
{
runtime_printlock();
runtime_printstring((__int64)"incorrect argCount\n", 19LL);
runtime_printunlock();
}
else // 命令行传参
{
*(_QWORD *)&v5 = runtime_newobject((__int64)" ");
v12 = v3;
qmemcpy(v10, "does your parser support the latest version of go", 49);
crypto_sha256_Sum256((__int64)v10, 49LL, 49LL);// 固定加密
v0 = v12;
*v12 = v5;
v0[1] = v8;
if ( (unsigned __int64)argc <= 1 )
runtime_panicIndex(v1, v4);
if ( (unsigned __int64)argc <= 2 )
runtime_panicIndex(v1, v4);
*(_QWORD *)&v10[49] = *(_QWORD *)(qword_D5B8A0 + 16);
*(_QWORD *)&v10[57] = *(_QWORD *)(qword_D5B8A0 + 32);
v13 = 0LL;
v14 = 0LL;
v15 = 0LL;
((void (*)(void))duffzero)(); // 意义不明
*(_QWORD *)&v14 = &v16;
runtime_fastrand(v1);
HIDWORD(v13) = v2;
runtime_mapassign_faststr((__int64)"\b", (__int64)&v13, (__int64)&unk_CBCE97, 1LL, *((__int64 *)&v5 + 1));
if ( dword_D9E7B0 )
runtime_gcWriteBarrier();
else
*v6 = &encrypt; // 重点
runtime_mapassign_faststr((__int64)"\b", (__int64)&v13, (__int64)&unk_CBCE96, 1LL, (__int64)v6);
if ( dword_D9E7B0 )
runtime_gcWriteBarrier();
else
*v7 = decrypt;
runtime_mapaccess1_faststr((__int64)"\b", (__int64)&v13, (__int64)&unk_CBCE97, 1LL);
(*(void (__golang **)(_OWORD *))*v7)(v12);
if ( v9 )
{
(*(void (__golang **)())(v9 + 24))();
v11 = 32LL;
runtime_printlock();
runtime_printstring(v11, 32LL);
runtime_printnl();
runtime_printunlock();
}
}
}

发现程序需要传两个参数

先都传123动态跑

跑到最后弹出没有123这个文件

知道要传个文件进去

正好有个flag.txt

传进去试试

跑完后得到一个123文件(第二个传进去的参数)

打开应该是解密后的flag

1
2
3
4
5
6
7
O*******   JUNK AAAABBBBCCCCDDDD   *******O


flag{ISEC-42115cad00f8c4a0495bffa97d2ca3a8}


O******* JUNK EEEEFFFFGGGGHHHH *******OC鯢??p~簁昔?9针漒畅yV?

babypython

python打包的exe

用pyinstxtractor解包后,还原pyc

1
2
3
4
5
6
7
8
9
10
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.8.6 (default, Sep 25 2020, 09:36:53)
# [GCC 10.2.0]
# Embedded file name: baby_python\baby.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
from baby_python.baby_core import main
if __name__ == '__main__':
main()

只有一个调用,东西都在baby_python.baby_core里面

在exe的解包中找到baby_python.baby_core.pyc.encrypted

pyz加密,直接用脚本解

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
import hashlib
def md5(s: bytes) -> str:
m = hashlib.md5()
m.update(s)
return m.hexdigest().lower()
def main():
secret = input('secret: ')
if len(secret) != 48:
return
else:
return secret.isnumeric() or None
values = []
for i in range(0, 48, 3):
values.append(int(secret[i:i + 3]))
co = [[158, 195, 205, 229, 213, 238, 211, 198, 190, 226, 135, 119, 145, 205, 113, 122],
[
234, 256, 185, 253, 244, 134, 102, 117, 190, 106, 131, 205, 198, 234, 162, 218],
[
164, 164, 209, 200, 168, 226, 189, 151, 253, 241, 232, 151, 193, 119, 226, 193],
[
213, 117, 151, 103, 249, 148, 103, 213, 218, 222, 104, 228, 100, 206, 218, 177],
[
217, 202, 126, 214, 195, 125, 144, 105, 152, 118, 167, 137, 171, 173, 206, 240],
[
160, 134, 131, 135, 186, 213, 146, 129, 125, 139, 174, 205, 177, 240, 194, 181],
[
183, 213, 127, 136, 136, 209, 199, 191, 150, 218, 160, 111, 191, 226, 154, 191],
[
247, 188, 210, 219, 179, 204, 155, 220, 215, 127, 225, 214, 195, 162, 214, 239],
[
108, 112, 104, 133, 178, 138, 110, 176, 232, 124, 193, 239, 131, 138, 161, 218],
[
140, 213, 142, 181, 179, 173, 203, 208, 184, 129, 129, 119, 122, 152, 186, 124],
[
105, 205, 124, 142, 175, 184, 234, 119, 195, 218, 141, 122, 202, 202, 190, 178],
[
183, 178, 256, 124, 241, 132, 163, 209, 204, 104, 175, 211, 196, 136, 158, 210],
[
224, 144, 189, 106, 177, 251, 206, 163, 167, 144, 208, 254, 117, 253, 100, 106],
[
251, 251, 136, 170, 145, 177, 175, 124, 193, 188, 193, 198, 208, 171, 151, 230],
[
143, 200, 143, 150, 243, 148, 136, 213, 161, 224, 170, 208, 185, 117, 189, 242],
[
234, 188, 226, 194, 248, 168, 250, 244, 166, 106, 113, 218, 209, 220, 158, 228]]
r = [
472214, 480121, 506256, 449505, 433390, 435414, 453899, 536361, 423332, 427624, 440268, 488759, 469049, 484574,
480266, 522818]
for i in range(16):
v = 0
for j in range(16):
v += co[i][j] * values[j]

if v != r[i]:
return

print('flag{ISEC-%s}' % md5(secret.encode()))

解出来是个算法题,16元一次方程,不会解,用z3硬跑

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

a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16 = Ints('a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16')
s=Solver()
s.add(158*a1+195*a2+205*a3+229*a4+213*a5+238*a6+211*a7+198*a8+190*a9+226*a10+135*a11+119*a12+145*a13+205*a14+113*a15+122*a16==472214)
s.add(234*a1+256*a2+185*a3+253*a4+244*a5+134*a6+102*a7+117*a8+190*a9+106*a10+131*a11+205*a12+198*a13+234*a14+162*a15+218*a16==480121)
s.add(164*a1+164*a2+209*a3+200*a4+168*a5+226*a6+189*a7+151*a8+253*a9+241*a10+232*a11+151*a12+193*a13+119*a14+226*a15+193*a16==506256)
s.add(213*a1+117*a2+151*a3+103*a4+249*a5+148*a6+103*a7+213*a8+218*a9+222*a10+104*a11+228*a12+100*a13+206*a14+218*a15+177*a16==449505)
s.add(217*a1+202*a2+126*a3+214*a4+195*a5+125*a6+144*a7+105*a8+152*a9+118*a10+167*a11+137*a12+171*a13+173*a14+206*a15+240*a16==433390)
s.add(160*a1+134*a2+131*a3+135*a4+186*a5+213*a6+146*a7+129*a8+125*a9+139*a10+174*a11+205*a12+177*a13+240*a14+194*a15+181*a16==435414)
s.add(183*a1+213*a2+127*a3+136*a4+136*a5+209*a6+199*a7+191*a8+150*a9+218*a10+160*a11+111*a12+191*a13+226*a14+154*a15+191*a16==453899)
s.add(247*a1+188*a2+210*a3+219*a4+179*a5+204*a6+155*a7+220*a8+215*a9+127*a10+225*a11+214*a12+195*a13+162*a14+214*a15+239*a16==536361)
s.add(108*a1+112*a2+104*a3+133*a4+178*a5+138*a6+110*a7+176*a8+232*a9+124*a10+193*a11+239*a12+131*a13+138*a14+161*a15+218*a16==423332)
s.add(140*a1+213*a2+142*a3+181*a4+179*a5+173*a6+203*a7+208*a8+184*a9+129*a10+129*a11+119*a12+122*a13+152*a14+186*a15+124*a16==427624)
s.add(105*a1+205*a2+124*a3+142*a4+175*a5+184*a6+234*a7+119*a8+195*a9+218*a10+141*a11+122*a12+202*a13+202*a14+190*a15+178*a16==440268)
s.add(183*a1+178*a2+256*a3+124*a4+241*a5+132*a6+163*a7+209*a8+204*a9+104*a10+175*a11+211*a12+196*a13+136*a14+158*a15+210*a16==488759)
s.add(224*a1+144*a2+189*a3+106*a4+177*a5+251*a6+206*a7+163*a8+167*a9+144*a10+208*a11+254*a12+117*a13+253*a14+100*a15+106*a16==469049)
s.add(251*a1+251*a2+136*a3+170*a4+145*a5+177*a6+175*a7+124*a8+193*a9+188*a10+193*a11+198*a12+208*a13+171*a14+151*a15+230*a16==484574)
s.add(143*a1+200*a2+143*a3+150*a4+243*a5+148*a6+136*a7+213*a8+161*a9+224*a10+170*a11+208*a12+185*a13+117*a14+189*a15+242*a16==480266)
s.add(234*a1+188*a2+226*a3+194*a4+248*a5+168*a6+250*a7+244*a8+166*a9+106*a10+113*a11+218*a12+209*a13+220*a14+158*a15+228*a16==522818)
if s.check() == sat:
print(s.model())
s='113201188123164176154241163109244215152103124165'
m=hashlib.md5()
m.update(s.encode())
print(m.hexdigest().lower())

写这个脚本累死了,好在跑出了

ca32ab6174689b5e366241ad58108c68

babynet

拿到程序,查出是c++写的,不过题目是.net,而且程序的对话框很像.net

把程序拖进ida发现看不懂

跑出来也没东西

看到题目描述是loader,猜测拿到的只是个启动程序

把程序跑起来dump一下

拿到生成的.net程序

但是跑不起来,发现需要传参,通过传参来进行窗口的初始化

啊这,又要回去看启动器

1.png

发现这里有东西

在资源段找到bin是一大段字母,应该是启动用的参数

传进去以后跑起dump下来的程序

11.png

通过传参生成了aes的key和iv

QvsiIpVK6iATLRE2YIo8siuz2uWMEm2L/L1uI02HOeARcVv9g2sb3W12K+tFeYIU enc1
kNDgXB9bm+NphKwQYJnG2d+HkzISsyRjrYboGt2biQSgj+o036bu3Hq5U86PuvLg enc2
94e4e1551b187ad6 iv
fd1cdef86a73484e key

再拿窗口编辑框的文本通过aes解密与enc1比较

22.png

比较以后再用输入生成flag,有个drawstring函数,应该输入正确后flag就出来了

找个在线解aes的网站解出输入是

use native executable to load .net binary

输入进去得到flag:

33.png

古典密码

01248密码(云影密码)

该密码又称为云影密码,使用 0,1,2,4,8 四个数字,其中 0 用来表示间隔,其他数字以加法可以表示出 如:28=10,124=7,18=9,再用 1->26 表示 A->Z。

可以看出该密码有以下特点

  • 只有 0,1,2,4,8

解密脚本

1
2
3
4
5
6
7
8
9
enc=[88421,122,48,2244,4,142242,248,122]
res=''
tab=['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
for i in enc:
c = 0
for j in str(i):
c+=int(j)
res+=tab[c-1]
print(res)

压缩包

需要密码的

三种可能:需要爆破、伪加密、密码相关信息藏在注释中

1.爆破

一般是rar,zip有时也要爆破

2.伪加密

zip伪加密,看全局标志位是不是00 00,是就是伪加密

3.注释

要认真看

有时候空白的也可能暗藏玄机

4.CRC碰撞

CRC32:CRC本身是“冗余校验码”的意思,CRC32则表示会产生一个32bit(8位十六进制数)的校验值。

在产生CRC32时,源数据块的每一位都参与了运算,因此即使数据块中只有一位发生改变也会得到不同的CRC32值,利用这个原理我们可以直接爆破出加密文件的内容。

脚本:

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
import zipfile
import string
import binascii

def CrackCrc(crc):
for i in dic:
for j in dic:
for k in dic:
for h in dic:
s = i + j + k + h
if crc == (binascii.crc32(s.encode())):
f.write(s)
return

def CrackZip():
for i in range(0,68):
file = 'out'+str(i)+'.zip'
crc = zipfile.ZipFile(file,'r').getinfo('data.txt').CRC
CrackCrc(crc)

dic = string.ascii_letters + string.digits + '+/='

f = open('out.txt','w')
CrackZip()
print("CRC32碰撞完成")
f.close

加密算法

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
#key
k='填key'

klen=len(k)
s=[]
for i in range(256):
s.append(i)
j=0
for i in range(256):
j=(j+s[i]+ord(k[i%klen]))%256
s[i],s[j] = s[j],s[i]
#input
m='填要加密或解密的'
d=[0]*256
j=0
i=0
mlen=len(m)
for k in range(mlen):
i=(i+1)%256
j=(j+s[i])%256
s[i],s[j]=s[j],s[i]
t=(s[i]+s[j])%256
d[k]=s[t]^ord(m[k])
flag=''
for i in d:
flag+=chr(i)
print(flag)

vm

初识

Vm_Instruction: vm才能识别的操作码

Vm_Context: vm用到的寄存器

Vm_Handlertable: 存放了指令,由操作码决定取出哪条指令

Vm_Dispatcher:读取操作码,决定用哪条handler

vm用esi做EIP,用EDI做寄存器

进制转换与文件io

from hex

1
2
3
4
5
6
7
import binascii
# 这是要读取的16进制
hex_data=open('1.txt','rb').read()
# 这是要输出的文件
out=open('res.rar','wb')
out.write(binascii.unhexlify(hex_data))
out.close()

特殊

字频统计

大量无特征、无规律字符

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+- =\\{\\}[]"#存在的字符
strings = open('flag.txt').read() #要打开的文件

result = {}
for i in alphabet:
counts = strings.count(i)
i = '{0}'.format(i)
result[i] = counts

res = sorted(result.items(),key=lambda item:item[1],reverse=True)
for data in res:
print(data)

for i in res:
flag = str(i[0])
print(flag[0],end="")

MP4

Kinovea这个工具

可以逐帧分析

一般是一闪而过找flag

键盘加密

EWAZX RTY TGB IJN IO KL这一串

属于是挺会玩

隐写

outguess

outguess下载安装

Kail终端命令输入git clone https://github.com/crorvick/outguess

安装包随即下载到文件夹。双击打开文件夹,右键点击空白区域选终端打开。

随后输入以下命令./configure && make && make install 进行安装

加密:

*outguess -k “my secret key” -d hidden.txt demo.jpg out.jpg*

加密之后,demo.jpg会覆盖out.jpg,

hidden.txt中的内容是要隐藏的东西

解密:

*outguess -k “my secret key” -r out.jpg hidden.txt*

解密之后,解密内容放在hidden.txt中

CRC校验

去kali看看能不能打开图片,报错是因为宽高出现问题

1.png

在这里宽高

看着改

lsb

最低有效位

一般stegsolve可以看出来信息

特殊的需要脚本

1
python lsb.py extract 目标.png 解密.xxx pwd

pwd是怎么回事暂时不知道,搞懂后补上