fortify sca rules 一直处于加密状态,只有在扫描的时候才会被加载,网上发现已经有大佬破解了,这里分享给大家,jar包知识星球自取,解密代码如下,自行编译即可:
import java.io.*;
import java.nio.file.Files;
import java.security.*;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class Main {
// 定义常量
private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-1"; // 消息摘要算法
private static final String CRYPTO_PROVIDER = "SUN"; // 加密提供者
private static final int BUFFER_SIZE = 262144; // 缓冲区大小
private static final String STD = "1fea047f-dee0ac89-b5db25a6-b0c3a4cf"; // 默认密钥
// 构造函数
public Main() {
}
// 获取消息摘要算法实例
public static MessageDigest getMessageDigestAlgorithm() {
try {
return MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM, CRYPTO_PROVIDER);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
// 计算输入流的摘要
public static byte[] makeDigest(InputStream inStream) throws IOException {
return makeDigest(inStream, getMessageDigestAlgorithm());
}
// 计算输入流的摘要,使用指定的消息摘要算法
public static byte[] makeDigest(InputStream inStream, MessageDigest md) throws IOException {
md.reset();
DigestInputStream in = new DigestInputStream(inStream, md);
return md.digest(); // 返回摘要结果
}
// 加密函数
private static void encrypt(long[] v, long[] k) {
long y = v[0];
long z = v[1];
long sum = 0L;
long delta = 2654435769L; // 常量 delta
long n = 32L; // 迭代次数
long top = 4294967295L; // 掩码
// 加密循环
for (; n-- > 0L; z &= top) {
sum += delta;
sum &= top;
y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
y &= top;
z += (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
}
v[0] = y;
v[1] = z;
}
// 解密函数
private static void decrypt(long[] v, long[] k) {
long n = 32L; // 迭代次数
long y = v[0];
long z = v[1];
long delta = 2654435769L; // 常量 delta
long top = 4294967295L; // 掩码
long sum = delta << 5;
// 解密循环
for (sum &= top; n-- > 0L; sum &= top) {
z -= (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
z &= top;
y -= (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
y &= top;
sum -= delta;
}
v[0] = y;
v[1] = z;
}
// 加密输入流到输出流
private static void enc(InputStream source, OutputStream dest, long[] usrKey) throws IOException {
long[] k = usrKey.clone(); // 克隆密钥
byte[] byteBuf = new byte[8]; // 字节缓冲区
byte[] tail = new byte[]{32, 32, 32, 32, 32, 32, 32, 8}; // 尾部字节
long[] unsigned32Buf = new long[2]; // 无符号32位缓冲区
long top = 4294967295L; // 掩码
int bytesRead;
// 读取输入流并加密
while ((bytesRead = source.read(byteBuf)) != -1) {
if (bytesRead < 8) {
tail[7] = (byte) bytesRead; // 设置尾部字节
}
byteArrayToUnsigned32(byteBuf, unsigned32Buf); // 字节数组转换为无符号32位数组
encrypt(unsigned32Buf, k); // 加密
k[0] = k[0] + 17L & top; // 更新密钥
k[1] = k[1] + 17L & top;
k[2] = k[2] + 17L & top;
k[3] = k[3] + 17L & top;
unsigned32ToByteArray(unsigned32Buf, byteBuf); // 无符号32位数组转换为字节数组
dest.write(byteBuf); // 写入输出流
}
byteArrayToUnsigned32(tail, unsigned32Buf); // 处理尾部字节
encrypt(unsigned32Buf, k);
k[0] = k[0] + 17L & top;
k[1] = k[1] + 17L & top;
k[2] = k[2] + 17L & top;
k[3] = k[3] + 17L & top;
unsigned32ToByteArray(unsigned32Buf, tail);
dest.write(tail); // 写入尾部字节
}
// 解密输入流到输出流
private static void dec(InputStream source, OutputStream dest, long[] usrKey) throws IOException {
long[] k = usrKey.clone(); // 克隆密钥
byte[] byteBuf = new byte[8]; // 字节缓冲区
byte[] byteBufDelay = null; // 延迟字节缓冲区
long[] unsigned32Buf = new long[2]; // 无符号32位缓冲区
long top = 4294967295L; // 掩码
int bytesRead;
// 读取输入流并解密
while ((bytesRead = source.read(byteBuf)) != -1) {
if (bytesRead < 8) {
throw new IOException("invalid encrypted stream"); // 无效的加密流
}
byteArrayToUnsigned32(byteBuf, unsigned32Buf); // 字节数组转换为无符号32位数组
decrypt(unsigned32Buf, k); // 解密
k[0] = k[0] + 17L & top; // 更新密钥
k[1] = k[1] + 17L & top;
k[2] = k[2] + 17L & top;
k[3] = k[3] + 17L & top;
unsigned32ToByteArray(unsigned32Buf, byteBuf); // 无符号32位数组转换为字节数组
if (source.available() == 0) {
int bytesToWrite = byteBuf[7];
if (bytesToWrite > 8 || bytesToWrite < 0 || byteBufDelay == null) {
throw new IOException("invalid encrypted stream"); // 无效的加密流
}
dest.write(byteBufDelay, 0, bytesToWrite); // 写入延迟字节
}
if (byteBufDelay != null) {
dest.write(byteBufDelay, 0, 8); // 写入延迟字节
byte[] t = byteBufDelay;
byteBufDelay = byteBuf;
byteBuf = t;
} else {
byteBufDelay = byteBuf;
byteBuf = new byte[8];
}
}
}
// 执行块加密或解密
private static void doBlockCipher(InputStream source, OutputStream dest, boolean encrypt, long[] usrKey) throws IOException {
if (encrypt) {
enc(source, dest, usrKey); // 加密
} else {
dec(source, dest, usrKey); // 解密
}
}
// 读取加密流中的头部信息
public static void readHeaders(InputStream encrypted) throws IOException {
Properties props = new Properties();
final PushbackInputStream src = new PushbackInputStream(encrypted);
props.load(new InputStream() {
boolean closed = false;
public int read() throws IOException {
if (closed) {
return -1;
} else {
int c = src.read();
if (c == 0) {
src.unread(c);
closed = true;
return -1;
} else {
return c;
}
}
}
});
int read = src.read();
if (read != 0) {
throw new IOException("invalid encrypted stream"); // 无效的加密流
}
}
// 解密并解压缩加密流中的数据
public static byte[] decryptCompressedAfterHeaders(InputStream encrypted, String keyString) throws IOException {
return decryptAfterHeaders(encrypted, keyString, true);
}
// 解密加密流中的数据,可以选择是否解压缩
public static byte[] decryptAfterHeaders(InputStream encrypted, String keyString, boolean compressed) throws IOException {
long[] key = makeKeyFromString(keyString != null ? keyString : STD); // 生成密钥
ByteArrayOutputStream cleartext = new ByteArrayOutputStream();
doBlockCipher(encrypted, cleartext, false, key); // 解密
cleartext.close();
byte[] bytes = cleartext.toByteArray();
if (compressed) {
bytes = uncompressString(bytes); // 解压缩
}
return bytes;
}
// 解密并解压缩加密流中的数据
public static byte[] decryptCompressed(InputStream encrypted, String keyString) throws IOException {
readHeaders(encrypted); // 读取头部信息
return decryptCompressedAfterHeaders(encrypted, keyString);
}
// 加密并压缩明文数据
public static void encryptAndCompress(InputStream cleartext, OutputStream ciphertext, String keyString, Properties properties) throws IOException {
if (properties != null) {
properties.store(ciphertext, null); // 存储属性
}
ciphertext.write(new byte[]{0}); // 写入分隔符
encryptAfterHeaders(cleartext, ciphertext, keyString, true); // 加密并压缩
}
// 加密明文数据,可以选择是否压缩
public static void encryptAfterHeaders(InputStream stream, OutputStream ciphertext, String keyString, boolean compress) throws IOException {
long[] key = makeKeyFromString(keyString != null ? keyString : STD); // 生成密钥
if (compress) {
stream = compressInputStream(stream); // 压缩输入流
}
doBlockCipher(stream, ciphertext, true, key); // 加密
stream.close();
}
// 从字符串生成密钥
private static long[] makeKeyFromString(String keyString) {
long[] k = new long[4];
String[] splitString = new String[4];
StringTokenizer st = new StringTokenizer(keyString, "-");
int i;
for (i = 0; i < splitString.length; ++i) {
if (!st.hasMoreTokens()) {
throw new Error("invalid key"); // 无效的密钥
}
splitString[i] = st.nextToken();
}
for (i = 0; i < 4; ++i) {
try {
k[i] = Long.parseLong(splitString[i], 16); // 解析密钥
} catch (NumberFormatException e) {
throw new Error("invalid key"); // 无效的密钥
}
}
return k;
}
// 解压缩字节数组
private static byte[] uncompressString(byte[] in) throws IOException {
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(in));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int bufferSize = 10240;
byte[] buffer = new byte[bufferSize];
while (true) {
int bytesRead = gis.read(buffer, 0, bufferSize);
if (bytesRead == -1) {
return out.toByteArray(); // 返回解压缩后的数据
}
out.write(buffer, 0, bytesRead);
}
}
// 压缩输入流
private static InputStream compressInputStream(InputStream in) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gz = new GZIPOutputStream(baos);
int bufferSize = 10240;
byte[] buffer = new byte[bufferSize];
int var5 = 0;
while (true) {
int bytesRead = in.read(buffer, 0, bufferSize);
if (bytesRead == -1) {
gz.close();
return new ByteArrayInputStream(baos.toByteArray()); // 返回压缩后的数据
}
gz.write(buffer, 0, bytesRead);
var5 += bytesRead;
}
}
// 字节数组转换为无符号32位数组
public static void byteArrayToUnsigned32(byte[] byteBuf, long[] unsigned32Buf) {
for (int i = 0; i < unsigned32Buf.length; ++i) {
unsigned32Buf[i] = ((long) byteBuf[i * 4] & 255L) + (((long) byteBuf[i * 4 + 1] & 255L) << 8) + (((long) byteBuf[i * 4 + 2] & 255L) << 16) + (((long) byteBuf[i * 4 + 3] & 255L) << 24);
}
}
// 无符号32位数组转换为字节数组
public static void unsigned32ToByteArray(long[] unsigned32Buf, byte[] byteBuf) {
for (int i = 0; i < unsigned32Buf.length; ++i) {
long l = unsigned32Buf[i];
byteBuf[i * 4] = (byte) ((int) (l & 255L));
byteBuf[i * 4 + 1] = (byte) ((int) (l >> 8 & 255L));
byteBuf[i * 4 + 2] = (byte) ((int) (l >> 16 & 255L));
byteBuf[i * 4 + 3] = (byte) ((int) (l >> 24 & 255L));
}
}
// 解密文件
public static void decryptFile(File src, File dst) throws Exception {
InputStream inputStream = Files.newInputStream(src.toPath());
byte[] rule = decryptCompressed(inputStream, null); // 解密并解压缩
OutputStream outputStream = Files.newOutputStream(dst.toPath());
outputStream.write(rule); // 写入解密后的数据
outputStream.close();
}
// 主函数
public static void main(String[] args) throws Exception {
String rulesDir = "F:\rules\2024.2.1.0003-zh_CN\rules";
String decryptDir = "F:\rules\2024.2.1.0003-zh_CN\decrypt";
File file = new File(rulesDir);
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
if (f.getName().endsWith(".bin")) {
decryptFile(f, new File(decryptDir + "/" + f.getName() + ".xml")); // 解密文件
}
}
} else {
decryptFile(file, new File(decryptDir + "/" + file.getName() + ".xml")); // 解密文件
}
}
}
原文始发于微信公众号(代码审计SDL):fortify sca rules分析