关于XTEA解密的理解(题目加python代码)
首先,简单的了解一下TEA的加密过程
在加密过程中,需要使用2个32位的无符号整数,密钥为128位,四个32位无符号整数
加密中一共有五个量参与运算,l(第一个明文),r(第二个明文),sum=0,delta给定一个定值,密钥key
void encrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0, delta = 0x9e3779b9;
for (size_t i = 0; i < 32; i++) {
sum += delta;
l += ((r << 4) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
r += ((l << 4) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
}
v[0] = l;
v[1] = r;
}
一共执行32次,最后将l,r放入v[0],v[1]中存储,得到密文
解密流程跟加密相反
void decrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0, delta = 0x9e3779b9;
sum = delta * 32;
for (size_t i = 0; i < 32; i++) {
r -= ((l << 4) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
l -= ((r << 4) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
sum -= delta;
}
v[0] = l;
v[1] = r;
}
接下来重点理解一下比赛中的魔改版XTEA算法(由于我c只看的懂但不太会写,所以我就用python实现了)
首先我们还是先了解一下XTEA算法
跟TEA算法很类似,差别就是将r的变化结果和l变化结果进行了交替赋值,同时位移次数进行了一些变化,也掺杂了一些与操作
#include<stdio.h>
#include<stdint.h>
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; //这里是加密轮数,自己设置
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;
}
这里我们看一道关于魔改的XTEA的题目
无壳64位,接着分析主函数代码
接下来看一下dll文件
这边额外补充一下TLS回调函数
分析的已经差不多了,接下来就是上脚本了
from ctypes import *
"""c_uint32对象本身是一个包装器对象,需要使用.value来访问底层整数值"""
"""c语言中char元素是一个字节,而int元素通常是4个字节,所以一个32位无符号整数代表4个字符(一个字符通常是一个字节)"""
def encrypt(v,k):
v0=c_uint32(v[0])
v1=c_uint32(v[1])
sum1=c_uint32(0)
delta=999999999
for i in range(33):
v0.value+=(((v1.value<<3)^(v1.value>>4))+v1.value)^(sum1.value+k[sum1.value&3])
sum1.value+=delta
v1.value+=(((v0.value<<3)^(v0.value>>4))+v0.value)^(sum1.value+k[(sum1.value>>11)&3])
return v0.value,v1.value
def decrypt(v,k):
v0=c_uint32(v[0])
v1=c_uint32(v[1])
delta=999999999
sum1=c_uint32((delta*33)+1)
for i in range(33):
v1.value-=(((v0.value<<3)^(v0.value>>4))+v0.value)^(sum1.value+k[(sum1.value>>11)&3])
sum1.value-=delta
v0.value-=(((v1.value<<3)^(v1.value>>4))+v1.value)^(sum1.value+k[sum1.value&3])
return v0.value,v1.value
enc = [130,67,163,137,111,186,128,200,248,180,86,189,179,65,178,141,218,68,14,4,3,46,56,222,18,84,173,137,149,48,99,33,223,13,148,17,220,178,208,17]
k=[5,20,13,14]
t = [int.from_bytes(enc[i:i+4], byteorder='little') for i in range(0, len(enc), 4)]
"""
这是一个方法调用,它将四个字节的字节数组(刚才切片得到的)转换为一个整数。byteorder='little' 表示采用小端字节顺序,这意味着最低有效字节在前面,最高有效字节在后面
"""
#print(t)
temp = []
for i in range(0,10,2):
v = t[i:i+2]
res = decrypt(v,k)
temp.extend(res) # extend()方法通常用于将一个可迭代对象的元素添加到另一个可迭代对象中
#print(temp)
#temp=[1734437990 , 828457851, 813260652, 1983078261, 828337765 ,863461222 ,863125599 ,1916823135, 1634746719, 2099344498]
for i in range(10):
num = temp[i]
char1 = chr(num & 0xFF) # 0xFF是一个掩码,用于提取最低8位 下面一个意思
char2 = chr((num >> 8) & 0xFF)
char3 = chr((num >> 16) & 0xFF)
char4 = chr((num >> 24) & 0xFF)
print(char1 + char2 + char3 + char4, end='')
#flag{Ca1l_y0u_3ven_1f_w3_@r3_f@r_Apart!}
#这里也可以导入libum库,用flag += libum.n2s(res[0])[::-1] flag += libum.n2s(res[1])[::-1]
#来直接输出flag
学到的东西
-
dword只能存储两个字也就是四个字节,而输入的也是4个字节,这就说明了是4个字节一组,并且在机器中一般是小端序储存的,看地址也看的出来
-
python如何实现低八位的字符串提取
-
对基于python的XTEA加解密代码的理解与使用