ToDesk v4.2.8 逆向分析
前言:ToDesk v4.2.8逆向分析
我在win10上和XP上它运行的机制不同,在x64上的话它会用到一个zrtc.dll的动态链接库,而x32比如xp上就没有用到
比起360浏览器记录密码功能的加密算法,这个有点难,我没分析出来,等之后学了相关的算法之后再看吧,这里就做个分析记录
应用结构
主程序todesk.exe启动 -> 启动服务todesk_service.exe和加载zrtc.dll
1、todesk.exe 界面程序
2、todesk_service.exe 后端程序
3、zrtc.dll 提供相关的函数功能
总体过程
我一开始想要直接调试ToDesk,但是发现程序会直接结束,然后通过pchunter也没发现有相关的钩子存在,接着分析ToDesk.exe,会发现ToDesk.exe主程序运行起来之后,它会把ToDesk_service.exe作为服务启动,此时ToDesk_service.exe会跑起来,然后ToDesk会发送一个信号给ToDesk_service,接着ToDesk_service.exe才算真正的运行起来,接着就是ToDesk_service.exe会检测ToDesk.exe(不知道具体的,它会进行检测是不是被调试的状态还是什么),如果不是的话那么它会将ToDesk.exe杀掉,然后ToDesk_service.exe再重新启动ToDesk.exe作为子进程。
因为没有相关的钩子存在,所以我这里就通过附加的方式来进行调试,这里的话是可以继续调试的,然后接着就通过相关定位来到加密的过程,虽然找到了相关的加密方式,分析应该是通过了三段的加密方式,但是我发现第一段是自己通过随机数梅森旋转算法来生成一段初始的随机数字节大小为32个字节的数组,接着是通过Salsa20来继续生成22个字节,这里一共是54个字节,然后第三段的话就是通过这54个字节继续生成108个字节,这个108个字节就作为密文写入到config.ini的tempAuthPassEx字段
不太懂相关的算法,它第一步既然是随机数也不知道如果逆向之后该如何进行解密操作,所以就想去找它本身是如何解密的,本身的解密应该也是在ToDesk中,我是通过两个调试器来互相进行调试,因为如果Todesk直接调试,它启动的service会杀掉Todesk,当启动service就可以通过另外一个调试器来进行附加操作,然后service继续启动todesk进程,这个时候将其进程挂起操作,但是我发现最后还是调试不到ToDesk是如何解密密码然后展示到界面的,所以这个只能留着,因为逆向不是自己主长,希望通过后面的继续学习然后回头过来再看看,到时候再看能不能解决,有大佬知道如何操作请告知教教我
ToDesk启动服务ToDesk_service.exe
004AD932 . FF15 2CF00801 CALL DWORD PTR DS:[<&ADVAPI32.StartServi>; ADVAPI32.StartServiceW
004AD938 . 68 7CFD2001 PUSH ToDesk.0120FD7C ; /String = "controller.start"
004AD93D . FF15 98F50801 CALL DWORD PTR DS:[<&KERNEL32.OutputDebu>; \OutputDebugStringW
004AD943 . 68 DC050000 PUSH 5DC ; /Timeout = 1500. ms
004AD948 . FF15 90F50801 CALL DWORD PTR DS:[<&KERNEL32.Sleep>] ; \Sleep
ToDesk通知ToDesk_service.exe启动
004AD96A . 50 PUSH EAX ; /pWSAData
004AD96B . 68 02020000 PUSH 202 ; |RequestedVersion = 202 (2.2.)
004AD970 . FF15 38FB0801 CALL DWORD PTR DS:[<&WS2_32.#115>] ; \WSAStartup
004AD976 . 6A 00 PUSH 0 ; /Arg1 = 00000000
004AD978 . 8D8D 60FEFFFF LEA ECX,DWORD PTR SS:[EBP-1A0] ; |
004AD97E . E8 9DB10B00 CALL ToDesk.00568B20 ; \ToDesk.00568B20
004AD983 . FF15 34FB0801 CALL DWORD PTR DS:[<&WS2_32.#116>] ; [WSACleanup
创建文件config.ini
00007FF67C5F8A35 | E8 06F9FFFF | call todesk.7FF67C5F8340 | 创建config.ini
00007FF67C5F8A3A | 84C0 | test al,al | 判断config.ini是否创建成功
00007FF67C5F8A3C | 0F84 07010000 | je todesk.7FF67C5F8B49 | 成功则不跳转
加密函数
00007FF67C5F8AB0 | FF50 18 | call qword ptr ds:[rax+18] | 里面有进行相关的算法操作
00007FF67C5F8AB3 | 48:634424 30 | movsxd rax,dword ptr ss:[rsp+30] | eax 0x36 -> 54长度
00007FF67C5F8AB8 | 48:8B9C24 90040000 | mov rbx,qword ptr ss:[rsp+490] |
00007FF67C5F8AC0 | 85C0 | test eax,eax | 判断加密的长度是否为0
00007FF67C5F8AC2 | 0F84 81000000 | je todesk.7FF67C5F8B49 | 不为0的话不跳转
00007FF67C5F8AC8 | 4C:8BC0 | mov r8,rax |
00007FF67C5F8ACB | 48:8D5424 60 | lea rdx,qword ptr ss:[rsp+60] | rdx = 上面的CALL加密出来的数据
00007FF67C5F8AD0 | 48:8D4C24 38 | lea rcx,qword ptr ss:[rsp+38] | rcx = 上面的CALL加密出来的数据
00007FF67C5F8AD5 | E8 966AFEFF | call todesk.7FF67C5DF570 | 重要的加密函数
写入文件
00007FF67C5F8AF1 | 4C:8D4424 38 | lea r8,qword ptr ss:[rsp+38] | r8 = 密文的地址
00007FF67C5F8AF6 | 48:8D15 2B82EF00 | lea rdx,qword ptr ds:[7FF67D4F0D28] | tempAuthPassEx的字段
00007FF67C5F8AFD | 4C:0F434424 38 | cmovae r8,qword ptr ss:[rsp+38] | r8 = 密文的地址
00007FF67C5F8B03 | 48:8D0D A681EF00 | lea rcx,qword ptr ds:[7FF67D4F0CB0] | configInfo的字段头的信息
00007FF67C5F8B0A | FF15 C89ECE00 | call qword ptr ds:[<&WritePrivateProfil | 写入到对应的config.ini文件中
过程分析
关键CALL 00007FF67C599586 | E8 85F40500 | call <todesk.sub_7FF67C5F8A10> | 创建文件-加密字段-写入文件-恢复现场
算法一:通过随机数梅森旋转算法生成一段大小为32个字节数组A
- 外轮32次,内轮624次,外轮每次最终产生一个字节大小,总共就是32个字节大小
算法二:通过相关的Salsa20流式对称加密算法一段大小为22个字节数组B
- 生成的22个字节大小的数组B拼接到数组A的后面,36+22个字节,也就是总共为54个字节大小的数组
算法三:将前面大小为54个字节的数组进行加密相关的操作生成一段0x6C大小的字节数组密文
- 总共循环54次,每次循环都会用到一个字节,一个字节有两段操作,每次一个字节都会经过两段操作,生成两个字节,最后填充到一个大小为0x6C的字节数组C中