魔数前增加恶意头检测
This commit is contained in:
parent
ed88ad03cf
commit
3540ecc3aa
|
|
@ -143,7 +143,13 @@ object ProxyServer {
|
||||||
producerJob += CoroutineScope(Dispatchers.IO).launch {
|
producerJob += CoroutineScope(Dispatchers.IO).launch {
|
||||||
// 异步下载数据块
|
// 异步下载数据块
|
||||||
val data = getVideoStream(chunkStart, chunkEnd, url, headers)
|
val data = getVideoStream(chunkStart, chunkEnd, url, headers)
|
||||||
|
//如果是0开始,且检测到恶意头,那么就把数据截断
|
||||||
|
if (chunkStart == 0L) {
|
||||||
|
val offset = detectMaliciousPrefix(data)
|
||||||
|
channels[i].send(data.copyOfRange(offset, data.size))
|
||||||
|
} else {
|
||||||
channels[i].send(data)
|
channels[i].send(data)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
currentStart = chunkEnd + 1
|
currentStart = chunkEnd + 1
|
||||||
|
|
@ -169,7 +175,64 @@ object ProxyServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun detectMaliciousPrefix(data: ByteArray): Int {
|
||||||
|
|
||||||
|
|
||||||
|
val buffer = ByteArray(64) // 读取前64字节足够
|
||||||
|
ByteArrayInputStream(data).use { fis ->
|
||||||
|
fis.read(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否以合法魔数开头
|
||||||
|
if (isValidVideoHeader(buffer)) {
|
||||||
|
return 0 // 正常,无恶意前缀
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在后续位置查找合法魔数(比如最多跳过前256字节)
|
||||||
|
val searchLimit = minOf(256, data.size)
|
||||||
|
val searchBuffer = ByteArray(searchLimit)
|
||||||
|
ByteArrayInputStream(data).use { fis ->
|
||||||
|
fis.read(searchBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试从偏移1开始查找合法视频头
|
||||||
|
for (offset in 1 until searchLimit - 16) {
|
||||||
|
if (isValidVideoHeader(searchBuffer, offset)) {
|
||||||
|
SpiderDebug.log("发现合法视频头位于偏移 $offset,疑似被插入恶意前缀!")
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 // 未找到合法头,可能是损坏或非视频文件
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断从指定偏移开始是否是合法视频头
|
||||||
|
fun isValidVideoHeader(data: ByteArray, offset: Int = 0): Boolean {
|
||||||
|
if (data.size - offset < 8) return false
|
||||||
|
|
||||||
|
// MP4 / MOV: ... ftyp
|
||||||
|
if (offset + 8 <= data.size && data[offset + 4].toInt() == 0x66 && // 'f'
|
||||||
|
data[offset + 5].toInt() == 0x74 && // 't'
|
||||||
|
data[offset + 6].toInt() == 0x79 && // 'y'
|
||||||
|
data[offset + 7].toInt() == 0x70 // 'p'
|
||||||
|
) {
|
||||||
|
// 还可进一步校验前4字节是否为合法 size(>=8 且合理)
|
||||||
|
val size =
|
||||||
|
(data[offset].toLong() and 0xFF shl 24) or (data[offset + 1].toLong() and 0xFF shl 16) or (data[offset + 2].toLong() and 0xFF shl 8) or (data[offset + 3].toLong() and 0xFF)
|
||||||
|
if (size >= 8 && size <= 0x100000) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// AVI: RIFF
|
||||||
|
if (offset + 4 <= data.size && data[offset] == 0x52.toByte() && data[offset + 1] == 0x49.toByte() && data[offset + 2] == 0x46.toByte() && data[offset + 3] == 0x46.toByte()) return true
|
||||||
|
|
||||||
|
// MKV
|
||||||
|
if (offset + 4 <= data.size && data[offset] == 0x1A.toByte() && data[offset + 1] == 0x45.toByte() && data[offset + 2] == 0xDF.toByte() && data[offset + 3] == 0xA3.toByte()) return true
|
||||||
|
|
||||||
|
// FLV
|
||||||
|
if (offset + 4 <= data.size && data[offset] == 0x46.toByte() && data[offset + 1] == 0x4C.toByte() && data[offset + 2] == 0x56.toByte() && data[offset + 3] == 0x01.toByte()) return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
private fun queryToMap(query: String?): Map<String, String>? {
|
private fun queryToMap(query: String?): Map<String, String>? {
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
return null
|
return null
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue