-
-
[原创]Blowfish 解密 静态分析和动态调试流程记录
-
发表于: 2026-3-8 15:15 919
-
在仿真途中遇到了一个 DSPLib.py 文件,每次仿真都会加载一次,开头明摆着写着 VPICRYPTV2 ;要是它放在内部加载,恐怕也不会注意到,放在用户可见的目录中加载,这有些引发好奇心了,于是看看到底从哪里加载到源码的。下面记一下查找解密位置的流程:
首先,是个 .py,加载后是 module,先看看加载流程,发现了一个内置库 vpi_tc_internal
它没有 __file__ 字段,说明其是内置或故意隐藏的,应该嵌入在解释器内部;先观察执行效果,它使用 check_header 方法检查数据头部,另一个 init_module 方法从 module spec 加载,解密并初始化这一模块,这是 spec 的结构:
不过,spec 被初始化后,已经编译为字节码了,没有 __source__ 字段:
劫持 exec 会导致相关的 scipy 组件初始化出错,看起来没有很好的方法,并且无法保留注释等内容,接下来看下究竟是哪里进行了解密。
仿真由界面调用启动,界面程序为 pde.exe,命令行仿真程序为 ptcl.exe,在 System Informer 下可以看到创建的进程:
IDA 静态分析 ptcl.exe,搜索 VPICRYPTV2,寻找到一个字符串,发现字符串初始化结构:
这是一个字符串对象的初始化过程,atexit 是销毁逻辑,初始化时将固定位置的字符串复制到这一对象的数据区,IDA 中暂时标注为 VPICRYPTV2_string 对象;
接下来,寻找对象引用,按 x 找交叉引用,能够找到两个主要使用点,有一个较短,再向上找引用是 check_header 的逻辑,显然,并无解密逻辑;另一个伪代码较长,后续流程较为复杂,应该是要排查的内容:
上来就是一个字符串比较,清晰明了,进入这一分支的是解密流程,跳过压缩文件相关的逻辑,要看的是 VPICRYPTV2 解密逻辑:
排查这些步骤中的函数,标注了 get_VPICRYPTV2_key_string,其内部逻辑执行了混淆的 blowfish 秘钥构建,密钥是由 off_141A4A5E8 位置的三个字符串交叉生成的,这三个原始字符串似乎是开发人员随手复制的,例如 Error: no file existing,重新混合组合成二进制秘钥字符串,下面是偏移处的数据:
不过,这里的逻辑有些难以辨识,这一 get_VPICRYPTV2_key_string 函数给了一个明确的返回值,考虑直接动态调试查看秘钥情况。
由于 ptcl.exe 由 pde.exe 界面程序创建进程,先调试 pde.exe,断点设置在创建进程相关接口:
和 ptcl.exe 相关的执行停止在 CreateProcessW,对于 CreateProcessW 有六个参数:
在 x64 调用约定中,前 4 个参数在寄存器(RCX, RDX, R8, R9),后面的参数在栈上。
RDX 指针位置的数据的确是 ptcl.exe 相关的命令行指令,从 System Informer 可以看到环境变量和运行参数,使用 x64dbg.exe 启动 ptcl.exe 开始调试:
x64dbg 跳过 pde.exe 的 CreateProcessW 进程创建,IDA 内找到 ptcl.exe 的断点在 ret 之前:
例如 .text:0000000141240966 地址,由于 IDA 静态时默认起始地址 0x140000000,对应的实际运行时断点位置为 ptcl.exe + 0x14124F5D2 - 0x140000000;
x64dbg 下 Ctrl+G 在 x64dbg.exe 中导航到这一地址位置设置断点,F9 继续运行 ptcl.exe 和 pde.exe 使二者正常完成初始化 HTTP 通信,开始读取文件和解密(bp fopen 会无法初始化,还是需要手动设用户段的断点):
停止在 00007FF7A9D90966 (IDA内0x141240956附近),RAX 内部地址为 000000FEC42FE638,是函数返回的目标字符串对象指针,RAX 内存镜像 dump 000000FEC42FE638:
前 8 字节为 50 B9 FC 43 D2 02 00 00,转换成地址是:0x000002D243FCB950,这是数据指针;偏移 16 字节(+0x10)处为 52 00 00 00 00 00 00 00,十六进制 0x52 = 十进制 82,说明 Blowfish 算法使用的密钥长度是 82 字节。
去数据区寻找秘钥 dump 0x000002D243FCB950:
可以看到秘钥为
69r114o114:32n111 102i108e32e120i115t105n10380r111f105l101 98a10068i115k32f117l108
看起来仍然是混淆的,这并不是个好现象,不过秘钥指针传递到了 v24,一定是被后续使用到。
继续静态分析,看后续代码 blowfish_start_decrypt,v24 传递给函数第四个参数,函数内 a4 就是这一秘钥字符串:
sub_14123DBC0 使用 a4 字符串赋值给了 v13,v13 在下一个 blowfish_decrypt_init 函数中被处理为 Blowfish 解密需要的 S-Box 和 P-Array,存入a1 + 0x68(104)和a1 + 0x24(32):
之后 blowfish_crypt_exec 使用了 a1 中储存的 S-Box 和 P-Array,进行分块解密,返回值 v11 为数据长度,这是最终解密操作的核心:
数据写入到前面申请的地址空间 v12 = (void *)operator new(*a3 - 4);,v12 作为第五个参数传递到函数中:
因此,在上一级函数 blowfish_start_decrypt动态调试,返回 v12 前打一个断点,读取 v12(R12) 即为解密后的数据,a1(RDI) + 0x68 和 a1(RDI) + 0x20 的两个偏置位置则为 S-Box 和 P-Array 数据,现在继续动态调试:
停止在 00007FF7A9D9F6F6,对应 IDA 的 .text:000000014124F6F6,做内存转储 dump R12,直接报错解密后数据即可。
查看对应的 RDI + 0x20 和 RDI + 0x68 地址位置的 S-Box 和 P-Array,RDI + 0x20 可以直接转储,18 个 P-Array 秘钥连续储存,RDI + 0x68 的 S-Box 数据是字符串对象,同理找到其数据区地址 0x000000FEC42FE760:
获取数据区内容 dump 0x000000FEC42FE760:
有了 S-Box 和 P-Array,也可以手动做 Blowfish ECB 解码获取数据
这样就能离线解码出目标文件了:
总之这一代码库的加密部分,使用 Blowfish ECB 已经是加密的老一辈了,而且代码库也没有更多的做混淆或检测;寻找解密部分还算顺利,这次就说到这吧
[2026-03-07 13:36:28] vpi_tc_internal info: Type: <class 'module'> Dir: ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'check_header', 'eval_expr', 'get_param_expr_type', 'get_param_value', 'init_module'] __name__: vpi_tc_internal[2026-03-07 13:36:28] vpi_tc_internal info: Type: <class 'module'> Dir: ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'check_header', 'eval_expr', 'get_param_expr_type', 'get_param_value', 'init_module'] __name__: vpi_tc_internal[2026-03-07 13:36:28] spec info: Type: <class '_frozen_importlib.ModuleSpec'> Dir: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_cached', '_set_fileattr', 'cached', 'has_location', 'loader', 'loader_state', 'name', 'origin', 'parent', 'submodule_search_locations'] __module__: _frozen_importlib[2026-03-07 13:36:28] spec info: Type: <class '_frozen_importlib.ModuleSpec'> Dir: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_cached', '_set_fileattr', 'cached', 'has_location', 'loader', 'loader_state', 'name', 'origin', 'parent', 'submodule_search_locations'] __module__: _frozen_importlib[2026-03-07 12:50:20] Source exec info: Type: <class 'code'> Dir: ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'][2026-03-07 12:50:20] Source exec info: Type: <class 'code'> Dir: ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']"C:\Program Files\VPI\VPIdesignSuite 11.1\simeng\bin\x64\ptcl.exe" -port 7801 -id 1 -dir "C:\Users\zsig\AppData\Local\Temp\VPIDS111\jobs\6" -x"C:\Program Files\VPI\VPIdesignSuite 11.1\simeng\bin\x64\ptcl.exe" -port 7801 -id 1 -dir "C:\Users\zsig\AppData\Local\Temp\VPIDS111\jobs\6" -xint sub_140021720(){ sub_14123DE40((__int64)&VPICRYPTV2_string, "VPICRYPTV2"); return atexit(sub_1416A3850);}int sub_140021720(){ sub_14123DE40((__int64)&VPICRYPTV2_string, "VPICRYPTV2"); return atexit(sub_1416A3850);}if ( (unsigned int)compare_string_objects(v60, &VPICRYPTV1_string) && (unsigned int)compare_string_objects(v60, &VPICRYPTV2_string) )if ( (unsigned int)compare_string_objects(v60, &VPICRYPTV1_string) && (unsigned int)compare_string_objects(v60, &VPICRYPTV2_string) )v50 = 0;v62 = 16;v63 = 8;v64 = 5;v65 = 56;v66 = 16;v67 = (void *)operator new(saturated_mul(0x12u, 4u));Block = (void *)operator new(4096);sub_1412404B0(v69, &off_141A4A5E8);v52 = v57;v24 = get_VPICRYPTV2_key_string(v69, v57, &off_141A4A5E8);v25 = (char *)blowfish_start_decrypt(pExceptionObject, v53, &v46, v24);v50 = v25;j_j_free_0(Block);j_j_free_0(v67);sub_14124D840(a1, v25, (unsigned int)v46, &v47);v26 = (int)v47;v27 = v46 - v47;v46 -= v47;v50 = 0;v62 = 16;v63 = 8;v64 = 5;v65 = 56;v66 = 16;v67 = (void *)operator new(saturated_mul(0x12u, 4u));Block = (void *)operator new(4096);sub_1412404B0(v69, &off_141A4A5E8);v52 = v57;v24 = get_VPICRYPTV2_key_string(v69, v57, &off_141A4A5E8);v25 = (char *)blowfish_start_decrypt(pExceptionObject, v53, &v46, v24);v50 = v25;j_j_free_0(Block);j_j_free_0(v67);sub_14124D840(a1, v25, (unsigned int)v46, &v47);v26 = (int)v47;v27 = v46 - v47;v46 -= v47;.rdata:0000000141A4A5E8 off_141A4A5E8 dq offset aErrorNoFileExi.rdata:0000000141A4A5E8 ; DATA XREF: sub_140E5A0E0:loc_140E5A12D↑o.rdata:0000000141A4A5E8 ; sub_1411D3970:loc_1411D39DE↑o ....rdata:0000000141A4A5E8 ; "Error: no file existing".rdata:0000000141A4A5F0 dq offset aProfileBad ; "Profile bad".rdata:0000000141A4A5F8 dq offset aDiskFull ; "Disk full".rdata:0000000141A4A600 aErrorNoFileExi db 'Error: no file existing',0.rdata:0000000141A4A600 ; DATA XREF: .rdata:off_141A4A5E8↑o.rdata:0000000141A4A618 aProfileBad db 'Profile bad',0 ; DATA XREF: .rdata:0000000141A4A5F0↑o.rdata:0000000141A4A624 align 8.rdata:0000000141A4A628 aDiskFull db 'Disk full',0 ; DATA XREF: .rdata:0000000141A4A5F8↑o.rdata:0000000141A4A632 align 8.rdata:0000000141A4A5E8 off_141A4A5E8 dq offset aErrorNoFileExi.rdata:0000000141A4A5E8 ; DATA XREF: sub_140E5A0E0:loc_140E5A12D↑o.rdata:0000000141A4A5E8 ; sub_1411D3970:loc_1411D39DE↑o ....rdata:0000000141A4A5E8 ; "Error: no file existing".rdata:0000000141A4A5F0 dq offset aProfileBad ; "Profile bad".rdata:0000000141A4A5F8 dq offset aDiskFull ; "Disk full".rdata:0000000141A4A600 aErrorNoFileExi db 'Error: no file existing',0.rdata:0000000141A4A600 ; DATA XREF: .rdata:off_141A4A5E8↑o.rdata:0000000141A4A618 aProfileBad db 'Profile bad',0 ; DATA XREF: .rdata:0000000141A4A5F0↑o.rdata:0000000141A4A624 align 8.rdata:0000000141A4A628 aDiskFull db 'Disk full',0 ; DATA XREF: .rdata:0000000141A4A5F8↑o.rdata:0000000141A4A632 align 8$env:BNROOT = "C:\Program Files\VPI\VPIdesignSuite 11.1\simeng"$env:HOME = "C:\Users\zsig"$env:PTCL_GPU_SETTINGS = "0:4294836224"$env:PTCL_PYTHON_ENGINE = "C:\ProgramData\VPI\VPIpython\x64\pyenvs\0\Scripts\python37.dll"$env:PTDS_HOME = "C:\Program Files\VPI\VPIdesignSuite 11.1\"$env:PTOLEMY = "C:\Program Files\VPI\VPIdesignSuite 11.1\simeng\ptolemy"$env:PYTHONHOME = "C:\ProgramData\VPI\VPIpython\x64\pyenvs\0"$env:PYTHONPATH = ""$env:TMM_DATA = "C:\Users\zsig\AppData\Local\Temp\VPIDS111"$env:TMM_LOGDIR = "C:\Users\zsig\AppData\Local\Temp\VPIDS111\log"$env:TMP = "C:\Users\zsig\AppData\Local\Temp"$env:USERNAME = "zsig"$env:USERPROFILE = "C:\Users\zsig"Start-Process "D:\U-WindowsUserData\TmpData\x64dbg\release\x64\x64dbg.exe" -ArgumentList @( '"C:\Program Files\VPI\VPIdesignSuite 11.1\simeng\bin\x64\ptcl.exe"', '--', '-port 7802', '-id 1', '-dir "C:\Users\zsig\AppData\Local\Temp\VPIDS111\jobs\2"', '-x')$env:BNROOT = "C:\Program Files\VPI\VPIdesignSuite 11.1\simeng"$env:HOME = "C:\Users\zsig"$env:PTCL_GPU_SETTINGS = "0:4294836224"$env:PTCL_PYTHON_ENGINE = "C:\ProgramData\VPI\VPIpython\x64\pyenvs\0\Scripts\python37.dll"$env:PTDS_HOME = "C:\Program Files\VPI\VPIdesignSuite 11.1\"$env:PTOLEMY = "C:\Program Files\VPI\VPIdesignSuite 11.1\simeng\ptolemy"$env:PYTHONHOME = "C:\ProgramData\VPI\VPIpython\x64\pyenvs\0"$env:PYTHONPATH = ""$env:TMM_DATA = "C:\Users\zsig\AppData\Local\Temp\VPIDS111"$env:TMM_LOGDIR = "C:\Users\zsig\AppData\Local\Temp\VPIDS111\log"$env:TMP = "C:\Users\zsig\AppData\Local\Temp"$env:USERNAME = "zsig"$env:USERPROFILE = "C:\Users\zsig"Start-Process "D:\U-WindowsUserData\TmpData\x64dbg\release\x64\x64dbg.exe" -ArgumentList @( '"C:\Program Files\VPI\VPIdesignSuite 11.1\simeng\bin\x64\ptcl.exe"', '--', '-port 7802', '-id 1', '-dir "C:\Users\zsig\AppData\Local\Temp\VPIDS111\jobs\2"', '-x')// Hidden C++ exception states: #wind=3void *__fastcall blowfish_start_decrypt(_DWORD *a1, __int64 a2, _DWORD *a3, void *a4){ int v8; // edi __int64 i; // rax int v10; // edx int v11; // ecx void *v12; // r14 __int64 v13; // rax int v14; // eax size_t v15; // rbx void *v16; // rdi void *v18; // [rsp+30h] [rbp-A8h] _BYTE v19[32]; // [rsp+48h] [rbp-90h] BYREF _BYTE v20[32]; // [rsp+68h] [rbp-70h] BYREF void *v21; // [rsp+88h] [rbp-50h] v21 = a4; v8 = 0; for ( i = 0; i < 4; ++i ) { v10 = *(char *)(i + a2); v11 = v10 + 256; if ( v10 >= 0 ) v11 = *(char *)(i + a2); v8 += v11; if ( i < 3 ) v8 <<= 8; } v12 = (void *)operator new(*a3 - 4); v18 = (void *)sub_14123DBC0(v19, a4); v13 = sub_14123DBC0(v20, v18); blowfish_decrypt_init(a1, v13); sub_14123E010(v18); *a1 = 1; v14 = blowfish_crypt_exec((_DWORD)a1, a2, 4, *a3 - 4, (__int64)v12, 0); *a3 = v8; if ( v8 == v14 ) { sub_14123E010(a4); return v12; } else { v15 = v8; v16 = (void *)operator new(v8); memcpy(v16, v12, v15); j_j_free_0(v12); sub_14123E010(a4); return v16; }}// Hidden C++ exception states: #wind=3void *__fastcall blowfish_start_decrypt(_DWORD *a1, __int64 a2, _DWORD *a3, void *a4){ int v8; // edi __int64 i; // rax int v10; // edx int v11; // ecx void *v12; // r14 __int64 v13; // rax int v14; // eax size_t v15; // rbx void *v16; // rdi void *v18; // [rsp+30h] [rbp-A8h] _BYTE v19[32]; // [rsp+48h] [rbp-90h] BYREF _BYTE v20[32]; // [rsp+68h] [rbp-70h] BYREF void *v21; // [rsp+88h] [rbp-50h] v21 = a4; v8 = 0; for ( i = 0; i < 4; ++i ) { v10 = *(char *)(i + a2); v11 = v10 + 256; if ( v10 >= 0 ) v11 = *(char *)(i + a2); v8 += v11; if ( i < 3 ) v8 <<= 8; } v12 = (void *)operator new(*a3 - 4); v18 = (void *)sub_14123DBC0(v19, a4); v13 = sub_14123DBC0(v20, v18); blowfish_decrypt_init(a1, v13); sub_14123E010(v18); *a1 = 1; v14 = blowfish_crypt_exec((_DWORD)a1, a2, 4, *a3 - 4, (__int64)v12, 0); *a3 = v8; if ( v8 == v14 ) { sub_14123E010(a4); return v12; } else { v15 = v8; v16 = (void *)operator new(v8); memcpy(v16, v12, v15); j_j_free_0(v12); sub_14123E010(a4); return v16; }}void __fastcall blowfish_decrypt_init(__int64 a1, _QWORD *a2){ _OWORD *v3; // rax _OWORD *v4; // rcx __int64 v5; // rdi __int64 v6; // rdx _OWORD *v7; // rax _OWORD *v8; // rcx __int64 v9; // rdx _OWORD *v10; // rax _OWORD *v11; // rcx __int64 v12; // rdx _OWORD *v13; // rax _OWORD *v14; // rcx __int64 v15; // rdx int v16; // edx int v17; // r8d __int64 v18; // rsi int v19; // esi int v20; // ebp __int64 v21; // rax int v22; // r14d int v23; // r15d int v24; // r12d __int64 v25; // rax int v26; // r11d unsigned __int64 v27; // rdx __int64 v28; // r10 _QWORD *v29; // rsi unsigned __int64 v30; // rbp int v31; // ecx int v32; // edx int v33; // r8d int v34; // edx int v35; // r9d int v36; // edx int v37; // ecx int v38; // esi int v39; // r14d __int64 v40; // rbp __int64 v41; // r13 int v42; // r13d __int64 v43; // rax _DWORD *v44; // rdx int v45; // [rsp+30h] [rbp-78h] BYREF int v46; // [rsp+34h] [rbp-74h] int v47; // [rsp+38h] [rbp-70h] _QWORD *v48; // [rsp+40h] [rbp-68h] unsigned __int64 v49; // [rsp+48h] [rbp-60h] void *v50; // [rsp+50h] [rbp-58h] __int64 v51; // [rsp+58h] [rbp-50h] _QWORD *v52; // [rsp+60h] [rbp-48h] v51 = -2; v50 = a2; v52 = a2; if ( a2[3] < 0x10u ) v48 = a2; else v48 = (_QWORD *)*a2; v49 = a2[2]; v3 = *(_OWORD **)(a1 + 104); v4 = &unk_141A6C0D0; v5 = 8; v6 = 8; do { *v3 = *v4; v3[1] = v4[1]; v3[2] = v4[2]; v3[3] = v4[3]; v3[4] = v4[4]; v3[5] = v4[5]; v3[6] = v4[6]; v3 += 8; *(v3 - 1) = v4[7]; v4 += 8; --v6; } while ( v6 ); v7 = (_OWORD *)(*(_QWORD *)(a1 + 104) + 1024LL); v8 = &unk_141A6C4D0; v9 = 8; do { *v7 = *v8; v7[1] = v8[1]; v7[2] = v8[2]; v7[3] = v8[3]; v7[4] = v8[4]; v7[5] = v8[5]; v7[6] = v8[6]; v7 += 8; *(v7 - 1) = v8[7]; v8 += 8; --v9; } while ( v9 ); v10 = (_OWORD *)(*(_QWORD *)(a1 + 104) + 2048LL); v11 = &unk_141A6C8D0; v12 = 8; do { *v10 = *v11; v10[1] = v11[1]; v10[2] = v11[2]; v10[3] = v11[3]; v10[4] = v11[4]; v10[5] = v11[5]; v10[6] = v11[6]; v10 += 8; *(v10 - 1) = v11[7]; v11 += 8; --v12; } while ( v12 ); v13 = (_OWORD *)(*(_QWORD *)(a1 + 104) + 3072LL); v14 = &unk_141A6CCD0; v15 = 8; do { *v13 = *v14; v13[1] = v14[1]; v13[2] = v14[2]; v13[3] = v14[3]; v13[4] = v14[4]; v13[5] = v14[5]; v13[6] = v14[6]; v13 += 8; *(v13 - 1) = v14[7]; v14 += 8; --v15; } while ( v15 ); memcpy(*(void **)(a1 + 24), &unk_141A6C080, 4LL * (*(_DWORD *)(a1 + 20) + 2)); v16 = 0; v45 = 0; v17 = 0; v46 = 0; v18 = 10; while ( 1 ) { blowfish_encrypt(a1, v16, v17, (unsigned int)&v45, 0); if ( !--v18 ) break; v17 = v46; v16 = v45; } v19 = v46; v20 = v45; if ( v45 != -1426174275 || v46 != 651634172 ) { v21 = sub_14002CE50(std::cout, "Blowfish: Self Test 1 failed: encrypt^10(0) ="); std::ostream::operator<<(v21, sub_14002DE00); } v47 = 9; v22 = 9; while ( 1 ) { blowfish_decrypt(a1, v20, v19, (unsigned int)&v45, 0); if ( --v22 < 0 ) break; v19 = v46; v20 = v45; } v23 = v46; v24 = v45; if ( v45 || v46 ) { v25 = sub_14002CE50(std::cout, "Blowfish: Self Test 1 failed: decrypt^10(encrypt^10(0)) = "); std::ostream::operator<<(v25, sub_14002DE00); } v26 = 0; LODWORD(v27) = 0; if ( *(_DWORD *)(a1 + 20) + 2 > 0 ) { v28 = 0; v29 = v48; v30 = v49; do { v31 = *((unsigned __int8 *)v29 + (int)v27); v32 = ((int)v27 + 1) % v30; v33 = (v31 << 8) | *((unsigned __int8 *)v29 + v32); v34 = (v32 + 1) % v30; v35 = (v33 << 8) | *((unsigned __int8 *)v29 + v34); v36 = (v34 + 1) % v30; v37 = (v35 << 8) | *((unsigned __int8 *)v29 + v36); v27 = (v36 + 1) % v30; *(_DWORD *)(v28 + *(_QWORD *)(a1 + 24)) ^= v37; ++v26; v28 += 4; } while ( v26 < *(_DWORD *)(a1 + 20) + 2 ); } blowfish_encrypt(a1, 0, 0, *(_QWORD *)(a1 + 24), 0); v38 = 2; v39 = 2; if ( *(_DWORD *)(a1 + 20) + 2 > 2 ) { v40 = 8; do { blowfish_encrypt( a1, *(_DWORD *)(*(_QWORD *)(a1 + 24) + v40 - 8), *(_DWORD *)(*(_QWORD *)(a1 + 24) + v40 - 4), *(_QWORD *)(a1 + 24), v39); v39 += 2; v40 += 8; } while ( v39 < *(_DWORD *)(a1 + 20) + 2 ); } blowfish_encrypt( a1, *(_DWORD *)(*(_QWORD *)(a1 + 24) + 4LL * *(int *)(a1 + 20)), *(_DWORD *)(*(_QWORD *)(a1 + 24) + 4LL * (*(_DWORD *)(a1 + 20) + 1)), *(_QWORD *)(a1 + 104), 0); do { blowfish_encrypt( a1, *(_DWORD *)(v5 + *(_QWORD *)(a1 + 104) - 8), *(_DWORD *)(v5 + *(_QWORD *)(a1 + 104) - 4), *(_QWORD *)(a1 + 104), v38); v38 += 2; v5 += 8; } while ( v38 < 1024 ); v41 = 10; while ( 1 ) { blowfish_encrypt(a1, v24, v23, (unsigned int)&v45, 0); if ( !--v41 ) break; v23 = v46; v24 = v45; } v42 = v47; do { blowfish_decrypt(a1, v45, v46, (unsigned int)&v45, 0); --v42; } while ( v42 >= 0 ); if ( v45 || v46 ) { v43 = sub_14002CE50(std::cout, "Blowfish: Self Test 2 failed: decrypt^10(encrypt^10(0)) = "); std::ostream::operator<<(v43, sub_14002DE00); } if ( *(_DWORD *)(a1 + 20) == *(_DWORD *)(a1 + 4) ) { v44 = *(_DWORD **)(a1 + 24); *(_DWORD *)(a1 + 32) = *v44; *(_DWORD *)(a1 + 36) = v44[1]; *(_DWORD *)(a1 + 40) = v44[2]; *(_DWORD *)(a1 + 44) = v44[3]; *(_DWORD *)(a1 + 48) = v44[4]; *(_DWORD *)(a1 + 52) = v44[5]; *(_DWORD *)(a1 + 56) = v44[6]; *(_DWORD *)(a1 + 60) = v44[7]; *(_DWORD *)(a1 + 64) = v44[8]; *(_DWORD *)(a1 + 68) = v44[9]; *(_DWORD *)(a1 + 72) = v44[10]; *(_DWORD *)(a1 + 76) = v44[11]; *(_DWORD *)(a1 + 80) = v44[12]; *(_DWORD *)(a1 + 84) = v44[13]; *(_DWORD *)(a1 + 88) = v44[14]; *(_DWORD *)(a1 + 92) = v44[15]; *(_DWORD *)(a1 + 96) = v44[16]; *(_DWORD *)(a1 + 100) = v44[17]; } sub_14123E010(v50);}void __fastcall blowfish_decrypt_init(__int64 a1, _QWORD *a2){ _OWORD *v3; // rax _OWORD *v4; // rcx __int64 v5; // rdi __int64 v6; // rdx _OWORD *v7; // rax _OWORD *v8; // rcx __int64 v9; // rdx _OWORD *v10; // rax _OWORD *v11; // rcx __int64 v12; // rdx _OWORD *v13; // rax _OWORD *v14; // rcx __int64 v15; // rdx int v16; // edx int v17; // r8d __int64 v18; // rsi int v19; // esi int v20; // ebp __int64 v21; // rax int v22; // r14d int v23; // r15d int v24; // r12d __int64 v25; // rax int v26; // r11d unsigned __int64 v27; // rdx __int64 v28; // r10 _QWORD *v29; // rsi unsigned __int64 v30; // rbp int v31; // ecx int v32; // edx int v33; // r8d int v34; // edx int v35; // r9d int v36; // edx int v37; // ecx int v38; // esi int v39; // r14d __int64 v40; // rbp __int64 v41; // r13 int v42; // r13d __int64 v43; // rax _DWORD *v44; // rdx int v45; // [rsp+30h] [rbp-78h] BYREF int v46; // [rsp+34h] [rbp-74h] int v47; // [rsp+38h] [rbp-70h] _QWORD *v48; // [rsp+40h] [rbp-68h] unsigned __int64 v49; // [rsp+48h] [rbp-60h] void *v50; // [rsp+50h] [rbp-58h] __int64 v51; // [rsp+58h] [rbp-50h] _QWORD *v52; // [rsp+60h] [rbp-48h] v51 = -2; v50 = a2; v52 = a2; if ( a2[3] < 0x10u ) v48 = a2; else v48 = (_QWORD *)*a2; v49 = a2[2]; v3 = *(_OWORD **)(a1 + 104); v4 = &unk_141A6C0D0; v5 = 8; v6 = 8; do { *v3 = *v4; v3[1] = v4[1]; v3[2] = v4[2]; v3[3] = v4[3]; v3[4] = v4[4]; v3[5] = v4[5]; v3[6] = v4[6]; v3 += 8; *(v3 - 1) = v4[7]; v4 += 8; --v6; } while ( v6 ); v7 = (_OWORD *)(*(_QWORD *)(a1 + 104) + 1024LL); v8 = &unk_141A6C4D0; v9 = 8; do { *v7 = *v8; v7[1] = v8[1]; v7[2] = v8[2]; v7[3] = v8[3]; v7[4] = v8[4]; v7[5] = v8[5]; v7[6] = v8[6]; v7 += 8; *(v7 - 1) = v8[7]; v8 += 8; --v9; } while ( v9 ); v10 = (_OWORD *)(*(_QWORD *)(a1 + 104) + 2048LL); v11 = &unk_141A6C8D0; v12 = 8; do { *v10 = *v11; v10[1] = v11[1]; v10[2] = v11[2]; v10[3] = v11[3]; v10[4] = v11[4]; v10[5] = v11[5]; v10[6] = v11[6]; v10 += 8; *(v10 - 1) = v11[7]; v11 += 8; --v12; } while ( v12 ); v13 = (_OWORD *)(*(_QWORD *)(a1 + 104) + 3072LL); v14 = &unk_141A6CCD0; v15 = 8; do { *v13 = *v14; v13[1] = v14[1]; v13[2] = v14[2]; v13[3] = v14[3]; v13[4] = v14[4]; v13[5] = v14[5]; v13[6] = v14[6]; v13 += 8; *(v13 - 1) = v14[7]; v14 += 8; --v15; } while ( v15 ); memcpy(*(void **)(a1 + 24), &unk_141A6C080, 4LL * (*(_DWORD *)(a1 + 20) + 2)); v16 = 0; v45 = 0; v17 = 0; v46 = 0; v18 = 10; while ( 1 ) { blowfish_encrypt(a1, v16, v17, (unsigned int)&v45, 0); if ( !--v18 ) break; v17 = v46; v16 = v45; } v19 = v46; v20 = v45;