0x00 分析

此题使用多种加密(RSA,TEA,XOR…),还加入了一点流量分析,所以做起来不太简单(

附件是一个程序(elf)和一个流量包

0x01 解

经典流程,先查壳

彳亍,直接上IDA

可以直接找到main函数

可以看到下面有一个recv函数,用于从连接的套接字或绑定的无连接套接字接收数据,接收到了一个qword_50A0,然后传给了qword_5020,最后放入了函数sub_2090进行使用

看看函数sub_2090

一步步分析,

首先是a1,应该是用户输入的某个东西

然后是a2,看不太出是干嘛的,所以先跳过

最后是a3,看到v8从0开始递增,所以合理认为a3是一个长度,而从调用的输入可以看出,a3传入是48,所以基本可以断定这是一个长度

除此之外还有一个for循环,这个循环在大循环内部,以8为条件,结合v10的变化(一段a2并进行移位),猜测起到一个分段的作用

有长度、有输入、还有一个不知道是啥的东西,感觉应该是个加密函数

实际上,这是一个RSA的加密函数,跟入sub_1F9C和sub_1E6E可以看到接了两个幂运算(__modti3),由此可以判断

__moditi3本身只有三个参数,但是汇编时会被拆成高低位,因此在IDA中会出现五个参数

可参考:https://stackoverflow.com/questions/52384456/what-does-modti3-do

既然知道这是一个RSA,那么根据密码学的相关知识,RSA一般用于加密对称密钥或者作为数字签名,根据题目意思,这个地方应该是用来加密密钥了,而recv接收的是用户输入,这个地方不可能是被加密的密钥,所以这个只能是一个公钥,毕竟公钥不怕被泄露,因此这个a3,即传入的unk_5060就是一个对称密钥了

那么就有了另一个问题:后续加解密的key哪来的呢?

跟进去unk_5060发现是空的,说明这个密钥是随机生成的,既然是随机生成的,那么就需要根据附件来进行解密,找出这个随机密钥了

打开wireshark看附件,追踪一下TCP流

根据刚才的分析,可得RSA的公钥就是第一段,而众所周知,RSA的公钥由N和e组成,怎么知道N和e的具体长度呢?

这就要看函数如何处理接收到的公钥了

从sub_2090中输入sub_1F9C的变量可知,a1被分成三段进行输入,一个是前16B,另一个是紧接着的8B,最后是其他的8B

所以在第一段中前16个字节是RSA的N,那么剩下的8个字节就是e了,最后的字节因为为全0所以不用管

因此可以得到

1
2
3
n = "0x5fcef0e867349fc68f40763a6b0bde01"
e = "0x0100010000000000"
# 注意这里都是little-endian“

e和N都不是很大,可以自行分解

1
2
3
4
5
6
# 此处已转换为大端
n = 0x1DE0B6B3A76408FC69F3467E8F0CE5F
e = 0x10001
p = 0x1DE0B6B3A7640125
q = 0x1000000000000433
d = 0x15154B177F196213E61BD868372FB31

接着就可以把随机生成的密钥进行解码了

需要注意的是,这个RSA加密函数将这个key以8字节分段,最后生成每个段为16字节,一共6个段,即最终传输16*6=96字节的数据(结合main函数在sub_2090后的send和sub_2090的第三个参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from Crypto.Util.number import *
import gmpy2 as gp
n = 0x1DE0B6B3A76408FC69F3467E8F0CE5F
e = 0x10001
p = 0x1DE0B6B3A7640125
q = 0x1000000000000433
d = 0x15154B177F196213E61BD868372FB31

data = "7a3202cc78acb66216341041b18ea201a3eb93301b27a2b6e77cb244d2e02c0082cd6369f3a7c1d2a1dd9b561c98510017c911f2ac5ec565e2d9b9016df34900661212d889172b99954d25018b5d43012e81783c2d8cebedeb053ccd651de400"

k = b""
for i in range(0, len(data), 32):
# 八个字节为一组进行加密,即需要取32个字符(一个hex字符4bit)
c = bytes.fromhex(data[i:i+32])[::-1]
c = int(c.hex(), 16)
k += long_to_bytes(pow(c, d, n))
print(k.hex())
# key = fd94f6110000000072504b1d0000000004dec05c00000000e1f4d9500000000017cb56c17a19fb2dfedb84729728c894

回到main函数,看看这个密钥被用来干什么了

由main函数可以看到,从用户接收的数据是v5,然后v5就和密钥被用到sub_1D9A这个函数了

合理怀疑这个sub_1D9A是解密函数

看来确实是,不过解密也被分为了两种,当字节数大于16时使用一种,字节数小于16时使用另一种

字节数十六以下的使用了一个异或,这个异或用到了随机密钥的后16位

字节数十六以上用了一个算法,跟进去看看

是看不懂的算法,搜一搜发现是一个叫做TEA的算法

参考:https://blog.csdn.net/xiao__1bai/article/details/123307059

在这里此算法使用了密钥的前32位进行操作

回到main函数

main中,服务端循环接受客户端传来的12字节作为控制码,结构是3个dword,第一个用于决定操作类型,第二个是存储偏移或校检等,第三个是有效数据长度

操作类型:1对应解密输出,2对应解密后存储,3对应输入并存储,4是输出,5执行写入的shellcode,6退出。

由于控制码都是小于16的,所以可以根据这个对控制码进行解密,并将数据进行分组

据此,写脚本初步解密流量中的密文

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
import binascii
k = "fd94f6110000000072504b1d0000000004dec05c00000000e1f4d9500000000017cb56c17a19fb2dfedb84729728c894"

"""
先获取TEA的密钥
"""
k = binascii.unhexlify(k)
teak = [int.from_bytes(k[i:i+8], "little") for i in range(0, 32, 8)]
for i in teak:
print(hex(i), end=', ')
print()
# teak = [0x11f694fd, 0x1d4b5072, 0x5cc0de04, 0x50d9f4e1]

'''
再获取XOR的密钥
'''
xork = []
for i in range(len(k)):
if i >= 32:
xork.append(k[i])
for i in xork:
print(hex(i), end=', ')
print()
# xork = [0x17, 0xcb, 0x56, 0xc1, 0x7a, 0x19, 0xfb, 0x2d, 0xfe, 0xdb, 0x84, 0x72, 0x97, 0x28, 0xc8, 0x94]

s = "16cb56c17a19fb2ddcdb8472d52d1d6b1693164a13316a33be05bc1c4a2029b9efbf96dc917da5056d3ee46c2b0815cb56c17b19fb2de6db847211fd382bc3eb739037f7dfa4b0ca553f4dc67f81b71b7f9215cb56c17819fb2dd6db84727c8526cc3d6383bbcf0159590648586e7dd08b49cc1ee7f519ec206592254842b7f33d25646640ab16cb56c17a19fb2de5db8472c008ba6c15334f76485d8c17082f4468addbb3a62d20e754105d1014cb56c17a19fb2dfedb847215cb56c17219fb2dbdd984723419b3ea63306ff1224173d834b1f9c436332f39ec2aa102bb7747859d50793674b05a56f14ee29491895944cbf1f6846a9831f8dd5666202c4b0d558a690239b1dece4322fe535c0742cc2f37378577b999eaab713d853643bc379dac7f7f471ef2240b8898fac4431149aa27a65507db39a9111dea802a803506fbd4a2d558068974f993dcab4587a5620db6909a951dcf8bb65d4f8e92ac8300fd049bb3218199705babb255e7daef40a28c1d7e3f74cb1d44687be127258aafc4dbdaf09266daa68605e250aa244c179d759d22e90ed3d8a9bf155fae86c721ed8ee5603c4613ac47e5a80079b909727277fff31d20529b3c022e3b1a3616d639ca036586ef17d3dc9bdf1eeec5859f0022514f29b240f30c818e7fdd478f36779978c08885b2266e3cf599d0a4c27bca4615720a08e13916ec4a6ef5c943ddb25566e620726f56c5160913564d683badcc7204ec8e7080221de325a431a0680e9e108e427c7bc3807b86c78820bc9c2340709da352d953aea805a04b53f2d88f7b8fae50e5ba2de55615bc9b2e526167226e75f5c8827593281f23a65e5098e0e8e2623ee4f892bac76e6987a05832bc0b84215bb74ed83786bd55265e61ba5702170fda63e01a44d6b8a6f1740a6c03803095e5176bde18ee873dcd6380de9f325f1c436c11e3250cebceceb319a49a4e3f2f62cfd137b602e27f3974a113df414287da48afd9e8c7ef0bdb4d345313b52d662202f543f426f8271432a20186b1dc7f70d4123def1c3745c1ffe7f4017ff60e0b7486f0e8db90889a36072583ddb26dbd37778115cb56c17e19fb2d5edb847263424fb4921f224eb2d445183f9bc6541d1ac77072a6e616e6826cbbebe96af229e79620462869e51686d4d523f782b2e5b43a769403bf62f1b87512013f95d068dc04beb337f8741b471386a7746ebc7b9c7a9568ed9b590936cdc533f6f943e3a37966362b62092ce5a3c53a95b33d0ff1ac2c5800b67b8cc40d614b8df74d4114d4bb7104b545ac7d0b9eb606578fd63561578740ce7eeaa189baacd436ae15cb56c17f19fb2d5edb8472ecc4942bbc4e2bbec5c4adb791a7096298f6347c4a277364cea894234bdcf69811f31ce644bae10edc0de4ccc200a44fa0e2faa4d2eb3b28dcecc3a468efdbfa7de2728b27dfafd1a5df4803a7986cfa768fb1f9751ba1a7d47c9a6928978810d76dceb819738f4684637d3ddd2cc41e2a4585a366d4a46b32db59508f34bf5c654be7b5c86e24cca5d1013738c32ba9b6083e76e0f93c80fe712261841e546315cb56c17c19fb2d5edb847260fd338fdcecb096e26a56603082a58f5b1fb0ffb7fc8faac33589ec52ed02256aba88b2c2836433a5d146c6efe784d47da7a7ffc4256f3dce73314c0171f89e9a4f6a95f59e8460d2b65fe178daba5faf8d34d99e32a50aefbbb7ed9c9507765958870dd2e1836fe608215ca753a7125f3cb86ac32d1149cf2a144b873fc7a96914d376ed2fe88d36a609596a68d8bb76e71d1b81a8db3618271f002ff6fb5815cb56c17d19fb2d5edb8472b72d657abc1a3c2133fa45fd834d28fce3b5bdd8f111bfa61386a306aa74598ea6e5022f4aac8d9acd442c44465eb334c26d060dfc8f4f59c13f3225a5ea111f9e3e9ef4c75f40b85c43dbdd5d30970cde507cd96fa6a88970e23c1dc1cb9a1eab2f4cc16444226aff6c49dd13e030240ea32267a1699b5b8c83d05c1cc257f5028d649e2b58d96a1f59fcd42f027179e7400f2c64c3063ae1f9c496ec019eba12cb56c17219fa2dfedb847213cb56c17919fb2dfedb847211cb56c17a19fb2dfedb8472"
cur = 0

while cur < len(s):
# 读取12字节的命令,一个字节两个字符,故为24
op1 = bytearray(bytes.fromhex(s[cur:cur+24]))
cur += 24
# 命令都小于15字节,故只需进行异或
for i in range(len(op1)):
op1[i] ^= xork[i]
op = [int.from_bytes(op1[i:i+4], "little") for i in range(0, 12, 4)]
for i in op:
print('{:02x}'.format(i), end=' ')
print()
# 根据命令中的数据长度获取数据,同样要注意因为字节所以乘2
tmp = list(bytes.fromhex(s[cur:cur+2*op[-1]]))
for i in tmp:
print('{:02x}'.format(i), end='')
print()
cur += 2*op[-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
01 00 22 
d52d1d6b1693164a13316a33be05bc1c4a2029b9efbf96dc917da5056d3ee46c2b08
02 01 18
11fd382bc3eb739037f7dfa4b0ca553f4dc67f81b71b7f92
02 02 28
7c8526cc3d6383bbcf0159590648586e7dd08b49cc1ee7f519ec206592254842b7f33d25646640ab
01 00 1b
c008ba6c15334f76485d8c17082f4468addbb3a62d20e754105d10
03 00 00

02 08 243
3419b3ea63306ff1224173d834b1f9c436332f39ec2aa102bb7747859d50793674b05a56f14ee29491895944cbf1f6846a9831f8dd5666202c4b0d558a690239b1dece4322fe535c0742cc2f37378577b999eaab713d853643bc379dac7f7f471ef2240b8898fac4431149aa27a65507db39a9111dea802a803506fbd4a2d558068974f993dcab4587a5620db6909a951dcf8bb65d4f8e92ac8300fd049bb3218199705babb255e7daef40a28c1d7e3f74cb1d44687be127258aafc4dbdaf09266daa68605e250aa244c179d759d22e90ed3d8a9bf155fae86c721ed8ee5603c4613ac47e5a80079b909727277fff31d20529b3c022e3b1a3616d639ca036586ef17d3dc9bdf1eeec5859f0022514f29b240f30c818e7fdd478f36779978c08885b2266e3cf599d0a4c27bca4615720a08e13916ec4a6ef5c943ddb25566e620726f56c5160913564d683badcc7204ec8e7080221de325a431a0680e9e108e427c7bc3807b86c78820bc9c2340709da352d953aea805a04b53f2d88f7b8fae50e5ba2de55615bc9b2e526167226e75f5c8827593281f23a65e5098e0e8e2623ee4f892bac76e6987a05832bc0b84215bb74ed83786bd55265e61ba5702170fda63e01a44d6b8a6f1740a6c03803095e5176bde18ee873dcd6380de9f325f1c436c11e3250cebceceb319a49a4e3f2f62cfd137b602e27f3974a113df414287da48afd9e8c7ef0bdb4d345313b52d662202f543f426f8271432a20186b1dc7f70d4123def1c3745c1ffe7f4017ff60e0b7486f0e8db90889a36072583ddb26dbd377781
02 04 a0
63424fb4921f224eb2d445183f9bc6541d1ac77072a6e616e6826cbbebe96af229e79620462869e51686d4d523f782b2e5b43a769403bf62f1b87512013f95d068dc04beb337f8741b471386a7746ebc7b9c7a9568ed9b590936cdc533f6f943e3a37966362b62092ce5a3c53a95b33d0ff1ac2c5800b67b8cc40d614b8df74d4114d4bb7104b545ac7d0b9eb606578fd63561578740ce7eeaa189baacd436ae
02 05 a0
ecc4942bbc4e2bbec5c4adb791a7096298f6347c4a277364cea894234bdcf69811f31ce644bae10edc0de4ccc200a44fa0e2faa4d2eb3b28dcecc3a468efdbfa7de2728b27dfafd1a5df4803a7986cfa768fb1f9751ba1a7d47c9a6928978810d76dceb819738f4684637d3ddd2cc41e2a4585a366d4a46b32db59508f34bf5c654be7b5c86e24cca5d1013738c32ba9b6083e76e0f93c80fe712261841e5463
02 06 a0
60fd338fdcecb096e26a56603082a58f5b1fb0ffb7fc8faac33589ec52ed02256aba88b2c2836433a5d146c6efe784d47da7a7ffc4256f3dce73314c0171f89e9a4f6a95f59e8460d2b65fe178daba5faf8d34d99e32a50aefbbb7ed9c9507765958870dd2e1836fe608215ca753a7125f3cb86ac32d1149cf2a144b873fc7a96914d376ed2fe88d36a609596a68d8bb76e71d1b81a8db3618271f002ff6fb58
02 07 a0
b72d657abc1a3c2133fa45fd834d28fce3b5bdd8f111bfa61386a306aa74598ea6e5022f4aac8d9acd442c44465eb334c26d060dfc8f4f59c13f3225a5ea111f9e3e9ef4c75f40b85c43dbdd5d30970cde507cd96fa6a88970e23c1dc1cb9a1eab2f4cc16444226aff6c49dd13e030240ea32267a1699b5b8c83d05c1cc257f5028d649e2b58d96a1f59fcd42f027179e7400f2c64c3063ae1f9c496ec019eba
05 10008 00

04 03 00

06 00 00

然后解密数据

根据解密算法,编写解密TEA的脚本如下:

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 Crypto.Util.number import *
from pwn import *
teak = [0x11f694fd, 0x1d4b5072, 0x5cc0de04, 0x50d9f4e1]
xork = [0x17, 0xcb, 0x56, 0xc1, 0x7a, 0x19, 0xfb, 0x2d, 0xfe, 0xdb, 0x84, 0x72, 0x97, 0x28, 0xc8, 0x94]


def tea_decrypt(d):
# 64表示u64,即64位,8B
v0 = unpack(d[0:8], 64)
v1 = unpack(d[8:16], 64)
s = 0x13c6ef3720
LIMIT = 0xffff_ffff_ffff_ffff
for i in range(32):
tmp = ((v0 + s) ^ ((v0 << 4) + teak[2]) ^ ((v0 >> 5) + teak[3])) & LIMIT
v1 = (v1 - tmp) & LIMIT
tmp = ((v1 + s) ^ ((v1 << 4) + teak[0]) ^ ((v1 >> 5) + teak[1])) & LIMIT
v0 = (v0 - tmp) & LIMIT
s = (s - 0x9e3779b9) & LIMIT
return pack(v0, 64) + pack(v1, 64)


def decrypt(m):
l = len(m)
if l > 15:
b = bytearray(m)
# 从小端开始取,单位为8B即16个字符
for i in range(l-16, -1, -1):
b[i:(i+16)] = tea_decrypt(b[i:(i+16)])
return bytes(b)


tmp = bytes.fromhex("加密字串")
dec = decrypt(tmp)
print(dec)
for i in dec:
print('{:02x}'.format(i), end='')

解密结果如下:

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
01 00 22 
b'Hello, this is the remote server.\n'
02 01 18
b'Your input is incorrect\n'
02 02 28
b'Your input is correct , Congratulations\n'
01 00 1b
b'Please enter your password\n'
03 00 00

02 08 243
f30f1efa554889e54883ec3048897dd8c745e800000000eb048345e8018b45e84898488d148500000000488b45d84801d08b0085c075e2837de8280f85ea000000488b45d84889c7e82e010000c745ec00000000eb7e8b45ec4898488d148500000000488b45d84801d08b00c1f8108945f88b45ec4898488d148500000000488b45d84801d08b0025ffff00008945fc8b45ec05580200004898488d148500000000488b45d84801d08b003945f8757e8b45ec05bc0200004898488d148500000000488b45d84801d08b003945fc755e8345ec01837dec270f8e78ffffffc745f000000000eb3c8b45f005c80000004898488d148500000000488b45d84801d08b55f081c22c0100004863d2488d0c9500000000488b55d84801ca8b0089028345f001837df0637ebeeb4e90eb0190c745f400000000eb3a8b45f483c0644898488d148500000000488b45d84801d08b55f481c22c0100004863d2488d0c9500000000488b55d84801ca8b0089028345f401837df4637ec090c9c3f30f1efa554889e548897de8c745f800000000eb4d8b45f84898488d148500000000488b45e84801d08b088b45f805900100004898488d148500000000488b45e84801d08b108b45f84898488d348500000000488b45e84801f031ca89108345f801837df8277eadc745fc00000000eb4d8b45fc4898488d148500000000488b45e84801d08b088b45fc05f40100004898488d148500000000488b45e84801d08b108b45fc4898488d348500000000488b45e84801f001ca89108345fc01837dfc277ead90905dc3
02 04 a0
10e427223ed24c7ba09ac12abbf7b618380e605a2acb227a5c8ac836fbb0b651cce0a364aee0af11d9ddd5016af9d841b1c5bc3b508eda0474c85e5e0f4c767a78f3b22e7dcc7a4be0caab3da0a74b21b7dfa6201e43460f4399d67e63028936401f211dc3c2fa3fc7e53a1841709732ded60431c6e93f794b6e884beeba2c5304bc8c74eb084a76a9b2e36b3ccaec4e15d46c70053dac22387ba320e2b41055
02 05 a0
59000000330000000a0000002e000000210000001900000040000000540000004200000052000000100000004a000000380000005800000025000000340000001900000061000000250000005600000031000000080000004a0000001f0000000900000015000000150000004d0000002600000031000000410000004f000000340000004b0000004e00000025000000350000002a0000001600000013000000
02 06 a0
272200004c7b0000c12a0000b6180000605a0000227a0000c8360000b6510000a3640000af110000d5010000d8410000bc3b0000da0400005e5e0000767a0000b22e00007a4b0000ab3d00004b210000a6200000460f0000d67e000089360000211d0000fa3f00003a18000097320000043100003f790000884b00002c5300008c7400004a760000e36b0000ec4e00006c700000ac220000a320000010550000
02 07 a0
ade40000b2d20000fd9a000026f800008d0e000085cb0000678a000022b1000000e1000033e100009fdd0000a9f90000bfc50000ba8e000063c800006e4c00003af30000a9cc0000b5ca00002ba80000cddf0000334300006c9900002d020000371f00000ac30000b2e5000081700000ced6000025ea00004a6e00002abb000099bc00000309000016b300002eca00008ed40000963d00005f7b0000b2b40000
05 10008 00

04 03 00

06 00 00

最长的那一段就是判断密码的函数了

将它放入程序去分析,写个patch加到程序里面

1
2
3
4
5
6
import struct
sub = "f30f1efa554889e54883ec3048897dd8c745e800000000eb048345e8018b45e84898488d148500000000488b45d84801d08b0085c075e2837de8280f85ea000000488b45d84889c7e82e010000c745ec00000000eb7e8b45ec4898488d148500000000488b45d84801d08b00c1f8108945f88b45ec4898488d148500000000488b45d84801d08b0025ffff00008945fc8b45ec05580200004898488d148500000000488b45d84801d08b003945f8757e8b45ec05bc0200004898488d148500000000488b45d84801d08b003945fc755e8345ec01837dec270f8e78ffffffc745f000000000eb3c8b45f005c80000004898488d148500000000488b45d84801d08b55f081c22c0100004863d2488d0c9500000000488b55d84801ca8b0089028345f001837df0637ebeeb4e90eb0190c745f400000000eb3a8b45f483c0644898488d148500000000488b45d84801d08b55f481c22c0100004863d2488d0c9500000000488b55d84801ca8b0089028345f401837df4637ec090c9c3f30f1efa554889e548897de8c745f800000000eb4d8b45f84898488d148500000000488b45e84801d08b088b45f805900100004898488d148500000000488b45e84801d08b108b45f84898488d348500000000488b45e84801f031ca89108345f801837df8277eadc745fc00000000eb4d8b45fc4898488d148500000000488b45e84801d08b088b45fc05f40100004898488d148500000000488b45e84801d08b108b45fc4898488d348500000000488b45e84801f001ca89108345fc01837dfc277ead90905dc3"
sub = bytes.fromhex(sub)
print(list(sub))

# [243, 15, 30, 250, 85, 72, 137, 229, 72, 131, 236, 48, 72, 137, 125, 216, 199, 69, 232, 0, 0, 0, 0, 235, 4, 131, 69, 232, 1, 139, 69, 232, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 133, 192, 117, 226, 131, 125, 232, 40, 15, 133, 234, 0, 0, 0, 72, 139, 69, 216, 72, 137, 199, 232, 46, 1, 0, 0, 199, 69, 236, 0, 0, 0, 0, 235, 126, 139, 69, 236, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 193, 248, 16, 137, 69, 248, 139, 69, 236, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 37, 255, 255, 0, 0, 137, 69, 252, 139, 69, 236, 5, 88, 2, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 57, 69, 248, 117, 126, 139, 69, 236, 5, 188, 2, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 57, 69, 252, 117, 94, 131, 69, 236, 1, 131, 125, 236, 39, 15, 142, 120, 255, 255, 255, 199, 69, 240, 0, 0, 0, 0, 235, 60, 139, 69, 240, 5, 200, 0, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 85, 240, 129, 194, 44, 1, 0, 0, 72, 99, 210, 72, 141, 12, 149, 0, 0, 0, 0, 72, 139, 85, 216, 72, 1, 202, 139, 0, 137, 2, 131, 69, 240, 1, 131, 125, 240, 99, 126, 190, 235, 78, 144, 235, 1, 144, 199, 69, 244, 0, 0, 0, 0, 235, 58, 139, 69, 244, 131, 192, 100, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 85, 244, 129, 194, 44, 1, 0, 0, 72, 99, 210, 72, 141, 12, 149, 0, 0, 0, 0, 72, 139, 85, 216, 72, 1, 202, 139, 0, 137, 2, 131, 69, 244, 1, 131, 125, 244, 99, 126, 192, 144, 201, 195, 243, 15, 30, 250, 85, 72, 137, 229, 72, 137, 125, 232, 199, 69, 248, 0, 0, 0, 0, 235, 77, 139, 69, 248, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 8, 139, 69, 248, 5, 144, 1, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 16, 139, 69, 248, 72, 152, 72, 141, 52, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 240, 49, 202, 137, 16, 131, 69, 248, 1, 131, 125, 248, 39, 126, 173, 199, 69, 252, 0, 0, 0, 0, 235, 77, 139, 69, 252, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 8, 139, 69, 252, 5, 244, 1, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 16, 139, 69, 252, 72, 152, 72, 141, 52, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 240, 1, 202, 137, 16, 131, 69, 252, 1, 131, 125, 252, 39, 126, 173, 144, 144, 93, 195]

先将hex转为intlist

1
2
3
4
5
6
7
8
import ida_bytes
sub = [243, 15, 30, 250, 85, 72, 137, 229, 72, 131, 236, 48, 72, 137, 125, 216, 199, 69, 232, 0, 0, 0, 0, 235, 4, 131, 69, 232, 1, 139, 69, 232, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 133, 192, 117, 226, 131, 125, 232, 40, 15, 133, 234, 0, 0, 0, 72, 139, 69, 216, 72, 137, 199, 232, 46, 1, 0, 0, 199, 69, 236, 0, 0, 0, 0, 235, 126, 139, 69, 236, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 193, 248, 16, 137, 69, 248, 139, 69, 236, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 37, 255, 255, 0, 0, 137, 69, 252, 139, 69, 236, 5, 88, 2, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 57, 69, 248, 117, 126, 139, 69, 236, 5, 188, 2, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 0, 57, 69, 252, 117, 94, 131, 69, 236, 1, 131, 125, 236, 39, 15, 142, 120, 255, 255, 255, 199, 69, 240, 0, 0, 0, 0, 235, 60, 139, 69, 240, 5, 200, 0, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 85, 240, 129, 194, 44, 1, 0, 0, 72, 99, 210, 72, 141, 12, 149, 0, 0, 0, 0, 72, 139, 85, 216, 72, 1, 202, 139, 0, 137, 2, 131, 69, 240, 1,
131, 125, 240, 99, 126, 190, 235, 78, 144, 235, 1, 144, 199, 69, 244, 0, 0, 0, 0, 235, 58, 139, 69, 244, 131, 192, 100, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 216, 72, 1, 208, 139, 85, 244, 129, 194, 44, 1, 0, 0, 72, 99, 210, 72, 141, 12, 149, 0, 0, 0, 0, 72, 139, 85, 216, 72, 1, 202, 139, 0, 137, 2, 131, 69, 244, 1, 131, 125, 244, 99, 126, 192, 144, 201, 195, 243, 15, 30, 250, 85, 72, 137, 229, 72, 137, 125, 232, 199, 69, 248, 0, 0, 0, 0, 235, 77, 139, 69, 248, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 8, 139, 69, 248, 5, 144, 1, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 16, 139, 69, 248, 72, 152, 72, 141, 52, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 240, 49, 202, 137, 16, 131, 69, 248, 1, 131, 125, 248, 39, 126, 173, 199, 69, 252, 0, 0, 0, 0, 235, 77, 139, 69, 252, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 8, 139, 69, 252, 5, 244, 1, 0, 0, 72, 152, 72, 141, 20, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 208, 139, 16, 139, 69, 252, 72, 152, 72, 141, 52, 133, 0, 0, 0, 0, 72, 139, 69, 232, 72, 1, 240, 1, 202, 137, 16, 131, 69, 252, 1, 131, 125, 252, 39, 126, 173, 144, 144, 93, 195]
dt = sub
adr = 0x3198
for i in range(len(dt)):
patch_byte(adr+i, dt[i])
print("ok")

然后写补丁

最后再IDA中运行(可以考虑先把基址设为0)

然后就写入了

然后转换为函数进行分析

可以看到这样的东西

sub_3313也很重要

根据这两个函数,我们可以得知

这段代码分别使用了400,500,600和700偏移处的数据,判断出结果以后,再把100或者200处的字符串数据复制到300中,然后调用命令代码4的输出功能将300处的结果显示出来。

于是可以写出代码如下:

将上面的数据转换为intlist

1
2
3
d="hex数据"
dec = bytes.fromhex(d)
print(list(dec))

再根据函数进行解密

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
# 2 4
dec6 = [16, 228, 39, 34, 62, 210, 76, 123, 160, 154, 193, 42, 187, 247, 182, 24, 56, 14, 96, 90, 42, 203, 34, 122, 92, 138, 200, 54, 251, 176, 182, 81, 204, 224, 163, 100, 174, 224, 175, 17, 217, 221, 213, 1, 106, 249, 216, 65, 177, 197, 188, 59, 80, 142, 218, 4, 116, 200, 94, 94, 15, 76, 118, 122, 120, 243, 178, 46, 125, 204, 122, 75, 224, 202, 171, 61, 160, 167,
75, 33, 183, 223, 166, 32, 30, 67, 70, 15, 67, 153, 214, 126, 99, 2, 137, 54, 64, 31, 33, 29, 195, 194, 250, 63, 199, 229, 58, 24, 65, 112, 151, 50, 222, 214, 4, 49, 198, 233, 63, 121, 75, 110, 136, 75, 238, 186, 44, 83, 4, 188, 140, 116, 235, 8, 74, 118, 169, 178, 227, 107, 60, 202, 236, 78, 21, 212, 108, 112, 5, 61, 172, 34, 56, 123, 163, 32, 226, 180, 16, 85]
# 2 5
dec7 = [89, 0, 0, 0, 51, 0, 0, 0, 10, 0, 0, 0, 46, 0, 0, 0, 33, 0, 0, 0, 25, 0, 0, 0, 64, 0, 0, 0, 84, 0, 0, 0, 66, 0, 0, 0, 82, 0, 0, 0, 16, 0, 0, 0, 74, 0, 0, 0, 56, 0, 0, 0, 88, 0, 0, 0, 37, 0, 0, 0, 52, 0, 0, 0, 25, 0, 0, 0, 97, 0, 0, 0, 37, 0, 0, 0, 86, 0, 0,
0, 49, 0, 0, 0, 8, 0, 0, 0, 74, 0, 0, 0, 31, 0, 0, 0, 9, 0, 0, 0, 21, 0, 0, 0, 21, 0, 0, 0, 77, 0, 0, 0, 38, 0, 0, 0, 49, 0, 0, 0, 65, 0, 0, 0, 79, 0, 0, 0, 52, 0, 0, 0, 75, 0, 0, 0, 78, 0, 0, 0, 37, 0, 0, 0, 53, 0, 0, 0, 42, 0, 0, 0, 22, 0, 0, 0, 19, 0, 0, 0]
# 2 6
dec8 = [39, 34, 0, 0, 76, 123, 0, 0, 193, 42, 0, 0, 182, 24, 0, 0, 96, 90, 0, 0, 34, 122, 0, 0, 200, 54, 0, 0, 182, 81, 0, 0, 163, 100, 0, 0, 175, 17, 0, 0, 213, 1, 0, 0, 216, 65, 0, 0, 188, 59, 0, 0, 218, 4, 0, 0, 94, 94, 0, 0, 118, 122, 0, 0, 178, 46, 0, 0, 122, 75, 0, 0, 171, 61, 0, 0, 75, 33, 0,
0, 166, 32, 0, 0, 70, 15, 0, 0, 214, 126, 0, 0, 137, 54, 0, 0, 33, 29, 0, 0, 250, 63, 0, 0, 58, 24, 0, 0, 151, 50, 0, 0, 4, 49, 0, 0, 63, 121, 0, 0, 136, 75, 0, 0, 44, 83, 0, 0, 140, 116, 0, 0, 74, 118, 0, 0, 227, 107, 0, 0, 236, 78, 0, 0, 108, 112, 0, 0, 172, 34, 0, 0, 163, 32, 0, 0, 16, 85, 0, 0]
# 2 7
dec9 = [173, 228, 0, 0, 178, 210, 0, 0, 253, 154, 0, 0, 38, 248, 0, 0, 141, 14, 0, 0, 133, 203, 0, 0, 103, 138, 0, 0, 34, 177, 0, 0, 0, 225, 0, 0, 51, 225, 0, 0, 159, 221, 0, 0, 169, 249, 0, 0, 191, 197, 0, 0, 186, 142, 0, 0, 99, 200, 0, 0, 110, 76, 0, 0, 58, 243, 0, 0, 169, 204, 0, 0, 181, 202, 0, 0, 43, 168,
0, 0, 205, 223, 0, 0, 51, 67, 0, 0, 108, 153, 0, 0, 45, 2, 0, 0, 55, 31, 0, 0, 10, 195, 0, 0, 178, 229, 0, 0, 129, 112, 0, 0, 206, 214, 0, 0, 37, 234, 0, 0, 74, 110, 0, 0, 42, 187, 0, 0, 153, 188, 0, 0, 3, 9, 0, 0, 22, 179, 0, 0, 46, 202, 0, 0, 142, 212, 0, 0, 150, 61, 0, 0, 95, 123, 0, 0, 178, 180, 0, 0]

# 注意little-edian
k4 = [int.from_bytes(bytes(dec6[i:i+4]), "little") for i in range(0, 160, 4)]
k5 = [int.from_bytes(bytes(dec7[i:i+4]), "little") for i in range(0, 160, 4)]

k6 = [int.from_bytes(bytes(dec8[i:i+4]), "little") for i in range(0, 160, 4)]
k7 = [int.from_bytes(bytes(dec9[i:i+4]), "little") for i in range(0, 160, 4)]
for i in range(40):
c = (k6[i] << 16) | (k7[i])
c -= k5[i]
c ^= k4[i]
print(chr(c), end='')
# DASCTF{5rOV562J5Y5pu+5amn6Zuv2B5aSa5Liq}