记录DDCTF中一道非常需要耐心的逆向题

栏目: Ruby · 发布时间: 8年前

内容简介:记录DDCTF中一道非常需要耐心的逆向题

这题出现在DDCTF的level8,题目给了两张图片和一段文字,稍后我会提供附件。

挑战:《Crack me if you can》

赛题背景:图片信息隐藏与数字水印技术一直是安全研究领域的热门话题之一,本挑战结合了图片内嵌、算法逆向等知识点,考察了挑战者的综合技术素养。

赛题描述:本题是一张图片,请试分析图片中隐藏的内嵌文件,逆向 Crack me 算法并得到 DDCTF-65f9 输入所对应的密钥。

评分标准:密钥正确则可进入下一题。

图片1:

记录DDCTF中一道非常需要耐心的逆向题

图片2(名字crackme.png,关键附件,请从下文中下载原图):

记录DDCTF中一道非常需要耐心的逆向题

附件下载: http://pan.baidu.com/s/1jIMaBum 密码:5cah

从图片到程序

首先由名字crackme,我们知道了这是一道re题,但他给了一张图片。

我们用010editor打开他。

记录DDCTF中一道非常需要耐心的逆向题

emmm,标准的jpg文件头,果然png的后缀名是假的,jpg的文件结尾标志是FFD9,ctrl+F查找

记录DDCTF中一道非常需要耐心的逆向题

发现后面附加了一段数据,把这段数据先单独存下来。

不知是不是直觉,我猜这段数据是zlib的压缩数据,用 python 写脚本解压一下。

import zlib
enc = open('dump','rb').read()
dec = zlib.decompress(enc)
print dec

输出了一段base64,由于数据过长,就不贴了。我把他base64解码后写到文件。

import zlib
enc = open('dump','rb').read()
dec = zlib.decompress(enc).decode('base64')
open('dump_base64','wb').write(dec)

再用010editor打开,发现我们熟悉的zip文件头PK被改成了KP(滑稽)

记录DDCTF中一道非常需要耐心的逆向题

改过来以后得到压缩包 dump.zip

然而解压需要密码。

结合题目提供的第一张图,这是一个除零错误。

试一试就知道了。

2 / 0

Traceback (most recent call last):
  File "C:\Users\veritas501\Desktop\study\test.py", line 1, in <module>
    2/0
ZeroDivisionError: integer division or modulo by zero
[Finished in 0.1s]

所以压缩密码是 integer division or modulo by zero

成功得到 crackme.exe !!

记录DDCTF中一道非常需要耐心的逆向题

IDA加OD动静态分析

OD里下 GetDlgItemTextA 断点,来到获取输入的地址 0x00**1EE4 ,IDA也相应的来到 0x00**1EE4

接下来在IDA中疯狂整理代码逻辑和变量名。这段辛酸过程省略,不想整理的话我上面的附件里也提供了我当时做题时整理好的idb文件,直接载入也行。

首先程序里有一段240bytes长的char * head,作为常量,结合输入的password(即mail)进行大量的运算,所得的值1和输入的uasename通过某种运算的到的值2相等。

记录DDCTF中一道非常需要耐心的逆向题

整理一下逻辑。

username题目告诉我们了,因为用了strcat,所以key可以推出,key到IV3由于是正向计算,直接在OD中动态跟一下结果IV3也就出来了。又因为IV2和IV3是相等的关系,所以IV2也可以直接得到。head到hash是正向算法,hash也可以直接动态跟出来。

   head->hash\
               IV1\
mail_mid->pwd/      IV2\
              head/     equal!!
     username->key->IV3/

username:DDCTF-65f9
IV3:IV2:'e8d8e2ceaf9de076a0f211f5a1895352'.encode('hex')
len IV2,IV3 = 16
hash:
7DEC14283116611B3CBD497513843B3B304D171BF021FF0C9E8D4692307EBC7AE8223FB03CE6FE1C6EC09B6C957C40A49D8D2CC63F13953F8973EDF80CD3B7775C5DE5D0BE87E7B62AD148729F60649E3D059704628685678A0AEC8BC80ED5F70AB1B095042BFD3FCDA94906961437F5A8009DBC70D01C4591D583A6FE967A9992CF10E197BDBAAD3BE159E448393F08DAC047366783936D408B2DA876AFB530CAA6F54FAD0AF83A6F860B9E8B40EC1D
len hash :0xB0

所以现在的关键是需要对IV12IV3这个算法求逆,由IV2和head推出IV1。然后再对hash2IV1这个函数求逆,由IV1和hash推出pwd。然后pwd直接encode_hex就能得到mail_mid。

分析IV12IV2

又是一段艰苦的逆向,最后发现就是一个稍微变化过的aes解码函数。。。

记录DDCTF中一道非常需要耐心的逆向题

当然逆向这东西,事后看看都觉得简单,只有自己逆过才懂得艰辛。

用python写出加密和解密函数:

head = '4E5332303137434D2D44444354462D006469646963687578696E672E636F6D00E3E22A86D2D569CBFF912D88ABD70088795A7C0A1A320972735C6E5C1033035C7E73C8AAACA6A16153378CE9F8E08C61B0FD53F4AACF5A86D99334DAC9A037861090A478BC360519EF0189F017E105912C5455E7869B0F615F083BBB96A80C3DDD94FDCB61A2F8D28EA37122994274B3434E26BBC5D529DA9ADD12610C751E5C0DB91FCF6C1BE71DE2B8963F7BFAE28CAF1526946AC00F4EF01D1D2FFC680373A928A37DC5334460278BD25F5C7130D34D8C69C6274C6688D7517BA72B3978D4CBAF95E70E9CD187291703D87566330B'.decode('hex')

box = 'E2D681A62AFEC53CBDAF540A75D85120E9BBED7A92EE48A46E03B56DB8A5597DDF4A391A4DD3C722EC50DEFCF3C95CC8899183D7F4438874C06A5896020837720C7C0DA92F7E6980684C352D40BE9A36F72C8FC6B6DBCE09BCEB04D0A8C411B20552B1D415A2972E90642963318AE8CA873E762321D20B257824E034A1D90EAC8D0060E4AA5D0FEA3827BA7FA3703216FB66DA06653DBF3B2871E162F8AD9F4E9D42F2CF1285A04F672B93F0824B01561C9CE513C2FAFFDC9B9498E3F684EF77E76B10465EB386B0F9176F73D1AE7B446CAB1ED55B9E265FC33A14181B3F79F1FD8EB7C1CC55F5455357A747958BCD6149198C1F305A99411D33B4E6CB07DDB9'.decode('hex')

inv_box = [0]*256

inv_a = [3,1,1,2]
a = [9,0xe,0xb,0xd]

int_1 = 14
def AddRoundKey(tmp,head,k):
	for j in range(4):
		tmp[j] ^= ord(head[16*k+4*j])
		tmp[j+4] ^= ord(head[16*k+4*j+1])
		tmp[j+8] ^= ord(head[16*k+4*j+2])
		tmp[j+12] ^= ord(head[16*k+4*j+3])
	return tmp

def ShiftRows(tmp):
	for i in range(1,4):
		for j in range(i):
			v3 = tmp[4*i+3]
			for k in range(3,0,-1):
				tmp[4*i+k] = tmp[4*i+k-1]
			tmp[4*i] = v3
	return tmp

def inv_ShiftRows(tmp):
	for i in range(1,4):
		for j in range(i):
			v3 = tmp[4*i]
			for k in range(0,3):
				tmp[4*i+k] = tmp[4*i+k+1]
			tmp[4*i+3] = v3
	return tmp

def SubBytes(tmp):
	for i in range(4):
		for j in range(4):
			tmp[4*i+j] = ord(box[16 * (tmp[4*i+j] & 0xF) + (( tmp[4*i+j] & 0xF0) >> 4)])
	return tmp

def inv_SubBytes(tmp):
    for i in range(256):
        inv_box[ord(box[i])] = i

    for i in range(4):
        for j in range(4):
            tmp[4*i+j] = inv_box[tmp[4*i+j]]
            tmp[4*i+j] = 16 * (tmp[4*i+j] & 0xF) + (( tmp[4*i+j] & 0xF0) >> 4)
    return tmp

def mix_single_column(v6):
	d = [0]*4
	d[0] = gmult(a[0],v6[0])^gmult(a[3],v6[1])^gmult(a[2],v6[2])^gmult(a[1],v6[3]);
	d[1] = gmult(a[1],v6[0])^gmult(a[0],v6[1])^gmult(a[3],v6[2])^gmult(a[2],v6[3]);
	d[2] = gmult(a[2],v6[0])^gmult(a[1],v6[1])^gmult(a[0],v6[2])^gmult(a[3],v6[3]);
	d[3] = gmult(a[3],v6[0])^gmult(a[2],v6[1])^gmult(a[1],v6[2])^gmult(a[0],v6[3]);
	return d

def gmult(aa,bb):
	p=0
	hbs=0
	for i in range(8):
		if (bb&1):
			p ^= aa
		hbs=aa&0x80
		aa<<=1
		aa = aa&0xff
		if hbs:
			aa ^= 0x1b
		bb>>=1
	return p

def mix_columns(tmp):
	v6 = [0]*4
	for i in range(4):
		for j in range(4):
			v6[j] = tmp[4*j+i]
		v6 = mix_single_column(v6)
		for j in range(4):
			tmp[4*j+i] = v6[j]
	return tmp

def inv_mix_columns(tmp):
	v6 = [0]*4
	for i in range(4):
		for j in range(4):
			v6[j] = tmp[4*j+i]
		v6 = inv_mix_single_column(v6)
		for j in range(4):
			tmp[4*j+i] = v6[j]
	return tmp

def inv_mix_single_column(v6):
	d = [0]*4
	d[0] = gmult(inv_a[0],v6[0])^gmult(inv_a[3],v6[1])^gmult(inv_a[2],v6[2])^gmult(inv_a[1],v6[3]);
	d[1] = gmult(inv_a[1],v6[0])^gmult(inv_a[0],v6[1])^gmult(inv_a[3],v6[2])^gmult(inv_a[2],v6[3]);
	d[2] = gmult(inv_a[2],v6[0])^gmult(inv_a[1],v6[1])^gmult(inv_a[0],v6[2])^gmult(inv_a[3],v6[3]);
	d[3] = gmult(inv_a[3],v6[0])^gmult(inv_a[2],v6[1])^gmult(inv_a[1],v6[2])^gmult(inv_a[0],v6[3]);
	return d

def print_iv(iv):
	out=''
	for i in range(len(iv)):
		out += chr(iv[i])
	print out.encode('hex')

def enc(iv1):
	print iv1
	iv1 = list(iv1.decode('hex'))
	for i in range(len(iv1)):
		iv1[i] = ord(iv1[i])
	
	tmp=[0]*16
	iv2=[0]*16
	for i in range(4):
		for j in range(4):
			tmp[4*i+j] = iv1[4*j+i]
	
	tmp = AddRoundKey(tmp,head,int_1)
	
	for k in range(int_1-1,0,-1):
		tmp = ShiftRows(tmp)
		tmp = SubBytes(tmp)
		tmp = AddRoundKey(tmp,head,k)
		tmp = mix_columns(tmp)
	tmp = ShiftRows(tmp)
	tmp = SubBytes(tmp)
	tmp = AddRoundKey(tmp,head,0)

	for i in range(4):
		for j in range(4):
			iv2[4*j+i] = tmp[4*i+j]
	
	for i in range(len(iv2)):
		iv2[i] = chr(iv2[i])
	
	iv2 = ''.join(iv2)
	iv2 = iv2.encode('hex')
	return iv2

def dec(iv1):
	print iv1
	iv1 = list(iv1.decode('hex'))
	for i in range(len(iv1)):
		iv1[i] = ord(iv1[i])
	
	tmp=[0]*16
	iv2=[0]*16
	for i in range(4):
		for j in range(4):
			tmp[4*i+j] = iv1[4*j+i]
	
	tmp = AddRoundKey(tmp,head,0)
	tmp = inv_SubBytes(tmp)
	tmp = inv_ShiftRows(tmp)

	for k in range(1,int_1):
		tmp = inv_mix_columns(tmp)
		tmp = AddRoundKey(tmp,head,k)
		tmp = inv_SubBytes(tmp)
		tmp = inv_ShiftRows(tmp)

	tmp = AddRoundKey(tmp,head,int_1)

	for i in range(4):
		for j in range(4):
			iv2[4*j+i] = tmp[4*i+j]
	
	for i in range(len(iv2)):
		iv2[i] = chr(iv2[i])
	
	iv2 = ''.join(iv2)
	iv2 = iv2.encode('hex')
	return iv2


iv2 = 'e8d8e2ceaf9de076a0f211f5a1895352'
iv1 = dec(iv2)
print iv1

得到 iv1:e3c8f0eb7ad23ff182c8d87383f44918

分析hash2IV1函数

又是一阵疯狂的逆向加整理。

如果你直接在ida里按f5的话,你会得到这样的代码:

int __cdecl hash2IV1(char *hash, char *pwd, char *IV1)
{
  unsigned int v3; // ST14_4@3
  unsigned int v4; // ST24_4@3
  char *v5; // ST18_4@3
  unsigned int v6; // ST0C_4@3
  int v7; // ST14_4@3
  int v8; // ST0C_4@4
  int v9; // ST24_4@4
  int result; // eax@4
  int xxx4; // [sp+Ch] [bp-20h]@1
  int xxx1; // [sp+10h] [bp-1Ch]@1
  char *v13; // [sp+18h] [bp-14h]@1
  int xxx3; // [sp+1Ch] [bp-10h]@1
  int xxx2; // [sp+24h] [bp-8h]@1
  unsigned int i; // [sp+28h] [bp-4h]@1

  xxx2 = *((_DWORD *)pwd + 1);
  xxx4 = *((_DWORD *)pwd + 3);
  xxx3 = *((_DWORD *)pwd + 2) - *((_DWORD *)hash + 0x2B);
  xxx1 = *(_DWORD *)pwd - *((_DWORD *)hash + 0x2A);
  v13 = hash + 0xA4;
  for ( i = 0; i < 0x14; ++i )
  {
    v3 = ((unsigned int)(xxx1 * (2 * xxx3 + 1)) >> 25) | (xxx1 * (2 * xxx3 + 1) << 7);
    v4 = v3 ^ (((unsigned int)(xxx2 - *(_DWORD *)v13) >> (32 - ((unsigned int)(xxx3 * (2 * xxx1 + 1)) >> 23))) | ((xxx2 - *(_DWORD *)v13) << ((unsigned int)(xxx3 * (2 * xxx1 + 1)) >> 23)));
    v5 = v13 - 4;
    v6 = (((unsigned int)(xxx3 * (2 * xxx1 + 1)) >> 23) | (xxx3 * (2 * xxx1 + 1) << 9)) ^ (((unsigned int)(xxx4 - *(_DWORD *)v5) >> (32 - (32 - v3))) | ((xxx4 - *(_DWORD *)v5) << (32 - v3)));
    v13 = v5 - 4;
    v7 = v6;
    xxx4 = xxx3;
    xxx3 = v4;
    xxx2 = xxx1;
    xxx1 = v7;
  }
  v8 = xxx4 - *(_DWORD *)v13;
  v9 = xxx2 - *((_DWORD *)v13 - 1);
  *((_DWORD *)IV1 + 3) = xxx1;
  *(_DWORD *)IV1 = v9;
  *((_DWORD *)IV1 + 1) = xxx3;
  result = v8;
  *((_DWORD *)IV1 + 2) = v8;
  return result;
}

这种代码你想写逆算法根本是不可能的,我们要先对这段代码进行整理和改编。

由于用了一些不同数据长度的类型的转换,所以这里我用 c语言 来写。

include <stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
typedef unsigned char byte;
typedef unsigned int uint;

byte pwd[] = { 0x59 ,0x43 ,0x29 ,0x31 ,0x19 ,0xA8 ,0x45 ,0xE9 ,0xBB ,0xDB ,0xDE ,0x5A ,0x36 ,0x9C ,0x1F ,0x50 };
byte iv1[] = { 0xe3 ,0xc8 ,0xf0 ,0xeb ,0x7a ,0xd2 ,0x3f ,0xf1 ,0x82 ,0xc8 ,0xd8 ,0x73 ,0x83 ,0xf4 ,0x49 ,0x18 };
byte out[] = { 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 };
byte hashcode[] = { 0x7D,0xEC,0x14,0x28,0x31,0x16,0x61,0x1B,0x3C,0xBD,0x49,0x75,0x13,0x84,0x3B,0x3B,0x30,0x4D,0x17,0x1B,0xF0,0x21,0xFF,0x0C,0x9E,0x8D,0x46,0x92,0x30,0x7E,0xBC,0x7A,0xE8,0x22,0x3F,0xB0,0x3C,0xE6,0xFE,0x1C,0x6E,0xC0,0x9B,0x6C,0x95,0x7C,0x40,0xA4,0x9D,0x8D,0x2C,0xC6,0x3F,0x13,0x95,0x3F,0x89,0x73,0xED,0xF8,0x0C,0xD3,0xB7,0x77,0x5C,0x5D,0xE5,0xD0,0xBE,0x87,0xE7,0xB6,0x2A,0xD1,0x48,0x72,0x9F,0x60,0x64,0x9E,0x3D,0x05,0x97,0x04,0x62,0x86,0x85,0x67,0x8A,0x0A,0xEC,0x8B,0xC8,0x0E,0xD5,0xF7,0x0A,0xB1,0xB0,0x95,0x04,0x2B,0xFD,0x3F,0xCD,0xA9,0x49,0x06,0x96,0x14,0x37,0xF5,0xA8,0x00,0x9D,0xBC,0x70,0xD0,0x1C,0x45,0x91,0xD5,0x83,0xA6,0xFE,0x96,0x7A,0x99,0x92,0xCF,0x10,0xE1,0x97,0xBD,0xBA,0xAD,0x3B,0xE1,0x59,0xE4,0x48,0x39,0x3F,0x08,0xDA,0xC0,0x47,0x36,0x67,0x83,0x93,0x6D,0x40,0x8B,0x2D,0xA8,0x76,0xAF,0xB5,0x30,0xCA,0xA6,0xF5,0x4F,0xAD,0x0A,0xF8,0x3A,0x6F,0x86,0x0B,0x9E,0x8B,0x40,0xEC,0x1D };
void printout(byte* pout){
	int unequal = 0;
	for (int i = 0; i < 16; i++) {
		unequal |= (pwd[i] ^ pout[i]);
		printf("%x,", pout[i]);
	}
	printf("\n\n");
	if (!unequal) {
		printf("true!!!\n");
	}
	else {
		printf("FALSE\n");
	}
}

inlineuintrol(uint a, uint off){
	return (a << off) | (a >> (32 - off));
}

inlineuintror(uint a, uint off){
	return (a << (32 - off)) | (a >> off);
}

void enc(byte* in_pwd){
	uint xxx1, xxx2, xxx3, xxx4;
	byte * v13;
	uint a, b, c, d;
	xxx1 = *((uint*)in_pwd) - *((uint*)hashcode + 0x2a);
	xxx2 = *((uint*)in_pwd + 1);
	xxx3 = *((uint*)in_pwd + 2) - *((uint*)hashcode + 0x2b);
	xxx4 = *((uint*)in_pwd + 3);

	for (int i = 0; i < 0x14; ++i) {
		v13 = hashcode + 0xa4 - i * 8;

		a = rol(xxx1 * (2 * xxx3 + 1), 7);
		b = rol(xxx2 - *(uint *)v13, ((xxx3 * (2 * xxx1 + 1)) >> 23));
		c = rol(xxx3 * (2 * xxx1 + 1), 9);
		d = ror(xxx4 - *(uint *)(v13 - 4), a);

		xxx4 = xxx3;
		xxx3 = a^b;
		xxx2 = xxx1;
		xxx1 = c^d;
	}

	*(uint *)out = xxx2 - *((uint *)hashcode);
	*((uint *)out + 1) = xxx3;
	*((uint *)out + 2) = xxx4 - *(uint *)(hashcode + 4);
	*((uint *)out + 3) = xxx1;

}

从这改编过的代码中,我们可以明显看出轮加密的痕迹,也就是Feistel网络结构。

那逆算法就好写了。

include <stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
typedef unsigned char byte;
typedef unsigned int uint;

byte pwd[] = { 0x59 ,0x43 ,0x29 ,0x31 ,0x19 ,0xA8 ,0x45 ,0xE9 ,0xBB ,0xDB ,0xDE ,0x5A ,0x36 ,0x9C ,0x1F ,0x50 };
byte iv1[] = { 0xe3 ,0xc8 ,0xf0 ,0xeb ,0x7a ,0xd2 ,0x3f ,0xf1 ,0x82 ,0xc8 ,0xd8 ,0x73 ,0x83 ,0xf4 ,0x49 ,0x18 };
byte out[] = { 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 };
byte hashcode[] = { 0x7D,0xEC,0x14,0x28,0x31,0x16,0x61,0x1B,0x3C,0xBD,0x49,0x75,0x13,0x84,0x3B,0x3B,0x30,0x4D,0x17,0x1B,0xF0,0x21,0xFF,0x0C,0x9E,0x8D,0x46,0x92,0x30,0x7E,0xBC,0x7A,0xE8,0x22,0x3F,0xB0,0x3C,0xE6,0xFE,0x1C,0x6E,0xC0,0x9B,0x6C,0x95,0x7C,0x40,0xA4,0x9D,0x8D,0x2C,0xC6,0x3F,0x13,0x95,0x3F,0x89,0x73,0xED,0xF8,0x0C,0xD3,0xB7,0x77,0x5C,0x5D,0xE5,0xD0,0xBE,0x87,0xE7,0xB6,0x2A,0xD1,0x48,0x72,0x9F,0x60,0x64,0x9E,0x3D,0x05,0x97,0x04,0x62,0x86,0x85,0x67,0x8A,0x0A,0xEC,0x8B,0xC8,0x0E,0xD5,0xF7,0x0A,0xB1,0xB0,0x95,0x04,0x2B,0xFD,0x3F,0xCD,0xA9,0x49,0x06,0x96,0x14,0x37,0xF5,0xA8,0x00,0x9D,0xBC,0x70,0xD0,0x1C,0x45,0x91,0xD5,0x83,0xA6,0xFE,0x96,0x7A,0x99,0x92,0xCF,0x10,0xE1,0x97,0xBD,0xBA,0xAD,0x3B,0xE1,0x59,0xE4,0x48,0x39,0x3F,0x08,0xDA,0xC0,0x47,0x36,0x67,0x83,0x93,0x6D,0x40,0x8B,0x2D,0xA8,0x76,0xAF,0xB5,0x30,0xCA,0xA6,0xF5,0x4F,0xAD,0x0A,0xF8,0x3A,0x6F,0x86,0x0B,0x9E,0x8B,0x40,0xEC,0x1D };
void printout(byte* pout){
	int unequal = 0;
	for (int i = 0; i < 16; i++) {
		unequal |= (pwd[i] ^ pout[i]);
		printf("%x,", pout[i]);
	}
	printf("\n\n");
	if (!unequal) {
		printf("true!!!\n");
	}
	else {
		printf("FALSE\n");
	}
}

inlineuintrol(uint a, uint off){
	return (a << off) | (a >> (32 - off));
}

inlineuintror(uint a, uint off){
	return (a << (32 - off)) | (a >> off);
}

void enc(byte* in_pwd){
	uint xxx1, xxx2, xxx3, xxx4;
	byte * v13;
	uint a, b, c, d;
	xxx1 = *((uint*)in_pwd) - *((uint*)hashcode + 0x2a);
	xxx2 = *((uint*)in_pwd + 1);
	xxx3 = *((uint*)in_pwd + 2) - *((uint*)hashcode + 0x2b);
	xxx4 = *((uint*)in_pwd + 3);

	for (int i = 0; i < 0x14; ++i) {
		v13 = hashcode + 0xa4 - i * 8;

		a = rol(xxx1 * (2 * xxx3 + 1), 7);
		b = rol(xxx2 - *(uint *)v13, ((xxx3 * (2 * xxx1 + 1)) >> 23));
		c = rol(xxx3 * (2 * xxx1 + 1), 9);
		d = ror(xxx4 - *(uint *)(v13 - 4), a);

		xxx4 = xxx3;
		xxx3 = a^b;
		xxx2 = xxx1;
		xxx1 = c^d;
	}

	*(uint *)out = xxx2 - *((uint *)hashcode);
	*((uint *)out + 1) = xxx3;
	*((uint *)out + 2) = xxx4 - *(uint *)(hashcode + 4);
	*((uint *)out + 3) = xxx1;

}

void dec(byte* in_iv){
	uint xxx1, xxx1_up, xxx2, xxx2_up, xxx3, xxx3_up, xxx4, xxx4_up;
	byte * v13;
	uint a, b, c, d;

	xxx2 = *(uint *)in_iv + *((uint *)hashcode);
	xxx3 = *((uint *)in_iv + 1);
	xxx4 = *((uint *)in_iv + 2) + *(uint *)(hashcode + 4);;
	xxx1 = *((uint *)in_iv + 3);

	for (int i = 0x13; i >= 0; --i) {
		v13 = hashcode + 0xa4 - i * 8;

		xxx1_up = xxx2;
		xxx3_up = xxx4;

		a = rol(xxx1_up * (2 * xxx3_up + 1), 7);
		c = rol(xxx3_up * (2 * xxx1_up + 1), 9);
		b = xxx3^a;
		d = xxx1^c;

		xxx2_up = ror(b, ((xxx3_up * (2 * xxx1_up + 1)) >> 23)) + *(uint *)v13;
		xxx4_up = rol(d, a) + *(uint *)(v13 - 4);

		xxx4 = xxx4_up;
		xxx3 = xxx3_up;
		xxx2 = xxx2_up;
		xxx1 = xxx1_up;
	}

	*((uint*)out) = xxx1 + *((uint*)hashcode + 0x2a);
	*((uint*)out + 1) = xxx2;
	*((uint*)out + 2) = xxx3 + *((uint*)hashcode + 0x2b);
	*((uint*)out + 3) = xxx4;

}
int main(void){
	dec(iv1);

	printout(out);
	system("pause");
	return 0;
}

从而得到 pwd:93c65c807c3800b15f3600d449c64692

收尾

由格式知,我们的password(也就是mail)为 DDCTF-93c65c807c3800b15f3600d449c64692@didichuxing.com

记录DDCTF中一道非常需要耐心的逆向题

总结这道题,不说前面的非re部分,难点主要在于求这两个的逆函数上。对此应当对常见的加密算法模式有比较透彻的理解。

而且从头到尾彻彻底底的写了一遍AES加密算法和AES的解密算法还真TM赤鸡呢!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Spark SQL内核剖析

Spark SQL内核剖析

朱锋、张韶全、黄明 / 电子工业出版社 / 2018-8 / 69.00元

Spark SQL 是 Spark 技术体系中较有影响力的应用(Killer application),也是 SQL-on-Hadoop 解决方案 中举足轻重的产品。《Spark SQL内核剖析》由 11 章构成,从源码层面深入介绍 Spark SQL 内部实现机制,以及在实际业务场 景中的开发实践,其中包括 SQL 编译实现、逻辑计划的生成与优化、物理计划的生成与优化、Aggregation 算......一起来看看 《Spark SQL内核剖析》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具