逆向算法之TEA算法
之前在做逆向题的时候遇到过很多加密算法,但是都没有系统的学习过,所以准备总结一下这些算法,今天复现的是tea算法。TEA算法使用64位的明文分组和128位的密钥,使用feistel分组加框架,需要进行32轮循环得到最后的64位密文,其中magic number DELTA是由黄金分割点。
加密算法源码
#include<stdio.h> #define DELTA 0x9e3779b9 void tea_encrypt(unsigned int* v, unsigned int* key) { unsigned int l = v[0], r = v[1], sum = 0; for (size_t i = 0; i < 32; i++) { //进行32次迭代加密,Tea算法作者的建议迭代次数 l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]); sum += DELTA; //累加Delta的值 r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]); //利用多次双位移和异或将明文与密钥扩散混乱,并将两个明文互相加密 } v[0] = l; v[1] = r; } void tea_decrypt(unsigned int* v, unsigned int* key) { unsigned int l = v[0], r = v[1], sum = 0; sum = DELTA * 32; //32次迭代累加后delta的值 for (size_t i = 0; i < 32; i++) { r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]); sum -= DELTA; l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]); } v[0] = l; v[1] = r; } int main(int argc, char const *argv[]) { unsigned int key[4]={0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f}; unsigned int v1[2] = {0xaabbccdd,0x01234567}; tea_encrypt(v1,key); printf("tea_encrypt:%x %x\n",v1[0],v1[1]); tea_decrypt(v1,key); printf("tea_decrypt:%x %x\n",v1[0],v1[1]); return 0;
tea算法最关键的是要找到DELTA值和128位的key。
在逆向程序的时候,可以利用ida的插件findcypto识别tea算法
如上图的程序,可以看出a2就是key,v4-=0x61c88647和v4+=0x9e3779b9是等价的,显然DELTA就是0x9e3779b9
例:Android CrackME TEA加密算法的逆向
在so文件的xxx()函数找到了加密算法。
其中可以发现TEA的显著特征0xC6EF3720,和 -0x61C88647(即0x9E3779B9)还有十六个字节的key
根据加密写出解密脚本
#define _DWORD unsigned int #define HIDWORD(x) (*((_DWORD *)&(x) + 1)) #define LODWORD(x) (*((_DWORD *)&(x))) //key="\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA\xDC\xFE\x10\x32\x54\x76" //TEA解密算法 long long xxxx_decrypt(int a1, int a2) { int v2; int v3; int v4; unsigned int v5; unsigned int v6; int v7; long long v9; v2 = *(int *)(a2 + 8); //v2=0xFEDCBA98 v3 = *(int *)a2; //v3=0x1234567 v4 = *(int *)(a2 + 4); //v4=0x89ABCDEF v5 = *(int *)a1; v6 = *(int *)(a1 + 4); HIDWORD(v9) = *(int *)(a2 + 12); v7 = 0xC6EF3720; LODWORD(v9) = v2; //v9=0x76543210FEDCBA98 do { v6 -= ((v5 >> 5) + HIDWORD(v9)) ^ (16 * v5 + v2) ^ (v5 + v7); v5 -= ((v6 >> 5) + v4) ^ (16 * v6 + v3) ^ (v6 + v7); v7 += 0x61C88647; } while (v7 != 0); *(int *)a1 = v5; *(int *)(a1 + 4) = v6; return v9; }
tea算法还可以进行魔改,魔改的地方主要是DELTA值,将这个值修改会让很多加密算法识别软件失效,像下面的程序就将DELTA魔改为0x1234567,绕过来peid的插件KANAL的识别。
补充TEA及魔改TEA加密与解密源码:
初级TEA
#include <stdio.h> #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; } int main() { uint32_t v[2]={1,2},k[4]={2,2,3,4}; // v为要加密的数据是两个32位无符号整数 // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位 printf("加密前原始数据:%u %u\n",v[0],v[1]); encrypt(v, k); printf("加密后的数据:%u %u\n",v[0],v[1]); decrypt(v, k); printf("解密后的数据:%u %u\n",v[0],v[1]); return 0; }
TEA升级版XTEA,增加了更多的密钥表,移位和异或等操作。
#include <stdio.h> #include <stdint.h> /* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */ void encipher(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 decipher(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; } int main() { uint32_t v[2]={1,2}; uint32_t const k[4]={2,2,3,4}; unsigned int r=32;//num_rounds建议取值为32 // v为要加密的数据是两个32位无符号整数 // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位 printf("加密前原始数据:%u %u\n",v[0],v[1]); encipher(r, v, k); printf("加密后的数据:%u %u\n",v[0],v[1]); decipher(r, v, k); printf("解密后的数据:%u %u\n",v[0],v[1]); return 0; } ————————————————
XXTEA,又称Corrected Block TEA,是XTEA的升级版
#include <stdio.h> #include <stdint.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea(uint32_t *v, int n, uint32_t const key[4]) { uint32_t y, z, sum; unsigned p, rounds, e; if (n > 1) /* Coding Part */ { rounds = 6 + 52/n; sum = 0; z = v[n-1]; do { 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; } while (--rounds); } else if (n < -1) /* Decoding Part */ { n = -n; rounds = 6 + 52/n; sum = rounds*DELTA; y = v[0]; do { 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; } while (--rounds); } } int main() { uint32_t v[2]= {1,2}; uint32_t const k[4]= {2,2,3,4}; int n= 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密 // v为要加密的数据是两个32位无符号整数 // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位 printf("加密前原始数据:%u %u\n",v[0],v[1]); btea(v, n, k); printf("加密后的数据:%u %u\n",v[0],v[1]); btea(v, -n, k); printf("解密后的数据:%u %u\n",v[0],v[1]); return 0; }