【软件逆向-一次对二次加密的股票期货指标逆向记录】此文章归类为:软件逆向。
春节期间,看到某视频平台上直播间在售卖一个量化指标系统,看着很是神奇,可以使用体验3天,看着很是高大上,看着主播滔滔不绝的讲解,很是诱人。(本人是从不相信天上掉馅饼的事情的,特别是股市期货市场,如果你有一个绝招可以挣钱,闷声发财就行了,为什么会拿出来分享呢),在网络上搜索相关的内容也很少,有人1W米出售源码,证明加密确实做的不错。一时技痒,忍不住拿来研究一番。
总体的逻辑是,将指标公式二次加密,客户端身份验证通过后,启动WH行情软件,通过进程注入,将公式解密,同时屏蔽行情软件的指标管理器功能。


既然是定制化的加密,直接破解难度很大,客户端的身份验证也是通过验证,反调试也是一套一套的,很是麻烦。
作为外挂系统,数据总要解密,行情交易软件才能正常读取试用,找到该系统的核心DLL whnloader.dll,也就是注入到WH行情软件中。
经过分析在DLLMAIN函数中发现了端倪,该DLL是对CreateFileA、ReadFile、WriteFile三个API函数下了钩子
|
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
|
000000018000694C
|
48
:
8B0D
3D180100
| mov rcx,qword ptr ds:[<&ReadFile>] | HOOK ReadFile
0000000180006953
|
4C
:
8D05
06A80100
| lea r8,qword ptr ds:[
0x180021160
] |
000000018000695A
|
48
:
8D15
7FEFFFFF
| lea rdx,qword ptr ds:[<sub_1800058E0>] | XTRD文件解密 函数
0000000180006961
| E8 DEADFFFF | call <whnloader.begin of sub_180001744> |
0000000180006966
|
85C0
| test eax,eax |
0000000180006968
|
0F85
99FCFFFF
| jne whnloader.
180006607
|
000000018000696E
|
48
:
8B0D
1B180100
| mov rcx,qword ptr ds:[<&ReadFile>] |
0000000180006975
| E8
72B0FFFF
| call <whnloader.begin of sub_1800019EC> | hook ReadFile
000000018000697A
|
85C0
| test eax,eax |
000000018000697C
|
0F85
85FCFFFF
| jne whnloader.
180006607
|
0000000180006982
|
48
:
8B0D
A7160100 | mov rcx,qword ptr ds:[<&CreateFileA>] | Hook CreateFileA
0000000180006989
|
4C
:
8D05
E8A70100 | lea r8,qword ptr ds:[
0x180021178
] |
0000000180006990
|
48
:
8D15
09E8FFFF
| lea rdx,qword ptr ds:[<begin of sub_1800051A0>] | 调用 内存解密
0000000180006997
| E8 A8ADFFFF | call <whnloader.begin of sub_180001744> |
000000018000699C
|
85C0
| test eax,eax |
000000018000699E
|
0F85
63FCFFFF
| jne whnloader.
180006607
|
00000001800069A4
|
48
:
8B0D
85160100
| mov rcx,qword ptr ds:[<&CreateFileA>] |
00000001800069AB
| E8
3CB0FFFF
| call <whnloader.begin of sub_1800019EC> | hook CreateFileA
00000001800069B0
|
85C0
| test eax,eax |
00000001800069B2
|
0F85
4FFCFFFF
| jne whnloader.
180006607
|
00000001800069B8
|
48
:
8B0D
49170100
| mov rcx,qword ptr ds:[<&WriteFile>] | HOOK WriteFile
00000001800069BF
|
4C
:
8D05
BAA70100 | lea r8,qword ptr ds:[
0x180021180
] |
00000001800069C6
|
48
:
8D15
C3E9FFFF | lea rdx,qword ptr ds:[<sub_180005390>] |
00000001800069CD
| E8
72ADFFFF
| call <whnloader.begin of sub_180001744> |
00000001800069D2
|
85C0
| test eax,eax |
00000001800069D4
|
0F85
2DFCFFFF
| jne whnloader.
180006607
|
00000001800069DA
|
48
:
8B0D
27170100
| mov rcx,qword ptr ds:[<&WriteFile>] |
00000001800069E1
| E8
06B0FFFF
| call <whnloader.begin of sub_1800019EC> | hook WriteFile
00000001800069E6
|
85C0
| test eax,eax |
00000001800069E8
|
0F85
19FCFFFF
| jne whnloader.
180006607
|
|
一切的数据处理都是在HOOK后的函数中处理,如最关键READFile,sub_1800058E0
|
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
|
0000000180005931
|
803B
4A
|
cmp
byte ptr ds:[rbx],
0x4A
|
4A
:
'J'
0000000180005934
|
0F85
6F070000
| jne whnloader.
1800060A9
|
000000018000593A
|
807B
01
6D
|
cmp
byte ptr ds:[rbx
+
0x1
],
0x6D
|
6D
:
'm'
000000018000593E
|
0F85
65070000
| jne whnloader.
1800060A9
|
0000000180005944
|
807B
02
38
|
cmp
byte ptr ds:[rbx
+
0x2
],
0x38
|
38
:
'8'
0000000180005948
|
0F85
5B070000
| jne whnloader.
1800060A9
|
000000018000594E
|
807B
60
BC |
cmp
byte ptr ds:[rbx
+
0x60
],
0xBC
|
0000000180005952
|
0F85
51070000
| jne whnloader.
1800060A9
|
0000000180005958
|
807B
61
D3 |
cmp
byte ptr ds:[rbx
+
0x61
],
0xD3
|
000000018000595C
|
0F85
47070000
| jne whnloader.
1800060A9
|
0000000180005962
|
807B
62
C3 |
cmp
byte ptr ds:[rbx
+
0x62
],
0xC3
|
0000000180005966
|
0F85
3D070000
| jne whnloader.
1800060A9
|
000000018000596C
|
807B
63
DC |
cmp
byte ptr ds:[rbx
+
0x63
],
0xDC
|
0000000180005970
|
0F85
33070000
| jne whnloader.
1800060A9
|
0000000180005976
|
807B
64
D6 |
cmp
byte ptr ds:[rbx
+
0x64
],
0xD6
|
000000018000597A
|
0F85
29070000
| jne whnloader.
1800060A9
|
0000000180005980
|
807B
65
A7 |
cmp
byte ptr ds:[rbx
+
0x65
],
0xA7
|
0000000180005984
|
0F85
1F070000
| jne whnloader.
1800060A9
|
000000018000598A
|
807B
66
B3 |
cmp
byte ptr ds:[rbx
+
0x66
],
0xB3
|
000000018000598E
|
0F85
15070000
| jne whnloader.
1800060A9
|
0000000180005994
|
807B
67
D6 |
cmp
byte ptr ds:[rbx
+
0x67
],
0xD6
|
0000000180005998
|
0F85
0B070000
| jne whnloader.
1800060A9
|
000000018000599E
|
807B
68
A3 |
cmp
byte ptr ds:[rbx
+
0x68
],
0xA3
|
00000001800059A2
|
0F85
01070000
| jne whnloader.
1800060A9
|
00000001800059A8
|
807B
69
BA |
cmp
byte ptr ds:[rbx
+
0x69
],
0xBA
|
00000001800059AC
|
0F85
F7060000 | jne whnloader.
1800060A9
|
00000001800059B2
|
807B
6A
D5 |
cmp
byte ptr ds:[rbx
+
0x6A
],
0xD5
|
00000001800059B6
|
0F85
ED060000 | jne whnloader.
1800060A9
|
00000001800059BC
|
807B
6B
C5 |
cmp
byte ptr ds:[rbx
+
0x6B
],
0xC5
|
00000001800059C0
|
0F85
E3060000 | jne whnloader.
1800060A9
|
00000001800059C6
|
807B
6C
D4 |
cmp
byte ptr ds:[rbx
+
0x6C
],
0xD4
|
00000001800059CA
|
0F85
D9060000 | jne whnloader.
1800060A9
|
00000001800059D0
|
807B
6D
A3 |
cmp
byte ptr ds:[rbx
+
0x6D
],
0xA3
|
00000001800059D4
|
0F85
CF060000 | jne whnloader.
1800060A9
|
00000001800059DA
|
807B
6E
B7 |
cmp
byte ptr ds:[rbx
+
0x6E
],
0xB7
|
00000001800059DE
|
0F85
C5060000 | jne whnloader.
1800060A9
|
00000001800059E4
|
807B
6F
C9 |
cmp
byte ptr ds:[rbx
+
0x6F
],
0xC9
|
00000001800059E8
|
0F85
BB060000 | jne whnloader.
1800060A9
|
00000001800059EE
|
807B
70
03
|
cmp
byte ptr ds:[rbx
+
0x70
],
0x3
|
00000001800059F2
|
0F85
B1060000 | jne whnloader.
1800060A9
|
00000001800059F8
|
807B
71
20
|
cmp
byte ptr ds:[rbx
+
0x71
],
0x20
|
20
:
' '
00000001800059FC
|
0F85
A7060000 | jne whnloader.
1800060A9
|
0000000180005A02
|
807B
72
20
|
cmp
byte ptr ds:[rbx
+
0x72
],
0x20
|
20
:
' '
0000000180005A06
|
0F85
9D060000
| jne whnloader.
1800060A9
|
0000000180005A0C
|
807B
73
20
|
cmp
byte ptr ds:[rbx
+
0x73
],
0x20
|
20
:
' '
0000000180005A10
|
0F85
93060000
| jne whnloader.
1800060A9
|
0000000180005A16
|
807B
74
77
|
cmp
byte ptr ds:[rbx
+
0x74
],
0x77
|
77
:
'w'
0000000180005A1A
|
0F85
89060000
| jne whnloader.
1800060A9
|
0000000180005A20
|
807B
75
77
|
cmp
byte ptr ds:[rbx
+
0x75
],
0x77
|
77
:
'w'
0000000180005A24
|
0F85
7F060000
| jne whnloader.
1800060A9
|
0000000180005A2A
|
807B
76
77
|
cmp
byte ptr ds:[rbx
+
0x76
],
0x77
|
77
:
'w'
0000000180005A2E
|
0F85
75060000
| jne whnloader.
1800060A9
|
0000000180005A34
|
807B
77
2E
|
cmp
byte ptr ds:[rbx
+
0x77
],
0x2E
| rbx
+
77
:L
"ā"
,
2E
:
'.'
0000000180005A38
|
0F85
6B060000
| jne whnloader.
1800060A9
|
0000000180005A3E
|
807B
78
4A
|
cmp
byte ptr ds:[rbx
+
0x78
],
0x4A
|
4A
:
'J'
0000000180005A42
|
0F85
61060000
| jne whnloader.
1800060A9
|
0000000180005A48
|
807B
79
6D
|
cmp
byte ptr ds:[rbx
+
0x79
],
0x6D
|
6D
:
'm'
0000000180005A4C
|
0F85
57060000
| jne whnloader.
1800060A9
|
0000000180005A52
|
807B
7A
69
|
cmp
byte ptr ds:[rbx
+
0x7A
],
0x69
|
69
:
'i'
0000000180005A56
|
0F85
4D060000
| jne whnloader.
1800060A9
|
0000000180005A5C
|
807B
7B
38
|
cmp
byte ptr ds:[rbx
+
0x7B
],
0x38
|
38
:
'8'
0000000180005A60
|
0F85
43060000
| jne whnloader.
1800060A9
|
0000000180005A66
|
807B
7C
2E
|
cmp
byte ptr ds:[rbx
+
0x7C
],
0x2E
|
2E
:
'.'
0000000180005A6A
|
0F85
39060000
| jne whnloader.
1800060A9
|
0000000180005A70
|
807B
7D
63
|
cmp
byte ptr ds:[rbx
+
0x7D
],
0x63
|
63
:
'c'
0000000180005A74
|
0F85
2F060000
| jne whnloader.
1800060A9
|
0000000180005A7A
|
807B
7E
6F
|
cmp
byte ptr ds:[rbx
+
0x7E
],
0x6F
|
6F
:
'o'
0000000180005A7E
|
0F85
25060000
| jne whnloader.
1800060A9
|
0000000180005A84
|
807B
7F
6D
|
cmp
byte ptr ds:[rbx
+
0x7F
],
0x6D
|
6D
:
'm'
|
该函数接管ReadFile后先判断,文件的头部是否有加密的特征数据,符合要求,同时又进行了一番时间校验和反调试判断,才进行解密。
数据处理的逻辑清楚了,想拿到源码就简单了。
写一个DLL,也注入到行情软件中,依次执行读取二次加密文件的动作,自然就触发了ReadFile,因为这一切都是在系统中运行,也就理所当然的拿到解密后代码了,因为系统对WriteFile也下了钩子,可以将数据发送到进程外面保存即可。

看到了标准的系统加密数据
想看源码,没有查看密码,这也容易
在公式管理器中输入错误密码,在主程序模块中,查找字符串"密码输入错误,可能有多个地方,断点跟踪一下,就找到了
|
1
2
3
4
5
6
7
8
9
10
11
|
0000000140EFB574
|
85D2
| test edx,edx |
0000000140EFB576
|
0F85
7F000000
| jne mytrader_whsp.
140EFB5FB
| 将je 修改为jne 即可跳过设置密码
0000000140EFB57C
|
45
:
33C9
| xor r9d,r9d |
0000000140EFB57F
|
4C
:
8D05
42F14500
| lea r8,qword ptr ds:[
14135A6C8
] |
000000014135A6C8
:
"提示"
0000000140EFB586
|
48
:
8D15
F3155C00 | lea rdx,qword ptr ds:[
1414BCB80
] |
00000001414BCB80
:
"密码输入错误,请重新输入"
0000000140EFB58D
|
48
:
8BCB
| mov rcx,rbx |
0000000140EFB590
|
48
:
83C4
20
| add rsp,
20
|
0000000140EFB594
|
5B
| pop rbx |
0000000140EFB595
| E9
4E1AC4FF
| jmp mytrader_whsp.
140B3CFE8
|
0000000140EFB59A
|
48
:
8B83
30010000
| mov rax,qword ptr ds:[rbx
+
130
] |
0000000140EFB5A1
|
4C
:
8B83
48010000
| mov r8,qword ptr ds:[rbx
+
148
] |
|
剩下就一切水到渠成了。
示例中二次加密的指标公式就一行代码。
DRAWBKBMP(1,'说明书');
看到代码,你还觉得神奇吗?
更多【软件逆向-一次对二次加密的股票期货指标逆向记录】相关视频教程:www.yxfzedu.com