PE文件中,一些固定的整数也可能是一种静态特征,比如比较特定的整数大小,API hash的值等等。我们也可以使用类似字符串的加解密方法,来实现编译时加密整数,运行时解密。
下面是一个GitHub上不错的项目,crystr https://github.com/android1337/crystr,介绍其中的crynum和crynum_long,并测试实际效果。
以下代码分析部分由Grok3生成,这里不得说一句,大模型的发展确实提高了工作的效率。
crynum
和 crynum_long
是两个用于加密数字的宏,它们基于 crys::cryNum
模板类实现。它们的主要区别在于支持的数字类型和加密方式的细节。下是对这两个宏的详细解析:
1. crynum
宏
定义
#define crynum(num) []() { constexpr thread_local auto val = num; constexpr static auto const_str = crys::cryNum <const_hash(__DATE__ __TIME__, __COUNTER__), decltype(val)>(std::bit_cast<unsigned int, decltype(val)>(num)); return const_str; }()
- 功能
: 用于加密一个数字(通常是 32 位整数类型,如 int
或unsigned int
)。 - 输入
: num
是需要加密的数字。 - 返回
: 返回一个 crys::cryNum
类的实例,封装了加密后的数字。
分解
- 匿名函数
:
-
使用 Lambda 表达式 []()
创建一个匿名函数,确保每次调用时返回的对象是独立的。 -
返回值是一个 crys::cryNum
实例。
- 模板参数
:
const_hash(__DATE__ __TIME__, __COUNTER__)
: 生成一个编译期唯一的 64 位整数作为 uniqueid
。
__DATE__ __TIME__
: 编译时的日期和时间字符串。 __COUNTER__
: 编译器内置计数器,每次使用时递增。
decltype(val)
: 推导 num
的类型(如int
或unsigned int
)。
- 加密过程
:
std::bit_cast<unsigned int, decltype(val)>(num)
: 将输入的 num
转换为 32 位无符号整数。-
传递给 crys::cryNum
构造函数,执行加密。
使用示例
auto encrypted = crynum(42);int decrypted = encrypted.decrypt(); // 解密后得到 42
-
输入 42
被加密为一个cryNum
对象,调用decrypt()
后返回原始值。
2. crynum_long
宏
定义
#define crynum_long(num) []() { constexpr thread_local auto val = num; constexpr static auto const_str = crys::cryNum <const_hash(__DATE__ __TIME__, __COUNTER__), decltype(val)>(std::bit_cast<unsigned long long, decltype(val)>(num)); return const_str; }()
- 功能
: 用于加密一个长整数(通常是 64 位整数类型,如 long long
或unsigned long long
)。 - 输入
: num
是需要加密的数字。 - 返回
: 返回一个 crys::cryNum
类的实例,封装了加密后的 64 位数字。
分解
- 匿名函数
:
-
与 crynum
相同,使用 Lambda 表达式封装加密逻辑。
- 模板参数
:
const_hash(__DATE__ __TIME__, __COUNTER__)
: 与 crynum
相同,生成唯一的 64 位uniqueid
。decltype(val)
: 推导 num
的类型(如long long
或unsigned long long
)。
- 加密过程
:
std::bit_cast<unsigned long long, decltype(val)>(num)
: 将输入的 num
转换为 64 位无符号整数。-
传递给 crys::cryNum
构造函数,执行加密。
使用示例
auto encrypted = crynum_long(12345678901234LL);long long decrypted = encrypted.decrypt(); // 解密后得到 12345678901234
-
输入一个 64 位整数,被加密为 cryNum
对象,解密后返回原始值。
3. crys::cryNum
类的实现
crynum
和 crynum_long
都依赖于 crys::cryNum
模板类。以下是其核心实现:
模板参数
uniqueid
: 编译期生成的唯一标识符。 T
: 数字的类型(如 int
或long long
)。
构造函数
__forceinline constexpr cryNum(unsigned long long value){ // 生成密钥并加密 value auto v = uniqueid * double((3.1415926535897932f / (180.f)) / 2.f); auto y = v - (2.0f * 3.1415926535897932f) * double((0.31830988618f * 0.5f) * v + 0.5f); // ... (复杂的数学运算生成 z 和 w) data = value ^ std::bit_cast<unsigned long long>(z * y + w);}
- 输入
: 一个 64 位无符号整数 value
(由宏中的std::bit_cast
提供)。 - 加密
: 使用数学运算生成密钥,然后通过 XOR 将 value
加密,存储到data
。
解密方法
__forceinline T decrypt(){ thread_local auto ret = xor_decrypt(); return *(T*)&ret;}
-
调用 xor_decrypt()
,返回解密后的 64 位值,再通过类型转换返回原始类型T
。
密钥生成
get_xor_key()
: 与构造函数类似,使用 uniqueid
通过三角函数近似生成相同的密钥。xor_decrypt()
: 使用密钥对 data
进行 XOR 操作,返回解密结果。
4. crynum
与 crynum_long
的区别
原文始发于微信公众号(红蓝对抗技战术):杀软静态对抗-去除敏感整数
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论