計算 CRC32 的逆函式
本月初我寫了一篇文章“加密的壓縮包”,說是一道 CTF 題需要根據已知的 CRC32 值反向破解文字檔案(6 bytes)的內容。當時是暴力破解。總共需要破解 3 個 CRC32 值,暴力破解 1 個 CRC32 值平均需要 5 個多小時,還好我的計算機有 4 個邏輯 CPU,可以同時破解這 3 個 CRC32 值。
後來,根據我同事的解題方法,知道可以計算 CRC32 的逆函式。我們把明文儲存在一個長度為 6 的 byte 陣列中,該陣列的前 2 個位元組遍歷所有可能的明文字元,然後根據給定的 CRC32 值(以及該陣列的前 2 個位元組)計算逆函式,填入該陣列的後 4 個位元組,然後判斷它們是否在明文字元範圍內。這個方法只需要 0.1 秒。
- 暴力破解的計算量:656 = 75,418,890,625
- 計算逆函式計算量:652 = 4225
這個方法如下所示:
$ csc reversecrc32.cs ~/src/apps/lib/Crc32.cs
$ mono reversecrc32.exe 4B10DEBA
$ mono reversecrc32.exe 1FD8A07A
$ mono reversecrc32.exe E7F7E18C
當然,明文的長度不必須是 6 個字元,不論是上篇文章的暴力破解,還是這篇文章的計算 CRC32 的逆函式,都很容易修改以適應其他明文長度,或者明文有特定的字首或字尾等情況。
下面是相應的 C# 源程式:
reversecrc32.cs:
using System;
using System.Text;
using System.Collections.Generic;
using Skyiv.Utils;
static class ReverseCrc32
{
static readonly Encoding ascii = new ASCIIEncoding();
static readonly HashSet<byte> a = new HashSet<byte>();
static ReverseCrc32()
{
for (var i = '0'; i <= '9'; i++) a.Add((byte)i);
for (var i = 'A'; i <= 'Z'; i++) a.Add((byte)i);
for (var i = 'a'; i <= 'z'; i++) a.Add((byte)i);
a.Add((byte)'+'); a.Add((byte)'/'); a.Add((byte)'=');
}
static bool Valid(byte[] bs)
{
foreach (var b in bs) if (!a.Contains(b)) return false;
return true;
}
static void Main(string[] args)
{
var z = Convert.ToUInt32(args[0], 16);
var bs = new byte[6];
foreach (var i in a)
foreach (var j in a) {
bs[0] = i; bs[1] = j;
bs.ReverseCrc32(z, 2);
if (Valid(bs)) Console.WriteLine("{0}", ascii.GetString(bs));
}
}
}
Crc32.cs:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Skyiv.Utils
{
public static class Crc32
{
static readonly uint[] t1 = new uint[256];
static readonly uint[] t2 = new uint[256];
static Crc32()
{
uint p = 0xEDB88320;
for (uint f, r, j, i = 0; i < t1.Length; t1[i] = f, t2[i] = r, i++)
for (f = i, r = i << 24, j = 8; j > 0; j--) {
f = ((f & 1) == 0) ? (f >> 1) : ((f >> 1) ^ p);
r = ((r & 0x80000000) == 0) ? (r << 1) : (((r ^ p) << 1) | 1);
}
}
public static void ReverseCrc32(this byte[] bs, uint crc, int n)
{
if (bs.Length < n + 4) return;
uint z = 0xFFFFFFFF;
for (int i = 0; i < n; i++) z = (z >> 8) ^ t1[(z ^ bs[i]) & 0xFF];
Array.Copy(BitConverter.GetBytes(z), 0, bs, n, 4);
z = crc ^ 0xFFFFFFFF;
for (int i = bs.Length-1; i >= n; i--) z = (z<<8)^t2[z>>24]^bs[i];
Array.Copy(BitConverter.GetBytes(z), 0, bs, n, 4);
}
public static uint GetCrc32<T>(this IEnumerable<T> bs)
{
return ~bs.Aggregate(0xFFFFFFFF, (r, b) =>
(t1[(r & 0xFF) ^ Convert.ToByte(b)] ^ (r >> 8)));
}
}
}
參考資料
相關文章
- PHP 每日一函式 — 字串函式 crc32 ()PHP函式字串
- 計算日期的函式函式
- 逆波蘭計算器
- 【機器學習】SVM核函式的計算機器學習函式
- Java計算器(使用逆波蘭表示式演算法)Java演算法
- 從雲端計算到函式計算函式
- 計算幾何常用的函式/方法函式
- 萬能的計算日期函式(轉)函式
- 函式計算——應用初探函式
- Mysql中日期計算函式MySql函式
- 基於函式計算的 BFF 架構函式架構
- matchTemplate函式各個方法的計算公式函式公式
- 外層函式的變數直接被巢狀函式引用計算函式變數巢狀
- 遷移 Express 到函式計算Express函式
- 溫溼度計算露點函式函式
- leetcode 224. 基本計算器(逆波蘭表示式)LeetCode
- 計算誤差函式的積分--erf(x)函式
- 使用oracle utl_raw作為dump的逆函式Oracle函式
- pycuda-一些計算函式函式
- 函式計算-HelloWorld應用開發函式
- C#資料結構與演算法系列(十):逆波蘭計算器——逆波蘭表示式(字尾表示式)C#資料結構演算法
- C語言程式設計>第八週 ② 編寫函式fun,函式的功能是:根據以下公式計算,計算結果作為函式值返回。C語言程式設計函式公式
- 逆波蘭計算器分析和實現
- 陣列操作,計算組元素的極值函式陣列函式
- Shell 計算明天和昨天日期的函式(轉)函式
- SQL 10 函式 3 日期時間函式 - 5 計算日期差額SQL函式
- 函式計算支援 MySQL 例項繫結函式MySql
- Serverless 解惑——函式計算如何安裝字型Server函式
- 遷移 Spring Boot 到函式計算Spring Boot函式
- Serverless 實戰 —— 函式計算 + Typescript 實踐Server函式TypeScript
- 筆記:PostgreSQL 、Node.js 、函式計算筆記SQLNode.js函式
- Oracle 函式大全(字串函式,數學函式,日期函式,邏輯運算函式,其他函式)Oracle函式字串
- 開發函式計算的正確姿勢 —— 爬蟲函式爬蟲
- 白話講解函式計算中的角色授權函式
- Serverless 在阿里雲函式計算中的實踐Server阿里函式
- 部署基於pythonwsgiweb框架的工程到函式計算PythonWeb框架函式
- WPS文字的表格中進行函式公式計算函式公式
- 資料庫中Date型別的計算 DATEDIFF() 函式資料庫型別函式