Re:从零开始的逆向生活 01day

目录

前言

Base64

TEA

RC4

MD5


前言

对自己逆向学习的一个小小的记录与整理,定期更新博客并回头修订

对于纯萌新来说可能会有点难度,不懂的建议私信拷打(大哭,真的不知道怎么写

第一次写这类博客,经验欠缺,请务必谅解


逆向中常见的编码和或算法

Base64,TEA,MD5,RC4(按能力学多少算多少)

AES,DES,RSA,sm4,angr,z3(受编者能力所限,暂时不讲)

参考资料:常见加密算法和编码识别 - CTF Wiki (ctf-wiki.org)

Base64

Base编码有很多:Base16,Base32,Base64,Base85,Base36,Base 58,Base91,Base 92,Base62。最重要的是Base64。

#include <iostream>
#include <cstring>
#include <stdlib.h>

using namespace std;

const char base64_table[] ="qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD";

void decode(string input, char* output) {
    int i = 0, j = 0;
    int length = input.length();

    while (i < length) {
        int index1 = strchr(base64_table, input[i++]) - base64_table;
        int index2 = strchr(base64_table, input[i++]) - base64_table;
        int index3 = strchr(base64_table, input[i++]) - base64_table;
        int index4 = strchr(base64_table, input[i++]) - base64_table;
        
        output[j++] = ((index1 << 2) | (index2 >> 4));

        if (index3 != 64) {
            output[j++] = (((index2 & 15) << 4) | (index3 >> 2));
            if (index4 != 64) {
                output[j++] = (((index3 & 3) << 6) | index4);
            }
        }
    }
    output[j] = '\0';
}

int main() {
    string encoded = "a5mc58bphliax7j";
    int length = (int)(encoded.length()*0.75); 
// Base64 编码后的字符串长度为输入字符数的 4/3
    char* decoded = (char*) malloc(length + 1); // 分配内存

    decode(encoded, decoded);
    cout << decoded << endl;
    free(decoded);

    return 0;
}

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。

如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:1.先使用0字节值在末尾补足,使其能够被3整除,然后再进行Base64的编码。2.在编码后的Base64文本后加上一个或两个=号,代表补足的字节数。

魔改:换表+自定义结构 

参考资料:

Base系列编码浅析【base16 base32 base64 base85 base36 base 58 base91 base 92 base62】 - 0yst3r - 博客园 (cnblogs.com)

TEA

该系列共有三种算法,TEA --> XTEA -->XXTEA,从右往左依次是前面的升级版。

#include <stdio.h>
#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k) {
    uint32_t sum = 0;  // 注意sum也是32位无符号整型
    uint32_t v0 = v[0], v1 = v[1];
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

    for (int i=0; i<32; i++) {
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
    }
    v[0]=v0;
    v[1]=v1;
}

void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1];
    uint32_t delta = 0x9e3779b9;
    uint32_t sum = delta * 32;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

    for (int i=0; i<32; i++) {
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }
    v[0]=v0;
    v[1]=v1;
}
// test

int main(){
    // 两个32位无符号整数,即待加密的64bit明文数据
    uint32_t v[2] = {0x12345678, 0x78563412};
    // 四个32位无符号整数,即128bit的key
    uint32_t k[4]= {0x1, 0x2, 0x3, 0x4};

    printf("Data is : %x %x\n", v[0], v[1]);
    encrypt(v, k);
    printf("Encrypted data is : %x %x\n", v[0], v[1]);
    decrypt(v, k);
    printf("Decrypted data is : %x %x\n", v[0], v[1]);
    
    return 0;

}
/*
Data is : 12345678 78563412
Encrypted data is : 9a65a69a 67ed00f6
Decrypted data is : 12345678 78563412
*/

微型加密算法(Tiny Encryption Algorithm,TEA)是一种分组加密算法,此系列算法都使用0x9E3779B9作为倍数。有时该常数会以减法的形式出现,-0x61C88647=0x9E3779B9。代码中均使用64bit(8byte)的明文作为加密数据,采用128bit(16byte)的值作为key,算法采用迭代的形式,这里采用32轮。

共同特征就是会有移位和异或的操作,逻辑、数据、个数会发生一定的变化。

魔改:自定义delta、key、数据类型和迭代轮数

参考资料:(3条消息) tea系列加密算法学习笔记_tea加密___lifanxin的博客-CSDN博客

RC4

RC4是一种流加密算法,也属于对称加密算法,密匙长度可变

//程序开始
#include<stdio.h>
#include<string.h>

typedef unsigned longULONG;
/*初始化函数*/

void rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
    int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;

    for (i = 0; i<256; i++){
        s[i] = i;
        k[i] = key[i%Len];
    }
    for (i = 0; i<256; i++){
        j = (j + s[i] + k[i]) % 256;
        tmp = s[i];
        s[i] = s[j];//交换s[i]和s[j]
        s[j] = tmp;
    }
}
/*加解密*/

void rc4_crypt(unsigned char*s, unsigned char*Data, unsigned long Len)
{
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;

    for (k = 0; k<Len; k++){
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];//交换s[x]和s[y]
        s[j] = tmp;
        t = (s[i] + s[j]) % 256;
        Data[k] ^= s[t];
    }
}

int main(){
    unsigned char s[256] = { 0 }, s2[256] = { 0 };//S-box
    char key[256] = { "justfortest" };
    char pData[512] = "这是一个用来加密的数据Data";
    unsigned long len = strlen(pData);
    int i;

    printf("pData=%s\n", pData);
    printf("key=%s,length=%d\n\n", key, strlen(key));
    rc4_init(s, (unsigned char*)key, strlen(key));//已经完成了初始化
    printf("完成对S[i]的初始化,如下:\n\n");
    
    for (i = 0; i<256; i++)
    {
        printf("%02X", s[i]);
        if (i && (i + 1) % 16 == 0)putchar('\n');
    }
    printf("\n\n");
    for (i = 0; i<256; i++)//用s2[i]暂时保留经过初始化的s[i]
    {
        s2[i] = s[i];
    }
    printf("已经初始化,现在加密:\n\n");
    rc4_crypt(s, (unsigned char*)pData, len);//加密
    printf("pData=%s\n\n", pData);
    printf("已经加密,现在解密:\n\n");
    //rc4_init(s,(unsignedchar*)key,strlen(key));//初始化密钥
    rc4_crypt(s2, (unsigned char*)pData, len);//解密
    printf("pData=%s\n\n", pData);
    
    return 0;
}

RC4算法的原理包括初始化算法(KSA)和伪随机子密码生成算法(PRGA)两大部分。对字符数组 s 进行了初始化赋值,分别递增。之后对 s 进行了 256 次交换操作。然后通过一定的算法定位 S 盒中的一个元素,并与输入字节异或,得到 k。循环中还改变了 S 盒。

参考资料:RC4加密算法 - zbility - 博客园 (cnblogs.com)

MD5

MD5是一种哈希算法

//伪代码表示
/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)

主要特征是四个magic数

0x67452301;

0xEFCDAB89;

0x98BADCFE;

0x10325476;

数据填充:1.先判断文件(消息)的大小(长度) mod 512 == 448 mod 512 ,就是大小(长度)对512求余等于448。(这里的512、448是“位”为单位,转成“字节”就是64、56,即mod 64 == 56 mod 64)2.如果大小(长度)满足 mod 512 == 448 mod 512,就在文件(消息)的末尾处添加64位(8字节)的值,值的内容是原消息的长度(以位为单位)3.如果大小(长度)不满足要求,就执行以下操作:(1)填充1个1(2)填充0,直到满足满足过程的第一步。注意:这里是以位为单位,假如是以字节为单位,第一个填充的是0x80(1000 0000),然后就填0x0

将填充完的数据以及四个magic数经过四个函数各16轮,共四个周期的加密得到结果。具体原理暂不细说,有在线解密网站

参考资料:(4条消息) MD5算法详解_什么名字都被用了的博客-CSDN博客

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值