計算 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函式字串
- 函式計算——應用初探函式
- leetcode 224. 基本計算器(逆波蘭表示式)LeetCode
- 從雲端計算到函式計算函式
- 基於函式計算的 BFF 架構函式架構
- matchTemplate函式各個方法的計算公式函式公式
- 逆波蘭計算器
- 外層函式的變數直接被巢狀函式引用計算函式變數巢狀
- 遷移 Express 到函式計算Express函式
- 溫溼度計算露點函式函式
- C語言程式設計>第八週 ② 編寫函式fun,函式的功能是:根據以下公式計算,計算結果作為函式值返回。C語言程式設計函式公式
- pycuda-一些計算函式函式
- 遷移 Spring Boot 到函式計算Spring Boot函式
- 函式計算-HelloWorld應用開發函式
- 部署基於pythonwsgiweb框架的工程到函式計算PythonWeb框架函式
- Serverless 在阿里雲函式計算中的實踐Server阿里函式
- 陣列操作,計算組元素的極值函式陣列函式
- 函式計算Python連線SQLServer小結函式PythonSQLServer
- 阿里雲 函式計算 域名配置問題阿里函式
- Serverless 實戰 —— 函式計算 + Typescript 實踐Server函式TypeScript
- 函式計算支援 MySQL 例項繫結函式MySql
- Serverless 解惑——函式計算如何安裝字型Server函式
- 筆記:PostgreSQL 、Node.js 、函式計算筆記SQLNode.js函式
- IDA 逆 WDF 驅動時的函式識別外掛函式
- 開發函式計算的正確姿勢 —— 爬蟲函式爬蟲
- 白話講解函式計算中的角色授權函式
- matlab符號函式的求導與差分的計算Matlab符號函式求導
- MySql中SUM函式計算錯誤問題MySql函式
- 阿里雲函式計算 VSCode 使用,及部署 Docusaurus阿里函式VSCode
- 函式計算實踐——一個應用案例函式
- NumPy常用的位運算函式函式
- C#資料結構與演算法系列(十):逆波蘭計算器——逆波蘭表示式(字尾表示式)C#資料結構演算法
- 大神是怎樣用函式式JavaScript計算陣列平均值的函式JavaScript陣列
- 從零入門 Serverless | 函式計算的可觀測性Server函式
- 開發函式計算的正確姿勢——OCR 服務函式
- 如何計算PHP函式中傳遞的引數數量PHP函式
- fork函式的學習--深入瞭解計算機系統函式計算機
- C語言:使用函式計算兩點間的距離C語言函式