看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

WriteUp 7个月前 admin
145 0 0

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

这是一场人类与超智能AI的“生死”较量

请立刻集结,搭乘SpaceX,前往AI控制空间站

智慧博弈  谁能问鼎


看雪·2023 KCTF 年度赛于9月1日中午12点正式开赛!比赛基本延续往届模式,设置了难度值、火力值和精致度积分。由此来引导竞赛的难度和趣味度,使其更具挑战性和吸引力,同时也为参赛选手提供了更加公平、有趣的竞赛平台。

*注意:签到题持续开放,整个比赛期间均可提交答案获得积分


昨日中午12:00第七题《智能联盟计划》已截止答题,该题共有6支战队成功提交flag,一起来看下该题的设计思路和解析吧。



出题团队简介


出题战队:Archaia

战队成员:ThisCha、asm_zhang、刘宽森、C举个例子、wx_ZYL

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析


设计思路


战队名称:

Archaia


公开的用户名及序列号:

用户名 : CCFE84316BD02C02

序列号 : D532E41AFE55A4265D7789C84BF40384


题目答案:

用户名 : KCTF

序列号 : 8BCBB6979E174CB7ECAEACDA104522CA


题目设计:此题使用了X86的代码混淆。


1.题目介绍:这次提交的题目是windows32位的应用程序,作战思路是将算法高级代码和汇编进行混淆、膨胀。


2.整体设计:

(1)用户名加密部分:

使用修改过的DES算法,对用户名进行多次加密,将结果进行hash、拼接,再进行hash,得到一个值。

(2)序列号加密部分

使用修改后的AES算法,对序列号进行解密,将结果通过修改过的DES算法,进行多次解密,密钥来自于(1)的中间结果,最后得到一个值,再进行序列化解密,与(1)最后生成的值进行比较。


3.混淆:

(1)32位混淆:对常见汇编指令进行替换、膨胀,增加垃圾代码,乱序。


4.算法:

使用修改过的DES算法

使用修改过的AES算法

使用简单的解释执行算法

使用RSHash算法保护算法部分的内存完整性


技术要点:

1、X86的代码混淆

2、算法设计


破解时可能会遇到的问题:


1.总体思路:

通过调试器的trace功能或者模拟执行的方式拿到完整的解密算法,最后分析解密算法得到加密算法。


2.需要解决的问题:

(1)拿到完整的代码之后,需要写脚本将垃圾指令除去,以便最后的分析。

(2)通过分析解密算法得到加密的算法。

(3)需要正面对抗大量冗余代码。


预期的破解思路:

1.找到混淆规律,提升分析速度。

2.根据关键算法代码写逆算法。



赛题解析


本题解析由看雪大牛 GreatIchild 提供:
看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

main 函数挺大,不过没加混淆,其他函数都是加了混淆的。看看混淆模式后写个脚本提取指令去混淆:

#!/usr/bin/env python3

# import ida_bytes
import keystone
import capstone

def set_x86():
global ks, cs
ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32)
cs = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32)

set_x86()

def asm(code, addr=0):
return bytes(ks.asm(code, addr)[0])

def disasm(code, addr=0):
for i in cs.disasm(code, addr):
return ('%s %s' %(i.mnemonic, i.op_str))

def ins_len(code):
return len(next(cs.disasm(code, 0)).bytes)

def to_char(x):
assert 0 <= x < 0x100
if x >= 0x80: x -= 0x100
return x

def to_int(b):
assert len(b) == 4
x = int.from_bytes(b, 'little')
if x >= 1 << 31: x -= 1 << 32
return x

def make_label(i):
return '_%x' % (i + ob_start)

ob_start = 0x403AC0
ob_end = 0x617DE0
def extract_block(ins, i):
# print('extract block: 0x%x' % (ob_start + i))
is_zero = False
ebx_ebp = False
push_eax = False
push_ebx = False
push_eax_i = None
push_ebx_i = None
eax_value = None
eax_value_i = None
eax_value_2 = None
eax_value_2_i = None
ebx_value = None
ebx_value_i = None
test_eax = False
push_value = None
last_i = None

while True:
if i in ins:
if last_i:
ins[last_i] += 'njmp %s' % make_label(i)
return []
# print(hex(i + ob_start))
if data[i] == 0x0f and 0x80 <= data[i + 1] < 0x90: # j?? dword
offset = to_int(data[i + 2: i + 6])
if data[i + 6] == 0x0f and data[i + 7] == data[i + 1] ^ 1 and
offset == 6 + to_int(data[i + 8: i + 12]):
ins[i] = 'jmp %s' % make_label(i + 6 + offset)
last_i = None
i += 6 + offset
elif data[i + 1] == 0x84 and is_zero: # jz
ins[i] = 'jmp %s' % make_label(i + 6 + offset)
last_i = None
i += 6 + offset
elif data[i + 1] == 0x85 and test_eax: # jnz
ins[i] = 'jmp %s' % make_label(i + 6 + offset)
last_i = None
i += 6 + offset
else:
mnem = disasm(data[i: i + 6]).split(' ')[0]
ins[i] = '%s %snjmp %s' % (mnem, make_label(i + 6 + offset), make_label(i + 6))
return [i + 6, i + 6 + offset]
elif data[i] == 0x3b and data[i + 1] == 0xc0: # cmp eax, eax
is_zero = True
test_eax = False
ins[i] = 'cmp eax, eax'
last_i = i
i += 2
elif data[i] == 0x3b and data[i + 1] == 0xdb: # cmp ebx, ebx
is_zero = True
test_eax = False
ins[i] = 'cmp ebx, ebx'
last_i = i
i += 2
elif data[i] == 0x50 and eax_value: # push eax
push_eax_i = i
push_eax = True
ins[i] = 'push eax'
last_i = i
i += 1
elif data[i] == 0x53: # push ebx
push_ebx_i = i
push_ebx = True
ins[i] = 'push ebx'
last_i = i
i += 1
elif data[i] == 0x68: # push dword
value = to_int(data[i + 1: i + 5])
if data[i + 5] == 0xc3: # ret
ins[i] = 'jmp %s' % make_label(value - ob_start)
last_i = None
i = value - ob_start
else:
push_value = value
push_value_i = i
ins[i] = 'push 0x%x' % push_value
last_i = i
i += 5
elif 0x70 <= data[i] < 0x80: # j?? short
offset = to_char(data[i + 1])
if data[i + 2] == data[i] ^ 1 and offset == 2 + to_char(data[i + 3]):
ins[i] = 'jmp %s' % make_label(i + 2 + offset)
last_i = None
i += 2 + offset
elif data[i] == 0x74 and is_zero: # jz short
ins[i] = 'jmp %s' % make_label(i + 2 + offset)
last_i = None
i += 2 + offset
elif data[i] == 0x75 and test_eax: # jnz short
ins[i] = 'jmp %s' % make_label(i + 2 + offset)
last_i = None
i += 2 + offset
else:
mnem = disasm(data[i: i + 2]).split(' ')[0]
ins[i] = '%s %snjmp %s' % (mnem, make_label(i + 2 + offset), make_label(i + 2))
return [i + 2, i + 2 + offset]
elif data[i] == 0x85 and data[i + 1] == 0xc0 and eax_value: # test eax, eax
if eax_value_2 != None:
assert eax_value_2 != 0 # call_dst
else:
pass
test_eax = True
is_zero = False
ins[i] = 'test eax, eax'
last_i = i
i += 2
elif data[i] == 0x87 and data[i + 1] == 0x1c and data[i + 2] == 0x24 and push_ebx: # xchg ebx, [esp]
if ebx_value:
assert not ebx_ebp
ins[push_ebx_i] = 'nop'
ins[ebx_value_i] = 'push 0x%x' % ebx_value
ins[i] = 'nop'
push_ebx = False
push_value = ebx_value
ebx_value = None
push_value_i = ebx_value_i
elif ebx_ebp:
ins[push_ebx_i] = 'push ebp'
ins[ebx_ebp_i] = 'nop'
ins[i] = 'nop'
push_ebx = False
ebx_ebp = False
else:
ins[i] = 'xchg ebx, [esp]'
push_ebx = False
last_i = i
i += 3
elif data[i] == 0x8b and data[i + 1] == 0xdd and push_ebx: # mov ebx, ebp
ins[i] = 'mov ebx, ebp'
last_i = i
ebx_ebp_i = i
ebx_ebp = True
i += 2
elif data[i] == 0x90: # nop
ins[i] = 'nop'
last_i = i
i += 1
elif data[i] == 0xb8: # mov eax, dword
value = to_int(data[i + 1: i + 5])
ins[i] = 'mov eax, 0x%x' % value
last_i = i
if not eax_value:
eax_value_i = i
eax_value = value
else:
assert push_eax
eax_value_2_i = i
eax_value_2 = value
i += 5
elif data[i] == 0xbb and push_ebx: # mov ebx, dword
value = to_int(data[i + 1: i + 5])
ins[i] = 'mov ebx, 0x%x' % value
last_i = i
ebx_value_i = i
ebx_value = value
i += 5
elif data[i] == 0xe9: # jmp
ins[i] = 'jmp %s' % make_label(i + 5 + to_int(data[i + 1: i + 5]))
last_i = None
i += 5 + to_int(data[i + 1: i + 5])
elif data[i] == 0xeb: # jmp short
ins[i] = 'jmp %s' % make_label(i + 2 + to_char(data[i + 1]))
last_i = None
i += 2 + to_char(data[i + 1])
elif data[i] == 0xc3: # ret
if push_value:
ins[i] = 'ud2'
i = push_value_i
j = i + ob_start
dst = push_value
offset = dst - j - 5 & 0xffffffff
ins[i] = 'jmp %s' % make_label(dst - ob_start)
last_i = None
push_value = None
i = dst - ob_start
else:
ins[i] = 'ret'
return []
elif data[i] == 0xff and data[i + 1] == 0xe0: # jmp eax
assert push_eax and eax_value and eax_value_2
ins[i] = 'ud2'
i = eax_value_2_i
j = i + ob_start
dst = eax_value_2
offset = dst - j - 5 & 0xffffffff
ins[eax_value_i] = 'nop'
ins[push_eax_i] = 'nop'
ins[i] = 'call f%s' % make_label(dst - ob_start)
funcs_to_handle.append(dst)
i += 5
j = i + ob_start
dst = eax_value
offset = dst - j - 5 & 0xffffffff
ins[i] = 'jmp %s' % make_label(dst - ob_start)
last_i = None
i = dst - ob_start
push_eax = False
eax_value = None
eax_value_2 = None
else:
is_zero = False
test_eax = False
push_ebx = False
ebx_ebp = False
ebx_value = None
push_value = None
push_eax = False
eax_value = None
eax_value_2 = None

l = ins_len(data[i: i + 20])
ins[i] = disasm(data[i: i + l], i + ob_start)
last_i = i
i += l

def extract_function(function):
print('// function: 0x%x' % function)
branches_to_handle = [function - ob_start]
ins = dict()
while branches_to_handle:
addr = branches_to_handle.pop(0)
if addr in ins: continue
branches_to_handle += extract_block(ins, addr)

code = 'f%s:n' % make_label(function - ob_start)
in_pushal = False
in_pushfd = False
for i in ins:
if in_pushal:
assert ins[i] != 'pushal '
code += '%s:n' % make_label(i)
if ins[i].startswith('popal '):
in_pushal = False
for j in ins[i].splitlines()[1: ]:
code += j + 'n'
elif in_pushfd:
assert ins[i] != 'pushfd '
code += '%s:n' % make_label(i)
if ins[i].startswith('popfd '):
in_pushfd = False
for j in ins[i].splitlines()[1: ]:
code += j + 'n'
elif ins[i] == 'pushal ':
code += '%s:n' % make_label(i)
in_pushal = True
elif ins[i] == 'pushfd ':
code += '%s:n' % make_label(i)
in_pushfd = True
else:
code += '%s:n%sn' % (make_label(i), ins[i])
return code

offset = 0x400c00
data = open('./KCTF_CrackMe.exe', 'rb').read()[ob_start - offset: ob_end - offset]


funcs_to_handle = [
0x611e44, 0x611513, 0x610baf, 0x60f9f2, 0x60f17a, 0x60e8b9, 0x60df9a, 0x60d635,
0x60cce7, 0x60c3ba, 0x60bac0, 0x60b190, 0x60a819, 0x609f67, 0x609604, 0x608ca6,
0x608375, 0x607aaa, 0x60714f, 0x6067da, 0x605eba, 0x60557e, 0x604c95, 0x604305,
0x603a11, 0x603091, 0x60277c, 0x601e0d, 0x601434, 0x600b97, 0x60027e, 0x5ff957,
0x5fef61, 0x5fe61e, 0x5fdd3d, 0x5fd517, 0x5fcbc4, 0x5fc2cb, 0x5fb9af, 0x5fb07f,
0x5fa795, 0x5f9e5c, 0x5f94be, 0x5f8bb2, 0x5f822a, 0x5f792b, 0x5f700b, 0x5f673f,
0x40f9af, 0x5f52e3, 0x409de1, 0x40e62d, 0x403aca, 0x5f50e0
]

funcs_to_handle += [
0x4055C4, 0x404F6B
]

funcs_handled = set()
code = ''
while funcs_to_handle:
f = funcs_to_handle.pop(0)
if f in funcs_handled: continue
funcs_handled.add(f)
if ob_start <= f < ob_end:
code += extract_function(f)
else:
print("// unknown func (maybe library function): f%s" % make_label(f - ob_start))
code += 'f%s:njmp 0x%xn' % (make_label(f - ob_start), f)
code += 'nn.string "================"nn'

# print('n' + code)

with open('out.s', 'w') as f:
f.write(code)

print('OK')

得到指令后编译为二进制:

import pwn
# pwn.context.os = 'windows' # not needed
pwn.context.arch = 'i386'

code = open('out.s', 'r').read()

with open('out', 'wb') as f:
f.write(pwn.asm(code, vma=0x800000))

print('OK')

最后在 ida 里新加一个段,起始地址 0x800000 ,将指令放进去。

import ida_bytes
with open('out', 'rb') as f:
data = f.read()

ida_bytes.patch_bytes(0x800000, data)

得到的这些函数再手动处理一下多余的指令,逻辑就基本上出来了。

main 前面大部分逻辑都是与用户名相关的,直接跳到最后的判断逻辑:
  
printf(v597); // 输入序列号:
gets_s(password, 0x100u);
if ( strlen(password) >= 0x21 )
goto LABEL_20;
for ( k = 0; ; ++k )
{
v5 = strlen(password);
if ( k >= v5 )
break;
if ( password[k] >= 97 && password[k] <= 122 )
goto LABEL_20;
}
v525 = (char *)((int (__cdecl *)(char *, int))loc_40E62D)(password, 32); // hex to bytes
memset(input, 0, 0x100u);
j_AES_encrypt(v525, v609, input);

// ...

j_decrypt1(&Source[189], output, input);
memcpy(&output[8], v573, 8u);
j_decrypt1(&Source[180], v602, output);
memcpy(&v602[8], v594, 8u);
j_decrypt1(&Source[171], output, v602);
memcpy(&output[8], v593, 8u);
j_decrypt1(&Source[162], v602, output);
memcpy(&v602[8], v592, 8u);
j_decrypt1(&Source[153], output, v602);
memcpy(&output[8], v591, 8u);
j_decrypt1(&Source[144], v602, output);
memcpy(&v602[8], v590, 8u);
j_decrypt1(&Source[135], output, v602);
memcpy(&output[8], v589, 8u);
j_decrypt1(&Source[126], v602, output);
memcpy(&v602[8], v588, 8u);
j_decrypt1(&Source[117], output, v602);
memcpy(&output[8], v587, 8u);
j_decrypt1(&Source[108], v602, output);
memcpy(&v602[8], v586, 8u);
j_decrypt1(&Source[99], output, v602);
memcpy(&output[8], v585, 8u);
j_decrypt1(&Source[90], v602, output);
memcpy(&v602[8], v584, 8u);
j_decrypt1(&Source[81], output, v602);
memcpy(&output[8], v583, 8u);
j_decrypt1(&Source[72], v602, output);
memcpy(&v602[8], v582, 8u);
j_decrypt1(&Source[63], output, v602);
memcpy(&output[8], v581, 8u);
j_decrypt1(&Source[54], v602, output);
memcpy(&v602[8], v580, 8u);
j_decrypt1(&Source[45], output, v602);
memcpy(&output[8], v579, 8u);
j_decrypt1(&Source[36], v602, output);
memcpy(&v602[8], v578, 8u);
j_decrypt1(&Source[27], output, v602);
memcpy(&output[8], v577, 8u);
j_decrypt1(&Source[18], v602, output);
memcpy(&v602[8], v575, 8u);
j_decrypt1(&Source[9], output, v602);
memcpy(&output[8], v576, 8u);
j_decrypt1(Source, v602, output);
Str2[8] = 0;
memcpy(Str2, v602, 8u);
memset(Destination, 0, 0x1F4u);
for ( l = 0; l < 50; strcat_s(Destination, 0x400u, &Source[9 * l++]) )
;
memmove(vm_key, Destination, 500u);
j_vm_encrypt(vm_key, Str2, 1);
if ( !strcmp(Str1, Str2) )
MessageBoxA(0, "success", "success", 0);
else
LABEL_20:
MessageBoxA(0, "fail", "fail", 0);
return 0;
}

输入 password 后 16 转成字节数组,传入魔改的 aes 加密,之后又用魔改的 des 加密 22 轮,再用个简单的虚拟机加密,再和最终的目标值比较。密钥和比较的值都应该是固定的或者只与用户名有关,所以调试拿值就行。
aes 实现方式:

void __cdecl AES_encrypt(char *input, char *key, char *output)
{
char v3[176]; // [esp+1Ch] [ebp-ECh] BYREF
char v4[16]; // [esp+CCh] [ebp-3Ch] BYREF
int v5; // [esp+DCh] [ebp-2Ch]
char state[16]; // [esp+E0h] [ebp-28h] BYREF
DWORD v7; // [esp+F0h] [ebp-18h] BYREF
Params *v8; // [esp+F4h] [ebp-14h]
int j; // [esp+F8h] [ebp-10h]
Params *v10; // [esp+FCh] [ebp-Ch]
int i; // [esp+100h] [ebp-8h]

v5 = 0;
j_memset_0(state, 0, sizeof(state));
j_memset_0(v4, 0, sizeof(v4));
j_memset_0(v3, 0, sizeof(v3));
j_AES_set_state(input, state);
j_AES_set_state(key, v4);
j_AES_KeyExpansion(v4, v3);
j_AES_AddRoundKey(state, v3, 4 * aes_lock_index);
aes_lock_index += 2;
j_AES_ShiftRows(state);
j_AES_SubBytes(state);
v7 = 1;
for ( i = 8; i <= 20; i += 4 )
{
v10 = (Params *)j_calloc_0(0xCu, 1u);
v10->index = i;
v10->state = state;
v10->exkey = v3;
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)j_thread_1, v10, 0, &v7);
}
for ( j = 18; j > 0; j -= 4 )
{
v8 = (Params *)j_calloc_0(0xCu, 1u);
v8->index = j;
v8->state = state;
v8->exkey = v3;
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)j_thread_2, v8, 0, &v7);
}
while ( aes_lock_index != -1 )
;
j_AES_AddRoundKey(state, v3, 0);
AES_get_state(state, output);
}

void __cdecl thread_1(Params *p)
{
while ( aes_lock_index != p->index / 2 )
;
j_AES_AddRoundKey(p->state, p->exkey, 4 * (p->index / 2));
AES_MixColumns(p->state);
j_AES_ShiftRows(p->state);
j_AES_SubBytes(p->state);
if ( aes_lock_index == 10 )
--aes_lock_index;
else
aes_lock_index += 2;
j_free(p);
}

void __cdecl thread_2(Params *p)
{
while ( aes_lock_index != p->index / 2 )
;
j_AES_AddRoundKey(p->state, p->exkey, 4 * (p->index / 2));
AES_MixColumns(p->state);
j_AES_ShiftRows(p->state);
j_AES_SubBytes(p->state);
aes_lock_index -= 2;
j_free(p);
}

多线程但是用一个全局锁控制流程,只有一种执行方式。部分 AES 的实现做了魔改,改一下 aes 板子即可。

#include <stdio.h>
#include <string.h>
#include <assert.h>
// AES
typedef struct {
unsigned char rk[4][11][4]; // round key
unsigned char iv[16];
} AES_CONTEXT;

const unsigned char Sbox[256] = {
0x28, 0xC2, 0xE8, 0x57, 0x48, 0x24, 0x97, 0xC5, 0x18, 0x8C, 0x9B, 0x72, 0xF7, 0x99, 0xDE, 0xD3,
0x85, 0x58, 0x7A, 0x0B, 0x44, 0xD1, 0xB0, 0x47, 0xC7, 0xAE, 0xF0, 0x6D, 0x53, 0xE1, 0x60, 0xB4,
0x4B, 0x5C, 0x10, 0x52, 0x01, 0x39, 0xB9, 0x90, 0xAB, 0x00, 0xD4, 0x73, 0x64, 0x32, 0x9F, 0xA1,
0x6A, 0x1C, 0x6B, 0x21, 0xF1, 0xEF, 0x3F, 0x67, 0x95, 0xF2, 0x79, 0xE0, 0x0C, 0xD0, 0x66, 0x7F,
0x2C, 0xC3, 0x12, 0x5A, 0x34, 0xEB, 0x15, 0xA6, 0xBC, 0x7D, 0xA0, 0xB8, 0x55, 0x49, 0xC1, 0xFB,
0xE9, 0x08, 0x3C, 0xE2, 0x56, 0x2F, 0x30, 0x9E, 0x0E, 0xCB, 0x25, 0xE3, 0x46, 0x5D, 0xEC, 0x4C,
0x09, 0xBE, 0x87, 0x04, 0x89, 0xD8, 0x19, 0x3D, 0x71, 0x40, 0x7E, 0x5F, 0x16, 0x7B, 0x3A, 0x27,
0x43, 0x76, 0x45, 0x8A, 0x35, 0x96, 0xF9, 0x07, 0x8F, 0x0F, 0x54, 0xCF, 0xBA, 0x38, 0x83, 0xCE,
0x2A, 0xAC, 0x68, 0xF4, 0x80, 0x31, 0xA4, 0xFE, 0x93, 0xB3, 0x7C, 0xCA, 0xB6, 0x75, 0xDA, 0xA8,
0xD7, 0xB1, 0x37, 0xC4, 0x6C, 0x6F, 0xD5, 0x4F, 0x23, 0x14, 0x98, 0xAA, 0xDC, 0x65, 0x74, 0x42,
0xC8, 0x41, 0x8D, 0xA5, 0x22, 0xEA, 0x4D, 0xB5, 0x17, 0x02, 0x1E, 0x88, 0x91, 0x33, 0xC6, 0x78,
0x3B, 0x2D, 0xD9, 0xFC, 0x1B, 0x9A, 0xCD, 0xE6, 0x1F, 0xED, 0x92, 0x29, 0x4A, 0xFA, 0x1A, 0xEE,
0x0D, 0xE7, 0x63, 0x8E, 0xFF, 0x06, 0x3E, 0x1D, 0xF8, 0xAD, 0xE5, 0x36, 0x05, 0x70, 0xA2, 0x69,
0x84, 0xBF, 0xA9, 0x8B, 0x03, 0xD6, 0x26, 0x2E, 0x82, 0x62, 0x81, 0xE4, 0x94, 0xA7, 0xAF, 0x5E,
0x9D, 0xD2, 0xB2, 0x86, 0x2B, 0x51, 0xCC, 0xDD, 0x13, 0xF5, 0x77, 0x50, 0xC0, 0xB7, 0x0A, 0x59,
0x4E, 0xC9, 0xBB, 0x11, 0xA3, 0x6E, 0xDB, 0xF6, 0x61, 0x9C, 0x20, 0xDF, 0xFD, 0xBD, 0x5B, 0xF3
};

unsigned char InvSbox[256] = {

};

void KeyExpansion(AES_CONTEXT *ctx, const unsigned char* key) {
int i, j, r, c;
unsigned char rc[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
for(r = 0; r < 4; r++) {
for(c = 0; c < 4; c++) {
ctx->rk[r][0][c] = key[r + c * 4];
}
}
for(i = 1; i <= 10; i++) {
for(j = 0; j < 4; j++) {
unsigned char t[4];
for(r = 0; r < 4; r++) {
t[r] = j ? ctx->rk[r][i][j - 1] : ctx->rk[r][i - 1][3];
}
if(j == 0) {
unsigned char temp = t[0];
for(r = 0; r < 3; r++) {
t[r] = Sbox[t[(r + 1) % 4]];
}
t[3] = Sbox[temp];
t[0] ^= rc[i - 1];
}
for(r = 0; r < 4; r++) {
ctx->rk[r][i][j] = ctx->rk[r][i - 1][j] ^ t[r];
}
}
}
}

unsigned char FFmul(unsigned char a, unsigned char b) {
unsigned char bw[4];
unsigned char res = 0;
int i;
bw[0] = b;
for(i = 1; i < 4; i++) {
bw[i] = bw[i-1] << 1;
if(bw[i - 1] & 0x80) {
bw[i] ^= 0x1b;
}
}
for(i=0; i<4; i++) {
if((a >> i) & 0x01) {
res ^= bw[i];
}
}
return res;
}

void SubBytes(AES_CONTEXT *ctx, unsigned char state[][4]) {
int r, c;
for(r = 0; r < 4; r++) {
for(c = 0; c < 4; c++) {
state[r][c] = Sbox[state[r][c]];
}
}
}

unsigned int ror4(unsigned int x, int n) {
return (x >> n) | (x << (32 - n));
}

unsigned int rol4(unsigned int x, int n) {
return ror4(x, 32 - n);
}

void ShiftRows(AES_CONTEXT *ctx, unsigned char state[][4]) {
unsigned int* _s = (unsigned int*) state;
_s[0] = ror4(_s[0], 0);
_s[1] = ror4(_s[1], 8);
_s[2] = ror4(_s[2], 24);
_s[3] = ror4(_s[3], 16);
}

void MixColumns(AES_CONTEXT *ctx, unsigned char state[][4]) {
unsigned char t[4];
int r, c;
for(c = 0; c < 4; c++) {
for(r = 0; r < 4; r++) {
t[r] = state[r][c];
}
for(r=0; r<4; r++) {
state[r][c] = FFmul(0x0e, t[r]) ^ FFmul(0x0b, t[(r + 1) % 4]) ^ FFmul(0x0d, t[(r + 2) % 4]) ^ FFmul(0x09, t[(r + 3) % 4]);
}
}
}

void AddRoundKey(AES_CONTEXT *ctx, unsigned char state[][4], unsigned char k[][11][4], int index) {
int r, c;
for(c = 0; c < 4; c++) {
for(r = 0; r < 4; r++) {
state[c][r] ^= k[c][index][r];
}
}
}

void InvSubBytes(AES_CONTEXT *ctx, unsigned char state[][4]) {
int r, c;
for(r = 0; r < 4; r++) {
for(c = 0; c < 4; c++) {
state[r][c] = InvSbox[state[r][c]];
}
}
}

void InvShiftRows(AES_CONTEXT *ctx, unsigned char state[][4]) {
unsigned int* _s = (unsigned int*) state;
_s[0] = rol4(_s[0], 0);
_s[1] = rol4(_s[1], 8);
_s[2] = rol4(_s[2], 24);
_s[3] = rol4(_s[3], 16);
}

void InvMixColumns(AES_CONTEXT *ctx, unsigned char state[][4]) {
unsigned char t[4];
int r, c;
for(c = 0; c < 4; c++) {
for(r = 0; r < 4; r++) {
t[r] = state[r][c];
}
for(r = 0; r < 4; r++) {
state[r][c] = FFmul(0x02, t[r]) ^ FFmul(0x03, t[(r + 1) % 4]) ^ FFmul(0x01, t[(r + 2) % 4]) ^ FFmul(0x01, t[(r + 3) % 4]);
}
}
}

void aes_init(AES_CONTEXT *ctx, const unsigned char* key, const void* iv) {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
InvSbox[Sbox[16 * i + j]] = 16 * i + j;
}
}
KeyExpansion(ctx, key);
if (iv) memcpy(ctx->iv, iv, 16);
}

unsigned char* aes_encrypt_block(AES_CONTEXT* ctx, unsigned char* input) {
unsigned char state[4][4];
int i, r, c;
for(r = 0; r < 4; r++) {
for(c = 0; c < 4 ;c++) {
state[r][c] = input[c * 4 + r];
}
}

AddRoundKey(ctx, state, ctx->rk, 2);
ShiftRows(ctx, state);
SubBytes(ctx, state);

for(i = 8; i <= 20; i += 4) {
AddRoundKey(ctx, state, ctx->rk, i / 2);
MixColumns(ctx, state);
ShiftRows(ctx, state);
SubBytes(ctx, state);
}

for(i = 18; i > 0; i -= 4) {
AddRoundKey(ctx, state, ctx->rk, i / 2);
MixColumns(ctx, state);
ShiftRows(ctx, state);
SubBytes(ctx, state);
}
AddRoundKey(ctx, state, ctx->rk, 0);

for(r = 0; r < 4; r++) {
for(c = 0; c < 4 ;c++) {
input[c * 4 + r] = state[r][c];
}
}

return input;
}

unsigned char* aes_decrypt_block(AES_CONTEXT *ctx, unsigned char* input) {
unsigned char state[4][4];
int i, r, c;

for(r = 0; r < 4; r++) {
for(c = 0; c < 4; c++) {
state[r][c] = input[c * 4 + r];
}
}

AddRoundKey(ctx, state, ctx->rk, 0);
for (int i = 2; i <= 18; i += 4) {
InvSubBytes(ctx, state);
InvShiftRows(ctx, state);
InvMixColumns(ctx, state);
AddRoundKey(ctx, state, ctx->rk, i / 2);
}
for(i = 20; i >= 8; i -= 4) {
InvSubBytes(ctx, state);
InvShiftRows(ctx, state);
InvMixColumns(ctx, state);
AddRoundKey(ctx, state, ctx->rk, i / 2);
}

InvSubBytes(ctx, state);
InvShiftRows(ctx, state);
AddRoundKey(ctx, state, ctx->rk, 2);

for(r = 0; r < 4; r++) {
for(c = 0; c < 4 ;c++) {
input[c * 4 + r] = state[r][c];
}
}

return input;
}

void aes_encrypt_ecb(const void* key, void* data, int data_len) {
assert(data_len % 16 == 0);
AES_CONTEXT ctx;
aes_init(&ctx, (const unsigned char*) key, NULL);
unsigned char* _data = (unsigned char*) data;
for (int i = 0; i < data_len / 16; i++) {
aes_encrypt_block(&ctx, _data);
_data += 16;
}
}

void aes_decrypt_ecb(const void* key, void* data, int data_len) {
assert(data_len % 16 == 0);
AES_CONTEXT ctx;
aes_init(&ctx, (const unsigned char*) key, NULL);
unsigned char* _data = (unsigned char*) data;
for (int i = 0; i < data_len / 16; i++) {
aes_decrypt_block(&ctx, _data);
_data += 16;
}
}

des 加密(实际上是解密):

void __cdecl decrypt1(char *key, char *output, char *input)
{
DES_key_expansion(key);
des_decrypt(output, input, 18, 18);
}

void __cdecl DES_key_expansion(char *key)
{
int i; // [esp+10h] [ebp-8h]

DES_D = key_block;
DES_C = &key_block[28];
bytes_to_bits(key_block, key, 64);
table_trans(key_block, key_block, DES_PC1, 56);
for ( i = 0; i < 16; ++i )
{
rol(DES_D, DES_iteration_shift[i], 28);
rol(DES_C, DES_iteration_shift[i], 28);
table_trans(sub_key[i], key_block, DES_PC2, 48);
}
}

void __cdecl des_decrypt(char *output, char *input, int index1, int index2)
{
int i; // [esp+Ch] [ebp-8h]

hex_string_to_bits(block, input, 64);
table_trans(block, block, DES_IP, 64);
for ( i = 15; i >= 0; --i )
{
uint_cpy(tmp_2, block_left_ptr, 32);
encrypt_round(block_left_ptr, sub_key[i], index1, index2);
bits_xor(block_left_ptr, block_right_ptr, 32);
uint_cpy(block_right_ptr, tmp_2, 32);
}
table_trans(block, block, DES_PI, 64);
bits_to_bytes(output, block, 64);
}

与标准的 DES 中的常量相比, S 改了两个值, PC2 改了一个值。抄写出来得到:

/* Initial Permutation Table */
static char IP[] = {
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7
};

/* Inverse Initial Permutation Table */
static char PI[] = {
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25
};

/*Expansion table */
static char E[] = {
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1
};

/* Post S-Box permutation */
static char P[] = {
16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25
};

/* The S-Box tables */
static char S[8][64] = {{
/* S1 */
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
},{
/* S2 */
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
},{
/* S3 */
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
},{
/* S4 */
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
},{
/* S5 */
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
},{
/* S6 */
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
// 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
10, 15, 4, 2, 7, 12, 0, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
},{
/* S7 */
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
// 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
13, 0, 11, 7, 4, 0, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
},{
/* S8 */
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
}};

/* Permuted Choice 1 Table */
static char PC1[] = {
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,

63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4
};

/* Permuted Choice 2 Table */
static char PC2[] = {
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
// 30, 40, 51, 45, 33, 48,
30, 40, 51, 34, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32
};

/* Iteration Shift Array */
static char iteration_shift[] = {
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};

unsigned int sub_key[16][48];

void bytes_to_bits(unsigned int *dst, const char *src, int length) {
char v3; // cl
int i; // [esp+Ch] [ebp-8h]

for ( i = 0; i < length; ++i ) {
v3 = i & 7;
dst[i] = (src[i / 8] >> v3) & 1;
}
}

void uint_cpy(unsigned int *dst, unsigned int *src, int size) {
int i; // [esp+10h] [ebp-8h]

for ( i = 0; i < size; ++i )
dst[i] = src[i];
}

void table_trans(unsigned int *output, unsigned int *input, char *trans_table, int size) {
int i; // [esp+Ch] [ebp-8h]
unsigned int tmp[256];

for ( i = 0; i < size; ++i )
tmp[i] = input[trans_table[i] - 1];
uint_cpy(output, tmp, size);
}

void rol(unsigned int *arr, int n, int size) {
unsigned int tmp[256];
uint_cpy(tmp, arr, n);
uint_cpy(arr, &arr[n], size - n);
uint_cpy(&arr[size - n], tmp, n);
}

void DES_key_expansion(const char* key) {
unsigned int key_block[64];

unsigned int* DES_D = key_block;
unsigned int* DES_C = key_block + 28;
bytes_to_bits(key_block, key, 64);
table_trans(key_block, key_block, PC1, 56);
for (int i = 0; i < 16; ++i) {
rol(DES_D, iteration_shift[i], 28);
rol(DES_C, iteration_shift[i], 28);
table_trans(sub_key[i], key_block, PC2, 48);
}
}

void bits_xor(unsigned int *dst, unsigned int *src, int size) {
int i; // [esp+10h] [ebp-8h]
for ( i = 0; i < size; ++i )
dst[i] ^= src[i];
}

void DES_SBOX(unsigned int *output, unsigned int *input) {
int i; // [esp+14h] [ebp-8h]

for ( i = 0; i < 8; ++i ) {
bytes_to_bits(output, &S[i][32 * *input + 16 * input[5] + 8 * input[1] + 4 * input[2] + 2 * input[3] + input[4]], 4);
input += 6;
output += 4;
}
}

void encrypt_round(unsigned int *R, unsigned int *_sub_key, int i, int j) {
char v4; // [esp+10h] [ebp-8h]
unsigned int DES_s_input[48];

table_trans(DES_s_input, R, E, 48);
bits_xor(DES_s_input, _sub_key, 48);
DES_SBOX(R, DES_s_input);
v4 = P[i];
P[i] = P[j];
P[j] = v4;
table_trans(R, R, P, 32);
}

void decrypt_round(unsigned int *R, unsigned int *_sub_key, int i, int j) {
char v4; // [esp+10h] [ebp-8h]
unsigned int DES_s_input[48];

table_trans(DES_s_input, R, E, 48);
bits_xor(DES_s_input, _sub_key, 48);
DES_SBOX(R, DES_s_input);
table_trans(R, R, P, 32);
v4 = P[i];
P[i] = P[j];
P[j] = v4;
}

void bits_to_hex_string(char *output, unsigned int *input, int size) {
for (int i = 0; i < size / 4 + 1; i++) output[i] = 0;
for (int i = 0; i < size / 4; i++) {
for (int j = 0; j < 4; j++) {
output[i] |= input[4 * i + j] << j;
}
if (output[i] <= 9) output[i] += '0';
else output[i] += - 10 + 'A';
}
}

void DES_encrypt_inner(const char *input, char *output, int index1, int index2) {
int i; // [esp+10h] [ebp-8h]
unsigned int block[64];
unsigned int tmp[32];

bytes_to_bits(block, input, 64);
table_trans(block, block, IP, 64);
for ( i = 0; i < 16; ++i ) {
uint_cpy(tmp, block + 32, 32);
encrypt_round(block + 32, sub_key[i], index1, index2);
bits_xor(block + 32, block, 32);
uint_cpy(block, tmp, 32);
}

table_trans(block, block, PI, 64);
bits_to_hex_string(output, block, 64);
}

void DES_encrypt(const char* key, const char* input, char* output, int index1, int index2) {
DES_key_expansion(key);
DES_encrypt_inner(input, output, index1, index2);
}

void hex_string_to_bits(unsigned int *output, const char *input, int size) {
for (int i = 0; i < size; i++) {
char c = input[i / 4];
if (c <= 0x39) c -= '0';
else c -= 'A' - 10;
output[i] = (c >> (i & 3)) & 1;
}
}

void bits_to_bytes(char *output, unsigned int *input, int size) {
int i; // [esp+10h] [ebp-8h]
int j; // [esp+10h] [ebp-8h]

for ( i = 0; i < size / 8 + 1; ++i )
output[i] = 0;
for ( j = 0; j < size; ++j )
output[j / 8] |= input[j] << (j % 8);
}

void DES_decrypt_inner(char* output, const char* input, int index1, int index2) {
unsigned int block[64];
unsigned int tmp[32];
int i; // [esp+Ch] [ebp-8h]

hex_string_to_bits(block, input, 64);
table_trans(block, block, IP, 64);
for ( i = 15; i >= 0; --i ) {
uint_cpy(tmp, block, 32);
encrypt_round(block, sub_key[i], index1, index2);
bits_xor(block, block + 32, 32);
uint_cpy(block + 32, tmp, 32);
}
table_trans(block, block, PI, 64);
bits_to_bytes(output, block, 64);
}

void DES_decrypt(const char* key, const char* input, char* output, int index1, int index2) {
DES_key_expansion(key);
DES_decrypt_inner(output, input, index1, index2);
}

void DES_decrypt_decrypt_inner(const char *input, char *output, int index1, int index2) {
int i; // [esp+10h] [ebp-8h]
unsigned int block[64];
unsigned int tmp[32];

bytes_to_bits(block, input, 64);
table_trans(block, block, IP, 64);
for ( i = 0; i < 16; ++i ) {
uint_cpy(tmp, block + 32, 32);
decrypt_round(block + 32, sub_key[i], index1, index2);
bits_xor(block + 32, block, 32);
uint_cpy(block, tmp, 32);
}

table_trans(block, block, PI, 64);
bits_to_hex_string(output, block, 64);
}

void DES_decrypt_decrypt(const char* key, const char* input, char* output, int index1, int index2) {
DES_key_expansion(key);
DES_decrypt_decrypt_inner(input, output, index1, index2);
}

最后还有个简单的虚拟机的形式的加密,抄写出来写逆:

void vm_encrypt(const char* key, char* data, char flag) {
const char* code = "188314639360140916609214592753355241102748157658325077451310433873512805611046964127739955621255841702411199825520291475473529536531735880099500596431514601528872505540869163506318442965625785468536063896163123867531708491350401766156647550166763071341544";
int v3; // [esp+14h] [ebp-18h]
signed int output_len; // [esp+18h] [ebp-14h]
int v5; // [esp+1Ch] [ebp-10h]
int v6; // [esp+20h] [ebp-Ch]
signed int i; // [esp+24h] [ebp-8h]

output_len = strlen(data);
if ( output_len < 8 )
output_len = 8;
i = 0;
v3 = 0;
while ( i < output_len ) {
if ( v3 == strlen(key) )
v3 = 0;
v5 = key[v3];
if ( code[v5] ) {
v6 = code[v5] - '0';
if ( flag && code[v5] != '0' && code[v5] != '9' ) {
if ( v6 % 2 )
++v6;
else
v6 = code[v5] - '1';
}
switch ( v6 ) {
case 1:
data[i] += code[v5 + 1] - 48;
break;
case 2:
data[i] -= code[v5 + 1] - 48;
break;
case 3:
data[i] += code[v5 + 1] + code[v5] - 96;
break;
case 4:
data[i] -= code[v5 + 1] + code[v5] - 96;
break;
case 5:
data[i] += code[v5 + 1] + code[v5] - 48;
break;
case 6:
data[i] -= code[v5 + 1] + code[v5] - 48;
break;
case 7:
data[i] += code[v5 + 1] + code[v5] - 48;
break;
case 8:
data[i] -= code[v5 + 1] + code[v5] - 48;
break;
case 9:
data[i] ^= code[v5 + 1] - 48;
break;
}
}
++i;
++v3;
}
}

void vm_decrypt(const char* key, char* data, int flag) {
const char* code = "188314639360140916609214592753355241102748157658325077451310433873512805611046964127739955621255841702411199825520291475473529536531735880099500596431514601528872505540869163506318442965625785468536063896163123867531708491350401766156647550166763071341544";
int v3; // [esp+14h] [ebp-18h]
signed int output_len; // [esp+18h] [ebp-14h]
int v5; // [esp+1Ch] [ebp-10h]
int v6; // [esp+20h] [ebp-Ch]
signed int i; // [esp+24h] [ebp-8h]

output_len = strlen(data);
if ( output_len < 8 )
output_len = 8;
i = output_len - 1;
v3 = (output_len - 1) % strlen(key);
while ( i >= 0 ) {
if ( v3 == -1 )
v3 = strlen(key) - 1;
v5 = key[v3];
if ( code[v5] ) {
v6 = code[v5] - '0';
if ( flag && code[v5] != '0' && code[v5] != '9' ) {
if ( v6 % 2 )
++v6;
else
v6 = code[v5] - '1';
}
switch ( v6 ) {
case 1:
data[i] -= code[v5 + 1] - 48;
break;
case 2:
data[i] += code[v5 + 1] - 48;
break;
case 3:
data[i] -= code[v5 + 1] + code[v5] - 96;
break;
case 4:
data[i] += code[v5 + 1] + code[v5] - 96;
break;
case 5:
data[i] -= code[v5 + 1] + code[v5] - 48;
break;
case 6:
data[i] += code[v5 + 1] + code[v5] - 48;
break;
case 7:
data[i] -= code[v5 + 1] + code[v5] - 48;
break;
case 8:
data[i] += code[v5 + 1] + code[v5] - 48;
break;
case 9:
data[i] ^= code[v5 + 1] - 48;
break;
}
}
--i;
--v3;
}
}

将最终结果以及各个密钥动调拿出来,写逆得到密码:

int main() {
const char* vm_key = "x6fx7cx78x33x41x39x38x3dx72x7fx6bx3ax30x4ax46x36x71x7cx79x3bx2bx48x46x3dx6ex73x69x49x2fx45x36x3bx7ex7ex79x48x3dx4ax49x3ax71x71x66x39x2ex3ax4ax4ax7ex6bx6ax48x2fx3bx47x48x7ex6bx65x3ax31x34x3ex3ax80x74x76x37x2dx35x4bx4ax6dx6cx6ax3ax33x36x46x49x7ex80x6ax45x41x4ax3dx35x7cx81x69x38x3ex36x4bx3cx72x6dx6ax3bx30x45x49x36x7dx6ex78x34x3cx3bx39x46x81x6bx6cx35x31x46x37x3dx6ex6cx66x49x3dx48x3bx4ax6bx81x67x36x33x48x3ex46x7cx6cx7bx3ax40x35x49x3bx6bx7dx78x35x2bx38x3bx35x7fx7dx6bx44x40x3bx46x36x7dx80x65x34x3ex48x48x38x7ex71x79x46x2bx38x3ex3ax80x7ex76x35x32x47x3ex3d";
char data[32] = "5528f900";
vm_decrypt(vm_key, data, 1);
puts(data);

char tmp[64];
tmp[17] = 0;
for (int i = 0; i < 22; i++) {
DES_decrypt_decrypt(vm_key + 8 * i, data, tmp, 18, 18);
memcpy(data, tmp, 17);
// puts(data);
}

aes_decrypt_ecb("40041A36A4B0C478", data, 16);
for (int i = 0; i < 16; i++) {
printf("%02X", data[i] & 0xff);
}
putchar('n');
// 8BCBB6979E174CB7ECAEACDA104522CA

return 0;
}


看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析
昨日中午12:00
第八题《AI核心地带》已开赛!

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析
看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

截至发文,本题已有6支战队攻破:


看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

在这个充满变数的赛场上,没有人能够预料到最终的结局。有时,优势的领先可能只是一时的,一瞬间的失误就足以颠覆一切。而那些一直默默努力、不断突破自我的人,往往会在最后关头迎头赶上,成为最耀眼的存在。

谁能保持领先优势?谁能迎头赶上?谁又能突出重围成为黑马?

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

球分享

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

球点赞

看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

球在看


看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

点击阅读原文进入比赛

原文始发于微信公众号(看雪学苑):看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析

版权声明:admin 发表于 2023年9月18日 下午6:03。
转载请注明:看雪2023 KCTF年度赛 | 第七题·智能联盟计划-设计思路及解析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...