2023NepCTF-RE部分题解
2023NepCTF-RE部分题解
九龙拉棺
过反调试
很容易发现
void __stdcall sub_401700()
里面有tea的痕迹
接出来发现只是前半部分
#include <stdio.h>
#include <stdint.h>
#include"defs.h"
#include <stdio.h>
#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;//0xc6ef3720 /* set up */
uint32_t delta = 0x61C88647; /* 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 enc[17] = {
0x88AFD2D6, 0x3FBE45A7, 0x27AAD1B9, 0x8CB3E51E, 0x09348FFA, 0xE19F3C42, 0xFFDD0D86, 0xEDB97383,
0x12C4C0BF, 0x1B67BD19, 0xF7A514D6, 0x18F95254, 0xAB100CB0, 0x00CBA137, 0x02A91712, 0xC58D0D9E,0
};
int sum = 0;
uint32_t v[2] = { 1,2 }, k[4] = { 1,2,3,4 };
for (int i = 0; i < 16; i += 2)
{
decrypt(&enc[i], k);
}
puts((char*)enc);//NepCTF{c9cdnwdi3iu41m0pv3x7kllzu8pdq6mt9n2nwjdp6kat8ent4dhn5r158
return 0;
}
卡在找后半段flag校验的地方很久,
这里其实有优先级
按创建顺序开始
tea后面的函数是根据密文直接校验的结果进行判断
。
慢慢看
void __usercall StartAddress(int a1@<ebp>)
里面
断点下在这,明显在内存看到MZ标识
这里使用idapython没把数据提取出来
纯shift+f12拉出来的
#include <stdio.h>
#include <stdint.h>
#include"defs.h"
#include <stdio.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;//0xc6ef3720 /* set up */
uint32_t delta = 0x61C88647; /* 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 enc[17] = {
0 };
enc[0] = 0x1DC74989;
enc[1] = 0xD979AF77;
enc[2] = 0x888D136D;
enc[3] = 0x8E26DB7F;
enc[4] = 0xC10C3CC9;
enc[5] = 0xC3845D40;
enc[6] = 0xC6E04459;
enc[7] = 0xA2EBDF07;
enc[8] = 0xD484388D;
enc[9] = 0x12F956A2;
enc[10] = 0x5ED7EE59;
enc[11] = 0x43137F85;
enc[12] = 0xEF43F9F0;
enc[13] = 0xB29683AA;
enc[14] = 0x8E3640B4;
enc[15] = 0xc2d36177;
int sum = 0;
uint32_t v[2] = { 1,2 }, k[4] = { 18,52,86,120 };
for (int i = 0; i < 16; i += 2)
{
decrypt(&enc[i],k);
}
puts((char*)enc);
return 0;
}
后64位flag
拼凑一下
Review
这里有反调试,patch就好
需要对aes的key进行爆破,有2位根据相等位置生成,xxtea加密后,有个异常处理,里面进行~操作
from Crypto.Cipher import AES
from ctypes import *
def MX(z, y, total, key, p, e):
temp1 = (z.value >> 5 ^ y.value << 2) + (y.value >> 3 ^ z.value << 4)
temp2 = (total.value ^ y.value) + (key[(p & 3) ^ e.value] ^ z.value)
return c_uint32(temp1 ^ temp2)
def encrypt(n, v, key):
delta = 0x9e3779b9
rounds = 6 + 52 // n
total = c_uint32(0)
z = c_uint32(v[n - 1])
e = c_uint32(0)
while rounds > 0:
total.value += delta
e.value = (total.value >> 2) & 3
for p in range(n - 1):
y = c_uint32(v[p + 1])
v[p] = c_uint32(v[p] + MX(z, y, total, key, p, e).value).value
z.value = v[p]
y = c_uint32(v[0])
v[n - 1] = c_uint32(v[n - 1] + MX(z, y, total, key, n - 1, e).value).value
z.value = v[n - 1]
rounds -= 1
return v
def decrypt(n, v, key):
delta = 0x9e3779b9
rounds = 6 + 52 // n
total = c_uint32(rounds * delta)
y = c_uint32(v[0])
e = c_uint32(0)
while rounds > 0:
e.value = (total.value >> 2) & 3
for p in range(n - 1, 0, -1):
z = c_uint32(v[p - 1])
v[p] = c_uint32((v[p] - MX(z, y, total, key, p, e).value)).value
y.value = v[p]
z = c_uint32(v[n - 1])
v[0] = c_uint32(v[0] - MX(z, y, total, key, 0, e).value).value
y.value = v[0]
total.value -= delta
rounds -= 1
return v
Aeskey=[ 0x19, 0x28, 0x6E, 0x04, 0x19, 0x28, 0x6E, 0x04, 0x46, 0x55,
0xC8, 0x04, 0x46, 0x55, 0xC8, 0x04]
for i in range(47):
v17=i+4
Aeskey[3]=v17
Aeskey[11]=v17
enc = [0xF4, 0x9C, 0xDD, 0x41, 0x03, 0xDD, 0x5A, 0x13, 0x2E, 0x55, 0x97, 0x9E, 0xFF, 0xD5, 0x08, 0xD9, 0xF6, 0xD1,
0x09, 0x8C, 0x68, 0x9E, 0x92, 0xFF, 0x75, 0x0F, 0x80, 0x95, 0x4B, 0x16, 0xB9, 0xC6, 0x7F, 0x54, 0x2E, 0x20,
0x35, 0xFC, 0x1B, 0x46, 0x14, 0xAA, 0xDA, 0x5E, 0x4F, 0xBD, 0x59, 0x71]
aes = AES.new(bytes(Aeskey), AES.MODE_ECB) # 创建一个aes对象
den_text = aes.decrypt(bytes(enc)) # 解密密文
x=[i for i in den_text]
for i in range(len(x)):
x[i] = ~x[i]
x[i]&=0xff
enc1 = [int.from_bytes(x[i*4:i*4+4],'little') for i in range(12)]
xxteakey = [0x00000019, 0x00000000, 0x0000006E, 0x00000003]
m=decrypt(12,enc1,xxteakey)
import libnum
try:
x=[libnum.n2s(i).decode()[::-1] for i in m]
for i in x:
print(i,end='')#NepCTF{tEA_with_AES_by_mixing_antiDebug_hahaHah}
except :
pass
# flag='NepCTF{'+'11112222'*5+'}'
# print(flag)
#NepCTF{1111222211112222111122221111222211112222}
eeeeerte
0xA3, 0xD7, 0x09, 0x83, 0xF8, 0x48, 0xF6, 0xF4, 0xB3, 0x21, 0x15, 0x78, 0x99, 0xB1, 0xAF, 0xF9, 0xE7, 0x2D, 0x4D, 0x8A, 0xCE, 0x4C, 0xCA, 0x2E, 0x52, 0x95, 0xD9, 0x1E, 0x4E, 0x38, 0x44, 0x28, 0x0A, 0xDF, 0x02, 0xA0, 0x17, 0xF1, 0x60, 0x68, 0x12, 0xB7, 0x7A, 0xC3, 0xE9, 0xFA, 0x3D, 0x53, 0x96, 0x84, 0x6B, 0xBA, 0xF2, 0x63, 0x9A, 0x19, 0x7C, 0xAE, 0xE5, 0xF5, 0xF7, 0x16, 0x6A, 0xA2, 0x39, 0xB6, 0x7B, 0x0F, 0xC1, 0x93, 0x81, 0x1B, 0xEE, 0xB4, 0x1A, 0xEA, 0xD0, 0x91, 0x2F, 0xB8, 0x55, 0xB9, 0xDA, 0x85, 0x3F, 0x41, 0xBF, 0xE0, 0x5A, 0x58, 0x80, 0x5F, 0x66, 0x0B, 0xD8, 0x90, 0x35, 0xD5, 0xC0, 0xA7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6D, 0x98, 0x9B, 0x76, 0x97, 0xFC, 0xB2, 0xC2, 0xB0, 0xFE, 0xDB, 0x20, 0xE1, 0xEB, 0xD6, 0xE4, 0xDD, 0x47, 0x4A, 0x1D, 0x42, 0xED, 0x9E, 0x6E, 0x49, 0x3C, 0xCD, 0x43, 0x27, 0xD2, 0x07, 0xD4, 0xDE, 0xC7, 0x67, 0x18, 0x89, 0xCB, 0x30, 0x1F, 0x8D, 0xC6, 0x8F, 0xAA, 0xC8, 0x74, 0xDC, 0xC9, 0x5D, 0x5C, 0x31, 0xA4, 0x70, 0x88, 0x61, 0x2C, 0x9F, 0x0D, 0x2B, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7D, 0x03, 0x40, 0x34, 0x4B, 0x1C, 0x73, 0xD1, 0xC4, 0xFD, 0x3B, 0xCC, 0xFB, 0x7F, 0xAB, 0xE6, 0x3E, 0x5B, 0xA5, 0xAD, 0x04, 0x23, 0x9C, 0x14, 0x51, 0x22, 0xF0, 0x29, 0x79, 0x71, 0x7E, 0xFF, 0x8C, 0x0E, 0xE2, 0x0C, 0xEF, 0xBC, 0x72, 0x75, 0x6F, 0x37, 0xA1, 0xEC, 0xD3, 0x8E, 0x62, 0x8B, 0x86, 0x10, 0xE8, 0x08, 0x77, 0x11, 0xBE, 0x92, 0x4F, 0x24, 0xC5, 0x32, 0x36, 0x9D, 0xCF, 0xF3, 0xA6, 0xBB, 0xAC, 0x5E, 0x6C, 0xA9, 0x13, 0x57, 0x25, 0xB5, 0xE3, 0xBD, 0xA8, 0x3A, 0x01, 0x05, 0x59, 0x2A, 0x46
根据常量数组识别出skipjack
这里让易语言画图没反应手撸
address=0x00401426
end_address=0x0040295C
foud=[0x68, 0x01, 0x03, 0x00, 0x80, 0x6A, 0x00]
call_select=[ 0x68, 0x35, 0x00, 0x01, 0x16, 0x68, 0x01, 0x00, 0x01, 0x52,
0xE8,]
map_sit=[]
def get_point(a3,a4):
Point=[]
Point.append(a4 + 10)
Point.append(a3 + 10)
Point.append(a4)
Point.append(a3)
Point.append(a4+20)
Point.append(a3+10)
Point.append(a4+10)
Point.append(a3)
Point.append(a4+30)
Point.append(a3+10)
Point.append(a4+20)
Point.append(a3)
Point.append(a4+40)
Point.append(a3+10)
Point.append(a4+30)
Point.append(a3)
return Point
while address<=end_address:
if idc.get_bytes(address,len(foud))==bytes(foud):
address+=len(foud)+1
map_sit.append(ord(idc.get_bytes(address,1)))
elif idc.get_bytes(address,len(call_select))==bytes(call_select) and ord(idc.get_bytes(address+12,1))==0x3c :
address-=10
address+=1
a3=0
a4=0
a4=ord(idc.get_bytes(address,1))
address += 5
a3=ord(idc.get_bytes(address,1))
map_sit+=get_point(a3,a4)
address+=4
address+=len(call_select)
print(hex(address))
address+=1
print(map_sit)
map_sit=[20, 20, 10, 10, 30, 20, 20, 10, 40, 20, 30, 10, 30, 30, 20, 20, 30, 50, 20, 40, 40, 40, 30, 30, 40, 50, 30, 40, 50, 50, 40, 40, 20, 90, 10, 80, 20, 100, 10, 90, 20, 110, 10, 100, 30, 100, 20, 90, 150, 40, 140, 30, 160, 30, 150, 20, 160, 40, 150, 30, 160, 50, 150, 40, 110, 150, 100, 140, 120, 140, 110, 130, 120, 150, 110, 140, 130, 150, 120, 140, 140, 150, 130, 140, 150, 150, 140, 140, 150, 140, 140, 130, 150, 160, 140, 150, 120, 210, 110, 200, 130, 200, 120, 190, 130, 210, 120, 200, 140, 210, 130, 200, 50, 20, 40, 10, 60, 20, 50, 10, 70, 20, 60, 10, 80, 20, 70, 10, 60, 50, 50, 40, 70, 50, 60, 40, 80, 50, 70, 40, 90, 50, 80, 40, 20, 70, 10, 60, 30, 70, 20, 60, 40, 70, 30, 60, 50, 70, 40, 60, 60, 70, 50, 60, 70, 70, 60, 60, 80, 70, 70, 60, 90, 70, 80, 60, 40, 100, 30, 90, 50, 100, 40, 90, 60, 100, 50, 90, 70, 100, 60, 90, 30, 150, 20, 140, 40, 150, 30, 140, 50, 150, 40, 140, 60, 150, 50, 140, 40, 170, 30, 160, 50, 170, 40, 160, 60, 170, 50, 160, 70, 170, 60, 160, 20, 210, 10, 200, 30, 210, 20, 200, 40, 210, 30, 200, 50, 210, 40, 200, 60, 210, 50, 200, 70, 210, 60, 200, 80, 210, 70, 200, 90, 210, 80, 200, 130, 100, 120, 90, 140, 100, 130, 90, 150, 100, 140, 90, 160, 100, 150, 90, 30, 130, 20, 120, 30, 140, 20, 130, 40, 130, 30, 120, 50, 130, 40, 120, 60, 130, 50, 120, 60, 140, 50, 130, 60, 140, 50, 140, 30, 170, 20, 160, 30, 180, 20, 170, 30, 190, 20, 180, 40, 190, 30, 180, 120, 30, 110, 20, 120, 40, 110, 30, 120, 50, 110, 40, 130, 50, 120, 40, 110, 200, 100, 190, 110, 210, 100, 200, 110, 220, 100, 210, 120, 220, 110, 210, 50, 180, 40, 170, 60, 180, 50, 170, 60, 190, 50, 180, 70, 190, 60, 180, 140, 30, 130, 20, 140, 40, 130, 30, 140, 50, 130, 40, 150, 30, 140, 20, 120, 80, 110, 70, 130, 80, 120, 70, 140, 80, 130, 70, 140, 90, 130, 80, 140, 220, 130, 210, 150, 220, 140, 210, 150, 210, 140, 200, 150, 200, 140, 190]
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# 替换为您的数字数组
data = map_sit
# 创建一个新的绘图
fig, ax = plt.subplots()
# 遍历每个矩形的数据
# 遍历每个矩形的数据
for i in range(0, len(data), 4):
rect = patches.Rectangle((data[i], data[i+1]), data[i+2] - data[i], data[i+3] - data[i+1], linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rect)
# 设置坐标轴范围
ax.set_xlim(0, 300)
ax.set_ylim(0, 300)
# 显示图像
plt.show()
拿到key
直接逆
import base64
FTABLE = (0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4,
0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e,
0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68,
0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19,
0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b,
0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0,
0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69,
0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20,
0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43,
0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa,
0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87,
0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b,
0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0,
0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1,
0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5,
0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3,
0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46)
# G işlemi
def g(key, k, w):
g1 = 0xFF & (w >> 8)
g2 = 0xFF & w
g3 = FTABLE[g2 ^ key[(4 * k + 0) % 10]] ^ g1
g4 = FTABLE[g3 ^ key[(4 * k + 1) % 10]] ^ g2
g5 = FTABLE[g4 ^ key[(4 * k + 2) % 10]] ^ g3
g6 = FTABLE[g5 ^ key[(4 * k + 3) % 10]] ^ g4
return ((g5 << 8) + g6)
# G işleminin tersi
def ginv(key, k, w):
g5 = 0xFF & (w >> 8)
g6 = 0xFF & w
g4 = FTABLE[g5 ^ key[(4 * k + 3) % 10]] ^ g6
g3 = FTABLE[g4 ^ key[(4 * k + 2) % 10]] ^ g5
g2 = FTABLE[g3 ^ key[(4 * k + 1) % 10]] ^ g4
g1 = FTABLE[g2 ^ key[(4 * k + 0) % 10]] ^ g3
return ((g1 << 8) + g2)
def skip(key, buf, encrypt):
# Gruplara ayırma
w1 = (buf[0] << 8) + buf[1]
w2 = (buf[2] << 8) + buf[3]
w3 = (buf[4] << 8) + buf[5]
w4 = (buf[6] << 8) + buf[7]
if encrypt:
k, step = 0, 1
for t in range(2):
# A işlemi
for i in range(8):
gw1 = g(key, k, w1)
w1, w2, w3, w4 = gw1 ^ w4 ^ (k + step), gw1, w2, w3
k += step
# B işlemi
for i in range(8):
gw1 = g(key, k, w1)
w1, w2, w3, w4 = w4, gw1, w1 ^ w2 ^ (k + step), w3
k += step
else:
k, step = 32, -1
for t in range(2):
# B^-1
for i in range(8):
gw2 = ginv(key, k + step, w2)
w1, w2, w3, w4 = gw2, gw2 ^ w3 ^ k, w4, w1
k += step
# B
for i in range(8):
w1, w2, w3, w4 = ginv(key, k + step, w2), w3, w4, w1 ^ w2 ^ k
k += step
return bytes((w1 >> 8, w1 & 0xFF, w2 >> 8, w2 & 0xFF,
w3 >> 8, w3 & 0xFF, w4 >> 8, w4 & 0xFF))
class Skipjack:
# Class bir anahtar ile oluşturulur
def __init__(self, key):
if len(key) != 10:
raise ValueError("key must be 10 bytes in length")
else:
self._key = bytearray(key, 'utf-8')
# Şifreleme Fonksiyonu
def encrypt(self, value):
pad = bytearray(8 - len(value)) # 8 karakterden az şifreleme için padding
buf = bytearray(value, 'utf-8') + pad
enc = skip(self._key, buf, True)
print(enc)
return enc
def decrypt(self, value):
pad = bytearray(8 - len(value))
buf = value + pad
dec = skip(self._key, buf, False)
#print(dec)
return dec
import base64
enc='xmxO93Sn8YjfoWqaFS6poLf6n1q7bWrIyXbLAdcSjygWfs/jAVc4leFrTDZYdFoL'
enc=base64.b64decode(enc)
enc1=[int.from_bytes(enc[i*8:i*8+8],'little') for i in range(len(enc)//8)]
enc1=[bytes(enc[i*8:i*8+8]) for i in range(len(enc)//8)]
import libnum
# example
CT = 0x33221100ddccbbaa
KEY = [ord(i) for i in "NITORI2413"]
sj = Skipjack("NITORI2413")
for i in enc1:
m=sj.decrypt(i)
print(m.decode(),end='')#NepCTF{3456789TQKA2,Jack_was_skipped_by_EPL}