Bootstrap

基于一道newstarctf中的逆向题学习XTEA解密

关于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加解密代码的理解与使用

;