算法逆向

Base64

简单说,就是将3个8位的字节重新划分为4个6位字节,然后在每个字节的前面补2位0,然后算出其十进制数并将其与下面字符对应,例:其中一个四位为101010,则变为00101010(42),对应q

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
编号字符 编号字符编号	字符	编号字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

注:索引表不是唯一的

Tea

关键就是获取magic并将其赋值给delta

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i < 32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
} /* end cycle */
v[0]=v0; v[1]=v1;
}

void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}

MD5

产生128位(16字节)的散列值

显著特征是存在4个变量 h0=0x67452301 h1=0xefcdab89 h2=0x98badcfe h3=0x10325476

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
var int[64] r, k

//r specifies the per-round shift amounts
r[ 0..15]:= {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22}
r[16..31]:= {5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20}
r[32..47]:= {4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23}
r[48..63]:= {6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}

//Use binary integer part of the sines of integers as constants:
for i from 0 to 63
k[i] := floor(abs(sin(i + 1)) × 2^32)

//Initialize variables:
var int h0 := 0x67452301
var int h1 := 0xEFCDAB89
var int h2 := 0x98BADCFE
var int h3 := 0x10325476

//Pre-processing:
append "1" bit to message
append "0" bits until message length in bits ≡ 448 (mod 512)
append bit length of message as 64-bit little-endian integer to message

//Process the message in successive 512-bit chunks:
for each 512-bit chunk of message
break chunk into sixteen 32-bit little-endian words w[i], 0 ≤ i ≤ 15

//Initialize hash value for this chunk:
var int a := h0
var int b := h1
var int c := h2
var int d := h3

//Main loop:
for i from 0 to 63
if 0 ≤ i ≤ 15 then
f := (b and c) or ((not b) and d)
g := i
else if 16 ≤ i ≤ 31
f := (d and b) or ((not d) and c)
g := (5×i + 1) mod 16
else if 32 ≤ i ≤ 47
f := b xor c xor d
g := (3×i + 5) mod 16
else if 48 ≤ i ≤ 63
f := c xor (b or (not d))
g := (7×i) mod 16

temp := d
d := c
c := b
b := leftrotate((a + f + k[i] + w[g]),r[i]) + b
a := temp
Next i
//Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
End ForEach var int digest := h0 append h1 append h2 append h3 //(expressed as little-endian)

BUUCTF技巧

目前做的几道题都是先检查一下有没有壳,有的话脱一下外壳,然后扔进IDA,基本上flag都出来了

reverse 3

主要是介绍一下64解码代码怎么写

main_0函数,从下往上看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
const char *v4; // eax
size_t v5; // eax
char v7; // [esp+0h] [ebp-188h]
char v8; // [esp+0h] [ebp-188h]
signed int j; // [esp+DCh] [ebp-ACh]
int i; // [esp+E8h] [ebp-A0h]
signed int v11; // [esp+E8h] [ebp-A0h]
char Destination[108]; // [esp+F4h] [ebp-94h] BYREF
char Str[28]; // [esp+160h] [ebp-28h] BYREF
_BYTE v14[8]; // [esp+17Ch] [ebp-Ch] BYREF

for ( i = 0; i < 100; ++i )
{
if ( (unsigned int)i >= 0x64 )
j____report_rangecheckfailure();
Destination[i] = 0;
}
sub_41132F("please enter the flag:", v7); //我们输入flag
sub_411375("%20s", (char)Str);
v3 = j_strlen(Str);
v4 = (const char *)sub_4110BE((int)Str, v3, (int)v14);
strncpy(Destination, v4, 0x28u); //点进去是64编码,太长了就不点了
v11 = j_strlen(Destination);
for ( j = 0; j < v11; ++j )
Destination[j] += j; //将其与该位置的索引相减,v11为destination长度
v5 = j_strlen(Destination);
if ( !strncmp(Destination, Str2, v5) ) //将我们获取到的destination与str2比较,对的话就是获取flag成功,那就找destination位置
sub_41132F("rigth flag!\n", v8);
else
sub_41132F("wrong flag!\n", v8);
return 0;
}

很明显了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(lion㉿kali)-[~]
└─$ python
Python 3.13.9 (main, Oct 15 2025, 14:56:22) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> str='e3nifIH9b_C@n@dH'
>>> flag=''
>>> for i in range(len(str)):
... flag+=chr(ord(str[i])-i) //减去那个j
...
>>> print(flag)
e2lfbDB2ZV95b3V9 //获得了剪完的destination
>>> flag=base64.b64decode(flag)
>>> print(flag)
b'{i_l0ve_you}' //解64码了
>>> flag=flag.decode('ASCII') //将起改为正宗的ASCII
>>> print(flag)
{i_l0ve_you}
>>>