-
-
[原创]一次对二次加密的股票期货指标逆向记录
-
2024-2-19 09:59 1547
-
春节期间,看到某视频平台上直播间在售卖一个量化指标系统,看着很是神奇,可以使用体验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,'说明书');
看到代码,你还觉得神奇吗?
[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法