Reverse_CheckList

凯撒解密 (IF 判断 ASCII,移位)

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
__int64 __fastcall encode_three(const char *a1, int a2, char *a3, int *a4)
{
char v5; // [rsp+Fh] [rbp-11h]
int i; // [rsp+14h] [rbp-Ch]
const char *v8; // [rsp+30h] [rbp+10h]

v8 = a1;
if ( !a1 || !a2 )
return 0xFFFFFFFFi64; //不用管
for ( i = 0; i < a2; ++i )
{
v5 = *v8;
//可以先从最里面开始逆向,方便阅读
if ( *v8 <= 64 || v5 > 90 ) //大写字母 (大写字母不包括,所以else中才是大写字母移位的操作)
{
if ( v5 <= 96 || v5 > 122 ) //小写字母
{
if ( v5 <= 47 || v5 > 57 ) //如果是非0-9的字符
*a3 = v5; //直接移位
else
*a3 = (v5 - 48 + 3) % 10 + 48; //数字移位
}
else
{
*a3 = (v5 - 97 + 3) % 26 + 97; //小写字母移位
}
}
else
{
*a3 = (v5 - 65 + 3) % 26 + 65; //大写字母移位
}
++a3;
++v8;
}
return 0i64;
}

移位操作,+3 移位需要都改成 -3, 反着来, 先进行 else , 解密脚本

  • 伪代码没有= ,不输出时可以尝试加上=,一般要加=
  • 记得变符号
  • 没有最后的else就不管他
1
2
3
4
5
6
7
8
9
for i in data:
    if ord(i) >= 48 and ord(i) <= 57: # 记得加等于, 即使伪代码没有写
        data1 += chr((ord(i) - 48 - 3 ) % 10 + 48)
    elif ord(i) >= 97 and ord(i) <= 122:
        data1 += chr((ord(i) - 97 - 3) % 26 + 97)
    elif ord(i) >= 65 and ord(i) <= 90:
        data1 += chr((ord(i) - 65 - 3) % 26 + 65)
    else: # 有些伪代码可能没有else: 那就不写else呗
        data1 += i;

TEA 系列 (DELTA,左移右移)

  • TEA / XTEA
    特征:
    0x9e3779b9 DELTA
    左移4和右移5
1
2
3
4
5
6
7
// 加密核心代码
for (i=0; i<32; i++) {
v1 += ((v0<<4) + k2) ∧ (v0 + sum) ∧ ((v0>>5) + k3); // 右侧异或可以理解为是常数, v1 += const
v0 += ((v1<<4) + k0) ∧ (v1 + sum) ∧ ((v1>>5) + k1);
sum += 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
#include <stdint.h>
#include <stdio.h>

void encrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (i=0; i < num_rounds; i++) {
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        sum += delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
    }
    v[0]=v0; v[1]=v1;
}

void decrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}
  • XXTEA
    特征:
    右移5,左移2,右移3,左移4
    有固定 DELTA 值: 0x9e3779b9
    [+]解密脚本
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
#include <stdio.h>
#include <stdbool.h>

#define MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[(p & 3) ^ e] ^ z)
bool xxtea(unsigned int* v, int n, unsigned int* k) {
    unsigned int z = v[n - 1], y = v[0], sum = 0, e, DELTA = 0x9e3779b9; //注意DELTA值!
    unsigned int p, q;
    if (n > 1) { /* Coding Part */
        q = 6 + 52 / n;
        while (q-- > 0) {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p = 0; p < n - 1; p++)
                y = v[p + 1], z = v[p] += MX;
            y = v[0];
            z = v[n - 1] += MX;
        }
        return 0;
    }
    else if (n < -1) { /* Decoding Part */
        n = -n;
        q = 6 + 52 / n;
        sum = q * DELTA;
        while (sum != 0) {
            e = (sum >> 2) & 3;
            for (p = n - 1; p > 0; p--)
                z = v[p - 1], y = v[p] -= MX;
            z = v[n - 1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        return 0;
    }
    return 1;
}

int main(int argc, char const* argv[]) {
    unsigned int v[35] = {
        3880694563u, 3081185334u, 1506439138u, 2524759489u,
        3883935348u, 1026381030u, 2325545814u, 2581382044u,
        1881594093u, 1781792173u, 4103492874u, 1553756062u,
        468045900u, 1730391575u, 1383114178u, 2890011402u,
        2227070898u, 1885128569u, 1548828056u, 4214676013u,
        571971141u, 1558401693u, 3515474427u, 3898332297u,
        1942540575u, 1421197718u, 3061626000u, 555214026u,
        2648963476u, 794468778u, 2816999933u, 3272437419u,  
        464379036u, 877899850u, 2460223225u //解密的数据
    };
    unsigned int key[4] = { 1, 2, 3, 4 };   //key值
    xxtea(v, -35, key);   //-35: 35为35位(strlen),负号为解密,不加则是加密
    for (int i = 0; i < 35; i++)
        printf("%c", v[i]);  //依次打印
}

也可尝试此解密脚本 (大小端序?)

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
#include <stdbool.h>
#include <stdio.h>
#define MX (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)) ^ (sum ^ y) + (k[(p & 3) ^ e] ^ z))
bool btea(unsigned int *v, int n, unsigned int *k)
{
unsigned int z = v[n - 1], y = v[0], sum = 0, e, DELTA = 0x61C88647; //May Change This
unsigned int p, q;
if (n > 1)
{ /* enCoding Part */
q = 415 / n + 114; //May Chnage This
while (q-- > 0)
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < (n - 1); p++)
{
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
}
return 0;
}
else if (n < -1)
{ /* Decoding Part */
n = -n;
q = 415 / n + 114; //May Change This
sum = -q * DELTA; //different
while (sum != 0)
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum += DELTA; //different
}
return 0;
}
return 1;
}

int main()
{
unsigned int v[11] = {0x480AC20C, 0xCE9037F2, 0x8C212018, 0xE92A18D, 0xA4035274, 0x2473AAB1, 0xA9EFDB58, 0xA52CC5C8, 0xE432CB51, 0xD04E9223, 0x6FD07093}, key[4] = {0x79696755, 0x67346F6C, 0x69231231, 0x5F674231};
int n = 11; // n为要加密的数据个数
btea(v, -n, key); // 取正为加密,取负为解密
char *p = (char *)v;
for (int i = 0; i < 44; i++)
{
printf("%c", *p);
p++;
}
return 0;
}
//flag{efccf8f0-0c97-12ec-82e0-0c9d9242e335}

RC4 (多次256循环以及模256)

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
import base64

def rc4_main(key = "init_key", message = "init_message"):
print("RC4解密主函数调用成功")
print('\n')
s_box = rc4_init_sbox(key)
crypt = rc4_excrypt(message, s_box)
return crypt

def rc4_init_sbox(key):
s_box = list(range(256))
print("原来的 s 盒:%s" % s_box)
print('\n')
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
print("混乱后的 s 盒:%s"% s_box)
print('\n')
return s_box

def rc4_excrypt(plain, box):
print("调用解密程序成功。")
print('\n')
plain = base64.b64decode(plain.encode('utf-8'))
plain = bytes.decode(plain)
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))

print("res用于解密字符串,解密后是:%res" %res)
print('\n')
cipher = "".join(res)
print("解密后的字符串是:%s" %cipher)
print('\n')
print("解密后的输出(没经过任何编码):")
print('\n')
return cipher

a = [0xc6,0x21,0xca,0xbf,0x51,0x43,0x37,0x31,0x75,0xe4,0x8e,0xc0,0x54,0x6f,0x8f,0xee,0xf8,0x5a,0xa2,0xc1,0xeb,0xa5,0x34,0x6d,0x71,0x55,0x8,0x7,0xb2,0xa8,0x2f,0xf4,0x51,0x8e,0xc,0xcc,0x33,0x53,0x31,0x0,0x40,0xd6,0xca,0xec,0xd4 ]
# 不能有空格, 为汇编中的原数据
# mov [rbp+var_50], 0C6h 中的0xC6

key = "Nu1Lctf233"
s = ""

for i in a:
s += chr(i)

s = str(base64.b64encode(s.encode('utf-8')), 'utf-8')
print(s)

rc4_main(key, s)

RSA (C,N,E)

可能会出现 __gmpz_powm(v6, v6, v5, v4); 这类伪代码,v6 的 v5方模 v4赋值给 v6
并且有明显特征的:

1
2
3
4
__gmpz_init_set_str(v7, "ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16LL);    (需改写成0xad93...)
__gmpz_init_set_str(v4, "103461035900816914121390101299049044413950405173712170434161686539878160984549", 10LL);
__gmpz_init_set_str(v5, "65537", 10LL);
__gmpz_powm(v6, v6, v5, v4);

v4就是 N ,分解出 p / q : http://www.factordb.com/
稍短的 v5就是 E

解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
import gmpy2
import binascii

p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
e = 65537
d = gmpy2.invert(e, (p - 1) * (q - 1))
m = gmpy2.powmod(c, d, n)
# print(binascii.unhexlify(hex(m)[2:]).decode(encoding="utf-8"))
print (hex(m)[2:])  # 需要HEX to String

Others

  • LL 结尾为长整型(Long Long),小端存储,IDA 按 R 转换为 Char 类型需要进行逆序
  • Main 函数有 if () 判断条件后直接跟输出 flag 函数的,可以尝试动调绕过 if 直接输出关键函数,具体在于比较改为